-- file: IntPress.Mesa
-- edited by Brotz, January 28, 1981 5:40 PM
-- edited by Schroeder, 28-Oct-80 11:17:06

DIRECTORY
Ascii,
csD: FROM "CoreStreamDefs",
DMSTimeDefs,
EFTPDefs,
exD: FROM "ExceptionDefs",
Inline,
intCommon: FROM "IntCommon",
LaurelHardcopyDefs,
lsD: FROM "LaurelStateDefs",
ovD: FROM "OverviewDefs",
PupDefs,
PupTypes,
Stream,
StringDefs,
TimeDefs;

IntPress: PROGRAM
IMPORTS csD, DMSTimeDefs, EFTPDefs, exD, Inline, intC: intCommon,
LaurelHardcopyDefs, lsD, PupDefs, StringDefs, TimeDefs
EXPORTS LaurelHardcopyDefs = PUBLIC

BEGIN

OPEN LaurelHardcopyDefs;

nPressFilePages: CARDINAL = 240;

pressStream: csD.StreamHandle;
nPressBufferPages: CARDINAL = 2;

partDirectoryStream: csD.StreamHandle;
nPartDirectoryBufferPages: CARDINAL = 2;

entityListStream: csD.StreamHandle;
nEntityListBufferPages: CARDINAL = 1;

dlStartPosition: csD.Position;

who: PupDefs.PupAddress;


WriteCommandAndMica: PROCEDURE [com: Byte, val: Mica] =
BEGIN
q, r: CARDINAL;
[q, r] ← Inline.DIVMOD[val, 400B];
WriteEntityByte[com];
WriteEntityByte[q];
WriteEntityByte[r];
END; -- of WriteCommandAndMica --


WriteEntityByte: PROCEDURE [val: Byte] = INLINE {csD.Write[entityListStream, val]};


WritePressByte: PROCEDURE [val: Byte] = INLINE {csD.Write[pressStream, val]};


WritePressString: PROCEDURE [string: STRING, nChars: CARDINAL] =
BEGIN
length: CARDINAL = MIN[string.length, nChars];
i: CARDINAL;
WritePressByte[length];
FOR i IN [0 .. length) DO
WritePressByte[LOOPHOLE[string[i]]];
ENDLOOP;
THROUGH [length .. nChars) DO
WritePressByte[0];
ENDLOOP;
END; -- of WritePressString --


AdvancePressStreamToNextPage: PROCEDURE RETURNS[incr:CARDINAL] =
BEGIN
p: csD.Position = csD.GetPosition[pressStream];
incr ← ((512 - Inline.LowHalf[p MOD 512]) MOD 512);
csD.SetPosition[pressStream, p+incr];
END; --of AdvancPressStreamToNextPage--


InitPressPage: PROCEDURE =
-- Initializes state variables.
BEGIN
dlStartPosition ← csD.GetPosition[pressStream];
END; -- of InitPressPage --


FinishPressPage: PROCEDURE =
-- Completes the current page part by pushing out the entity list onto the pressStream and
-- by adding a new entry to the part directory.
BEGIN
partDirectoryEntry: PartDirectoryEntry;
entityTrailer: EntityTrailer ← EntityTrailer
[entityType: 0,
fontSet: 0,
beginByteHigh: 0,
beginByteLow: 0,
byteLengthHigh: 0,
byteLengthLow: Inline.LowHalf[csD.GetPosition[pressStream] - dlStartPosition],
ye: 0,
xe: 0,
left: 0,
bottom: 0,
width: 8 * inch + inch/2,
height: 11 * inch,
entityLength: Inline.LowHalf[(csD.GetPosition[entityListStream] + 1) / 2 + SIZE[EntityTrailer]]];
IF csD.GetPosition[pressStream] MOD 2 = 1 THEN WritePressByte[377B];
WritePressByte[0];
WritePressByte[0];
IF csD.GetPosition[entityListStream] MOD 2 = 1 THEN WriteEntityByte[377B];
csD.SetPosition[entityListStream,0];
csD.StreamCopy[entityListStream, pressStream, csD.GetLength[entityListStream]];
csD.WriteBlock[pressStream, LOOPHOLE[@entityTrailer], 0, 2*SIZE[EntityTrailer]];
csD.Reset[entityListStream];

