/****************************************************************************
 *									   										*
 *  MODULE	: WVPRINT.C						   								*
 *									   										*
 *                  Jim Dumoulin  NASA/KSC                                  *
 *                                                                          *
 *                                                                          *
 *  PURPOSE	: Printing code for WinVN.                                 		*
 *																			*
 *  FUNCTIONS:	FreePrinterMemory () -		Frees all memory associated		*
 *											with a printer device context	*
 *																			*
 *				GetPrinterDC ()		-		Creates a printer DC for the	*
 *											default device.		   			*
 *									  										*
 *				DeletePrinterDC ()	-  		Deletes a printer DC for the 	*
 *											default device.		   			*
 *									   										*
 *				AbortProc ()		-  		Export proc. for GDI to check	*
 *											print abort.					*
 *																			*
 *				PrintDlgProc ()		-		Dialog function for the print	*
 *											cancel dialog.					*
 *																			*
 *				ReportPrintError ()	-		Decodes err codes for calls		*
 *											to Windows print functions		*
 *																			*
 *				PrintHeaderP ()		-		Determines if header string		*
 *											is one that gets printed		*
 *																			*
 *				PrintArticle ()		-  		Prints the contents of the		*
 *											an article window.				*
 ****************************************************************************/

/*
 * $Id: wvprint.c 1.37 1997/03/07 02:23:24 dumoulin Exp $
 */

#include <windows.h>
#include <windowsx.h>
#include "wvglob.h"
#include "winvn.h"
#pragma hdrstop

static BOOL near PdlgAbort = FALSE;			/* TRUE if the user has aborted the print job	*/
HWND hwndPDlg = NULL;						/* Handle to the cancel print dialog			*/

          
/****************************************************************************
 *																			*          
 *  FUNCTION   : AbortProc()												*
 *																			*
 *  PURPOSE    : To be called by GDI print code to check for user abort.    *
 *               Returns TRUE to continue Printing, FALSE to cancel.        *
 *																			*
 ****************************************************************************/
