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.

3078 lines
94 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. Mooly Beery (MoolyB) Jun-2000
  11. --*/
  12. #define DEFINE_T30_GLOBALS
  13. #define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_MAIN
  14. #include "prep.h"
  15. #include <mcx.h>
  16. #include "tiff.h"
  17. #include "glbproto.h"
  18. #include <faxext.h>
  19. #include "faxreg.h"
  20. ///RSL Wes should export this.
  21. #define TAPI_VERSION 0x00020000
  22. #include "t30gl.h"
  23. #include "psslog.h"
  24. #define FILE_ID FILE_ID_T30API
  25. #define T30_DEBUG_LOG_FILE _T("T30DebugLogFile.txt")
  26. #define T30_MAX_LOG_SIZE 104857600 // 100MB
  27. #define MAX_DEVICE_NAME_SIZE 256
  28. VOID pFaxDevCleanup(PThrdGlbl pTG,int RecoveryIndex);
  29. long pFaxDevExceptionCleanup();
  30. BOOL ReadExtensionConfiguration(PThrdGlbl pTG);
  31. HRESULT
  32. FaxExtInitializeConfig (
  33. PFAX_EXT_GET_DATA pfGetExtensionData, // Pointer to FaxExtGetExtensionData in service
  34. PFAX_EXT_SET_DATA pfSetExtensionData, // Pointer to FaxExtSetExtensionData in service
  35. PFAX_EXT_REGISTER_FOR_EVENTS pfRegisterForExtensionEvents, // Pointer to FaxExtRegisterForExtensionEvents in service
  36. PFAX_EXT_UNREGISTER_FOR_EVENTS pfUnregisterForExtensionEvents, // Pointer to FaxExtUnregisterForExtensionEvents in service
  37. PFAX_EXT_FREE_BUFFER pfExtFreeBuffer // Pointer to FaxExtFreeBuffer in service
  38. )
  39. {
  40. UNREFERENCED_PARAMETER(pfSetExtensionData);
  41. UNREFERENCED_PARAMETER(pfRegisterForExtensionEvents);
  42. UNREFERENCED_PARAMETER(pfUnregisterForExtensionEvents);
  43. Assert(pfGetExtensionData);
  44. Assert(pfSetExtensionData);
  45. Assert(pfRegisterForExtensionEvents);
  46. Assert(pfUnregisterForExtensionEvents);
  47. Assert(pfExtFreeBuffer);
  48. g_pfFaxGetExtensionData = pfGetExtensionData;
  49. g_pfFaxExtFreeBuffer = pfExtFreeBuffer;
  50. return S_OK;
  51. }
  52. ///////////////////////////////////////////////////////////////////////////////////
  53. VOID CALLBACK
  54. T30LineCallBackFunctionA(
  55. HANDLE hFax,
  56. DWORD hDevice,
  57. DWORD dwMessage,
  58. DWORD_PTR dwInstance,
  59. DWORD_PTR dwParam1,
  60. DWORD_PTR dwParam2,
  61. DWORD_PTR dwParam3
  62. )
  63. {
  64. LONG_PTR i;
  65. PThrdGlbl pTG = NULL;
  66. char rgchTemp128[128];
  67. LPSTR lpszMsg = "Unknown";
  68. DEBUG_FUNCTION_NAME(_T("T30LineCallBack"));
  69. DebugPrintEx( DEBUG_MSG,
  70. "hFax=%lx, dev=%lx, msg=%lx, dwInst=%lx,P1=%lx, P2=%lx, P3=%lx",
  71. hFax, hDevice, dwMessage, dwInstance,
  72. dwParam1, dwParam2, (unsigned long) dwParam3);
  73. // find the thread that this callback belongs to
  74. //----------------------------------------------
  75. i = (LONG_PTR) hFax;
  76. if (i < 1 || i >= MAX_T30_CONNECT)
  77. {
  78. DebugPrintEx(DEBUG_MSG,"wrong handle=%x", i);
  79. return;
  80. }
  81. if ( (! T30Inst[i].fAvail) && T30Inst[i].pT30)
  82. {
  83. pTG = (PThrdGlbl) T30Inst[i].pT30;
  84. }
  85. else
  86. {
  87. DebugPrintEx(DEBUG_ERR,"handle=%x invalid", i);
  88. return;
  89. }
  90. switch (dwMessage)
  91. {
  92. case LINE_LINEDEVSTATE:
  93. lpszMsg = "LINE_LINEDEVSTATE";
  94. if (dwParam1 == LINEDEVSTATE_RINGING)
  95. {
  96. DebugPrintEx( DEBUG_MSG,
  97. "Ring Count = %lx",
  98. (unsigned long) dwParam3);
  99. }
  100. else if (dwParam1 == LINEDEVSTATE_REINIT)
  101. {
  102. }
  103. break;
  104. case LINE_ADDRESSSTATE:
  105. lpszMsg = "LINE_ADDRESSSTATE";
  106. break;
  107. /* process state transition */
  108. case LINE_CALLSTATE:
  109. lpszMsg = "LINE_CALLSTATE";
  110. if (dwParam1 == LINECALLSTATE_CONNECTED)
  111. {
  112. pTG->fGotConnect = TRUE;
  113. }
  114. else if (dwParam1 == LINECALLSTATE_IDLE)
  115. {
  116. if (pTG->fDeallocateCall == 0)
  117. {
  118. pTG->fDeallocateCall = 1;
  119. }
  120. }
  121. break;
  122. case LINE_CREATE:
  123. lpszMsg = "LINE_CREATE";
  124. break;
  125. case LINE_CLOSE:
  126. lpszMsg = "LINE_CLOSE";
  127. break; // LINE_CLOSE
  128. /* handle simple tapi request. */
  129. case LINE_REQUEST:
  130. lpszMsg = "LINE_REQUEST";
  131. break; // LINE_REQUEST
  132. /* handle the assync completion of TAPI functions
  133. lineMakeCall/lineDropCall */
  134. case LINE_REPLY:
  135. lpszMsg = "LINE_REPLY";
  136. if (!hDevice)
  137. {
  138. itapi_async_signal(pTG, (DWORD)dwParam1, (DWORD)dwParam2, dwParam3);
  139. }
  140. else
  141. {
  142. DebugPrintEx( DEBUG_MSG,
  143. "Ignoring LINE_REPLY with nonzero device");
  144. }
  145. break;
  146. /* other messages that can be processed */
  147. case LINE_CALLINFO:
  148. lpszMsg = "LINE_CALLINFO";
  149. break;
  150. case LINE_DEVSPECIFIC:
  151. lpszMsg = "LINE_DEVSPECIFIC";
  152. break;
  153. case LINE_DEVSPECIFICFEATURE:
  154. lpszMsg = "LINE_DEVSPECIFICFEATURE";
  155. break;
  156. case LINE_GATHERDIGITS:
  157. lpszMsg = "LINE_GATHERDIGITS";
  158. break;
  159. case LINE_GENERATE:
  160. lpszMsg = "LINE_GENERATE";
  161. break;
  162. case LINE_MONITORDIGITS:
  163. lpszMsg = "LINE_MONITORDIGITS";
  164. break;
  165. case LINE_MONITORMEDIA:
  166. lpszMsg = "LINE_MONITORMEDIA";
  167. break;
  168. case LINE_MONITORTONE:
  169. lpszMsg = "LINE_MONITORTONE";
  170. break;
  171. } /* switch */
  172. _stprintf(rgchTemp128,
  173. "%s(p1=0x%lx, p2=0x%lx, p3=0x%lx)",
  174. (LPTSTR) lpszMsg,
  175. (unsigned long) dwParam1,
  176. (unsigned long) dwParam2,
  177. (unsigned long) dwParam3);
  178. DebugPrintEx( DEBUG_MSG,
  179. "Device:0x%lx; Message:%s",
  180. (unsigned long) hDevice,
  181. (LPTSTR) rgchTemp128);
  182. } /* LineCallBackProc */
  183. #ifdef DEBUG
  184. #define DEFAULT_LEVELEX (DEBUG_WRN_MSG | DEBUG_ERR_MSG)
  185. #else
  186. #define DEFAULT_LEVELEX (0)
  187. #endif
  188. #define DEFAULT_FORMATEX (DBG_PRNT_ALL_TO_FILE & ~DBG_PRNT_TIME_STAMP)
  189. #define DEFAULT_CONTEXTEX (DEBUG_CONTEXT_T30_MAIN | DEBUG_CONTEXT_T30_CLASS1 | DEBUG_CONTEXT_T30_CLASS2)
  190. void debugReadFromRegistry()
  191. {
  192. DWORD dwLevelEx = DEFAULT_LEVELEX;
  193. DWORD dwFormatEx = DEFAULT_FORMATEX;
  194. DWORD dwContextEx = DEFAULT_CONTEXTEX;
  195. DWORD err;
  196. DWORD size;
  197. DWORD type;
  198. HKEY hkey;
  199. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  200. REGKEY_DEVICE_PROVIDER_KEY TEXT("\\") REGVAL_T30_PROVIDER_GUID_STRING,
  201. 0,
  202. KEY_READ,
  203. &hkey);
  204. if (err != ERROR_SUCCESS)
  205. {
  206. goto exit;
  207. }
  208. size = sizeof(DWORD);
  209. err = RegQueryValueEx(hkey,
  210. REGVAL_DBGLEVEL_EX,
  211. 0,
  212. &type,
  213. (LPBYTE)&dwLevelEx,
  214. &size);
  215. if (err != ERROR_SUCCESS || type != REG_DWORD)
  216. {
  217. dwLevelEx = DEFAULT_LEVELEX;
  218. }
  219. err = RegQueryValueEx(hkey,
  220. REGVAL_DBGFORMAT_EX,
  221. 0,
  222. &type,
  223. (LPBYTE)&dwFormatEx,
  224. &size);
  225. if (err != ERROR_SUCCESS || type != REG_DWORD)
  226. {
  227. dwFormatEx = DEFAULT_FORMATEX;
  228. }
  229. err = RegQueryValueEx(hkey,
  230. REGVAL_DBGCONTEXT_EX,
  231. 0,
  232. &type,
  233. (LPBYTE)&dwContextEx,
  234. &size);
  235. if (err != ERROR_SUCCESS || type != REG_DWORD)
  236. {
  237. dwContextEx = DEFAULT_CONTEXTEX;
  238. }
  239. RegCloseKey(hkey);
  240. exit:
  241. SET_DEBUG_PROPERTIES(dwLevelEx,dwFormatEx,dwContextEx);
  242. }
  243. /*++
  244. Routine Description:
  245. Calls the TAPI functions lineGetID, lineGetDevConfig, lineGetDevCaps, reads
  246. the Unimodem registry, and sets the following vars accordingly:
  247. pTG->hComm
  248. pTG->dwSpeakerVolume
  249. pTG->dwSpeakerMode
  250. pTG->fBlindDial
  251. pTG->dwPermanentLineID
  252. pTG->lpszPermanentLineID
  253. pTG->lpszUnimodemKey
  254. pTG->lpszUnimodemFaxKey
  255. pTG->ResponsesKeyName
  256. pszDeviceName - a buffer to hold device name (for PSSLog)
  257. Return Value:
  258. TRUE - success
  259. FALSE - failure
  260. --*/
  261. BOOL GetModemParams(PThrdGlbl pTG, LPTSTR pszDeviceName, DWORD dwDeviceNameSize)
  262. {
  263. DWORD dwNeededSize;
  264. LONG lRet=0;
  265. LPVARSTRING lpVarStr=0;
  266. LPDEVICEID lpDeviceID=0;
  267. LONG lResult=0;
  268. LPLINEDEVCAPS lpLineDevCaps;
  269. BYTE buf[ sizeof(LINEDEVCAPS)+1000 ];
  270. LPMDM_DEVSPEC lpDSpec;
  271. LPMODEMSETTINGS lpModemSettings;
  272. LPDEVCFG lpDevCfg;
  273. char rgchKey[MAX_REG_KEY_NAME_SIZE]={'\0'};
  274. HKEY hKey;
  275. DWORD dwType;
  276. DWORD dwSize;
  277. DEBUG_FUNCTION_NAME(_T("GetModemParams"));
  278. // get the handle to a Comm port
  279. //----------------------------------
  280. lpVarStr = (LPVARSTRING) MemAlloc(IDVARSTRINGSIZE);
  281. if (!lpVarStr)
  282. {
  283. DebugPrintEx(DEBUG_ERR,"Couldn't allocate space for lpVarStr");
  284. pTG->fFatalErrorWasSignaled = 1;
  285. SignalStatusChange(pTG, FS_FATAL_ERROR);
  286. return FALSE;
  287. }
  288. _fmemset(lpVarStr, 0, IDVARSTRINGSIZE);
  289. lpVarStr->dwTotalSize = IDVARSTRINGSIZE;
  290. DebugPrintEx(DEBUG_MSG,"Calling lineGetId");
  291. lRet = lineGetID(pTG->LineHandle,
  292. 0, // +++ addr
  293. pTG->CallHandle,
  294. LINECALLSELECT_CALL, // dwSelect,
  295. lpVarStr, //lpDeviceID,
  296. "comm/datamodem" ); //lpszDeviceClass
  297. if (lRet)
  298. {
  299. DebugPrintEx( DEBUG_ERR,
  300. "lineGetID returns error 0x%lx",
  301. (unsigned long) lRet);
  302. MemFree (lpVarStr);
  303. pTG->fFatalErrorWasSignaled = 1;
  304. SignalStatusChange(pTG, FS_LINE_UNAVAILABLE);
  305. return FALSE;
  306. }
  307. DebugPrintEx(DEBUG_MSG,"lineGetId returned SUCCESS");
  308. // extract id
  309. if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY)
  310. {
  311. DebugPrintEx(DEBUG_ERR,"String format is not binary");
  312. MemFree (lpVarStr);
  313. pTG->fFatalErrorWasSignaled = 1;
  314. SignalStatusChange(pTG, FS_FATAL_ERROR);
  315. return FALSE;
  316. }
  317. if (lpVarStr->dwUsedSize<sizeof(DEVICEID))
  318. {
  319. DebugPrintEx(DEBUG_ERR,"linegetid : Varstring size too small");
  320. MemFree (lpVarStr);
  321. pTG->fFatalErrorWasSignaled = 1;
  322. SignalStatusChange(pTG, FS_FATAL_ERROR);
  323. return FALSE;
  324. }
  325. lpDeviceID = (LPDEVICEID) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset);
  326. DebugPrintEx( DEBUG_MSG,
  327. "lineGetID returns handle 0x%08lx, \"%s\"",
  328. (ULONG_PTR) lpDeviceID->hComm,
  329. (LPSTR) lpDeviceID->szDeviceName);
  330. pTG->hComm = lpDeviceID->hComm;
  331. if (NULL != lpDeviceID->szDeviceName)
  332. {
  333. // save device name - for PSSLog
  334. _tcsncpy(pszDeviceName, lpDeviceID->szDeviceName, dwDeviceNameSize);
  335. pszDeviceName[dwDeviceNameSize-1] = TEXT('\0');
  336. }
  337. if (BAD_HANDLE(pTG->hComm))
  338. {
  339. DebugPrintEx(DEBUG_ERR,"lineGetID returns NULL hComm");
  340. pTG->hComm = NULL;
  341. MemFree (lpVarStr);
  342. pTG->fFatalErrorWasSignaled = 1;
  343. SignalStatusChange(pTG, FS_FATAL_ERROR);
  344. return FALSE;
  345. }
  346. // get the Modem configuration (speaker, etc.) from TAPI
  347. //------------------------------------------------------
  348. _fmemset(lpVarStr, 0, IDVARSTRINGSIZE);
  349. lpVarStr->dwTotalSize = IDVARSTRINGSIZE;
  350. lResult = lineGetDevConfig(pTG->DeviceId,
  351. lpVarStr,
  352. "comm/datamodem");
  353. if (lResult)
  354. {
  355. if (lpVarStr->dwTotalSize < lpVarStr->dwNeededSize)
  356. {
  357. dwNeededSize = lpVarStr->dwNeededSize;
  358. MemFree (lpVarStr);
  359. if ( ! (lpVarStr = (LPVARSTRING) MemAlloc(dwNeededSize) ) )
  360. {
  361. DebugPrintEx( DEBUG_ERR,
  362. "Can't allocate %d bytes for lineGetDevConfig",
  363. dwNeededSize);
  364. pTG->fFatalErrorWasSignaled = 1;
  365. SignalStatusChange(pTG, FS_FATAL_ERROR);
  366. return FALSE;
  367. }
  368. _fmemset(lpVarStr, 0, dwNeededSize);
  369. lpVarStr->dwTotalSize = dwNeededSize;
  370. lResult = lineGetDevConfig(pTG->DeviceId,
  371. lpVarStr,
  372. "comm/datamodem");
  373. if (lResult)
  374. {
  375. DebugPrintEx( DEBUG_ERR,
  376. "lineGetDevConfig returns %x, le=%x",
  377. lResult, GetLastError() );
  378. MemFree (lpVarStr);
  379. pTG->fFatalErrorWasSignaled = 1;
  380. SignalStatusChange(pTG, FS_FATAL_ERROR);
  381. return FALSE;
  382. }
  383. }
  384. else
  385. {
  386. DebugPrintEx( DEBUG_ERR,
  387. "1st lineGetDevConfig returns %x, le=%x",
  388. lResult, GetLastError() );
  389. MemFree (lpVarStr);
  390. pTG->fFatalErrorWasSignaled = 1;
  391. SignalStatusChange(pTG, FS_FATAL_ERROR);
  392. return FALSE;
  393. }
  394. }
  395. //
  396. // extract DEVCFG
  397. //
  398. if (lpVarStr->dwStringFormat != STRINGFORMAT_BINARY)
  399. {
  400. DebugPrintEx(DEBUG_ERR,"String format is not binary for lineGetDevConfig");
  401. MemFree (lpVarStr);
  402. pTG->fFatalErrorWasSignaled = 1;
  403. SignalStatusChange(pTG, FS_FATAL_ERROR);
  404. return FALSE;
  405. }
  406. if (lpVarStr->dwUsedSize<sizeof(DEVCFG))
  407. {
  408. DebugPrintEx(DEBUG_ERR,"lineGetDevConfig: Varstring size returned too small");
  409. MemFree (lpVarStr);
  410. pTG->fFatalErrorWasSignaled = 1;
  411. SignalStatusChange(pTG, FS_FATAL_ERROR);
  412. return FALSE;
  413. }
  414. lpDevCfg = (LPDEVCFG) ((LPBYTE)(lpVarStr)+lpVarStr->dwStringOffset);
  415. lpModemSettings = (LPMODEMSETTINGS) ( (LPBYTE) &(lpDevCfg->commconfig.wcProviderData) );
  416. pTG->dwSpeakerVolume = lpModemSettings->dwSpeakerVolume;
  417. pTG->dwSpeakerMode = lpModemSettings->dwSpeakerMode;
  418. if ( lpModemSettings->dwPreferredModemOptions & MDM_BLIND_DIAL )
  419. {
  420. pTG->fBlindDial = 1;
  421. }
  422. else
  423. {
  424. pTG->fBlindDial = 0;
  425. }
  426. DebugPrintEx( DEBUG_MSG,
  427. "lineGetDevConfig returns SpeakerVolume=%x, "
  428. "Mode=%x BlindDial=%d",
  429. pTG->dwSpeakerVolume, pTG->dwSpeakerMode, pTG->fBlindDial);
  430. MemFree (lpVarStr);
  431. lpVarStr=0;
  432. // get dwPermanentLineID
  433. // ---------------------------
  434. lpLineDevCaps = (LPLINEDEVCAPS) buf;
  435. _fmemset(lpLineDevCaps, 0, sizeof (buf) );
  436. lpLineDevCaps->dwTotalSize = sizeof(buf);
  437. lResult = lineGetDevCaps(gT30.LineAppHandle,
  438. pTG->DeviceId,
  439. TAPI_VERSION,
  440. 0,
  441. lpLineDevCaps);
  442. if (lResult)
  443. {
  444. DebugPrintEx(DEBUG_ERR,"lineGetDevCaps failed");
  445. pTG->fFatalErrorWasSignaled = 1;
  446. SignalStatusChange(pTG, FS_FATAL_ERROR);
  447. return FALSE;
  448. }
  449. if (lpLineDevCaps->dwNeededSize > lpLineDevCaps->dwTotalSize)
  450. {
  451. DebugPrintEx(DEBUG_ERR,"lineGetDevCaps NOT enough MEMORY");
  452. pTG->fFatalErrorWasSignaled = 1;
  453. SignalStatusChange(pTG, FS_FATAL_ERROR);
  454. return FALSE;
  455. }
  456. // Save the permanent ID.
  457. //------------------------
  458. pTG->dwPermanentLineID = lpLineDevCaps->dwPermanentLineID;
  459. _stprintf (pTG->lpszPermanentLineID, "%08X\\Modem", pTG->dwPermanentLineID);
  460. DebugPrintEx(DEBUG_MSG,"Permanent Line ID=%s", pTG->lpszPermanentLineID);
  461. // Get the Unimodem key name for this device
  462. //------------------------------------------
  463. lpDSpec = (LPMDM_DEVSPEC) ( ( (LPBYTE) lpLineDevCaps) + lpLineDevCaps->dwDevSpecificOffset);
  464. if ( (lpLineDevCaps->dwDevSpecificSize < sizeof(MDM_DEVSPEC) ) ||
  465. (lpLineDevCaps->dwDevSpecificSize <= lpDSpec->dwKeyOffset) )
  466. {
  467. DebugPrintEx( DEBUG_ERR,
  468. "Devspecifc caps size is only %lu",
  469. (unsigned long) lpLineDevCaps->dwDevSpecificSize );
  470. pTG->fFatalErrorWasSignaled = 1;
  471. SignalStatusChange(pTG, FS_FATAL_ERROR);
  472. return FALSE;
  473. }
  474. else
  475. {
  476. UINT u = lpLineDevCaps->dwDevSpecificSize - lpDSpec->dwKeyOffset;
  477. if ( (lpDSpec->dwContents != 1) || (lpDSpec->dwKeyOffset != 8 ) )
  478. {
  479. DebugPrintEx( DEBUG_ERR,
  480. "Nonstandard Devspecific: dwContents=%lu; "
  481. "dwKeyOffset=%lu",
  482. (unsigned long) lpDSpec->dwContents,
  483. (unsigned long) lpDSpec->dwKeyOffset );
  484. pTG->fFatalErrorWasSignaled = 1;
  485. SignalStatusChange(pTG, FS_FATAL_ERROR);
  486. return FALSE;
  487. }
  488. if (u)
  489. {
  490. if ( u + lstrlen("\\FAX") >= MAX_REG_KEY_NAME_SIZE)
  491. {
  492. //
  493. // can't hold this registry key name string.
  494. //
  495. DebugPrintEx(DEBUG_ERR,"Unimodem fax key is too long. (%ld characters)",u);
  496. pTG->fFatalErrorWasSignaled = 1;
  497. SignalStatusChange(pTG, FS_FATAL_ERROR);
  498. return FALSE;
  499. }
  500. _fmemcpy(rgchKey, lpDSpec->rgby, u);
  501. if (rgchKey[u])
  502. {
  503. DebugPrintEx(DEBUG_ERR,"rgchKey not null terminated!");
  504. rgchKey[u-1]=0;
  505. }
  506. //
  507. // Get ResponsesKeyName
  508. //
  509. lRet = RegOpenKeyEx(
  510. HKEY_LOCAL_MACHINE,
  511. rgchKey,
  512. 0,
  513. KEY_READ,
  514. &hKey);
  515. if (lRet != ERROR_SUCCESS)
  516. {
  517. DebugPrintEx(DEBUG_ERR,"Can't read Unimodem key %s",rgchKey);
  518. pTG->fFatalErrorWasSignaled = 1;
  519. SignalStatusChange(pTG, FS_FATAL_ERROR);
  520. return FALSE;
  521. }
  522. dwSize = sizeof( pTG->ResponsesKeyName);
  523. lRet = RegQueryValueEx(
  524. hKey,
  525. "ResponsesKeyName",
  526. 0,
  527. &dwType,
  528. pTG->ResponsesKeyName,
  529. &dwSize);
  530. RegCloseKey(hKey);
  531. if (lRet != ERROR_SUCCESS)
  532. {
  533. DebugPrintEx( DEBUG_ERR,
  534. "Can't read Unimodem key\\ResponsesKeyName %s",
  535. rgchKey);
  536. pTG->fFatalErrorWasSignaled = 1;
  537. SignalStatusChange(pTG, FS_FATAL_ERROR);
  538. return FALSE;
  539. }
  540. lstrcpyn(pTG->lpszUnimodemKey, rgchKey, ARR_SIZE(pTG->lpszUnimodemKey));
  541. // Append "\\Fax" to the key
  542. u = lstrlen(rgchKey);
  543. if (u)
  544. {
  545. lstrcpy(rgchKey+u, (LPSTR) "\\FAX");
  546. }
  547. lstrcpyn(pTG->lpszUnimodemFaxKey, rgchKey, ARR_SIZE(pTG->lpszUnimodemFaxKey));
  548. DebugPrintEx( DEBUG_MSG,
  549. "Unimodem Fax key=%s",
  550. pTG->lpszUnimodemFaxKey);
  551. }
  552. }
  553. return TRUE;
  554. }
  555. ///////////////////////////////////////////////////////////////////////////////////
  556. BOOL WINAPI
  557. FaxDevInitializeA(
  558. IN HLINEAPP LineAppHandle,
  559. IN HANDLE HeapHandle,
  560. OUT PFAX_LINECALLBACK *LineCallbackFunction,
  561. IN PFAX_SERVICE_CALLBACK FaxServiceCallback
  562. )
  563. /*++
  564. Routine Description:
  565. Device Provider Initialization.
  566. Arguments:
  567. Return Value:
  568. --*/
  569. { int i;
  570. LONG lRet;
  571. HKEY hKey;
  572. DWORD dwType;
  573. DWORD dwSizeNeed;
  574. OPEN_DEBUG_FILE_SIZE(T30_DEBUG_LOG_FILE, T30_MAX_LOG_SIZE);
  575. {
  576. DEBUG_FUNCTION_NAME(_T("FaxDevInitializeA"));
  577. T30CritSectionInit = 0;
  578. T30RecoveryCritSectionInit = 0;
  579. debugReadFromRegistry();
  580. if (!LineAppHandle)
  581. {
  582. Assert(FALSE);
  583. DebugPrintEx(DEBUG_ERR,"called with INVALID_HANDLE_VALUE LineAppHandle");
  584. goto error;
  585. }
  586. if (HeapHandle==NULL || HeapHandle==INVALID_HANDLE_VALUE)
  587. {
  588. Assert(FALSE);
  589. DebugPrintEx(DEBUG_ERR,"called with NULL/INVALID_HANDLE_VALUE HeapHandle");
  590. goto error;
  591. }
  592. if (LineCallbackFunction==NULL)
  593. {
  594. Assert(FALSE);
  595. DebugPrintEx(DEBUG_ERR,"called with NULL LineCallbackFunction");
  596. goto error;
  597. }
  598. gT30.LineAppHandle = LineAppHandle;
  599. gT30.HeapHandle = HeapHandle;
  600. gT30.fInit = TRUE;
  601. *LineCallbackFunction = T30LineCallBackFunction;
  602. for (i=1; i<MAX_T30_CONNECT; i++)
  603. {
  604. T30Inst[i].fAvail = TRUE;
  605. T30Inst[i].pT30 = NULL;
  606. }
  607. if (FAILED(SafeInitializeCriticalSection(&T30CritSection)))
  608. {
  609. DWORD ec = GetLastError();
  610. DebugPrintEx(
  611. DEBUG_ERR,
  612. TEXT("InitializeCriticalSection(&T30CritSection) failed: err = %d"),
  613. ec);
  614. goto error;
  615. }
  616. T30CritSectionInit = 1;
  617. for (i=0; i<MAX_T30_CONNECT; i++)
  618. {
  619. T30Recovery[i].fAvail = TRUE;
  620. }
  621. if (FAILED(SafeInitializeCriticalSection(&T30RecoveryCritSection)))
  622. {
  623. DWORD ec = GetLastError();
  624. DebugPrintEx(
  625. DEBUG_ERR,
  626. TEXT("InitializeCriticalSection(&T30RecoveryCritSection) failed: err = %d"),
  627. ec);
  628. goto error;
  629. }
  630. T30RecoveryCritSectionInit = 1;
  631. lRet = RegOpenKeyEx(
  632. HKEY_LOCAL_MACHINE,
  633. REGKEY_DEVICE_PROVIDER_KEY TEXT("\\") REGVAL_T30_PROVIDER_GUID_STRING,
  634. 0,
  635. KEY_READ,
  636. &hKey);
  637. if (lRet == ERROR_SUCCESS)
  638. {
  639. dwSizeNeed = sizeof(int);
  640. lRet = RegQueryValueEx(
  641. hKey,
  642. "MaxErrorLinesPerPage",
  643. 0,
  644. &dwType,
  645. (LPBYTE) &gT30.MaxErrorLinesPerPage,
  646. &dwSizeNeed);
  647. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) )
  648. {
  649. gT30.MaxErrorLinesPerPage = 110;
  650. }
  651. dwSizeNeed = sizeof(int);
  652. lRet = RegQueryValueEx(
  653. hKey,
  654. "MaxConsecErrorLinesPerPage",
  655. 0,
  656. &dwType,
  657. (LPBYTE) &gT30.MaxConsecErrorLinesPerPage,
  658. &dwSizeNeed);
  659. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) )
  660. {
  661. gT30.MaxConsecErrorLinesPerPage = 110;
  662. }
  663. //
  664. // Exception Handling enable / disable
  665. //
  666. dwSizeNeed = sizeof(DWORD);
  667. // Number of Re-transmittion retries before we start drop speed (default: 1)
  668. lRet = RegQueryValueEx(
  669. hKey,
  670. "RetriesBeforeDropSpeed",
  671. 0,
  672. &dwType,
  673. (LPBYTE) &(gRTNRetries.RetriesBeforeDropSpeed),
  674. &dwSizeNeed);
  675. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) )
  676. {
  677. gRTNRetries.RetriesBeforeDropSpeed = DEF_RetriesBeforeDropSpeed;
  678. }
  679. dwSizeNeed = sizeof(DWORD);
  680. // Number of Re-transmittion retries before we do DCN (default: 3)
  681. lRet = RegQueryValueEx(
  682. hKey,
  683. "RetriesBeforeDCN",
  684. 0,
  685. &dwType,
  686. (LPBYTE) &(gRTNRetries.RetriesBeforeDCN),
  687. &dwSizeNeed);
  688. if ( ( lRet != ERROR_SUCCESS) || (dwType != REG_DWORD) )
  689. {
  690. gRTNRetries.RetriesBeforeDCN = DEF_RetriesBeforeDCN;
  691. }
  692. if (gRTNRetries.RetriesBeforeDCN < gRTNRetries.RetriesBeforeDropSpeed)
  693. {
  694. // Should not be, so use default if it so
  695. gRTNRetries.RetriesBeforeDropSpeed = DEF_RetriesBeforeDropSpeed;
  696. gRTNRetries.RetriesBeforeDCN = DEF_RetriesBeforeDCN;
  697. }
  698. }
  699. else
  700. {
  701. // If there is no such entry in the registry, this vars must have values,
  702. gRTNRetries.RetriesBeforeDropSpeed = DEF_RetriesBeforeDropSpeed;
  703. gRTNRetries.RetriesBeforeDCN = DEF_RetriesBeforeDCN;
  704. }
  705. DebugPrintEx( DEBUG_MSG,
  706. "Retries policy: RetriesBeforeDropSpeed = %d , "
  707. "RetriesBeforeDCN = %d",
  708. gRTNRetries.RetriesBeforeDropSpeed,
  709. gRTNRetries.RetriesBeforeDCN);
  710. // temp. directory
  711. gT30.dwLengthTmpDirectory = GetTempPathA (_MAX_FNAME - 15, gT30.TmpDirectory);
  712. if (gT30.dwLengthTmpDirectory > _MAX_FNAME - 15)
  713. {
  714. DebugPrintEx( DEBUG_ERR,
  715. "GetTempPathA needs %d have %d bytes",
  716. gT30.dwLengthTmpDirectory,
  717. (_MAX_FNAME - 15) );
  718. goto error;
  719. }
  720. if (!gT30.dwLengthTmpDirectory)
  721. {
  722. DebugPrintEx(DEBUG_ERR,"GetTempPathA fails le=%x",GetLastError());
  723. goto error;
  724. }
  725. DebugPrintEx( DEBUG_MSG,
  726. "hLineApp=%x heap=%x TempDir=%s Len=%d at %ld",
  727. LineAppHandle,
  728. HeapHandle,
  729. gT30.TmpDirectory,
  730. gT30.dwLengthTmpDirectory,
  731. GetTickCount() );
  732. gT30.Status = STATUS_OK;
  733. CLOSE_DEBUG_FILE;
  734. return (TRUE);
  735. }
  736. error:
  737. if (T30CritSectionInit == 1)
  738. {
  739. DeleteCriticalSection(&T30CritSection);
  740. T30CritSectionInit = 0;
  741. }
  742. if (T30RecoveryCritSectionInit == 1)
  743. {
  744. DeleteCriticalSection(&T30RecoveryCritSection);
  745. T30RecoveryCritSectionInit = 0;
  746. }
  747. CLOSE_DEBUG_FILE;
  748. return (FALSE);
  749. }
  750. ///////////////////////////////////////////////////////////////////////////////////
  751. BOOL WINAPI
  752. FaxDevStartJobA(
  753. HLINE LineHandle,
  754. DWORD DeviceId,
  755. PHANDLE pFaxHandle,
  756. HANDLE CompletionPortHandle,
  757. ULONG_PTR CompletionKey
  758. )
  759. /*++
  760. Routine Description:
  761. Device Provider Initialization. Synopsis:
  762. * Allocate ThreadGlobal, find place in T30Inst
  763. * Initialize fields, CreateEvent(s)
  764. Arguments:
  765. Return Value:
  766. --*/
  767. {
  768. PThrdGlbl pTG = NULL;
  769. DWORD i = 0;
  770. BOOL fFound = FALSE;
  771. OPEN_DEBUG_FILE_SIZE(T30_DEBUG_LOG_FILE, T30_MAX_LOG_SIZE);
  772. debugReadFromRegistry();
  773. {
  774. DEBUG_FUNCTION_NAME(_T("FaxDevStartJobA"));
  775. if (!pFaxHandle)
  776. {
  777. Assert(FALSE);
  778. DebugPrintEx(DEBUG_ERR,"called with NULL pFaxHandle");
  779. return FALSE;
  780. }
  781. DebugPrintEx(
  782. DEBUG_MSG,
  783. "LineHandle=%x, DevID=%x, pFaxH=%x Port=%x, Key=%x at %ld",
  784. LineHandle,
  785. DeviceId,
  786. pFaxHandle,
  787. CompletionPortHandle,
  788. CompletionKey,
  789. GetTickCount()
  790. );
  791. if (InterlockedIncrement(&gT30.CntConnect) >= MAX_T30_CONNECT)
  792. {
  793. DebugPrintEx( DEBUG_ERR,
  794. "Exceeded # of connections (curr=%d, allowed=%d)",
  795. gT30.CntConnect, MAX_T30_CONNECT );
  796. goto ErrorExit;
  797. }
  798. // Alloc memory for pTG, fill it with zeros.
  799. if ( (pTG = (PThrdGlbl) T30AllocThreadGlobalData() ) == NULL )
  800. {
  801. DebugPrintEx(DEBUG_ERR,"can't malloc");
  802. goto ErrorExit;
  803. }
  804. EnterCriticalSection(&T30CritSection);
  805. for (i=1; i<MAX_T30_CONNECT; i++)
  806. {
  807. if (T30Inst[i].fAvail)
  808. {
  809. T30Inst[i].pT30 = (LPVOID) pTG;
  810. T30Inst[i].fAvail = FALSE;
  811. *pFaxHandle = ULongToHandle(i);
  812. fFound = TRUE;
  813. break;
  814. }
  815. }
  816. LeaveCriticalSection(&T30CritSection);
  817. if (!fFound)
  818. {
  819. DebugPrintEx( DEBUG_ERR,
  820. "can't find avail place in T30Inst "
  821. "table. # of connections (curr=%d, allowed=%d)",
  822. gT30.CntConnect, MAX_T30_CONNECT );
  823. goto ErrorExit;
  824. }
  825. pTG->LineHandle = LineHandle;
  826. pTG->DeviceId = DeviceId;
  827. pTG->FaxHandle = (HANDLE) pTG;
  828. pTG->CompletionPortHandle = CompletionPortHandle;
  829. pTG->CompletionKey = CompletionKey;
  830. // initialization
  831. //---------------------------
  832. if ((pTG->hevAsync = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  833. {
  834. /////////////////////////////////////////////////////////////////////////////
  835. // this is used to get notification from TAPI about the call
  836. // the event is reset in itapi_async_setup
  837. // we wait on the event is itapi_async_wait
  838. // the event is set in itapi_async_signal when we get LINE_REPLY from TAPI
  839. /////////////////////////////////////////////////////////////////////////////
  840. goto ErrorExit;
  841. }
  842. if ((pTG->ThrdSignal = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  843. {
  844. /////////////////////////////////////////////////////////////////////////////
  845. // this is used to communicate between the send/receive operation and
  846. // the threads that process the TIFF
  847. // in case we're SENDING:
  848. // the event is reset in ICommGetSendBuf
  849. // we wait on the event in TiffConvertThread in order to prepare more pages
  850. // the event is set in ICommGetSendBuf when we want more pages to be ready
  851. // in case we're RECEIVING:
  852. // the event is never explicitly reset
  853. // we wait on the event in DecodeFaxPageAsync in order to dump the received
  854. // strip on data to the TIFF file
  855. // the event is set in ICommPutRecvBuf when a new strip has been received
  856. /////////////////////////////////////////////////////////////////////////////
  857. goto ErrorExit;
  858. }
  859. if ((pTG->ThrdDoneSignal = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  860. {
  861. /////////////////////////////////////////////////////////////////////////////
  862. // this is used to communicate between the receive operation and
  863. // the thread that processes the TIFF (prepares the page)
  864. // the event is reset in ICommPutRecvBuf when we get RECV_STARTPAGE
  865. // we wait on the event in ICommPutRecvBuf to mark the end of prev page
  866. // and to signal when it's ok to delete the intermediate files
  867. // the event is set in PageAckThread when the page is prepared (TIFF file ok)
  868. /////////////////////////////////////////////////////////////////////////////
  869. goto ErrorExit;;
  870. }
  871. if ((pTG->ThrdAckTerminateSignal = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  872. {
  873. /////////////////////////////////////////////////////////////////////////////
  874. // this is used to communicate between the send/receive operation and
  875. // the threads that process the TIFF
  876. // in case we're SENDING:
  877. // the event is never explicitly reset
  878. // we wait on the event in FaxDevSendA to make sure the page is fully sent
  879. // the event is set at the end of TiffConvertThread thread
  880. // in case we're RECEIVING:
  881. // the event is never explicitly reset
  882. // we wait on the event in FaxDevReceiveA to make sure the page is fully in.
  883. // the event is set at the end of PageAckThread thread
  884. /////////////////////////////////////////////////////////////////////////////
  885. goto ErrorExit;
  886. }
  887. if ((pTG->FirstPageReadyTxSignal = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  888. {
  889. /////////////////////////////////////////////////////////////////////////////
  890. // this is used to communicate between the send operation and
  891. // the thread that processes the TIFF (prepares the data to be sent)
  892. // the event is never explicitly reset
  893. // we wait on the event in ICommGetSendBuf when we want some data to send
  894. // the event is set in TiffConvertThread after each page is ready to send
  895. /////////////////////////////////////////////////////////////////////////////
  896. goto ErrorExit;
  897. }
  898. if ((pTG->AbortReqEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) == NULL)
  899. {
  900. /////////////////////////////////////////////////////////////////////////////
  901. // this is used to signal an abort request came in
  902. // the event is set in FaxDevAbortOperationA only
  903. // we wait on the event in many places: FComFilterFillCache
  904. // FComFilterReadBuf
  905. // FComGetOneChar
  906. // ICommPutRecvBuf
  907. // DecodeFaxPageAsync
  908. // itapi_async_wait
  909. // TiffConvertThread
  910. // the event may be reset in all those places.
  911. // THIS IS THE WAY THE ABORT WORKS:
  912. // when we get an abort event, then we quit everything in general
  913. // the exception is when we have permission to ignore the abort for a while
  914. // this permission may be granted by setting the fOkToResetAbortReqEvent flag
  915. // if it is set it means we're on the way out anyway so the abort is meaningless
  916. // or that we're in a critical i/o operation that we don't want to abort.
  917. // So if this flag is set, we reset the event and continue operation.
  918. // The saga continues...
  919. // since we ignored a legtimate abort request, we set fAbortReqEventWasReset
  920. // flag to make sure that resetting the event is done only once.
  921. // The actual abort operation is checked against the fAbortRequested flag
  922. // This flag is used everywhere to check if we need to abort.
  923. // the only excuse for the event is to help us escape long
  924. // WaitForMultipleObject calls.
  925. // When we have permission to reset the event, the fAbortRequested is still
  926. // on (even though the event was reset) and the next piece of code
  927. // which checks for an abort will decide that it's a true abort.
  928. // The only thing left to complete this story is to describe when do we
  929. // have permission to reset the event:
  930. // 1. when we're receiving we can always reset the abort event
  931. // 2. when we're sending we can reset it until the end of PhaseB
  932. // 3. when the imaging threads are done we can reset it (on the way out anyway)
  933. /////////////////////////////////////////////////////////////////////////////
  934. goto ErrorExit;
  935. }
  936. if ((pTG->AbortAckEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
  937. {
  938. /////////////////////////////////////////////////////////////////////////////
  939. // this is used to communicate between the send/receive operation and
  940. // the abort thread
  941. // the event is reset
  942. // we wait on the event in
  943. // the event is set at the end of FaxDevSend and FaxDevReceice
  944. /////////////////////////////////////////////////////////////////////////////
  945. goto ErrorExit;
  946. }
  947. pTG->fWaitingForEvent = FALSE;
  948. pTG->fDeallocateCall = 0;
  949. MyAllocInit(pTG);
  950. pTG->StatusId = 0;
  951. pTG->StringId = 0;
  952. pTG->PageCount = 0;
  953. pTG->CSI = 0;
  954. pTG->CallerId[0] = 0;
  955. pTG->RoutingInfo = 0;
  956. // helper image threads sync. flags
  957. pTG->AckTerminate = 1;
  958. pTG->fOkToResetAbortReqEvent = TRUE;
  959. pTG->Inst.awfi.fLastPage = 0;
  960. CLOSE_DEBUG_FILE;
  961. return (TRUE);
  962. ErrorExit:
  963. InterlockedDecrement(&gT30.CntConnect);
  964. if(pTG)
  965. {
  966. CloseHandle(pTG->hevAsync);
  967. CloseHandle(pTG->ThrdSignal);
  968. CloseHandle(pTG->ThrdDoneSignal);
  969. CloseHandle(pTG->ThrdAckTerminateSignal);
  970. CloseHandle(pTG->FirstPageReadyTxSignal);
  971. CloseHandle(pTG->AbortReqEvent);
  972. CloseHandle(pTG->AbortAckEvent);
  973. MemFree(pTG);
  974. }
  975. if (fFound) // So we have to free i entry.
  976. {
  977. EnterCriticalSection(&T30CritSection);
  978. T30Inst[i].fAvail = TRUE; // Mark the entry as free.
  979. T30Inst[i].pT30 = NULL;
  980. LeaveCriticalSection(&T30CritSection);
  981. }
  982. CLOSE_DEBUG_FILE;
  983. return (FALSE);
  984. }
  985. }
  986. ///////////////////////////////////////////////////////////////////////////////////
  987. BOOL WINAPI
  988. FaxDevEndJobA(HANDLE FaxHandle)
  989. /*++
  990. Routine Description:
  991. Device Provider Initialization.
  992. Arguments:
  993. Device Provider Cleanup. Synopsis:
  994. * Find ThreadGlobal in T30Inst
  995. * CloseHandle(s), MemFree, etc.
  996. * Free entry in T30Inst
  997. Return Value:
  998. --*/
  999. {
  1000. PThrdGlbl pTG=NULL;
  1001. LONG_PTR i;
  1002. OPEN_DEBUG_FILE_SIZE(T30_DEBUG_LOG_FILE, T30_MAX_LOG_SIZE);
  1003. {
  1004. DEBUG_FUNCTION_NAME(_T("FaxDevEndJobA"));
  1005. DebugPrintEx(DEBUG_MSG,"FaxHandle=%x", FaxHandle);
  1006. // find instance data
  1007. //------------------------
  1008. i = (LONG_PTR) FaxHandle;
  1009. if (i < 1 || i >= MAX_T30_CONNECT)
  1010. {
  1011. DebugPrintEx(DEBUG_ERR,"got wrong FaxHandle=%d", i);
  1012. CLOSE_DEBUG_FILE;
  1013. return (FALSE);
  1014. }
  1015. if (T30Inst[i].fAvail)
  1016. {
  1017. DebugPrintEx(DEBUG_ERR,"got wrong FaxHandle (marked as free) %d", i);
  1018. CLOSE_DEBUG_FILE;
  1019. return (FALSE);
  1020. }
  1021. pTG = (PThrdGlbl) T30Inst[i].pT30;
  1022. if (pTG->hevAsync)
  1023. {
  1024. CloseHandle(pTG->hevAsync);
  1025. }
  1026. if (pTG->StatusId == FS_NOT_FAX_CALL)
  1027. {
  1028. if (pTG->hComm)
  1029. {
  1030. CloseHandle( pTG->hComm );
  1031. pTG->hComm = NULL;
  1032. }
  1033. }
  1034. if (pTG->ThrdSignal)
  1035. {
  1036. CloseHandle(pTG->ThrdSignal);
  1037. }
  1038. if (pTG->ThrdDoneSignal)
  1039. {
  1040. CloseHandle(pTG->ThrdDoneSignal);
  1041. }
  1042. if (pTG->ThrdAckTerminateSignal)
  1043. {
  1044. CloseHandle(pTG->ThrdAckTerminateSignal);
  1045. }
  1046. if (pTG->FirstPageReadyTxSignal)
  1047. {
  1048. CloseHandle(pTG->FirstPageReadyTxSignal);
  1049. }
  1050. if (pTG->AbortReqEvent)
  1051. {
  1052. CloseHandle(pTG->AbortReqEvent);
  1053. }
  1054. if (pTG->AbortAckEvent)
  1055. {
  1056. CloseHandle(pTG->AbortAckEvent);
  1057. }
  1058. if (pTG->hThread)
  1059. {
  1060. CloseHandle(pTG->hThread);
  1061. }
  1062. MemFree(pTG->lpwFileName);
  1063. pTG->fRemoteIdAvail = 0;
  1064. if (pTG->RemoteID)
  1065. {
  1066. MemFree(pTG->RemoteID);
  1067. }
  1068. CleanModemInfStrings(pTG);
  1069. MemFree(pTG);
  1070. EnterCriticalSection(&T30CritSection);
  1071. T30Inst[i].fAvail = TRUE;
  1072. T30Inst[i].pT30 = NULL;
  1073. gT30.CntConnect--;
  1074. LeaveCriticalSection(&T30CritSection);
  1075. DebugPrintEx(DEBUG_MSG,"Handle %d", FaxHandle);
  1076. CLOSE_DEBUG_FILE;
  1077. return (TRUE);
  1078. }
  1079. }
  1080. ///////////////////////////////////////////////////////////////////////////////////
  1081. BOOL WINAPI
  1082. FaxDevSendA(
  1083. IN HANDLE FaxHandle,
  1084. IN PFAX_SEND_A FaxSend,
  1085. IN PFAX_SEND_CALLBACK FaxSendCallback
  1086. )
  1087. /*++
  1088. Routine Description:
  1089. Device provider send. Synopsis:
  1090. * Find ThreadGlobal in T30Inst
  1091. * TAPI: lineMakeCall
  1092. * itapi_async_wait (until LineCallBack sends TAPI message LINE_CALLSTATE)
  1093. * Add entry to recovery area
  1094. * GetModemParams
  1095. * Convert the destination# to a dialable
  1096. * If dial string contains special characters, check if the modem supports them
  1097. * T30ModemInit
  1098. * Open TIFF file to send
  1099. * FaxSendCallback
  1100. ****************** Send the fax
  1101. * Delete remaining temp files
  1102. * FaxDevCleanup
  1103. Arguments:
  1104. Return Value:
  1105. --*/
  1106. {
  1107. LONG_PTR i;
  1108. PThrdGlbl pTG=NULL;
  1109. LONG lRet;
  1110. DWORD dw;
  1111. LPSTR lpszFaxNumber;
  1112. LPLINECALLPARAMS lpCallParams;
  1113. HCALL CallHandle;
  1114. BYTE rgby [sizeof(LINETRANSLATEOUTPUT)+64];
  1115. LPLINETRANSLATEOUTPUT lplto1 = (LPLINETRANSLATEOUTPUT) rgby;
  1116. LPLINETRANSLATEOUTPUT lplto;
  1117. BOOL RetCode;
  1118. int fFound=0;
  1119. int RecoveryIndex = -1;
  1120. BOOL bDialBilling = FALSE;
  1121. BOOL bDialQuiet = FALSE;
  1122. BOOL bDialDialTone = FALSE;
  1123. LPCOMMPROP lpCommProp = NULL;
  1124. TCHAR szDeviceName[MAX_DEVICE_NAME_SIZE] = {'\0'}; // used for PSSLog
  1125. DWORD dwLineReplyParam = 0;
  1126. OPEN_DEBUG_FILE_SIZE(T30_DEBUG_LOG_FILE, T30_MAX_LOG_SIZE);
  1127. __try
  1128. {
  1129. DEBUG_FUNCTION_NAME(_T("FaxDevSendA"));
  1130. DebugPrintEx( DEBUG_MSG,
  1131. "FaxHandle=%x, FaxSend=%x, FaxSendCallback=%x at %ld",
  1132. FaxHandle, FaxSend, FaxSendCallback, GetTickCount() );
  1133. // find instance data
  1134. //------------------------
  1135. i = (LONG_PTR) FaxHandle;
  1136. if (i < 1 || i >= MAX_T30_CONNECT)
  1137. {
  1138. MemFree(FaxSend->FileName);
  1139. MemFree(FaxSend->CallerName);
  1140. MemFree(FaxSend->CallerNumber);
  1141. MemFree(FaxSend->ReceiverName);
  1142. MemFree(FaxSend->ReceiverNumber);
  1143. CLOSE_DEBUG_FILE;
  1144. return FALSE;
  1145. }
  1146. if (T30Inst[i].fAvail)
  1147. {
  1148. MemFree(FaxSend->FileName);
  1149. MemFree(FaxSend->CallerName);
  1150. MemFree(FaxSend->CallerNumber);
  1151. MemFree(FaxSend->ReceiverName);
  1152. MemFree(FaxSend->ReceiverNumber);
  1153. CLOSE_DEBUG_FILE;
  1154. return FALSE;
  1155. }
  1156. pTG = (PThrdGlbl) T30Inst[i].pT30;
  1157. pTG->RecoveryIndex = -1;
  1158. lpszFaxNumber = FaxSend->ReceiverNumber;
  1159. pTG->Operation = T30_TX;
  1160. // store LocalID
  1161. if (FaxSend->CallerNumber == NULL)
  1162. {
  1163. pTG->LocalID[0] = 0;
  1164. }
  1165. else
  1166. {
  1167. _fmemcpy(pTG->LocalID, FaxSend->CallerNumber, min (_fstrlen(FaxSend->CallerNumber), sizeof(pTG->LocalID) - 1) );
  1168. pTG->LocalID [ min (_fstrlen(FaxSend->CallerNumber), sizeof(pTG->LocalID) - 1) ] = 0;
  1169. }
  1170. // go to TAPI pass-through mode
  1171. //-------------------------------
  1172. lpCallParams = itapi_create_linecallparams();
  1173. if (!itapi_async_setup(pTG))
  1174. {
  1175. DebugPrintEx(DEBUG_ERR,"itapi_async_setup failed");
  1176. MemFree (lpCallParams);
  1177. pTG->fFatalErrorWasSignaled = 1;
  1178. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1179. RetCode = FALSE;
  1180. goto l_exit;
  1181. }
  1182. lRet = lineMakeCall (pTG->LineHandle,
  1183. &CallHandle,
  1184. lpszFaxNumber,
  1185. 0,
  1186. lpCallParams);
  1187. if (lRet < 0)
  1188. {
  1189. DebugPrintEx( DEBUG_ERR,
  1190. "lineMakeCall returns ERROR value 0x%lx",
  1191. (unsigned long) lRet);
  1192. pTG->fFatalErrorWasSignaled = 1;
  1193. SignalStatusChange(pTG, FS_LINE_UNAVAILABLE);
  1194. MemFree (lpCallParams);
  1195. RetCode = FALSE;
  1196. goto l_exit;
  1197. }
  1198. else
  1199. {
  1200. DebugPrintEx(DEBUG_MSG,"lineMakeCall returns 0x%lx",(unsigned long)lRet);
  1201. }
  1202. if (!itapi_async_wait(pTG, (DWORD)lRet, &dwLineReplyParam, NULL, ASYNC_TIMEOUT) ||
  1203. (dwLineReplyParam != 0) )
  1204. {
  1205. DebugPrintEx(DEBUG_ERR,"itapi_async_wait failed, dwLineReplyParam=%x", dwLineReplyParam);
  1206. pTG->fFatalErrorWasSignaled = 1;
  1207. SignalStatusChange(pTG, FS_LINE_UNAVAILABLE);
  1208. MemFree (lpCallParams);
  1209. RetCode = FALSE;
  1210. goto l_exit;
  1211. }
  1212. // now we wait for the connected message
  1213. //--------------------------------------
  1214. for (dw=50; dw<10000; dw = dw*120/100)
  1215. {
  1216. Sleep(dw);
  1217. if (pTG->fGotConnect)
  1218. break;
  1219. }
  1220. if (!pTG->fGotConnect)
  1221. {
  1222. DebugPrintEx(DEBUG_ERR,"Failure waiting for CONNECTED message....");
  1223. // We ignore... goto failure1;
  1224. }
  1225. MemFree (lpCallParams);
  1226. pTG->CallHandle = CallHandle;
  1227. //
  1228. // Add entry to the Recovery Area.
  1229. //
  1230. fFound = 0;
  1231. for (i=0; i<MAX_T30_CONNECT; i++)
  1232. {
  1233. if (T30Recovery[i].fAvail)
  1234. {
  1235. EnterCriticalSection(&T30RecoveryCritSection);
  1236. T30Recovery[i].fAvail = FALSE;
  1237. T30Recovery[i].ThreadId = GetCurrentThreadId();
  1238. T30Recovery[i].FaxHandle = FaxHandle;
  1239. T30Recovery[i].pTG = (LPVOID) pTG;
  1240. T30Recovery[i].LineHandle = pTG->LineHandle;
  1241. T30Recovery[i].CallHandle = CallHandle;
  1242. T30Recovery[i].DeviceId = pTG->DeviceId;
  1243. T30Recovery[i].CompletionPortHandle = pTG->CompletionPortHandle;
  1244. T30Recovery[i].CompletionKey = pTG->CompletionKey;
  1245. T30Recovery[i].TiffThreadId = 0;
  1246. T30Recovery[i].TimeStart = GetTickCount();
  1247. T30Recovery[i].TimeUpdated = T30Recovery[i].TimeStart;
  1248. T30Recovery[i].CkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail,
  1249. sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1);
  1250. LeaveCriticalSection(&T30RecoveryCritSection);
  1251. fFound = 1;
  1252. RecoveryIndex = (int)i;
  1253. pTG->RecoveryIndex = (int)i;
  1254. break;
  1255. }
  1256. }
  1257. if (! fFound)
  1258. {
  1259. DebugPrintEx(DEBUG_ERR,"Couldn't find available space for Recovery");
  1260. pTG->fFatalErrorWasSignaled = 1;
  1261. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1262. RetCode = FALSE;
  1263. goto l_exit;
  1264. }
  1265. RetCode = GetModemParams(pTG, szDeviceName, MAX_DEVICE_NAME_SIZE);
  1266. if (!RetCode)
  1267. {
  1268. DebugPrintEx(DEBUG_ERR,"GetModemParams failed");
  1269. goto l_exit;
  1270. }
  1271. // Convert the destination# to a dialable
  1272. //--------------------------------------------
  1273. // find out how big a buffer should be
  1274. //
  1275. _fmemset(rgby, 0, sizeof(rgby));
  1276. lplto1->dwTotalSize = sizeof(rgby);
  1277. lRet = lineTranslateAddress (gT30.LineAppHandle,
  1278. pTG->DeviceId,
  1279. TAPI_VERSION,
  1280. lpszFaxNumber,
  1281. 0, // dwCard
  1282. 0,
  1283. lplto1);
  1284. if (lRet)
  1285. {
  1286. DebugPrintEx(DEBUG_ERR,"Can't translate dest. address %s", lpszFaxNumber);
  1287. pTG->fFatalErrorWasSignaled = 1;
  1288. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1289. RetCode = FALSE;
  1290. goto l_exit;
  1291. }
  1292. if (lplto1->dwNeededSize <= 0)
  1293. {
  1294. DebugPrintEx(DEBUG_ERR,"Can't dwNeededSize<0 for Fax# %s", lpszFaxNumber);
  1295. pTG->fFatalErrorWasSignaled = 1;
  1296. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1297. RetCode = FALSE;
  1298. goto l_exit;
  1299. }
  1300. lplto = MemAlloc(lplto1->dwNeededSize);
  1301. if (! lplto)
  1302. {
  1303. DebugPrintEx(DEBUG_ERR,"Couldn't allocate space for lplto");
  1304. pTG->fFatalErrorWasSignaled = 1;
  1305. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1306. RetCode = FALSE;
  1307. goto l_exit;
  1308. }
  1309. lplto->dwTotalSize = lplto1->dwNeededSize;
  1310. lRet = lineTranslateAddress (gT30.LineAppHandle,
  1311. pTG->DeviceId,
  1312. TAPI_VERSION,
  1313. lpszFaxNumber,
  1314. 0, // dwCard
  1315. 0,
  1316. lplto);
  1317. if (lRet)
  1318. {
  1319. DebugPrintEx(DEBUG_ERR,"Can't translate dest. address %s", lpszFaxNumber);
  1320. MemFree(lplto);
  1321. pTG->fFatalErrorWasSignaled = 1;
  1322. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1323. RetCode = FALSE;
  1324. goto l_exit;
  1325. }
  1326. if ((lplto->dwNeededSize > lplto->dwTotalSize) || (lplto->dwDialableStringSize>=MAXPHONESIZE))
  1327. {
  1328. DebugPrintEx( DEBUG_ERR,
  1329. "NeedSize=%d > TotalSize=%d for Fax# %s",
  1330. lplto->dwNeededSize ,lplto->dwTotalSize, lpszFaxNumber);
  1331. MemFree(lplto);
  1332. pTG->fFatalErrorWasSignaled = 1;
  1333. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1334. RetCode = FALSE;
  1335. goto l_exit;
  1336. }
  1337. _fmemcpy (pTG->lpszDialDestFax, ( (char *) lplto) + lplto->dwDialableStringOffset, lplto->dwDialableStringSize);
  1338. DebugPrintEx(DEBUG_MSG,"Dialable Dest is %s", pTG->lpszDialDestFax);
  1339. OpenPSSLogFile(pTG, szDeviceName);
  1340. MemFree(lplto);
  1341. // check if the dial string contains '$', '@' or 'W'
  1342. if (_tcschr(pTG->lpszDialDestFax,_T('$'))!=NULL)
  1343. {
  1344. // the '$' means we're supposed to wait for a billing tone ('bong')
  1345. bDialBilling = TRUE;
  1346. }
  1347. if (_tcschr(pTG->lpszDialDestFax,_T('@'))!=NULL)
  1348. {
  1349. // the '@' means we're supposed to wait for quiet before dialing
  1350. bDialQuiet = TRUE;
  1351. }
  1352. if (_tcschr(pTG->lpszDialDestFax,_T('W'))!=NULL)
  1353. {
  1354. // the 'W' means we're supposed to wait for a dial tone before dialing
  1355. bDialDialTone = TRUE;
  1356. }
  1357. if (bDialBilling || bDialQuiet || bDialDialTone)
  1358. {
  1359. LPMODEMDEVCAPS lpModemDevCaps = NULL;
  1360. // dial string contains special characters, check if the modem supports them
  1361. lpCommProp = (LPCOMMPROP)LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  1362. sizeof(COMMPROP) + sizeof(MODEMDEVCAPS));
  1363. if (lpCommProp==NULL)
  1364. {
  1365. DebugPrintEx(DEBUG_ERR,"Couldn't allocate space for llpCommPropplto");
  1366. pTG->fFatalErrorWasSignaled = 1;
  1367. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1368. RetCode = FALSE;
  1369. goto l_exit;
  1370. }
  1371. lpCommProp->wPacketLength = sizeof(COMMPROP) + sizeof(MODEMDEVCAPS);
  1372. lpCommProp->dwProvSubType = PST_MODEM;
  1373. lpCommProp->dwProvSpec1 = COMMPROP_INITIALIZED;
  1374. if (!GetCommProperties(pTG->hComm,lpCommProp))
  1375. {
  1376. DebugPrintEx(DEBUG_ERR,"GetCommProperties failed (ec=%d)",GetLastError());
  1377. pTG->fFatalErrorWasSignaled = 1;
  1378. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1379. RetCode = FALSE;
  1380. goto l_exit;
  1381. }
  1382. // since dwProvSubType == PST_MODEM, lpCommProp->wcProvChar contains a MODEMDEVCAPS struct
  1383. lpModemDevCaps = (LPMODEMDEVCAPS)lpCommProp->wcProvChar;
  1384. if ((bDialBilling && !(lpModemDevCaps->dwDialOptions & DIALOPTION_BILLING)) ||
  1385. (bDialQuiet && !(lpModemDevCaps->dwDialOptions & DIALOPTION_QUIET)) ||
  1386. (bDialDialTone && !(lpModemDevCaps->dwDialOptions & DIALOPTION_DIALTONE)) )
  1387. {
  1388. // modem does not support special char, but char was specified, fail job
  1389. DebugPrintEx(DEBUG_ERR,"Unsupported char in dial string");
  1390. pTG->fFatalErrorWasSignaled = 1;
  1391. SignalStatusChangeWithStringId(pTG, FS_UNSUPPORTED_CHAR, IDS_UNSUPPORTED_CHARACTER);
  1392. RetCode = FALSE;
  1393. goto l_exit;
  1394. }
  1395. }
  1396. /// RSL -revisit, may decrease prty during computation
  1397. if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) )
  1398. {
  1399. DebugPrintEx( DEBUG_ERR,
  1400. "SetThreadPriority TIME CRITICAL failed le=%x",
  1401. GetLastError() );
  1402. }
  1403. //
  1404. // initialize modem
  1405. //--------------------
  1406. if ( T30ModemInit(pTG) != INIT_OK )
  1407. {
  1408. DebugPrintEx(DEBUG_ERR,"can't do T30ModemInit");
  1409. pTG->fFatalErrorWasSignaled = TRUE;
  1410. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1411. RetCode = FALSE;
  1412. goto l_exit;
  1413. }
  1414. pTG->Inst.ProtParams.uMinScan = MINSCAN_0_0_0;
  1415. ET30ProtSetProtParams(pTG, &pTG->Inst.ProtParams, pTG->FComModem.CurrMdmCaps.uSendSpeeds, pTG->FComModem.CurrMdmCaps.uRecvSpeeds);
  1416. // store the TIFF filename
  1417. //-------------------------
  1418. pTG->lpwFileName = AnsiStringToUnicodeString(FaxSend->FileName);
  1419. if ( !pTG->fTiffOpenOrCreated)
  1420. {
  1421. pTG->Inst.hfile = TiffOpenW (pTG->lpwFileName,
  1422. &pTG->TiffInfo,
  1423. TRUE);
  1424. if (!(pTG->Inst.hfile))
  1425. {
  1426. DebugPrintEx(DEBUG_ERR,"Can't open tiff file %s", pTG->lpwFileName);
  1427. // pTG->StatusId = FS_TIFF_SRC_BAD
  1428. pTG->fFatalErrorWasSignaled = 1;
  1429. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1430. RetCode = FALSE;
  1431. goto l_exit;
  1432. }
  1433. if (pTG->TiffInfo.YResolution == 98)
  1434. {
  1435. pTG->SrcHiRes = 0;
  1436. }
  1437. else
  1438. {
  1439. pTG->SrcHiRes = 1;
  1440. }
  1441. pTG->fTiffOpenOrCreated = 1;
  1442. DebugPrintEx( DEBUG_MSG,
  1443. "Successfully opened TIFF Yres=%d HiRes=%d",
  1444. pTG->TiffInfo.YResolution, pTG->SrcHiRes);
  1445. }
  1446. else
  1447. {
  1448. DebugPrintEx(DEBUG_ERR,"tiff file %s is OPENED already", pTG->lpwFileName);
  1449. DebugPrintEx(DEBUG_ERR,"Can't open tiff file %s", pTG->lpwFileName);
  1450. // pTG->StatusId = FS_TIFF_SRC_BAD
  1451. pTG->fFatalErrorWasSignaled = 1;
  1452. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1453. RetCode = FALSE;
  1454. goto l_exit;
  1455. }
  1456. InitCapsBC( pTG, (LPBC) &pTG->Inst.SendCaps, sizeof(pTG->Inst.SendCaps), SEND_CAPS);
  1457. // Fax Service Callback
  1458. //----------------------
  1459. if (!FaxSendCallback(FaxHandle,
  1460. CallHandle,
  1461. 0,
  1462. 0) )
  1463. {
  1464. pTG->fFatalErrorWasSignaled = 1;
  1465. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1466. RetCode = FALSE;
  1467. goto l_exit;
  1468. }
  1469. // Send the Fax
  1470. //-----------------------------------------------------------------------
  1471. // here we already know what Class we will use for a particular modem.
  1472. //-------------------------------------------------------------------
  1473. if (pTG->ModemClass == MODEM_CLASS2)
  1474. {
  1475. Class2Init(pTG);
  1476. RetCode = T30Cl2Tx (pTG, pTG->lpszDialDestFax);
  1477. }
  1478. else if (pTG->ModemClass == MODEM_CLASS2_0)
  1479. {
  1480. Class20Init(pTG);
  1481. RetCode = T30Cl20Tx (pTG, pTG->lpszDialDestFax);
  1482. }
  1483. else if (pTG->ModemClass == MODEM_CLASS1)
  1484. {
  1485. RetCode = T30Cl1Tx(pTG, pTG->lpszDialDestFax);
  1486. }
  1487. // delete all the files that are left
  1488. _fmemcpy (pTG->InFileName, gT30.TmpDirectory, gT30.dwLengthTmpDirectory);
  1489. _fmemcpy (&pTG->InFileName[gT30.dwLengthTmpDirectory], pTG->lpszPermanentLineID, 8);
  1490. for (dw = pTG->CurrentIn; dw <= pTG->LastOut; dw++)
  1491. {
  1492. sprintf( &pTG->InFileName[gT30.dwLengthTmpDirectory+8], ".%03d", dw);
  1493. if (! DeleteFileA (pTG->InFileName) )
  1494. {
  1495. DWORD dwLastError = GetLastError();
  1496. if (dwLastError==ERROR_SHARING_VIOLATION && pTG->InFileHandleNeedsBeClosed)
  1497. { // t-jonb: This can happen if the job is FaxDevAborted
  1498. DebugPrintEx(DEBUG_WRN,
  1499. "file %s can't be deleted; le = ERROR_SHARING_VIOLATION; trying to close InFileHandle",
  1500. pTG->InFileName);
  1501. CloseHandle(pTG->InFileHandle);
  1502. pTG->InFileHandleNeedsBeClosed = 0;
  1503. if (! DeleteFileA (pTG->InFileName) )
  1504. {
  1505. DebugPrintEx(DEBUG_ERR,
  1506. "file %s still can't be deleted; le=%lx",
  1507. pTG->InFileName, GetLastError());
  1508. }
  1509. }
  1510. else
  1511. {
  1512. DebugPrintEx( DEBUG_ERR,
  1513. "file %s can't be deleted; le=%lx",
  1514. pTG->InFileName, dwLastError);
  1515. }
  1516. }
  1517. }
  1518. l_exit:
  1519. pFaxDevCleanup(pTG,RecoveryIndex);
  1520. if (RetCode)
  1521. {
  1522. PSSLogEntry(PSS_MSG, 0, "Fax was sent successfully");
  1523. }
  1524. else
  1525. {
  1526. PSSLogEntry(PSS_ERR, 0, "Failed send");
  1527. }
  1528. MemFree(FaxSend->FileName);
  1529. FaxSend->FileName = NULL;
  1530. MemFree(FaxSend->CallerName);
  1531. FaxSend->CallerName = NULL;
  1532. MemFree(FaxSend->CallerNumber);
  1533. FaxSend->CallerNumber = NULL;
  1534. MemFree(FaxSend->ReceiverName);
  1535. FaxSend->ReceiverName = NULL;
  1536. MemFree(FaxSend->ReceiverNumber);
  1537. FaxSend->ReceiverNumber = NULL;
  1538. if (lpCommProp)
  1539. {
  1540. LocalFree(lpCommProp);
  1541. lpCommProp = NULL;
  1542. }
  1543. if ( (RetCode == FALSE) && (pTG->StatusId == FS_COMPLETED) )
  1544. {
  1545. DebugPrintEx(DEBUG_ERR,"exit success but later failed");
  1546. RetCode = TRUE;
  1547. }
  1548. ClosePSSLogFile(pTG, RetCode);
  1549. CLOSE_DEBUG_FILE;
  1550. if (!RetCode)
  1551. {
  1552. SetLastError(ERROR_FUNCTION_FAILED);
  1553. }
  1554. return (RetCode);
  1555. }
  1556. __except (pFaxDevExceptionCleanup())
  1557. {
  1558. //
  1559. // Code never gets here
  1560. //
  1561. return 0;
  1562. }
  1563. }
  1564. ///////////////////////////////////////////////////////////////////////////////////
  1565. VOID pFaxDevCleanup(PThrdGlbl pTG,int RecoveryIndex)
  1566. {
  1567. LONG lRet = 0;
  1568. DEBUG_FUNCTION_NAME(_T("pFaxDevCleanup"));
  1569. if (pTG->fTiffOpenOrCreated)
  1570. {
  1571. TiffClose( pTG->Inst.hfile);
  1572. pTG->fTiffOpenOrCreated = 0;
  1573. }
  1574. if (!pTG->ReqTerminate)
  1575. {
  1576. pTG->ReqTerminate = TRUE;
  1577. if (!SetEvent(pTG->ThrdSignal))
  1578. {
  1579. DebugPrintEx(DEBUG_ERR, "SetEvent(ThrdSignal) returns failure code: %d", GetLastError());
  1580. }
  1581. }
  1582. if (pTG->FComStatus.fModemInit)
  1583. {
  1584. if(!iModemClose(pTG))
  1585. {
  1586. DebugPrintEx(DEBUG_ERR,"iModemClose failed!");
  1587. }
  1588. }
  1589. else
  1590. {
  1591. // the modem was not initialized, so the job failed or was aborted before
  1592. // we got to T30ModemInit, but it also means that lineGetID was called
  1593. // and there's a good chance this handle is still open.
  1594. // in order to recover from pass throuhg mode, we have to attemp to close this
  1595. // handle, no matter what...
  1596. if (pTG->hComm)
  1597. {
  1598. DebugPrintEx(DEBUG_WRN,"Trying to close comm for any case, hComm=%x", pTG->hComm);
  1599. if (!CloseHandle(pTG->hComm))
  1600. {
  1601. DebugPrintEx( DEBUG_ERR,
  1602. "Close Handle pTG->hComm failed (ec=%d)",
  1603. GetLastError());
  1604. }
  1605. else
  1606. {
  1607. pTG->hComm = NULL;
  1608. }
  1609. }
  1610. }
  1611. if (pTG->Comm.fEnableHandoff && pTG->Comm.fDataCall)
  1612. {
  1613. DebugPrintEx(DEBUG_WRN,"DataCall dont hangup");
  1614. }
  1615. else
  1616. {
  1617. // release the line
  1618. //-----------------------------
  1619. if (pTG->fDeallocateCall == 0)
  1620. {
  1621. //
  1622. // line never was signalled IDLE, need to lineDrop first
  1623. //
  1624. if (!itapi_async_setup(pTG))
  1625. {
  1626. DebugPrintEx(DEBUG_ERR,"lineDrop itapi_async_setup failed");
  1627. if (!pTG->fFatalErrorWasSignaled)
  1628. {
  1629. pTG->fFatalErrorWasSignaled = 1;
  1630. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1631. }
  1632. }
  1633. lRet = 0;
  1634. if (pTG->CallHandle)
  1635. lRet = lineDrop (pTG->CallHandle, NULL, 0);
  1636. if (lRet < 0)
  1637. {
  1638. DebugPrintEx(DEBUG_ERR,"lineDrop failed %lx", lRet);
  1639. }
  1640. else
  1641. {
  1642. DebugPrintEx(DEBUG_MSG,"lineDrop returns request %d", lRet);
  1643. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_SHORT_TIMEOUT))
  1644. {
  1645. DebugPrintEx(DEBUG_ERR,"itapi_async_wait failed on lineDrop");
  1646. }
  1647. DebugPrintEx(DEBUG_MSG,"lineDrop SUCCESS");
  1648. }
  1649. //
  1650. //deallocating call
  1651. //
  1652. // it took us some time since first test
  1653. if (pTG->fDeallocateCall == 0)
  1654. { // Here we know that pTG->fDeallocateCall == 0 is true...
  1655. pTG->fDeallocateCall = 1;
  1656. }
  1657. }
  1658. }
  1659. if ( (RecoveryIndex >= 0) && (RecoveryIndex < MAX_T30_CONNECT) )
  1660. {
  1661. T30Recovery[RecoveryIndex].fAvail = TRUE;
  1662. }
  1663. /// RSL -revisit, may decrease prty during computation
  1664. if (!SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL) )
  1665. {
  1666. DebugPrintEx( DEBUG_ERR,
  1667. "SetThreadPriority Normal failed le=%x",
  1668. GetLastError() );
  1669. }
  1670. if (pTG->InFileHandleNeedsBeClosed)
  1671. {
  1672. CloseHandle(pTG->InFileHandle);
  1673. pTG->InFileHandleNeedsBeClosed = 0;
  1674. }
  1675. if (!pTG->AckTerminate)
  1676. {
  1677. if (WaitForSingleObject(pTG->ThrdAckTerminateSignal, TX_WAIT_ACK_TERMINATE_TIMEOUT) == WAIT_TIMEOUT)
  1678. {
  1679. DebugPrintEx(DEBUG_WRN,"Never got AckTerminate");
  1680. }
  1681. }
  1682. DebugPrintEx(DEBUG_MSG,"Got AckTerminate OK");
  1683. if (!SetEvent(pTG->AbortAckEvent))
  1684. {
  1685. DebugPrintEx( DEBUG_ERR,
  1686. "SetEvent(0x%lx) returns failure code: %ld",
  1687. (ULONG_PTR)pTG->AbortAckEvent,
  1688. (long) GetLastError());
  1689. }
  1690. }
  1691. ///////////////////////////////////////////////////////////////////////////////////
  1692. long pFaxDevExceptionCleanup()
  1693. {
  1694. //
  1695. // try to use the Recovery data
  1696. //
  1697. // Each function that will fail here will stop the line closing sequence.
  1698. //
  1699. DWORD dwCkSum;
  1700. HCALL CallHandle;
  1701. HANDLE CompletionPortHandle;
  1702. ULONG_PTR CompletionKey;
  1703. PThrdGlbl pTG = NULL;
  1704. DWORD dwThreadId = GetCurrentThreadId();
  1705. int fFound=0,i;
  1706. long lRet;
  1707. DEBUG_FUNCTION_NAME(_T("pFaxDevExceptionCleanup"));
  1708. fFound = FALSE;
  1709. SetLastError(ERROR_FUNCTION_FAILED);
  1710. DebugPrintEx(DEBUG_WRN,"Trying to find Recovery Information after catch exception.");
  1711. for (i=0; i<MAX_T30_CONNECT; i++)
  1712. {
  1713. if ( (! T30Recovery[i].fAvail) && (T30Recovery[i].ThreadId == dwThreadId) )
  1714. {
  1715. if ( ( dwCkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail,
  1716. sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1) ) == T30Recovery[i].CkSum )
  1717. {
  1718. CallHandle = T30Recovery[i].CallHandle;
  1719. CompletionPortHandle = T30Recovery[i].CompletionPortHandle;
  1720. CompletionKey = T30Recovery[i].CompletionKey;
  1721. pTG = (PThrdGlbl) T30Recovery[i].pTG;
  1722. fFound = TRUE;
  1723. T30Recovery[i].fAvail = TRUE;
  1724. break;
  1725. }
  1726. }
  1727. }
  1728. if (!fFound)
  1729. {
  1730. //
  1731. // Need to indicate that FaxT30 couldn't recover by itself.
  1732. //
  1733. DebugPrintEx(DEBUG_ERR,"Have not found the recovery information");
  1734. return EXCEPTION_CONTINUE_SEARCH;
  1735. }
  1736. //
  1737. // get out of Pass-through
  1738. //
  1739. if (pTG->FComStatus.fModemInit)
  1740. {
  1741. if(!iModemClose(pTG))
  1742. {
  1743. DebugPrintEx(DEBUG_ERR,"iModemClose failed!");
  1744. }
  1745. }
  1746. else
  1747. {
  1748. // the modem was not initialized, so the job failed or was aborted before
  1749. // we got to T30ModemInit, but it also means that lineGetID was called
  1750. // and there's a good chance this handle is still open.
  1751. // in order to recover from pass throuhg mode, we have to attemp to close this
  1752. // handle, no matter what...
  1753. if (pTG->hComm)
  1754. {
  1755. DebugPrintEx(DEBUG_WRN,"Trying to close comm for any case...");
  1756. if (!CloseHandle(pTG->hComm))
  1757. {
  1758. DebugPrintEx( DEBUG_ERR,
  1759. "Close Handle pTG->hComm failed (ec=%d)",
  1760. GetLastError());
  1761. }
  1762. else
  1763. {
  1764. pTG->hComm = NULL;
  1765. }
  1766. }
  1767. }
  1768. if (!itapi_async_setup(pTG))
  1769. {
  1770. DebugPrintEx( DEBUG_ERR,
  1771. "Failed in itapi_async_setup, before lineSetCallParams"
  1772. " ,ec = %d",
  1773. GetLastError());
  1774. return EXCEPTION_CONTINUE_SEARCH;
  1775. }
  1776. lRet = lineSetCallParams(CallHandle,
  1777. LINEBEARERMODE_VOICE,
  1778. 0,
  1779. 0xffffffff,
  1780. NULL);
  1781. if (lRet < 0)
  1782. {
  1783. DebugPrintEx( DEBUG_ERR,
  1784. "lineSetCallParams failed, Return value is %d",
  1785. lRet);
  1786. return EXCEPTION_CONTINUE_SEARCH;
  1787. }
  1788. else
  1789. {
  1790. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT))
  1791. {
  1792. DebugPrintEx( DEBUG_ERR,
  1793. "Failed in itapi_async_wait, after"
  1794. " lineSetCallParams ,ec = %d",
  1795. GetLastError());
  1796. return EXCEPTION_CONTINUE_SEARCH;
  1797. }
  1798. }
  1799. //
  1800. // hang up
  1801. //
  1802. if (!itapi_async_setup(pTG))
  1803. {
  1804. DebugPrintEx( DEBUG_ERR,
  1805. "Failed in itapi_async_setup, before lineDrop"
  1806. " ,ec = %d",
  1807. GetLastError());
  1808. return EXCEPTION_CONTINUE_SEARCH;
  1809. }
  1810. lRet = lineDrop (CallHandle, NULL, 0);
  1811. if (lRet < 0)
  1812. {
  1813. DebugPrintEx( DEBUG_ERR,
  1814. "Failed in lineDrop ,Return value is = %d",
  1815. lRet);
  1816. return EXCEPTION_CONTINUE_SEARCH;
  1817. }
  1818. else
  1819. {
  1820. if(!itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT))
  1821. {
  1822. DebugPrintEx( DEBUG_ERR,
  1823. "Failed in itapi_async_wait, after lineDrop"
  1824. " ,ec = %d",
  1825. GetLastError());
  1826. return EXCEPTION_CONTINUE_SEARCH;
  1827. }
  1828. }
  1829. SignalRecoveryStatusChange( &T30Recovery[i] );
  1830. if (pTG->InFileHandleNeedsBeClosed)
  1831. {
  1832. CloseHandle(pTG->InFileHandle);
  1833. }
  1834. SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL);
  1835. ClosePSSLogFile (pTG, FALSE);
  1836. return EXCEPTION_CONTINUE_SEARCH;
  1837. }
  1838. ///////////////////////////////////////////////////////////////////////////////////
  1839. BOOL WINAPI
  1840. FaxDevReceiveA(
  1841. HANDLE FaxHandle,
  1842. HCALL CallHandle,
  1843. PFAX_RECEIVE_A FaxReceive
  1844. )
  1845. /*++
  1846. Routine Description:
  1847. Device provider receive. Synopsis:
  1848. * Find ThreadGlobal in T30Inst
  1849. * Add entry to recovery area
  1850. * TAPI: lineSetCallParams
  1851. * itapi_async_wait (until LineCallBack sends TAPI message LINE_CALLSTATE)
  1852. * GetModemParams
  1853. * ReadExtensionConfiguration (Reads T30 extension config, i.e. "adaptive answering enabled")
  1854. * T30ModemInit
  1855. * GetCallerIDFromCall
  1856. ****************** Receive the fax
  1857. * FaxDevCleanup
  1858. Arguments:
  1859. Return Value:
  1860. --*/
  1861. {
  1862. LONG_PTR i;
  1863. PThrdGlbl pTG=NULL;
  1864. long lRet;
  1865. DWORD dw;
  1866. BOOL RetCode;
  1867. int fFound=0;
  1868. BOOL bBlindReceive = FALSE;
  1869. int RecoveryIndex = -1;
  1870. TCHAR szDeviceName[MAX_DEVICE_NAME_SIZE] = {'\0'}; // used for PSSLog
  1871. DWORD dwLineReplyParam = 0;
  1872. OPEN_DEBUG_FILE_SIZE(T30_DEBUG_LOG_FILE, T30_MAX_LOG_SIZE);
  1873. __try
  1874. {
  1875. DEBUG_FUNCTION_NAME(_T("FaxDevReceiveA"));
  1876. DebugPrintEx( DEBUG_MSG,
  1877. "FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld",
  1878. FaxHandle, CallHandle, FaxReceive, GetTickCount() );
  1879. // find instance data
  1880. //------------------------
  1881. i = (LONG_PTR) FaxHandle;
  1882. if (i < 1 || i >= MAX_T30_CONNECT)
  1883. {
  1884. MemFree(FaxReceive->FileName);
  1885. MemFree(FaxReceive->ReceiverName);
  1886. MemFree(FaxReceive->ReceiverNumber);
  1887. DebugPrintEx( DEBUG_ERR,
  1888. "FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld",
  1889. FaxHandle, CallHandle, FaxReceive, GetTickCount() );
  1890. CLOSE_DEBUG_FILE;
  1891. return (FALSE);
  1892. }
  1893. if (T30Inst[i].fAvail)
  1894. {
  1895. MemFree(FaxReceive->FileName);
  1896. MemFree(FaxReceive->ReceiverName);
  1897. MemFree(FaxReceive->ReceiverNumber);
  1898. DebugPrintEx( DEBUG_ERR,
  1899. "AVAIL FaxHandle=%x, CallHandle=%x, FaxReceive=%x at %ld",
  1900. FaxHandle, CallHandle, FaxReceive, GetTickCount() );
  1901. CLOSE_DEBUG_FILE;
  1902. return (FALSE);
  1903. }
  1904. pTG = (PThrdGlbl) T30Inst[i].pT30;
  1905. pTG->CallHandle = CallHandle;
  1906. //
  1907. // Add entry to the Recovery Area.
  1908. //
  1909. fFound = 0;
  1910. for (i=0; i<MAX_T30_CONNECT; i++)
  1911. {
  1912. if (T30Recovery[i].fAvail)
  1913. {
  1914. EnterCriticalSection(&T30RecoveryCritSection);
  1915. T30Recovery[i].fAvail = FALSE;
  1916. T30Recovery[i].ThreadId = GetCurrentThreadId();
  1917. T30Recovery[i].FaxHandle = FaxHandle;
  1918. T30Recovery[i].pTG = (LPVOID) pTG;
  1919. T30Recovery[i].LineHandle = pTG->LineHandle;
  1920. T30Recovery[i].CallHandle = CallHandle;
  1921. T30Recovery[i].DeviceId = pTG->DeviceId;
  1922. T30Recovery[i].CompletionPortHandle = pTG->CompletionPortHandle;
  1923. T30Recovery[i].CompletionKey = pTG->CompletionKey;
  1924. T30Recovery[i].TiffThreadId = 0;
  1925. T30Recovery[i].TimeStart = GetTickCount();
  1926. T30Recovery[i].TimeUpdated = T30Recovery[i].TimeStart;
  1927. T30Recovery[i].CkSum = ComputeCheckSum( (LPDWORD) &T30Recovery[i].fAvail,
  1928. sizeof ( T30_RECOVERY_GLOB ) / sizeof (DWORD) - 1);
  1929. LeaveCriticalSection(&T30RecoveryCritSection);
  1930. fFound = 1;
  1931. RecoveryIndex = (int)i;
  1932. pTG->RecoveryIndex = (int)i;
  1933. break;
  1934. }
  1935. }
  1936. if (! fFound)
  1937. {
  1938. DebugPrintEx(DEBUG_ERR,"Couldn't find available space for Recovery");
  1939. pTG->fFatalErrorWasSignaled = 1;
  1940. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1941. RetCode = FALSE;
  1942. goto l_exit;
  1943. }
  1944. pTG->Operation = T30_RX;
  1945. // store LocalID
  1946. if (FaxReceive->ReceiverNumber == NULL)
  1947. {
  1948. pTG->LocalID[0] = 0;
  1949. }
  1950. else
  1951. {
  1952. _fmemcpy(pTG->LocalID, FaxReceive->ReceiverNumber, min (_fstrlen(FaxReceive->ReceiverNumber), sizeof(pTG->LocalID) - 1) );
  1953. pTG->LocalID [ min (_fstrlen(FaxReceive->ReceiverNumber), sizeof(pTG->LocalID) - 1) ] = 0;
  1954. }
  1955. // tiff
  1956. //-----------------------------------------------
  1957. pTG->lpwFileName = AnsiStringToUnicodeString(FaxReceive->FileName);
  1958. pTG->SrcHiRes = 1;
  1959. pTG->fGotConnect = FALSE;
  1960. if (!itapi_async_setup(pTG))
  1961. {
  1962. DebugPrintEx(DEBUG_ERR,"itapi_async_setup failed");
  1963. pTG->fFatalErrorWasSignaled = 1;
  1964. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1965. RetCode = FALSE;
  1966. goto l_exit;
  1967. }
  1968. if (0 == CallHandle)
  1969. {
  1970. //
  1971. // Special case - blind receive mode
  1972. // This happens when we use the blind-receive (reciveing a fax without a ring / offer from TAPI).
  1973. //
  1974. // We must use lineMakeCall (hLine, &hCall, NULL, 0, LINEBEARERMODE_PASSTHROUGH)
  1975. // to get the initial hCall.
  1976. //
  1977. LPLINECALLPARAMS lpCallParams = itapi_create_linecallparams();
  1978. if (!lpCallParams)
  1979. {
  1980. DebugPrintEx(DEBUG_ERR,
  1981. TEXT("itapi_create_linecallparams failed with %ld"),
  1982. GetLastError ());
  1983. pTG->fFatalErrorWasSignaled = 1;
  1984. SignalStatusChange(pTG, FS_FATAL_ERROR);
  1985. RetCode = FALSE;
  1986. goto l_exit;
  1987. }
  1988. lRet = lineMakeCall (pTG->LineHandle, // TAPI line
  1989. &CallHandle, // New call handle
  1990. NULL, // No address
  1991. 0, // No country code
  1992. lpCallParams); // Line call params
  1993. MemFree (lpCallParams);
  1994. if (lRet < 0)
  1995. {
  1996. DebugPrintEx(DEBUG_ERR,
  1997. TEXT("lineMakeCall returns ERROR value 0x%lx"),
  1998. (unsigned long)lRet);
  1999. pTG->fFatalErrorWasSignaled = 1;
  2000. SignalStatusChange(pTG, FS_FATAL_ERROR);
  2001. RetCode = FALSE;
  2002. goto l_exit;
  2003. }
  2004. else
  2005. {
  2006. DebugPrintEx( DEBUG_MSG,
  2007. "lineMakeCall returns ID %ld",
  2008. (long) lRet);
  2009. }
  2010. bBlindReceive = TRUE;
  2011. }
  2012. else
  2013. {
  2014. // Normal case.
  2015. //
  2016. // take line over from TAPI
  2017. //--------------------------
  2018. //
  2019. // initiate passthru
  2020. //
  2021. lRet = lineSetCallParams(CallHandle,
  2022. LINEBEARERMODE_PASSTHROUGH,
  2023. 0,
  2024. 0xffffffff,
  2025. NULL);
  2026. if (lRet < 0)
  2027. {
  2028. DebugPrintEx(DEBUG_ERR,"lineSetCallParams failed");
  2029. pTG->fFatalErrorWasSignaled = 1;
  2030. SignalStatusChange(pTG, FS_FATAL_ERROR);
  2031. RetCode = FALSE;
  2032. goto l_exit;
  2033. }
  2034. else
  2035. {
  2036. DebugPrintEx( DEBUG_MSG,
  2037. "lpfnlineSetCallParams returns ID %ld",
  2038. (long) lRet);
  2039. }
  2040. }
  2041. //
  2042. // Wait for a successful LINE_REPLY message
  2043. //
  2044. if (!itapi_async_wait(pTG, (DWORD)lRet, &dwLineReplyParam, NULL, ASYNC_TIMEOUT) ||
  2045. (dwLineReplyParam != 0) )
  2046. {
  2047. DebugPrintEx(DEBUG_ERR,"itapi_async_wait failed, dwLineReplyParam=%x", dwLineReplyParam);
  2048. pTG->fFatalErrorWasSignaled = 1;
  2049. SignalStatusChange(pTG, FS_FATAL_ERROR);
  2050. RetCode = FALSE;
  2051. goto l_exit;
  2052. }
  2053. if (bBlindReceive)
  2054. {
  2055. //
  2056. // Only now, after we got the LINE_REPLY from lineMakeCall, we can start using the call handle
  2057. //
  2058. pTG->CallHandle = CallHandle;
  2059. }
  2060. // now we wait for the connected message
  2061. //--------------------------------------
  2062. for (dw=50; dw<10000; dw = dw*120/100)
  2063. {
  2064. Sleep(dw);
  2065. if (pTG->fGotConnect)
  2066. {
  2067. break;
  2068. }
  2069. }
  2070. if (!pTG->fGotConnect)
  2071. {
  2072. DebugPrintEx(DEBUG_ERR,"Failure waiting for CONNECTED message....");
  2073. // We ignore...
  2074. }
  2075. RetCode = GetModemParams(pTG, szDeviceName, MAX_DEVICE_NAME_SIZE);
  2076. if (!RetCode)
  2077. {
  2078. DebugPrintEx(DEBUG_ERR,"GetModemParams failed");
  2079. goto l_exit;
  2080. }
  2081. OpenPSSLogFile(pTG, szDeviceName);
  2082. /// RSL -revisit, may decrease prty during computation
  2083. if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) )
  2084. {
  2085. DebugPrintEx( DEBUG_ERR,
  2086. "SetThreadPriority TIME CRITICAL failed le=%x",
  2087. GetLastError() );
  2088. }
  2089. //
  2090. // Read extension configuration
  2091. //
  2092. if (!ReadExtensionConfiguration(pTG))
  2093. {
  2094. DebugPrintEx(
  2095. DEBUG_ERR,
  2096. "ReadExtensionConfiguration() failed for device id: %ld (ec: %ld)",
  2097. pTG->dwPermanentLineID,
  2098. GetLastError()
  2099. );
  2100. pTG->fFatalErrorWasSignaled = 1;
  2101. SignalStatusChange(pTG, FS_FATAL_ERROR);
  2102. RetCode = FALSE;
  2103. goto l_exit;
  2104. }
  2105. // initialize modem
  2106. //--------------------
  2107. if ( T30ModemInit(pTG) != INIT_OK )
  2108. {
  2109. DebugPrintEx(DEBUG_ERR, "can't do T30ModemInit");
  2110. pTG->fFatalErrorWasSignaled = TRUE;
  2111. SignalStatusChange(pTG, FS_FATAL_ERROR);
  2112. RetCode = FALSE;
  2113. goto l_exit;
  2114. }
  2115. pTG->Inst.ProtParams.uMinScan = MINSCAN_0_0_0;
  2116. ET30ProtSetProtParams(pTG, &pTG->Inst.ProtParams, pTG->FComModem.CurrMdmCaps.uSendSpeeds, pTG->FComModem.CurrMdmCaps.uRecvSpeeds);
  2117. InitCapsBC( pTG, (LPBC) &pTG->Inst.SendCaps, sizeof(pTG->Inst.SendCaps), SEND_CAPS);
  2118. // answer the call and receive a fax
  2119. //-----------------------------------
  2120. if (GetCallerIDFromCall(pTG->CallHandle,pTG->CallerId,sizeof(pTG->CallerId)))
  2121. {
  2122. DebugPrintEx(DEBUG_MSG, "Caller ID is %s",pTG->CallerId);
  2123. }
  2124. else
  2125. {
  2126. DebugPrintEx(DEBUG_ERR, "GetCallerIDFromCall failed");
  2127. }
  2128. // here we already know what Class we will use for a particular modem.
  2129. //-------------------------------------------------------------------
  2130. if (pTG->ModemClass == MODEM_CLASS2)
  2131. {
  2132. Class2Init(pTG);
  2133. RetCode = T30Cl2Rx (pTG);
  2134. }
  2135. else if (pTG->ModemClass == MODEM_CLASS2_0)
  2136. {
  2137. Class20Init(pTG);
  2138. RetCode = T30Cl20Rx (pTG);
  2139. }
  2140. else if (pTG->ModemClass == MODEM_CLASS1)
  2141. {
  2142. RetCode = T30Cl1Rx(pTG);
  2143. }
  2144. l_exit:
  2145. pFaxDevCleanup(pTG,RecoveryIndex);
  2146. if ( (RetCode == FALSE) && (pTG->StatusId == FS_COMPLETED) )
  2147. {
  2148. DebugPrintEx(DEBUG_ERR,"exit success but later failed");
  2149. RetCode = TRUE;
  2150. }
  2151. if (RetCode)
  2152. {
  2153. PSSLogEntry(PSS_MSG, 0, "Fax was received successfully");
  2154. }
  2155. else
  2156. {
  2157. PSSLogEntry(PSS_ERR, 0, "Failed receive");
  2158. }
  2159. MemFree(FaxReceive->FileName);
  2160. FaxReceive->FileName = NULL;
  2161. MemFree(FaxReceive->ReceiverName);
  2162. FaxReceive->ReceiverName = NULL;
  2163. MemFree(FaxReceive->ReceiverNumber);
  2164. FaxReceive->ReceiverNumber = NULL;
  2165. ClosePSSLogFile(pTG, RetCode);
  2166. DebugPrintEx(DEBUG_MSG,"returns %d",RetCode);
  2167. CLOSE_DEBUG_FILE;
  2168. if (!RetCode)
  2169. {
  2170. SetLastError(ERROR_FUNCTION_FAILED);
  2171. }
  2172. return (RetCode);
  2173. }
  2174. __except (pFaxDevExceptionCleanup())
  2175. {
  2176. //
  2177. // Code never runs here
  2178. //
  2179. return 0;
  2180. }
  2181. }
  2182. ///////////////////////////////////////////////////////////////////////////////////
  2183. BOOL WINAPI
  2184. FaxDevReportStatusA(
  2185. IN HANDLE FaxHandle OPTIONAL,
  2186. OUT PFAX_DEV_STATUS FaxStatus,
  2187. IN DWORD FaxStatusSize,
  2188. OUT LPDWORD FaxStatusSizeRequired
  2189. )
  2190. /*++
  2191. Routine Description:
  2192. Arguments:
  2193. Return Value:
  2194. --*/
  2195. {
  2196. LONG_PTR i;
  2197. PThrdGlbl pTG;
  2198. LPWSTR lpwCSI; // inside the FaxStatus struct.
  2199. LPWSTR lpwCallerId = NULL;
  2200. LPBYTE lpTemp;
  2201. DEBUG_FUNCTION_NAME(_T("FaxDevReportStatusA"));
  2202. if (FaxHandle == NULL)
  2203. {
  2204. // means global status
  2205. DebugPrintEx( DEBUG_ERR,
  2206. "EP: FaxDevReportStatus NULL FaxHandle; "
  2207. "gT30.Status=%d",
  2208. gT30.Status);
  2209. if (gT30.Status == STATUS_FAIL)
  2210. {
  2211. goto failure;
  2212. }
  2213. else
  2214. {
  2215. return (TRUE);
  2216. }
  2217. }
  2218. else
  2219. {
  2220. // find instance data
  2221. //------------------------
  2222. i = (LONG_PTR) FaxHandle;
  2223. if (i < 1 || i >= MAX_T30_CONNECT)
  2224. {
  2225. DebugPrintEx(DEBUG_ERR,"got wrong FaxHandle=%d", i);
  2226. goto failure;
  2227. }
  2228. if (T30Inst[i].fAvail)
  2229. {
  2230. DebugPrintEx(DEBUG_ERR,"got wrong FaxHandle (marked as free) %d", i);
  2231. goto failure;
  2232. }
  2233. pTG = (PThrdGlbl) T30Inst[i].pT30;
  2234. // Calculate required size
  2235. //-------------------------
  2236. *FaxStatusSizeRequired = sizeof (FAX_DEV_STATUS);
  2237. if (pTG->fRemoteIdAvail)
  2238. {
  2239. *FaxStatusSizeRequired += (wcslen(pTG->RemoteID)+1) * sizeof(WCHAR);
  2240. }
  2241. // pTG->CallerId is in ANSI, but we want to know how much it'll take in unicode
  2242. *FaxStatusSizeRequired += (strlen(pTG->CallerId)+1) * sizeof(WCHAR);
  2243. if (FaxStatusSize < *FaxStatusSizeRequired )
  2244. {
  2245. DebugPrintEx( DEBUG_WRN,
  2246. "wrong size passed=%d, expected not less than %d",
  2247. FaxStatusSize,
  2248. *FaxStatusSizeRequired);
  2249. goto failure;
  2250. }
  2251. FaxStatus->SizeOfStruct = sizeof(FAX_DEV_STATUS);
  2252. FaxStatus->StatusId = pTG->StatusId;
  2253. FaxStatus->StringId = pTG->StringId;
  2254. FaxStatus->PageCount = pTG->PageCount;
  2255. lpTemp = (LPBYTE) FaxStatus;
  2256. lpTemp += sizeof(FAX_DEV_STATUS);
  2257. if (pTG->fRemoteIdAvail)
  2258. {
  2259. lpwCSI = (LPWSTR) lpTemp;
  2260. wcscpy(lpwCSI, pTG->RemoteID);
  2261. FaxStatus->CSI = (LPWSTR) lpwCSI;
  2262. lpTemp += ((wcslen(FaxStatus->CSI)+1)*sizeof(WCHAR));
  2263. }
  2264. else
  2265. {
  2266. FaxStatus->CSI = NULL;
  2267. }
  2268. FaxStatus->CallerId = (LPWSTR) lpTemp;
  2269. lpwCallerId = (LPWSTR) AnsiStringToUnicodeString(pTG->CallerId);
  2270. if (lpwCallerId)
  2271. {
  2272. wcscpy(FaxStatus->CallerId, lpwCallerId);
  2273. MemFree(lpwCallerId);
  2274. }
  2275. else
  2276. {
  2277. FaxStatus->CallerId = NULL;
  2278. }
  2279. FaxStatus->RoutingInfo = NULL; // (char *) AnsiStringToUnicodeString(pTG->RoutingInfo);
  2280. DebugPrintEx(DEBUG_MSG,"returns %lx", pTG->StatusId);
  2281. return (TRUE);
  2282. }
  2283. DebugPrintEx(DEBUG_ERR, "wrong return");
  2284. return (TRUE);
  2285. failure:
  2286. SetLastError(ERROR_FUNCTION_FAILED);
  2287. return (FALSE);
  2288. }
  2289. ///////////////////////////////////////////////////////////////////////////////////
  2290. BOOL WINAPI
  2291. FaxDevAbortOperationA(
  2292. HANDLE FaxHandle
  2293. )
  2294. /*++
  2295. Routine Description:
  2296. Arguments:
  2297. Return Value:
  2298. --*/
  2299. {
  2300. LONG_PTR i;
  2301. PThrdGlbl pTG=NULL;
  2302. long lRet;
  2303. OPEN_DEBUG_FILE_SIZE(T30_DEBUG_LOG_FILE, T30_MAX_LOG_SIZE);
  2304. {
  2305. DEBUG_FUNCTION_NAME(_T("FaxDevAbortOperationA"));
  2306. DebugPrintEx(DEBUG_MSG,"FaxHandle=%x",FaxHandle);
  2307. // find instance data
  2308. //------------------------
  2309. i = (LONG_PTR) FaxHandle;
  2310. if (i < 1 || i >= MAX_T30_CONNECT)
  2311. {
  2312. DebugPrintEx(DEBUG_ERR, "got wrong FaxHandle=%d", i);
  2313. CLOSE_DEBUG_FILE;
  2314. return (FALSE);
  2315. }
  2316. if (T30Inst[i].fAvail)
  2317. {
  2318. DebugPrintEx(DEBUG_ERR,"got wrong FaxHandle (marked as free) %d", i);
  2319. return (FALSE);
  2320. }
  2321. pTG = (PThrdGlbl) T30Inst[i].pT30;
  2322. if (pTG->fAbortRequested)
  2323. {
  2324. DebugPrintEx(DEBUG_ERR, "ABORT request had been POSTED already");
  2325. return (FALSE);
  2326. }
  2327. if (pTG->StatusId == FS_NOT_FAX_CALL)
  2328. {
  2329. DebugPrintEx( DEBUG_MSG,"Abort on DATA called");
  2330. if (!itapi_async_setup(pTG))
  2331. {
  2332. DebugPrintEx(DEBUG_ERR,"itapi_async_setup failed");
  2333. return (FALSE);
  2334. }
  2335. lRet = lineDrop(pTG->CallHandle, NULL, 0);
  2336. if (lRet < 0)
  2337. {
  2338. DebugPrintEx(DEBUG_ERR, "lineDrop failed %x", lRet);
  2339. return (FALSE);
  2340. }
  2341. if( !itapi_async_wait(pTG, (DWORD)lRet, (LPDWORD)&lRet, NULL, ASYNC_TIMEOUT))
  2342. {
  2343. DebugPrintEx(DEBUG_ERR, "async_wait lineDrop failed");
  2344. return (FALSE);
  2345. }
  2346. DebugPrintEx( DEBUG_MSG, "finished SUCCESS");
  2347. return (TRUE);
  2348. }
  2349. //
  2350. // real ABORT request.
  2351. //
  2352. DebugPrintEx( DEBUG_MSG,"ABORT requested");
  2353. pTG->fFatalErrorWasSignaled = TRUE;
  2354. SignalStatusChange(pTG, FS_USER_ABORT);
  2355. // set the global abort flag for pTG
  2356. pTG->fAbortRequested = TRUE;
  2357. // set the abort flag for imaging threads
  2358. pTG->ReqTerminate = TRUE;
  2359. PSSLogEntry(PSS_WRN, 0, "User abort");
  2360. // signal manual-reset event to everybody waiting on multiple objects
  2361. if (! SetEvent(pTG->AbortReqEvent) )
  2362. {
  2363. DebugPrintEx(DEBUG_ERR,"SetEvent FAILED le=%lx", GetLastError());
  2364. }
  2365. DebugPrintEx( DEBUG_MSG, "finished SUCCESS");
  2366. }
  2367. CLOSE_DEBUG_FILE;
  2368. return (TRUE);
  2369. }
  2370. BOOL ReadExtensionConfiguration(PThrdGlbl pTG)
  2371. /*++
  2372. Routine Description:
  2373. Reads the T30 Configuration Data using the fax configuration
  2374. persistence mechanism and places it in the pTG.
  2375. This currently include only an indication if adaptive answerign was enabled
  2376. by the administrator.
  2377. If the configuration is not found the default configuration is used.
  2378. If another error occurs the function fails.
  2379. Arguments:
  2380. pTG
  2381. Return Value:
  2382. TRUE if the function succeeded. This means that either the information was read
  2383. or it was not found and defaults were used.
  2384. FALSE for any other error. Use GetLastError() to get extended error information.
  2385. --*/
  2386. {
  2387. DWORD ec = ERROR_SUCCESS;
  2388. LPT30_EXTENSION_DATA lpExtData = NULL;
  2389. DWORD dwExtDataSize = 0;
  2390. DEBUG_FUNCTION_NAME(_T("ReadExtensionConfiguration"));
  2391. memset(&pTG->ExtData,0,sizeof(T30_EXTENSION_DATA));
  2392. pTG->ExtData.bAdaptiveAnsweringEnabled = FALSE;
  2393. Assert(g_pfFaxGetExtensionData);
  2394. ec = g_pfFaxGetExtensionData(
  2395. pTG->dwPermanentLineID,
  2396. DEV_ID_SRC_TAPI, // TAPI device id
  2397. GUID_T30_EXTENSION_DATA_W,
  2398. (LPBYTE *)&lpExtData,
  2399. &dwExtDataSize);
  2400. if (ERROR_SUCCESS != ec)
  2401. {
  2402. if (ERROR_FILE_NOT_FOUND == ec)
  2403. {
  2404. DebugPrintEx(
  2405. DEBUG_WRN,
  2406. "can't find extension configuration information"
  2407. " for device id : 0x%08X. Using defaults.",
  2408. pTG->dwPermanentLineID);
  2409. //
  2410. // We are going to use the defaults.
  2411. //
  2412. ec = ERROR_SUCCESS;
  2413. }
  2414. else
  2415. {
  2416. DebugPrintEx(
  2417. DEBUG_ERR,
  2418. "Get extension configuration information"
  2419. " for device id : 0x%08X failed with ec: %ld",
  2420. pTG->dwPermanentLineID,
  2421. ec);
  2422. }
  2423. }
  2424. else
  2425. {
  2426. if (sizeof(T30_EXTENSION_DATA) != dwExtDataSize)
  2427. {
  2428. DebugPrintEx(
  2429. DEBUG_ERR,
  2430. "Extension configuration data size mismatch"
  2431. " for device id: 0x%08X. Expected: %ld - Got: %ld",
  2432. sizeof(T30_EXTENSION_DATA),
  2433. pTG->dwPermanentLineID,
  2434. dwExtDataSize);
  2435. ec = ERROR_BAD_FORMAT;
  2436. }
  2437. else
  2438. {
  2439. memcpy(&pTG->ExtData,lpExtData,sizeof(T30_EXTENSION_DATA));
  2440. }
  2441. }
  2442. if (ERROR_SUCCESS != ec)
  2443. {
  2444. SetLastError(ec);
  2445. }
  2446. if (lpExtData)
  2447. {
  2448. Assert(g_pfFaxExtFreeBuffer);
  2449. g_pfFaxExtFreeBuffer(lpExtData);
  2450. }
  2451. return (ERROR_SUCCESS == ec);
  2452. }
  2453. ///////////////////////////////////////////////////////////////////////////////////
  2454. #define WAIT_ALL_ABORT_TIMEOUT 20000
  2455. HRESULT WINAPI
  2456. FaxDevShutdownA()
  2457. {
  2458. PThrdGlbl pTG = NULL;
  2459. PThrdGlbl pTGArray[MAX_T30_CONNECT];
  2460. HANDLE HandlesArray[MAX_T30_CONNECT] = {INVALID_HANDLE_VALUE};
  2461. DWORD iCountForceAbortJobs = 0;
  2462. DWORD i = 0;
  2463. OPEN_DEBUG_FILE_SIZE(T30_DEBUG_LOG_FILE, T30_MAX_LOG_SIZE);
  2464. {
  2465. DEBUG_FUNCTION_NAME(_T("FaxDevShutdownA"));
  2466. if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL) )
  2467. {
  2468. DebugPrintEx( DEBUG_ERR,
  2469. "SetThreadPriority TIME CRITICAL failed le=%x",
  2470. GetLastError() );
  2471. }
  2472. EnterCriticalSection(&T30CritSection);
  2473. for (i=1; i<MAX_T30_CONNECT; i++)
  2474. {
  2475. if (!T30Inst[i].fAvail)
  2476. {
  2477. // this is bad.
  2478. // it means someone is shutting down the service when a job
  2479. // is somewhere in the pipe here.
  2480. // first let's post an abort requset
  2481. pTG = (PThrdGlbl)T30Inst[i].pT30;
  2482. if (!FaxDevAbortOperationA(ULongToHandle(i)))
  2483. {
  2484. DebugPrintEx(DEBUG_WRN,"Posting Abort request failed");
  2485. }
  2486. pTGArray[iCountForceAbortJobs] = pTG;
  2487. HandlesArray[iCountForceAbortJobs] = pTG->AbortAckEvent;
  2488. iCountForceAbortJobs++;
  2489. }
  2490. }
  2491. LeaveCriticalSection(&T30CritSection);
  2492. if (iCountForceAbortJobs)
  2493. {
  2494. DebugPrintEx( DEBUG_WRN,
  2495. "We have %d jobs to abort brutally",
  2496. iCountForceAbortJobs);
  2497. WaitForMultipleObjects(iCountForceAbortJobs,HandlesArray,TRUE,WAIT_ALL_ABORT_TIMEOUT);
  2498. DebugPrintEx( DEBUG_MSG, "Finished waiting");
  2499. // regardless of the return value of WaitForMultipleObjects...
  2500. // there might be some modems off-hook, tapi lines allocated and so on...
  2501. // so, now i'm shutting everything down brutally.
  2502. for (i=0; i<iCountForceAbortJobs; i++)
  2503. {
  2504. pTG = pTGArray[i];
  2505. if (pTG->FComStatus.fModemInit)
  2506. {
  2507. // this is unfortunate...
  2508. // it means the abort request wasn't fulfilled
  2509. // so let's close the modem anyhow to make it
  2510. // work when the service comes back to life
  2511. if(!iModemClose(pTG))
  2512. {
  2513. DebugPrintEx(DEBUG_ERR,"iModemClose failed!");
  2514. }
  2515. DebugPrintEx(DEBUG_MSG,"finished Shutdown of Job %d...",i+1);
  2516. }
  2517. }
  2518. }
  2519. DeleteCriticalSection(&T30CritSection);
  2520. T30CritSectionInit = 0;
  2521. DeleteCriticalSection(&T30RecoveryCritSection);
  2522. T30RecoveryCritSectionInit = 0;
  2523. if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL) )
  2524. {
  2525. DebugPrintEx( DEBUG_ERR,
  2526. "SetThreadPriority TIME CRITICAL failed le=%x",
  2527. GetLastError() );
  2528. }
  2529. DebugPrintEx(DEBUG_MSG,"Exit FaxDevShutdownA");
  2530. }
  2531. HeapCleanup();
  2532. CLOSE_DEBUG_FILE;
  2533. return S_OK;
  2534. }