partDirectoryEntry ← PartDirectoryEntry
[partType: 0,
recordStart: Inline.LowHalf[dlStartPosition/512],
nRecords: 0, -- fill in later --
entityListPadding: AdvancePressStreamToNextPage[]/2];
partDirectoryEntry.nRecords ← Inline.LowHalf[(csD.GetPosition[pressStream] - dlStartPosition)/512];
csD.WriteBlock[partDirectoryStream, LOOPHOLE[@partDirectoryEntry],
0, SIZE[PartDirectoryEntry]];
END; -- of FinishPressPage --


FinishPressFile: PROCEDURE [chunk: CARDINAL] =
-- Completes the press file by pushing out the font directory, the part directory, and the
-- document directory.
BEGIN
partDirStartPosition: csD.Position;
pressFileName: STRING ← "Mail, part x"L;
userNameString: STRING ← [31];
timeString: STRING ← [39];
-- don’t change this limit!
i: CARDINAL;
pt: DMSTimeDefs.PackedTime;
fontDirectory: FontDirectory;
documentDirectoryHeader: DocumentDirectoryHeader;

partDirectoryEntry: PartDirectoryEntry ← PartDirectoryEntry
[partType: 1,
recordStart: Inline.LowHalf[csD.GetPosition[pressStream]/512],
nRecords: intC.fontDirectorySegment.pages,
entityListPadding: 177777B];
fontDirectory ← lsD.SwapInStateSegment[intC.fontDirectorySegment];
csD.WriteBlock[pressStream, LOOPHOLE[fontDirectory], 0, SIZE[FontDirectoryRec] * 2];
lsD.ReleaseStateSegment[intC.fontDirectorySegment];
[] ← AdvancePressStreamToNextPage[];
partDirStartPosition ← csD.GetPosition[pressStream];
csD.WriteBlock[partDirectoryStream, LOOPHOLE[@partDirectoryEntry],
0, SIZE[PartDirectoryEntry]];
csD.SetPosition[partDirectoryStream, 0];
csD.StreamCopy[partDirectoryStream, pressStream, csD.GetLength[partDirectoryStream]];
[] ← AdvancePressStreamToNextPage[];

documentDirectoryHeader ← DocumentDirectoryHeader[
generalPassword: 27183,
nRecordsInFile: Inline.LowHalf[csD.GetPosition[pressStream]/512] + 1,
nParts: Inline.LowHalf[csD.GetLength[partDirectoryStream] / SIZE[PartDirectoryEntry]],
partDirectoryStartRecord: Inline.LowHalf[partDirStartPosition/512],
nRecordsInPartDirectory: Inline.LowHalf[(csD.GetPosition[pressStream] - partDirStartPosition)/512],
obsoleteBackPointer: 0,
unused1: DMSTimeDefs.currentTime.highbits,
unused2: DMSTimeDefs.currentTime.lowbits,
firstCopy: 1,
lastCopy: intC.hardCopies];
csD.Reset[partDirectoryStream];
csD.WriteBlock[pressStream, LOOPHOLE[@documentDirectoryHeader],
0, SIZE[DocumentDirectoryHeader] * 2];
THROUGH [20 .. 256) DO
WritePressByte[377B];
ENDLOOP;
IF chunk = 1 THEN pressFileName.length ← 4
ELSE {pressFileName.length ← 12; pressFileName[11] ← ’0 + chunk MOD 10};
WritePressString[pressFileName, 51];

