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