BOOL CALLBACK AbortProc (HDC hdc, int nCode)
{
	MSG msg;
	char mes[20]; 

	// I give up getting this to work for this release so we won't have
	// print canceling.  This has been intermittent ever since WinVN
	// grew too big.  Major problems with the fact the CALLBACK functions
	// can't access any global variables in the LARGE model.    (JD 11/29/94)

	//return TRUE;

	if ((nCode < 0) && (nCode != SP_OUTOFDISK)) 
	{
		sprintf (mes, "%d", (int) nCode);
		WVArgMessageBox (NULL, IDS_WVPRINT_ABORT3, IDS_WVPRINT_ABORT4, MB_OK | MB_ICONEXCLAMATION, mes);
		return FALSE;
	}
	else  

		/* Allow other apps to run, or get abort messages */
		while (!PdlgAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
		{
			if (!hwndPDlg || !IsDialogMessage (hwndPDlg, &msg)) 
			{
				TranslateMessage (&msg);
				DispatchMessage (&msg);
			}
		}

	if (PdlgAbort == TRUE)
		return FALSE;
	else
		return TRUE;
}

/****************************************************************************
 *																			*
 *  FUNCTION   : PrinterInit ()												*
 *																			*
 *  PURPOSE    : Initializes Global Variables used by the Printing Code.  	*
 *				 This function gets called once when WinVN starts up but	*
 *				 may be called again if a printer error occurs and a device	*
 *				 context is lost.											*
 *																			*
 *  RETURNS    : TRUE if successful, FALSE if not							*
 *																			*
 ****************************************************************************/
BOOL WINAPI PrinterInit (void)
{
	memset(&pd, 0, sizeof(pd));
	pd.lStructSize = (DWORD) sizeof (PRINTDLG);
	//(pd.hwndOwner omitted)
	//pd.hDevMode = NULL;
	//pd.hDevNames = NULL;
	//pd.hDC = (HDC) NULL;
	pd.Flags = PD_RETURNDC;
	//pd.nFromPage = 0;
	//pd.nToPage = 0;
	//pd.nMinPage = 0;
	//pd.nMaxPage = 0xFFFE;
	pd.nCopies = 1;
	//pd.hInstance = (HANDLE) NULL;
	//pd.lCustData = 0L;
	//pd.lpfnPrintHook = (UINT) NULL;
	//pd.lpfnSetupHook = (UINT) NULL;
	//pd.lpPrintTemplateName = (LPSTR) NULL;
	//pd.lpSetupTemplateName = (LPSTR) NULL;
	//pd.hPrintTemplate = (HANDLE) NULL;
	//pd.hSetupTemplate = (HANDLE) NULL;

	hFontPrint = NULL;
	hFontPrintB = NULL;
	hFontPrintI = NULL;
	hFontPrintS = NULL;

	return TRUE;
}

/****************************************************************************
 *																			*
 *  FUNCTION:	FreePrinterMemory ()										*
 *																			*
 *  PURPOSE	: 	Frees any memory structures allocated for the Printer		*
 *		 		Device context.	This is typically called once when WinVN	*
 *				exits but will also be called if a printer error occurs.	*
 *																			*
 *  RETURNS	: 	TRUE if successful else FALSE								*
 *																			*
 ****************************************************************************/
BOOL WINAPI FreePrinterMemory (void)
{
	BOOL success = TRUE;

	if (pd.hDevMode)
		success = (GlobalFree (pd.hDevMode) == NULL) ? TRUE : FALSE;
	if (pd.hDevNames)
		success = (GlobalFree (pd.hDevNames) == NULL) ? success : FALSE;
	if (pd.hDC)
		success = DeletePrinterDC (pd.hDC) ? success : FALSE;
	PrinterInit ();
	return success;
}

/****************************************************************************
 *																			*
 *  FUNCTION   : PrinterSetup ()											*
 *																			*
 *  PURPOSE    : Creates a printer display context for the default device.  *
 *																			*
 *  RETURNS    : Zero if successful, 1 = cancel, else Extended Error Code	*
 *																			*
 ****************************************************************************/
DWORD WINAPI PrinterSetup (HWND hwnd, DWORD flags)
{
	char mes[60];
	DWORD cError = 0;

	pd.hwndOwner = hwnd;
	pd.Flags = flags;

	if (pd.hDC != 0)
		DeletePrinterDC (pd.hDC);

	if (PrintDlg (&pd) == 0) 
	{
		cError = CommDlgExtendedError ();
		if (cError != 0) 
		{
			_snprintf (mes, 60, "%d", (DWORD) cError);
			WVArgMessageBox (hwnd, IDS_WVPRINT_DEVICE1, IDS_WVPRINT_DEVICE2, MB_OK | MB_ICONEXCLAMATION, mes);
			FreePrinterMemory ();
			return cError;
		}
		else
			return 1;
	}
	else
		return 0;
}

/****************************************************************************
 *																			*
 *  FUNCTION:	GetPrinterDC ()												*
 *																			*
 *  PURPOSE:	Finds or creates a printer display context for the			*
 *				selected printer.											*
 *																			*
 *  RETURNS    : HDC - A handle to printer DC or Null if error				*
 *																			*
 ****************************************************************************/
HDC WINAPI GetPrinterDC (HWND hwnd)
{
	DWORD pError = 0;

	if (pd.hDC)
		return pd.hDC;
	else 
	{
		if ((pd.hDevMode == NULL) && (pd.hDevNames == NULL))
			pError = PrinterSetup (hwnd, PD_RETURNDC | PD_RETURNDEFAULT);
		else
			pError = PrinterSetup (hwnd, PD_RETURNDC);

		if (pError > 0)
			return NULL;
		else
			return pd.hDC;
	}
}

/****************************************************************************
 *																			*
 *  FUNCTION   : DeletePrinterDC ()											*
 *																			*
 *  PURPOSE    : Releases a printer display context for the selected        *
 *               printer.                                                   *
 *																			*
 *  RETURNS    : TRUE if Successful, FALSE if Error                    	    *
 *																			*
 ****************************************************************************/

BOOL WINAPI DeletePrinterDC (HDC hDC)
{
	BOOL success = TRUE;

	if (pd.hDC != hDC)
		success = DeleteDC (pd.hDC);

	success = DeleteDC (hDC) ? success : FALSE;
	pd.hDC = NULL;
	return success;
}


/****************************************************************************
 *																			*
 *  FUNCTION   : PrintDlgProc ()											*
 *																			*
 *  PURPOSE    : Dialog function for the print cancel dialog box.			*
 *																			*
 *  RETURNS    : TRUE  - OK to abort/ not OK to abort						*
 *				 FALSE - otherwise.											*
 *																			*
 ****************************************************************************/
INT_PTR CALLBACK PrintDlgProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg) 
	{
		case WM_INITDIALOG:
			hwndPDlg = hwnd;
			ShowWindow (hwnd, SW_SHOW);
			break;

		case WM_COMMAND:				/* abort printing if the cancel button gets hit */
		switch (LOWORD (wParam)) 
		{
			case IDOK:
			case IDCANCEL:

				PdlgAbort = TRUE;
				EnableWindow (GetParent (hwnd), TRUE);
				if (hwndPDlg)
				{
					DestroyWindow (hwndPDlg);	/* Delete Cancel Dialog */
					hwndPDlg = NULL;
				}
				return TRUE;
		}
		break;
	}
	return FALSE;
}