userNameString.length ← 0;
FOR i IN [0 .. intC.hardcopyUserName.length) DO
IF intC.hardcopyUserName[i] = ’$ THEN
StringDefs.AppendString[userNameString, intC.user.name
! StringDefs.StringBoundsFault => EXIT]
ELSE StringDefs.AppendChar[userNameString, intC.hardcopyUserName[i]
! StringDefs.StringBoundsFault => EXIT];
ENDLOOP;
WritePressString[userNameString, 31];

pt.lc ← TimeDefs.CurrentDayTime[];
DMSTimeDefs.MapPackedTimeToTimeZoneString[pt, timeString];
WritePressString[timeString, 39];

THROUGH [380 .. 512) DO
WritePressByte[0];
ENDLOOP;

END; -- of FinishPressFile --


PrintPressString: PROCEDURE [string: STRING, fontNumber: CARDINAL, x, y: Mica, segTable: POINTER TO LineSegmentTable] =
-- Puts string into the press file entity list and data list.
BEGIN
start, end: CARDINAL ← 0;

PrintSubString: PROCEDURE [x, y: Mica, start, length: CARDINAL] =
BEGIN
IF length = 0 THEN RETURN;
WriteCommandAndMica[setXCom, x];
WriteCommandAndMica[setYCom, y];
-- output string data
csD.WriteBlock[pressStream, LOOPHOLE[@string.text], start, length];
-- output string description
IF length <= 32 THEN
WriteEntityByte[showCharactersShortCom + length - 1]
ELSE {WriteEntityByte[showCharactersCom]; WriteEntityByte[length]};
END; -- of PrintSubString --

IF segTable = NIL THEN PrintSubString[x, y, 0, string.length]
ELSE
FOR i: CARDINAL IN [0 .. 12) UNTIL end = string.length DO
start ← end;
end ← segTable[i + 1].index;
PrintSubString[segTable[i].x, y, start, end - start];
ENDLOOP;
END; -- of PrintPressString --


SetCurrentPressFont: PROCEDURE [font: FontNumber] =
-- Sets font in the press file entity list.
BEGIN
WriteEntityByte[fontCom + font];
WriteEntityByte[setSpaceXCom];
WriteEntityByte[0];
WriteEntityByte[widthTable[font][Ascii.SP]];
END; -- of SetCurrentPressFont --



-- ************************
-- Press File Transmission
-- ************************


FindPrinter: PROCEDURE RETURNS [error: ovD.ErrorCode] =
-- Locates printer to which press file will be sent. Returns ok if found, cantConnect if not.
BEGIN
error ← ovD.ok;
who ← [ , , PupTypes.eftpReceiveSoc];
PupDefs.GetPupAddress[@who, intC.hardcopyHost !
PupDefs.PupNameTrouble =>
BEGIN
exD.DisplayBothExceptionLines[NIL, exD.cantFindPrinter, e, exD.nil];
error ← ovD.cantConnect;
CONTINUE
END];
END; -- of FindPrinter --


TimeToSend: PROCEDURE RETURNS [BOOLEAN] =
-- Returns TRUE iff press file exceeds maximum length.
BEGIN
RETURN[csD.GetPosition[pressStream]/512 > nPressFilePages];
END; -- of TimeToSend --


SendPressFile: PROCEDURE =
-- Uses EFTP to send the current press file to the current hardcopy host.
BEGIN
OPEN EFTPDefs, StringDefs;
bytesInPressStream: csD.Position = csD.GetPosition[pressStream];
utilityString: STRING ← [80];

