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.
 
 
 
 
 
 

2204 lines
66 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
faxmon.c
Abstract:
Implementation of the following print monitor entry points:
InitializePrintMonitor
OpenPort
ClosePort
StartDocPort
EndDocPort
WritePort
ReadPort
Environment:
Windows XP fax print monitor
Revision History:
05/09/96 -davidx-
Remove caching of ports from the monitor.
02/22/96 -davidx-
Created it.
mm/dd/yy -author-
description
--*/
#include "faxmon.h"
#include "tiff.h"
#include "faxreg.h"
#include "faxext.h"
#include "faxsvcrg.h"
#include "faxevent.h"
#include "faxevent_messages.h"
#include "FaxRpcLimit.h"
//
// tag mapping structure for getting job parameters out of parameter string.
// see GetTagsFromParam().
//
typedef struct
{
LPTSTR lptstrTagName;
LPTSTR * lpptstrValue;
int nLen;
} FAX_TAG_MAP_ENTRY2;
//
// Fax monitor name string
//
TCHAR faxMonitorName[CCHDEVICENAME] = FAX_MONITOR_NAME; // Name defined in faxreg.h
//
// DLL instance handle
//
HINSTANCE g_hInstance = NULL;
HINSTANCE g_hResource = NULL;
BOOL
WriteToLog(
IN DWORD dwMsgId,
IN DWORD dwError,
IN PFAXPORT pFaxPort,
IN JOB_INFO_2 *pJobInfo
);
BOOL
WINAPI
DllMain(
HINSTANCE hModule,
ULONG ulReason,
PCONTEXT pContext
)
/*++
Routine Description:
DLL initialization procedure.
Arguments:
hModule - DLL instance handle
ulReason - Reason for the call
pContext - Pointer to context (not used by us)
Return Value:
TRUE if DLL is initialized successfully, FALSE otherwise.
--*/
{
switch (ulReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hModule);
g_hInstance = hModule;
g_hResource = GetResInstance(hModule);
if(!g_hResource)
{
return FALSE;
}
FXSEVENTInitialize();
break;
case DLL_PROCESS_DETACH:
FXSEVENTFree();
HeapCleanup();
FreeResInstance();
break;
}
return TRUE;
}
LPMONITOREX
InitializePrintMonitor(
LPTSTR pRegistryRoot
)
/*++
Routine Description:
Initialize the print monitor
Arguments:
pRegistryRoot = Points to a string that specifies the registry root for the monitor
Return Value:
Pointer to a MONITOREX structure which contains function pointers
to other print monitor entry points. NULL if there is an error.
--*/
{
static MONITOREX faxmonFuncs =
{
sizeof(MONITOR),
{
FaxMonEnumPorts, // EnumPorts
FaxMonOpenPort, // OpenPort
NULL, // OpenPortEx (Language monitors only.)
FaxMonStartDocPort, // StartDocPort
FaxMonWritePort, // WritePort
FaxMonReadPort, // ReadPort (Not in use)
FaxMonEndDocPort, // EndDocPort
FaxMonClosePort, // ClosePort
FaxMonAddPort, // AddPort (Obsolete. Should be NULL.)
FaxMonAddPortEx, // AddPortEx (Obsolete. Should be NULL.)
FaxMonConfigurePort, // ConfigurePort (Obsolete. Should be NULL.)
FaxMonDeletePort, // DeletePort (Obsolete. Should be NULL.)
NULL, // GetPrinterDataFromPort
NULL, // SetPortTimeOuts
NULL, // XcvOpenPort
NULL, // XcvDataPort
NULL // XcvClosePort
}
};
BOOL bRes = TRUE;
PREG_FAX_SERVICE pFaxReg = NULL;
DEBUG_FUNCTION_NAME(TEXT("InitializePrintMonitor"));
//
// Initialize Fax Event Log
//
if (!InitializeEventLog(&pFaxReg))
{
bRes = FALSE;
DebugPrintEx(DEBUG_ERR, _T("InitializeEventLog() failed: %ld"), GetLastError());
}
FreeFaxRegistry(pFaxReg);
return bRes ? &faxmonFuncs : NULL;
}
BOOL
FaxMonOpenPort(
LPTSTR pPortName,
PHANDLE pHandle
)
/*++
Routine Description:
Provides a port for a newly connected printer
Arguments:
pName - Points to a string that specifies the port name
pHandle - Returns a handle to the port
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFAXPORT pFaxPort = NULL;
LPTSTR pPortNameDup = NULL;
DEBUG_FUNCTION_NAME(TEXT("FaxMonOpenPort"));
Assert(pHandle != NULL && pPortName != NULL && !lstrcmp(pPortName, FAX_PORT_NAME));
//
// Only support one port - It's name must be FAX_PORT_NAME
//
if (lstrcmp(pPortName,FAX_PORT_NAME))
{
*pHandle = NULL;
return FALSE;
}
//
// Get information about the specified port
//
if ((pFaxPort = (PFAXPORT)MemAllocZ(sizeof(FAXPORT))) &&
(pPortNameDup = DuplicateString(FAX_PORT_NAME)) )
{
pFaxPort->startSig = pFaxPort->endSig = pFaxPort;
pFaxPort->pName = pPortNameDup;
pFaxPort->hFile = INVALID_HANDLE_VALUE;
pFaxPort->hCoverPageFile = INVALID_HANDLE_VALUE;
pFaxPort->pCoverPageFileName=NULL;
}
else
{
MemFree(pFaxPort);
pFaxPort = NULL;
}
*pHandle = (HANDLE) pFaxPort;
return (*pHandle != NULL);
} // FaxMonOpenPort
VOID
FreeFaxJobInfo(
PFAXPORT pFaxPort
)
/*++
Routine Description:
Free up memory used for maintaining information about the current job
Arguments:
pFaxPort - Points to a fax port structure
Return Value:
NONE
--*/
{
DEBUG_FUNCTION_NAME(TEXT("FreeFaxJobInfo"));
//
// Close and delete the temporary file if necessary
//
if (pFaxPort->hCoverPageFile != INVALID_HANDLE_VALUE)
{
CloseHandle(pFaxPort->hCoverPageFile);
pFaxPort->hCoverPageFile = INVALID_HANDLE_VALUE;
}
if (pFaxPort->pCoverPageFileName)
{
//
// If the cover page is a server based cover page it was not generated by the print monitor.
// No need to delete it.
// This however is a personal cover page temp file. It was generated by the print monitor and we
// need to delete it.
//
if (!DeleteFile(pFaxPort->pCoverPageFileName))
{
DebugPrintEx(DEBUG_WRN,
TEXT("Failed to delete cover page file: %s (ec: %ld)"),
pFaxPort->pCoverPageFileName,
GetLastError());
}
MemFree(pFaxPort->pCoverPageFileName);
pFaxPort->pCoverPageFileName = NULL;
}
if (pFaxPort->hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(pFaxPort->hFile);
pFaxPort->hFile = INVALID_HANDLE_VALUE;
}
if (pFaxPort->pFilename)
{
if (!DeleteFile(pFaxPort->pFilename))
{
DebugPrintEx(DEBUG_WRN,
TEXT("Failed to delete body file: %s (ec: %ld)"),
pFaxPort->pFilename,
GetLastError());
}
MemFree(pFaxPort->pFilename);
pFaxPort->pFilename = NULL;
}
if (pFaxPort->hPrinter)
{
ClosePrinter(pFaxPort->hPrinter);
pFaxPort->hPrinter = NULL;
}
MemFree(pFaxPort->pPrinterName);
pFaxPort->pPrinterName = NULL;
//
// Note: freeing pFaxPort->pParameters effectively frees the memory pointed by the strings in
// FAXPORT.JobParamsEx, FAXPORT.CoverPageEx, FAXPORT.SenderProfile and the recipients in
// FAXPORT.pRecipients
//
MemFree(pFaxPort->pParameters);
pFaxPort->pParameters = NULL;
ZeroMemory(&pFaxPort->JobParamsEx, sizeof(pFaxPort->JobParamsEx));
ZeroMemory(&pFaxPort->CoverPageEx, sizeof(pFaxPort->CoverPageEx));
ZeroMemory(&pFaxPort->SenderProfile, sizeof(pFaxPort->SenderProfile));
//
// Free the recipients array
//
MemFree(pFaxPort->pRecipients);
pFaxPort->pRecipients = NULL;
//
// Disconnect from the fax service if necessary
//
if (pFaxPort->hFaxSvc)
{
if (!FaxClose(pFaxPort->hFaxSvc))
{
DebugPrintEx(DEBUG_ERR,
TEXT("FaxClose failed: %d\n"),
GetLastError());
}
pFaxPort->hFaxSvc = NULL;
}
} // FreeFaxJobInfo
BOOL
FaxMonClosePort(
HANDLE hPort
)
/*++
Routine Description:
Closes the port specified by hPort when there are no printers connected to it
Arguments:
hPort - Specifies the handle of the port to be close
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFAXPORT pFaxPort = (PFAXPORT) hPort;
DEBUG_FUNCTION_NAME(TEXT("FaxMonClosePort"));
DEBUG_TRACE_ENTER;
//
// Make sure we have a valid handle
//
if (! ValidFaxPort(pFaxPort))
{
DebugPrintEx(DEBUG_ERR,TEXT("Trying to close an invalid fax port handle\n"));
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
//
// Free up memory used for maintaining information about the current job
//
FreeFaxJobInfo(pFaxPort);
MemFree(pFaxPort->pName);
MemFree(pFaxPort);
return TRUE;
} // FaxMonClosePort
LPTSTR
CreateTempFaxFile(
LPCTSTR lpctstrPrefix
)
/*++
Routine Description:
Create a temporary file in the system temp directory. The file name is prefixed
With the specified prefix.
Arguments:
lpctstrPrefix - [in] The temporary file prefix (3 characters).
Return Value:
Pointer to the name of the newly created temporary file
NULL if there is an error.
Caller should free the return value.
--*/
{
LPTSTR pFilename;
DWORD dwRes;
TCHAR TempDir[MAX_PATH];
DEBUG_FUNCTION_NAME(TEXT("CreateTempFaxFile"));
//
// Allocate a memory buffer for holding the temporary filename
//
pFilename = (LPTSTR)MemAlloc(sizeof(TCHAR) * MAX_PATH);
if (!pFilename)
{
DebugPrintEx(DEBUG_ERR,
TEXT("Failed to allocate %ld bytes"),
sizeof(TCHAR) * MAX_PATH);
return NULL;
}
dwRes = GetTempPath(sizeof(TempDir)/sizeof(TCHAR),TempDir);
if (!dwRes || dwRes > sizeof(TempDir)/sizeof(TCHAR))
{
DebugPrintEx(DEBUG_ERR,
TEXT("GetTempPath failed with %ld"),
GetLastError ());
MemFree(pFilename);
return NULL;
}
if (!GetTempFileName(TempDir, lpctstrPrefix, 0, pFilename))
{
DebugPrintEx(DEBUG_ERR,
TEXT("GetTempFileName failed with %ld"),
GetLastError ());
MemFree(pFilename);
return NULL;
}
return pFilename;
} // CreateTempFaxFile
BOOL OpenCoverPageFile(PFAXPORT pFaxPort)
{
DEBUG_FUNCTION_NAME(TEXT("OpenCoverPageFile"));
//
//Generate a unique file name for the cover page temp file in the TEMP directory
//
pFaxPort->pCoverPageFileName = CreateTempFaxFile(FAX_COVER_PAGE_EXT_LETTERS);
if (!pFaxPort->pCoverPageFileName)
{
DebugPrintEx(DEBUG_ERR,TEXT("Failed to generate temporary file for cover page template (ec: %d).\n"),GetLastError());
return FALSE;
}
DebugPrintEx(DEBUG_MSG,TEXT("Cover page temporary file: %ws\n"), pFaxPort->pCoverPageFileName);
//
// Open the file for reading and writing
//
pFaxPort->hCoverPageFile = CreateFile(pFaxPort->pCoverPageFileName,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == pFaxPort->hCoverPageFile)
{
DebugPrintEx(DEBUG_ERR,TEXT("Failed to open for WRITE temporary file for cover page template (ec: %d)"),GetLastError());
}
return (pFaxPort->hCoverPageFile != INVALID_HANDLE_VALUE);
} // OpenCoverPageFile
BOOL
OpenTempFaxFile(
PFAXPORT pFaxPort,
BOOL doAppend
)
/*++
Routine Description:
Open a handle to the current fax job file associated with a port
Arguments:
pFaxPort - Points to a fax port structure
doAppend - Specifies whether to discard existing data in the file or
append new data to it
Return Value:
TRUE if successful, FALSE otherwise
--*/
{
DWORD creationFlags;
DEBUG_FUNCTION_NAME(TEXT("OpenTempFaxFile"));
Assert(pFaxPort->pFilename && pFaxPort->hFile == INVALID_HANDLE_VALUE);
DebugPrintEx(DEBUG_MSG,TEXT("Temporary fax job file: %ws\n"), pFaxPort->pFilename);
//
// Open the file for reading and writing
//
creationFlags = doAppend ? OPEN_ALWAYS : (OPEN_ALWAYS | TRUNCATE_EXISTING);
pFaxPort->hFile = CreateFile(pFaxPort->pFilename,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
creationFlags,
FILE_ATTRIBUTE_NORMAL,
NULL);
//
// If we're appending, then move the file pointer to end of file
//
if (doAppend && pFaxPort->hFile != INVALID_HANDLE_VALUE &&
SetFilePointer(pFaxPort->hFile, 0, NULL, FILE_END) == 0xffffffff)
{
DebugPrintEx(DEBUG_ERR,TEXT("SetFilePointer failed: %d\n"), GetLastError());
CloseHandle(pFaxPort->hFile);
pFaxPort->hFile = INVALID_HANDLE_VALUE;
}
return (pFaxPort->hFile != INVALID_HANDLE_VALUE);
} // OpenTempFaxFile
LPCTSTR
ExtractFaxTag(
LPCTSTR pTagKeyword,
LPCTSTR pTaggedStr,
INT *pcch
)
/*++
Routine Description:
Find the value of for the specified tag in a tagged string.
Arguments:
pTagKeyword - specifies the interested tag keyword
pTaggedStr - points to the tagged string to be searched
pcch - returns the length of the specified tag value (if found)
Return Value:
Points to the value for the specified tag.
NULL if the specified tag is not found
NOTE:
Tagged strings have the following form:
<tag>value<tag>value
The format of tags is defined as:
<$FAXTAG$ tag-name>
There is exactly one space between the tag keyword and the tag name.
Characters in a tag are case-sensitive.
--*/
{
LPCTSTR pValue;
if (pValue = _tcsstr(pTaggedStr, pTagKeyword))
{
pValue += _tcslen(pTagKeyword);
if (pTaggedStr = _tcsstr(pValue, FAXTAG_PREFIX))
{
*pcch = (INT)(pTaggedStr - pValue);
}
else
{
*pcch = _tcslen(pValue);
}
}
return pValue;
} // ExtractFaxTag
//*********************************************************************************
//* Name: GetTagsFromParam()
//* Author: Ronen Barenboim
//* Date: March 23, 1999
//*********************************************************************************
//* DESCRIPTION:
//* Given a tagged parameter string this function populates a FAX_TAG_MAP_ENTRY2
//* array with pointers to each of the tag values and the length of each tag
//* value (for those tages specified in the tag map array).
//* PARAMETERS:
//* lpctstrParams
//* A pointer to the string containin the tagged parameters.
//* lpcTags
//* A pointer to a FAX_TAG_MAP_ENTRY2 array. For each element in the array
//* FAX_TAG_MAP_ENTRY2.lptstrTagName must point to the name of the tag to
//* look for.
//* FAX_TAG_MAP_ENTRY2.lpptstrValue will be set to a pointer to the first
//* char of the value string or NULL if the tag is not found.
//* If the tage is found FAX_TAG_MAP_ENTRY2.nLen will be set to the its
//* string value length. Otherwise its value is not defined.
//*
//* int nTagCount
//* The number of tages in the tag map array.
//* RETURN VALUE:
//* NONE
//* NOTE:
//* The function does not allocate any memory !!!
//* It returns pointers to substrings in the provided tagged paramter string.
//*********************************************************************************
void
GetTagsFromParam(
LPCTSTR lpctstrParams,
FAX_TAG_MAP_ENTRY2 * lpcTags,
int nTagCount)
{
//
// Note: GetTagsFromParam DOES NOT ALLOCATE any memory for the returned tag values.
// It returns pointers to location within the parameter string.
// Thus, freeing the parameter string (deallocated when the port is closed)
// is enough. DO NOT attempt to free the memory for each tag.
//
int nTag;
//
// Extract individual fields out of the tagged string
//
for (nTag=0; nTag < nTagCount; nTag++)
{
*(lpcTags[nTag].lpptstrValue) = (LPTSTR)ExtractFaxTag(lpcTags[nTag].lptstrTagName,
lpctstrParams,
&(lpcTags[nTag].nLen));
}
//
// Null-terminate each field
//
for (nTag=0; nTag < nTagCount; nTag++)
{
if (*(lpcTags[nTag].lpptstrValue))
{
(*(lpcTags[nTag].lpptstrValue))[lpcTags[nTag].nLen] = NUL;
}
}
} // GetTagsFromParam
//*********************************************************************************
//* Name: SetRecipientFromTaggedParams()
//* Author: Ronen Barenboim
//* Date: March 23, 1999
//*********************************************************************************
//* DESCRIPTION:
//* Populates a recipient FAX_PERSONAL_PROFILE with pointers to relevant
//* information in in the provided tagged parameter string.
//* PARAMETERS:
//* pParamStr
//*
//* PFAX_PERSONAL_PROFILE lpProfile
//*
//* RETURN VALUE:
//* NONE
//* NOTE:
//* This function does not allocate memory !!!
//* The returned pointers are pointed to locations within the provided
//* pParamStr string.
//*********************************************************************************
VOID SetRecipientFromTaggedParams(
LPCTSTR pParamStr,
PFAX_PERSONAL_PROFILE lpProfile)
{
FAX_TAG_MAP_ENTRY2 tagMap[] =
{
{ FAXTAG_RECIPIENT_NAME, (LPTSTR *)&lpProfile->lptstrName},
{ FAXTAG_RECIPIENT_NUMBER, (LPTSTR *)&lpProfile->lptstrFaxNumber },
{ FAXTAG_RECIPIENT_COMPANY, (LPTSTR *)&lpProfile->lptstrCompany },
{ FAXTAG_RECIPIENT_STREET, (LPTSTR *)&lpProfile->lptstrStreetAddress },
{ FAXTAG_RECIPIENT_CITY, (LPTSTR *)&lpProfile->lptstrCity },
{ FAXTAG_RECIPIENT_STATE, (LPTSTR *)&lpProfile->lptstrState },
{ FAXTAG_RECIPIENT_ZIP, (LPTSTR *)&lpProfile->lptstrZip },
{ FAXTAG_RECIPIENT_COUNTRY, (LPTSTR *)&lpProfile->lptstrCountry },
{ FAXTAG_RECIPIENT_TITLE, (LPTSTR *)&lpProfile->lptstrTitle },
{ FAXTAG_RECIPIENT_DEPT, (LPTSTR *)&lpProfile->lptstrDepartment },
{ FAXTAG_RECIPIENT_OFFICE_LOCATION, (LPTSTR *)&lpProfile->lptstrOfficeLocation },
{ FAXTAG_RECIPIENT_HOME_PHONE, (LPTSTR *)&lpProfile->lptstrHomePhone },
{ FAXTAG_RECIPIENT_OFFICE_PHONE, (LPTSTR *)&lpProfile->lptstrOfficePhone },
};
ZeroMemory(lpProfile, sizeof(FAX_PERSONAL_PROFILE));
lpProfile->dwSizeOfStruct = sizeof( FAX_PERSONAL_PROFILE);
GetTagsFromParam(pParamStr, tagMap, sizeof(tagMap)/sizeof(FAX_TAG_MAP_ENTRY2));
} // SetRecipientFromTaggedParams
//*********************************************************************************
//* Name: SetJobInfoFromTaggedParams()
//* Author: Ronen Barenboim
//* Date: March 23, 1999
//*********************************************************************************
//* DESCRIPTION:
//* Popultaes pFaxPort->JobParamsEx, CoverPageEx , SenderProfile and
//* nRecipientCount using the provided tagged parameter string.
//* The string must be NULL terminated.
//* PARAMETERS:
//* LPCTSTR pParamStr [IN\OUT]
//*
//* PFAXPORT pFaxPort [OUT]
//*
//* RETURN VALUE:
//* NONE
//* NOTE:
//* The string pointers put into the populated pFaxPort structures are pointers
//* into the provided pParamStr string. No memory is allocated by this
//* function !!!
//*********************************************************************************
void SetJobInfoFromTaggedParams(
LPCTSTR pParamStr,
PFAXPORT pFaxPort)
{
LPTSTR lptstrServerCoverPage = NULL;
LPTSTR WhenToSend = NULL;
LPTSTR SendAtTime = NULL;
LPTSTR lptstrPageCount=NULL; //temp for holding the page count string;
LPTSTR lptstrRecipientCount=NULL;
LPTSTR lptstrReceiptFlags = NULL;
LPTSTR lptstrPriority = NULL;
FAX_TAG_MAP_ENTRY2 tagMap[] =
{
{ FAXTAG_SENDER_NAME, (LPTSTR *)&pFaxPort->SenderProfile.lptstrName},
{ FAXTAG_SENDER_NUMBER, (LPTSTR *)&pFaxPort->SenderProfile.lptstrFaxNumber },
{ FAXTAG_SENDER_COMPANY, (LPTSTR *)&pFaxPort->SenderProfile.lptstrCompany },
{ FAXTAG_SENDER_TITLE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrTitle },
{ FAXTAG_SENDER_DEPT, (LPTSTR *)&pFaxPort->SenderProfile.lptstrDepartment },
{ FAXTAG_SENDER_OFFICE_LOCATION, (LPTSTR *)&pFaxPort->SenderProfile.lptstrOfficeLocation },
{ FAXTAG_SENDER_HOME_PHONE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrHomePhone },
{ FAXTAG_SENDER_OFFICE_PHONE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrOfficePhone },
{ FAXTAG_SENDER_STREET, (LPTSTR *)&pFaxPort->SenderProfile.lptstrStreetAddress },
{ FAXTAG_SENDER_CITY, (LPTSTR *)&pFaxPort->SenderProfile.lptstrCity },
{ FAXTAG_SENDER_STATE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrState },
{ FAXTAG_SENDER_ZIP, (LPTSTR *)&pFaxPort->SenderProfile.lptstrZip },
{ FAXTAG_SENDER_COUNTRY, (LPTSTR *)&pFaxPort->SenderProfile.lptstrCountry },
{ FAXTAG_SENDER_EMAIL, (LPTSTR *)&pFaxPort->SenderProfile.lptstrEmail },
{ FAXTAG_TSID, (LPTSTR *)&pFaxPort->SenderProfile.lptstrTSID },
{ FAXTAG_BILLING_CODE, (LPTSTR *)&pFaxPort->SenderProfile.lptstrBillingCode},
{ FAXTAG_COVERPAGE_NAME, (LPTSTR *)&pFaxPort->CoverPageEx.lptstrCoverPageFileName },
{ FAXTAG_SERVER_COVERPAGE, (LPTSTR *)&lptstrServerCoverPage },
{ FAXTAG_NOTE, (LPTSTR *)&pFaxPort->CoverPageEx.lptstrNote },
{ FAXTAG_SUBJECT, (LPTSTR *)&pFaxPort->CoverPageEx.lptstrSubject},
{ FAXTAG_WHEN_TO_SEND, (LPTSTR *)&WhenToSend },
{ FAXTAG_SEND_AT_TIME, (LPTSTR *)&SendAtTime },
{ FAXTAG_PAGE_COUNT, (LPTSTR *)&lptstrPageCount },
{ FAXTAG_RECEIPT_TYPE, (LPTSTR *)&lptstrReceiptFlags},
{ FAXTAG_RECEIPT_ADDR, (LPTSTR *)&pFaxPort->JobParamsEx.lptstrReceiptDeliveryAddress},
{ FAXTAG_PRIORITY, (LPTSTR *)&lptstrPriority},
{ FAXTAG_RECIPIENT_COUNT, (LPTSTR *)&lptstrRecipientCount}
};
ZeroMemory(&pFaxPort->SenderProfile, sizeof(FAX_PERSONAL_PROFILE));
pFaxPort->SenderProfile.dwSizeOfStruct = sizeof( FAX_PERSONAL_PROFILE);
ZeroMemory(&pFaxPort->CoverPageEx, sizeof(FAX_COVERPAGE_INFO_EXW));
pFaxPort->CoverPageEx.dwSizeOfStruct = sizeof( FAX_COVERPAGE_INFO_EXW);
ZeroMemory(&pFaxPort->JobParamsEx, sizeof(FAX_JOB_PARAM_EXW));
pFaxPort->JobParamsEx.dwSizeOfStruct = sizeof( FAX_JOB_PARAM_EXW);
//
// Note: GetTagsFromParam DOES NOT ALLOCATE any memory for the returned tag values.
// It returns pointers to location within the parameter string.
// Thus, freeing the parameter string (deallocated when the port is closed)
// is enough. DO NOT attempt to free the memory for each tag.
//
GetTagsFromParam(pParamStr,tagMap,sizeof(tagMap)/sizeof(FAX_TAG_MAP_ENTRY2));
if (lptstrServerCoverPage)
{
pFaxPort->CoverPageEx.bServerBased=TRUE;
}
else
{
pFaxPort->CoverPageEx.bServerBased=FALSE;
}
pFaxPort->CoverPageEx.dwCoverPageFormat=FAX_COVERPAGE_FMT_COV;
if (WhenToSend)
{
if (_tcsicmp( WhenToSend, TEXT("cheap") ) == 0)
{
pFaxPort->JobParamsEx.dwScheduleAction = JSA_DISCOUNT_PERIOD;
}
else if (_tcsicmp( WhenToSend, TEXT("at") ) == 0)
{
pFaxPort->JobParamsEx.dwScheduleAction = JSA_SPECIFIC_TIME;
}
}
if (SendAtTime)
{
if (_tcslen(SendAtTime) == 5 && SendAtTime[2] == L':' &&
_istdigit(SendAtTime[0]) && _istdigit(SendAtTime[1]) &&
_istdigit(SendAtTime[3]) && _istdigit(SendAtTime[4]))
{
DWORDLONG FileTime;
SYSTEMTIME LocalTime;
INT Minutes;
INT SendMinutes;
SendAtTime[2] = 0;
//
// Calculate the number of minutes from now to send and add that to the current time.
//
GetLocalTime( &LocalTime );
SystemTimeToFileTime( &LocalTime, (LPFILETIME) &FileTime );
SendMinutes = min(23,_ttoi( &SendAtTime[0] )) * 60 + min(59,_ttoi( &SendAtTime[3] ));
Minutes = LocalTime.wHour * 60 + LocalTime.wMinute;
Minutes = SendMinutes - Minutes;
//
// Account for passing midnight
//
if (Minutes < 0)
{
Minutes += 24 * 60;
}
FileTime += (DWORDLONG)(Minutes * 60I64 * 1000I64 * 1000I64 * 10I64);
FileTimeToSystemTime((LPFILETIME) &FileTime, &pFaxPort->JobParamsEx.tmSchedule );
}
}
//
// Setting PageCount=0 means the server will count the number of pages in the job
//
pFaxPort->JobParamsEx.dwPageCount = 0;
pFaxPort->nRecipientCount =_ttoi(lptstrRecipientCount);
pFaxPort->JobParamsEx.Priority = (FAX_ENUM_PRIORITY_TYPE)_ttoi(lptstrPriority);
pFaxPort->JobParamsEx.dwReceiptDeliveryType = _ttoi(lptstrReceiptFlags);
} // SetJobInfoFromTaggedParams
//*********************************************************************************
//* Name: GetJobInfo()
//* Author: Ronen Barenboim
//* Date: March 23, 1999
//*********************************************************************************
//* DESCRIPTION:
//* Popultes the sender information , cover page information ,job parameters
//* information and recipients information in the pointed FAXPORT structure.
//* The information is retrieved from pFaxPort->pParameters tagged parameter string.
//* PARAMETERS:
//* pFaxPort [OUT]
//*
//* jobId [IN]
//*
//* RETURN VALUE:
//*
//* Notes:
//* the format of the tagged parameter string is:
//* The string is partitioned to "records" each record starts with the <$FAXTAG NEWREC>
//* tag with a dummy value of "1" (exactly one character).
//* The first record contains all the information which is not recipient related
//* (cover page, sender info, etc.) and also contains the number of recipients in
//* the transmission.
//* This record is followed by a number of records which is equal to the number
//* of specified recipients. Rach of these records contains recipient information
//* which is equivalent to the content of FAX_PERSONAL_PROFILE.
//*********************************************************************************
BOOL
GetJobInfo(
PFAXPORT pFaxPort,
DWORD jobId
)
{
JOB_INFO_2 *pJobInfo2 = NULL;
LPTSTR pParameters = NULL;
LPTSTR lptstrCurRecipient = NULL;
LPTSTR lptstrNextRecipient = NULL;
UINT nRecp;
DEBUG_FUNCTION_NAME(TEXT("GetJobInfo"));
pJobInfo2 = (PJOB_INFO_2)MyGetJob(pFaxPort->hPrinter, 2, jobId);
if (!pJobInfo2)
{ // pJobInfo2 is allocated here
DebugPrintEx(DEBUG_ERR,
TEXT("Failed to get job information for print job: %ld"),
jobId);
goto Error;
}
if (!pJobInfo2->pParameters)
{
DebugPrintEx(DEBUG_ERR,
TEXT("Print job %ld has NULL tagged parameter string. No op."),
jobId);
goto Error;
}
if ((pFaxPort->pParameters = DuplicateString(pJobInfo2->pParameters)) == NULL)
{
DebugPrintEx(DEBUG_ERR,
_T("DuplicateString(pJobInfo2->pParameters) failed"));
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto Error;
}
pParameters = pFaxPort->pParameters;
//
// Find the first recipient new record tag and place a NULL at its start.
// This makes the first record into a NULL terminated string and
// allows us to use _tcsstr (used by ExtractTag) to locate tags in the first record.
//
lptstrCurRecipient=_tcsstr(pParameters+1, FAXTAG_NEW_RECORD);
if (lptstrCurRecipient)
{
*lptstrCurRecipient=TEXT('\0');
//
// move past the <$FAXTAG NEWREC> dummy value so we point to the start of
// the recipient info.
//
lptstrCurRecipient = lptstrCurRecipient + _tcslen(FAXTAG_NEW_RECORD)+1;
}
else
{
//
// Bad job info e.g. LPR/LPD job
//
DebugPrintEx(DEBUG_ERR,
TEXT("Bad job info, No recipients - pFaxPort->pParameters is %s"),
pFaxPort->pParameters);
goto Error;
}
//
// Populate all but the recipient information from the tagged parameter string (1st record)
//
SetJobInfoFromTaggedParams(pParameters,pFaxPort);
//
// Allocate the recipient list (Note that only after calling SetJobInfoFromTaggedParams()
// we know how many recipients there are).
//
if (0 == pFaxPort->nRecipientCount ||
pFaxPort->nRecipientCount > FAX_MAX_RECIPIENTS)
{
//
// Recipients count is greater than the limit. This can be an attack that will cause the spooler to allocate alot of memory.
//
DebugPrintEx(DEBUG_ERR,
TEXT("Recipient limit exceeded, or no recipients. #of recipients: %ld"),
pFaxPort->nRecipientCount);
goto Error;
}
pFaxPort->pRecipients = (PFAX_PERSONAL_PROFILE)MemAlloc(sizeof(FAX_PERSONAL_PROFILE)*pFaxPort->nRecipientCount);
if (!pFaxPort->pRecipients)
{
DebugPrintEx( DEBUG_ERR,
TEXT("Failed to allocate %ld bytes for recipient array.(ec: 0x%0X)"),
sizeof(FAX_PERSONAL_PROFILE)*pFaxPort->nRecipientCount,
GetLastError());
goto Error;
}
//
// Go over the recipients array and populate each recipient from the parameter string.
//
for (nRecp=0; nRecp<pFaxPort->nRecipientCount; nRecp++)
{
//
// At each stage we must first turn the string into null terminated string
// by locating the next new record tag and replacing its first char with NULL.
// This allows us to use ExtractTag on the current recipient record alone (without
// crossing over into the content of the next recipient record).
// lptstrCurRecipient allways points to the first char past the new record tag and
// dummy value.
//
lptstrNextRecipient=_tcsstr(lptstrCurRecipient,FAXTAG_NEW_RECORD);
if (lptstrNextRecipient)
{
*lptstrNextRecipient=TEXT('\0');
//
// Before being assigned into lptstrCurRecipient we make sure lptstrNextRecipient
// points to the data following the next recipient new record tag and dummy value.
//
lptstrNextRecipient=lptstrNextRecipient+_tcslen(FAXTAG_NEW_RECORD);
}
else
{
if (nRecp != (pFaxPort->nRecipientCount-1))
{
//
// only the last recipient does not have a following recipient
// We have a mismach between the number of recipients in the recipients array
// to the number of recipients reported.
//
DebugPrintEx(
DEBUG_ERR,
TEXT("Number of recipients mismatch."));
goto Error;
}
}
SetRecipientFromTaggedParams( lptstrCurRecipient,&pFaxPort->pRecipients[nRecp]);
//
// Move to the next record in the parameter string
//
lptstrCurRecipient=lptstrNextRecipient;
}
MemFree(pJobInfo2);
return TRUE;
Error:
MemFree(pJobInfo2);
return FALSE;
} // GetJobInfo
BOOL
FaxMonStartDocPort(
HANDLE hPort,
LPTSTR pPrinterName,
DWORD JobId,
DWORD Level,
LPBYTE pDocInfo
)
/*++
Routine Description:
Spooler calls this function to start a new print job on the port
Arguments:
hPort - Identifies the port
pPrinterName - Specifies the name of the printer to which the job is being sent
JobId - Identifies the job being sent by the spooler
Level - Specifies the DOC_INFO_x level
pDocInfo - Points to the document information
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
DWORD dwErr = ERROR_SUCCESS;
JOB_INFO_3 *pJobInfo;
PFAXPORT pFaxPort = (PFAXPORT) hPort;
DEBUG_FUNCTION_NAME(TEXT("FaxMonStartDocPort"));
DebugPrintEx(DEBUG_MSG,TEXT("Entering StartDocPort: %d ...\n"), JobId);
//
// Make sure we have a valid handle
//
if (! ValidFaxPort(pFaxPort))
{
DebugPrintEx(DEBUG_ERR,TEXT("StartDocPort is given an invalid fax port handle\n"));
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
//
// Check if we're at the beginning of a series of chained jobs
//
pFaxPort->bCoverPageJob = FALSE;
if (INVALID_HANDLE_VALUE != pFaxPort->hCoverPageFile)
{
//
// Cover page file exists.
// We already written to it (since this startdoc event is for the body of the fax)
// so lets close the file.
//
CloseHandle(pFaxPort->hCoverPageFile);
pFaxPort->hCoverPageFile = INVALID_HANDLE_VALUE;
}
if (pFaxPort->hFaxSvc)
{
//
// If pFaxPort->hFaxSvc is not NULL then we are in the job following the cover page print job.
// FaxMonEndDocPort() that was called after the cover page print job updated pFaxPort->NextJobId
// to the next job id in the chain. Thus, the job id we got as a parameter must be
// the same is pFaxPort->JobId.
//
Assert(pFaxPort->jobId == JobId);
return TRUE;
}
//
// If we are not connected to the fax server yet.
// This means that this is the FIRST job we handle since the port was last opened.
// (This means it is the cover page job).
//
Assert(pFaxPort->pPrinterName == NULL &&
pFaxPort->hPrinter == NULL &&
pFaxPort->pParameters == NULL &&
pFaxPort->pFilename == NULL &&
pFaxPort->hFile == INVALID_HANDLE_VALUE);
if (!OpenPrinter(pPrinterName, &pFaxPort->hPrinter, NULL))
{
pFaxPort->hPrinter = NULL;
DebugPrintEx(DEBUG_ERR,TEXT("Failed to open printer %s (ec: %d)"),
pPrinterName,
GetLastError());
goto Error;
}
//
// Connect to the fax service and obtain a session handle
//
if (!FaxConnectFaxServer(NULL, &pFaxPort->hFaxSvc))
{
dwErr = GetLastError();
DebugPrintEx(DEBUG_ERR, _T("FaxConnectFaxServer failed: %d\n"), dwErr);
pFaxPort->hFaxSvc = NULL;
goto Error;
}
//
// Remember the printer name because we'll need it at EndDocPort time.
//
pFaxPort->pPrinterName = DuplicateString(pPrinterName);
if (!pFaxPort->pPrinterName)
{
DebugPrintEx(DEBUG_ERR,TEXT("Failed to duplicate printer name (ec: %d)"),GetLastError());
goto Error;
}
//
// All Jobs are chained, with first job being Cover Page and
// second one being the Body.
//
// The only case where only one Job is arrived, is when the Job
// is created by FaxStartPrintJob(). In this case, the Job
// contains both the Cover Page Info and the Body together.
//
// To check whether the Job is chained or not, MyGetJob() is called.
//
// If NextJob is NOT zero ==> there is chained job ==>
// ==> so the current job is the Cover Page job.
//
if (pJobInfo = (PJOB_INFO_3)MyGetJob(pFaxPort->hPrinter, 3, JobId))
{
pFaxPort->bCoverPageJob = (pJobInfo->NextJobId != 0);
MemFree(pJobInfo);
}
else
{
DebugPrintEx(DEBUG_ERR,
_T("MyGetJob() for JobId = %ld failed, ec = %ld"),
JobId,
GetLastError());
goto Error;
}
//
// Get the job parameters from the string in JOB_INFO_2:pParameters.
//
if (!GetJobInfo(pFaxPort, JobId))
{
DebugPrintEx(DEBUG_ERR,TEXT("Failed to get job info for job id : %d"),JobId);
goto Error;
}
//
// CreateTempFaxFile() creates a temporray files into which the fax body
// data written by FaxMonWritePort() will be saved.
//
if (!(pFaxPort->pFilename = CreateTempFaxFile(TEXT("fax"))))
{
DebugPrintEx(DEBUG_ERR,TEXT("Failed to Create temp file for fax body. (ec: %d)"),
GetLastError());
goto Error;
}
//
// Open the temporary file we just created for write operation.
//
if (!OpenTempFaxFile(pFaxPort, FALSE))
{
DebugPrintEx(DEBUG_ERR,TEXT("Failed to Open temp file for fax body. (ec: %d)"),
GetLastError());
goto Error;
}
if (pFaxPort->CoverPageEx.lptstrCoverPageFileName && !pFaxPort->CoverPageEx.bServerBased)
{
//
// A cover page is specified and it is a personal cover page.
// The cover page (template) is in the chained print job.
// We create a file to which the cover page will be written (by FaxMonWriteDocPort).
//
DebugPrintEx(DEBUG_MSG,TEXT("Personal cover page detected."));
if (!OpenCoverPageFile(pFaxPort))
{
DebugPrintEx(DEBUG_ERR,TEXT("Failed to open temp file for fax cover page. (ec: %d)"),
GetLastError());
goto Error;
}
}
else
{
//
// The specified cover page is a server based cover page or no cover page is specified.
// In both cases there is no cover page data in the print job body so we do not create
// the file to hold it.
//
DebugPrintEx(DEBUG_MSG,TEXT("Server cover page detected or no cover page specified."));
pFaxPort->hCoverPageFile=INVALID_HANDLE_VALUE;
}
//
// If we got here there were no errors. Keep the job id.
//
pFaxPort->jobId = JobId;
return TRUE;
Error:
if (NULL == pFaxPort->hFaxSvc && pFaxPort->hPrinter)
{
//
// pFaxPort->hFaxSvc == NULL
// i.e. FaxConnectFaxServer failed
//
// So, we need to Write to Fax Log
//
if (GetJobInfo(pFaxPort, JobId))
{
JOB_INFO_2 *pJobInfo2 = NULL;
pJobInfo2 = (PJOB_INFO_2)MyGetJob( pFaxPort->hPrinter, 2, JobId );
if (pJobInfo2)
{
WriteToLog(MSG_FAX_MON_CONNECT_FAILED, dwErr, pFaxPort, pJobInfo2);
MemFree(pJobInfo2);
}
}
}
if(pFaxPort->hPrinter)
{
//
// Delete print job
//
if (!SetJob(pFaxPort->hPrinter, JobId, 0, NULL, JOB_CONTROL_DELETE))
{
DebugPrintEx(DEBUG_ERR, _T("Failed to delete job with id: %d"), JobId);
}
}
FreeFaxJobInfo(pFaxPort);
return FALSE;
} // FaxMonStartDocPort
INT
CheckJobRestart(
PFAXPORT pFaxPort
)
/*++
Routine Description:
Check if the job has been restarted.
If not, get the ID of the next job in the chain.
Arguments:
pFaxPort - Points to a fax port structure
Return Value:
FAXERR_RESTART or FAXERR_NONE
--*/
{
JOB_INFO_3 *pJobInfo3;
JOB_INFO_2 *pJobInfo2;
INT status = FAXERR_NONE;
//
// If not, get the ID of the next job in the chain.
//
DEBUG_FUNCTION_NAME(TEXT("CheckJobRestart"));
DebugPrintEx(DEBUG_MSG,TEXT("Job chain: id = %d\n"), pFaxPort->nextJobId);
if (pJobInfo3 = (PJOB_INFO_3)MyGetJob(pFaxPort->hPrinter, 3, pFaxPort->jobId))
{
pFaxPort->nextJobId = pJobInfo3->NextJobId;
MemFree(pJobInfo3);
}
else
{
pFaxPort->nextJobId = 0;
}
//
// Determine whether the job has been restarted or deleted
//
if (pJobInfo2 = (PJOB_INFO_2)MyGetJob(pFaxPort->hPrinter, 2, pFaxPort->jobId))
{
if (pJobInfo2->Status & (JOB_STATUS_RESTART | JOB_STATUS_DELETING))
{
status = FAXERR_RESTART;
}
MemFree(pJobInfo2);
}
return status;
} // CheckJobRestart
BOOL
FaxMonEndDocPort(
HANDLE hPort
)
/*++
Routine Description:
Spooler calls this function at the end of a print job
Arguments:
hPort - Identifies the port
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFAXPORT pFaxPort = (PFAXPORT) hPort;
INT status;
BOOL Rslt;
JOB_INFO_2 *pJobInfo2 = NULL;
FAX_COVERPAGE_INFO_EX * pCovInfo;
BOOL bBodyFileIsEmpty=FALSE;
DWORD dwFileSize;
DWORDLONG dwlParentJobId; // Receives teh parent job id after job submittion
DWORDLONG* lpdwlRecipientJobIds = NULL; // Receives the recipient job ids after job submittion
DEBUG_FUNCTION_NAME(TEXT("FaxMonEndDocPort"));
//
// Make sure we have a valid handle
//
if (! ValidFaxPort(pFaxPort) || ! pFaxPort->hFaxSvc)
{
DebugPrintEx(DEBUG_ERR,TEXT("EndDocPort is given an invalid fax port handle\n"));
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
//
// Check if the job has been restarted. If not, get the ID of
// the next job in the chain.
//
//
// set pFaxPort->nextJobId to the next job id reported by JOB_INFO_3
// set to 0 if no more chained jobs.
//
if ((status = CheckJobRestart(pFaxPort)) != FAXERR_NONE)
{
goto ExitEndDocPort;
}
//
// Check if we're at the end of a job chain
//
// The job chain starts with a cover page job and ends with a body job.
// The cover page job has JOB_INFO_2:pParametes which is not NULL. This string
// is copied to pFaxPort->pParameters when GetJobInfo() was called at FaxMonStartDocPort().
// This is pParameters is not NULL it means that the current job is a cover page job.
// In case the current job is a cover page job we report that we sent the job to the printer
// and do nothing more. Since we do not close the temp file to which FaxMonWriteDoc() is writing
// the next job (body) will continue to write to the same file. This effectively merges the cover
// page with the body.
//
if (pFaxPort->nextJobId != 0 && pFaxPort->pParameters != NULL)
{
SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
return TRUE;
}
//
// If we are here then we are at the end of writing the body (the last job in the chain).
// In the temporaty file we have a TIFF file with the cover page followed by the body.
//
FlushFileBuffers(pFaxPort->hFile);
if ((dwFileSize = GetFileSize(pFaxPort->hFile, NULL)) == 0)
{
DebugPrintEx(DEBUG_WRN, TEXT("Body TIFF file is empty."));
bBodyFileIsEmpty = TRUE;
status = FAXERR_IGNORE;
}
if (INVALID_FILE_SIZE == dwFileSize)
{
status = GetLastError ();
DebugPrintEx(DEBUG_ERR, TEXT("Can't get file size (ec = %ld)"), status);
goto ExitEndDocPort;
}
CloseHandle(pFaxPort->hFile);
pFaxPort->hFile = INVALID_HANDLE_VALUE;
//
// Call the fax service to send the TIFF file
//
pJobInfo2 = (PJOB_INFO_2)MyGetJob( pFaxPort->hPrinter, 2, pFaxPort->jobId );
if (pJobInfo2)
{
pFaxPort->JobParamsEx.lptstrDocumentName = pJobInfo2->pDocument;
}
else
{
DebugPrintEx(DEBUG_WRN, TEXT("MyGetJob failed for JobId: %d. Setting document name to NULL."), pFaxPort->jobId);
pFaxPort->JobParamsEx.lptstrDocumentName = NULL;
}
pFaxPort->JobParamsEx.dwReserved[0] = 0xffffffff;
pFaxPort->JobParamsEx.dwReserved[1] = pFaxPort->jobId;
if (pFaxPort->CoverPageEx.lptstrCoverPageFileName)
{
//
// If a cover page is specified at all.
//
if (pFaxPort->CoverPageEx.bServerBased)
{
//
// Server cover page. Use the user specified path.
//
pCovInfo=&(pFaxPort->CoverPageEx);
DebugPrintEx(DEBUG_MSG,
TEXT("Using server based cover page: %s"),
pFaxPort->CoverPageEx.lptstrCoverPageFileName);
}
else
{
//
// Personal cover page. Use the cover page file created from the print job.
// Note that there is no cleanup issue here. pCoverPageFileName is deallocated on cleanup.
// and pFaxPort->CoverPageEx.lptstrCoverPageFileName is never deallocated directly. It points
// to a location within pFaxPort->pParameters which is freed at cleanup.
//
pFaxPort->CoverPageEx.lptstrCoverPageFileName = pFaxPort->pCoverPageFileName;
pCovInfo=&(pFaxPort->CoverPageEx);
DebugPrintEx(DEBUG_MSG,
TEXT("Using personal cover page copied to : %s"),
pFaxPort->CoverPageEx.lptstrCoverPageFileName);
}
}
else
{
//
// No cover page specified by the user. Nullify the cover page info sent to FaxSendDocument.
//
pCovInfo=NULL;
}
if (!pCovInfo && bBodyFileIsEmpty)
{
DebugPrintEx(DEBUG_WRN,TEXT("Body file is empty and cover page is not specified. Job is ignored."));
status = FAXERR_IGNORE;
goto ExitEndDocPort;
}
//
// Allocate array of recipient job ids
//
lpdwlRecipientJobIds=(DWORDLONG*)MemAlloc(sizeof(DWORDLONG)*pFaxPort->nRecipientCount);
if (!lpdwlRecipientJobIds)
{
DebugPrintEx(DEBUG_ERR,
TEXT("Failed to allocate array of size %ld for recipient job ids (ec: 0x%0X)."),
sizeof(DWORD)*pFaxPort->nRecipientCount,
GetLastError());
goto ExitEndDocPort;
}
if (bBodyFileIsEmpty)
{
DebugPrintEx(DEBUG_MSG, TEXT("Sending fax with EMPTY body (cover page is available)"));
Rslt = FaxSendDocumentEx(
pFaxPort->hFaxSvc,
NULL, // NO BODY
pCovInfo,
&pFaxPort->SenderProfile,
pFaxPort->nRecipientCount,
pFaxPort->pRecipients,
&pFaxPort->JobParamsEx,
&dwlParentJobId,
lpdwlRecipientJobIds);
}
else
{
DebugPrintEx(DEBUG_MSG, TEXT("Sending fax with body"));
Rslt = FaxSendDocumentEx(
pFaxPort->hFaxSvc,
pFaxPort->pFilename,
pCovInfo,
&pFaxPort->SenderProfile,
pFaxPort->nRecipientCount,
pFaxPort->pRecipients,
&pFaxPort->JobParamsEx,
&dwlParentJobId,
lpdwlRecipientJobIds);
}
if (Rslt)
{
DebugPrintEx(DEBUG_MSG,
TEXT("Successfuly submitted job. Parent Job Id = 0x%I64x"),
dwlParentJobId);
status = FAXERR_NONE;
SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
//
// pFaxPort>pFileName will be deleted on exit by FreeFaxJobInfo()
//
}
else
{
status = GetLastError();
DebugPrintEx(DEBUG_ERR,
_T("FaxSendDocument failed: ec = %d, job id = %ld\n"),
GetLastError(),
pFaxPort->jobId);
if (pJobInfo2)
{
WriteToLog(MSG_FAX_MON_SEND_FAILED, status, pFaxPort, pJobInfo2);
}
SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_DELETE);
status = FAXERR_NONE;
}
ExitEndDocPort:
//
// If the job wasn't successfully sent to the fax service,
// inform the spooler that there is an error on the job.
//
// Or if the print job has no data, simply ignore it.
//
switch (status)
{
case FAXERR_NONE:
break;
case FAXERR_RESTART:
DebugPrintEx(DEBUG_WRN,TEXT("Job restarted or deleted: id = %d\n"), pFaxPort->jobId);
//
// Deliberate fall through
//
case FAXERR_IGNORE:
SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_SENT_TO_PRINTER);
break;
default:
DebugPrintEx(DEBUG_ERR,TEXT("Error sending fax job: id = %d\n"), pFaxPort->jobId);
SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_DELETE);
break;
}
if (pJobInfo2)
{
MemFree( pJobInfo2 );
pFaxPort->JobParamsEx.lptstrDocumentName = NULL; // It was set to point into pJobInfo2
}
if (lpdwlRecipientJobIds)
{
MemFree(lpdwlRecipientJobIds);
lpdwlRecipientJobIds=NULL;
}
FreeFaxJobInfo(pFaxPort);
return (status < FAXERR_SPECIAL);
} // FaxMonEndDocPort
BOOL
FaxMonWritePort(
HANDLE hPort,
LPBYTE pBuffer,
DWORD cbBuf,
LPDWORD pcbWritten
)
/*++
Routine Description:
Writes data to a port
Arguments:
hPort - Identifies the port
pBuffer - Points to a buffer that contains data to be written to the port
cbBuf - Specifies the size in bytes of the buffer
pcbWritten - Returns the count of bytes successfully written to the port
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
PFAXPORT pFaxPort = (PFAXPORT) hPort;
BOOL bRet = TRUE;
//
// Make sure we have a valid handle
//
DEBUG_FUNCTION_NAME(TEXT("FaxMonWritePort"));
if (! ValidFaxPort(pFaxPort) || ! pFaxPort->hFaxSvc)
{
DebugPrintEx(DEBUG_ERR,TEXT("WritePort is given an invalid fax port handle\n"));
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (pFaxPort->bCoverPageJob)
{
//
// If pFaxPort->bCoverPageJob is on it means that the print job that writes is the cover page print job.
// If the cover page is a personal cover page then it is embedded (the template itself) in this print job
// and we write it to the temp cover page file we created earlier (pFaxPort->hCoverPageFile).
// If the cover page is a server cover page then it is NOT embedded in the print job (since it can be found
// directly on the server) and we do not create a temp cover page file and do not write the print job content
// into it.
//
if (!pFaxPort->CoverPageEx.bServerBased)
{
//
// Personal cover page
//
Assert(pFaxPort->hCoverPageFile != INVALID_HANDLE_VALUE);
if(!WriteFile(pFaxPort->hCoverPageFile, pBuffer, cbBuf, pcbWritten, NULL))
{
bRet = FALSE;
DebugPrintEx(DEBUG_ERR,TEXT("WriteFile failed (ec: %d)"), GetLastError());
}
}
else
{
//
// Server cover page - the print job body is empty and the port shoult not be written to.
// This should never execute.
//
Assert(FALSE);
*pcbWritten = cbBuf;
}
}
else
{
Assert(pFaxPort->hFile != INVALID_HANDLE_VALUE);
if(!WriteFile(pFaxPort->hFile, pBuffer, cbBuf, pcbWritten, NULL))
{
bRet = FALSE;
DebugPrintEx(DEBUG_ERR,TEXT("WriteFile failed (ec: %d)"), GetLastError());
}
}
if(!bRet)
{
//
// Operation failed
// Delete print job
//
if (!SetJob(pFaxPort->hPrinter, pFaxPort->jobId, 0, NULL, JOB_CONTROL_DELETE))
{
DebugPrintEx(DEBUG_ERR, _T("Failed to delete job with id: %d"), pFaxPort->jobId);
}
}
return bRet;
} // FaxMonWritePort
BOOL
FaxMonReadPort(
HANDLE hPort,
LPBYTE pBuffer,
DWORD cbBuf,
LPDWORD pcbRead
)
/*++
Routine Description:
Reads data from the port
Arguments:
hPort - Identifies the port
pBuffer - Points to a buffer where data read from the printer can be written
cbBuf - Specifies the size in bytes of the buffer pointed to by pBuffer
pcbRead - Returns the number of bytes successfully read from the port
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
DEBUG_FUNCTION_NAME(TEXT("FaxMonReadPort"));
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
} // FaxMonReadPort
BOOL
FaxMonEnumPorts(
LPTSTR pServerName,
DWORD Level,
LPBYTE pPorts,
DWORD cbBuf,
LPDWORD pcbNeeded,
LPDWORD pReturned
)
/*++
Routine Description:
Enumerates the ports available on the specified server
Arguments:
pServerName - Specifies the name of the server whose ports are to be enumerated
dwLevel - Specifies the version of the structure to which pPorts points
pPorts - Points to an array of PORT_INFO_1 structures where data describing
the available ports will be writteno
cbBuf - Specifies the size in bytes of the buffer to which pPorts points
pcbNeeded - Returns the required buffer size identified by pPorts
pReturned - Returns the number of PORT_INFO_1 structures returned
Return Value:
TRUE if successful, FALSE if there is an error
--*/
#define MAX_DESC_LEN 64
{
TCHAR portDescStr[MAX_DESC_LEN];
INT descStrSize, faxmonNameSize;
DWORD cbNeeded;
BOOL status = TRUE;
PORT_INFO_1 *pPortInfo1 = (PORT_INFO_1 *) pPorts;
PORT_INFO_2 *pPortInfo2 = (PORT_INFO_2 *) pPorts;
INT strSize;
DEBUG_FUNCTION_NAME(TEXT("FaxMonEnumPorts"));
DEBUG_TRACE_ENTER;
if (pcbNeeded == NULL || pReturned == NULL || (pPorts == NULL && cbBuf != 0))
{
DebugPrintEx(DEBUG_ERR,TEXT("Invalid input parameters\n"));
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
//
// Load the fax port description string
//
if (!LoadString(g_hResource, IDS_FAX_PORT_DESC, portDescStr, MAX_DESC_LEN))
{
portDescStr[0] = NUL;
}
descStrSize = SizeOfString(portDescStr);
faxmonNameSize = SizeOfString(faxMonitorName);
switch (Level)
{
case 1:
cbNeeded = sizeof(PORT_INFO_1) + SizeOfString(FAX_PORT_NAME);
break;
case 2:
cbNeeded = sizeof(PORT_INFO_2) + descStrSize + faxmonNameSize + SizeOfString(FAX_PORT_NAME);
break;
default:
ASSERT_FALSE;
cbNeeded = 0xffffffff;
break;
}
*pReturned = 1;
*pcbNeeded = cbNeeded;
if (cbNeeded > cbBuf)
{
//
// Caller didn't provide a big enough buffer
//
SetLastError(ERROR_INSUFFICIENT_BUFFER);
status = FALSE;
}
else
{
//
// Strings must be packed at the end of the caller provided buffer.
// Otherwise, spooler will screw up royally.
//
pPorts += cbBuf;
//
// Copy the requested port information to the caller provided buffer
//
strSize = SizeOfString(FAX_PORT_NAME);
pPorts -= strSize;
CopyMemory(pPorts, FAX_PORT_NAME, strSize);
switch (Level)
{
case 1:
pPortInfo1->pName = (LPTSTR) pPorts;
DebugPrintEx(DEBUG_MSG, TEXT("Port info 1: %ws\n"), pPortInfo1->pName);
pPortInfo1++;
break;
case 2:
pPortInfo2->pPortName = (LPTSTR) pPorts;
//
// Copy the fax monitor name string
//
pPorts -= faxmonNameSize;
pPortInfo2->pMonitorName = (LPTSTR) pPorts;
CopyMemory(pPorts, faxMonitorName, faxmonNameSize);
//
// Copy the fax port description string
//
pPorts -= descStrSize;
pPortInfo2->pDescription = (LPTSTR) pPorts;
CopyMemory(pPorts, portDescStr, descStrSize);
pPortInfo2->fPortType = PORT_TYPE_WRITE;
pPortInfo2->Reserved = 0;
DebugPrintEx(DEBUG_MSG,
TEXT("Port info 2: %ws, %ws, %ws\n"),
pPortInfo2->pPortName,
pPortInfo2->pMonitorName,
pPortInfo2->pDescription);
pPortInfo2++;
break;
default:
ASSERT_FALSE;
status = FALSE;
break;
}
}
return status;
} // FaxMonEnumPorts
BOOL
DisplayErrorNotImplemented(
HWND hwnd,
INT titleId
)
/*++
Routine Description:
Display an error dialog to tell the user that he cannot manage
fax devices in the Printers folder.
Arguments:
hwnd - Specifies the parent window for the message box
titleId - Message box title string resource ID
Return Value:
FALSE
--*/
{
TCHAR title[128] = {0};
TCHAR message[256] = {0};
LoadString(g_hResource, titleId, title, 128);
LoadString(g_hResource, IDS_CONFIG_ERROR, message, 256);
AlignedMessageBox(hwnd, message, title, MB_OK|MB_ICONERROR);
SetLastError(ERROR_SUCCESS);
return FALSE;
} // DisplayErrorNotImplemented
BOOL
FaxMonAddPort(
LPTSTR pServerName,
HWND hwnd,
LPTSTR pMonitorName
)
/*++
Routine Description:
Adds the name of a port to the list of supported ports
Arguments:
pServerName - Specifies the name of the server to which the port is to be added
hwnd - Identifies the parent window of the AddPort dialog box
pMonitorName - Specifies the monitor associated with the port
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
DEBUG_FUNCTION_NAME(TEXT("FaxMonAddPort"));
return DisplayErrorNotImplemented(hwnd, IDS_ADD_PORT);
} // FaxMonAddPort
BOOL
FaxMonAddPortEx(
LPTSTR pServerName,
DWORD level,
LPBYTE pBuffer,
LPTSTR pMonitorName
)
/*++
Routine Description:
Adds the name of a port to the list of supported ports
Arguments:
pServerName - Specifies the name of the server to which the port is to be added
hwnd - Identifies the parent window of the AddPort dialog box
pMonitorName - Specifies the monitor associated with the port
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
DEBUG_FUNCTION_NAME(TEXT("FaxMonAddPortEx"));
SetLastError(ERROR_NOT_SUPPORTED);
return FALSE;
} // FaxMonAddPortEx
BOOL
FaxMonDeletePort(
LPTSTR pServerName,
HWND hwnd,
LPTSTR pPortName
)
/*++
Routine Description:
Delete the specified port from the list of supported ports
Arguments:
pServerName - Specifies the name of the server from which the port is to be removed
hwnd - Identifies the parent window of the port-deletion dialog box
pPortName - Specifies the name of the port to be deleted
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
DEBUG_FUNCTION_NAME(TEXT("FaxMonDeletePort"));
return DisplayErrorNotImplemented(hwnd, IDS_CONFIGURE_PORT);
} // FaxMonDeletePort
BOOL
FaxMonConfigurePort(
LPWSTR pServerName,
HWND hwnd,
LPWSTR pPortName
)
/*++
Routine Description:
Display a dialog box to allow user to configure the specified port
Arguments:
pServerName - Specifies the name of the server on which the given port exists
hwnd - Identifies the parent window of the port-configuration dialog
pPortName - Specifies the name of the port to be configured
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{
DEBUG_FUNCTION_NAME(TEXT("FaxMonConfigurePort"));
return DisplayErrorNotImplemented(hwnd, IDS_CONFIGURE_PORT);
} // FaxMonConfigurePort
PVOID
MyGetJob(
HANDLE hPrinter,
DWORD level,
DWORD jobId
)
/*++
Routine Description:
Wrapper function for spooler API GetJob
Arguments:
hPrinter - Handle to the printer object
level - Level of JOB_INFO structure interested
jobId - Specifies the job ID
Return Value:
Pointer to a JOB_INFO structure, NULL if there is an error
--*/
{
PBYTE pJobInfo = NULL;
DWORD cbNeeded;
DEBUG_FUNCTION_NAME(TEXT("MyGetJob"));
if (!GetJob(hPrinter, jobId, level, NULL, 0, &cbNeeded) &&
GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
(pJobInfo = (PBYTE)MemAlloc(cbNeeded)) &&
GetJob(hPrinter, jobId, level, pJobInfo, cbNeeded, &cbNeeded))
{
return pJobInfo;
}
DebugPrintEx(DEBUG_ERR,TEXT("GetJob failed: %d\n"), GetLastError());
MemFree(pJobInfo);
return NULL;
} // MyGetJob
BOOL
WriteToLog(
IN DWORD dwMsgId,
IN DWORD dwError,
IN PFAXPORT pFaxPort,
IN JOB_INFO_2* pJobInfo
)
/*++
Routine name : WriteToLog
Routine description:
Write to the Event Log of Fax Service
Author:
Iv Garber (IvG), Sep, 2000
Arguments:
dwError [in] - error code
pFaxPort [in] - data about the fax
pJobInfo [in] - data about the fax job
Return Value:
TRUE if succeded to write to the event log, FALSE otherwise.
--*/
{
DWORD dwBufferSize = MAX_PATH - 1;
TCHAR tszBuffer[MAX_PATH] = {0};
BOOL bRes = FALSE;
DEBUG_FUNCTION_NAME(_T("WriteToLog"));
if (FAX_ERR_RECIPIENTS_LIMIT == dwError)
{
DWORD dwRecipientsLimit = 0;
if (!FaxGetRecipientsLimit( pFaxPort->hFaxSvc, &dwRecipientsLimit))
{
DebugPrintEx(DEBUG_ERR, _T("FaxGetRecipientsLimit() failed: %ld"), GetLastError());
}
//
// Write to the Event Log
//
bRes = FaxLog(FAXLOG_CATEGORY_OUTBOUND,
FAXLOG_LEVEL_MIN,
5,
MSG_FAX_MON_SEND_RECIPIENT_LIMIT,
pJobInfo->pMachineName,
pJobInfo->pUserName,
pFaxPort->SenderProfile.lptstrName,
DWORD2DECIMAL(pFaxPort->nRecipientCount),
DWORD2DECIMAL(dwRecipientsLimit));
}
else
{
//
// Write to the Event Log
//
bRes = FaxLog(FAXLOG_CATEGORY_OUTBOUND,
FAXLOG_LEVEL_MIN,
5,
dwMsgId,
DWORD2DECIMAL(dwError),
pJobInfo->pMachineName,
pJobInfo->pUserName,
pFaxPort->SenderProfile.lptstrName,
DWORD2DECIMAL(pFaxPort->nRecipientCount));
}
if (!bRes)
{
DebugPrintEx(DEBUG_ERR, _T("FaxLog() failed, ec = %ld"), GetLastError());
}
return bRes;
} // WriteToLog
LPTSTR
DuplicateString(
LPCTSTR pSrcStr
)
/*++
Routine Description:
Make a duplicate of the given character string
Arguments:
pSrcStr - Specifies the string to be duplicated
Return Value:
Pointer to the duplicated string, NULL if there is an error
NOTICE:
We're not using the utility function StringDup on purpose.
StringDup uses the utility MemAlloc / MemFree heap management routines.
However, in this module, MemAlloc / MemFree are remapped (in faxmon.h) to LocalAlloc / LocalFree.
--*/
{
LPTSTR pDestStr;
INT strSize;
DEBUG_FUNCTION_NAME(TEXT("DuplicateString"));
if (pSrcStr != NULL)
{
strSize = SizeOfString(pSrcStr);
if (pDestStr = (LPTSTR)MemAlloc(strSize))
{
CopyMemory(pDestStr, pSrcStr, strSize);
}
else
{
DebugPrintEx(DEBUG_ERR,TEXT("Memory allocation failed\n"));
}
}
else
{
pDestStr = NULL;
}
return pDestStr;
} // DuplicateString