|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
client16.c
Abstract:
Support for 16-bit (win31 and win95) fax clients
Environment:
Windows NT fax monitor
Revision History:
06/02/96 -davidx- Created it.
mm/dd/yy -author- description
--*/
#include "faxmon.h"
#include "tiffstub.h"
#include "prtcovpg.h"
#include "jobtag.h"
//
// File header for the fax data from downlevel client
//
#define FAX16_SIGNATURE 'NF16'
typedef struct {
WORD Magic; // 'II'
WORD Magic2; // 0x0042
DWORD FirstIFDOffset; // offset to the first IFD
DWORD Fax16Signature; // 'NF16'
DWORD CodePage; // code page use for converting multibyte strings to Unicode
DWORD SenderName; // sender's name string
DWORD SenderFaxNumber; // sender's fax number string
DWORD SenderCompany; // sender's company string
DWORD SenderAddress; // sender's address string
DWORD SenderTitle; // sender's title string
DWORD SenderDepartment; // sender's department string
DWORD SenderOffice; // sender's office location string
DWORD SenderHomePhone; // sender's home phone number string
DWORD SenderOfficePhone; // sender's office phone number string
DWORD RecName; // recipient's name string
DWORD RecFaxNumber; // recipient's fax number string
DWORD RecCompany; // recipient's company string
DWORD RecAddress; // recipient's address string
DWORD RecCity; // recipient's city string
DWORD RecState; // recipient's state string
DWORD RecZip; // recipient's zip code string
DWORD RecCountry; // recipient's country string
DWORD RecTitle; // recipient's title string
DWORD RecDepartment; // recipient's department string
DWORD RecOffice; // recipient's office string
DWORD RecHomePhone; // recipient's home phone number string
DWORD RecOfficePhone; // recipient's office phone number string
DWORD SubjectLine; // subject string
DWORD NoteMessage; // note string
DWORD TimeSent; // time-sent string
DWORD BillingCode; // billing code string
DWORD CoverPageFilename; // cover page filename string
DWORD CoverPageDataSize; // size of embedded cover page file in bytes
DWORD CoverPageData; // offset to beginning of embedded cover page file
DWORD NumberOfPages; // number of pages (not including the cover page)
DWORD EmailNotify; // offset to Email notification address
DWORD Reserved[7]; // reserved - must be 0 for now
//
// String data and embedded cover page file if any
//
} FAX16_TIFF_HEADER, *PFAX16_TIFF_HEADER;
LPWSTR CopyClientStringToUnicode( PFAX16_TIFF_HEADER pFax16Hdr, ULONG_PTR offset )
/*++
Routine Description:
Copy ANSI string from 16-bit clients to Unicode string
Arguments:
pFax16Hdr - Points to the fax data from downlevel client offset - Specifies the starting offset for the ANSI string
Return Value:
Pointer to the duplicated Unicode string NULL if there is an error
--*/
{ LPSTR pAnsiStr; INT cch; LPWSTR pUnicodeStr = NULL;
if (offset != 0) {
pAnsiStr = (LPSTR) ((LPBYTE) pFax16Hdr + offset); cch = strlen(pAnsiStr);
if (pUnicodeStr = MemAllocZ((cch + 1) * sizeof(WCHAR))) MultiByteToWideChar(pFax16Hdr->CodePage, 0, pAnsiStr, cch, pUnicodeStr, cch); }
return pUnicodeStr; }
VOID FreeCoverPageFields( PCOVERPAGEFIELDS pCPFields )
/*++
Routine Description:
Dispose of cover page field information
Arguments:
pCPFields - Points to cover page field information
Return Value:
NONE
--*/
{
if (pCPFields != NULL) {
LPTSTR *ppStr; LONG_PTR count;
//
// Free individual cover page field strings.
// HACK: We assume all fields between RecName and ToList are LPTSTRs.
//
ppStr = &pCPFields->RecName; count = (offsetof(COVERPAGEFIELDS, ToList) - offsetof(COVERPAGEFIELDS, RecName)) / sizeof(LPTSTR);
while (count-- > 0) {
MemFree(*ppStr); ppStr++; }
MemFree(pCPFields); } }
PCOVERPAGEFIELDS CollectFax16CoverPageFields( PFAX16_TIFF_HEADER pFax16Hdr )
/*++
Routine Description:
Collect cover page field information from 16bit client fax job
Arguments:
pFax16Hdr - Points to the fax data from downlevel client
Return Value:
Pointer to cover page field information NULL if there is an error
--*/
{ //
// Map fields in FAX16_TIFF_HEADER to fields in COVERPAGEFIELDS.
// HACK: We assume all fields between RecName and NumberOfPages are LPTSTRs.
//
#define NUM_CPFIELDS ((offsetof(COVERPAGEFIELDS, NumberOfPages) - \
offsetof(COVERPAGEFIELDS, RecName)) / sizeof(LPTSTR))
ULONG_PTR strOffsets[NUM_CPFIELDS] = {
pFax16Hdr->RecName, pFax16Hdr->RecFaxNumber, pFax16Hdr->RecCompany, pFax16Hdr->RecAddress, pFax16Hdr->RecCity, pFax16Hdr->RecState, pFax16Hdr->RecZip, pFax16Hdr->RecCountry, pFax16Hdr->RecTitle, pFax16Hdr->RecDepartment, pFax16Hdr->RecOffice, pFax16Hdr->RecHomePhone, pFax16Hdr->RecOfficePhone,
pFax16Hdr->SenderName, pFax16Hdr->SenderFaxNumber, pFax16Hdr->SenderCompany, pFax16Hdr->SenderAddress, pFax16Hdr->SenderTitle, pFax16Hdr->SenderDepartment, pFax16Hdr->SenderOffice, pFax16Hdr->SenderHomePhone, pFax16Hdr->SenderOfficePhone,
pFax16Hdr->NoteMessage, pFax16Hdr->SubjectLine, pFax16Hdr->TimeSent, };
PCOVERPAGEFIELDS pCPFields; LPTSTR *ppStr; LONG_PTR index;
if ((pCPFields = MemAllocZ(sizeof(COVERPAGEFIELDS))) == NULL) return NULL;
//
// Convert individual cover page field from ANSI to Unicode string
//
for (index=0, ppStr = &pCPFields->RecName; index < NUM_CPFIELDS; index++, ppStr++) {
if ((strOffsets[index] != 0) && (*ppStr = CopyClientStringToUnicode(pFax16Hdr, strOffsets[index])) == NULL) { FreeCoverPageFields(pCPFields); return NULL; } }
//
// Number of pages printed
//
if ((pCPFields->NumberOfPages = MemAllocZ(sizeof(TCHAR) * 16)) == NULL) {
FreeCoverPageFields(pCPFields); return NULL; }
return pCPFields; }
BOOL CollectFax16JobParam( PFAXPORT pFaxPort, PCOVERPAGEFIELDS pCPFields, LPTSTR pBillingCode )
/*++
Routine Description:
Collect 16-bit client fax job parameters
Arguments:
pFaxPort - Points to a fax port structure pCPFields - Points to cover page field information pBillingCode - Points to billing code string from 16-bit client
Return Value:
TRUE if successful, FALSE otherwise
--*/
{ //
// Cover page fields which are passed fax service as parameters
//
LPTSTR pSrcStr[NUM_JOBPARAM_TAGS] = {
pCPFields->RecFaxNumber, pCPFields->RecName, pCPFields->SdrFaxNumber, pCPFields->SdrName, pCPFields->SdrCompany, pCPFields->SdrDepartment, pBillingCode };
LPTSTR *ppDestStr[NUM_JOBPARAM_TAGS] = {
(LPTSTR *)&pFaxPort->jobParam.RecipientNumber, (LPTSTR *)&pFaxPort->jobParam.RecipientName, (LPTSTR *)&pFaxPort->jobParam.Tsid, (LPTSTR *)&pFaxPort->jobParam.SenderName, (LPTSTR *)&pFaxPort->jobParam.SenderCompany, (LPTSTR *)&pFaxPort->jobParam.SenderDept, (LPTSTR *)&pFaxPort->jobParam.BillingCode };
INT size, index; LPTSTR p;
//
// Calculate the total length for all parameters
//
for (index=size=0; index < NUM_JOBPARAM_TAGS; index++) {
if (pSrcStr[index]) size += SizeOfString(pSrcStr[index]); }
//
// Concatenate all parameters into a single string
//
if (size > 0 && (p = pFaxPort->pParameters = MemAllocZ(size))) {
for (index=0; index < NUM_JOBPARAM_TAGS; index++) {
if (pSrcStr[index]) {
*ppDestStr[index] = p; _tcscpy(p, pSrcStr[index]); p += _tcslen(p) + 1; } } }
return (pFaxPort->pParameters != NULL); }
LPTSTR GetClientCoverPageFile( PFAX16_TIFF_HEADER pFax16Hdr )
/*++
Routine Description:
Return the cover page file associated with a 16-bit client fax job
Arguments:
pFax16Hdr - Points to the fax data from downlevel client
Return Value:
Points to the name of the cover page file NULL if there is an error
--*/
#define SERVER_CP_DIRECTORY TEXT("\\coverpg\\")
{ LPTSTR pFilename;
if (pFax16Hdr->CoverPageFilename) {
//
// Use server-based cover page file
//
if (pFilename = CopyClientStringToUnicode(pFax16Hdr, pFax16Hdr->CoverPageFilename)) {
LPTSTR pServerDir = NULL, p; DWORD cb, len;
len = (_tcslen(SERVER_CP_DIRECTORY) + _tcslen(pFilename) + 1) * sizeof(TCHAR);
if (!GetPrinterDriverDirectory(NULL, NULL, 1, NULL, 0, &cb) && GetLastError() == ERROR_INSUFFICIENT_BUFFER && (pServerDir = MemAllocZ(cb + len)) && GetPrinterDriverDirectory(NULL, NULL, 1, (PBYTE) pServerDir, cb, &cb)) { //
// Strip off the last component of the driver directory
// which should be w32<arch>.
//
if (p = _tcsrchr(pServerDir, TEXT('\\'))) *p = NUL;
_tcscat(pServerDir, SERVER_CP_DIRECTORY); _tcscat(pServerDir, pFilename);
MemFree(pFilename); pFilename = pServerDir;
} else {
MemFree(pServerDir); MemFree(pFilename); pFilename = NULL; } }
} else if (pFilename = CreateTempFaxFile()) {
//
// Cover page data is embedded in the cover page job
// Create a temporary file and copy cover page data into it
//
HANDLE hFile; DWORD cbWritten; BOOL copied = FALSE;
Assert(pFax16Hdr->CoverPageData != 0 && pFax16Hdr->CoverPageDataSize != 0);
hFile = CreateFile(pFilename, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS | TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
copied = WriteFile(hFile, (LPBYTE) pFax16Hdr + pFax16Hdr->CoverPageData, pFax16Hdr->CoverPageDataSize, &cbWritten, NULL);
CloseHandle(hFile); }
if (! copied) {
Error(("Failed to copy cover page data to a temporary file\n")); DeleteFile(pFilename); MemFree(pFilename); pFilename = NULL; } }
return pFilename; }
LPTSTR GetBaseNoteFilename( VOID )
/*++
Routine Description:
Get the name of base cover page file in system32 directory
Arguments:
NONE
Return Value:
Pointer to name of base cover page file NULL if there is an error
--*/
#define BASENOTE_FILENAME TEXT("\\basenote.cov")
{ TCHAR systemDir[MAX_PATH]; LPTSTR pBaseNoteName = NULL; COVDOCINFO covDocInfo;
if (GetSystemDirectory(systemDir, MAX_PATH) && (pBaseNoteName = MemAlloc(SizeOfString(systemDir) + SizeOfString(BASENOTE_FILENAME)))) { _tcscpy(pBaseNoteName, systemDir); _tcscat(pBaseNoteName, BASENOTE_FILENAME); Verbose(("Base cover page filename: %ws\n", pBaseNoteName));
if (PrintCoverPage(NULL, NULL, pBaseNoteName, &covDocInfo) || ! (covDocInfo.Flags & COVFP_NOTE) || ! (covDocInfo.Flags & COVFP_SUBJECT)) { Error(("Invalid base cover page file: %ws\n", pBaseNoteName)); MemFree(pBaseNoteName); pBaseNoteName = NULL; } }
return pBaseNoteName; }
BOOL ProcessFax16CoverPage( PFAXPORT pFaxPort, PFAX16_TIFF_HEADER pFax16Hdr )
/*++
Routine Description:
Render the cover page for downlevel client into a temporary file
Arguments:
pFaxPort - Points to a fax port structure pFax16Hdr - Pointer to the fax data from downlevel client
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ PCOVERPAGEFIELDS pCPFields; LPTSTR pBillingCode; INT result = FALSE;
//
// Make sure the recipient's fax number is specified
//
if (pFax16Hdr->RecFaxNumber == 0) {
Error(("No recipient number is specified\n")); return FALSE; }
//
// Collect cover page field information and
// assemble fax job parameters and
// create a new temporary file for storing cover page job
//
pBillingCode = CopyClientStringToUnicode(pFax16Hdr, pFax16Hdr->BillingCode);
if ((pCPFields = CollectFax16CoverPageFields(pFax16Hdr)) && CollectFax16JobParam(pFaxPort, pCPFields, pBillingCode) && (pFaxPort->pFilename = CreateTempFaxFile())) { LPTSTR pCPFilename = NULL; LPTSTR pBaseNoteName = NULL; DWORD pageCount = pFax16Hdr->NumberOfPages; BOOL renderCP; COVDOCINFO covDocInfo;
//
// Check if cover page is requested - either a server cover page filename
// is specified or the cover page data is embedded in the file.
//
renderCP = (pFax16Hdr->CoverPageFilename || (pFax16Hdr->CoverPageDataSize && pFax16Hdr->CoverPageData));
ZeroMemory(&covDocInfo, sizeof(covDocInfo));
if (renderCP) {
if (pCPFilename = GetClientCoverPageFile(pFax16Hdr)) {
//
// Find out if the specified cover page contains note/subject fields
//
DWORD ec = PrintCoverPage( NULL, NULL, pCPFilename, &covDocInfo ); if (ec) { Error(( "Cannot examine cover page: %d\n", ec )); }
result = TRUE; pageCount++; }
} else result = TRUE;
//
// Calculate the total number of pages including cover page(s)
//
if (((pCPFields->Note && !IsEmptyString(pCPFields->Note) && !(covDocInfo.Flags & COVFP_NOTE)) ||
(pCPFields->Subject && !IsEmptyString(pCPFields->Subject) && !(covDocInfo.Flags & COVFP_SUBJECT))) &&
(pBaseNoteName = GetBaseNoteFilename())) { renderCP = TRUE; pageCount++; }
wsprintf(pCPFields->NumberOfPages, TEXT("%d"), pageCount);
//
// Render the fax cover page(s)
//
if (result && renderCP) {
DOCINFO docinfo; HDC hdc = NULL; DEVMODE devmode, *pDevmode;
ZeroMemory(&docinfo, sizeof(docinfo)); docinfo.cbSize = sizeof(docinfo); docinfo.lpszDocName = TEXT("faxmon"); docinfo.lpszOutput = pFaxPort->pFilename; renderCP = FALSE;
if (covDocInfo.PaperSize > 0) {
ZeroMemory(&devmode, sizeof(devmode)); _tcsncpy(devmode.dmDeviceName, pFaxPort->pPrinterName, CCHDEVICENAME);
devmode.dmSpecVersion = DM_SPECVERSION; devmode.dmSize = sizeof(devmode);
devmode.dmFields = DM_PAPERSIZE|DM_ORIENTATION; devmode.dmPaperSize = covDocInfo.PaperSize; devmode.dmOrientation = covDocInfo.Orientation;
pDevmode = &devmode;
} else pDevmode = NULL;
if ((hdc = CreateDC(NULL, pFaxPort->pPrinterName, NULL, pDevmode)) && (StartDoc(hdc, &docinfo) > 0)) { //
// Render the user specified cover page
//
if (pCPFilename) {
if (StartPage(hdc) > 0) {
renderCP = PrintCoverPage(hdc, pCPFields, pCPFilename, &covDocInfo) == 0 ? TRUE : FALSE; EndPage(hdc); }
} else renderCP = TRUE;
//
// Render the extra cover page for note and subject
//
if (pBaseNoteName && renderCP) {
if (StartPage(hdc) > 0) {
renderCP = PrintCoverPage(hdc, pCPFields, pBaseNoteName, &covDocInfo) == 0 ? TRUE : FALSE; EndPage(hdc);
} else renderCP = FALSE; }
if (renderCP) EndDoc(hdc); else AbortDoc(hdc); }
result = renderCP;
if (hdc) DeleteDC(hdc); }
//
// In the embedded cover page data case, we created a temporary
// cover page file earlier. So delete it here.
//
if (pCPFilename && !pFax16Hdr->CoverPageFilename) DeleteFile(pCPFilename);
MemFree(pCPFilename); MemFree(pBaseNoteName); }
FreeCoverPageFields(pCPFields); MemFree(pBillingCode);
//
// Open the cover page TIFF file if there was no error
//
return result && OpenTempFaxFile(pFaxPort, TRUE); }
BOOL ConcatFax16Data( PFAXPORT pFaxPort, PFAX16_TIFF_HEADER pFax16Hdr, DWORD size )
/*++
Routine Description:
Concatenate the fax data from downlevel client to the end of cover page TIFF file
Arguments:
pFaxPort - Points to a fax port structure pFax16Hdr - Pointer to the fax data from downlevel client size - Size of the fax data from downlevel client
Return Value:
TRUE if successful, FALSE otherwise
--*/
{ DWORD bytesWritten;
return (pFax16Hdr->NumberOfPages == 0) || (WriteFile(pFaxPort->hFile, pFax16Hdr, size, &bytesWritten, NULL) && bytesWritten == size); }
INT ProcessDownlevelFaxJob( PFAXPORT pFaxPort )
/*++
Routine Description:
Process fax jobs sent from win31 and win95 clients
Arguments:
pFaxPort - Points to a fax port structure
Return Value:
error code FAXERR_*
--*/
{ DWORD fileSize; LPVOID pFileView = NULL; HANDLE hFileMap = NULL; INT result = FAXERR_BAD_DATA16; LPTSTR pOrigFilename;
//
// Get the size of fax job file
//
FlushFileBuffers(pFaxPort->hFile);
if ((fileSize = GetFileSize(pFaxPort->hFile, NULL)) == 0xffffffff || (fileSize < sizeof(DWORD) * 2)) { return FAXERR_FATAL; }
//
// Map the fax job data into memory
//
if (hFileMap = CreateFileMapping(pFaxPort->hFile, NULL, PAGE_READONLY, 0, 0, NULL)) pFileView = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, fileSize);
CloseHandle(pFaxPort->hFile); pFaxPort->hFile = INVALID_HANDLE_VALUE;
pOrigFilename = pFaxPort->pFilename; pFaxPort->pFilename = NULL;
__try {
PFAX16_TIFF_HEADER pFax16Hdr = pFileView;
//
// Validate the fax data from the downlevel client
//
if (hFileMap != NULL && pFileView != NULL && ValidTiffFileHeader(pFileView) && pFax16Hdr->Fax16Signature == FAX16_SIGNATURE) { //
// Render the cover page into a temporary TIFF file
// and concatenate the original TIFF data at the end
//
if (ProcessFax16CoverPage(pFaxPort, pFax16Hdr) && ConcatFax16Data(pFaxPort, pFax16Hdr, fileSize)) { result = FAXERR_NONE;
} else {
Error(("Error processing downlevel fax job\n")); result = FAXERR_FATAL; }
} else {
Error(("Bad TIFF file from downlevel fax client\n")); }
} __except(EXCEPTION_EXECUTE_HANDLER) {
Error(("Access violation while reading downlevel fax job\n")); }
//
// Perform necessary cleanup before returning to caller
//
if (pFileView) UnmapViewOfFile(pFileView);
if (hFileMap) CloseHandle(hFileMap);
DeleteFile(pOrigFilename); MemFree(pOrigFilename);
return result; }
|