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.

693 lines
20 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. receive.c
  5. Abstract:
  6. This module handles the FAX receive case.
  7. Author:
  8. Wesley Witt (wesw) 6-Mar-1996
  9. Revision History:
  10. --*/
  11. #include "faxsvc.h"
  12. #pragma hdrstop
  13. DWORD
  14. FaxReceiveThread(
  15. PFAX_RECEIVE_ITEM FaxReceiveItem
  16. )
  17. /*++
  18. Routine Description:
  19. This function process a FAX send operation. This runs
  20. asynchronously as a separate thread. There is one
  21. thread for each outstanding FAX operation.
  22. Arguments:
  23. FaxReceiveItem - FAX receive packet
  24. Return Value:
  25. Error code.
  26. --*/
  27. {
  28. DWORD rVal = ERROR_SUCCESS;
  29. PJOB_ENTRY JobEntry;
  30. DWORD JobId;
  31. PLINE_INFO LineInfo;
  32. PFAX_RECEIVE FaxReceive = NULL;
  33. PFAX_DEV_STATUS FaxStatus = NULL;
  34. DWORD ReceiveSize;
  35. DWORD StatusSize;
  36. BOOL Result;
  37. DWORD BytesNeeded;
  38. DWORDLONG ElapsedTime = 0;
  39. DWORDLONG ReceiveTime = 0;
  40. BOOL DoFaxRoute = FALSE;
  41. DWORD Attrib;
  42. DWORD RecoveredPages,TotalPages;
  43. MS_TAG_INFO MsTagInfo;
  44. BOOL fReceiveNoFile = FALSE;
  45. BOOL ReceiveFailed = FALSE;
  46. PJOB_QUEUE JobQueue = NULL;
  47. BOOL DeviceCanSend;
  48. __try {
  49. LineInfo = FaxReceiveItem->LineInfo;
  50. JobEntry = FaxReceiveItem->JobEntry;
  51. JobQueue = AddJobQueueEntry(
  52. JT_RECEIVE,
  53. FaxReceiveItem->FileName,
  54. NULL,
  55. NULL,
  56. FALSE,
  57. JobEntry
  58. );
  59. if (!JobQueue) {
  60. return ERROR_NOT_ENOUGH_MEMORY;
  61. }
  62. JobId = JobQueue->JobId;
  63. DeviceCanSend = ((LineInfo->Flags & FPF_SEND) == FPF_SEND);
  64. //
  65. // allocate memory for the receive packet
  66. // this is a variable size packet based
  67. // on the size of the strings contained
  68. // withing the packet.
  69. //
  70. ReceiveSize = sizeof(FAX_RECEIVE) + FAXDEVRECEIVE_SIZE;
  71. FaxReceive = MemAlloc( ReceiveSize );
  72. if (!FaxReceive) {
  73. RemoveJobQueueEntry( JobQueue );
  74. JobQueue = NULL;
  75. return ERROR_NOT_ENOUGH_MEMORY;
  76. }
  77. //
  78. // allocate memory for the status packet
  79. // this is a variable size packet based
  80. // on the size of the strings contained
  81. // withing the packet.
  82. //
  83. StatusSize = sizeof(FAX_DEV_STATUS) + FAXDEVREPORTSTATUS_SIZE;
  84. FaxStatus = (PFAX_DEV_STATUS) MemAlloc( StatusSize );
  85. if (!FaxStatus) {
  86. RemoveJobQueueEntry( JobQueue );
  87. JobQueue = NULL;
  88. MemFree( JobQueue );
  89. return ERROR_NOT_ENOUGH_MEMORY;
  90. }
  91. SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
  92. //
  93. // setup the status packet
  94. //
  95. FaxStatus->SizeOfStruct = StatusSize;
  96. //
  97. // setup the receive packet
  98. //
  99. FaxReceive->SizeOfStruct = ReceiveSize;
  100. //
  101. // copy filename into place
  102. //
  103. FaxReceive->FileName = (LPTSTR) ((LPBYTE)FaxReceive + sizeof(FAX_RECEIVE));
  104. _tcscpy( FaxReceive->FileName, FaxReceiveItem->FileName );
  105. FaxReceive->ReceiverName = NULL;
  106. //
  107. // copy number into place right after filename
  108. //
  109. FaxReceive->ReceiverNumber = (LPTSTR) ( (LPBYTE)FaxReceive->FileName +
  110. sizeof(TCHAR)*(_tcslen(FaxReceive->FileName) + 1));
  111. _tcscpy( FaxReceive->ReceiverNumber, LineInfo->Csid );
  112. FaxReceive->Reserved[0] = 0;
  113. FaxReceive->Reserved[1] = 0;
  114. FaxReceive->Reserved[2] = 0;
  115. FaxReceive->Reserved[3] = 0;
  116. Attrib = GetFileAttributes( FaxReceiveDir );
  117. if (Attrib == 0xffffffff) {
  118. MakeDirectory( FaxReceiveDir );
  119. }
  120. Attrib = GetFileAttributes( FaxReceiveDir );
  121. if (Attrib == 0xffffffff) {
  122. FaxLog(
  123. FAXLOG_CATEGORY_INBOUND,
  124. FAXLOG_LEVEL_MAX,
  125. 1,
  126. MSG_FAX_RECEIVE_NODIR,
  127. FaxReceiveDir
  128. );
  129. }
  130. Attrib = GetFileAttributes( FaxReceive->FileName );
  131. if (Attrib == 0xffffffff) {
  132. FaxLog(
  133. FAXLOG_CATEGORY_INBOUND,
  134. FAXLOG_LEVEL_MIN,
  135. 1,
  136. MSG_FAX_RECEIVE_NOFILE,
  137. FaxReceive->FileName
  138. );
  139. fReceiveNoFile = TRUE;
  140. DebugPrint(( TEXT("FaxReceive - %s does not exist"), FaxReceive->FileName ));
  141. } else {
  142. DebugPrint(( TEXT("Starting FAX receive into %s"), FaxReceive->FileName ));
  143. }
  144. //
  145. // do the actual receive
  146. //
  147. __try {
  148. Result = LineInfo->Provider->FaxDevReceive(
  149. (HANDLE) JobEntry->InstanceData,
  150. FaxReceiveItem->hCall,
  151. FaxReceive
  152. );
  153. } __except (EXCEPTION_EXECUTE_HANDLER) {
  154. Result = FALSE;
  155. DebugPrint(( TEXT("FaxDevReceive() failed: 0x%08x"), GetExceptionCode() ));
  156. ReceiveFailed = TRUE;
  157. }
  158. __try {
  159. LineInfo->Provider->FaxDevReportStatus(
  160. (HANDLE) JobEntry->InstanceData,
  161. FaxStatus,
  162. StatusSize,
  163. &BytesNeeded
  164. );
  165. } __except (EXCEPTION_EXECUTE_HANDLER) {
  166. DebugPrint(( TEXT("FaxDevReportStatus() failed: 0x%08x"), GetExceptionCode() ));
  167. }
  168. if (!Result) {
  169. DebugPrint(( TEXT("FAX receive failed: 0x%08x"), FaxStatus->StatusId ));
  170. ReceiveFailed = TRUE;
  171. if (FaxStatus->StatusId == FS_NOT_FAX_CALL) {
  172. if (HandoffCallToRas( LineInfo, FaxReceiveItem->hCall )) {
  173. FaxReceiveItem->hCall = 0;
  174. LineInfo->State = FPS_NOT_FAX_CALL;
  175. DeviceCanSend = FALSE;
  176. }
  177. RemoveJobQueueEntry( JobQueue );
  178. JobQueue = NULL;
  179. DeleteFile( FaxReceive->FileName );
  180. }
  181. if ( (FaxStatus->StatusId == FS_FATAL_ERROR) && (! fReceiveNoFile) ) {
  182. //
  183. // try to recover one or more pages of the received fax
  184. //
  185. if (!TiffRecoverGoodPages(FaxReceive->FileName,&RecoveredPages,&TotalPages) ) {
  186. //
  187. // couldn't recover any pages, just log an error and delete the received fax.
  188. //
  189. rxerr:
  190. FaxLog(
  191. FAXLOG_CATEGORY_INBOUND,
  192. FAXLOG_LEVEL_MIN,
  193. 0,
  194. MSG_FAX_RECEIVE_FAILED
  195. );
  196. //DeleteFile( FaxReceive->FileName );
  197. } else {
  198. //
  199. // recovered some pages, log a message and add to job queue
  200. //
  201. TCHAR RecoverCountStrBuf[64];
  202. TCHAR TotalCountStrBuf[64];
  203. TCHAR TimeStr[128];
  204. LPTSTR ToStr;
  205. TCHAR RecoverFileName[MAX_PATH];
  206. GenerateUniqueFileName( FaxReceiveDir, TEXT("tif"), RecoverFileName, MAX_PATH );
  207. if (!CopyFile(FaxReceive->FileName,RecoverFileName,FALSE)) {
  208. goto rxerr;
  209. }
  210. FormatElapsedTimeStr(
  211. (FILETIME*)&JobEntry->ElapsedTime,
  212. TimeStr,
  213. sizeof(TimeStr)
  214. );
  215. _ltot((LONG) RecoveredPages, RecoverCountStrBuf, 10);
  216. _ltot((LONG) TotalPages, TotalCountStrBuf, 10);
  217. if (FaxStatus->RoutingInfo == NULL || FaxStatus->RoutingInfo[0] == 0) {
  218. ToStr = FaxReceive->ReceiverNumber;
  219. } else {
  220. ToStr = FaxStatus->RoutingInfo;
  221. }
  222. FaxLog(
  223. FAXLOG_CATEGORY_INBOUND,
  224. FAXLOG_LEVEL_MIN,
  225. 8,
  226. MSG_FAX_RECEIVE_FAIL_RECOVER,
  227. RecoverFileName,
  228. FaxStatus->CSI,
  229. FaxStatus->CallerId,
  230. ToStr,
  231. RecoverCountStrBuf,
  232. TotalCountStrBuf,
  233. TimeStr,
  234. JobEntry->LineInfo->DeviceName
  235. );
  236. AddJobQueueEntry( JT_FAIL_RECEIVE,
  237. RecoverFileName,
  238. NULL,
  239. NULL,
  240. FALSE,
  241. NULL );
  242. }
  243. RemoveJobQueueEntry( JobQueue );
  244. JobQueue = NULL;
  245. }
  246. if (FaxStatus->StatusId == FS_USER_ABORT) {
  247. FaxLog(
  248. FAXLOG_CATEGORY_INBOUND,
  249. FAXLOG_LEVEL_MED,
  250. 0,
  251. MSG_FAX_RECEIVE_USER_ABORT
  252. );
  253. RemoveJobQueueEntry( JobQueue );
  254. JobQueue = NULL;
  255. //DeleteFile( FaxReceive->FileName);
  256. }
  257. } else {
  258. __try {
  259. GetSystemTimeAsFileTime( (FILETIME*) &JobEntry->EndTime );
  260. ReceiveTime = JobEntry->StartTime;
  261. JobEntry->ElapsedTime = JobEntry->EndTime - JobEntry->StartTime;
  262. if (!TiffPostProcessFast( FaxReceive->FileName, NULL )) {
  263. DebugPrint(( TEXT("failed to post process the TIFF file") ));
  264. DebugPrint(( TEXT("FAX receive %d failed"), JobId ));
  265. ReceiveFailed = TRUE;
  266. FaxLog(
  267. FAXLOG_CATEGORY_INBOUND,
  268. FAXLOG_LEVEL_MIN,
  269. 0,
  270. MSG_FAX_RECEIVE_FAILED
  271. );
  272. RemoveJobQueueEntry( JobQueue );
  273. JobQueue = NULL;
  274. } else {
  275. TCHAR PageCountStrBuf[64];
  276. TCHAR TimeStr[128];
  277. LPTSTR ToStr;
  278. DebugPrint(( TEXT("FAX receive %d succeeded"), JobId ));
  279. FormatElapsedTimeStr(
  280. (FILETIME*)&JobEntry->ElapsedTime,
  281. TimeStr,
  282. sizeof(TimeStr)
  283. );
  284. _ltot((LONG) FaxStatus->PageCount, PageCountStrBuf, 10);
  285. if (FaxStatus->RoutingInfo == NULL || FaxStatus->RoutingInfo[0] == 0) {
  286. ToStr = FaxReceive->ReceiverNumber;
  287. } else {
  288. ToStr = FaxStatus->RoutingInfo;
  289. }
  290. FaxLog(
  291. FAXLOG_CATEGORY_INBOUND,
  292. FAXLOG_LEVEL_MED,
  293. 7,
  294. MSG_FAX_RECEIVE_SUCCESS,
  295. FaxReceive->FileName,
  296. FaxStatus->CSI,
  297. FaxStatus->CallerId,
  298. ToStr,
  299. PageCountStrBuf,
  300. TimeStr,
  301. JobEntry->LineInfo->DeviceName
  302. );
  303. ElapsedTime = JobEntry->ElapsedTime;
  304. DoFaxRoute = TRUE;
  305. }
  306. } __except (EXCEPTION_EXECUTE_HANDLER) {
  307. DebugPrint(( TEXT("failed to post process the TIFF file, ec=%x"), GetExceptionCode() ));
  308. ReceiveFailed = TRUE;
  309. RemoveJobQueueEntry( JobQueue );
  310. JobQueue = NULL;
  311. }
  312. }
  313. } __except (EXCEPTION_EXECUTE_HANDLER) {
  314. DebugPrint(( TEXT("FAX receive failed due to exception in device provider, ec=0x%08x"), GetExceptionCode() ));
  315. ReceiveFailed = TRUE;
  316. RemoveJobQueueEntry( JobQueue );
  317. JobQueue = NULL;
  318. }
  319. if (PerfCounters && ReceiveFailed && LineInfo->State != FPS_NOT_FAX_CALL) {
  320. InterlockedIncrement( (PLONG)&PerfCounters->InboundFailedReceive );
  321. }
  322. //
  323. // end the job
  324. //
  325. JobEntry->RefCount -= 1;
  326. if (JobEntry->RefCount == 0 && JobEntry->hEventEnd) {
  327. SetEvent( JobEntry->hEventEnd );
  328. }
  329. ReleaseJob( JobEntry );
  330. //
  331. // add the microsoft fax tags to the file
  332. // this is necessary ONLY when we route the
  333. // file when doing a receive. if we are not
  334. // routing the file then it is deleted, so
  335. // adding the tags is not necessary.
  336. //
  337. MsTagInfo.RecipName = FaxReceive->ReceiverName;
  338. MsTagInfo.RecipNumber = FaxReceive->ReceiverNumber;
  339. MsTagInfo.SenderName = NULL;
  340. MsTagInfo.Routing = FaxStatus->RoutingInfo;
  341. MsTagInfo.CallerId = FaxStatus->CallerId;
  342. MsTagInfo.Csid = FaxReceive->ReceiverNumber;
  343. MsTagInfo.Tsid = FaxStatus->CSI;
  344. MsTagInfo.FaxTime = ReceiveTime;
  345. TiffAddMsTags( FaxReceive->FileName, &MsTagInfo );
  346. //
  347. // route the newly received fax
  348. //
  349. if (DoFaxRoute) {
  350. if (PerfCounters){
  351. SYSTEMTIME SystemTime ;
  352. DWORD Seconds ;
  353. HANDLE hFileHandle;
  354. DWORD Bytes = 0 ;
  355. InterlockedIncrement( (LPLONG) &PerfCounters->InboundFaxes ) ;
  356. InterlockedIncrement( (LPLONG) &PerfCounters->TotalFaxes ) ;
  357. FileTimeToSystemTime( (FILETIME*)&ElapsedTime, &SystemTime );
  358. Seconds = (DWORD)( SystemTime.wSecond + 60 * ( SystemTime.wMinute + 60 * SystemTime.wHour ));
  359. InterlockedExchangeAdd( (PLONG)&PerfCounters->InboundPages, (LONG)FaxStatus->PageCount );
  360. InterlockedExchangeAdd( (PLONG)&PerfCounters->TotalPages, (LONG)FaxStatus->PageCount );
  361. hFileHandle = CreateFile(
  362. FaxReceive->FileName,
  363. GENERIC_READ,
  364. 0,
  365. NULL,
  366. OPEN_EXISTING,
  367. FILE_ATTRIBUTE_NORMAL,
  368. NULL
  369. );
  370. if ( hFileHandle != INVALID_HANDLE_VALUE ){
  371. Bytes = GetFileSize( hFileHandle, NULL );
  372. CloseHandle( hFileHandle );
  373. }
  374. EnterCriticalSection( &CsPerfCounters );
  375. InboundSeconds += Seconds;
  376. TotalSeconds += Seconds;
  377. PerfCounters->InboundMinutes = InboundSeconds/60 ;
  378. PerfCounters->TotalMinutes = TotalSeconds/60;
  379. PerfCounters->InboundBytes += Bytes;
  380. PerfCounters->TotalBytes += Bytes;
  381. LeaveCriticalSection( &CsPerfCounters );
  382. }
  383. __try {
  384. BOOL RouteSucceeded;
  385. PROUTE_FAILURE_INFO RouteFailureInfo;
  386. DWORD CountFailureInfo;
  387. PFAX_ROUTE Route = MemAlloc( sizeof(FAX_ROUTE) );
  388. if (Route == NULL) {
  389. __leave;
  390. }
  391. //
  392. // now setup the fax routing data structure
  393. //
  394. Route->SizeOfStruct = sizeof(FAX_ROUTE);
  395. Route->JobId = JobId;
  396. Route->ElapsedTime = ElapsedTime;
  397. Route->ReceiveTime = ReceiveTime;
  398. Route->PageCount = FaxStatus->PageCount;
  399. Route->Csid = StringDup( FaxReceive->ReceiverNumber );
  400. Route->Tsid = StringDup( FaxStatus->CSI );
  401. Route->CallerId = StringDup( FaxStatus->CallerId );
  402. Route->ReceiverName = StringDup( FaxReceive->ReceiverName );
  403. Route->ReceiverNumber = StringDup( FaxReceive->ReceiverNumber );
  404. Route->DeviceName = LineInfo->DeviceName;
  405. Route->DeviceId = LineInfo->PermanentLineID;
  406. Route->RoutingInfo = StringDup( FaxStatus->RoutingInfo );
  407. JobQueue->FaxRoute = Route;
  408. JobQueue->FaxRoute = Route;
  409. RouteSucceeded = FaxRoute(
  410. JobQueue,
  411. FaxReceive->FileName,
  412. Route,
  413. &RouteFailureInfo,
  414. &CountFailureInfo
  415. );
  416. if (!RouteSucceeded)
  417. {
  418. INT i;
  419. TCHAR QueueFileName[MAX_PATH];
  420. EnterCriticalSection( &CsQueue );
  421. //
  422. // wrap the critical section stuff in try block so we always release CsQueue
  423. //
  424. __try {
  425. JobQueue->CountFailureInfo = CountFailureInfo;
  426. for (i = 0; i < (INT) CountFailureInfo; i++) {
  427. JobQueue->RouteFailureInfo[i] = RouteFailureInfo[i];
  428. }
  429. GenerateUniqueFileName( FaxQueueDir, TEXT("fqe"), QueueFileName, sizeof(QueueFileName)/sizeof(WCHAR) );
  430. JobQueue->QueueFileName = StringDup( QueueFileName );
  431. JobQueue->JobType = JT_ROUTING;
  432. JobQueue->JobStatus = JS_RETRYING;
  433. RescheduleJobQueueEntry( JobQueue );
  434. } __except (EXCEPTION_EXECUTE_HANDLER) {
  435. DebugPrint(( TEXT("FaxRoute() crashed, ec=0x%08x"), GetExceptionCode() ));
  436. }
  437. LeaveCriticalSection( &CsQueue );
  438. } else {
  439. RemoveJobQueueEntry( JobQueue );
  440. JobQueue = NULL;
  441. }
  442. } __except (EXCEPTION_EXECUTE_HANDLER) {
  443. DebugPrint(( TEXT("FaxRoute() crashed, ec=0x%08x"), GetExceptionCode() ));
  444. }
  445. }
  446. EnterCriticalSection( &CsQueue );
  447. if (JobQueue && JobQueue->JobEntry && (JobQueue->JobType != JT_ROUTING)) {
  448. JobQueue->JobStatus = JS_DELETING;
  449. JobQueue->JobEntry = NULL;
  450. }
  451. LeaveCriticalSection( &CsQueue );
  452. EndJob( JobEntry );
  453. //
  454. // clean up and exit
  455. //
  456. MemFree( FaxReceiveItem->FileName );
  457. MemFree( FaxReceiveItem );
  458. MemFree( FaxReceive );
  459. MemFree( FaxStatus );
  460. //
  461. // signal our queue if we now have a send capable device available.
  462. // (also false if we're did a RAS handoff, since the device is still in use
  463. //
  464. if (DeviceCanSend) {
  465. ReleaseSemaphore( JobQueueSemaphore, 1, NULL );
  466. }
  467. SetThreadExecutionState(ES_CONTINUOUS);
  468. return rVal;
  469. }
  470. DWORD
  471. StartFaxReceive(
  472. PJOB_ENTRY JobEntry,
  473. HCALL hCall,
  474. PLINE_INFO LineInfo,
  475. LPTSTR FileName,
  476. DWORD FileNameSize
  477. )
  478. /*++
  479. Routine Description:
  480. This function start a FAX receive operation by creating
  481. a thread that calls the appropriate device provider.
  482. Arguments:
  483. hCall - Call handle
  484. dwMessage - Reason for the callback
  485. dwInstance - LINE_INFO pointer
  486. dwParam1 - Callback parameter #1
  487. dwParam2 - Callback parameter #2
  488. dwParam3 - Callback parameter #3
  489. Return Value:
  490. Error code.
  491. --*/
  492. {
  493. PFAX_RECEIVE_ITEM FaxReceiveItem = NULL;
  494. DWORD rVal = ERROR_SUCCESS;
  495. HANDLE hThread;
  496. DWORD ThreadId;
  497. //
  498. // generate a filename for the received fax
  499. //
  500. GenerateUniqueFileName( FaxReceiveDir, TEXT("tif"), FileName, FileNameSize );
  501. //
  502. // allocate the fax receive structure
  503. //
  504. FaxReceiveItem = MemAlloc( sizeof(FAX_RECEIVE_ITEM) );
  505. if (!FaxReceiveItem) {
  506. rVal = ERROR_NOT_ENOUGH_MEMORY;
  507. goto exit;
  508. }
  509. //
  510. // setup the fax receive values
  511. //
  512. FaxReceiveItem->hCall = hCall;
  513. FaxReceiveItem->LineInfo = LineInfo;
  514. FaxReceiveItem->JobEntry = JobEntry;
  515. FaxReceiveItem->FileName = StringDup( FileName );
  516. JobEntry->JobType = JT_RECEIVE;
  517. JobEntry->CallHandle = hCall;
  518. JobEntry->RefCount += 1;
  519. LineInfo->State = FPS_INITIALIZING;
  520. //
  521. // start the receive operation
  522. //
  523. hThread = CreateThread(
  524. NULL,
  525. 1024*100,
  526. (LPTHREAD_START_ROUTINE) FaxReceiveThread,
  527. (LPVOID) FaxReceiveItem,
  528. 0,
  529. &ThreadId
  530. );
  531. if (!hThread) {
  532. MemFree( FaxReceiveItem );
  533. rVal = GetLastError();
  534. } else {
  535. CloseHandle( hThread );
  536. }
  537. exit:
  538. return rVal;
  539. }