BEGIN -- block for error exits
EFTPOpenForSending[who !
EFTPTimeOut =>
BEGIN
exD.DisplayBothExceptionLines[NIL, exD.printerNotRespond, NIL,
exD.cancelHardcopy, FALSE];
CheckForAbort[ ! AbortHardcopy => GO TO AbortSend];
-- sees DEL (or CANCEL) on second timeout
RESUME
END;
EFTPTroubleSending =>
IF e = eftpReceiverBusyAbort THEN
BEGIN
exD.DisplayBothExceptionLines[s, exD.printerBusy, NIL, exD.cancelHardcopy,
FALSE];
CheckForAbort[ ! AbortHardcopy => GO TO AbortSend];
-- sees DEL (or CANCEL) on second signal
RETRY
END
ELSE BEGIN
exD.GetExceptionString[exD.cannotConnectToPrinter, utilityString];
AppendString[utilityString, intC.hardcopyHost];
IF s ~= NIL AND s.length > 0 THEN
BEGIN
AppendString[utilityString, ": "L];
AppendString[utilityString, s];
END;
exD.DisplayBothExceptionLines[utilityString, exD.nil, NIL, exD.hardcopyCanceled];
GO TO KillSend
END
];
exD.GetExceptionString[exD.transmissionTo, utilityString];
AppendString[utilityString, intC.hardcopyHost];
exD.AppendExceptionString[exD.proceeding, utilityString];
exD.DisplayExceptionStringOnLine[utilityString, 1];

BEGIN
ENABLE
BEGIN
EFTPTimeOut =>
BEGIN
exD.DisplayBothExceptionLines[NIL, exD.printerTimeout, NIL, exD.hardcopyCanceled];
GO TO KillSend
END;
EFTPTroubleSending =>
BEGIN
exD.GetExceptionString[exD.printerTrouble, utilityString];
IF s # NIL THEN AppendString[utilityString, s ! StringBoundsFault => CONTINUE];
exD.DisplayBothExceptionLines[utilityString, exD.nil, NIL, exD.hardcopyCanceled];
GO TO KillSend
END
END;
IF intC.twoSidedPrinting THEN SendSpruceString["((DUPLEX TRUE))"L];
IF intC.passwordPrinting THEN
BEGIN
string: STRING ← [60];
StringDefs.AppendString[string, "((HOLD "L];
StringDefs.AppendString[string, intC.user.password];
StringDefs.AppendString[string, "))"L];
SendSpruceString[string];
END;
csD.SetPosition[pressStream, 0];
csD.ReadStream[pressStream, bytesInPressStream, SendPressStreamBlock];
csD.SetPosition[pressStream, 0];
CheckForAbort[ ! AbortHardcopy => GO TO AbortSend];
EFTPFinishSending[];
END;

RETURN;

EXITS
KillSend => aborted ← laurel;
AbortSend => NULL;
END;

EFTPAbortSending[""L];
ERROR AbortHardcopy

END; -- of SendPressFile --


SendPressStreamBlock: PROCEDURE[s: Stream.Block] =
{EFTPDefs.EFTPSendBlock[Inline.LowHalf[s.blockPointer+s.startIndex/2], s.stopIndexPlusOne-s.startIndex]};

SendSpruceString: PROCEDURE [s: STRING] =
BEGIN
hackArray: POINTER TO ARRAY [0 .. 1] OF CARDINAL ← LOOPHOLE[s];
length, maxLength: CARDINAL;
length ← hackArray[0];
maxLength ← hackArray[1];
hackArray[0] ← 125314B;
hackArray[1] ← 170377B;
EFTPDefs.EFTPSendBlock[hackArray, 2 * StringDefs.WordsForString[length]];
hackArray[0] ← length;
hackArray[1] ← maxLength;
END; -- of SendSpruceString --


OpenPressStreams: PROCEDURE =
-- Opens streams used during press file construction.
BEGIN
pressStream ← csD.OpenFromName["Swatee"L,intC.user, byte, write, nPressBufferPages];
partDirectoryStream ← csD.Open[NIL, word, write, nPartDirectoryBufferPages];
entityListStream ← csD.Open[NIL, byte, write, nEntityListBufferPages];
END; -- of OpenPressStreams --


ClosePressStreams: PROCEDURE =
-- Closes streams used during press file construction.
BEGIN
csD.Destroy[entityListStream];
csD.Destroy[partDirectoryStream];
csD.Destroy[pressStream];
END; -- of ClosePressStreams --


END. -- of IntPress --