/****************************************************************************
 *																			*
 *  FUNCTION   : ReportPrintError ()										*
 *																			*
 *  PURPOSE    : Decodes error codes from calls to Windows Print functions  *
 *																			*
 *  RETURNS    : NULL  - No errors or Error has already been reported       *
 *		 		 short - Error code numbers (from Windows.H)				*
 *																			*
 ****************************************************************************/

void WINAPI ReportPrintError (int nError, HWND hWnd)
{
	char mes[20];

	if (nError >= 0)
		return;

#ifdef __GNUC__ //S.Yoshida
#define SP_NOTREPORTED				 0x4000
#define SP_ERROR					 (-1)
#define SP_APPABORT					 (-2)
#define SP_USERABORT				 (-3)
#define SP_OUTOFDISK				 (-4)
#define SP_OUTOFMEMORY				 (-5)
#endif

	if ((nError & SP_NOTREPORTED) == 0)
	return;

	switch (nError) 
	{
		case SP_ERROR:
			WVMessageBox (hWnd, IDS_WVPRINT_OFFLINE1, IDS_WVPRINT_OFFLINE2, MB_OK | MB_ICONEXCLAMATION);
			break;

		case SP_APPABORT:
			WVMessageBox (hWnd, IDS_WVPRINT_CANCELA1, IDS_WVPRINT_CANCELA2, MB_OK | MB_ICONEXCLAMATION);
			break;

		case SP_USERABORT:
			WVMessageBox (hWnd, IDS_WVPRINT_CANCELU1, IDS_WVPRINT_CANCELU2, MB_OK | MB_ICONEXCLAMATION);
			break;

		case SP_OUTOFDISK:
			WVMessageBox (hWnd, IDS_WVPRINT_DISKSPACE1, IDS_WVPRINT_DISKSPACE2, MB_OK | MB_ICONEXCLAMATION);
			break;

		case SP_OUTOFMEMORY:
			WVMessageBox (hWnd, IDS_WVPRINT_MEMORY1, IDS_WVPRINT_MEMORY2, MB_OK | MB_ICONEXCLAMATION);
			break;

		default:
			sprintf (mes, "%d", (int) nError);
			WVArgMessageBox (hWnd, IDS_WVPRINT_UNKNOWN1, IDS_WVPRINT_UNKNOWN2 , MB_OK | MB_ICONEXCLAMATION, mes);
			break;

	}
	return;
}


/****************************************************************************
 *																			*
 *  FUNCTION   : PrintHeaderP ()											*
 *																			*
 *  PURPOSE    : Determines if this is a header we are printing				*
 *																			*
 *        Entry:  str    substring to search                                *
 *                limit  limits the search to no more than num characters   *
 *                                                                          *
 *        Exit:   BOOL   TRUE if we are not excluding print this header     *
 *                       FALSE if we are explicited excluding header        *
 *																			*
 ****************************************************************************/

