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.
 
 
 
 
 
 

1701 lines
60 KiB

/*++
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"
#include "faxreg.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.
--*/
{
WCHAR ArchiveFileName[MAX_PATH];
DWORD rVal = ERROR_SUCCESS;
DWORD dwRes;
PJOB_ENTRY JobEntry;
DWORD JobId;
PLINE_INFO LineInfo;
PFAX_RECEIVE FaxReceive = NULL;
DWORD ReceiveSize;
BOOL Result;
DWORDLONG ElapsedTime = 0;
DWORDLONG ReceiveTime = 0;
BOOL DoFaxRoute = FALSE;
DWORD Attrib;
DWORD RecoveredPages,TotalPages;
MS_TAG_INFO MsTagInfo = {0};
BOOL fReceiveNoFile = FALSE;
BOOL ReceiveFailed = FALSE;
PJOB_QUEUE JobQueue = NULL;
BOOL fSystemAbort;
BOOL DeviceCanSend = TRUE; // TRUE if the device is free for send after the receive is completed.
// FALSE for handoff jobs and devices that are not send enabled.
// Its value determines if to notify the queue that a device was freed up.
PJOB_QUEUE lpRecoverJob = NULL; // Pointer to a receive recover job if created.
LPFSPI_JOB_STATUS pFaxStatus = NULL;
LPFSPI_JOB_STATUS pOrigFaxStatus = NULL;
DEBUG_FUNCTION_NAME(TEXT("FaxReceiveThread"));
DWORD ec;
BOOL fCOMInitiliazed = FALSE;
HRESULT hr;
WCHAR wszArchiveFolder[MAX_PATH];
FSPI_JOB_STATUS FakedFaxStatus = {0};
BOOL bFakeStatus = FALSE;
DWORD dwSttRes = ERROR_SUCCESS;
WCHAR LastExStatusString[EX_STATUS_STRING_LEN] = {0}; // The last extended status string of this job (when it was active)
DWORD dwLastJobExtendedStatus = 0;
BOOL fSetSystemIdleTimer = TRUE;
Assert(FaxReceiveItem);
//
// Don't let the system go to sleep in the middle of the fax transmission.
//
if (NULL == SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_CONTINUOUS))
{
fSetSystemIdleTimer = FALSE;
DebugPrintEx(DEBUG_ERR,
TEXT("SetThreadExecutionState() failed"));
}
//
// Successfully created new receive job on line. Update counter
//
(VOID) UpdateDeviceJobsCounter ( FaxReceiveItem->LineInfo, // Device to update
FALSE, // Receiving
1, // Number of new jobs
TRUE); // Enable events
LineInfo = FaxReceiveItem->LineInfo;
Assert(LineInfo);
JobEntry = FaxReceiveItem->JobEntry;
Assert(JobEntry);
//
// Note: The receive job is not backed up by a file.
// When we turn it into a routing job (JT_ROUTING) we will create a .FQE
// file for it.
JobQueue=JobEntry->lpJobQueueEntry;
Assert(JobQueue);
JobId = JobQueue->JobId;
DebugPrintEx( DEBUG_MSG,
TEXT("[JobId: %ld] Start receive. hLine= 0x%0X hCall=0x%0X"),
JobId,
LineInfo->hLine,
FaxReceiveItem->hCall);
//
// 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 = (PFAX_RECEIVE) MemAlloc( ReceiveSize );
if (!FaxReceive)
{
TCHAR strTo[20+1]={0};
TCHAR strDeviceName[MAX_PATH]={0};
ReceiveFailed = TRUE;
DebugPrintEx(DEBUG_ERR,TEXT("Failed to allocate memory for FAX_RECEIVE"));
//
// Fake job status;
//
bFakeStatus = TRUE;
//
// Point to FakedFaxStatus on stack - all it's field are initialized to zero
//
pFaxStatus = &FakedFaxStatus;
FakedFaxStatus.dwSizeOfStruct = sizeof (FakedFaxStatus);
//
// Fake general failure
//
pFaxStatus->dwJobStatus = FSPI_JS_FAILED;
pFaxStatus->dwExtendedStatus = FSPI_ES_FATAL_ERROR;
EnterCriticalSection (&g_CsLine);
_tcsncpy(strTo,LineInfo->Csid,ARR_SIZE(strTo)-1);
_tcsncpy(strDeviceName,LineInfo->DeviceName,ARR_SIZE(strDeviceName)-1);
LeaveCriticalSection (&g_CsLine);
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
5,
MSG_FAX_RECEIVE_FAILED_EX,
NULL,
NULL,
strTo,
NULL,
strDeviceName
);
}
if (NULL != FaxReceive)
{
//
// setup the receive packet
//
FaxReceive->SizeOfStruct = ReceiveSize;
//
// copy filename into place
//
FaxReceive->FileName = (LPTSTR) ((LPBYTE)FaxReceive + sizeof(FAX_RECEIVE));
_tcscpy( FaxReceive->FileName, FaxReceiveItem->FileName );
//
// copy number into place right after filename
//
FaxReceive->ReceiverNumber = (LPTSTR) ( (LPBYTE)FaxReceive->FileName +
sizeof(TCHAR)*(_tcslen(FaxReceive->FileName) + 1));
EnterCriticalSection (&g_CsLine);
_tcscpy( FaxReceive->ReceiverNumber, LineInfo->Csid );
//
// copy device name into place right after number
//
FaxReceive->ReceiverName = (LPTSTR) ( (LPBYTE)FaxReceive->ReceiverNumber +
sizeof(TCHAR)*(_tcslen(FaxReceive->ReceiverNumber) + 1));
_tcscpy( FaxReceive->ReceiverName, LineInfo->DeviceName );
LeaveCriticalSection (&g_CsLine);
FaxReceive->Reserved[0] = 0;
FaxReceive->Reserved[1] = 0;
FaxReceive->Reserved[2] = 0;
FaxReceive->Reserved[3] = 0;
dwRes = IsValidFaxFolder(g_wszFaxQueueDir);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(DEBUG_ERR,
TEXT("[Job: %ld] FaxReceive - IsValidFaxFolder failed for Queue directory [%s] (ec=%lu)"),
JobId,
g_wszFaxQueueDir,
dwRes);
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
2,
MSG_FAX_QUEUE_FOLDER_ERR,
g_wszFaxQueueDir,
DWORD2DECIMAL(dwRes)
);
}
Attrib = GetFileAttributes( FaxReceive->FileName );
if (Attrib == 0xffffffff)
{
dwRes = GetLastError();
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
2,
MSG_FAX_RECEIVE_NOFILE,
FaxReceive->FileName,
DWORD2DECIMAL(dwRes)
);
fReceiveNoFile = TRUE;
DebugPrintEx(DEBUG_WRN,TEXT("[Job: %ld] FaxReceive - %s does not exist"), JobId, FaxReceive->FileName );
}
else
{
DebugPrintEx(DEBUG_MSG, TEXT("[Job: %ld] Starting FAX receive into %s"), JobId,FaxReceive->FileName );
}
//
// do the actual receive
//
__try
{
Result = LineInfo->Provider->FaxDevReceive(
(HANDLE) JobEntry->InstanceData,
FaxReceiveItem->hCall,
FaxReceive
);
}
__except (HandleFaxExtensionFault(EXCEPTION_SOURCE_FSP, LineInfo->Provider->FriendlyName, GetExceptionCode()))
{
ASSERT_FALSE;
}
EnterCriticalSection (&g_CsJob);
GetSystemTimeAsFileTime( (FILETIME*) &JobEntry->EndTime );
ReceiveTime = JobEntry->StartTime;
JobEntry->ElapsedTime = JobEntry->EndTime - JobEntry->StartTime;
LeaveCriticalSection (&g_CsJob);
//
// Get the final status of the job.
//
dwSttRes = GetDevStatus((HANDLE)JobEntry->InstanceData,
LineInfo,
&pFaxStatus);
if (dwSttRes != ERROR_SUCCESS)
{
DebugPrintEx(DEBUG_ERR,
TEXT("[Job: %ld] GetDevStatus failed - %d"),
JobId,
dwSttRes);
//
// Fake job status;
//
bFakeStatus = TRUE;
}
else if ((FSPI_JS_ABORTED != pFaxStatus->dwJobStatus) &&
(FSPI_JS_COMPLETED != pFaxStatus->dwJobStatus) &&
(FSPI_JS_FAILED != pFaxStatus->dwJobStatus) &&
(FSPI_JS_FAILED_NO_RETRY != pFaxStatus->dwJobStatus) &&
(FSPI_JS_DELETED != pFaxStatus->dwJobStatus))
{
//
// Status returned is unacceptable - fake one.
//
bFakeStatus = TRUE;
DebugPrintEx(DEBUG_WRN,
TEXT("GetDevStatus return unacceptable status - %d. Faking the status"),
pFaxStatus->dwJobStatus);
pOrigFaxStatus = pFaxStatus;
memcpy (&FakedFaxStatus, pFaxStatus, sizeof (FakedFaxStatus));
if (pFaxStatus->fAvailableStatusInfo & FSPI_JOB_STATUS_INFO_FSP_PRIVATE_STATUS_CODE)
{
//
// The FSP returned proprietary status.
//
FakedFaxStatus.dwExtendedStatus = pFaxStatus->dwExtendedStatus;
FakedFaxStatus.dwExtendedStatusStringId = pFaxStatus->dwExtendedStatusStringId;
}
pFaxStatus = NULL;
}
if (bFakeStatus)
{
//
// Fake status code
//
pFaxStatus = &FakedFaxStatus;
FakedFaxStatus.dwSizeOfStruct = sizeof (FakedFaxStatus);
if (Result)
{
//
// Fake success
//
pFaxStatus->dwJobStatus = FSPI_JS_COMPLETED;
if (0 == pFaxStatus->dwExtendedStatus)
{
//
// The FSP did not report proprietary status
//
pFaxStatus->dwExtendedStatus = FSPI_ES_CALL_COMPLETED;
}
}
else
{
//
// Fake general failure
//
pFaxStatus->dwJobStatus = FSPI_JS_FAILED;
if (0 == pFaxStatus->dwExtendedStatus)
{
//
// The FSP did not report proprietry status
//
pFaxStatus->dwExtendedStatus = FSPI_ES_FATAL_ERROR;
}
}
}
if (!Result)
{
DebugPrintEx(DEBUG_ERR,
TEXT("[Job: %ld] FAX receive failed. FSP reported ")
TEXT("status: 0x%08X, extended status: 0x%08x"),
JobId,
pFaxStatus->dwJobStatus,
pFaxStatus->dwExtendedStatus);
ReceiveFailed = TRUE;
if (pFaxStatus->dwExtendedStatus == FSPI_ES_NOT_FAX_CALL)
{
DebugPrintEx(DEBUG_MSG,
TEXT("[Job: %ld] FSP reported that call is not ")
TEXT("a fax call. Handing off to RAS."),
JobId);
if (HandoffCallToRas( LineInfo, FaxReceiveItem->hCall ))
{
FaxReceiveItem->hCall = 0;
EnterCriticalSection (&g_CsLine);
LineInfo->State = FPS_NOT_FAX_CALL;
LeaveCriticalSection (&g_CsLine);
//
// In case of a handoff to RAS the device is still in use and can not send.
// We do not want to notify the queue a device was freed.
//
DeviceCanSend = FALSE;
}
else
{
//
// since the handoff failed we must notify
// the fsp so that the call can be put onhook
//
__try
{
LineInfo->Provider->FaxDevAbortOperation(
(HANDLE) JobEntry->InstanceData
);
}
__except (HandleFaxExtensionFault(EXCEPTION_SOURCE_FSP, LineInfo->Provider->FriendlyName, GetExceptionCode()))
{
ASSERT_FALSE;
}
}
}
else
if (FSPI_JS_ABORTED != pFaxStatus->dwJobStatus)
{
if (!fReceiveNoFile)
{
//
// We have a partially received fax.
// The FSP reported some failure but it was not an ABORT.
// 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.
//
LPTSTR ToStr;
TCHAR TotalCountStrBuf[64];
if (pFaxStatus->fAvailableStatusInfo & FSPI_JOB_STATUS_INFO_PAGECOUNT)
{
_ltot((LONG) pFaxStatus->dwPageCount, TotalCountStrBuf, 10);
}
else
{
_ltot((LONG) 0, TotalCountStrBuf, 10);
}
if ( (NULL == pFaxStatus->lpwstrRoutingInfo) ||
(pFaxStatus->lpwstrRoutingInfo[0] == TEXT('\0')) )
{
ToStr = FaxReceive->ReceiverNumber;
}
else
{
ToStr = pFaxStatus->lpwstrRoutingInfo;
}
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
5,
MSG_FAX_RECEIVE_FAILED_EX,
pFaxStatus->lpwstrRemoteStationId,
pFaxStatus->lpwstrCallerId,
ToStr,
TotalCountStrBuf,
JobEntry->LineInfo->DeviceName
);
}
else
{
//
// recovered some pages, log a message and add to job queue
//
TCHAR RecoverCountStrBuf[64];
TCHAR TotalCountStrBuf[64];
TCHAR TimeStr[128];
LPTSTR ToStr;
FormatElapsedTimeStr(
(FILETIME*)&JobEntry->ElapsedTime,
TimeStr,
ARR_SIZE(TimeStr)
);
_ltot((LONG) RecoveredPages, RecoverCountStrBuf, 10);
_ltot((LONG) TotalPages, TotalCountStrBuf, 10);
if ( (NULL == pFaxStatus->lpwstrRoutingInfo) ||
(pFaxStatus->lpwstrRoutingInfo[0] == TEXT('\0')) )
{
ToStr = FaxReceive->ReceiverNumber;
}
else
{
ToStr = pFaxStatus->lpwstrRoutingInfo;
}
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
8,
MSG_FAX_RECEIVE_FAIL_RECOVER,
FaxReceive->FileName,
pFaxStatus->lpwstrRemoteStationId,
pFaxStatus->lpwstrCallerId,
ToStr,
RecoverCountStrBuf,
TotalCountStrBuf,
TimeStr,
JobEntry->LineInfo->DeviceName
);
//
// Use the JobQueue to temporary store the original extended status for Activity Logging purpose
// This value will be overwritten when the activity logging is done
// Get extended status string
//
if (pFaxStatus->fAvailableStatusInfo & FSPI_JOB_STATUS_INFO_FSP_PRIVATE_STATUS_CODE)
{
//
// Proprietary extended status
//
if (pFaxStatus->dwExtendedStatusStringId != 0)
{
//
// We have a string ID, try to load it.
//
DWORD Size = 0;
HINSTANCE hLoadInstance = NULL;
if ( !_tcsicmp(JobEntry->LineInfo->Provider->szGUID,REGVAL_T30_PROVIDER_GUID_STRING) )
{ // special case where the FSP is our FSP (fxst30.dll).
hLoadInstance = g_hResource;
}
else
{
hLoadInstance = JobEntry->LineInfo->Provider->hModule;
}
Size = LoadString (hLoadInstance,
pFaxStatus->dwExtendedStatusStringId,
JobQueue->ExStatusString,
ARR_SIZE(JobQueue->ExStatusString));
if (Size == 0)
{
ec = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to load extended status string (ec: %ld) stringid"),
ec,
pFaxStatus->dwExtendedStatusStringId);
}
}
}
else
{
//
// Well known extended status
//
LPTSTR ResStr = MapFSPIJobExtendedStatusToString(pFaxStatus->dwExtendedStatus);
if (NULL == ResStr)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Unexpected extended status. Extended Status: %ld"),
pFaxStatus->dwExtendedStatus);
}
else
{
wcsncpy(JobQueue->ExStatusString, ResStr, ARR_SIZE(JobQueue->ExStatusString) - 1);
}
}
//
// Now, change status and extended status to partially received
//
pFaxStatus->dwJobStatus = FSPI_JS_COMPLETED;
pFaxStatus->dwExtendedStatus = FSPI_ES_PARTIALLY_RECEIVED;
//
// Ignore the private status code and the proprietary string returned from the FSP.
//
pFaxStatus->dwExtendedStatusStringId = 0;
pFaxStatus->fAvailableStatusInfo &= ~FSPI_JOB_STATUS_INFO_FSP_PRIVATE_STATUS_CODE;
DoFaxRoute = TRUE;
}
}
}
else
{
//
// FSPI_JS_ABORTED == pFaxStatus->dwJobStatus
//
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MAX,
0,
MSG_FAX_RECEIVE_USER_ABORT
);
}
}
else
{
TCHAR PageCountStrBuf[64];
TCHAR TimeStr[128];
LPTSTR ToStr;
if (!TiffPostProcessFast( FaxReceive->FileName, NULL ))
{
ASSERT_FALSE;
DebugPrintEx(
DEBUG_WRN,
TEXT("[Job: %ld] failed to post process the TIFF file, FileName %s"),
JobId,
FaxReceive->FileName);
}
DebugPrintEx(
DEBUG_MSG,
TEXT("[Job: %ld] FAX receive succeeded"),
JobId);
FormatElapsedTimeStr(
(FILETIME*)&JobEntry->ElapsedTime,
TimeStr,
ARR_SIZE(TimeStr)
);
_ltot((LONG) pFaxStatus->dwPageCount, PageCountStrBuf, 10);
if ( (NULL == pFaxStatus->lpwstrRoutingInfo) ||
(pFaxStatus->lpwstrRoutingInfo[0] == TEXT('\0')) )
{
ToStr = FaxReceive->ReceiverNumber;
}
else
{
ToStr = pFaxStatus->lpwstrRoutingInfo;
}
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MAX,
7,
MSG_FAX_RECEIVE_SUCCESS,
FaxReceive->FileName,
pFaxStatus->lpwstrRemoteStationId,
pFaxStatus->lpwstrCallerId,
ToStr,
PageCountStrBuf,
TimeStr,
JobEntry->LineInfo->DeviceName
);
ElapsedTime = JobEntry->ElapsedTime;
DoFaxRoute = TRUE;
}
}
if (g_pFaxPerfCounters && ReceiveFailed && LineInfo->State != FPS_NOT_FAX_CALL)
{
InterlockedIncrement( (PLONG)&g_pFaxPerfCounters->InboundFailedReceive );
}
//
// Call FaxDevEndJob() and Release the receive device but do not delete the job.
//
if (!ReleaseJob( JobEntry ))
{
DebugPrintEx( DEBUG_ERR,
TEXT("[Job: %ld] FAX ReleaseJob failed , ec=0x%08x"),
JobId,
GetLastError());
}
//
// We just successfully completed a receive job on the device - update counter.
//
(VOID) UpdateDeviceJobsCounter ( LineInfo, // Device to update
FALSE, // Receiving
-1, // Number of new jobs (-1 = decrease by one)
TRUE); // Enable events
//
// Update the FSPIJobStatus in the JobEntry
//
EnterCriticalSection (&g_CsJob); // Block FaxStatusThread
if (!UpdateJobStatus(JobEntry, pFaxStatus))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("[JobId: %ld] UpdateJobStatus() failed (ec: %ld)."),
JobEntry->lpJobQueueEntry->JobId,
GetLastError());
}
JobEntry->fStopUpdateStatus = TRUE; // Stop FaxStatusThread from changing this status
//
// Save the last extended status
//
wcscpy (LastExStatusString, JobEntry->ExStatusString);
dwLastJobExtendedStatus = pFaxStatus->dwExtendedStatus;
LeaveCriticalSection (&g_CsJob);
//
// route the newly received fax
//
if (DoFaxRoute)
{
HANDLE hFind;
WIN32_FIND_DATA FindFileData;
DWORD Bytes = 0 ;
BOOL fArchiveSuccess = FALSE;
BOOL fArchiveInbox;
//
// Change JobStatus to JS_ROUTING - This means that the reception is completed succesfully/partially
//
EnterCriticalSectionJobAndQueue;
JobQueue->JobStatus = JS_ROUTING;
//
// CreteFaxEventEx
//
dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_STATUS,
JobQueue
);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_STATUS) failed for job id %ld (ec: %lc)"),
JobQueue->UniqueId,
dwRes);
}
LeaveCriticalSectionJobAndQueue;
EnterCriticalSection (&g_CsConfig);
lstrcpyn ( wszArchiveFolder,
g_ArchivesConfig[FAX_MESSAGE_FOLDER_INBOX].lpcstrFolder,
MAX_PATH);
LeaveCriticalSection (&g_CsConfig);
hr = CoInitialize (NULL);
if (FAILED (hr))
{
DebugPrintEx( DEBUG_ERR,
TEXT("CoInitilaize failed, err %ld"),
hr);
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
3,
MSG_FAX_ARCHIVE_FAILED,
JobQueue->FileName,
wszArchiveFolder,
DWORD2DECIMAL(hr)
);
}
else
{
fCOMInitiliazed = TRUE;
}
EnterCriticalSection (&g_CsConfig);
fArchiveInbox = g_ArchivesConfig[FAX_MESSAGE_FOLDER_INBOX].bUseArchive;
LeaveCriticalSection (&g_CsConfig);
if (fArchiveInbox)
{
//
// Add the Microsoft Fax tags to the file
// this is necessary ONLY when we archive the
// file when doing a receive. if we are not
// routing the file then it is deleted, so
// adding the tags is not necessary.
//
if (NULL != pFaxStatus->lpwstrRoutingInfo)
{
MsTagInfo.Routing = pFaxStatus->lpwstrRoutingInfo;
}
if (NULL != pFaxStatus->lpwstrCallerId)
{
MsTagInfo.CallerId = pFaxStatus->lpwstrCallerId;
}
if (NULL != pFaxStatus->lpwstrRemoteStationId)
{
MsTagInfo.Tsid = pFaxStatus->lpwstrRemoteStationId;
}
if (pFaxStatus->fAvailableStatusInfo & FSPI_JOB_STATUS_INFO_PAGECOUNT)
{
MsTagInfo.Pages = pFaxStatus->dwPageCount;
}
MsTagInfo.Csid = FaxReceive->ReceiverNumber;
MsTagInfo.Port = FaxReceive->ReceiverName;
MsTagInfo.Type = JT_RECEIVE;
MsTagInfo.dwStatus = JS_COMPLETED; // We archive only succesfull/Partially received faxes
MsTagInfo.dwExtendedStatus = pFaxStatus->dwExtendedStatus;
if (lstrlen(JobEntry->ExStatusString))
{
MsTagInfo.lptstrExtendedStatus = JobEntry->ExStatusString;
}
if (!GetRealFaxTimeAsFileTime (JobEntry, FAX_TIME_TYPE_START, (FILETIME*)&MsTagInfo.StartTime))
{
MsTagInfo.StartTime = 0;
DebugPrintEx(DEBUG_ERR,TEXT("GetRealFaxTimeAsFileTime (Start time) Failed (ec: %ld)"), GetLastError() );
}
if (!GetRealFaxTimeAsFileTime (JobEntry, FAX_TIME_TYPE_END, (FILETIME*)&MsTagInfo.EndTime))
{
MsTagInfo.EndTime = 0;
DebugPrintEx(DEBUG_ERR,TEXT("GetRealFaxTimeAsFileTime (Eend time) Failed (ec: %ld)"), GetLastError() );
}
//
// Archive the file
//
ec = IsValidFaxFolder(wszArchiveFolder);
if(ERROR_SUCCESS != ec)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("IsValidFaxFolder failed for folder : %s (ec=%lu)."),
wszArchiveFolder,
ec
);
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
2,
MSG_FAX_ARCHIVE_INBOX_FOLDER_ERR,
wszArchiveFolder,
DWORD2DECIMAL(ec)
);
}
else
{
if (!GenerateUniqueArchiveFileName( wszArchiveFolder,
ArchiveFileName,
ARR_SIZE(ArchiveFileName),
JobQueue->UniqueId,
NULL))
{
ec = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to generate unique name for archive file at dir [%s] (ec: %ld)"),
wszArchiveFolder,
ec);
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
1,
MSG_FAX_ARCHIVE_CREATE_FILE_FAILED,
DWORD2DECIMAL(ec)
);
}
else
{
Assert(JobQueue->FileName);
if (!CopyFile( JobQueue->FileName, ArchiveFileName, FALSE ))
{
ec = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("CopyFile [%s] to [%s] failed. (ec: %ld)"),
JobQueue->FileName,
ArchiveFileName,
ec);
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
1,
MSG_FAX_ARCHIVE_CREATE_FILE_FAILED,
DWORD2DECIMAL(ec)
);
if (!DeleteFile(ArchiveFileName))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("DeleteFile [%s] failed. (ec: %ld)"),
ArchiveFileName,
GetLastError());
}
}
else
{
BOOL bTagsEventLogged = FALSE; // Did we issue event MSG_FAX_ARCHIVE_NO_TAGS?
//
// Store archive properties as TIFF tags (always)
//
if (!TiffAddMsTags( ArchiveFileName, &MsTagInfo, FALSE ))
{
ec = GetLastError ();
DebugPrintEx( DEBUG_ERR,
TEXT("TiffAddMsTags failed, ec = %ld"),
ec);
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
2,
MSG_FAX_ARCHIVE_NO_TAGS,
ArchiveFileName,
DWORD2DECIMAL(ec)
);
bTagsEventLogged = TRUE;
}
//
// Also attempt to persist inbound information using IPropertyStorage-NTFS File System
//
if (fCOMInitiliazed)
{
if (!AddNTFSStorageProperties ( ArchiveFileName, &MsTagInfo, FALSE ))
{
ec = GetLastError();
if (ERROR_OPEN_FAILED != ec)
{
//
// If AddNTFSStorageProperties fails with ERROR_OPEN_FAIL then the archive
// folder is not on an NTFS 5 partition.
// This is ok - NTFS properties are a backup mechanism but not a must
//
DebugPrintEx( DEBUG_ERR,
TEXT("AddNTFSStorageProperties failed, ec = %ld"),
ec);
if (!bTagsEventLogged)
{
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
2,
MSG_FAX_ARCHIVE_NO_TAGS,
ArchiveFileName,
DWORD2DECIMAL(ec)
);
bTagsEventLogged = TRUE;
}
}
else
{
DebugPrintEx( DEBUG_WRN,
TEXT("AddNTFSStorageProperties failed with ERROR_OPEN_FAIL. Probably not an NTFS 5 partition"));
}
}
}
fArchiveSuccess = TRUE;
}
}
}
if (fArchiveSuccess == FALSE)
{
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
3,
MSG_FAX_ARCHIVE_FAILED,
JobQueue->FileName,
wszArchiveFolder,
DWORD2DECIMAL(ec)
);
JobQueue->fDeleteReceivedTiff = FALSE; // Do not delete the tiff file from the queue
}
else
{
dwRes = CreateArchiveEvent (JobQueue->UniqueId,
FAX_EVENT_TYPE_IN_ARCHIVE,
FAX_JOB_EVENT_TYPE_ADDED,
NULL);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CreateConfigEvent(FAX_CONFIG_TYPE_*_ARCHIVE) failed (ec: %lc)"),
dwRes);
}
hFind = FindFirstFile( ArchiveFileName, &FindFileData);
if (INVALID_HANDLE_VALUE == hFind)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("FindFirstFile failed (ec: %lc), File %s"),
GetLastError(),
ArchiveFileName);
}
else
{
// Update the archive size - for quota management
EnterCriticalSection (&g_CsConfig);
if (FAX_ARCHIVE_FOLDER_INVALID_SIZE != g_ArchivesConfig[FAX_MESSAGE_FOLDER_INBOX].dwlArchiveSize)
{
g_ArchivesConfig[FAX_MESSAGE_FOLDER_INBOX].dwlArchiveSize += (MAKELONGLONG(FindFileData.nFileSizeLow ,FindFileData.nFileSizeHigh));
}
LeaveCriticalSection (&g_CsConfig);
if (!FindClose(hFind))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("FindClose failed (ec: %lc)"),
GetLastError());
}
}
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MAX,
2,
MSG_FAX_RECEIVED_ARCHIVE_SUCCESS,
JobQueue->FileName,
ArchiveFileName
);
}
}
//
// The fax receive operation was successful.
//
EnterCriticalSection (&g_CsQueue);
JobQueue->PageCount = pFaxStatus->dwPageCount;
// Get the file size
hFind = FindFirstFile( FaxReceive->FileName, &FindFileData);
if (INVALID_HANDLE_VALUE == hFind)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("FindFirstFile failed (ec: %lc), File %s"),
GetLastError(),
FaxReceive->FileName);
}
else
{
Bytes = FindFileData.nFileSizeLow;
if (!FindClose(hFind))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("FindClose failed (ec: %lc)"),
GetLastError());
}
}
JobQueue->FileSize = Bytes;
LeaveCriticalSection( &g_CsQueue );
if (g_pFaxPerfCounters)
{
SYSTEMTIME SystemTime ;
if (FileTimeToSystemTime( (FILETIME*)&ElapsedTime, &SystemTime ))
{
DWORD Seconds ;
InterlockedIncrement( (LPLONG) &g_pFaxPerfCounters->InboundFaxes ) ;
InterlockedIncrement( (LPLONG) &g_pFaxPerfCounters->TotalFaxes ) ;
Seconds = (DWORD)( SystemTime.wSecond + 60 * ( SystemTime.wMinute + 60 * SystemTime.wHour ));
InterlockedExchangeAdd( (PLONG)&g_pFaxPerfCounters->InboundPages, (LONG)pFaxStatus->dwPageCount );
InterlockedExchangeAdd( (PLONG)&g_pFaxPerfCounters->TotalPages, (LONG)pFaxStatus->dwPageCount );
EnterCriticalSection( &g_CsPerfCounters );
g_dwInboundSeconds += Seconds;
g_dwTotalSeconds += Seconds;
g_pFaxPerfCounters->InboundMinutes = g_dwInboundSeconds/60 ;
g_pFaxPerfCounters->TotalMinutes = g_dwTotalSeconds/60;
g_pFaxPerfCounters->InboundBytes += Bytes;
g_pFaxPerfCounters->TotalBytes += Bytes;
LeaveCriticalSection( &g_CsPerfCounters );
}
else
{
DebugPrintEx(
DEBUG_ERR,
TEXT("FileTimeToSystemTime failed (ec: %ld)"),
GetLastError());
}
}
PFAX_ROUTE Route = (PFAX_ROUTE)MemAlloc( sizeof(FAX_ROUTE) );
if (Route == NULL)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("MemAlloc failed to allocate FAX_ROUTE (ec: %ld)"),
GetLastError());
//
// We failed in the FaxRoute() and did not checked any Routing Method
//
WCHAR TmpStr[20] = {0};
swprintf(TmpStr,TEXT("0x%016I64x"), JobQueue->UniqueId);
FaxLog(FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
3,
MSG_FAX_ROUTE_FAILED,
TmpStr,
LineInfo->DeviceName,
pFaxStatus->lpwstrRemoteStationId
);
}
else
{
BOOL RouteSucceeded;
PROUTE_FAILURE_INFO RouteFailureInfo;
DWORD CountFailureInfo;
//
// now setup the fax routing data structure
//
Route->SizeOfStruct = sizeof(FAX_ROUTE);
Route->JobId = JobId;
Route->ElapsedTime = ElapsedTime;
Route->ReceiveTime = ReceiveTime;
Route->PageCount = pFaxStatus->dwPageCount;
Route->Csid = StringDup( LineInfo->Csid );
if (LineInfo->Csid && !Route->Csid)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StringDup( LineInfo->Csid ) failed (ec: %ld)"),
GetLastError());
}
if (NULL != pFaxStatus->lpwstrRemoteStationId)
{
Route->Tsid = StringDup( pFaxStatus->lpwstrRemoteStationId );
if (!Route->Tsid)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StringDup( pFaxStatus->lpwstrRemoteStationId ) ")
TEXT("failed (ec: %ld)"),
GetLastError());
}
}
if (NULL != pFaxStatus->lpwstrCallerId)
{
Route->CallerId = StringDup( pFaxStatus->lpwstrCallerId );
if (!Route->CallerId)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StringDup( pFaxStatus->lpwstrCallerId ) failed ")
TEXT("(ec: %ld)"),
GetLastError());
}
}
Route->ReceiverName = StringDup( FaxReceive->ReceiverName );
if (FaxReceive->ReceiverName && !Route->ReceiverName)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StringDup( FaxReceive->ReceiverName ) failed ")
TEXT("(ec: %ld)"),
GetLastError());
}
Route->ReceiverNumber = StringDup( FaxReceive->ReceiverNumber );
if (FaxReceive->ReceiverNumber && !Route->ReceiverNumber)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StringDup( FaxReceive->ReceiverNumber ) failed ")
TEXT("(ec: %ld)"),
GetLastError());
}
Route->DeviceName = StringDup(LineInfo->DeviceName);
if (LineInfo->DeviceName && !Route->DeviceName)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StringDup( LineInfo->DeviceName ) failed ")
TEXT("(ec: %ld)"),
GetLastError());
}
Route->DeviceId = LineInfo->PermanentLineID;
if (NULL != pFaxStatus->lpwstrRoutingInfo)
{
Route->RoutingInfo = StringDup( pFaxStatus->lpwstrRoutingInfo );
if (!Route->RoutingInfo)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("StringDup( pFaxStatus->lpwstrRoutingInfo ) ")
TEXT("failed (ec: %ld)"),
GetLastError());
}
}
JobQueue->FaxRoute = Route;
RouteSucceeded = FaxRoute(
JobQueue,
FaxReceive->FileName,
Route,
&RouteFailureInfo,
&CountFailureInfo
);
if ( RouteSucceeded && (CountFailureInfo == 0) )
{
DebugPrintEx(DEBUG_MSG,
_T("[Job Id: %ld] Routing SUCCEEDED."),
JobQueue->UniqueId);
}
else
{
DebugPrintEx(DEBUG_MSG,
_T("[Job Id: %ld] Routing FAILED."),
JobQueue->UniqueId);
if (CountFailureInfo == 0)
{
//
// We failed in the FaxRoute() and did not checked any Routing Method
//
WCHAR TmpStr[20] = {0};
swprintf(TmpStr,TEXT("0x%016I64x"), JobQueue->UniqueId);
FaxLog(FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
3,
MSG_FAX_ROUTE_FAILED,
TmpStr,
Route->DeviceName,
Route->Tsid
);
}
else
{
//
// There are some routing methods failed
//
TCHAR QueueFileName[MAX_PATH];
DWORDLONG dwlUniqueId;
DebugPrintEx(
DEBUG_MSG,
TEXT("[Job Id: %ld] Routing FAILED."));
EnterCriticalSectionJobAndQueue;
//
// Now we turn the receive job to a routing (JT_ROUTING) job.
// The receive job was not committed to file but the routing job must be.
// So we create a FQR file for it.
//
dwlUniqueId = GenerateUniqueQueueFile( JT_ROUTING,
QueueFileName,
sizeof(QueueFileName)/sizeof(WCHAR) );
if (!dwlUniqueId)
{
//
// Failed to generate a unique id for the routing job.
// This is a critical error. Job will be lost when the service stops.
DebugPrintEx(
DEBUG_ERR,
TEXT("[JobId: %ld] Failed to generate unique id for routing job. (ec: %ld)"),
JobQueue->JobId,
GetLastError());
Assert ( JobQueue->QueueFileName == NULL );
}
else
{
JobQueue->QueueFileName = StringDup( QueueFileName );
if (!JobQueue->QueueFileName)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("[JobId: %ld] StringDup( QueueFileName) failed for routing job. (ec: %ld)"),
JobQueue->JobId,
GetLastError());
if (!DeleteFile (QueueFileName))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("DeleteFile. (ec: %ld)"),
GetLastError());
}
}
}
JobQueue->CountFailureInfo = CountFailureInfo;
JobQueue->pRouteFailureInfo = RouteFailureInfo;
JobQueue->StartTime = JobEntry->StartTime;
JobQueue->EndTime = JobEntry->EndTime;
//
// check if we are supposed to retry.
//
EnterCriticalSection (&g_CsConfig);
DWORD dwMaxRetries = g_dwFaxSendRetries;
LeaveCriticalSection (&g_CsConfig);
if (0 == dwMaxRetries)
{
JobQueue->JobStatus = JS_RETRIES_EXCEEDED;
WCHAR TmpStr[20] = {0};
swprintf(TmpStr,TEXT("0x%016I64x"), JobQueue->UniqueId);
FaxLog(FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
3,
MSG_FAX_ROUTE_FAILED,
TmpStr,
JobQueue->FaxRoute->DeviceName,
JobQueue->FaxRoute->Tsid
);
}
else
{
JobQueue->JobStatus = JS_RETRYING;
}
//
// A job changes its type from RECEIVING to ROUTING after the 1st routing failure.
// This is a 2 stages change:
// 1. JT_RECEIVE__JS_ROUTING -> JT_RECEIVE__JS_RETRYING/JS_RETRIES_EXCEEDED
// 2. JT_RECEIVE__JS_RETRYING/JS_RETRIES_EXCEEDED -> JT_ROUTING__JS_RETRYING/JS_ROUTING_EXCEEDED
//
// The server activity counters g_ServerActivity are updated in the first change.
//
JobQueue->JobType = JT_ROUTING;
if (JobQueue->JobStatus == JS_RETRIES_EXCEEDED)
{
MarkJobAsExpired(JobQueue);
}
else
{
JobQueue->SendRetries++;
RescheduleJobQueueEntry( JobQueue ); // This will also commit the job to a file
}
#if DEBUG
WCHAR szSchedule[256] = {0};
DebugDateTime(JobQueue->ScheduleTime, szSchedule, ARR_SIZE(szSchedule) );
DebugPrintEx(
DEBUG_MSG,
TEXT("[JobId: %ld] Transformed into JT_ROUTING job."),
JobQueue->JobId,
szSchedule);
#endif //#if DEBUG
//
// CreteFaxEventEx
//
dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_STATUS,
JobQueue
);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_STATUS) failed for job id %ld (ec: %lc)"),
JobQueue->UniqueId,
dwRes);
}
LeaveCriticalSectionJobAndQueue;
}
}
}
}
//
// This code executes wether the receive operation succeeded or failed.
// If the job suceeded we already removed the queue entry (if routing succeeded)
// or transformed it into routing job (if routing failed).
//
EnterCriticalSectionJobAndQueue;
Assert(JobQueue);
//
// Log Inbound Activity
//
EnterCriticalSection (&g_CsInboundActivityLogging);
if (INVALID_HANDLE_VALUE == g_hOutboxActivityLogFile)
{
DebugPrintEx(DEBUG_ERR,
TEXT("Logging not initialized"));
}
else
{
if (!LogInboundActivity(JobQueue, pFaxStatus))
{
DebugPrintEx(DEBUG_ERR, TEXT("Logging inbound activity failed"));
}
}
LeaveCriticalSection (&g_CsInboundActivityLogging);
if (fCOMInitiliazed == TRUE)
{
CoUninitialize ();
}
fSystemAbort = JobEntry->fSystemAbort;
EndJob( JobEntry);
JobQueue->JobEntry = NULL;
if (JobQueue->JobType == JT_RECEIVE)
{
//
// Set the final receive job status
//
if (FALSE == DoFaxRoute)
{
if (FSPI_JS_ABORTED == pFaxStatus->dwJobStatus &&
FALSE == fSystemAbort)
{
JobQueue->JobStatus = JS_CANCELED;
}
else
{
JobQueue->JobStatus = JS_FAILED;
}
wcscpy (JobQueue->ExStatusString, LastExStatusString);
JobQueue->dwLastJobExtendedStatus = dwLastJobExtendedStatus;
//
// CreteFaxEventEx
//
dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_STATUS,
JobQueue
);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_STATUS) failed for job id %ld (ec: %lc)"),
JobQueue->UniqueId,
dwRes);
}
}
//
// we remove the job unless it was turned into a routing job
//
JobQueue->JobStatus = JS_DELETING;
DecreaseJobRefCount (JobQueue, TRUE); // TRUE means notify
}
LeaveCriticalSectionJobAndQueue;
//
// clean up and exit
//
MemFree( FaxReceiveItem->FileName );
MemFree( FaxReceiveItem );
MemFree( FaxReceive );
if (!bFakeStatus)
{
MemFree( pFaxStatus );
pFaxStatus = NULL;
}
else
{
//
// This is a faked job status - pointing to a structure on the stack.
//
if (pOrigFaxStatus)
{
//
// The FSP reported some status but we faked it.
// This is a good time to also free it
//
MemFree (pOrigFaxStatus);
pOrigFaxStatus = NULL;
}
}
//
// signal our queue if we now have a send capable device available.
// (DeviceCanSend will be false if we did a RAS handoff, since the device is still in use
//
if (TRUE == DeviceCanSend)
{
// Not a handoff job - check if the device is send enabled
EnterCriticalSection (&g_CsLine);
DeviceCanSend = ((LineInfo->Flags & FPF_SEND) == FPF_SEND);
LeaveCriticalSection (&g_CsLine);
}
if (DeviceCanSend)
{
if (!SetEvent( g_hJobQueueEvent ))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to set g_hJobQueueEvent. (ec: %ld)"),
GetLastError());
EnterCriticalSection (&g_CsQueue);
g_ScanQueueAfterTimeout = TRUE;
LeaveCriticalSection (&g_CsQueue);
}
}
//
// Let the system go back to sleep. Set the system idle timer.
//
if (TRUE == fSetSystemIdleTimer)
{
if (NULL == SetThreadExecutionState(ES_CONTINUOUS))
{
DebugPrintEx(DEBUG_ERR,
TEXT("SetThreadExecutionState() failed"));
}
}
if (!DecreaseServiceThreadsCount())
{
DebugPrintEx(
DEBUG_ERR,
TEXT("DecreaseServiceThreadsCount() failed (ec: %ld)"),
GetLastError());
}
return rVal;
} // FaxReceiveThread
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:
JobEntry - Newly allocated job
hCall - Call handle
LineInfo - LINE_INFO pointer
FileName - Receive file name
FileNameSize - File name size
Return Value:
Error code.
--*/
{
PFAX_RECEIVE_ITEM FaxReceiveItem = NULL;
DWORD rVal = ERROR_SUCCESS;
HANDLE hThread;
DWORD ThreadId;
PJOB_QUEUE lpRecvJobQEntry=NULL;
DWORDLONG UniqueJobId;
DWORD dwRes;
DEBUG_FUNCTION_NAME(TEXT("StartFaxReceive"));
//
// generate a filename for the received fax
//
UniqueJobId = GenerateUniqueQueueFile( JT_RECEIVE, FileName, FileNameSize );
if (UniqueJobId == 0) {
rVal=GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("GenerateUniqueQueueFile for receive file has failed. (ec: %ld) "),
GetLastError());
goto Error;
}
//
// allocate the fax receive structure
//
FaxReceiveItem =(PFAX_RECEIVE_ITEM) MemAlloc( sizeof(FAX_RECEIVE_ITEM) );
if (!FaxReceiveItem)
{
rVal = ERROR_NOT_ENOUGH_MEMORY;
goto Error;
}
//
// setup the fax receive values
//
FaxReceiveItem->hCall = hCall;
FaxReceiveItem->LineInfo = LineInfo;
FaxReceiveItem->JobEntry = JobEntry;
FaxReceiveItem->FileName = StringDup( FileName );
if (! FaxReceiveItem->FileName )
{
rVal = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("StringDup( FileName ) failed (ec: %ld)"),
GetLastError());
goto Error;
}
lpRecvJobQEntry =AddReceiveJobQueueEntry(FaxReceiveItem->FileName,JobEntry,JT_RECEIVE, UniqueJobId);
if (!lpRecvJobQEntry)
{
rVal = ERROR_NOT_ENOUGH_MEMORY;
goto Error;
}
JobEntry->CallHandle = hCall;
LineInfo->State = FPS_INITIALIZING;
//
// Crete FAX_EVENT_EX.
//
dwRes = CreateQueueEvent ( FAX_JOB_EVENT_TYPE_ADDED,
lpRecvJobQEntry
);
if (ERROR_SUCCESS != dwRes)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("CreateQueueEvent(FAX_JOB_EVENT_TYPE_ADDED) failed for job id %ld (ec: %lc)"),
UniqueJobId,
dwRes);
}
//
// start the receive operation
//
//
// Note:
// If FAX_ABORT happens here (no g_CsQueue protection) the job is alrady is JS_INPROGRESS state so FaxDevAbortOperation() is called.
// The recieve thread will catch it when it calls FaxDevReceive() (it will get back an error indicating a user abort).
// FaxReceiveThread() will then cleanup the job and remove it from the queue.
//
hThread = CreateThreadAndRefCount(
NULL,
0,
(LPTHREAD_START_ROUTINE) FaxReceiveThread,
(LPVOID) FaxReceiveItem,
0,
&ThreadId
);
if (!hThread)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Failed to create FaxReceiveThread (CreateThreadAndRefCount) (ec: %ld)"),
GetLastError());
MemFree( FaxReceiveItem );
rVal = GetLastError();
goto Error;
}
else
{
CloseHandle( hThread );
}
goto exit;
Error:
//
// EndJob() must be called before RemoveReceiveJob() !!!
//
EndJob(JobEntry);
if (lpRecvJobQEntry)
{
lpRecvJobQEntry->JobEntry = NULL;
DecreaseJobRefCount (lpRecvJobQEntry, FALSE); // do not notify the clients
//
// Note that this does not free the running job entry.
//
}
if (FaxReceiveItem) {
MemFree(FaxReceiveItem);
MemFree(FaxReceiveItem->FileName);
}
FaxLog(
FAXLOG_CATEGORY_INBOUND,
FAXLOG_LEVEL_MIN,
0,
MSG_FAX_RECEIVE_FAILED
);
exit:
return rVal;
}