windows-nt/Source/XPSP1/NT/printscan/fax/service/server/receive.c
2020-09-26 16:20:57 +08:00

694 lines
20 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
receive.c
Abstract:
This module handles the FAX receive case.
Author:
Wesley Witt (wesw) 6-Mar-1996
Revision History:
--*/
#include "faxsvc.h"
#pragma hdrstop
DWORD
FaxReceiveThread(
PFAX_RECEIVE_ITEM FaxReceiveItem
)
/*++
Routine Description:
This function process a FAX send operation. This runs
asynchronously as a separate thread. There is one
thread for each outstanding FAX operation.
Arguments:
FaxReceiveItem - FAX receive packet
Return Value:
Error code.
--*/
{
DWORD rVal = ERROR_SUCCESS;
PJOB_ENTRY JobEntry;
DWORD JobId;
PLINE_INFO LineInfo;
PFAX_RECEIVE FaxReceive = NULL;
PFAX_DEV_STATUS FaxStatus = NULL;
DWORD ReceiveSize;
DWORD StatusSize;
BOOL Result;
DWORD BytesNeeded;
DWORDLONG ElapsedTime = 0;
DWORDLONG ReceiveTime = 0;
BOOL DoFaxRoute = FALSE;
DWORD Attrib;
DWORD RecoveredPages,TotalPages;
MS_TAG_INFO MsTagInfo;
BOOL fReceiveNoFile = FALSE;
BOOL ReceiveFailed = FALSE;
PJOB_QUEUE JobQueue = NULL;
BOOL DeviceCanSend;
__try {
LineInfo = FaxReceiveItem->LineInfo;
JobEntry = FaxReceiveItem->JobEntry;
JobQueue = AddJobQueueEntry(
JT_RECEIVE,
FaxReceiveItem->FileName,
NULL,
NULL,
FALSE,
JobEntry
);
if (!JobQueue) {
return ERROR_NOT_ENOUGH_MEMORY;
}
JobId = JobQueue->JobId;
DeviceCanSend = ((LineInfo->Flags & FPF_SEND) == FPF_SEND);
//
// allocate memory for the receive packet
// this is a variable size packet based
// on the size of the strings contained
// withing the packet.
//
ReceiveSize = sizeof(FAX_RECEIVE) + FAXDEVRECEIVE_SIZE;
FaxReceive = MemAlloc( ReceiveSize );
if (!FaxReceive) {
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
return ERROR_NOT_ENOUGH_MEMORY;
}
//
// allocate memory for the status packet
// this is a variable size packet based
// on the size of the strings contained
// withing the packet.
//
StatusSize = sizeof(FAX_DEV_STATUS) + FAXDEVREPORTSTATUS_SIZE;
FaxStatus = (PFAX_DEV_STATUS) MemAlloc( StatusSize );
if (!FaxStatus) {
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
MemFree( JobQueue );
return ERROR_NOT_ENOUGH_MEMORY;
}
SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS);
//
// setup the status packet
//
FaxStatus->SizeOfStruct = StatusSize;
//
// setup the receive packet
//
FaxReceive->SizeOfStruct = ReceiveSize;
//
// copy filename into place
//
FaxReceive->FileName = (LPTSTR) ((LPBYTE)FaxReceive + sizeof(FAX_RECEIVE));
_tcscpy( FaxReceive->FileName, FaxReceiveItem->FileName );
FaxReceive->ReceiverName = NULL;
//
// copy number into place right after filename
//
FaxReceive->ReceiverNumber = (LPTSTR) ( (LPBYTE)FaxReceive->FileName +
sizeof(TCHAR)*(_tcslen(FaxReceive->FileName) + 1));
_tcscpy( FaxReceive->ReceiverNumber, LineInfo->Csid );
FaxReceive->Reserved[0] = 0;
FaxReceive->Reserved[1] = 0;
FaxReceive->Reserved[2] = 0;
FaxReceive->Reserved[3] = 0;
Attrib = GetFileAttributes( FaxReceiveDir );
if (Attrib == 0xffffffff) {
MakeDirectory( FaxReceiveDir );
}
Attrib = GetFileAttributes( FaxReceiveDir );
if (Attrib == 0xffffffff) {
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MAX,
1,
MSG_FAX_RECEIVE_NODIR,
FaxReceiveDir
);
}
Attrib = GetFileAttributes( FaxReceive->FileName );
if (Attrib == 0xffffffff) {
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
1,
MSG_FAX_RECEIVE_NOFILE,
FaxReceive->FileName
);
fReceiveNoFile = TRUE;
DebugPrint(( TEXT("FaxReceive - %s does not exist"), FaxReceive->FileName ));
} else {
DebugPrint(( TEXT("Starting FAX receive into %s"), FaxReceive->FileName ));
}
//
// do the actual receive
//
__try {
Result = LineInfo->Provider->FaxDevReceive(
(HANDLE) JobEntry->InstanceData,
FaxReceiveItem->hCall,
FaxReceive
);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Result = FALSE;
DebugPrint(( TEXT("FaxDevReceive() failed: 0x%08x"), GetExceptionCode() ));
ReceiveFailed = TRUE;
}
__try {
LineInfo->Provider->FaxDevReportStatus(
(HANDLE) JobEntry->InstanceData,
FaxStatus,
StatusSize,
&BytesNeeded
);
} __except (EXCEPTION_EXECUTE_HANDLER) {
DebugPrint(( TEXT("FaxDevReportStatus() failed: 0x%08x"), GetExceptionCode() ));
}
if (!Result) {
DebugPrint(( TEXT("FAX receive failed: 0x%08x"), FaxStatus->StatusId ));
ReceiveFailed = TRUE;
if (FaxStatus->StatusId == FS_NOT_FAX_CALL) {
if (HandoffCallToRas( LineInfo, FaxReceiveItem->hCall )) {
FaxReceiveItem->hCall = 0;
LineInfo->State = FPS_NOT_FAX_CALL;
DeviceCanSend = FALSE;
}
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
DeleteFile( FaxReceive->FileName );
}
if ( (FaxStatus->StatusId == FS_FATAL_ERROR) && (! fReceiveNoFile) ) {
//
// try to recover one or more pages of the received fax
//
if (!TiffRecoverGoodPages(FaxReceive->FileName,&RecoveredPages,&TotalPages) ) {
//
// couldn't recover any pages, just log an error and delete the received fax.
//
rxerr:
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
0,
MSG_FAX_RECEIVE_FAILED
);
//DeleteFile( FaxReceive->FileName );
} else {
//
// recovered some pages, log a message and add to job queue
//
TCHAR RecoverCountStrBuf[64];
TCHAR TotalCountStrBuf[64];
TCHAR TimeStr[128];
LPTSTR ToStr;
TCHAR RecoverFileName[MAX_PATH];
GenerateUniqueFileName( FaxReceiveDir, TEXT("tif"), RecoverFileName, MAX_PATH );
if (!CopyFile(FaxReceive->FileName,RecoverFileName,FALSE)) {
goto rxerr;
}
FormatElapsedTimeStr(
(FILETIME*)&JobEntry->ElapsedTime,
TimeStr,
sizeof(TimeStr)
);
_ltot((LONG) RecoveredPages, RecoverCountStrBuf, 10);
_ltot((LONG) TotalPages, TotalCountStrBuf, 10);
if (FaxStatus->RoutingInfo == NULL || FaxStatus->RoutingInfo[0] == 0) {
ToStr = FaxReceive->ReceiverNumber;
} else {
ToStr = FaxStatus->RoutingInfo;
}
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
8,
MSG_FAX_RECEIVE_FAIL_RECOVER,
RecoverFileName,
FaxStatus->CSI,
FaxStatus->CallerId,
ToStr,
RecoverCountStrBuf,
TotalCountStrBuf,
TimeStr,
JobEntry->LineInfo->DeviceName
);
AddJobQueueEntry( JT_FAIL_RECEIVE,
RecoverFileName,
NULL,
NULL,
FALSE,
NULL );
}
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
}
if (FaxStatus->StatusId == FS_USER_ABORT) {
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MED,
0,
MSG_FAX_RECEIVE_USER_ABORT
);
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
//DeleteFile( FaxReceive->FileName);
}
} else {
__try {
GetSystemTimeAsFileTime( (FILETIME*) &JobEntry->EndTime );
ReceiveTime = JobEntry->StartTime;
JobEntry->ElapsedTime = JobEntry->EndTime - JobEntry->StartTime;
if (!TiffPostProcessFast( FaxReceive->FileName, NULL )) {
DebugPrint(( TEXT("failed to post process the TIFF file") ));
DebugPrint(( TEXT("FAX receive %d failed"), JobId ));
ReceiveFailed = TRUE;
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
0,
MSG_FAX_RECEIVE_FAILED
);
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
} else {
TCHAR PageCountStrBuf[64];
TCHAR TimeStr[128];
LPTSTR ToStr;
DebugPrint(( TEXT("FAX receive %d succeeded"), JobId ));
FormatElapsedTimeStr(
(FILETIME*)&JobEntry->ElapsedTime,
TimeStr,
sizeof(TimeStr)
);
_ltot((LONG) FaxStatus->PageCount, PageCountStrBuf, 10);
if (FaxStatus->RoutingInfo == NULL || FaxStatus->RoutingInfo[0] == 0) {
ToStr = FaxReceive->ReceiverNumber;
} else {
ToStr = FaxStatus->RoutingInfo;
}
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MED,
7,
MSG_FAX_RECEIVE_SUCCESS,
FaxReceive->FileName,
FaxStatus->CSI,
FaxStatus->CallerId,
ToStr,
PageCountStrBuf,
TimeStr,
JobEntry->LineInfo->DeviceName
);
ElapsedTime = JobEntry->ElapsedTime;
DoFaxRoute = TRUE;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
DebugPrint(( TEXT("failed to post process the TIFF file, ec=%x"), GetExceptionCode() ));
ReceiveFailed = TRUE;
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
DebugPrint(( TEXT("FAX receive failed due to exception in device provider, ec=0x%08x"), GetExceptionCode() ));
ReceiveFailed = TRUE;
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
}
if (PerfCounters && ReceiveFailed && LineInfo->State != FPS_NOT_FAX_CALL) {
InterlockedIncrement( (PLONG)&PerfCounters->InboundFailedReceive );
}
//
// end the job
//
JobEntry->RefCount -= 1;
if (JobEntry->RefCount == 0 && JobEntry->hEventEnd) {
SetEvent( JobEntry->hEventEnd );
}
ReleaseJob( JobEntry );
//
// add the microsoft fax tags to the file
// this is necessary ONLY when we route the
// file when doing a receive. if we are not
// routing the file then it is deleted, so
// adding the tags is not necessary.
//
MsTagInfo.RecipName = FaxReceive->ReceiverName;
MsTagInfo.RecipNumber = FaxReceive->ReceiverNumber;
MsTagInfo.SenderName = NULL;
MsTagInfo.Routing = FaxStatus->RoutingInfo;
MsTagInfo.CallerId = FaxStatus->CallerId;
MsTagInfo.Csid = FaxReceive->ReceiverNumber;
MsTagInfo.Tsid = FaxStatus->CSI;
MsTagInfo.FaxTime = ReceiveTime;
TiffAddMsTags( FaxReceive->FileName, &MsTagInfo );
//
// route the newly received fax
//
if (DoFaxRoute) {
if (PerfCounters){
SYSTEMTIME SystemTime ;
DWORD Seconds ;
HANDLE hFileHandle;
DWORD Bytes = 0 ;
InterlockedIncrement( (LPLONG) &PerfCounters->InboundFaxes ) ;
InterlockedIncrement( (LPLONG) &PerfCounters->TotalFaxes ) ;
FileTimeToSystemTime( (FILETIME*)&ElapsedTime, &SystemTime );
Seconds = (DWORD)( SystemTime.wSecond + 60 * ( SystemTime.wMinute + 60 * SystemTime.wHour ));
InterlockedExchangeAdd( (PLONG)&PerfCounters->InboundPages, (LONG)FaxStatus->PageCount );
InterlockedExchangeAdd( (PLONG)&PerfCounters->TotalPages, (LONG)FaxStatus->PageCount );
hFileHandle = CreateFile(
FaxReceive->FileName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if ( hFileHandle != INVALID_HANDLE_VALUE ){
Bytes = GetFileSize( hFileHandle, NULL );
CloseHandle( hFileHandle );
}
EnterCriticalSection( &CsPerfCounters );
InboundSeconds += Seconds;
TotalSeconds += Seconds;
PerfCounters->InboundMinutes = InboundSeconds/60 ;
PerfCounters->TotalMinutes = TotalSeconds/60;
PerfCounters->InboundBytes += Bytes;
PerfCounters->TotalBytes += Bytes;
LeaveCriticalSection( &CsPerfCounters );
}
__try {
BOOL RouteSucceeded;
PROUTE_FAILURE_INFO RouteFailureInfo;
DWORD CountFailureInfo;
PFAX_ROUTE Route = MemAlloc( sizeof(FAX_ROUTE) );
if (Route == NULL) {
__leave;
}
//
// now setup the fax routing data structure
//
Route->SizeOfStruct = sizeof(FAX_ROUTE);
Route->JobId = JobId;
Route->ElapsedTime = ElapsedTime;
Route->ReceiveTime = ReceiveTime;
Route->PageCount = FaxStatus->PageCount;
Route->Csid = StringDup( FaxReceive->ReceiverNumber );
Route->Tsid = StringDup( FaxStatus->CSI );
Route->CallerId = StringDup( FaxStatus->CallerId );
Route->ReceiverName = StringDup( FaxReceive->ReceiverName );
Route->ReceiverNumber = StringDup( FaxReceive->ReceiverNumber );
Route->DeviceName = LineInfo->DeviceName;
Route->DeviceId = LineInfo->PermanentLineID;
Route->RoutingInfo = StringDup( FaxStatus->RoutingInfo );
JobQueue->FaxRoute = Route;
JobQueue->FaxRoute = Route;
RouteSucceeded = FaxRoute(
JobQueue,
FaxReceive->FileName,
Route,
&RouteFailureInfo,
&CountFailureInfo
);
if (!RouteSucceeded)
{
INT i;
TCHAR QueueFileName[MAX_PATH];
EnterCriticalSection( &CsQueue );
//
// wrap the critical section stuff in try block so we always release CsQueue
//
__try {
JobQueue->CountFailureInfo = CountFailureInfo;
for (i = 0; i < (INT) CountFailureInfo; i++) {
JobQueue->RouteFailureInfo[i] = RouteFailureInfo[i];
}
GenerateUniqueFileName( FaxQueueDir, TEXT("fqe"), QueueFileName, sizeof(QueueFileName)/sizeof(WCHAR) );
JobQueue->QueueFileName = StringDup( QueueFileName );
JobQueue->JobType = JT_ROUTING;
JobQueue->JobStatus = JS_RETRYING;
RescheduleJobQueueEntry( JobQueue );
} __except (EXCEPTION_EXECUTE_HANDLER) {
DebugPrint(( TEXT("FaxRoute() crashed, ec=0x%08x"), GetExceptionCode() ));
}
LeaveCriticalSection( &CsQueue );
} else {
RemoveJobQueueEntry( JobQueue );
JobQueue = NULL;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
DebugPrint(( TEXT("FaxRoute() crashed, ec=0x%08x"), GetExceptionCode() ));
}
}
EnterCriticalSection( &CsQueue );
if (JobQueue && JobQueue->JobEntry && (JobQueue->JobType != JT_ROUTING)) {
JobQueue->JobStatus = JS_DELETING;
JobQueue->JobEntry = NULL;
}
LeaveCriticalSection( &CsQueue );
EndJob( JobEntry );
//
// clean up and exit
//
MemFree( FaxReceiveItem->FileName );
MemFree( FaxReceiveItem );
MemFree( FaxReceive );
MemFree( FaxStatus );
//
// signal our queue if we now have a send capable device available.
// (also false if we're did a RAS handoff, since the device is still in use
//
if (DeviceCanSend) {
ReleaseSemaphore( JobQueueSemaphore, 1, NULL );
}
SetThreadExecutionState(ES_CONTINUOUS);
return rVal;
}
DWORD
StartFaxReceive(
PJOB_ENTRY JobEntry,
HCALL hCall,
PLINE_INFO LineInfo,
LPTSTR FileName,
DWORD FileNameSize
)
/*++
Routine Description:
This function start a FAX receive operation by creating
a thread that calls the appropriate device provider.
Arguments:
hCall - Call handle
dwMessage - Reason for the callback
dwInstance - LINE_INFO pointer
dwParam1 - Callback parameter #1
dwParam2 - Callback parameter #2
dwParam3 - Callback parameter #3
Return Value:
Error code.
--*/
{
PFAX_RECEIVE_ITEM FaxReceiveItem = NULL;
DWORD rVal = ERROR_SUCCESS;
HANDLE hThread;
DWORD ThreadId;
//
// generate a filename for the received fax
//
GenerateUniqueFileName( FaxReceiveDir, TEXT("tif"), FileName, FileNameSize );
//
// allocate the fax receive structure
//
FaxReceiveItem = MemAlloc( sizeof(FAX_RECEIVE_ITEM) );
if (!FaxReceiveItem) {
rVal = ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
//
// setup the fax receive values
//
FaxReceiveItem->hCall = hCall;
FaxReceiveItem->LineInfo = LineInfo;
FaxReceiveItem->JobEntry = JobEntry;
FaxReceiveItem->FileName = StringDup( FileName );
JobEntry->JobType = JT_RECEIVE;
JobEntry->CallHandle = hCall;
JobEntry->RefCount += 1;
LineInfo->State = FPS_INITIALIZING;
//
// start the receive operation
//
hThread = CreateThread(
NULL,
1024*100,
(LPTHREAD_START_ROUTINE) FaxReceiveThread,
(LPVOID) FaxReceiveItem,
0,
&ThreadId
);
if (!hThread) {
MemFree( FaxReceiveItem );
rVal = GetLastError();
} else {
CloseHandle( hThread );
}
exit:
return rVal;
}