#define LEFTMARGIN 6			/* Left Margin in characters on printed page */
#define TOPMARGIN 4				/* Top Margin in characters on printed page */
#define BOTTOMMARGIN 6			/* Bottom Margin in characters on printed page */
#define MAXHEADERSIZE 20		/* Largest number of chars allowed in a header name */
#define	MAXSCANHEADERSIZE 30		/* Content-Transfer-Encoding: is 25 characters :-( */

#define MAXPRINTSPOOLERID 64		/* Length of name for Printspooler */


BOOL WINAPI PrintHeaderP (char *str, int limit)
{
	if (limit >= MAXHEADERSIZE) /* this header is wider than place for it on page */
		return (FALSE);
	//wouldn't it be easier to specify the headers we do accept?
	
	if (_strnicmp (str, "Relay-Version:", limit) == 0 
		|| _strnicmp (str, "Path:", limit) == 0
		|| _strnicmp (str, "References:", limit) == 0
		|| _strnicmp (str, "NNTP-Posting-Host:", limit) == 0
		|| _strnicmp (str, "Mime-Version:", limit) == 0
		|| _strnicmp (str, "Content-Type:", limit) == 0
		|| _strnicmp (str, "Content-Transfer-Encoding:", limit) == 0
		|| _strnicmp (str, "User-Agent:", limit) == 0
		|| _strnicmp (str, "Injection-Date:", limit) == 0
		|| _strnicmp (str, "Injection-Info:", limit) == 0
		|| _strnicmp (str, "Importance:", limit) == 0
		|| _strnicmp (str, "Complaints-To:", limit) == 0
		|| _strnicmp (str, "Cancel-Lock:", limit) == 0
		|| _strnicmp (str, "Face:", limit) == 0
		|| _strnicmp (str, "NNTP-Posting-Date:", limit) == 0
		|| _strnicmp (str, "X-Newsreader:", limit) == 0
		|| _strnicmp (str, "X-Mailer:", limit) == 0
		|| _strnicmp (str, "X-XXMessage-ID:", limit) == 0
		|| _strnicmp (str, "X-XXDate:", limit) == 0
		|| _strnicmp (str, "Xref:", limit) == 0
		|| _strnicmp (str, "X-Priority:", limit) == 0
		|| _strnicmp (str, "X-MimeOLE:", limit) == 0
		|| _strnicmp (str, "X-MSMail-Priority:", limit) == 0
		|| _strnicmp (str, "X-Priority:", limit) == 0
		|| _strnicmp (str, "X-No-Archive:", limit) == 0
		|| _strnicmp (str, "X-Trace:", limit) == 0
		|| _strnicmp (str, "X-Complaints-To:", limit) == 0
		|| _strnicmp (str, "X-HTTP-User-Agent:", limit) == 0
		|| _strnicmp (str, "X-Trace:", limit) == 0
		|| _strnicmp (str, "X-Face:", limit) == 0
		|| _strnicmp (str, "X-RFC2646:", limit) == 0
		|| _strnicmp (str, "X-Original-Bytes:", limit) == 0
		|| _strnicmp (str, "X-Comments:", limit) == 0
		|| _strnicmp (str, "X-Antivirus:", limit) == 0
		|| _strnicmp (str, "X-Antivirus-Status:", limit) == 0
		|| _strnicmp (str, "X-Accept-Language:", limit) == 0
		|| _strnicmp (str, "X-HTTP-UserAgent:", limit) == 0
		|| _strnicmp (str, "X-Received:", limit) == 0		
		)
		return (FALSE); /* this header is unwanted to take knowledge of it */
  
	return (TRUE);
}


/****************************************************************************
 *																			*
 *  FUNCTION   : PrintFile ()												*
 *																			*
 *  PURPOSE    : Prints the contents of the edit control.					*
 *																			*
 ****************************************************************************/

