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.
 
 
 
 
 
 

1997 lines
59 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
util.c
Abstract:
This module contains various utility functions.
Author:
Wesley Witt (wesw) 16-Jan-1996
Revision History:
BoazF 24-May-1999 - Added GetDevStatus
--*/
#include "faxsvc.h"
#include "faxreg.h"
#include <comenum.h>
#define STRSAFE_NO_DEPRECATE
#include <strsafe.h>
#pragma hdrstop
#ifdef EnterCriticalSection
#undef EnterCriticalSection
#endif
#ifdef LeaveCriticalSection
#undef LeaveCriticalSection
#endif
DWORDLONG g_dwLastUniqueId;
STRING_TABLE g_ServiceStringTable[] =
{
{ IDS_SVC_DIALING, FPS_DIALING, NULL },
{ IDS_SVC_SENDING, FPS_SENDING, NULL },
{ IDS_SVC_RECEIVING, FPS_RECEIVING, NULL },
{ IDS_COMPLETED, FPS_COMPLETED, NULL },
{ IDS_HANDLED, FPS_HANDLED, NULL },
{ IDS_BUSY, FPS_BUSY, NULL },
{ IDS_NO_ANSWER, FPS_NO_ANSWER, NULL },
{ IDS_BAD_ADDRESS, FPS_BAD_ADDRESS, NULL },
{ IDS_NO_DIAL_TONE, FPS_NO_DIAL_TONE, NULL },
{ IDS_DISCONNECTED, FPS_DISCONNECTED, NULL },
{ IDS_FATAL_ERROR, FPS_FATAL_ERROR, NULL },
{ IDS_NOT_FAX_CALL, FPS_NOT_FAX_CALL, NULL },
{ IDS_CALL_DELAYED, FPS_CALL_DELAYED, NULL },
{ IDS_CALL_BLACKLISTED, FPS_CALL_BLACKLISTED, NULL },
{ IDS_UNAVAILABLE, FPS_UNAVAILABLE, NULL },
{ IDS_AVAILABLE, FPS_AVAILABLE, NULL },
{ IDS_ABORTING, FPS_ABORTING, NULL },
{ IDS_ROUTING, FPS_ROUTING, NULL },
{ IDS_INITIALIZING, FPS_INITIALIZING, NULL },
{ IDS_SENDFAILED, FPS_SENDFAILED, NULL },
{ IDS_SENDRETRY, FPS_SENDRETRY, NULL },
{ IDS_BLANKSTR, FPS_BLANKSTR, NULL },
{ IDS_ROUTERETRY, FPS_ROUTERETRY, NULL },
{ IDS_CALL_COMPLETED, IDS_CALL_COMPLETED, NULL },
{ IDS_CALL_ABORTED, IDS_CALL_ABORTED, NULL },
{ IDS_ANSWERED, FPS_ANSWERED, NULL },
{ IDS_DR_SUBJECT, IDS_DR_SUBJECT, NULL },
{ IDS_DR_FILENAME, IDS_DR_FILENAME, NULL },
{ IDS_NDR_SUBJECT, IDS_NDR_SUBJECT, NULL },
{ IDS_NDR_FILENAME, IDS_NDR_FILENAME, NULL },
{ IDS_SERVICE_NAME, IDS_SERVICE_NAME, NULL },
{ IDS_NO_MAPI_LOGON, IDS_NO_MAPI_LOGON, NULL },
{ IDS_DEFAULT, IDS_DEFAULT, NULL },
{ IDS_FAX_LOG_CATEGORY_INIT_TERM, IDS_FAX_LOG_CATEGORY_INIT_TERM, NULL },
{ IDS_FAX_LOG_CATEGORY_OUTBOUND, IDS_FAX_LOG_CATEGORY_OUTBOUND, NULL },
{ IDS_FAX_LOG_CATEGORY_INBOUND, IDS_FAX_LOG_CATEGORY_INBOUND, NULL },
{ IDS_FAX_LOG_CATEGORY_UNKNOWN, IDS_FAX_LOG_CATEGORY_UNKNOWN, NULL },
{ IDS_SET_CONFIG, IDS_SET_CONFIG, NULL },
{ IDS_PARTIALLY_RECEIVED, IDS_PARTIALLY_RECEIVED, NULL },
{ IDS_FAILED_SEND, IDS_FAILED_SEND, NULL },
{ IDS_FAILED_RECEIVE, IDS_FAILED_RECEIVE, NULL },
{ IDS_CANCELED, IDS_CANCELED, NULL },
{ IDS_RECEIPT_RECIPIENT_NUMBER, IDS_RECEIPT_RECIPIENT_NUMBER, NULL },
{ IDS_RECEIPT_RECIPIENT_NUMBER_WIDTH, IDS_RECEIPT_RECIPIENT_NUMBER_WIDTH, NULL },
{ IDS_RECEIPT_RECIPIENT_NAME, IDS_RECEIPT_RECIPIENT_NAME, NULL },
{ IDS_RECEIPT_RECIPIENT_NAME_WIDTH, IDS_RECEIPT_RECIPIENT_NAME_WIDTH, NULL },
{ IDS_RECEIPT_START_TIME, IDS_RECEIPT_START_TIME, NULL },
{ IDS_RECEIPT_START_TIME_WIDTH, IDS_RECEIPT_START_TIME_WIDTH, NULL },
{ IDS_RECEIPT_END_TIME, IDS_RECEIPT_END_TIME, NULL },
{ IDS_RECEIPT_END_TIME_WIDTH, IDS_RECEIPT_END_TIME_WIDTH, NULL },
{ IDS_RECEIPT_RETRIES, IDS_RECEIPT_RETRIES, NULL },
{ IDS_RECEIPT_RETRIES_WIDTH, IDS_RECEIPT_RETRIES_WIDTH, NULL },
{ IDS_RECEIPT_LAST_ERROR, IDS_RECEIPT_LAST_ERROR, NULL },
{ IDS_RECEIPT_LAST_ERROR_WIDTH, IDS_RECEIPT_LAST_ERROR_WIDTH, NULL },
{ IDS_COMPLETED_RECP_LIST_HEADER, IDS_COMPLETED_RECP_LIST_HEADER, NULL },
{ IDS_FAILED_RECP_LIST_HEADER, IDS_FAILED_RECP_LIST_HEADER, NULL },
{ IDS_RECEIPT_NO_CP_AND_BODY_ATTACH, IDS_RECEIPT_NO_CP_AND_BODY_ATTACH, NULL },
{ IDS_RECEIPT_NO_CP_ATTACH, IDS_RECEIPT_NO_CP_ATTACH, NULL },
{ IDS_HTML_RECEIPT_HEADER, IDS_HTML_RECEIPT_HEADER, NULL }
};
const DWORD gc_dwCountServiceStringTable = (sizeof(g_ServiceStringTable)/sizeof(g_ServiceStringTable[0]));
#ifdef DBG
//*********************************************************************************
//* Name: DebugDateTime()
//* Author:
//* Date:
//*********************************************************************************
//* DESCRIPTION:
//* Accepts a 64 bit file time and generates a string with its content.
//* The format is Date Time (GMT). Date and Time format are system settings
//* specific.
//* PARAMETERS:
//* [IN] DWORD DateTime
//* 64 bit file time value
//* [OUT] LPTSTR lptstrDateTime
//* A pointer to a string buffer where the resulting string will
//* be placed.
//* [IN] UINT cchstrDateTime
//* The number of TCHARs in the lptstrDateTime buffer.
//* RETURN VALUE:
//* TRUE
//*
//* FALSE
//*
//*********************************************************************************
BOOL DebugDateTime( IN DWORDLONG DateTime,
OUT LPTSTR lptstrDateTime,
IN UINT cchstrDateTime)
{
SYSTEMTIME SystemTime;
TCHAR DateBuffer[256] = TEXT("NULL");
TCHAR TimeBuffer[256] = TEXT("NULL");
DEBUG_FUNCTION_NAME(TEXT("DebugDateTime"));
if (!FileTimeToSystemTime( (LPFILETIME) &DateTime, &SystemTime ))
{
return FALSE;
}
GetY2KCompliantDate (
LOCALE_SYSTEM_DEFAULT,
0,
&SystemTime,
DateBuffer,
sizeof(DateBuffer)/sizeof(DateBuffer[0])
);
FaxTimeFormat(
LOCALE_SYSTEM_DEFAULT,
0,
&SystemTime,
NULL,
TimeBuffer,
sizeof(TimeBuffer)/sizeof(TimeBuffer[0])
);
HRESULT hRc = StringCchPrintf(lptstrDateTime, cchstrDateTime,
TEXT("%s %s (GMT)"),DateBuffer, TimeBuffer);
if(FAILED(hRc))
{
ASSERT_FALSE
return FALSE;
}
return TRUE;
}
VOID
DebugPrintDateTime(
LPTSTR Heading,
DWORDLONG DateTime
)
{
SYSTEMTIME SystemTime;
TCHAR DateBuffer[256] = TEXT("NULL");
TCHAR TimeBuffer[256] = TEXT("NULL");
if (!FileTimeToSystemTime( (LPFILETIME) &DateTime, &SystemTime ))
{
return;
}
GetY2KCompliantDate (
LOCALE_SYSTEM_DEFAULT,
0,
&SystemTime,
DateBuffer,
sizeof(TimeBuffer)/sizeof(TimeBuffer[0])
);
FaxTimeFormat(
LOCALE_SYSTEM_DEFAULT,
0,
&SystemTime,
NULL,
TimeBuffer,
sizeof(TimeBuffer)/sizeof(TimeBuffer[0])
);
if (Heading) {
DebugPrint((TEXT("%s %s %s (GMT)"), Heading, DateBuffer, TimeBuffer));
} else {
DebugPrint((TEXT("%s %s (GMT)"), DateBuffer, TimeBuffer));
}
}
//*********************************************************************************
//* Name: SystemTimeToStr()
//* Author:
//* Date:
//*********************************************************************************
//* DESCRIPTION:
//* Accepts a pointer to a system time structure and generates a string with its content.
//* The format is Date Time (GMT). Date and Time format are system settings
//* specific.
//* PARAMETERS:
//* [IN] SYSTEMTIME * lptmTime
//* Pointer to SYSTEMTIME structure to convet to string
//* [OUT] LPTSTR lptstrDateTime
//* A pointer to a string buffer where the resulting string will
//* be placed.
//* [IN] UINT cchstrDateTime
//* The number of TCHARs in the lptstrDateTime out buffer.
//* RETURN VALUE:
//* TRUE
//*
//* FALSE
//*
//*********************************************************************************
BOOL SystemTimeToStr( IN const SYSTEMTIME * lptmTime,
OUT LPTSTR lptstrDateTime,
IN UINT cchstrDateTime)
{
TCHAR DateBuffer[256] = TEXT("NULL");
TCHAR TimeBuffer[256] = TEXT("NULL");
GetY2KCompliantDate (
LOCALE_SYSTEM_DEFAULT,
0,
lptmTime,
DateBuffer,
sizeof(TimeBuffer)/sizeof(TimeBuffer[0])
);
FaxTimeFormat(
LOCALE_SYSTEM_DEFAULT,
0,
lptmTime,
NULL,
TimeBuffer,
sizeof(TimeBuffer)/sizeof(TimeBuffer[0])
);
HRESULT hRc = StringCchPrintf(lptstrDateTime, cchstrDateTime,
TEXT("%s %s (GMT)"),DateBuffer, TimeBuffer);
if(FAILED(hRc))
{
ASSERT_FALSE
return FALSE;
}
return TRUE;
}
#endif
BOOL
InitializeStringTable(
VOID
)
{
DWORD i;
TCHAR Buffer[512];
DWORD ec = ERROR_SUCCESS;
for (i = 0; i < gc_dwCountServiceStringTable; i++)
{
if (LoadString(
g_hResource,
g_ServiceStringTable[i].ResourceId,
Buffer,
sizeof(Buffer)/sizeof(TCHAR)
))
{
g_ServiceStringTable[i].String = (LPTSTR) MemAlloc( StringSize( Buffer ) );
if (!g_ServiceStringTable[i].String)
{
ec = ERROR_OUTOFMEMORY;
goto Error;
}
else
{
_tcscpy( g_ServiceStringTable[i].String, Buffer );
}
}
else
{
ec = GetLastError();
goto Error;
}
}
return TRUE;
Error:
Assert (ERROR_SUCCESS != ec);
for (i = 0; i < gc_dwCountServiceStringTable; i++)
{
MemFree (g_ServiceStringTable[i].String);
g_ServiceStringTable[i].String = NULL;
}
SetLastError(ec);
return FALSE;
}
LPTSTR
GetString(
DWORD InternalId
)
/*++
Routine Description:
Loads a resource string and returns a pointer to the string.
The caller must free the memory.
Arguments:
ResourceId - resource string id
Return Value:
pointer to the string
--*/
{
DWORD i;
for (i=0; i<gc_dwCountServiceStringTable; i++) {
if (g_ServiceStringTable[i].InternalId == InternalId) {
return g_ServiceStringTable[i].String;
}
}
return NULL;
}
BOOL
InitializeFaxQueue(
PREG_FAX_SERVICE pFaxReg
)
/*++
Routine Description:
Initializes the queue directory that fax will use.
The administrator can configure the queue directory using the registry.
This function does not create the queue directory.
Arguments:
pFaxReg - pointer to the fax registry data.
Return Value:
TRUE if successful. modifies path globals
--*/
{
DWORD dwRet;
WCHAR FaxDir[MAX_PATH] = {0};
DEBUG_FUNCTION_NAME(TEXT("InitializeFaxQueue"));
SetGlobalsFromRegistry( pFaxReg ); // Can not fail.
// sets the following globals from registry -
// g_dwFaxSendRetries
// g_dwFaxSendRetryDelay
// g_dwFaxDirtyDays
// g_dwNextJobId
// g_dwQueueState
// g_fFaxUseDeviceTsid
// g_fFaxUseBranding
// g_fServerCp
// g_StartCheapTime
// g_StopCheapTime
//
if (NULL != pFaxReg->lptstrQueueDir)
{
//
// The administrator changed the queue directory
//
wcsncpy (g_wszFaxQueueDir, pFaxReg->lptstrQueueDir, ARR_SIZE(g_wszFaxQueueDir)-1);
}
else
{
//
// Get the default queue directory
//
if (!GetSpecialPath( CSIDL_COMMON_APPDATA, FaxDir, ARR_SIZE(FaxDir) ) )
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Couldn't GetSpecialPath, ec = %d\n"),
GetLastError());
return FALSE;
}
if (wcslen(FaxDir) + wcslen(FAX_QUEUE_DIR) + 1 >= ARR_SIZE(g_wszFaxQueueDir)) // 1 for '\'
{
DebugPrintEx(
DEBUG_ERR,
TEXT("Queue folder exceeds MAX_PATH"));
SetLastError(ERROR_BUFFER_OVERFLOW);
return FALSE;
}
_sntprintf( g_wszFaxQueueDir,
ARR_SIZE(g_wszFaxQueueDir) -1,
TEXT("%s\\%s"),
FaxDir,
FAX_QUEUE_DIR);
}
g_wszFaxQueueDir[ARR_SIZE(g_wszFaxQueueDir) -1] = _T('\0');
dwRet = IsValidFaxFolder(g_wszFaxQueueDir);
if(ERROR_SUCCESS != dwRet)
{
DebugPrintEx(DEBUG_ERR,
TEXT("IsValidFaxFolder failed for folder : %s (ec=%lu)."),
g_wszFaxQueueDir,
dwRet);
SetLastError(dwRet);
}
return (dwRet == ERROR_SUCCESS);
}
//*********************************************************************************
//* Name: GenerateUniqueQueueFile()
//* Author: Ronen Barenboim
//* Date: April 19, 1999
//*********************************************************************************
//* DESCRIPTION:
//* Generates a unique QUEUE file in the queue directory.
//* returns a UNIQUE id for the file based on the job type. (see the remarks
//* section for more details).
//* PARAMETERS:
//* [IN] DWORD dwJobType
//* The job type for which a file is to be generated
//* [OUT] LPTSTR lptstrFileName
//* A pointer to the buffer where the resulting file name (including path)
//* will be placed.
//* [IN] DWORD dwFileNameSize
//* The size of the output file name buffer.
//* RETURN VALUE:
//* If successful the function returns A DWORDLONG with the unique id for the file.
//* On failure it returns 0.
//* REMARKS:
//* The generated unique id is derived from the unique name of the generated
//* file (which is only unique within files with the same extension) and the
//* type of the job for which the file was generated.
//* Thus it is ensured that there can be no two jobs with the same unique id
//* although there can be two jobs with the same unique file name which are
//* different only by the file extension.
//* The 64 bit unique file id is the result of SystemTimeToFileTime.
//* This is the number of 100 nano seconds intervals since 1-1-1601
//* In year 3000 it will be approximately 5BC826A600000 i.e. 52 bites long.
// We use the left most 8 bits for the job type. Leaving extra 4 more bits
//* |-----------------3----------------2----------------1----------------|
//* |FEDCBA98|76543210|FEDCBA9876543210|FEDCBA9876543210|FEDCBA9876543210|
//* |-----------------|----------------|----------------|----------------|
//* | JobType| 56 LSB bits of SystemTimeToFileTime |
//* |-----------------|----------------|----------------|----------------|
//* Job Type:
//* The JT_* value of the job type.
//*********************************************************************************
DWORDLONG GenerateUniqueQueueFile(
DWORD dwJobType,
LPTSTR lptstrFileName,
DWORD dwFileNameSize)
{
DWORD dwUniqueIdHigh;
DWORD dwUniqueIdLow;
DWORDLONG dwlUniqueId = 0 ;
FILETIME FileTime;
SYSTEMTIME SystemTime;
LPTSTR lpszExt=NULL;
DEBUG_FUNCTION_NAME(TEXT("GenerateUniqueQueueFile"));
EnterCriticalSection(&g_csUniqueQueueFile);
GetSystemTime( &SystemTime ); // returns VOID
if (!SystemTimeToFileTime( &SystemTime, &FileTime ))
{
DebugPrintEx(DEBUG_ERR, TEXT("SystemTimeToFileTime() failed (ec: %ld)"), GetLastError());
goto Error;
}
dwlUniqueId = MAKELONGLONG(FileTime.dwLowDateTime, FileTime.dwHighDateTime);
dwlUniqueId = dwlUniqueId >> 8;
if(dwlUniqueId == g_dwLastUniqueId)
{
//
// Not enough time has passed since the last generation to ensure
// out time based unique id algorithm will produce a unique id
// (in case the already generated file was deleted from the queue directory).
// Let some more time pass to ensure uniqueness.
//
Sleep(1);
}
//
// Note that dwlUniqueId might be smaller than g_dwLastUniqueId if the system time was moved
// back during the service operation.
//
switch (dwJobType)
{
case JT_SEND:
{
lpszExt=TEXT("FQE");
}
break;
case JT_BROADCAST:
{
lpszExt=TEXT("FQP");
}
break;
case JT_RECEIVE:
{
lpszExt=FAX_TIF_FILE_EXT;
}
break;
case JT_ROUTING:
{
lpszExt=TEXT("FQR");
}
break;
default:
Assert(FALSE);
}
dwlUniqueId=GenerateUniqueFileName(
g_wszFaxQueueDir,
lpszExt,
lptstrFileName,
dwFileNameSize);
if (!dwlUniqueId) {
goto Error;
}
g_dwLastUniqueId = dwlUniqueId;
dwUniqueIdHigh = (DWORD) (dwlUniqueId >> 32);
dwUniqueIdLow = (DWORD) dwlUniqueId;
//
// Set the 8 MSB bits to zero.
//
dwUniqueIdHigh &= 0x00FFFFFF;
//
// skip past the 56 bits of SystemTimeToFileTime and put the job type at the high 8 MSB bits.
//
dwUniqueIdHigh |= (dwJobType << 24) ;
dwlUniqueId = MAKELONGLONG(dwUniqueIdLow,dwUniqueIdHigh);
Error:
LeaveCriticalSection(&g_csUniqueQueueFile);
return dwlUniqueId;
}
//*********************************************************************************
//* Name: GenerateUniqueArchiveFileName()
//* Author: Oded Sacher
//* Date: 7/11/99
//*********************************************************************************
//* DESCRIPTION:
//* Generates a unique file name and creates an archived file.
//* PARAMETERS:
//* [IN] LPTSTR Directory
//* The path where the file is to be created.
//* [OUT] LPTSTR FileName
//* The buffer where the resulting file name (including path) will be
//* placed. FileName size must not exceed MAX_PATH
//* [IN] UINT cchFileName
//* The size of FileName buffer in TCHARs.
//* [IN] DWORDLONG JobId
//* Input for the file name.
//* [IN] LPTSTR lptstrUserSid
//* Input for the file name.
//* RETURN VALUE:
//* If successful the function returns TRUE.
//* REMARKS:
//* FileName size must not exceed MAX_PATH
BOOL
GenerateUniqueArchiveFileName(
IN LPTSTR Directory,
OUT LPTSTR FileName,
IN UINT cchFileName,
IN DWORDLONG JobId,
IN LPTSTR lptstrUserSid
)
{
DEBUG_FUNCTION_NAME(TEXT("GenerateUniqueArchiveFileName"));
if(!Directory || Directory[0] == TEXT('\0'))
{
DebugPrintEx(DEBUG_ERR, TEXT("Archive folder directory should be supplied"));
ASSERT_FALSE
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (Directory[_tcslen(Directory)-1] == TEXT('\\')) {
Directory[_tcslen(Directory)-1] = 0;
}
HANDLE hFile = INVALID_HANDLE_VALUE;
HRESULT hRc = E_FAIL;
if (lptstrUserSid != NULL)
{
hRc = StringCchPrintf( FileName,
cchFileName,
TEXT("%s\\%s$%I64x.%s"),
Directory,
lptstrUserSid,
JobId,
FAX_TIF_FILE_EXT);
}
else
{
hRc = StringCchPrintf( FileName,
cchFileName,
TEXT("%s\\%I64x.%s"),
Directory,
JobId,
FAX_TIF_FILE_EXT
);
}
if(FAILED(hRc))
{
DebugPrintEx(DEBUG_ERR, TEXT("File Name exceeded buffer length"));
SetLastError(HRESULT_CODE(hRc));
return FALSE;
}
hFile = SafeCreateFile(
FileName,
GENERIC_WRITE,
0,
NULL,
CREATE_NEW,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE) {
DebugPrintEx(DEBUG_ERR,
TEXT("CreateFile Failed, err : %ld"),
GetLastError());
return FALSE;
}
CloseHandle( hFile );
return TRUE;
}
DWORD
MapFSPIJobStatusToEventId(
LPCFSPI_JOB_STATUS lpcFSPIJobStatus
)
{
DEBUG_FUNCTION_NAME(TEXT("MapFSPIJobStatusToEventId"));
DWORD EventId = 0;
DebugPrintEx(
DEBUG_MSG,
TEXT("lpcFSPIJobStatus->dwJobStatus: 0x%08X lpcFSPIJobStatus->dwExtendedStatus: 0x%08X"),
lpcFSPIJobStatus->dwJobStatus,
lpcFSPIJobStatus->dwExtendedStatus
);
switch (lpcFSPIJobStatus->dwJobStatus)
{
case FSPI_JS_INPROGRESS:
{
switch( lpcFSPIJobStatus->dwExtendedStatus) {
case FSPI_ES_INITIALIZING:
EventId = FEI_INITIALIZING;
break;
case FSPI_ES_DIALING:
EventId = FEI_DIALING;
break;
case FSPI_ES_TRANSMITTING:
EventId = FEI_SENDING;
break;
case FSPI_ES_RECEIVING:
EventId = FEI_RECEIVING;
break;
case FSPI_ES_HANDLED:
EventId = FEI_HANDLED;
break;
case FSPI_ES_ANSWERED:
EventId = FEI_ANSWERED;
break;
default:
//
// In W2K Fax a proprietry code generated an event with EventId ==0
//
EventId = 0;
break;
}
}
break;
case FSPI_JS_COMPLETED:
EventId = FEI_COMPLETED;
break;
case FSPI_JS_FAILED_NO_RETRY:
case FSPI_JS_FAILED:
case FSPI_JS_RETRY:
case FSPI_JS_DELETED:
switch( lpcFSPIJobStatus->dwExtendedStatus)
{
case FSPI_ES_LINE_UNAVAILABLE:
EventId = FEI_LINE_UNAVAILABLE;
break;
case FSPI_ES_BUSY:
EventId = FEI_BUSY;
break;
case FSPI_ES_NO_ANSWER:
EventId = FEI_NO_ANSWER;
break;
case FSPI_ES_BAD_ADDRESS:
EventId = FEI_BAD_ADDRESS;
break;
case FSPI_ES_NO_DIAL_TONE:
EventId = FEI_NO_DIAL_TONE;
break;
case FSPI_ES_DISCONNECTED:
EventId = FEI_DISCONNECTED;
break;
case FSPI_ES_FATAL_ERROR:
EventId = FEI_FATAL_ERROR;
break;
case FSPI_ES_NOT_FAX_CALL:
EventId = FEI_NOT_FAX_CALL;
break;
case FSPI_ES_CALL_DELAYED:
EventId = FEI_CALL_DELAYED;
break;
case FSPI_ES_CALL_BLACKLISTED:
EventId = FEI_CALL_BLACKLISTED;
break;
default:
//
// In W2K Fax a proprietry code generated an event with EventId ==0
//
EventId = 0;
break;
}
break;
case FSPI_JS_ABORTED:
case FSPI_JS_ABORTING:
EventId = FEI_ABORTING;
break;
case FSPI_JS_UNKNOWN:
case FSPI_JS_RESUMING:
case FSPI_JS_SUSPENDED:
case FSPI_JS_SUSPENDING:
//
// No legacy notification for these states
//
EventId = 0;
break;
default:
DebugPrintEx(
DEBUG_ERR,
TEXT("Invalid FSPI_JS: 0x%08X"),
lpcFSPIJobStatus->dwJobStatus);
Assert(FSPI_JS_ABORTED == lpcFSPIJobStatus->dwJobStatus); // ASSERT_FALSE
break;
}
return EventId;
}
void
FaxLogSend(
const JOB_QUEUE * lpcJobQueue, BOOL bRetrying
)
/*++
Routine Description:
Log a fax send event.
Arguments:
lpcJobQueue - Pointer to the recipient job to log send information for.
(It must be in a running state).
Return Value:
VOID
--*/
{
DWORD Level;
DWORD FormatId;
TCHAR PageCountStr[64];
TCHAR TimeStr[128];
BOOL fLog = TRUE;
TCHAR strJobID[20]={0};
PJOB_ENTRY lpJobEntry;
Assert(lpcJobQueue);
lpJobEntry = lpcJobQueue->JobEntry;
Assert(lpJobEntry);
//
// Convert Job ID into a string. (the string is 18 TCHARs long !!!)
//
_sntprintf(strJobID,ARR_SIZE(strJobID)-1,TEXT("0x%016I64x"), lpcJobQueue->UniqueId);
FormatElapsedTimeStr(
(FILETIME*)&lpJobEntry->ElapsedTime,
TimeStr,
ARR_SIZE(TimeStr)
);
_ltot((LONG) lpJobEntry->FSPIJobStatus.dwPageCount, PageCountStr, 10);
if ( FSPI_JS_COMPLETED == lpJobEntry->FSPIJobStatus.dwJobStatus ) {
FaxLog(
FAXLOG_CATEGORY_OUTBOUND,
FAXLOG_LEVEL_MAX,
10,
MSG_FAX_SEND_SUCCESS,
lpcJobQueue->SenderProfile.lptstrName,
lpcJobQueue->SenderProfile.lptstrBillingCode,
lpcJobQueue->SenderProfile.lptstrCompany,
lpcJobQueue->SenderProfile.lptstrDepartment,
lpJobEntry->FSPIJobStatus.lpwstrRemoteStationId,
PageCountStr,
TimeStr,
lpJobEntry->LineInfo->DeviceName,
strJobID,
lpcJobQueue->lpParentJob->UserName
);
return;
}
else
{
if (FSPI_JS_ABORTED == lpJobEntry->FSPIJobStatus.dwJobStatus )
{
Level = FAXLOG_LEVEL_MAX;
FormatId = MSG_FAX_SEND_USER_ABORT;
}
else if (lstrlen(lpJobEntry->ExStatusString))
{
//
// We have a FSP proprietary extended status.
//
Level = bRetrying ? FAXLOG_LEVEL_MED : FAXLOG_LEVEL_MIN;
FormatId = bRetrying ? MSG_FAX_PROPRIETARY_RETRY : MSG_FAX_PROPRIETARY_ABORT;
FaxLog(
FAXLOG_CATEGORY_OUTBOUND,
Level,
8,
FormatId,
lpJobEntry->ExStatusString,
lpcJobQueue->SenderProfile.lptstrName,
lpcJobQueue->SenderProfile.lptstrBillingCode,
lpcJobQueue->SenderProfile.lptstrCompany,
lpcJobQueue->SenderProfile.lptstrDepartment,
lpJobEntry->LineInfo->DeviceName,
strJobID,
lpcJobQueue->lpParentJob->UserName
);
return;
}
else
{
//
// well known extended status
//
switch (lpJobEntry->FSPIJobStatus.dwExtendedStatus)
{
case FSPI_ES_FATAL_ERROR:
Level = bRetrying ? FAXLOG_LEVEL_MED : FAXLOG_LEVEL_MIN;
FormatId = bRetrying ? MSG_FAX_SEND_FATAL_RETRY : MSG_FAX_SEND_FATAL_ABORT;
break;
case FSPI_ES_NO_DIAL_TONE:
Level = bRetrying ? FAXLOG_LEVEL_MED : FAXLOG_LEVEL_MIN;
FormatId = bRetrying ? MSG_FAX_SEND_NDT_RETRY : MSG_FAX_SEND_NDT_ABORT;
break;
case FSPI_ES_NO_ANSWER:
Level = bRetrying ? FAXLOG_LEVEL_MED : FAXLOG_LEVEL_MIN;
FormatId = bRetrying ? MSG_FAX_SEND_NA_RETRY : MSG_FAX_SEND_NA_ABORT;
break;
case FSPI_ES_DISCONNECTED:
Level = bRetrying ? FAXLOG_LEVEL_MED : FAXLOG_LEVEL_MIN;
FormatId = bRetrying ? MSG_FAX_SEND_INTERRUPT_RETRY : MSG_FAX_SEND_INTERRUPT_ABORT;
break;
case FSPI_ES_NOT_FAX_CALL:
Level = bRetrying ? FAXLOG_LEVEL_MED : FAXLOG_LEVEL_MIN;
FormatId = bRetrying ? MSG_FAX_SEND_NOTFAX_RETRY : MSG_FAX_SEND_NOTFAX_ABORT;
break;
case FSPI_ES_BUSY:
Level = bRetrying ? FAXLOG_LEVEL_MAX : FAXLOG_LEVEL_MIN;
FormatId = bRetrying ? MSG_FAX_SEND_BUSY_RETRY : MSG_FAX_SEND_BUSY_ABORT;
break;
case FSPI_ES_CALL_BLACKLISTED:
Level = FAXLOG_LEVEL_MIN;
FormatId = MSG_FAX_CALL_BLACKLISTED_ABORT;
break;
case FSPI_ES_CALL_DELAYED:
Level = FAXLOG_LEVEL_MIN;
FormatId = MSG_FAX_CALL_DELAYED_ABORT;
break;
case FSPI_ES_BAD_ADDRESS:
Level = FAXLOG_LEVEL_MIN;
FormatId = MSG_FAX_BAD_ADDRESS_ABORT;
break;
default:
fLog = FALSE;
}
}
if(fLog)
{
FaxLog(
FAXLOG_CATEGORY_OUTBOUND,
Level,
7,
FormatId,
lpcJobQueue->SenderProfile.lptstrName,
lpcJobQueue->SenderProfile.lptstrBillingCode,
lpcJobQueue->SenderProfile.lptstrCompany,
lpcJobQueue->SenderProfile.lptstrDepartment,
lpJobEntry->LineInfo->DeviceName,
strJobID,
lpcJobQueue->lpParentJob->UserName
);
}
}
return;
}
DWORD MyGetFileSize(LPCTSTR FileName)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD sizelow=0, sizehigh=0;
DWORD ec = ERROR_SUCCESS;
hFile = SafeCreateFile(
FileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
return 0;
}
sizelow = GetFileSize(hFile,&sizehigh);
if (sizelow == 0xFFFFFFFFF)
{
ec = GetLastError();
sizelow = 0;
}
else if (sizehigh != 0)
{
sizelow=0xFFFFFFFF;
}
CloseHandle(hFile);
if (ERROR_SUCCESS != ec)
{
SetLastError(ec);
}
return sizelow;
}
LPCWSTR szCsClients = L"g_CsClients";
LPCWSTR szCsHandleTable = L"g_CsHandleTable";
LPCWSTR szCsJob = L"g_CsJob";
LPCWSTR szCsLine = L"g_CsLine";
LPCWSTR szCsPerfCounters = L"g_CsPerfCounters";
LPCWSTR szCsQueue = L"g_CsQueue";
LPCWSTR szCsRouting = L"g_CsRouting";
LPCWSTR szCsConfig = L"g_CsConfig";
LPCWSTR szCsInboundActivityLogging = L"g_CsInboundActivityLogging";
LPCWSTR szCsOutboundActivityLogging = L"g_CsOutboundActivityLogging";
LPCWSTR szCsActivity = L"g_CsActivity";
LPCWSTR szCsUnknown = L"Other CS";
LPCWSTR GetSzCs(
LPCRITICAL_SECTION cs
)
{
if (cs == &g_CsClients) {
return szCsClients;
} else if (cs == &g_CsHandleTable) {
return szCsHandleTable;
} else if (cs == &g_CsLine) {
return szCsLine;
} else if (cs == &g_CsJob) {
return szCsJob;
} else if (cs == &g_CsPerfCounters) {
return szCsPerfCounters;
} else if (cs == &g_CsQueue) {
return szCsQueue;
} else if (cs == &g_CsRouting) {
return szCsRouting;
} else if (cs == &g_CsConfig) {
return szCsConfig;
} else if (cs == &g_CsInboundActivityLogging) {
return szCsInboundActivityLogging;
} else if (cs == &g_CsOutboundActivityLogging) {
return szCsOutboundActivityLogging;
} else if (cs == &g_CsActivity) {
return szCsActivity;
}
return szCsUnknown;
}
#if DBG
VOID AppendToLogFile(
LPWSTR String
)
{
DWORD BytesWritten;
LPSTR AnsiBuffer = UnicodeStringToAnsiString( String );
if (g_hCritSecLogFile != INVALID_HANDLE_VALUE) {
WriteFile(g_hCritSecLogFile,(LPBYTE)AnsiBuffer,strlen(AnsiBuffer) * sizeof(CHAR),&BytesWritten,NULL);
}
MemFree(AnsiBuffer);
}
VOID AppendFuncToLogFile(
LPCRITICAL_SECTION cs,
LPTSTR szFunc,
DWORD line,
LPTSTR file,
PDBGCRITSEC CritSec
)
{
WCHAR Buffer[300];
LPWSTR FileName;
LPCWSTR szcs = GetSzCs(cs);
FileName = wcsrchr(file,'\\');
if (!FileName) {
FileName = TEXT("Unknown ");
} else {
FileName += 1;
}
if (CritSec) {
wsprintf(Buffer,TEXT("%d\t%p\t%s\t%s\t%s\t%d\t%d\r\n"),
GetTickCount(),
(PULONG_PTR)cs,
szcs,
szFunc,
FileName,
line,
CritSec->ReleasedTime - CritSec->AquiredTime);
} else {
wsprintf(Buffer,TEXT("%d\t%p\t%s\t%s\t%s\t%d\r\n"),GetTickCount(),(PULONG_PTR)cs,szcs,szFunc, FileName,line);
}
AppendToLogFile( Buffer );
return;
}
VOID pEnterCriticalSection(
LPCRITICAL_SECTION cs,
DWORD line,
LPTSTR file
)
{
PDBGCRITSEC pCritSec = (PDBGCRITSEC)MemAlloc(sizeof(DBGCRITSEC));
if( pCritSec == NULL )
{
// memory allocation failed, do the actual work and exit...
EnterCriticalSection(cs);
return;
}
pCritSec->CritSecAddr = (ULONG_PTR) cs;
pCritSec->AquiredTime = GetTickCount();
pCritSec->ThreadId = GetCurrentThreadId();
EnterCriticalSection(&g_CsCritSecList);
InsertHeadList( &g_CritSecListHead, &pCritSec->ListEntry );
AppendFuncToLogFile(cs,TEXT("EnterCriticalSection"), line, file, NULL );
//
// check ordering of threads. ALWAYS aquire g_CsLine before aquiring g_CsQueue!!!
//
if ((LPCRITICAL_SECTION)cs == (LPCRITICAL_SECTION)&g_CsQueue)
{
if ((DWORD)GetCurrentThreadId() != PtrToUlong(g_CsJob.OwningThread()))
{
WCHAR DebugBuf[300];
wsprintf(DebugBuf, TEXT("%d : Attempting to aquire g_CsQueue (thread %x) without aquiring g_CsJob (thread %p, lock count %x) first, possible deadlock!\r\n"),
GetTickCount(),
GetCurrentThreadId(),
g_CsJob.OwningThread(),
g_CsJob.LockCount());
AppendToLogFile( DebugBuf );
}
}
LeaveCriticalSection(&g_CsCritSecList);
EnterCriticalSection(cs);
}
VOID pLeaveCriticalSection(
LPCRITICAL_SECTION cs,
DWORD line,
LPTSTR file
)
{
PDBGCRITSEC CritSec = NULL;
BOOL fRemove = FALSE;
EnterCriticalSection(&g_CsCritSecList);
PLIST_ENTRY Next = g_CritSecListHead.Flink;
while ((ULONG_PTR)Next != (ULONG_PTR) &g_CritSecListHead)
{
CritSec = CONTAINING_RECORD( Next, DBGCRITSEC, ListEntry );
if ((ULONG_PTR)CritSec->CritSecAddr == (ULONG_PTR) cs &&
( GetCurrentThreadId() == CritSec->ThreadId ) )
{
CritSec->ReleasedTime = GetTickCount();
fRemove = TRUE;
break;
}
Next = Next->Flink;
}
AppendFuncToLogFile(cs,TEXT("LeaveCriticalSection"),line, file, CritSec );
if (fRemove) {
RemoveEntryList( &CritSec->ListEntry );
MemFree( CritSec );
}
LeaveCriticalSection(&g_CsCritSecList);
LeaveCriticalSection(cs);
}
BOOL
ThreadOwnsCs(
VOID
)
{
PDBGCRITSEC pCritSec = NULL;
DWORD dwThreadId = GetCurrentThreadId();
EnterCriticalSection(&g_CsCritSecList);
PLIST_ENTRY Next = g_CritSecListHead.Flink;
while ((ULONG_PTR)Next != (ULONG_PTR) &g_CritSecListHead)
{
pCritSec = CONTAINING_RECORD( Next, DBGCRITSEC, ListEntry );
if (dwThreadId == pCritSec->ThreadId )
{
LeaveCriticalSection(&g_CsCritSecList);
return TRUE;
}
Next = Next->Flink;
}
LeaveCriticalSection(&g_CsCritSecList);
return FALSE;
}
#endif
DWORD
ValidateTiffFile(
LPCWSTR TifFileName
)
{
HANDLE hTiff;
DWORD rc = ERROR_SUCCESS;
TIFF_INFO TiffInfo;
//
// Validate tiff format
//
hTiff = TiffOpen( (LPWSTR)TifFileName, &TiffInfo, FALSE, FILLORDER_MSB2LSB );
if (!hTiff) {
rc = GetLastError();
return rc;
}
TiffClose( hTiff );
return ERROR_SUCCESS;
}
//
// Function:
// LegacyJobStatusToStatus
//
// Parameters:
// dwLegacyStatus - Legacy job status (FS_*)
// pdwStatus - A pointer to a DWORD that receives the new job status.
// pdwExtendedStatus - A pointer to a DWORD that receives the extended
// job status.
//
// Return Value:
// If the function succeeds, the return value is ERROR_SUCCESS, else the
// return value is an error code.
//
// Description:
// The function converts legacy FSP job status values to new job status.
//
//
DWORD
LegacyJobStatusToStatus(
DWORD dwLegacyStatus,
PDWORD pdwStatus,
PDWORD pdwExtendedStatus,
PBOOL pbPrivateStatusCode)
{
Assert(pdwStatus);
Assert(pdwExtendedStatus);
Assert(pbPrivateStatusCode);
*pbPrivateStatusCode = FALSE;
switch (dwLegacyStatus)
{
case FS_INITIALIZING:
*pdwStatus = FSPI_JS_INPROGRESS;
*pdwExtendedStatus = FSPI_ES_INITIALIZING;
break;
case FS_DIALING:
*pdwStatus = FSPI_JS_INPROGRESS;
*pdwExtendedStatus = FSPI_ES_DIALING;
break;
case FS_TRANSMITTING:
*pdwStatus = FSPI_JS_INPROGRESS;
*pdwExtendedStatus = FSPI_ES_TRANSMITTING;
break;
case FS_RECEIVING:
*pdwStatus = FSPI_JS_INPROGRESS;
*pdwExtendedStatus = FSPI_ES_RECEIVING;
break;
case FS_COMPLETED:
*pdwStatus = FSPI_JS_COMPLETED;
*pdwExtendedStatus = FSPI_ES_CALL_COMPLETED;
break;
case FS_HANDLED:
*pdwStatus = FSPI_JS_INPROGRESS;
*pdwExtendedStatus = FSPI_ES_HANDLED;
break;
case FS_LINE_UNAVAILABLE:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_LINE_UNAVAILABLE;
break;
case FS_BUSY:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_BUSY;
break;
case FS_NO_ANSWER:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_NO_ANSWER;
break;
case FS_BAD_ADDRESS:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_BAD_ADDRESS;
break;
case FS_NO_DIAL_TONE:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_NO_DIAL_TONE;
break;
case FS_DISCONNECTED:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_DISCONNECTED;
break;
case FS_FATAL_ERROR:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_FATAL_ERROR;
break;
case FS_NOT_FAX_CALL:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_NOT_FAX_CALL;
break;
case FS_CALL_DELAYED:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_CALL_DELAYED;
break;
case FS_CALL_BLACKLISTED:
*pdwStatus = FSPI_JS_FAILED;
*pdwExtendedStatus = FSPI_ES_CALL_BLACKLISTED;
break;
case FS_USER_ABORT:
*pdwStatus = FSPI_JS_ABORTED;
*pdwExtendedStatus = FSPI_ES_CALL_ABORTED;
break;
case FS_ANSWERED:
*pdwStatus = FSPI_JS_INPROGRESS;
*pdwExtendedStatus = FSPI_ES_ANSWERED;
break;
default:
//
// The FSP reports a status code which is not one of the predefined status codes.
// This can be a proprietry status code (in this case the StringId must not be zero)
// or a TAPI line error (one of LINEERR_constants). Note that all LINERR_constants
// are negative numbers (documented in MSDN).
// We mark the fact that it is not one of the stock values so we can map it back
// to legacy Fax API status codes. Otherwise we might get confused and think that
// a FSP proprietry code is one of the EFSPI extended status codes.
//
// Note that we don't have a way to correctly map the proprietry code
// to a FSPI_JS status code since we do not know the semantics of the
// proprietry code. We choose to report it as FSPI_JS_INPROGRESS.
//
*pdwStatus = FSPI_JS_INPROGRESS;
*pdwExtendedStatus = dwLegacyStatus;
*pbPrivateStatusCode = TRUE;
break;
}
return(ERROR_SUCCESS);
}
//
// Function:
// GetDevStatus
//
// Parameters:
// hFaxJob - the job handle that FaxDevStartJob returned.
// LineInfo - Ther line information structure.
// ppFaxStatus - A pointer to a buffer that receives the address of the
// FSPI_JOB_STATUS that contains the status.
//
// Return Value:
// If the function succeeds, the return value is ERROR_SUCCESS, else the
// return value is an error code.
//
// Description:
// The function allocates a FSPI_JOB_STATUS structure and calls the FSP
// for final job status report.
// If the FSP is a legacy FSP, the function allocates first a
// FAX_DEV_STATUS structure, calls the legacy FSP status report function
// and mapps the returned values into the FSPI_JOB_STATUS structure.
//
DWORD
GetDevStatus(
HANDLE hFaxJob,
PLINE_INFO LineInfo,
LPFSPI_JOB_STATUS *ppFaxStatus)
{
DEBUG_FUNCTION_NAME(TEXT("GetDevStatus"));
DWORD dwRet = ERROR_SUCCESS;
LPWSTR szStatusStr = NULL;
DWORD dwSize = 0;
BOOL bPrivateStatusCode = FALSE;
Assert(hFaxJob);
Assert(LineInfo);
Assert(ppFaxStatus);
Assert(LineInfo->Provider->dwAPIVersion == FSPI_API_VERSION_1);
//
// We're have a legacy FSP to deal with.
//
PFAX_DEV_STATUS pLegacyFaxStatus = NULL;
LPFSPI_JOB_STATUS pFaxStatus = NULL;
//
// Allocate memory for the status packet this is a variable size packet
// based on the size of the strings contained withing the packet.
//
DWORD StatusSize = sizeof(FAX_DEV_STATUS) + FAXDEVREPORTSTATUS_SIZE;
pLegacyFaxStatus = (PFAX_DEV_STATUS) MemAlloc( StatusSize );
if (!pLegacyFaxStatus)
{
DebugPrintEx(DEBUG_ERR,
TEXT("Failed to allocate memory for FAX_DEV_STATUS"));
dwRet = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}
//
// Setup the status packet
//
pLegacyFaxStatus->SizeOfStruct = StatusSize;
Assert(LineInfo->Provider->FaxDevReportStatus);
__try
{
//
// Call the FSP
//
DWORD BytesNeeded;
if (!LineInfo->Provider->FaxDevReportStatus(
hFaxJob,
pLegacyFaxStatus,
StatusSize,
&BytesNeeded
)) {
DebugPrintEx(DEBUG_ERR,
TEXT("FaxDevReportStatus() failed - %d"),
dwRet);
dwRet = GetLastError();
// catch the case in which FaxDevReportStatus() failded but doesn't
// report an error
Assert (ERROR_SUCCESS != dwRet);
// in case the provider did not set last error
if ( dwRet == ERROR_SUCCESS )
{
// force it to report an error
dwRet = ERROR_INVALID_FUNCTION;
}
goto Exit;
}
}
__except (HandleFaxExtensionFault(EXCEPTION_SOURCE_FSP, LineInfo->Provider->FriendlyName, GetExceptionCode()))
{
ASSERT_FALSE;
}
//
// Map FAX_DEV_STATUS into FSPI_JOB_STATUS.
//
//
// Compute the extra space that is needed after the structure for the
// various strings.
//
dwSize = sizeof(FSPI_JOB_STATUS);
if (pLegacyFaxStatus->CSI)
{
dwSize += sizeof(WCHAR) * (wcslen(pLegacyFaxStatus->CSI) + 1);
}
if (pLegacyFaxStatus->CallerId)
{
dwSize += sizeof(WCHAR) * (wcslen(pLegacyFaxStatus->CallerId) + 1);
}
if (pLegacyFaxStatus->RoutingInfo)
{
dwSize += sizeof(WCHAR) * (wcslen(pLegacyFaxStatus->RoutingInfo) + 1);
}
//
// Allocate the FSPI_JOB_STATUS structure with extra space for the strings.
//
pFaxStatus = (LPFSPI_JOB_STATUS)MemAlloc(dwSize);
if (!pFaxStatus)
{
DebugPrintEx(DEBUG_ERR,
TEXT("Failed to allocate memory for FSPI_JOB_STATUS"));
dwRet = ERROR_NOT_ENOUGH_MEMORY;
goto Exit;
}
//
// Zero-out the structure.
//
memset(pFaxStatus, 0, dwSize);
pFaxStatus->dwSizeOfStruct = sizeof(FSPI_JOB_STATUS);
//
// Map the legacy status into new EFSPI status.
//
dwRet = LegacyJobStatusToStatus(pLegacyFaxStatus->StatusId,
&(pFaxStatus->dwJobStatus),
&(pFaxStatus->dwExtendedStatus),
&bPrivateStatusCode);
if (dwRet != ERROR_SUCCESS)
{
DebugPrintEx(DEBUG_ERR,
TEXT("LegacyJobStatusToStatus failed - %d"),
dwRet);
goto Exit;
}
if (bPrivateStatusCode)
{
//
// The FSP reported a private status code (not one of the FS_* status codes).
// We mark this in the returned FSPI_JOB_STATUS by turning on the private flag
// FSPI_JOB_STATUS_INFO_FSP_PRIVATE_STATUS_CODE.
// We will check this flag when converting the FSPI_JOB_STATUS
// back to FPS_ device status so we won't get confused by an FSP that returned
// a proprietry status code which is equal to one the new FSPI_JS_* codes.
//
pFaxStatus->fAvailableStatusInfo |= FSPI_JOB_STATUS_INFO_FSP_PRIVATE_STATUS_CODE;
#if DEBUG
if (0 == pLegacyFaxStatus->StringId && pLegacyFaxStatus->StatusId < LINEERR_ALLOCATED)
{
//
// The status reported is not one of the stock status codes and is not a TAPI Error code.
// pLegacyFaxStatus->StringId must not be 0.
//
DebugPrintEx(
DEBUG_WRN,
TEXT("Provider [%s] has reported an illegal FAX_DEV_STATUS for device [%s]\n. ")
TEXT("Although the reported status code (0x%08X) is proprietry the string id is 0"),
LineInfo->Provider->FriendlyName,
LineInfo->DeviceName,
pLegacyFaxStatus->StatusId);
}
#endif
}
pFaxStatus->dwExtendedStatusStringId = pLegacyFaxStatus->StringId;
szStatusStr = (LPWSTR)(((PBYTE)pFaxStatus) + sizeof(FSPI_JOB_STATUS));
//
// Copy CSI into lpwstrRemoteStationId
//
if (pLegacyFaxStatus->CSI)
{
pFaxStatus->lpwstrRemoteStationId = szStatusStr;
wcscpy(szStatusStr, pLegacyFaxStatus->CSI);
szStatusStr += wcslen(pLegacyFaxStatus->CSI) + 1;
}
//
// Copy the Caller ID string.
//
if (pLegacyFaxStatus->CallerId)
{
pFaxStatus->lpwstrCallerId = szStatusStr;
wcscpy(szStatusStr, pLegacyFaxStatus->CallerId);
szStatusStr += wcslen(pLegacyFaxStatus->CallerId) + 1;
}
//
// Copy the Routing Info string.
//
if (pLegacyFaxStatus->RoutingInfo)
{
pFaxStatus->lpwstrRoutingInfo = szStatusStr;
wcscpy(szStatusStr, pLegacyFaxStatus->RoutingInfo);
}
//
// Copy Page Count.
//
pFaxStatus->dwPageCount = pLegacyFaxStatus->PageCount;
pFaxStatus->fAvailableStatusInfo |= FSPI_JOB_STATUS_INFO_PAGECOUNT;
Exit:
if (dwRet == ERROR_SUCCESS)
{
*ppFaxStatus = pFaxStatus;
}
else
{
MemFree(pFaxStatus);
}
MemFree(pLegacyFaxStatus);
return(dwRet);
}
BOOL
GetRealFaxTimeAsSystemTime (
const PJOB_ENTRY lpcJobEntry,
FAX_ENUM_TIME_TYPES TimeType,
SYSTEMTIME* lpFaxTime
)
{
DEBUG_FUNCTION_NAME(TEXT("GetRealFaxTimeAsSystemTime)"));
Assert (lpcJobEntry);
Assert (lpFaxTime);
PJOB_QUEUE pJobQueue = lpcJobEntry->lpJobQueueEntry;
Assert (pJobQueue);
DWORDLONG dwlFileTime;
dwlFileTime = ((TimeType == FAX_TIME_TYPE_START) ? lpcJobEntry->StartTime : lpcJobEntry->EndTime);
if (dwlFileTime == 0)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("JonEntry contains invalid time (=0) "));
SetLastError (ERROR_INVALID_DATA);
return FALSE;
}
if (!FileTimeToSystemTime ((FILETIME*)&dwlFileTime, lpFaxTime))
{
DebugPrintEx(
DEBUG_ERR,
TEXT("FileTimeToSystemTime failed (ec: %ld)"),
GetLastError());
return FALSE;
}
return TRUE;
}
BOOL
GetRealFaxTimeAsFileTime (
const PJOB_ENTRY lpcJobEntry,
FAX_ENUM_TIME_TYPES TimeType,
FILETIME* lpFaxTime
)
{
DEBUG_FUNCTION_NAME(TEXT("GetRealFaxTimeAsSystemTime)"));
Assert (lpcJobEntry);
Assert (lpFaxTime);
PJOB_QUEUE pJobQueue = lpcJobEntry->lpJobQueueEntry;
Assert (pJobQueue);
DWORDLONG dwlFileTime;
dwlFileTime = ((TimeType == FAX_TIME_TYPE_START) ? lpcJobEntry->StartTime : lpcJobEntry->EndTime);
if (dwlFileTime == 0)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("JonEntry contains invalid time (=0) "));
SetLastError (ERROR_INVALID_DATA);
return FALSE;
}
*lpFaxTime = *((FILETIME*)&dwlFileTime);
return TRUE;
}
VOID
FaxExtFreeBuffer(
LPVOID lpvBuffer
)
{
MemFree( lpvBuffer );
}
//
// Service threads count functions.
// The service is terminated only when service threads refernce count is 0.
// When the count is 0 the g_hThreadCountEvent is set.
// When the count is greater than 0, the g_hThreadCountEvent is reset.
// EndFaxSvc() waits on g_hThreadCountEvent before starting to cleanup.
//
BOOL
IncreaseServiceThreadsCount(
VOID
)
/*++
Routine name : IncreaseServiceThreadsCount
Routine description:
Safetly increments the service threads reference count
Author:
Oded Sacher (OdedS), Dec, 2000
Arguments:
VOID
Return Value:
BOOL
--*/
{
BOOL bRet = TRUE;
DEBUG_FUNCTION_NAME(TEXT("IncreaseServiceThreadsCount"));
EnterCriticalSection (&g_CsServiceThreads);
g_lServiceThreadsCount++;
DebugPrintEx(
DEBUG_MSG,
TEXT("Current service threads count is %ld"),
g_lServiceThreadsCount);
if (1 == g_lServiceThreadsCount)
{
bRet = ResetEvent (g_hThreadCountEvent);
if (FALSE == bRet)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("ResetEvent failed (g_hThreadCountEvent) (ec: %ld"),
GetLastError());
}
}
LeaveCriticalSection (&g_CsServiceThreads);
return bRet;
}
BOOL
DecreaseServiceThreadsCount(
VOID
)
/*++
Routine name : DecreaseServiceThreadsCount
Routine description:
Safetly decrements the service threads reference count
Author:
Oded Sacher (OdedS), Dec, 2000
Arguments:
VOID
Return Value:
BOOL
--*/
{
BOOL bRet = TRUE;
DEBUG_FUNCTION_NAME(TEXT("DecreaseServiceThreadsCount"));
Assert (!ThreadOwnsCs()); // verify that the terminating thread does not own a critical section!!!
EnterCriticalSection (&g_CsServiceThreads);
g_lServiceThreadsCount--;
Assert (g_lServiceThreadsCount >= 0);
DebugPrintEx(
DEBUG_MSG,
TEXT("Current service threads count is %ld"),
g_lServiceThreadsCount);
if (0 == g_lServiceThreadsCount)
{
bRet = SetEvent (g_hThreadCountEvent);
if (FALSE == bRet)
{
DebugPrintEx(
DEBUG_ERR,
TEXT("SetEvent failed (g_hThreadCountEvent) (ec: %ld"),
GetLastError());
}
}
LeaveCriticalSection (&g_CsServiceThreads);
return bRet;
}
HANDLE CreateThreadAndRefCount(
LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD
DWORD dwStackSize, // initial stack size
LPTHREAD_START_ROUTINE lpStartAddress, // thread function
LPVOID lpParameter, // thread argument
DWORD dwCreationFlags, // creation option
LPDWORD lpThreadId // thread identifier
)
/*++
Routine name : CreateThreadAndRefCount
Routine description:
Creates a thread and saftely increments the service threads reference count.
All function parameters and return value are IDENTICAL to CreateThread().
Author:
Oded Sacher (OdedS), Dec, 2000
Arguments:
lpThreadAttributes [ ] -
dwStackSize [ ] -
lpStartAddress [ ] -
lpParameter [ ] -
dwCreationFlags [ ] -
lpThreadId [ ] -
Return Value:
HANDLE
--*/
{
HANDLE hThread;
DWORD ec;
DEBUG_FUNCTION_NAME(TEXT("CreateThreadAndRefCount"));
//
// First enter g_CsServiceThreads so the threads reference counter is always ssynced!
//
EnterCriticalSection (&g_CsServiceThreads);
hThread = CreateThread( lpThreadAttributes,
dwStackSize,
lpStartAddress,
lpParameter,
dwCreationFlags,
lpThreadId
);
if (NULL == hThread)
{
ec = GetLastError();
DebugPrintEx(
DEBUG_ERR,
TEXT("CreateThread failed (ec: %ld"),
ec);
}
else
{
if (!IncreaseServiceThreadsCount())
{
DebugPrintEx(
DEBUG_ERR,
TEXT("IncreaseServiceThreadsCount failed (ec: %ld"),
GetLastError());
}
}
LeaveCriticalSection (&g_CsServiceThreads);
if (NULL == hThread)
{
SetLastError(ec);
}
return hThread;
}
LPTSTR
MapFSPIJobExtendedStatusToString (DWORD dwFSPIExtendedStatus)
//*********************************************************************************
//* Name: MapFSPIJobExtendedStatusToString()
//* Author: Oded sacher
//* Date: Jan 2002
//*********************************************************************************
//* DESCRIPTION:
//* Maps FSPI extended job status codes to a displayable string
//* PARAMETERS:
//* [IN ] DWORD dwFSPIExtendedStatus
//* The FSPI extended Status code.
//*
//* RETURN VALUE:
//* Pointer to a string describing the well known extended status
//*
//*********************************************************************************
{
struct _ExStatusStringsMapEntry
{
DWORD dwFSPIExtendedStatus;
DWORD dwStringResourceId;
} ExStatusStringsMap [] =
{
{FSPI_ES_DISCONNECTED, FPS_DISCONNECTED },
{FSPI_ES_INITIALIZING, FPS_INITIALIZING },
{FSPI_ES_DIALING, FPS_DIALING },
{FSPI_ES_TRANSMITTING, FPS_SENDING },
{FSPI_ES_ANSWERED, FPS_ANSWERED },
{FSPI_ES_RECEIVING, FPS_RECEIVING },
{FSPI_ES_LINE_UNAVAILABLE, FPS_UNAVAILABLE },
{FSPI_ES_BUSY, FPS_BUSY },
{FSPI_ES_NO_ANSWER, FPS_NO_ANSWER },
{FSPI_ES_BAD_ADDRESS, FPS_BAD_ADDRESS },
{FSPI_ES_NO_DIAL_TONE, FPS_NO_DIAL_TONE },
{FSPI_ES_FATAL_ERROR, FPS_FATAL_ERROR },
{FSPI_ES_CALL_DELAYED, FPS_CALL_DELAYED },
{FSPI_ES_CALL_BLACKLISTED, FPS_CALL_BLACKLISTED },
{FSPI_ES_NOT_FAX_CALL, FPS_NOT_FAX_CALL },
{FSPI_ES_PARTIALLY_RECEIVED, IDS_PARTIALLY_RECEIVED },
{FSPI_ES_HANDLED, FPS_HANDLED },
{FSPI_ES_CALL_COMPLETED, IDS_CALL_COMPLETED },
{FSPI_ES_CALL_ABORTED, IDS_CALL_ABORTED }
};
LPTSTR lptstrString = NULL;
for (DWORD dwIndex = 0; dwIndex < sizeof (ExStatusStringsMap) / sizeof (_ExStatusStringsMapEntry); dwIndex++)
{
if (ExStatusStringsMap[dwIndex].dwFSPIExtendedStatus == dwFSPIExtendedStatus)
{
lptstrString = GetString (ExStatusStringsMap[dwIndex].dwStringResourceId);
break;
}
}
return lptstrString;
}