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.
 
 
 
 
 
 

2864 lines
85 KiB

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
faxdoc.cpp
Abstract:
This module contains all code necessary to print an
exchange message as a fax document.
Author:
Wesley Witt (wesw) 13-Aug-1996
Revision History:
20/10/99 -danl-
Connect to appropriate server, get basenote from windir
dd/mm/yy -author-
description
--*/
#include "faxxp.h"
#include "emsabtag.h"
#include "mapiutil.h"
#include "debugex.h"
#include <set>
using namespace std;
#pragma hdrstop
struct CRecipCmp
{
/*
Comparison operator 'less'
Compare two FAX_PERSONAL_PROFILEs by recipient's name and fax number
*/
bool operator()(LPCFAX_PERSONAL_PROFILE lpcRecipient1,
LPCFAX_PERSONAL_PROFILE lpcRecipient2) const
{
bool bRes = false;
int nFaxNumberCpm = 0;
if(!lpcRecipient1 ||
!lpcRecipient2 ||
!lpcRecipient1->lptstrFaxNumber ||
!lpcRecipient2->lptstrFaxNumber)
{
Assert(false);
return bRes;
}
nFaxNumberCpm = _tcscmp(lpcRecipient1->lptstrFaxNumber, lpcRecipient2->lptstrFaxNumber);
if(nFaxNumberCpm < 0)
{
bRes = true;
}
else if(nFaxNumberCpm == 0)
{
//
// The fax numbers are same
// lets compare the names
//
if(lpcRecipient1->lptstrName && lpcRecipient2->lptstrName)
{
bRes = (_tcsicmp(lpcRecipient1->lptstrName, lpcRecipient2->lptstrName) < 0);
}
else
{
bRes = (lpcRecipient1->lptstrName < lpcRecipient2->lptstrName);
}
}
return bRes;
}
};
typedef set<LPCFAX_PERSONAL_PROFILE, CRecipCmp> RECIPIENTS_SET;
// prototypes
LPTSTR ConvertAStringToTString(LPCSTR lpcstrSource);
extern "C"
BOOL MergeTiffFiles(
LPTSTR BaseTiffFile,
LPTSTR NewTiffFile
);
extern "C"
BOOL PrintRandomDocument(
LPCTSTR FaxPrinterName,
LPCTSTR DocName,
LPTSTR OutputFile
);
PVOID
CXPLogon::MyGetPrinter(
LPTSTR PrinterName,
DWORD Level
)
/*++
Routine Description:
Gets the printer data for a specific printer
Arguments:
PrinterName - Name of the desired printer
Return Value:
Pointer to a printer info structure or NULL for failure.
--*/
{
DBG_ENTER(TEXT("CXPLogon::MyGetPrinter"));
PVOID PrinterInfo = NULL;
HANDLE hPrinter = NULL;
DWORD Bytes;
PRINTER_DEFAULTS PrinterDefaults;
PrinterDefaults.pDatatype = NULL;
PrinterDefaults.pDevMode = NULL;
PrinterDefaults.DesiredAccess = PRINTER_ACCESS_USE;
if (!OpenPrinter( PrinterName, &hPrinter, &PrinterDefaults ))
{
CALL_FAIL (GENERAL_ERR, TEXT("OpenPrinter"),::GetLastError());
goto exit;
}
if ((!GetPrinter( hPrinter, Level, NULL, 0, &Bytes )) && (::GetLastError() != ERROR_INSUFFICIENT_BUFFER))
{
// we just want to know how much memory we need, so we pass NULL and 0,
// this way, the function will fail, but will return us the number of
// bytes required in Bytes
CALL_FAIL (GENERAL_ERR, TEXT("GetPrinter"), ::GetLastError());
goto exit;
}
PrinterInfo = (LPPRINTER_INFO_2) MemAlloc( Bytes );
if (!PrinterInfo)
{
goto exit;
}
if (!GetPrinter( hPrinter, Level, (LPBYTE) PrinterInfo, Bytes, &Bytes ))
{
MemFree(PrinterInfo);
PrinterInfo = NULL;
goto exit;
}
exit:
if(hPrinter)
{
ClosePrinter( hPrinter );
}
return PrinterInfo;
}
static BOOL
GetFaxTempFileName(
OUT LPTSTR lpstrTempName,
IN DWORD dwOutStrSize
)
/*++
Routine Description:
Generates a temporal file with prefix 'fax' in directory
designated for temporal files.
Arguments:
[OUT] lpstrTempName - Output paramter. Pointer to the temporal file name.
The buffer should be MAX_PATH characters.
[IN] dwOutStrSize - Size of buffer lpstrTempName in TCHARs
Return Value:
TRUE if success, FALSE otherwise
--*/
{
BOOL bRes = TRUE;
DBG_ENTER(TEXT("GetFaxTempFileName"),bRes);
TCHAR strTempPath[MAX_PATH] = {0};
TCHAR strTempFile[MAX_PATH] = {0};
DWORD ec = ERROR_SUCCESS; // LastError for this function.
Assert(lpstrTempName);
if (!GetTempPath( sizeof(strTempPath)/sizeof(TCHAR), strTempPath ))
{
ec=::GetLastError();
goto Exit;
}
if (GetTempFileName( strTempPath, _T("fax"), 0, strTempFile ) == 0)
{
ec=::GetLastError();
goto Exit;
}
//
//Copy the source string and leave space for the NULL char
//
_tcsncpy(lpstrTempName, strTempFile, dwOutStrSize-1);
Exit:
if (ERROR_SUCCESS != ec)
{
SetLastError(ec);
bRes = FALSE;
}
return bRes;
}
BOOL
CXPLogon::PrintRichText(
HWND hWndRichEdit,
HDC hDC
)
/*++
Routine Description:
Prints the rich text contained in a rich text
window into a DC.
Arguments:
hWndRichEdit - Window handle for the rich text window
hDC - Printer device context
Return Value:
None.
--*/
{
BOOL bRet = FALSE;
DBG_ENTER(TEXT("CXPLogon::PrintRichText"), bRet);
FORMATRANGE fr;
LONG lTextOut;
LONG lTextCurr;
RECT rcTmp;
fr.hdc = hDC;
fr.hdcTarget = hDC;
fr.chrg.cpMin = 0;
fr.chrg.cpMax = -1;
//
// Set page rect to phys page size in twips
//
fr.rcPage.top = 0;
fr.rcPage.left = 0;
fr.rcPage.right = MulDiv(GetDeviceCaps(hDC, PHYSICALWIDTH),
1440,
GetDeviceCaps(hDC, LOGPIXELSX));
fr.rcPage.bottom = MulDiv(GetDeviceCaps(hDC, PHYSICALHEIGHT),
1440,
GetDeviceCaps(hDC, LOGPIXELSY));
//
// Set up 3/4" horizontal and 1" vertical margins, but leave a minimum of 1"
// printable space in each direction. Otherwise, use full page.
//
fr.rc = fr.rcPage; // start with full page
if (fr.rcPage.right > 2*3*1440/4 + 1440)
{
fr.rc.right -= (fr.rc.left = 3*1440/4);
}
if (fr.rcPage.bottom > 3*1440)
{
fr.rc.bottom -= (fr.rc.top = 1440);
}
//
// save the formatting rectangle
//
rcTmp = fr.rc;
if (!SetMapMode( hDC, MM_TEXT ))
{
CALL_FAIL (GENERAL_ERR, TEXT("SetMapMode"), ::GetLastError());
goto error;
}
lTextOut = 0;
lTextCurr = 0;
while (TRUE)
{
//
// Just measure the text
//
lTextOut = (LONG)SendMessage( hWndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM) &fr );
if(lTextOut <= lTextCurr)
{
//
// The end of the text
//
break;
}
lTextCurr = lTextOut;
if (StartPage( hDC ) <= 0)
{
CALL_FAIL (GENERAL_ERR, TEXT("StartPage"), ::GetLastError());
goto error;
}
//
// Render the page
//
lTextOut = (LONG)SendMessage( hWndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr );
if (EndPage( hDC ) <= 0)
{
CALL_FAIL (GENERAL_ERR, TEXT("EndPage"), ::GetLastError());
goto error;
}
fr.chrg.cpMin = lTextOut;
fr.chrg.cpMax = -1;
//
// EM_FORMATRANGE tends to modify fr.rc.bottom, reset here
//
fr.rc = rcTmp;
}
bRet = TRUE;
error:
//
// flush the cache
//
SendMessage( hWndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL );
return bRet;
}
DWORD
CXPLogon::PrintPlainText(
HDC hDC,
LPSTREAM lpstmT,
LPTSTR tszSubject,
PFAXXP_CONFIG FaxConfig
)
/*++
Routine Description:
Prints a stream of plain text into the printer DC provided.
Note: this code was stolen from notepad.
Arguments:
hDC - Printer DC
lpstmT - Stream pointer for rich text.
tszSubject - Subject
FaxConfig - Fax configuration data
Return Value:
ERROR_SUCCESS - if success
Error IDS_... code if failed.
--*/
{
DWORD rVal = ERROR_SUCCESS;
LPTSTR BodyText = NULL;
LPTSTR lpLine;
LPTSTR pLineEOL;
LPTSTR pNextLine;
HRESULT hResult;
HFONT hFont = NULL;
HFONT hPrevFont = NULL;
TEXTMETRIC tm;
INT nLinesPerPage;
INT dyTop; // width of top border (pixels)
INT dyBottom; // width of bottom border
INT dxLeft; // width of left border
INT dxRight; // width of right border
INT yPrintChar; // height of a character
INT tabSize; // Size of a tab for print device in device units
INT yCurpos = 0;
INT xCurpos = 0;
INT nPixelsLeft = 0;
INT guess = 0;
SIZE Size; // to see if text will fit in space left
INT nPrintedLines = 0;
BOOL fPageStarted = FALSE;
INT iPageNum = 0;
INT xPrintRes; // printer resolution in x direction
INT yPrintRes; // printer resolution in y direction
INT yPixInch; // pixels/inch
INT xPixInch; // pixels/inch
INT xPixUnit; // pixels/local measurement unit
INT yPixUnit; // pixels/local measurement unit
BOOL fEnglish;
DWORD Chars=0;
DWORD dwBodyLen=0;
DWORD dwSubjectLen=0;
STATSTG Stats;
INT PrevBkMode = 0;
DBG_ENTER(TEXT("CXPLogon::PrintPlainText"),rVal);
Assert(hDC);
Assert(FaxConfig);
if(lpstmT)
{
hResult = lpstmT->Stat( &Stats, 0 );
if (FAILED(hResult))
{
rVal = IDS_CANT_ACCESS_MSG_DATA;
goto exit;
}
dwBodyLen = (INT) Stats.cbSize.QuadPart;
}
if(tszSubject)
{
dwSubjectLen = _tcslen(tszSubject);
}
BodyText = (LPTSTR) MemAlloc(dwSubjectLen * sizeof(TCHAR) + dwBodyLen + 4 );
if (!BodyText)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
if(tszSubject)
{
_tcscpy(BodyText, tszSubject);
lpLine = _tcsninc(BodyText, dwSubjectLen);
}
else
{
lpLine = BodyText;
}
if(lpstmT)
{
hResult = lpstmT->Read( (LPVOID)lpLine, dwBodyLen, (LPDWORD) &dwBodyLen );
if (FAILED(hResult))
{
rVal = IDS_CANT_ACCESS_MSG_DATA;
goto exit;
}
}
lpLine = BodyText;
Chars = _tcslen(lpLine);
//
// check if the body is not empty
// if the message length is shorter then 32(arbitrary number)
// and all the carachters are control or space.
//
if(Chars < 32)
{
BOOL bEmpty = TRUE;
TCHAR* pTchar = lpLine;
for(DWORD dw = 0; dw < Chars; ++dw)
{
if(!_istspace(*pTchar) && !_istcntrl(*pTchar))
{
bEmpty = FALSE;
break;
}
pTchar = _tcsinc(pTchar);
}
if(bEmpty)
{
rVal = IDS_NO_MSG_BODY;
goto exit;
}
}
fEnglish = GetProfileInt( _T("intl"), _T("iMeasure"), 1 );
xPrintRes = GetDeviceCaps( hDC, HORZRES );
yPrintRes = GetDeviceCaps( hDC, VERTRES );
xPixInch = GetDeviceCaps( hDC, LOGPIXELSX );
yPixInch = GetDeviceCaps( hDC, LOGPIXELSY );
//
// compute x and y pixels per local measurement unit
//
if (fEnglish)
{
xPixUnit= xPixInch;
yPixUnit= yPixInch;
}
else
{
xPixUnit= CMToInches( xPixInch );
yPixUnit= CMToInches( yPixInch );
}
SetMapMode( hDC, MM_TEXT );
//
// match font size to the device point size
//
FaxConfig->FontStruct.lfHeight = -MulDiv(FaxConfig->FontStruct.lfHeight, yPixInch, 72);
hFont = CreateFontIndirect( &FaxConfig->FontStruct );
hPrevFont = (HFONT) SelectObject( hDC, hFont );
SetBkMode( hDC, TRANSPARENT );
if (!GetTextMetrics( hDC, &tm ))
{
rVal = IDS_CANT_PRINT_BODY;
goto exit;
}
yPrintChar = tm.tmHeight + tm.tmExternalLeading;
tabSize = tm.tmAveCharWidth * 8;
//
// compute margins in pixels
//
dxLeft = LEFT_MARGIN * xPixUnit;
dxRight = RIGHT_MARGIN * xPixUnit;
dyTop = TOP_MARGIN * yPixUnit;
dyBottom = BOTTOM_MARGIN * yPixUnit;
//
// Number of lines on a page with margins
//
nLinesPerPage = ((yPrintRes - dyTop - dyBottom) / yPrintChar);
while (*lpLine)
{
if ( _tcsncmp(lpLine,TEXT("\r"),1) == 0 )
{
lpLine = _tcsninc(lpLine,2);
yCurpos += yPrintChar;
nPrintedLines++;
xCurpos= 0;
continue;
}
pLineEOL = lpLine;
pLineEOL = _tcschr(pLineEOL,TEXT('\r'));
do
{
if ((nPrintedLines == 0) && (!fPageStarted))
{
StartPage( hDC );
fPageStarted = TRUE;
yCurpos = 0;
xCurpos = 0;
}
if ( _tcsncmp(lpLine,TEXT("\t"),1) == 0 )
{
//
// round up to the next tab stop
// if the current position is on the tabstop, goto next one
//
xCurpos = ((xCurpos + tabSize) / tabSize ) * tabSize;
lpLine = _tcsinc(lpLine);
}
else
{
//
// find end of line or tab
//
pNextLine = lpLine;
while (*pNextLine &&
(pNextLine != pLineEOL) &&
( _tcsncmp(pNextLine,TEXT("\t"),1) ) )
{
pNextLine = _tcsinc(pNextLine);
}
//
// find out how many characters will fit on line
//
Chars = (INT)(pNextLine - lpLine);
nPixelsLeft = xPrintRes - dxRight - dxLeft - xCurpos;
GetTextExtentExPoint( hDC, lpLine, Chars, nPixelsLeft, &guess, NULL, &Size );
if (guess)
{
//
// at least one character fits - print
//
TextOut( hDC, dxLeft+xCurpos, yCurpos+dyTop, lpLine, guess );
xCurpos += Size.cx; // account for printing
lpLine = _tcsninc(lpLine,guess);// printed characters
}
else
{
//
// no characters fit what's left
// no characters will fit in space left
// if none ever will, just print one
// character to keep progressing through
// input file.
//
if (xCurpos == 0)
{
if( lpLine != pNextLine )
{
//
// print something if not null line
// could use exttextout here to clip
//
TextOut( hDC, dxLeft+xCurpos, yCurpos+dyTop, lpLine, 1 );
lpLine = _tcsinc(lpLine);
}
}
else
{
//
// perhaps the next line will get it
//
xCurpos = xPrintRes; // force to next line
}
}
//
// move printhead in y-direction
//
if ((xCurpos >= (xPrintRes - dxRight - dxLeft) ) || (lpLine == pLineEOL))
{
yCurpos += yPrintChar;
nPrintedLines++;
xCurpos = 0;
}
if (nPrintedLines >= nLinesPerPage)
{
EndPage( hDC );
fPageStarted = FALSE;
nPrintedLines = 0;
xCurpos = 0;
yCurpos = 0;
iPageNum++;
}
}
} while (*lpLine && (lpLine != pLineEOL));
if ( _tcsncmp(lpLine,TEXT("\r"),1) == 0 )
{
lpLine = _tcsinc(lpLine);
}
if ( _tcsncmp(lpLine,TEXT("\n"),1) == 0 )
{
lpLine = _tcsinc(lpLine);
}
}
if (fPageStarted)
{
EndPage( hDC );
}
exit:
MemFree( BodyText );
if (hPrevFont)
{
SelectObject( hDC, hPrevFont );
DeleteObject( hFont );
}
if (PrevBkMode)
{
SetBkMode( hDC, PrevBkMode );
}
return rVal;
}
extern "C"
DWORD CALLBACK
EditStreamRead(
DWORD_PTR dwCookie,
OUT LPBYTE pbBuff,
LONG cb,
LONG *pcb
)
/*++
Routine Description:
Wrapper function for the IStream read method.
This function is used to read rich text from
an exchange stream.
Arguments:
dwCookie - This pointer for the IStream object
pbBuff - Pointer to the data buffer
cb - Size of the data buffer
pcb - Returned byte count
Return Value:
Return code from IStream::Read
--*/
{
return ((LPSTREAM)dwCookie)->Read( pbBuff, cb, (ULONG*) pcb );
}
DWORD
CXPLogon::PrintAttachmentToFile(
IN LPMESSAGE pMsgObj,
IN PFAXXP_CONFIG pFaxConfig,
OUT LPTSTR * lpptstrOutAttachments
)
/*++
Routine Description:
Prints all attachments to the output file, by itearating
over the attachment table
Arguments:
pMsgObj - Pointer to message object. Used to get an attachmnet table
pFaxConfig - Pointer to fax configuration
lpptstrOutAttachments - Name of the output tiff file. The string should be empty
Return Value:
0 - if success
Last error code from if failed.
Comments:
If this function succeeded it allocates a memory for *lpptstrOutAttachments
and creates a temporal file *lpptstrOutAttachments.
It's up to user to free both these allocations, by
DeleteFile(*lpptstrOutAttachments);
MemFree(*lpptstrOutAttachments);
--*/
{
DWORD rVal = 0;
DBG_ENTER(TEXT("CXPLogon::PrintAttachmentToFile"),rVal);
LPSPropValue pPropsAttachTable = NULL;
LPSPropValue pPropsAttach = NULL;
LPMAPITABLE AttachmentTable = NULL;
LPSRowSet pAttachmentRows = NULL;
LPATTACH lpAttach = NULL;
LPSTREAM lpstmA = NULL;
LPTSTR AttachFileName = NULL;
TCHAR TempPath[MAX_PATH];
TCHAR TempFile[MAX_PATH];
TCHAR DocFile[MAX_PATH];
HANDLE hFile = INVALID_HANDLE_VALUE;
LPTSTR DocType = NULL;
LPSTR p = NULL;
BOOL DeleteAttachFile = FALSE;
LPTSTR FileName = NULL;
BOOL AllAttachmentsGood = TRUE;
TCHAR strTempTiffFile[MAX_PATH] = {0};
TCHAR strMergedTiffFile[MAX_PATH] = {0};
HRESULT hResult = S_OK;
DWORD i = 0;
ULONG PropCount = 0;
DWORD Bytes;
LPTSTR lptstrTempStr = NULL;
Assert(lpptstrOutAttachments);
Assert(*lpptstrOutAttachments == NULL);
//
// get the attachment table, if it is available
//
hResult = pMsgObj->GetAttachmentTable( 0, &AttachmentTable );
if (HR_SUCCEEDED(hResult))
{
hResult = HrAddColumns(
AttachmentTable,
(LPSPropTagArray) &sptAttachTableProps,
gpfnAllocateBuffer,
gpfnFreeBuffer
);
if (HR_SUCCEEDED(hResult))
{
hResult = HrQueryAllRows(
AttachmentTable,
NULL,
NULL,
NULL,
0,
&pAttachmentRows
);
if (FAILED(hResult))
{
pAttachmentRows = NULL;
}
else
{
if (pAttachmentRows->cRows == 0)
{
FreeProws( pAttachmentRows );
pAttachmentRows = NULL;
}
}
}
}
if (pAttachmentRows)
{
//
// this loop verifies that each document's attachment registration
// supports the printto verb.
//
AllAttachmentsGood = TRUE;
for (i = 0; i < pAttachmentRows->cRows; ++i)
{
pPropsAttachTable = pAttachmentRows->aRow[i].lpProps;
lpAttach = NULL;
pPropsAttach = NULL;
if (pPropsAttachTable[MSG_ATTACH_METHOD].Value.ul == NO_ATTACHMENT)
{
goto next_attachment1;
}
//
// open the attachment
//
hResult = pMsgObj->OpenAttach( pPropsAttachTable[MSG_ATTACH_NUM].Value.ul, NULL, MAPI_BEST_ACCESS, &lpAttach );
if (FAILED(hResult))
{
AllAttachmentsGood = FALSE;
goto next_attachment1;
}
//
// get the attachment properties
//
hResult = lpAttach->GetProps(
(LPSPropTagArray) &sptAttachProps,
0,
&PropCount,
&pPropsAttach
);
if (FAILED(hResult))
{
AllAttachmentsGood = FALSE;
goto next_attachment1;
}
//
// try to get the extension if the file.
// this indicates what type of dicument it is.
// if we cannot get the document type then it is
// impossible to print the document.
//
if (DocType)
{
MemFree( DocType );
DocType = NULL;
}
if (PROP_TYPE(pPropsAttach[MSG_ATTACH_EXTENSION].ulPropTag) == PT_ERROR)
{
if (PROP_TYPE(pPropsAttach[MSG_ATTACH_LFILENAME].ulPropTag) != PT_ERROR)
{
p = strrchr( pPropsAttach[MSG_ATTACH_LFILENAME].Value.lpszA, '.' );
if (p)
{
DocType = ConvertAStringToTString( p );
if(!DocType)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
}
else if (PROP_TYPE(pPropsAttach[MSG_ATTACH_FILENAME].ulPropTag) != PT_ERROR)
{
p = strrchr( pPropsAttach[MSG_ATTACH_FILENAME].Value.lpszA, '.' );
if (p)
{
DocType = ConvertAStringToTString( p );
if(!DocType)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
}
}
else
{
DocType = ConvertAStringToTString( pPropsAttach[MSG_ATTACH_EXTENSION].Value.lpszA );
if(!DocType)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
if (!DocType)
{
AllAttachmentsGood = FALSE;
goto next_attachment1;
}
Bytes = sizeof(TempFile);
rVal = RegQueryValue( HKEY_CLASSES_ROOT, DocType, TempFile, (PLONG) &Bytes );
if ((rVal != ERROR_SUCCESS) && (rVal != ERROR_INVALID_DATA))
{
VERBOSE (DBG_MSG, TEXT("File Type: %s: isn't associated to any application"), DocType);
AllAttachmentsGood = FALSE;
goto next_attachment1;
}
wsprintf( TempPath, _T("%s\\shell\\printto\\command"), TempFile );
Bytes = sizeof(TempFile);
rVal = RegQueryValue( HKEY_CLASSES_ROOT, TempPath, TempFile, (PLONG) &Bytes );
if ((rVal != ERROR_SUCCESS) && (rVal != ERROR_INVALID_DATA))
{
VERBOSE (DBG_MSG, TEXT("File extension \"*%s\" doesn't have the PrintTo verb"), DocType);
AllAttachmentsGood = FALSE;
goto next_attachment1;
}
next_attachment1:
if (lpAttach)
{
lpAttach->Release();
}
if (pPropsAttach)
{
MAPIFreeBuffer( pPropsAttach );
pPropsAttach = NULL;
}
}
if (!AllAttachmentsGood)
{
rVal = IDS_BAD_ATTACHMENTS;
goto exit;
}
for (i = 0; i < pAttachmentRows->cRows; ++i)
{
pPropsAttachTable = pAttachmentRows->aRow[i].lpProps;
lpAttach = NULL;
pPropsAttach = NULL;
if (pPropsAttachTable[MSG_ATTACH_METHOD].Value.ul == NO_ATTACHMENT)
{
goto next_attachment2;
}
//
// open the attachment
//
hResult = pMsgObj->OpenAttach( pPropsAttachTable[MSG_ATTACH_NUM].Value.ul, NULL, MAPI_BEST_ACCESS, &lpAttach );
if (FAILED(hResult))
{
goto next_attachment2;
}
//
// get the attachment properties
//
hResult = lpAttach->GetProps(
(LPSPropTagArray) &sptAttachProps,
0,
&PropCount,
&pPropsAttach
);
if (FAILED(hResult))
{
goto next_attachment2;
}
//
// try to get the extension if the file.
// this indicates what type of dicument it is.
// if we cannot get the document type then it is
// impossible to print the document.
//
if (DocType)
{
MemFree( DocType );
DocType = NULL;
}
if (PROP_TYPE(pPropsAttach[MSG_ATTACH_EXTENSION].ulPropTag) == PT_ERROR)
{
if (PROP_TYPE(pPropsAttach[MSG_ATTACH_LFILENAME].ulPropTag) != PT_ERROR)
{
p = strrchr( pPropsAttach[MSG_ATTACH_LFILENAME].Value.lpszA, '.' );
if (p)
{
DocType = ConvertAStringToTString( p );
if(!DocType)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
}
else if (PROP_TYPE(pPropsAttach[MSG_ATTACH_FILENAME].ulPropTag) != PT_ERROR)
{
p = strrchr( pPropsAttach[MSG_ATTACH_FILENAME].Value.lpszA, '.' );
if (p)
{
DocType = ConvertAStringToTString( p );
if(!DocType)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
}
}
else
{
DocType = ConvertAStringToTString( pPropsAttach[MSG_ATTACH_EXTENSION].Value.lpszA );
if(!DocType)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
if (!DocType)
{
goto next_attachment2;
}
lpstmA = NULL;
AttachFileName = NULL;
DeleteAttachFile = FALSE;
//
// get the attached file name
//
if (FileName)
MemFree(FileName);
if (PROP_TYPE(pPropsAttach[MSG_ATTACH_PATHNAME].ulPropTag) != PT_ERROR)
{
FileName = ConvertAStringToTString(pPropsAttach[MSG_ATTACH_PATHNAME].Value.lpszA);
if(!FileName)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
else
{
FileName = NULL;
}
if (FileName)
{
AttachFileName = StringDup( FileName );
if(!AttachFileName)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
//
// get the stream object
//
switch( pPropsAttach[MSG_ATTACH_METHOD].Value.ul )
{
case ATTACH_BY_VALUE:
hResult = lpAttach->OpenProperty(
PR_ATTACH_DATA_BIN,
&IID_IStream,
0,
0,
(LPUNKNOWN*) &lpstmA
);
if (FAILED(hResult))
{
goto next_attachment2;
}
break;
case ATTACH_EMBEDDED_MSG:
case ATTACH_OLE:
hResult = lpAttach->OpenProperty(
PR_ATTACH_DATA_OBJ,
&IID_IStreamDocfile,
0,
0,
(LPUNKNOWN*) &lpstmA
);
if (FAILED(hResult))
{
hResult = lpAttach->OpenProperty(
PR_ATTACH_DATA_BIN,
&IID_IStreamDocfile,
0,
0,
(LPUNKNOWN*) &lpstmA
);
if (FAILED(hResult))
{
hResult = lpAttach->OpenProperty(
PR_ATTACH_DATA_OBJ,
&IID_IStorage,
0,
0,
(LPUNKNOWN*) &lpstmA
);
if (FAILED(hResult))
{
goto next_attachment2;
}
}
}
break;
}
if (lpstmA)
{
DWORD dwSize = GetTempPath( sizeof(TempPath)/sizeof(TCHAR) , TempPath );
Assert( dwSize != 0);
GetTempFileName( TempPath, _T("Fax"), 0, TempFile );
hFile = CreateFile(
TempFile,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
0,
NULL
);
if (hFile != INVALID_HANDLE_VALUE)
{
#define BLOCK_SIZE (64*1024)
LPBYTE StrmData;
DWORD BytesWrite;
StrmData = (LPBYTE) MemAlloc( BLOCK_SIZE );
if(!StrmData)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
do
{
hResult = lpstmA->Read( StrmData, BLOCK_SIZE, &Bytes );
if (FAILED(hResult))
{
break;
}
WriteFile( hFile, StrmData, Bytes, &BytesWrite, NULL );
} while (Bytes == BLOCK_SIZE);
CloseHandle( hFile );
if(StrmData)
{
MemFree( StrmData );
StrmData = NULL;
}
if (AttachFileName)
{
MemFree( AttachFileName );
AttachFileName = NULL;
}
_tcscpy( DocFile, TempFile );
lptstrTempStr = _tcsrchr( DocFile, '.' );
if (lptstrTempStr)
{
_tcscpy( lptstrTempStr, DocType );
MoveFile( TempFile, DocFile );
AttachFileName = StringDup( DocFile );
if(!AttachFileName)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
else
{
AttachFileName = StringDup( TempFile );
if(!AttachFileName)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
}
DeleteAttachFile = TRUE;
}
lpstmA->Release();
}
if (AttachFileName)
{
if (!GetFaxTempFileName(strTempTiffFile, ARR_SIZE(strTempTiffFile)))
{
rVal = IDS_BAD_ATTACHMENTS;//GetLastError();
goto exit;
}
//
// print the attachment
//
if (!PrintRandomDocument( pFaxConfig->PrinterName,
AttachFileName,
strTempTiffFile))
{
CALL_FAIL (GENERAL_ERR, TEXT("PrintRandomDocument"), ::GetLastError());
rVal = IDS_BAD_ATTACHMENTS;//GetLastError();
if (!DeleteFile( strTempTiffFile ))
{
CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
}
goto exit;
}
if (strMergedTiffFile[0] != 0)
{
//
// merge the attachments
//
if (!MergeTiffFiles( strMergedTiffFile,
strTempTiffFile))
{
CALL_FAIL (GENERAL_ERR, TEXT("MergeTiffFiles"), ::GetLastError());
rVal = IDS_BAD_ATTACHMENTS;//GetLastError();
if (!DeleteFile( strTempTiffFile ))
{
CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
}
goto exit;
}
if (!DeleteFile( strTempTiffFile ))
{
CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
}
}
else
{ // copies a first attachment
_tcscpy(strMergedTiffFile,strTempTiffFile);
}
if (DeleteAttachFile)
{
if (!DeleteFile( AttachFileName ))
{
CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
}
}
if(AttachFileName)
{
MemFree( AttachFileName );
AttachFileName = NULL;
}
}
next_attachment2:
if (lpAttach)
{
lpAttach->Release();
}
if (pPropsAttach)
{
MAPIFreeBuffer( pPropsAttach );
pPropsAttach = NULL;
}
}
}
else
{
//
// no attachments
//
rVal = IDS_NO_MSG_ATTACHMENTS;
}
if (strMergedTiffFile[0] != 0)
{
if (!(*lpptstrOutAttachments = StringDup(strMergedTiffFile)))
{
rVal = IDS_OUT_OF_MEM;
}
}
exit:
if (FileName)
{
MemFree( FileName );
}
if (DocType)
{
MemFree( DocType );
}
if (pAttachmentRows)
{
FreeProws( pAttachmentRows );
}
if (AttachmentTable)
{
AttachmentTable->Release();
}
if (AttachFileName)
{
MemFree( AttachFileName );
}
return rVal;
}
DWORD
CXPLogon::PrintMessageToFile(
IN LPSTREAM lpstmT,
IN BOOL UseRichText,
IN PFAXXP_CONFIG pFaxConfig,
IN LPTSTR tszSubject,
OUT LPTSTR* lpptstrOutDocument
)
/*++
Routine Description:
Prints the message body to the output file.
Arguments:
lpstmT - Pointer to the message body stream
UseRichText - boolean value. TRUE if the message is in Rich format,
FALSE - if this is a plain text
pFaxConfig - Pointer to fax configuration (used by plain text printing)
tszSubject - Subject
lpptstrOutDocument - Name of the output tiff file. The string should be empty
Return Value:
ERROR_SUCCESS - if success
Error IDS_... code if failed.
Comments:
If this function succeeded it allocates a memory for *lpptstrOutDocument
and creates a temporal file *lpptstrOutDocument.
It's up to user to free both these allocations, by
DeleteFile(*lpptstrOutDocument);
MemFree(*lpptstrOutDocument);
--*/
{
DWORD rVal = ERROR_SUCCESS;
LARGE_INTEGER BigZero = {0};
LPSTREAM lpstm = NULL;
HRESULT hResult;
HWND hWndRichEdit = NULL;
HDC hDC = NULL;
EDITSTREAM es = {0};
TCHAR strOutputTiffFile[MAX_PATH] = {0};
TCHAR DocName[64];
TCHAR tszSubjectFormat[64];
TCHAR* ptszSubjectText = NULL;
DWORD dwSubjectSize = 0;
DOCINFO docInfo =
{
sizeof(DOCINFO),
NULL,
NULL,
NULL,
0,
};
DBG_ENTER(TEXT("CXPLogon::PrintMessageToFile"),rVal);
Assert(pFaxConfig);
Assert(lpptstrOutDocument);
Assert(*lpptstrOutDocument==NULL);
if (!(hDC = CreateDC( NULL,
pFaxConfig->PrinterName,
NULL,
NULL)))
{
CALL_FAIL (GENERAL_ERR, TEXT("CreateDC"), ::GetLastError());
rVal = IDS_CANT_PRINT_BODY;
goto exit;
}
LoadString(g_hResource, IDS_MESSAGE_DOC_NAME, DocName, sizeof(DocName) / sizeof(DocName[0]));
docInfo.lpszDocName = DocName;
if (!GetFaxTempFileName(strOutputTiffFile, ARR_SIZE(strOutputTiffFile)))
{
rVal = IDS_CANT_PRINT_BODY;
goto exit;
}
docInfo.lpszOutput = strOutputTiffFile ;
docInfo.lpszDatatype = _T("RAW");
if (StartDoc(hDC, &docInfo) <= 0)
{
CALL_FAIL (GENERAL_ERR, TEXT("StartDoc"), ::GetLastError());
rVal = IDS_CANT_PRINT_BODY;
goto exit;
}
//
// position the stream to the beginning
//
if(lpstmT)
{
hResult = lpstmT->Seek( BigZero, STREAM_SEEK_SET, NULL );
if (HR_FAILED (hResult))
{
rVal = IDS_CANT_ACCESS_MSG_DATA;
goto exit;
}
}
if(!pFaxConfig->UseCoverPage && tszSubject && _tcslen(tszSubject))
{
//
// get subject string
//
dwSubjectSize = _tcslen(tszSubject) * sizeof(TCHAR) + sizeof(tszSubjectFormat);
ptszSubjectText = (TCHAR*)MemAlloc(dwSubjectSize);
if(!ptszSubjectText)
{
rVal = IDS_OUT_OF_MEM;
goto exit;
}
if(!LoadString(g_hResource, IDS_SUBJECT_FORMAT, tszSubjectFormat, sizeof(tszSubjectFormat) / sizeof(tszSubjectFormat[0])))
{
Assert(FALSE);
CALL_FAIL (GENERAL_ERR, TEXT("LoadString"), ::GetLastError());
_tcscpy(tszSubjectFormat, TEXT("%s"));
}
_stprintf(ptszSubjectText, tszSubjectFormat, tszSubject);
dwSubjectSize = _tcslen(ptszSubjectText);
}
if (UseRichText)
{
if(lpstmT)
{
hResult = WrapCompressedRTFStream( lpstmT, 0, &lpstm );
if (HR_FAILED (hResult))
{
rVal = IDS_CANT_ACCESS_MSG_DATA;
goto exit;
}
}
hWndRichEdit = CreateWindowEx(
0, // extended window style
TEXT("RICHEDIT"), // registered class name
TEXT(""), // window name
ES_MULTILINE, // window style
0, // horizontal position of window
0, // vertical position of window
0, // window width
0, // window height
NULL, // handle to parent or owner window
NULL, // menu handle or child identifier
g_hModule, // handle to application instance
NULL); // window-creation data
if (!hWndRichEdit)
{
CALL_FAIL (GENERAL_ERR, TEXT("CreateWindowEx"), ::GetLastError());
rVal = IDS_CANT_PRINT_BODY;
goto exit;
}
if(ptszSubjectText && _tcslen(ptszSubjectText))
{
//
// add subject to body
//
SendMessage(hWndRichEdit,
WM_SETTEXT,
0,
(LPARAM)ptszSubjectText);
//
// Set the subject's font
//
CHARFORMAT CharFormat = {0};
CharFormat.cbSize = sizeof (CHARFORMAT);
CharFormat.dwMask = CFM_BOLD |
CFM_CHARSET |
CFM_FACE |
CFM_ITALIC |
CFM_SIZE |
CFM_STRIKEOUT |
CFM_UNDERLINE;
CharFormat.dwEffects = ((FW_BOLD <= pFaxConfig->FontStruct.lfWeight) ? CFE_BOLD : 0) |
((pFaxConfig->FontStruct.lfItalic) ? CFE_ITALIC : 0) |
((pFaxConfig->FontStruct.lfStrikeOut) ? CFE_STRIKEOUT : 0) |
((pFaxConfig->FontStruct.lfUnderline) ? CFE_UNDERLINE : 0);
//
// Height is already in point size.
//
CharFormat.yHeight = abs ( pFaxConfig->FontStruct.lfHeight );
//
// Convert point to twip
//
CharFormat.yHeight *= 20;
CharFormat.bCharSet = pFaxConfig->FontStruct.lfCharSet;
CharFormat.bPitchAndFamily = pFaxConfig->FontStruct.lfPitchAndFamily;
lstrcpyn (CharFormat.szFaceName, pFaxConfig->FontStruct.lfFaceName, LF_FACESIZE);
SendMessage(hWndRichEdit,
EM_SETCHARFORMAT,
SCF_ALL, // Apply font formatting to all the control's text
(LPARAM)&CharFormat); // New font settings
//
// Place insertion point at the end of the subject text
// See MSDN under "HOWTO: Place a Caret After Edit-Control Text"
//
SendMessage(hWndRichEdit,
EM_SETSEL,
MAKELONG(0xffff,0xffff),
MAKELONG(0xffff,0xffff));
}
if(lpstm)
{
es.pfnCallback = EditStreamRead;
es.dwCookie = (DWORD_PTR) lpstm;
SendMessage(hWndRichEdit,
EM_STREAMIN,
SF_RTF | SFF_SELECTION | SFF_PLAINRTF,
(LPARAM) &es);
}
//
// Check if the body is not empty.
// If the message length is shorter then 32 (arbitrary number)
// and all the characters are control or space.
//
TCHAR tszText[32] = {0};
DWORD dwTextSize;
if (!GetWindowText(hWndRichEdit, tszText, sizeof(tszText)/sizeof(tszText[0])-1))
{
if (ERROR_INSUFFICIENT_BUFFER == ::GetLastError ())
{
//
// Subject + Body are longer than 31 characters.
// We're assuming they have valid printable text and
// that this is not an empty message.
//
goto DoPrintRichText;
}
//
// This is another type of error
//
rVal = ::GetLastError ();
CALL_FAIL (GENERAL_ERR, TEXT("GetWindowText"), rVal);
goto exit;
}
dwTextSize = _tcslen(tszText);
if(dwTextSize < sizeof(tszText)/sizeof(tszText[0])-2)
{
BOOL bEmpty = TRUE;
TCHAR* pTchar = tszText;
for(DWORD dw = 0; dw < dwTextSize; ++dw)
{
if(!_istspace(*pTchar) && !_istcntrl(*pTchar))
{
bEmpty = FALSE;
break;
}
pTchar = _tcsinc(pTchar);
}
if(bEmpty)
{
rVal = IDS_NO_MSG_BODY;
goto exit;
}
}
DoPrintRichText:
if (!PrintRichText(hWndRichEdit, hDC))
{
rVal = IDS_CANT_PRINT_BODY;
goto exit;
}
}
else
{
rVal = PrintPlainText(hDC, lpstmT, ptszSubjectText, pFaxConfig);
if (rVal)
{
goto exit;
}
}
// closes DC
if (EndDoc(hDC) <=0)
{
Assert(FALSE); // better not to be here
goto exit;
}
if (!DeleteDC(hDC))
{
Assert(FALSE); // better not to be here
goto exit;
}
hDC = NULL;
if (strOutputTiffFile[0] != 0)
{
if (!(*lpptstrOutDocument = StringDup(strOutputTiffFile)))
{
rVal = IDS_OUT_OF_MEM; //ERROR_NOT_ENOUGH_MEMORY;
goto exit;
}
VERBOSE (DBG_MSG, TEXT("Attachment File is %s:"), *lpptstrOutDocument);
}
rVal = ERROR_SUCCESS;
exit:
if (lpstm)
{
lpstm->Release();
}
if (hDC)
{
DeleteDC(hDC);
}
MemFree(ptszSubjectText);
if(ERROR_SUCCESS != rVal && _tcslen(strOutputTiffFile))
{
if (!DeleteFile( strOutputTiffFile ))
{
CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
}
}
return rVal;
}
DWORD
CXPLogon::PrintFaxDocumentToFile(
IN LPMESSAGE pMsgObj,
IN LPSTREAM lpstmT,
IN BOOL UseRichText,
IN PFAXXP_CONFIG pFaxConfig,
IN LPTSTR tszSubject,
OUT LPTSTR* lpptstrMessageFileName
)
/*++
Routine Description:
Runs printing of the message body and attachments to the output file.
Arguments:
pMsgObj - Pointer to the message object
lpstmT - Pointer to the message body stream
UseRichText - boolean value. TRUE if the message is in Rich format,
FALSE - if this is a plain text
pFaxConfig - Pointer to fax configuration (used by plain text printing)
tszSubject - Subject
lpptstrMessageFileName - Name of the output tiff file. The string should be empty
Return Value:
0 - if success
Error code if failed.
Comments:
If this function succeeded it returns an allocated memory for
*lpptstrMessageFileName and a temporal file *lpptstrMessageFileName.
It's up to user to free both these allocations, by
DeleteFile(*lpptstrMessageFileName);
MemFree(*lpptstrMessageFileName);
--*/
{
DWORD rVal = 0;
LPTSTR lptstrAttachmentsTiff = NULL;
BOOL bAttachment = TRUE;
BOOL bBody = TRUE;
DBG_ENTER(TEXT("CXPLogon::PrintFaxDocumentToFile"),rVal);
Assert(lpptstrMessageFileName);
Assert(*lpptstrMessageFileName == NULL);
//
// prints attachments
//
rVal = PrintAttachmentToFile(pMsgObj,
pFaxConfig,
&lptstrAttachmentsTiff);
if(rVal)
{
if(IDS_NO_MSG_ATTACHMENTS == rVal)
{
rVal = 0;
bAttachment = FALSE;
}
else
{
CALL_FAIL (GENERAL_ERR, TEXT("PrintAttachmentToFile"), 0);
goto error;
}
}
//
// prints the body
//
rVal = PrintMessageToFile(lpstmT,
UseRichText,
pFaxConfig,
tszSubject,
lpptstrMessageFileName);
if(rVal)
{
if(IDS_NO_MSG_BODY == rVal)
{
rVal = 0;
bBody = FALSE;
}
else
{
CALL_FAIL (GENERAL_ERR, TEXT("PrintMessageToFile"), 0);
goto error;
}
}
if(!bBody && !bAttachment)
{
rVal = IDS_EMPTY_MESSAGE;
goto error;
}
if (!*lpptstrMessageFileName) // empty body
{
if (lptstrAttachmentsTiff) // the message contains attachments
{
if (!(*lpptstrMessageFileName = StringDup(lptstrAttachmentsTiff)))
{
rVal = IDS_OUT_OF_MEM;
goto error;
}
}
}
else // the message contains body
{
if (lptstrAttachmentsTiff) // the message contains attachments
{
// merges message and attachements
if (!MergeTiffFiles( *lpptstrMessageFileName, lptstrAttachmentsTiff))
{
rVal = IDS_CANT_PRINT_BODY;
goto error;
}
// deletes attachements
if(!DeleteFile(lptstrAttachmentsTiff))
{
VERBOSE (DBG_MSG, TEXT("DeleteFile Failed in xport\\faxdoc.cpp"));
}
MemFree(lptstrAttachmentsTiff);
lptstrAttachmentsTiff = NULL;
}
}
return rVal;
error:
if (lptstrAttachmentsTiff)
{
if(!DeleteFile(lptstrAttachmentsTiff))
{
VERBOSE (DBG_MSG, TEXT("DeleteFile Failed in xport\\faxdoc.cpp"));
}
MemFree(lptstrAttachmentsTiff);
lptstrAttachmentsTiff = NULL;
}
if (*lpptstrMessageFileName)
{
if(!DeleteFile(*lpptstrMessageFileName))
{
VERBOSE (DBG_MSG, TEXT("DeleteFile Failed in xport\\faxdoc.cpp"));
}
MemFree(*lpptstrMessageFileName);
*lpptstrMessageFileName = NULL;
}
return rVal;
}
DWORD
CXPLogon::SendFaxDocument(
LPMESSAGE pMsgObj,
LPSTREAM lpstmT,
BOOL UseRichText,
LPSPropValue pMsgProps,
LPSRowSet pRecipRows,
LPDWORD lpdwRecipientsLimit
)
/*++
Routine Description:
Prints an exchange message and attachments to the fax printer.
Arguments:
pMsgObj - Pointer to message object
lpstmT - Stream pointer for rich text.
UseRichText - boolean value. TRUE if the message is in Rich format,
FALSE - if this is a plain text
pMsgProps - Message properties (those that are defined in sptPropsForHeader)
pRecipRows - Properties of recipients
lpdwRecipientsLimit - recieves the recipietns limit in case of failure. '0' means no limit
Return Value:
Zero for success, otherwise error code.
--*/
{
DWORD dwRetVal = 0;
PPRINTER_INFO_2 PrinterInfo = NULL;
PRINTER_DEFAULTS PrinterDefaults;
HANDLE hPrinter = NULL;
DWORD ec = 0;
HRESULT hResult = S_OK;
EDITSTREAM es = {0};
LPPROFSECT pProfileObj = NULL;
ULONG PropCount = 0;
ULONG PropMsgCount = 0;
LPSPropValue pProps = NULL;
LPSPropValue pPropsMsg = NULL;
FAXXP_CONFIG FaxConfig = {0};
MAPINAMEID NameIds[NUM_FAX_MSG_PROPS];
MAPINAMEID *pNameIds[NUM_FAX_MSG_PROPS] = {
&NameIds[0],
&NameIds[1],
&NameIds[2],
&NameIds[3],
&NameIds[4],
&NameIds[5]};
LPSPropTagArray MsgPropTags = NULL;
HKEY hKey = 0;
DWORD RegSize = 0;
DWORD RegType = 0;
DWORD CountPrinters = 0;
LPTSTR lptstrRecipientName = NULL ;
LPTSTR lptstrRecipientNumber = NULL ;
LPTSTR lptstrRecName = NULL ;
LPTSTR lptstrRecFaxNumber = NULL ;
LPTSTR lptstrSubject = NULL ;
LPTSTR lptszServerName = NULL;
LPTSTR lptstrDocumentFileName = NULL;
HANDLE FaxServer = NULL;
FAX_COVERPAGE_INFO_EX CovInfo = {0};
FAX_PERSONAL_PROFILE SenderProfile = {0};
FAX_JOB_PARAM_EX JobParamsEx = {0};
PFAX_PERSONAL_PROFILE pRecipients = NULL;
DWORDLONG dwlParentJobId = 0;
DWORDLONG* lpdwlRecipientJobIds = NULL;
BOOL bRslt = FALSE;
LPSPropValue pRecipProps = NULL;
DWORD dwRecipient = 0;
TCHAR strCoverpageName[MAX_PATH] = {0};
BOOL bServerBased = TRUE;
DWORD dwRecipientNumber = 0;
DWORD dwRights = 0; //access rights of fax sender
LPADRBOOK lpAdrBook = NULL;
LPTSTR lpstrSenderSMTPAdr = NULL;//sender's SMTP adr, including "SMTP:" prefix
LPTSTR lpstrSMTPPrefix = NULL;
LPTSTR lpstrSenderAdr = NULL;//sender's SMTP adr. without prefix
ULONG cValues = 0;
ULONG ulObjType = NULL;
LPMAILUSER pMailUser = NULL;
LPSPropValue lpPropValue = NULL;
ULONG i, j;
BOOL bGotSenderAdr = FALSE;
LPTSTR lptstrCPFullPath = NULL;
LPTSTR lptstrCPName = NULL;
DWORD dwError = 0;
BOOL bResult = FALSE;
DWORD dwReceiptsOptions = DRT_NONE;
RECIPIENTS_SET setRecip; // Recipients set used to remove the duplications
SizedSPropTagArray(1, sptPropxyAddrProp) = {1, PR_EMS_AB_PROXY_ADDRESSES_A};
DWORD dwRecipientsLimit = 0;
DBG_ENTER(TEXT("CXPLogon::SendFaxDocument"), dwRetVal);
//
// *****************************
// get the fax config properties
// *****************************
//
hResult = m_pSupObj->OpenProfileSection(
&g_FaxGuid,
MAPI_MODIFY,
&pProfileObj
);
if (HR_FAILED (hResult))
{
CALL_FAIL (GENERAL_ERR, TEXT("OpenProfileSection"), hResult);
dwRetVal = IDS_CANT_ACCESS_PROFILE;
goto exit;
}
hResult = pProfileObj->GetProps(
(LPSPropTagArray) &sptFaxProps,
0,
&PropCount,
&pProps
);
if ((FAILED(hResult))||(hResult == ResultFromScode(MAPI_W_ERRORS_RETURNED)) )
{
CALL_FAIL (GENERAL_ERR, TEXT("GetProps"), hResult);
dwRetVal = IDS_INTERNAL_ERROR;
goto exit;
}
FaxConfig.PrinterName = StringDup( (LPTSTR)pProps[PROP_FAX_PRINTER_NAME].Value.bin.lpb );
if(! FaxConfig.PrinterName)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
FaxConfig.CoverPageName = StringDup( (LPTSTR)pProps[PROP_COVERPAGE_NAME].Value.bin.lpb );
if(! FaxConfig.CoverPageName)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
FaxConfig.UseCoverPage = pProps[PROP_USE_COVERPAGE].Value.ul;
FaxConfig.ServerCoverPage = pProps[PROP_SERVER_COVERPAGE].Value.ul;
CopyMemory(
&FaxConfig.FontStruct,
pProps[PROP_FONT].Value.bin.lpb,
pProps[PROP_FONT].Value.bin.cb
);
FaxConfig.SendSingleReceipt= pProps[PROP_SEND_SINGLE_RECEIPT].Value.ul;
FaxConfig.bAttachFax = pProps[PROP_ATTACH_FAX].Value.ul;
//
// *************************************
// now get the message config properties
// *************************************
//
NameIds[MSGPI_FAX_PRINTER_NAME].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
NameIds[MSGPI_FAX_PRINTER_NAME].ulKind = MNID_STRING;
NameIds[MSGPI_FAX_PRINTER_NAME].Kind.lpwstrName = MSGPS_FAX_PRINTER_NAME;
NameIds[MSGPI_FAX_COVERPAGE_NAME].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
NameIds[MSGPI_FAX_COVERPAGE_NAME].ulKind = MNID_STRING;
NameIds[MSGPI_FAX_COVERPAGE_NAME].Kind.lpwstrName = MSGPS_FAX_COVERPAGE_NAME;
NameIds[MSGPI_FAX_USE_COVERPAGE].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
NameIds[MSGPI_FAX_USE_COVERPAGE].ulKind = MNID_STRING;
NameIds[MSGPI_FAX_USE_COVERPAGE].Kind.lpwstrName = MSGPS_FAX_USE_COVERPAGE;
NameIds[MSGPI_FAX_SERVER_COVERPAGE].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
NameIds[MSGPI_FAX_SERVER_COVERPAGE].ulKind = MNID_STRING;
NameIds[MSGPI_FAX_SERVER_COVERPAGE].Kind.lpwstrName = MSGPS_FAX_SERVER_COVERPAGE;
NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].ulKind = MNID_STRING;
NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].Kind.lpwstrName = MSGPS_FAX_SEND_SINGLE_RECEIPT;
NameIds[MSGPI_FAX_ATTACH_FAX].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
NameIds[MSGPI_FAX_ATTACH_FAX].ulKind = MNID_STRING;
NameIds[MSGPI_FAX_ATTACH_FAX].Kind.lpwstrName = MSGPS_FAX_ATTACH_FAX;
hResult = pMsgObj->GetIDsFromNames( (ULONG) NUM_FAX_MSG_PROPS, pNameIds, MAPI_CREATE, &MsgPropTags );
if (HR_FAILED(hResult))
{
if(hResult == MAPI_E_NOT_ENOUGH_MEMORY)
{
dwRetVal = IDS_OUT_OF_MEM;
}
else
{
dwRetVal = IDS_INTERNAL_ERROR;
}
CALL_FAIL (GENERAL_ERR, TEXT("GetIDsFromNames"), hResult);
goto exit;
}
MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME] = PROP_TAG( PT_BINARY, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME]));
MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME] = PROP_TAG( PT_BINARY, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME]));
MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE]));
MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE]));
MsgPropTags->aulPropTag[MSGPI_FAX_SEND_SINGLE_RECEIPT] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_SEND_SINGLE_RECEIPT]));
MsgPropTags->aulPropTag[MSGPI_FAX_ATTACH_FAX] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_ATTACH_FAX]));
hResult = pMsgObj->GetProps( MsgPropTags, 0, &PropMsgCount, &pPropsMsg );
if(hResult == ResultFromScode(MAPI_W_ERRORS_RETURNED))
{
VERBOSE (DBG_MSG, TEXT("GetProps in SendFaxDocument returned MAPI_W_ERRORS_RETURNED"));
}
if (FAILED(hResult))
//
// happens if user did not press ok on the "fax attributes" DlgBox - it's not an error!
//
{
CALL_FAIL (GENERAL_ERR, TEXT("GetProps"), hResult);
hResult = S_OK;
}
//
//prefer the config props defined for the message (if they exist) on those defined for the fax.
//
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_PRINTER_NAME].ulPropTag) != PT_ERROR)
{
MemFree( FaxConfig.PrinterName );
FaxConfig.PrinterName = StringDup((LPTSTR)pPropsMsg[MSGPI_FAX_PRINTER_NAME].Value.bin.lpb);
if(! FaxConfig.PrinterName)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
}
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_COVERPAGE_NAME].ulPropTag) != PT_ERROR)
{
MemFree( FaxConfig.CoverPageName);
FaxConfig.CoverPageName = StringDup((LPTSTR)pPropsMsg[MSGPI_FAX_COVERPAGE_NAME].Value.bin.lpb);
if(! FaxConfig.CoverPageName)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
}
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_USE_COVERPAGE].ulPropTag) != PT_ERROR)
{
FaxConfig.UseCoverPage = pPropsMsg[MSGPI_FAX_USE_COVERPAGE].Value.ul;
}
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_SERVER_COVERPAGE].ulPropTag) != PT_ERROR)
{
FaxConfig.ServerCoverPage = pPropsMsg[MSGPI_FAX_SERVER_COVERPAGE].Value.ul;
}
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_SEND_SINGLE_RECEIPT].ulPropTag) != PT_ERROR)
{
FaxConfig.SendSingleReceipt = pPropsMsg[MSGPI_FAX_SEND_SINGLE_RECEIPT].Value.ul;
}
if (PROP_TYPE(pPropsMsg[MSGPI_FAX_ATTACH_FAX].ulPropTag) != PT_ERROR)
{
FaxConfig.bAttachFax = pPropsMsg[MSGPI_FAX_ATTACH_FAX].Value.ul;
}
if (PROP_TYPE(pMsgProps[MSG_SUBJECT].ulPropTag) != PT_ERROR)
{
lptstrSubject = ConvertAStringToTString(pMsgProps[MSG_SUBJECT].Value.lpszA);
if(! lptstrSubject)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
}
//
// ******************************************
// open the printer, and create the tiff file
// ******************************************
//
//
// open the printer - first try to get info on the printer in FaxConfig,
// if you fail, search all the printers until the first fax printer is found.
//
PrinterInfo = (PPRINTER_INFO_2) MyGetPrinter( FaxConfig.PrinterName, 2 );
if (NULL == PrinterInfo)
{
// if the chosen printer is not accessable, try to locate another SharedFax printer
PrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters( NULL, 2, &CountPrinters );
if (NULL != PrinterInfo)
{
for (i=0; i<(int)CountPrinters; i++)
{
if (_tcscmp( PrinterInfo[i].pDriverName, FAX_DRIVER_NAME ) == 0)
{
break;
}
}
}
else
{
CountPrinters = i = 0; //no printers were found
}
if (i == (int)CountPrinters) //if there are no printers, or none of them is a fax printer
{
dwRetVal = IDS_NO_FAX_PRINTER;
goto exit;
}
//
// if a SharedFax printer was found, update it as the printer that we'll send the fax threw
//
MemFree( FaxConfig.PrinterName );
FaxConfig.PrinterName = StringDup( PrinterInfo[i].pPrinterName );
if(! FaxConfig.PrinterName)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
MemFree( PrinterInfo );
PrinterInfo = (PPRINTER_INFO_2) MyGetPrinter( FaxConfig.PrinterName, 2 );
if (NULL == PrinterInfo)
{
dwRetVal = IDS_CANT_ACCESS_PRINTER;
goto exit;
}
}
PrinterDefaults.pDatatype = NULL;
PrinterDefaults.pDevMode = NULL;
PrinterDefaults.DesiredAccess = PRINTER_ACCESS_USE;
if (!OpenPrinter( FaxConfig.PrinterName, &hPrinter, &PrinterDefaults ))
{
dwRetVal = IDS_CANT_ACCESS_PRINTER;
goto exit;
}
dwRetVal = PrintFaxDocumentToFile( pMsgObj,
lpstmT,
UseRichText,
&FaxConfig ,
lptstrSubject,
&lptstrDocumentFileName);
if (IDS_EMPTY_MESSAGE == dwRetVal)
{
//
// The message is empty. This is not really an error.
//
dwRetVal = 0;
if(!FaxConfig.UseCoverPage)
{
//
// If the message is empty and no cover page is specified there is
// nothing more to do.
//
goto exit;
}
}
if(dwRetVal)
{
goto exit;
}
VERBOSE (DBG_MSG, TEXT("Final Tiff is %s:"), lptstrDocumentFileName);
//
// **************************************
// initializes sender and recipients info
// **************************************
//
//
// sender's info
//
SenderProfile.dwSizeOfStruct = sizeof(SenderProfile);
hResult = FaxGetSenderInformation(&SenderProfile);
if(S_OK != hResult)
{
CALL_FAIL (GENERAL_ERR, TEXT("FaxGetSenderInformation"), hResult);
if (HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) == hResult)
{
dwRetVal = IDS_INTERNAL_ERROR;
}
else if (HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY) == hResult )
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
}
//
// recipients' info
// pRecipRows includes rows coresponding only to recipients that their PR_RESPONSIBILITY == FALSE
//
dwRecipientNumber = pRecipRows->cRows;
pRecipients = (PFAX_PERSONAL_PROFILE)MemAlloc(sizeof(FAX_PERSONAL_PROFILE) * dwRecipientNumber);
if(! pRecipients)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
ZeroMemory(pRecipients, sizeof(FAX_PERSONAL_PROFILE) * dwRecipientNumber);
dwRecipient = 0;
for (DWORD dwRecipRow=0; dwRecipRow < pRecipRows->cRows ; ++dwRecipRow)
{
pRecipProps = pRecipRows->aRow[dwRecipRow].lpProps;
lptstrRecipientName = ConvertAStringToTString(pRecipProps[RECIP_NAME].Value.lpszA);
if(! lptstrRecipientName)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
lptstrRecipientNumber = ConvertAStringToTString(pRecipProps[RECIP_EMAIL_ADR].Value.lpszA);
if(! lptstrRecipientNumber)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
if(_tcsstr(lptstrRecipientName, lptstrRecipientNumber))
{
//
// PR_EMAIL_ADDRESS_A is substring of PR_DISPLAY_NAME_A
// so we suppose that PR_DISPLAY_NAME_A was not specified.
// Try to get the recipient name from PR_EMAIL_ADDRESS_A
//
MemFree( lptstrRecipientName );
lptstrRecipientName = NULL;
}
//
// finds a fax number from the name string,
// e.g. "Fax Number@+14 (2) 324324" --> +14 (2) 324324)
//
LPTSTR pRecipientNumber = _tcschr(lptstrRecipientNumber, '@');
if (pRecipientNumber)
{
//
//if there was a @, increment the pointer to point to the next char after it.
//
*pRecipientNumber = '\0';
pRecipientNumber = _tcsinc(pRecipientNumber);
if(!lptstrRecipientName)
{
lptstrRecipientName = StringDup(lptstrRecipientNumber);
if(! lptstrRecipientName)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
}
}
else
{
//
//if there's no @ in the string, it's OK as it was.
//
pRecipientNumber = lptstrRecipientNumber;
}
//
// initializes recipient info
//
pRecipients[dwRecipient].dwSizeOfStruct = sizeof(FAX_PERSONAL_PROFILE);
pRecipients[dwRecipient].lptstrFaxNumber = StringDup(pRecipientNumber);
if(! pRecipients[dwRecipient].lptstrFaxNumber)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
if(lptstrRecipientName)
{
pRecipients[dwRecipient].lptstrName = StringDup(lptstrRecipientName);
if(! pRecipients[dwRecipient].lptstrName)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
}
__try
{
//
// Insert all the recipients into a set.
// If there are any duplications insert() failes
//
if(setRecip.insert(&pRecipients[dwRecipient]).second == true)
{
++dwRecipient;
}
else
{
//
// Such recipients already exists
//
MemFree(pRecipients[dwRecipient].lptstrName);
pRecipients[dwRecipient].lptstrName = NULL;
MemFree(pRecipients[dwRecipient].lptstrFaxNumber);
pRecipients[dwRecipient].lptstrFaxNumber = NULL;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
if(lptstrRecipientName)
{
MemFree( lptstrRecipientName );
lptstrRecipientName = NULL;
}
if(lptstrRecipientNumber)
{
MemFree( lptstrRecipientNumber );
lptstrRecipientNumber = NULL;
}
} // for
//
// Update the recipient number to the actual size without duplications
//
dwRecipientNumber = dwRecipient;
//
// *******************
// get cover page info
// *******************
//
if (FaxConfig.UseCoverPage)
{
bServerBased = FaxConfig.ServerCoverPage;
if(bServerBased)
{
_tcscpy(strCoverpageName,FaxConfig.CoverPageName);
}
else
{
//
// this is a personal CP, we have to add to it's name the full UNC path
//
TCHAR CpDir[MAX_PATH] = {0};
TCHAR* pCpName = NULL;
bResult = GetClientCpDir( CpDir, sizeof(CpDir) / sizeof(CpDir[0]));
if(! bResult)
{
CALL_FAIL(GENERAL_ERR, TEXT("GetClientCpDir"), ::GetLastError());
dwRetVal = IDS_INTERNAL_ERROR;
goto exit;
}
_tcscat(CpDir,FaxConfig.CoverPageName);
if((_tcslen(CpDir)/sizeof(TCHAR) + _tcslen(FAX_COVER_PAGE_FILENAME_EXT)/sizeof(TCHAR) + 1) > MAX_PATH)
{
dwRetVal = IDS_INTERNAL_ERROR;
goto exit;
}
_tcscat(CpDir, FAX_COVER_PAGE_FILENAME_EXT);
_tcscpy(strCoverpageName, CpDir);
}
VERBOSE (DBG_MSG, TEXT("Sending Fax with Coverpage: %s"), strCoverpageName);
//
// initializes a cover page info
//
CovInfo.dwSizeOfStruct = sizeof( FAX_COVERPAGE_INFO_EX);
CovInfo.dwCoverPageFormat = FAX_COVERPAGE_FMT_COV;
CovInfo.lptstrCoverPageFileName = strCoverpageName;
//if it's not a server's CP, should include exact path to the CP file
CovInfo.bServerBased = bServerBased ;
CovInfo.lptstrNote = NULL;
CovInfo.lptstrSubject = lptstrSubject;
}
else
{
//
// no cover page
//
CovInfo.dwSizeOfStruct = sizeof( FAX_COVERPAGE_INFO_EX);
CovInfo.dwCoverPageFormat = FAX_COVERPAGE_FMT_COV_SUBJECT_ONLY;
CovInfo.lptstrSubject = lptstrSubject;
}
//
// *************************
// connect to the fax server
// *************************
//
if (!GetServerNameFromPrinterInfo(PrinterInfo ,&lptszServerName ) ||
!FaxConnectFaxServer(lptszServerName,&FaxServer))
{
CALL_FAIL (GENERAL_ERR, TEXT("FaxConnectFaxServer"), ::GetLastError());
dwRetVal = IDS_CANT_ACCESS_SERVER;
goto exit;
}
VERBOSE (DBG_MSG, TEXT("Connected to Fax Server: %s"), lptszServerName);
//
// *****************************
// initialize the job parameters
// *****************************
//
JobParamsEx.dwSizeOfStruct = sizeof( FAX_JOB_PARAM_EX);
VERBOSE (DBG_MSG, TEXT("******************JobParamsEx:***********************"));
//
// get the sender's SMTP address
// pMsgProps hold PropsForHeader properties, including PR_SENDER_ENTRYID
//
hResult = m_pSupObj->OpenAddressBook(NULL, 0, &lpAdrBook);
if (FAILED(hResult))
{
CALL_FAIL (GENERAL_ERR, TEXT("OpenAddressBook"), ::GetLastError());
}
else
{
hResult = lpAdrBook->OpenEntry(
pMsgProps[MSG_SENDER_ENTRYID].Value.bin.cb,
(LPENTRYID)pMsgProps[MSG_SENDER_ENTRYID].Value.bin.lpb,
NULL,
0,
&ulObjType,
(LPUNKNOWN*)&pMailUser
);
if (FAILED(hResult))
{
CALL_FAIL (GENERAL_ERR, TEXT("OpenEntry"), ::GetLastError());
}
else
{
hResult = pMailUser->GetProps(
(LPSPropTagArray)&sptPropxyAddrProp,
0,
&cValues,
&lpPropValue
);
if (!HR_SUCCEEDED(hResult) ||
PT_ERROR == PROP_TYPE(lpPropValue->ulPropTag))
{
//
// We either failed to get the property or the property retrieved has some error.
// If we're unable to locate sender's address, we won't be sending a Delivry Receipt,
// but we won't fail the sending.
//
CALL_FAIL (GENERAL_ERR, TEXT("GetProps from MailUser failed, no receipt will be sent!"), hResult);
}
else
{
//
//loop through the proxy multivalue property
//
for(j=0;j<lpPropValue->Value.MVszA.cValues; j++)
{
lpstrSenderSMTPAdr = ConvertAStringToTString(lpPropValue->Value.MVszA.lppszA[j]);
if(! lpstrSenderSMTPAdr)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
//
// check if address begins with "SMTP:":
// function returns pointer to begining of second param.'s appearance in first param.
// if it does not appear, returns NULL
//
lpstrSMTPPrefix = _tcsstr(lpstrSenderSMTPAdr, TEXT("SMTP:"));
if( lpstrSenderSMTPAdr == lpstrSMTPPrefix)
{
//
// Remove this prefix from it, and store it in JobParamsEx.
//
lpstrSenderAdr = lpstrSenderSMTPAdr + _tcslen(TEXT("SMTP:"));
JobParamsEx.lptstrReceiptDeliveryAddress = _tcsdup(lpstrSenderAdr);
if(! JobParamsEx.lptstrReceiptDeliveryAddress)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
bGotSenderAdr = TRUE;
VERBOSE(DBG_MSG, TEXT("Receipt delivery address is %s"), JobParamsEx.lptstrReceiptDeliveryAddress);
break;
}
}
}
}
}
//
// when to send, sort of delivery receipt
//
JobParamsEx.dwScheduleAction = JSA_NOW;
if(!FaxGetReceiptsOptions(FaxServer, &dwReceiptsOptions))
{
CALL_FAIL(GENERAL_ERR, TEXT("FaxGetReceiptsOptions"), ::GetLastError());
}
JobParamsEx.dwReceiptDeliveryType = DRT_NONE;
if (bGotSenderAdr && (dwReceiptsOptions & DRT_EMAIL))
{
if (TRUE == FaxConfig.SendSingleReceipt)
{
JobParamsEx.dwReceiptDeliveryType = DRT_EMAIL | DRT_GRP_PARENT;
}
else
{
JobParamsEx.dwReceiptDeliveryType = DRT_EMAIL;
}
if (FaxConfig.bAttachFax)
{
JobParamsEx.dwReceiptDeliveryType |= DRT_ATTACH_FAX;
}
}
VERBOSE(DBG_MSG, TEXT("Receipt Delivery Type = %ld"), JobParamsEx.dwReceiptDeliveryType);
//
// priority
//
if (pMsgProps[MSG_IMPORTANCE].ulPropTag == PR_IMPORTANCE)
{
if(FALSE == (FaxAccessCheckEx(FaxServer, MAXIMUM_ALLOWED, &dwRights)))
{
if((hResult = ::GetLastError()) != ERROR_SUCCESS)
{
CALL_FAIL(GENERAL_ERR, TEXT("FaxAccessCheckEx"), hResult);
dwRetVal = IDS_CANT_ACCESS_PROFILE;
goto exit;
}
}
//
//try to give the sender the prio he asked for. if it's not allowed, try a lower prio.
//
switch(pMsgProps[MSG_IMPORTANCE].Value.l)
{
case (IMPORTANCE_HIGH):
if ((FAX_ACCESS_SUBMIT_HIGH & dwRights) == FAX_ACCESS_SUBMIT_HIGH)
{
JobParamsEx.Priority = FAX_PRIORITY_TYPE_HIGH;
break;
}
//fall through
case (IMPORTANCE_NORMAL):
if ((FAX_ACCESS_SUBMIT_NORMAL & dwRights) == FAX_ACCESS_SUBMIT_NORMAL)
{
JobParamsEx.Priority = FAX_PRIORITY_TYPE_NORMAL;
break;
}
//fall through
case (IMPORTANCE_LOW):
if ((FAX_ACCESS_SUBMIT & dwRights) == FAX_ACCESS_SUBMIT)
{
JobParamsEx.Priority = FAX_PRIORITY_TYPE_LOW;
}
else
{
VERBOSE(ASSERTION_FAILED, TEXT("xport\\faxdoc.cpp\\SendFaxDocument: user has no access rights!"));
//the user has no right to submit faxes, at any priority!
dwRetVal = IDS_NO_SUBMIT_RITHTS;
goto exit;
}
break;
default:
VERBOSE(ASSERTION_FAILED, TEXT("xport\\faxdoc.cpp\\SendFaxDocument: message importance has undefined value"));
ASSERTION_FAILURE
}
}
else
{
VERBOSE(ASSERTION_FAILED, TEXT("xport\\faxdoc.cpp\\SendFaxDocument: Message had no importance property value!"));
dwRetVal = IDS_INTERNAL_ERROR;
ASSERTION_FAILURE;
goto exit;
}
VERBOSE(DBG_MSG, TEXT("Message Priority is %ld (0=low, 1=normal, 2=high)"), JobParamsEx.Priority );
//
// doc name, number of pages,
//
TCHAR DocName[64];
LoadString(g_hResource, IDS_MESSAGE_DOC_NAME, DocName, sizeof(DocName) / sizeof (DocName[0]));
JobParamsEx.lptstrDocumentName = DocName;
JobParamsEx.dwPageCount = 0; //means the server will count the number of pages in the job
lpdwlRecipientJobIds = (DWORDLONG*)MemAlloc(sizeof(DWORDLONG)*dwRecipientNumber);
if(! lpdwlRecipientJobIds)
{
dwRetVal = IDS_OUT_OF_MEM;
goto exit;
}
//
// ************
// Send the fax
// ************
//
bRslt= FaxSendDocumentEx(
FaxServer,
(LPCTSTR) lptstrDocumentFileName,
&CovInfo,
&SenderProfile,
dwRecipientNumber,
pRecipients,
&JobParamsEx,
&dwlParentJobId,
lpdwlRecipientJobIds
);
if (!bRslt)
{
hResult = ::GetLastError();
CALL_FAIL (GENERAL_ERR, TEXT("FaxSendDocumentEx"), hResult);
// maybe we should swich possible retruned values from SendFaxDocEx,
// and choose a more informative IDS
switch(hResult)
{
case ERROR_NOT_ENOUGH_MEMORY:
dwRetVal = IDS_OUT_OF_MEM;
break;
case ERROR_NO_SYSTEM_RESOURCES:
dwRetVal = IDS_INTERNAL_ERROR;
break;
case ERROR_CANT_ACCESS_FILE:
dwRetVal = IDS_PERSONAL_CP_FORBIDDEN;
break;
case ERROR_BAD_FORMAT:
dwRetVal = IDS_BAD_CANNONICAL_ADDRESS;
break;
case FAX_ERR_RECIPIENTS_LIMIT:
dwRetVal = IDS_RECIPIENTS_LIMIT;
if (!FaxGetRecipientsLimit(FaxServer, &dwRecipientsLimit))
{
CALL_FAIL (GENERAL_ERR, TEXT("FaxGetRecipientsLimit"), ::GetLastError());
}
break;
default:
dwRetVal = IDS_CANT_PRINT;
break;
}
goto exit;
}
FaxClose(FaxServer);
FaxServer = NULL;
dwRetVal = 0;
exit:
if(lpAdrBook)
{
lpAdrBook->Release();
}
if(pMailUser)
{
pMailUser->Release();
}
if (FaxServer)
{
FaxClose(FaxServer);
}
if (pRecipients)
{
for (dwRecipient=0; dwRecipient<dwRecipientNumber ; dwRecipient++)
{
if (pRecipients[dwRecipient].lptstrName)
{
MemFree (pRecipients[dwRecipient].lptstrName);
}
if (pRecipients[dwRecipient].lptstrFaxNumber)
{
MemFree(pRecipients[dwRecipient].lptstrFaxNumber);
}
}
MemFree(pRecipients);
pRecipients = NULL;
}
if (pProfileObj)
{
pProfileObj->Release();
}
if (pProps)
{
MAPIFreeBuffer( pProps );
}
if (MsgPropTags)
{
MAPIFreeBuffer( MsgPropTags );
}
if (pPropsMsg)
{
MAPIFreeBuffer( pPropsMsg );
}
if (hPrinter)
{
ClosePrinter( hPrinter );
}
if (PrinterInfo)
{
MemFree( PrinterInfo );
}
if (FaxConfig.PrinterName)
{
MemFree( FaxConfig.PrinterName );
}
if (FaxConfig.CoverPageName)
{
MemFree( FaxConfig.CoverPageName );
}
if (lptstrRecipientName)
{
MemFree(lptstrRecipientName);
}
if (lptstrRecipientNumber)
{
MemFree(lptstrRecipientNumber);
}
if (lptstrRecName)
{
MemFree(lptstrRecName);
}
if (lptstrRecFaxNumber)
{
MemFree(lptstrRecFaxNumber);
}
if (lptstrSubject)
{
MemFree(lptstrSubject);
}
if (lptstrDocumentFileName)
{
DeleteFile(lptstrDocumentFileName);
MemFree(lptstrDocumentFileName);
}
if (lpdwlRecipientJobIds)
{
MemFree(lpdwlRecipientJobIds);
}
if (lptszServerName)
{
MemFree(lptszServerName);
}
FaxFreeSenderInformation(&SenderProfile);
*lpdwRecipientsLimit = dwRecipientsLimit;
return dwRetVal;
}