void WINAPI PrintFile (HWND hwnd)
{
	WVMessageBox (hwnd, IDS_WVPRINT_FUNCTION1, IDS_WVPRINT_FUNCTION2, MB_OK | MB_ICONINFORMATION);
	return;
}

/****************************************************************************
 *																			*
 *  FUNCTION   : PrintArticle ()											*
 *																			*
 *  PURPOSE    : Prints the current article.								*
 *																			*
 ****************************************************************************/


void WINAPI PrintArticle (HWND hwnd, TypDoc * Doc)
{
	char sz[MAXINTERNALLINE];
	char szFormat[MAXINTERNALLINE];
	char szTitle[MAXHEADERLINE];
	char mybuf[MAXINTERNALLINE];
	char PrintSpoolerId[MAXPRINTSPOOLERID];
	DOCINFO di;
	BOOL found;
	BOOL printableheader = FALSE;
	BOOL inheader = TRUE;
	BOOL ROT13Mode = GetArticleRot13Mode (Doc->hWndFrame);
	int i, dy, dx, yExtPage, yExtSoFar = 0, nPrintError, x;
	unsigned int LineLen, Offset, nCharsPerLine, nLinesPerPage;
	uint32 PageNum, nTotalPages, nTotalLines, iLine;
	char far *textptr;
	char *loc;
	DWORD cError = 0;
	TypBlock far *BlockPtr;
	TypLine far *LinePtr;
	HANDLE hBlock;
	TypLineID MyLineID;
	TEXTMETRIC tm;
	DEVNAMES *dv;
	ABORTPROC lpfnAbortProc = NULL;
	DLGPROC lpfnPrintDlgProc = NULL;
	TextSelect FAR *Start = NULL, *End = NULL;


	LoadString(hInst,IDS_WVPRINT_SPOOLERID,PrintSpoolerId,MAXPRINTSPOOLERID);
	/* Create the job title */
	memset(&di, 0, sizeof(di));
	di.cbSize = sizeof (di);
	di.lpszDocName = PrintSpoolerId;
	di.lpszOutput = NULL;

	/* Initialize the printer */
	nPrintError = 0;
	hwndPDlg = NULL;
	PdlgAbort = FALSE;
	cError = PrinterSetup (hwnd, PD_RETURNDC | PD_USEDEVMODECOPIES);
	if ((cError != 0) || (pd.hDC == 0))
		goto exitout;

	UpdateWindow(hwnd);

	/* Reinitialize Fonts just in case the user changed printers on us */
	InitPrintFonts ();

	/*  Create the Cancel dialog and Disable the main application window */
	lpfnPrintDlgProc = &PrintDlgProc;//(DLGPROC) MakeProcInstance ((FARPROC) PrintDlgProc, (HINSTANCE) hInst);
	if (!lpfnPrintDlgProc)
		goto exitout;
	hwndPDlg = CreateDialog ((HINSTANCE) hInst, MAKEINTRESOURCE(IDD_PRINTDIALOG), hwnd, (DLGPROC) lpfnPrintDlgProc);
	if (!hwndPDlg)
		goto exitout;

	/* Allow the app. to inform GDI of the Abort function to call */
	lpfnAbortProc = &AbortProc;//(ABORTPROC) MakeProcInstance ((FARPROC) AbortProc, (HINSTANCE) hInst);
	if (!lpfnAbortProc)
		goto exitout;

	EnableWindow (hwnd, FALSE);
	if (SetAbortProc (pd.hDC, (ABORTPROC) lpfnAbortProc) < 0) 
	{
		WVMessageBox (hwnd, IDS_WVPRINT_ABORT1, IDS_WVPRINT_ABORT2, MB_OK | MB_ICONEXCLAMATION);
		nPrintError = 0;			/* don't print double error messages */
		goto exitout;
	}

	/* Get the Subject, printer description and Port number */
	found = GetHeaderLine (Doc, "Subject:", szTitle, sizeof (szTitle));
	if (!found) lstrcpy (szTitle, "Subject: No Subject");
		TrimmMultiLineHeader( szTitle );

	SetDlgItemText ((HWND) hwndPDlg, IDD_PRINTSUBJECT, (LPSTR) szTitle);
	dv = (DEVNAMES *) GlobalLock (pd.hDevNames);
	// sprintf (sz, "To %s on %s", (LPSTR) dv + dv->wDeviceOffset, (LPSTR) dv + dv->wOutputOffset);
	strcpy(mybuf,(LPSTR) dv + dv->wDeviceOffset);   //Heirich 19960829
	if (strncmp(mybuf,"\\\\",2)) 
	{
		LoadString(hInst, IDS_WVPRINT_TO_LOCAL, szFormat, MAXINTERNALLINE);
		sprintf (sz, szFormat, mybuf, (LPSTR) dv + dv->wOutputOffset);
	} 
	else 
	{
		LoadString(hInst, IDS_WVPRINT_TO_REMOTE, szFormat, MAXINTERNALLINE);
		sprintf (sz, szFormat, mybuf);
	}
	SetDlgItemText ((HWND) hwndPDlg, IDD_PRINTDEVICE, (LPSTR) sz);
	GlobalUnlock (pd.hDevNames);

	LoadString(hInst,IDS_WVPRINT_INIT_STATUS, sz, MAXINTERNALLINE);
	SetDlgItemText ((HWND) hwndPDlg, IDD_PRINTSTATUS, (LPSTR) sz);

	/*  Initialize the Printer Device Context */
	nPrintError = StartDoc (pd.hDC, &di);
	if (hwndPDlg) 
	{
		UpdateWindow (hwndPDlg);	/* print to file may overwrite dialog */
		SetFocus (hwndPDlg);
	}
	if (nPrintError < 0)
		goto exitout;

	LockLine (Doc->hFirstBlock, sizeof (TypBlock), (TypLineID) 0L,
	&BlockPtr, &LinePtr);

	/* Get the lines in document and and a handle to the text buffer */
	iLine = 0;
	PageNum = 1;
	nTotalLines = Doc->TotalLines;

	// Prepare data structure if we are going to be printing selected text
	// Check to see if selected text was top-to-bottom or bottom-to-top
	if (((pd.Flags & PD_SELECTION) == 1) && (Doc->TextSelected)) 
	{
		if ((Doc->EndSelect.LineNum > Doc->BeginSelect.LineNum) ||
			((Doc->EndSelect.LineNum == Doc->BeginSelect.LineNum) &&
			(Doc->EndSelect.CharNum >= Doc->BeginSelect.CharNum))) 
		{
			Start = &Doc->BeginSelect;
			End = &Doc->EndSelect;
		}
		else 
		{
			Start = &Doc->EndSelect;
			End = &Doc->BeginSelect;
		}
	}

	/* Get the height of one line and the height of a page */
	SelectObject (pd.hDC, hFontPrint);	/* Select Printer Font */
	GetTextMetrics (pd.hDC, &tm);
	dy = tm.tmHeight + tm.tmExternalLeading;
	dx = tm.tmAveCharWidth;
	nCharsPerLine = GetDeviceCaps (pd.hDC, HORZRES) / dx;
	nLinesPerPage = GetDeviceCaps (pd.hDC, VERTRES) / dy;
	nTotalPages = (nTotalLines + BOTTOMMARGIN + TOPMARGIN) / nLinesPerPage;
	if (nTotalPages < 1)
		nTotalPages = 1;
	yExtPage = GetDeviceCaps (pd.hDC, VERTRES);
	nPrintError = StartPage (pd.hDC);
	if (nPrintError <= 0)
		goto abortout;

	/* If we are printing the First Page, place the Subject line at the Top */
	if ((((pd.Flags & PD_PAGENUMS) == 0) && ((pd.Flags & PD_SELECTION) == 0)) ||
		(pd.nFromPage == 0) ||
		(pd.nFromPage == 1)) 
	{
		LoadString(hInst, IDS_WVPRINT_PRINT_PAGE, szFormat, MAXINTERNALLINE);
		sprintf (sz, szFormat, PageNum, nTotalPages);
		SetDlgItemText (hwndPDlg, IDD_PRINTSTATUS, (LPSTR) sz);

		SelectObject (pd.hDC, hFontPrintS);		/* Select Printer Font */
		if ((pd.Flags & PD_SELECTION) == 0)
		{
			TextOut (pd.hDC, LEFTMARGIN * dx, TOPMARGIN * dy, szTitle, lstrlen (szTitle));
		}
		else 
		{
			LoadString(hInst, IDS_WVPRINT_SELECT_FROM, sz , MAXINTERNALLINE);
			strncat (sz, szTitle, MAXINTERNALLINE - strlen (sz) - 1);
			TextOut (pd.hDC, LEFTMARGIN * dx, TOPMARGIN * dy, sz, lstrlen (sz));
		}
		yExtSoFar = (int) dy *(TOPMARGIN + 4);
	}

	/* Print out text until no more lines or user aborts */
	while ((iLine < nTotalLines) && !PdlgAbort) 
	{
		if ((yExtSoFar + (BOTTOMMARGIN + 1) * dy) >= yExtPage) 
		{
			/* Reached the end of a page, print Page number */
			if ((((pd.Flags & PD_PAGENUMS) == 0) &&
				((pd.Flags & PD_SELECTION) == 0)) ||	      
				(((pd.Flags & PD_SELECTION) == 0) && 
				((pd.nFromPage == 0) || (PageNum >= pd.nFromPage)) &&
				((pd.nToPage == 0) || (PageNum <= pd.nToPage)))  ||
				(((pd.Flags & PD_SELECTION) == 1) && 
				(Doc->TextSelected) &&
				((long) iLine >= Start->LineNum) &&
				((long) iLine <= End->LineNum))) 
			{
				SelectObject (pd.hDC, hFontPrintB);
				LoadString(hInst, IDS_WVPRINT_THIS_PAGE, szFormat, MAXINTERNALLINE);
				sprintf (sz, szFormat , PageNum);
				if ((PageNum > 1) || (PageNumberAlwaysWithSubject)) 
				{
					strncat (sz, szTitle, MAXINTERNALLINE - strlen (sz) - 1);
					x = dx * LEFTMARGIN;	/* left justified for pages > 1 */
				}
				else 
				{
					x = (nCharsPerLine / 2) * dx;	/* centered for page 1 */
				}
				TextOut (pd.hDC, x, yExtSoFar + (2 * dy), sz, lstrlen (sz));

				/* Tell device driver to eject page */
				if (PageNum > nTotalPages)
					nTotalPages = PageNum;
				LoadString(hInst, IDS_WVPRINT_PRINT_PAGE, szFormat, MAXINTERNALLINE);
				sprintf (sz, szFormat, PageNum, nTotalPages);
				SetDlgItemText (hwndPDlg, IDD_PRINTSTATUS, (LPSTR) sz);
				nPrintError = EndPage (pd.hDC);
				if ((nPrintError < 0) || PdlgAbort)
					break;
				nPrintError = StartPage (pd.hDC);
				if ((nPrintError < 0) || PdlgAbort)
					break;
			}

			yExtSoFar = dy * TOPMARGIN;
			PageNum++;
		}

		/* Print the line and unlock the text handle */
		if (LinePtr->length != END_OF_BLOCK) 
		{
			textptr = GetTextPtr(LinePtr);
			LineLen = lstrlen (textptr);
			if (IsBlankStr (textptr))
				inheader = FALSE;

			if ((((pd.Flags & PD_PAGENUMS) == 0) &&
				((pd.Flags & PD_SELECTION) == 0)) ||		  
				(((pd.Flags & PD_SELECTION) == 0) && 
				((pd.nFromPage == 0) || (PageNum >= pd.nFromPage)) &&
				((pd.nToPage == 0) || (PageNum <= pd.nToPage))) ||
				((pd.Flags & PD_SELECTION) == 1) && 
				Doc->TextSelected &&
				(iLine >= (UINT) Start->LineNum) &&
				(iLine <= (UINT) End->LineNum)) 
			{
				if (inheader) 
				{
					loc = (char *) memchr (textptr, ':', MAXSCANHEADERSIZE);
					if (loc) 
					{
						i = loc - textptr + 1;
						printableheader = PrintHeaderP (textptr, i);
						if (printableheader) 
						{
							SelectObject (pd.hDC, hFontPrintB);
							TextOut (pd.hDC, (LEFTMARGIN * dx), yExtSoFar, textptr, i);
							SelectObject (pd.hDC, hFontPrint);
							TextOut (pd.hDC, (LEFTMARGIN + MAXHEADERSIZE + 2) * dx,
							yExtSoFar, textptr + i, LineLen - i);
							yExtSoFar += dy;
						}
					}
					else 
					{
						if (printableheader) 
						{
							SelectObject (pd.hDC, hFontPrint);
							TextOut (pd.hDC, (LEFTMARGIN + MAXHEADERSIZE + 2) * dx,
							yExtSoFar, textptr, LineLen);
							yExtSoFar += dy;
						}
					}
				}
				else 
				{		
					if (ROT13Mode) 
					{
						strcpy (mybuf, textptr);
						textptr = mybuf;
						strROT13 (textptr);
					}
					if (isLineQuotation (textptr))
						SelectObject (pd.hDC, hFontPrintI);
					else
						SelectObject (pd.hDC, hFontPrint);

					TextOut (pd.hDC, (LEFTMARGIN * dx), yExtSoFar, textptr, LineLen);
					yExtSoFar += dy;
				}
			}

			NextLine (&BlockPtr, &LinePtr);
		}

		/* Move down the page */
		iLine++;
	}   /* End While */

abortout:

	UnlockLine (BlockPtr, LinePtr, &hBlock, &Offset, &MyLineID);
	if (!PdlgAbort && (nPrintError >= 0)) 
	{
		/* Eject the last page. */
		if ((((pd.Flags & PD_PAGENUMS) == 0) &&
			((pd.Flags & PD_SELECTION) == 0)) || 
			(((pd.nFromPage == 0) || (PageNum >= pd.nFromPage)) &&
			((pd.nToPage == 0) || (PageNum <= pd.nToPage))) ||
			(((pd.Flags & PD_SELECTION) == 1) && 
			(Doc->TextSelected) &&
			(iLine >= (UINT) Start->LineNum) &&
			(iLine <= (UINT) End->LineNum))) 
		{
			SelectObject (pd.hDC, hFontPrintB);
			LoadString(hInst, IDS_WVPRINT_THIS_PAGE, szFormat, MAXINTERNALLINE);
			sprintf (sz, szFormat, PageNum);
			if ((PageNum > 1) || (PageNumberAlwaysWithSubject)) 
			{
				strncat (sz, szTitle, MAXINTERNALLINE - strlen (sz) - 1);
				x = dx * LEFTMARGIN;	/* left justified for pages > 1 */
			}
			else 
			{
				x = (nCharsPerLine / 2) * dx; /* centered for page 1 */
			}
			TextOut (pd.hDC, x, yExtPage - (BOTTOMMARGIN * dy), sz, lstrlen (sz));
			nPrintError = EndPage (pd.hDC);
		}

		/* Complete the document. */
		if (!PdlgAbort && (nPrintError >= 0))
			nPrintError = EndDoc (pd.hDC);
	}

exitout:

	if (PdlgAbort) 
	{
		if (pd.hDC)
		{
			AbortDoc (pd.hDC);
			DeletePrinterDC(pd.hDC);
		}
		WVMessageBox (hwnd, IDS_WVPRINT_CANCEL1, IDS_WVPRINT_CANCEL2, MB_OK | MB_ICONEXCLAMATION);
	}
	else if (nPrintError < 0)
	{
		ReportPrintError (nPrintError, hwnd);
	}

	EnableWindow (hwnd, TRUE);	/* ReEnable main procedure */
	if (hwndPDlg)
	{
		DestroyWindow ((HWND) hwndPDlg);	/* Delete Cancel Dialog */
		PdlgAbort = FALSE;
		hwndPDlg = NULL;
	}



  return;
}

/* 
 * Local Variables:
 * tab-width: 4
 * end:
 */
