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
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
|