{**********e******************************************************************
 ***                                                                      ***
 *** New Fabbo Singing Dancing OOP                                        ***
 ***                         WORD PROCESSOR LINK                          ***
 ***                                                                      ***
 *** M Hill                                                     Jan 1993  ***
 ****************************************************************************}
{$I compdirs}  {Compiler directives}
{Originally designed for WordPerfect 5.1, there should be no problem over
using this utility with *any* other wordprocessor as long as:
	Text can be inserted as plain ASCII (ie replacing <DT> with 12/12/12)
	Ideally should be able to start macros from the command line
}


{PROBLEMS with WP60 just now are:
	1) Translating from old wp51 docs to wp60.  Not so bad; we would have to define
	a path for forms for the old version, which wp will then automatically update.

	2) Any text formatting codes do not appear to be ascii.  Spaces are $80, carriage
	returns are wierd and I cannot track them down, so inserting text (such as dates, etc)
	is a bit of a problem, as it will need to be translated.}


unit KWPLink;

INTERFACE

uses	labels,
			global, setup, tuiedit,
			files,
			objects, {fnamestr}
			devices, tasks;

{**************************************************************
 ***               GENERAL WP ADMIN FUNCS                   ***
 **************************************************************}

{const
	WPLtrFileName = 'LETTER.$$$';
{	WPDefaultVer : byte;{}

procedure EditWPForm;
function EditWPFile(var FullFileName : FNameStr; const Ext : string) :Word;
function PrintWPFile(FileName : FNameStr) : word;  {returns 0 if called OK}

function CallWP(FileName : FNameStr; Macro : string) : word; {returns 0 if called OK}
function FaxWPFile(FileName : FNameStr): word;

procedure PrintDeferredWPLabels(FileName : string; PrintDetails: TPrintDEtails);
procedure PrintDeferredWPLetters;
procedure WPLinkDeleteDeferredLetters;


{**************************************************************
 ***               DEFINE WP OUTPUT STREAM                  ***
 **************************************************************}
{Overrides some parts of the normal output stream that assumes we
are reading a line-by-line form.  Therefore there is a different
printform, (as the outputstream reads by line - this has to read
by block as there may be a long time between CR's!) also there
cannot be any automatic indenting, so XPos is kept to 0}
{start print should print form with full
header, any other/later print form should skip WP header part}
type
	PWPStream = ^TWPStream;
	TWPStream = object(TDeviceStream)
		FirstForm : boolean;
		KeepOpen : boolean; {don't close at endprint}
		SendAsFax : boolean;
		constructor Init(AFName : FNameStr);
		procedure Initialise; virtual; {useful for bitstream stuff}
		procedure Close; virtual;
		procedure PrintForm(FormName : FNameStr); virtual;
		procedure StartPrint(NHeaderName1,NHeaderName2 : FNameStr); virtual; {Start report - page no set to 0, initial codes}
		procedure EndPrint; virtual; {doesn't do any of the FF stuff, etc}
		procedure Send; virtual; {prints}
		procedure FeedPage; virtual;  {Form Feed}
	end;

var
	WPStream : PWPstream; {acts like fax and printer driver, for permanant access}

type
	PWPSetup = ^TWPSetup;
	TWPSetup = object(TSetup)

		Path : string[40];{}
		LocalPath : string[40];
		FormsPath : string[40];

		ProgramName : string[70];
{		FaxProgram 	: string[70]; delete this and put in a "fax using " marker?{}

		FaxMacro 		: string[40];
		PrintMacro 	: string[40];
		EditMacro 	: string[40];
		InitMacro 	: string[40]; {do printer initialisation}

		SubsHdrs		: boolean; {substitute editor headers if wp doesn't exist}
		SubsFrms		: boolean; {substitute editor forms if wp doesn't exist}
		AutoInit    : boolean; {whether to do initialisation automatically}

		WPToFax			: boolean; {whether WP is to fax using the fax macro, or assume a 3rd party port capturer}

		CommentString : string[40];
		BeginMarker : string[40];
		NumBytesAfterComment : byte;

		procedure Load; virtual;
		procedure PostLoad; virtual;
		procedure Store; virtual;
		procedure SetButtonDefaults; virtual;
		procedure AddSetupLines(EditBox : PEditBox); virtual;
	end;

var
	WPSetup : TWPSetup;

const
{Comment separator, used to mark line between standard header and user modified bit}
	WP51CommentString = 'BEGIN';

	WP51CommentLength = char((length(WP51CommentString)+7) mod $100)
								+ char((length(WP51CommentString)+7) div $100);

	WP51BeginMarker
							 = #$D9+#$02    							{Comment, function code & subfunc code}
							 + WP51CommentLength							{length}
							 + #$06+#$00 	                {Old screen column?}
							 + #$01 											{#Lines}
							 + WP51CommentString
							 + WP51CommentLength
							 + #$02+#$D9;                 {End of comment marker}

	WP51NumBytesAfterComment = 4;  {2 bytes comment length, 2 bytes $02 $D9}


IMPLEMENTATION

uses 	dos,{for checking file attribute to see if it's been edited/saved}
			inpfname, dialogs, app, tuiapp, {for editing forms}
			messtext,	{for errors running WP}
			views, drivers,	{hcnocontext}
			forms, 		{for decoding callwp lines}
			help,
			kamsetup, {for storing setup}
			faxes,
			tuimsgs,
			tuiboxes, stddlg, {for form editing}
			lstrings,	{WPStream form printing}
			dosUtils,
			minilib;

{**********************************************************
 ***                                                    ***
 ***                 WORD PROCESSOR SETUP               ***
 ***                                                    ***
 **********************************************************}

procedure TWPSetup.Load;
begin
	Path :=     	GetPath('PATH', 'wp');
	LocalPath :=	GetPath('LOCAL PATH', Path);
	FormsPath := 	GetPath('FORMS PATH', Path);
	ProgramName :=Get('PROGRAM','\WP51\WP.EXE')+' ';
{	FaxProgram := Get('FAX PROGRAM', ProgramName)+' ';{}

{	WPInvoices := GetBoolean('INVOICES',False);
	WPSalesOrders := GetBoolean('SALES', False);
	WPLabels := GetBoolean('LABELS', False);{}
	SubsHdrs		:= GetBoolean('SUBS HDRS',False);
	SubsFrms		:= GetBoolean('SUBS FRMS',True);
	AutoInit		:= GetBoolean('AUTO INIT',True);
	WPToFax			:= GetBoolean('WP TO FAX',False);

	EditMacro := 	Get('EDIT MACRO','/m-kedit');
	PrintMacro := Get('PRINT MACRO','/m-kprint');
{	PrintDeferredMacro := Get('PRINT DEFERRED MACRO','/m-kdefer');{}
	InitMacro := Get('INIT MACRO','');	{usually none, but might set for bitstream}
	FaxMacro := 	Get('FAX MACRO','/m-kfax');
end;

procedure TWPSetup.PostLoad;
begin
	{set default dependants}
{all done as part of the get now	if FormsPath = '' then FormsPath := Path;
	if LocalPath = '' then LocalPath := Path; {working directory}
{	if FaxProgram = ' ' then FaxProgram := ProgramName;

	{special}
	CommentString 				:= WP51CommentString ;
	BeginMarker 					:= WP51BeginMarker;
	NumBytesAfterComment 	:= WP51NumBytesAfterComment;
end;

procedure TWPSetup.SetButtonDefaults;
begin
	{default to WordPerfect link}
	Path := 'C:\KAMELEON\WP\';
	FormsPath := '';
	LocalPath := '';

	ProgramName := 'C:\WP51\WP.EXE /ps=<FORMSPATH> <FILE> <MACRO>'; {add setup path}
{	FaxProgram := ' ';{}

{	WPInvoices := False;
	WPSalesOrders := False;
	WPLabels := False;{}
	SubsHdrs := False;
	SubsFrms := True;
	AutoInit := True;
	WPToFax		:= False;

	EditMacro := '/m-kedit';
	PrintMacro := '/m-kprint';
{	PrintDEferredMacro := '/m-kdefer';{}
	InitMacro := '';
	FaxMacro := '/m-kfax';            {}
end;

procedure TWPSetup.Store;
begin
{	if FaxProgram=ProgramName then FaxProgram := ' ';{}
	if FormsPath=Path then FormsPath := '';
	if LocalPath=Path then LocalPath := '';

	Put('PATH', Path);
	Put('LOCAL PATH', LocalPath);
	Put('FORMS PATH', FormsPath);
	Put('PROGRAM', ProgramName);
{	Put('FAX PROGRAM', FaxProgram);{}

	Put('EDIT MACRO', EditMacro);
	Put('PRINT MACRO', PrintMacro);
{	Put('PRINT DEFERRED MACRO', PrintDeferredMacro);{}
	Put('INIT MACRO', InitMacro);
	Put('FAX MACRO', FaxMacro);

{	PutBoolean('INVOICES', WPInvoices);
	PutBoolean('SALES', WPSalesOrders);
	PutBoolean('LABELS', WPLabels);{}

	PutBoolean('SUBS HDRS', SubsHdrs);
	PutBoolean('SUBS FRMS', SubsFrms);
	PutBoolean('AUTO INIT', AutoInit);
	PutBoolean('WP TO FAX', WPToFax);

	ProgramSetup.Store;
end;

{============ EDIT ======================}
procedure TWPSetup.AddSetupLines;
var R : TRect;
begin
	with EditBox^ do begin
		GrowTo(45,22);

		InsTitledField(20,  3,20, 1, 'Path', New(PInputELine, init(R, 40)));
		PInputELine(Current)^.MustInput := True;
		InsTitledField(20,  4,20, 1, 'Local Path', New(PInputELine, init(R, 40)));
		InsTitledField(20,  5,20, 1, 'Forms Path', New(PInputELine, init(R, 40)));

		InsTitledField(20,  7,20, 1, '~P~rogram', New(PInputELine, init(R, 70)));
		PInputELine(Current)^.MustInput := True;
{		InsTitledField(20,  8,20, 1, 'Fax Program', New(PInputELine, init(R, 70)));{}

		InsTitledField(20,  9,20, 1, 'Fax ~M~acro', New(PInputELine, init(R, 40)));
		InsTitledField(20, 10,20, 1, 'Print Macro', New(PInputELine, init(R, 40)));
		InsTitledField(20, 11,20, 1, 'Edit Macro', New(PInputELine, init(R, 40)));
		InsTitledField(20, 12,20, 1, 'Initialise Macro', New(PInputELine, init(R, 40)));

		InsTitledField(20, 14, 1, 1, 'Auto ~I~nit', New(PInputBoolean, init(R)));

		InsTitledField(20, 16, 1, 1, '~S~ubs Text Hdrs', New(PInputBoolean, init(R)));
		InsTitledField(20, 17, 1, 1, 'Subs Text Frms', New(PInputBoolean, init(R)));
		InsTitledField(20, 18, 1, 1, 'WP To ~F~ax', New(PInputBoolean, init(R)));

{		InsTitledField(20, 15, 1, 1, 'WP ~I~nvoices', New(PInputBoolean, init(R)));
		InsTitledField(20, 16, 1, 1, 'WP ~S~ales Orders', New(PInputBoolean, init(R)));
		InsTitledField(20, 17, 1, 1, 'WP ~L~abels', New(PInputBoolean, init(R)));{}

	end;
end;


{**********************************************************************
 ***                                                                ***
 ***                GENERAL WP ADMIN FUNCS                          ***
 ***                                                                ***
 **********************************************************************}

{**************************************
 ***         EDIT WP FORM           ***
 **************************************}
var
	LastWPFormFileName : FNameStr;

procedure EditWPForm;
var	Control : word;
		FullFileName : FNameStr;
		DefDir : string;

begin
	repeat
		Control := FileSelectBox('EDIT WP FORM','Form', LastWPFormFileName,
							'HDR HD1 FTR FTL FRM STL', WPSetup.FormsPath, fdPickOnly+fdOpenButton+fdNewButton, hcNoContext);

		case Control of
			cmNew : begin
				{want to start in forms directory}
				{doesn't seem to work - at least not under OS/2}
				DefDir := GetCurrentDirectory;
				SetCurrentDirectory(WPSetup.FormsPath);
				CallWP('', '');
				SetCurrentDirectory(DefDir);
			end;
			cmFileOpen : begin
				FullFileName := WPSetup.FormsPath + LastWPFormFileName;
				EditWPFile(Fullfilename,'');
			end;
		end;

	until Control=cmCancel;
end;

{====== EDIT WP FILE ============}
{No processing, just call with file name/path}
function EditWPFile;
var Attr : word;
		WPLtrFile : text;
begin
	if Copy(GetFileName(FullFileName),1,1) = '.' then FullFileName := ''; {clear if no name specified amongst path, ext, etc}
	if (pos('\', FullFileName)=0) and (FullFileName<>'') then FullFileName := WPSetup.FormsPath + FullFileName;
	CallWP(FullFileName,'');  {just call w/o doing normal "look for begin" macro}

	{test attribute to see if OK or cancelled}
	Assign(WPLtrFile, FullFileName);
	GetFAttr(WPLtrFile, Attr);
	if ((Attr and Archive)>0) then EditWPFile := cmOK else EditWPFile := cmCancel;
end;

function PrintWPFile;
begin
	if pos('\', FileName)=0 then FileName := WPSetup.FormsPath + FileName;
	PrintWPFile := CallWP(FileName, WPSetup.PrintMacro);  {just call w/o doing normal "look for begin" macro}
end;


{***************************************
 ***          CALL WP                ***
 ***************************************}

function CallWP(FileName : FNameStr; Macro : string) : word;
var I : integer;
		prog, Params : string;
		CodeSet : TFormCodeCollection;
		VideoMode, Err : integer;


begin
	CallWP := 0;

	{Split between program & parameters}
	SplitProgParams(WPSetup.ProgramName, Prog, Params);

	{Decode parameter line}
	CodeSet.Init;
	CodeSet.SetStr('WPPATH', WPSetup.Path);
	CodeSet.SetStr('FORMSPATH', WPSetup.FormsPath);
	CodeSet.SetStr('FILE',FileName);
	CodeSet.SetStr('MACRO',Macro);
	Params := CodeSet.QDecodeStr(Params);
	CodeSet.Done;

	Desktop^.ShowCursor;

	IdleOff := True;

	CloseAllFiles; {release handles}

	Err := Run(Prog, Params,rnNone,'Calling WordPerfect...');{}{}

	ReOpenAllFiles;

	IdleOff := False;

	{DBG{}{ DOSCommand('COPY '+WPLocalPath+'LETTER.TST '+WPSetup.LocalPath+'LETTER.$$$'); {}

	Desktop^.HideCursor;

	if Err<>0 then
		case Err of
			8 : ProgramWarning('Not enough memory to run WordPerfect',hcWPMemory);
			2,3 : ProgramWarning('Could not find WordPerfect Program'#13
														+Prog,hcEditWPSetup);
		else
			ProgramWarning('Error trying to run WordPerfect'#13
												+Prog+' '+Params+#13
												+IOError(Err)+#13,
												hcIOErrorMsg);
		end;


	CallWP := Err;
end;


{============= FAX WITH WP ===============================}
{Two kinds of faxing - one, using WP itself (dunno how to pass the
telephone number to WP though, but use the fax macro), and the second
using a capture device.  Only second really tested, but requires
a pre-line of >>TO to direct the fax where to send to... requires that
the Internal fax device is set up too}
{Fax number etc, is set in <FAXTO.NUM> etc codes of wpstream}
function FaxWPFile(FileName : FNameStr) : word;
var	CodeSet : PFormCodeCollection;
		S : string;

begin
	if True then begin {should use a setting in WPSetup instead}

		{-- Capture method --}
		if Fax=nil then
			ProgramWarning('No Internal Fax Device Set'#13#10'Cannot set fax number', hcSetFax)
		else begin
			{hmm, a bit fiddly - need to use WPStream's formcodes...}
			S := WPStream^.FormCodes^.QDecodeStr('<FAXTO.NUM>');
			CodeSet := Fax^.FormCodes;
			Fax^.FormCodes := WPStream^.FormCodes;
			Fax^.SetFaxNumber;
			Fax^.FormCodes := CodeSet;{}
		end;

		FaxWPFile := CallWP(FileName, WPSetup.PrintMacro);

	end else begin

		{-- WP to fax method ---}
		{could maybe decode faxmacro to a temporary file and use that as calling macro?
		faxmacro then has in it <FAXTO.> etc etc?}

		FaxWPFile := CallWP(FileName, WPSetup.FaxMacro);

	end;
end;


{**************************************************************
 ***                                                        ***
 ***                 WP OUTPUT STREAM                       ***
 ***                                                        ***
 **************************************************************}

constructor TWPStream.Init;
begin
	if pos('\',AFName)=0 then AFName := WPSetup.Path + AFName;
	inherited Init('WP Stream', AFName);

	FormOptions := FormOptions and not foASCII; {treat parameter of decodeline as a block, not a line}
	FirstForm := True; {marker to say whether this is the first form being done -
	if so then the complete form needs "printed", otherwise we must skip the
	header block}
	KeepOpen := False; {default to closing & sending at endprint}

	AutoInit := WPSetup.AutoInit;
	SendAsFax := False;
end;


procedure TWPStream.Initialise;
begin
	{Calls WP with a "do printer initialisation" macro}
	if (WPSetup.InitMacro<>'') then CallWP('', WPSetup.InitMacro);
	IsInitialised := True;
end;


procedure TWpStream.Close;
var Attr : word;
begin
	inherited Close;

	{remove archive attribute, so we can test to see if it has been changed}
	GetFAttr(DosFile, Attr);
	Attr := Attr and not Archive;
	SetFAttr(DosFile, Attr);
end;



{Has to be able to read forms w/o frequent CR's - eg WP headers}
procedure TWPStream.PrintForm(FormName : FNameStr);
const
	BlockSize = 100;

type
	TBlock = array[1..BlockSize] of char; {careful, if we make it char and
	treat it as a string, it will be treated as a nul-terminated string...}

var
	Block : TBLock;
	FormFile : file of TBlock;
	FormFileSize : longint;

	LString : TLongString;
	OutString : string;
	BlockNo : longint;
	DocStart : longint;
	B : byte;

	procedure ReadBlock;
	begin
{$I-}
		FillChar(Block, BlockSize, #0); {so that when it reads past end, the surplus is nul}
		System.Read(FormFile, Block);
		inc(BlockNo);

		{Check for error reading}
		ErrorInfo := IOResult;
		if (ErrorInfo<>0) and (ErrorInfo<>100) then begin {No problem, or Read passed end of file}
			ProgramWarning('Could not read form '+FormName+#13#10+IOError(ErrorInfo),hcIOErrorMsg);
			Status := stFormReadError;
		end;
{$I+}
	end;


begin
	FormFound := False;

	if (Status<>stOK) or (FormName='') or (FormName[1] ='.') then exit;

{$I-}
	ErrorInfo := IOResult; {Clear IOResult}
	if Pos('\',FormName)=0 then FormName := WPSetup.FormsPath+FormName;  {If no path specified, go for wp path}

	FormFileSize := GetFileSize(FormName); {get size of file, see doslink, returns <0 error if not found}

	if (FormFileSize<0) then begin
		{--- WP Form not found ----}
		{can substitute text one if there is.  This will screw up if the first
		form is non-wp and a subsequent one *is* wp...}
		if GetPath(FormName)<>FormsPath then
			{is it a header or form}
			if (pos('.HD',GetFileName(FormName))>0) or (pos('.FT',GetFileName(FormName))>0) then begin
				{header}
				if WPSetup.SubsHdrs then PrintForm(FormsPath+GetFileName(FormName));
			end else begin
				{form}
				if WPSetup.SubsFrms then PrintForm(FormsPath+GetFileName(FormName));
			end;

		exit; {false formfound already set above}
	end;

	FormFound := True;

	{open form file to read from}
	Assign(FormFile, FormName);
	System.Reset(FormFile); {Open file of blocks}

		BlockNo := 0;
		LSNew(LString);
		OutString := '';
		DocStart := 0;

		{Read first block to get document size, etc}
		ReadBlock;
		if Copy(Block,1,4)=#255+'WPC' then {wordperfect file}
			for B := 8 downto 5 do
				DocStart := (DocStart * $100) + ord(Block[B]);

		{Now read in rest of header, writing (but not decoding) if it is the
		first form}
		{NB, BlockNo is 1-based, so BlockNo*Blocksize = last byte read, assuming
		"byte read" is 1-based, whereas docstart is 0-based, so blockno*blocksize
		is actually the 0-based position of the *next* byte to be read...}
		while BlockNo*BlockSize<=DocStart do begin
			if FirstForm then begin
				{write blocks as we go along}
				LSAppendBlock(LString, Block,0,BlockSize);
				WriteLStr(LString);
				LSClear(LString);
			end;

			ReadBlock;
		end;

		{we now have a Block that countains some pre-docstart and some post-docstart
		chars - post docstart needs decoding}
		B := (DocStart mod BlockSize);
		if FirstForm then begin
			LSAppendBlock(LString, Block, 0, B);
			WriteLStr(LString);
			LSClear(LString);
		end;

		LSAppendBlock(LString, Block, B, BlockSize-B);

		{We now have lstring as the first part of the document itself}
		FirstForm := False; {so that including forms work}

		while (not eof(FormFile)) and (Status = stOK)  do begin
			ReadBlock;

			{output}
			LSAppendBlock(LString, Block, 0, BlockSize);
			WriteCodedBlock(LString, '');
		end; {end while}

		{Print last bit}
		if (LSLen(LString)>0) and (Status=stOK) then begin
			writeCodedBlock(LString,''); {make sure the remains gets decoded properly, eg in case above while is not done}
			WriteLStr(LString); {write remaining 50 bytes}
		end;

		System.Close(FormFile);
{$I+}
end;


procedure TWPstream.StartPrint(NHeaderName1,NHeaderName2 : FNameStr);
begin
	FirstForm := True;
	inherited StartPrint(NHeaderName1, NHeaderName2);
end;

procedure TWPStream.EndPrint;
begin
	{avoids putting FF on last page}
	LastPage := True;
	if Status=stOK then EndPage;

	{need to keep faxto codes...?}

	if not KeepOpen then begin
		Close;

		{Call WP?}
		if AutoSend then Send;
	end else
		FeedPage;

	ClearCOdes; {do this after send, as fax number may be required}
	Active := False;

end;

procedure TWPStream.Send;
begin
	if Status=stOK then begin
		if IsOpen then Close;

		if SendAsFax then begin
			{--- Fax ---------------}
			ErrorInfo := FaxWPFile(DosFileName);
		end else begin
			{--- Ordinary print ----}
			ErrorInfo := PrintWPFile(DosFileName);
		end;
		if ErrorInfo<>0 then Status := stFormOpenError; {not quite right but it will do}
	end;
end;

procedure TWPStream.FeedPage;
begin
	if Status=stOK then begin  {Form feed, reset variables}
		DeviceWrite(#12); { add only CR to start in col 1, and use DeviceWrite to avoid left margn spaces}
		CheckStatus('Feeding Page');
	end;
end;

{*************************************************************************
 **                                                                    ***
 **                   DEFERRED LETTERS/LABELS                          ***
 **                                                                    ***
 *************************************************************************}


{************************************************************************
 ***                   PRINT DEFERRED WP LETTERS                      ***
 ************************************************************************}
procedure PrintDeferredWPLetters;
var Control : word;
		NoLtrs : word;
begin
{	NoLtrs := GetNoDeferredLtrs(WPSetup.Path);
	if NoLtrs=0 then
		PauseMessage('No WP Letters to print','')
	else begin
		Control := ConfirmMessage('About to print WP letters',L2Str(NoLtrs)+' to print');
		if Control = cmYes then CallWP('',WPSetup.PrintDeferredMacro);
	end{}
end;

procedure DeleteDeferredWPLetters;
var Control : word;
		NoLtrs : word;
		LtrNo : word;
		LtrName : string;
begin
{	NoLtrs := GetNoDeferredLtrs(WPSetup.Path);
	if NoLtrs=0 then
		PauseMessage('No WP Letters to delete','')
	else begin
		Control := ConfirmMessage('About to delete WP letters','');
		if Control = cmYes then begin
			ThinkingOn('Deleting');
			for LtrNo := 1 to NoLtrs do begin
				LtrName := 'DFR'+PadZero(L2Str(LtrNo),4)+'.LTR';
				DeleteFile(WPSetup.Path+LtrName);  {in doslink - uses DOS interrupt}
{			end;
			ThinkingOff;
		end;
	end{}
end;

{************************************************************************
 ***                   PRINT DEFERRED WP LABELS                       ***
 ************************************************************************}
procedure PrintDeferredWPLabels(FileName : string; PrintDEtails : TPrintDetails);
var	WPStream : PWPStream;
		LabelFile : text;
		Line : string;
		I : integer;

begin
	{convert deferred label file to wp file}
	Assign(LabelFile, FileName);
	reset(LabelFile);

	New(WPStream, init(WPSetup.Path+'LABELS'));

	{Do WP header}
	WPStream^.StartPrint('',WPSetup.FormsPath+PrintDetails.LabelsFName+'.LFM');
{ not required any more due to autocheck while inputting?}
	if not WPStream^.FormFound then begin
		ProgramWarning('No WP Label header found'+#13#10+
									'Create WP file '+ucase(PrintDetails.LabelsFName)+'.LFM in '+WPSetup.FormsPath+' as label header',
									hcFileNotFoundMsg);
		exit;
	end;{}

	{Calculate starting pos}
	{Assumes current label filter matches WP label setup in terms of rows, cols}
	for I := 1 to ((PrintDEtails.Row-1){*Printer.Labels^.Columns} + PrintDetails.Col-1) do begin
		WPStream^.Writeln(''); {blank line}
		WPStream^.Writeln(FF);
	end;{}

	{copy in label data file}
	while not eof(LabelFile) do begin
		Readln(LabelFile, Line);
		if not eof(LabelFile) then WPStream^.Writeln(Line); {don't print last FF}
	end;

	WPStream^.EndPrint; {tidy up}

	dispose(WPStream, done);

	{Clear file}
{	Rewrite(LabelFile);{}
	close(LabelFile);{}

	{Print 'em out}
	CallWP(WPSetup.Path+'LABELS', WPSetup.PrintMacro);
end;



{****************************************************
 ***          PRINT DEFERRED LETTERS              ***
 ****************************************************}

procedure WPLinkPrintDeferredLetters; far;
begin
{	PrintDeferredLetters; {in KLetters, then go on to}

	{Print WP letters}
	PrintDeferredWPLetters;
end;

procedure WPLinkDeleteDeferredLetters;
begin
{	DeleteDeferredLetters; {in KLetters, then go on to}

	{Print WP letters}
	DeleteDeferredWPLetters;
end;

procedure EditWPSetup; far;
begin	WPSetup.Edit; end;


procedure StartWPStream; far;
begin
	New(WPStream, init(WPSetup.LocalPath+'WPSTREAM.$$$'));
	WPStream^.Permanant := True;
end;

procedure ShutWPStream; far;
begin
	if WpStream<>nil then begin
		WPStream^.Permanant := False;
		Dispose(WPStream, done);
		WPStream := nil;
	end;
end;

procedure InitWPPrinter; far;
begin
	if WPSetup.InitMacro='' then
		ProgramWarning('No WP Initialisation Macro',hcNoWPMacroMsg)
	else
		WPStream^.Initialise;
end;


{***************************************************
 ***              REPRINT REPORT                 ***
 ***************************************************}
procedure PrintLastWPReport; far;
begin
	CallWP(WPSetup.LocalPath+'WPSTREAM.$$$', WPSetup.PrintMacro);
end;

{**************************************
 ***       INITIALISER              ***
 **************************************}

begin
{$IFDEF kwplink}
{$IFDEF fixit} writeln('KWPLink...'); {$ENDIF}

	WPSetup.Init('Word Perfect');
	RegisterTask(DesktopTasks, cmEditWPSetup, @EditWPSetup);

	{Register form writing task}
	RegisterTask(DesktopTasks, cmEditWPForm, @EditWPForm);
	RegisterTask(DesktopTasks, cmPrintLastWPReport, @PrintLastWPReport);
	RegisterTask(DesktopTasks, cmInitWPPrinter, @InitWPPrinter);

	{replace standard deferred letter print with WPLink version}
{	ReplaceTask(DesktopTasks, cmDeferredLetters, @WPLinkPrintDeferredLetters);
	ReplaceTask(DesktopTasks, cmDeleteDeferredLetters, @WPLinkDeleteDeferredLetters);{}

	WPStream := nil;
	RegisterTask(StartupTasks,10,@StartWPStream);
	RegisterTask(ShutDownTasks, 10, @ShutWPStream);

	LastWPFormFileName := 'LETTER.HDR';

{$IFDEF fixit} writeln('..done'); {$ENDIF}
{$ENDIF}
end.
