DIRECTORY
BansheeTest USING [RunRepairMode, RunServeTestMode],
BasicTime USING [GetGMT, GetUniversalID, gmtEpoch, GMT, NetworkAddress, SecondsSinceEpoch],
ControlMessages USING [Key],
D1Test USING [RunRepairMode, RunServeTestMode],
DecomposerControl USING [DocumentInProgress, SetBannerMode, Status, UnloadOldFonts],
FaxTest USING [RunServeTestMode],
FontConverter USING [ConvertFontFile, CreateResources, DestroyResources, ErrorCode],
ForwardingControl USING [SetTargetPrintService],
FX3500Test USING [RunRepairMode, RunServeTestMode],
MarkerControl USING [EngineSpecific],
NSAssignedTypes USING [FileType],
NSDataStream USING [Source],
NSFile USING [Attribute, AttributesProc, ChangeAttributes, Close, Create, Delete, DeleteByName, Error, Handle, ID, List, Move, neverBackup, nullHandle, nullID, OpenByName, OpenChild, Replace, Scope, Selections, Session, Store, Time],
NSName USING [Name],
NSString USING [AppendString, EquivalentStrings, nullString, String, StringFromMesaString],
PaperHandling USING [Banner, PaperFeed, PaperStacking, PaperSupply, PrintOrder, Registration],
PaperTypes USING [PaperMMDimension],
PrintQueue USING [CopyStringIn, nilQueueObjectHandle, QueueObjectHandle, Requeue],
PSAssignedTypes USING [tFont200Rotated90, tFont300Rotated0, tFont300Rotated90, tTestPatterns],
PSAsyncMsg USING [ExpandArrayAndPutString, Insert],
PSCommand USING [allFiles, allFontPackages, Error, FaxTransmissionRetryReason, FileType, FileProc, FileFilter, FontFilter, FontProc, FontType, maxPhoneNoLength, PrintFileOptions],
PSCommandInternal USING [DisablePrinting, DisableQueuing, EnablePrinting, EnableQueuing, fontsNoticed, markerProcs, PutAsyncMsgFromKey, state, stateSpace, testPatternsNoticed],
PSKMessages USING [GetHandle],
PSState USING [OperationState],
PSVolume USING [Error, GetDefaultSession, GetDirectory],
RavenTest USING [RunRepairMode, RunServeTestMode],
Space USING [ForceOut],
String USING [AppendDecimal, AppendLongDecimal],
TargetPS USING [Error, GetPrinterProperties, GetPrinterStatus],
TargetPSStatus USING [Communication, Current, Properties],
TestPattern USING [CatalogTPs, Locate, NotFound],
XMessage USING [Handle, MsgKey];
PSCommandBImpl:
CEDAR
MONITOR
IMPORTS BansheeTest, D1Test, DecomposerControl, FaxTest, FontConverter, ForwardingControl, FX3500Test, NSFile, NSString, PrintQueue, PSAsyncMsg, PSCommand, PSCommandInternal, PSKMessages, PSVolume, RavenTest, Space, String, System, TargetPS, TestPattern
EXPORTS PSCommand, PSCommandInternal = BEGIN
OPEN PSCommandInternal;
session: NSFile.Session = PSVolume.GetDefaultSession[];
nsNil: NSString.String = NSString.nullString;
Message domain handle:
controlMsgs: XMessage.Handle ← PSKMessages.GetHandle[control];
===============================
PUBLIC PROCEDURES:
===============================
======================================
Font Operations:
======================================
ListFonts:
PUBLIC
PROCEDURE [proc: PSCommand.FontProc,
filter: PSCommand.FontFilter ← PSCommand.allFontPackages] = BEGIN --NOT MONITORED
dirH: NSFile.Handle ← NSFile.nullHandle;
selections: NSFile.Selections = [[createdOn: TRUE, dataSize: TRUE, name: TRUE, type: TRUE]];
scope: NSFile.Scope ← [];
nameAttribute: name NSFile.Attribute;
ListFontPackage: NSFile.AttributesProc =
BEGIN
[attributes] RETURNS [continue]--
It is TBD how we will tell one font type from another when we have font types other that cdFont. In the current implementation font type in the filter is ignored.
continue ← proc[cdFont, attributes.name, attributes.dataSize, attributes.createdOn];
END; --ListFontPackage
dirH ← PSVolume.GetDirectory[
SELECT state.option
FROM
bansheeDl, d1 => PSAssignedTypes.tFont300Rotated90,
Both rotated and unrotated banshee fonts will get listed since tFont300Rotated90 and tFont300Rotated0 fonts are in the same directory.
fax295, fax495 => PSAssignedTypes.tFont200Rotated90,
fx3500, feps9700, raven => PSAssignedTypes.tFont300Rotated0,
ENDCASE => ERROR ! PSVolume.Error => GOTO Exit];
IF filter.packageName # nsNil
THEN
BEGIN
nameAttribute ← [name[filter.packageName]];
scope.filter ← [matches[nameAttribute]];
END;
NSFile.List[directory: dirH, proc: ListFontPackage, selections: selections, scope: scope, session: session];
EXITS Exit => NULL;
END; --ListFonts
InstallFont:
PUBLIC
PROCEDURE [
type: PSCommand.FontType, packageName: NSString.String,
createDate: NSFile.Time, data: NSDataStream.Source,
packageSizeHintInBytes: LONG CARDINAL ← 0] = BEGIN --MONITORED OPERATION
Font installed is assumed to be of correct format for current printing option!!
fileHandle, fontDir: NSFile.Handle;
newFile: BOOLEAN ← FALSE;
fontFileType: NSAssignedTypes.FileType ←
SELECT state.option
FROM
d1 => PSAssignedTypes.tFont300Rotated90,
fax295, fax495 => PSAssignedTypes.tFont200Rotated90,
bansheeDl, feps9700, fx3500, raven => PSAssignedTypes.tFont300Rotated0
Banshee fonts initially have type tFont300Rotated0 before they are rotated and the type is changed to tFont300Rotated90.
ENDCASE => ERROR;
IF packageName # NSString.nullString
AND data.type # none
THEN
BEGIN
CheckAndUpdateCurrentMode[fromMode: normal, toMode: fileWrite];
DecomposerControl.UnloadOldFonts[
! DecomposerControl.DocumentInProgress => {
ResetCurrentMode[];
ERROR PSCommand.Error[[documentInProgress[]]]}
];
PSCommandInternal.fontsNoticed ←
FALSE;
fontDir ← PSVolume.GetDirectory[fontFileType];
fileHandle ← NSFile.OpenByName[
fontDir, packageName, , session ! NSFile.Error =>
IF error = [access[fileNotFound]]
THEN {newFile ← TRUE; CONTINUE}
ELSE {ResetCurrentMode[]; REJECT}];
IF newFile
THEN
BEGIN
storeFileAttributes:
ARRAY [0..5)
OF NSFile.Attribute ← [
[createdOn[createDate]], [type[fontFileType]],
[name[packageName]], [backedUpOn[NSFile.neverBackup]],
[dataSize[packageSizeHintInBytes]]];
storeFileAttributesDesc: LONG DESCRIPTOR FOR ARRAY OF NSFile.Attribute ← DESCRIPTOR[NIL, 0];
IF packageSizeHintInBytes # 0 THEN
<<If a package size hint is provided, describe all the file attributes above,
including the dataSize attribute.>>
storeFileAttributesDesc ← DESCRIPTOR[storeFileAttributes]
ELSE
<<If no package size hint is provided, describe only the first four file
attributes, leaving off the dataSize attribute.>>
storeFileAttributesDesc ← DESCRIPTOR[BASE[storeFileAttributes], 4];
fileHandle ← NSFile.Store[
fontDir, data, storeFileAttributesDesc, , session !
NSFile.Error => {
ResetCurrentMode[];
SELECT error
FROM
[transfer[aborted]] =>
ERROR PSCommand.Error[[abortedByClient[]]];
[space[mediumFull]] =>
ERROR PSCommand.Error[[insufficientSpace[]]];
ENDCASE => ERROR PSCommand.Error[[systemError[]]]}
];
END
ELSE
BEGIN
--this font package already exist on the server
replaceFileAttributes:
ARRAY [0..2)
OF NSFile.Attribute ← [
[createdOn[createDate]], [dataSize[packageSizeHintInBytes]]];
replaceFileAttributesDesc: LONG DESCRIPTOR FOR ARRAY OF NSFile.Attribute ← DESCRIPTOR[NIL, 0];
IF packageSizeHintInBytes # 0 THEN
<<If a package size hint is provided, describe all the file attributes above,
including the dataSize attribute.>>
replaceFileAttributesDesc ← DESCRIPTOR[replaceFileAttributes]
ELSE
<<If no package size hint is provided, describe only the first file attribute,
leaving off the dataSize attribute.>>
replaceFileAttributesDesc ← DESCRIPTOR[BASE[replaceFileAttributes], 1];
NSFile.Replace[
fileHandle, data, replaceFileAttributesDesc, session !
NSFile.Error => {
ResetCurrentMode[];
SELECT error
FROM
[transfer[aborted]] =>
ERROR PSCommand.Error[[abortedByClient[]]];
[space[mediumFull]] =>
ERROR PSCommand.Error[[insufficientSpace[]]];
ENDCASE => ERROR PSCommand.Error[[systemError[]]]}
];
IF state.option = bansheeDl THEN BEGIN
<<Must change the file type of banshee font files back to PSAssignedTypes.tFont300Rotated0 when already loaded fonts are installed.
When the fonts were loaded initially they were rotated for banshee and the
file types were changed to PSAssignedTypes.tFont300Rotated90. Newly installed
fonts have not been rotated yet, so the file type must be changed back to PSAssignedTypes.tFont300Rotated0 (or we won't notice that the new fonts need to be rotated.>>
newFontTypeAttribute:
ARRAY [0..1)
OF NSFile.Attribute ←
[[type[PSAssignedTypes.tFont300Rotated0]]];
NSFile.ChangeAttributes [
file: fileHandle, attributes: DESCRIPTOR[newFontTypeAttribute],
session: session];
END;
END;
NSFile.Close[fileHandle, session];
ResetCurrentMode[]; --Also backs up the state record.
END
ELSE ERROR PSCommand.Error[[invalidParameters[]]];
END; --InstallFont
DeleteFont:
PUBLIC
PROCEDURE [packageName: NSString.String] =
BEGIN --MONITORED OPERATION
fontDir: NSFile.Handle;
IF packageName # NSString.nullString
THEN
BEGIN
CheckAndUpdateCurrentMode[fromMode: normal, toMode: fileDelete];
PSCommandInternal.fontsNoticed ← FALSE;
DecomposerControl.UnloadOldFonts[
! DecomposerControl.DocumentInProgress => {
ResetCurrentMode[];
ERROR PSCommand.Error[[documentInProgress[]]]}
];
fontDir ← PSVolume.GetDirectory[
SELECT state.option
FROM
bansheeDl, d1 => PSAssignedTypes.tFont300Rotated90,
fax295, fax495 => PSAssignedTypes.tFont200Rotated90,
feps9700, fx3500, raven => PSAssignedTypes.tFont300Rotated0,
ENDCASE => ERROR];
NSFile.DeleteByName[
fontDir, packageName, session ! NSFile.Error => {
ResetCurrentMode[];
IF error = [access[fileNotFound]]
THEN ERROR PSCommand.Error[[fileNotFound[]]]
ELSE REJECT}];
ResetCurrentMode[];
END
ELSE ERROR PSCommand.Error[[invalidParameters[]]];
END; --DeleteFont
Exported by PSCommandInternal:
RotateFonts90: PUBLIC PROCEDURE = BEGIN
Rotates installed fonts by 90 degrees. Currently used to rotate raven fonts for banshee.
dirH: NSFile.Handle ← NSFile.nullHandle;
selections: NSFile.Selections = [[fileID: TRUE, type: TRUE, createdOn: TRUE, name: TRUE]];
fontFileAttributes: ARRAY [0..3) OF NSFile.Attribute;
oldFontFile, newFontFile: NSFile.Handle ← NSFile.nullHandle;
fontConverterError: FontConverter.ErrorCode ← none;
insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert;
rotationActuallyAttempted: BOOLEAN ← FALSE;
fontsRotated: CARDINAL ← 0;
count: LONG STRING ← [10];
startRotation, endRotation: System.GMT ← System.gmtEpoch;
graphicsFontName: NSString.String = Str["Xerox.Graphics.Newvec"L];
Rotate90: NSFile.AttributesProc =
BEGIN
[attributes] RETURNS [continue]--
SELECT attributes.type FROM
If the font has raven font file type, rotate it for banshee...
PSAssignedTypes.tFont300Rotated0 => BEGIN
The Newvec font should not be rotated. We change the file
type to the banshee file type anyway so we won't have to
keep checking to see if it needs to be rotated...
IF NSString.EquivalentStrings[attributes.name, graphicsFontName]
THEN
BEGIN
newAttribute:
ARRAY [0..1)
OF NSFile.Attribute ←
[[type[PSAssignedTypes.tFont300Rotated90]]];
graphicsFontFile: NSFile.Handle ← NSFile.OpenChild[
directory: dirH, id: attributes.fileID, session: session];
NSFile.ChangeAttributes[
file: graphicsFontFile, attributes: DESCRIPTOR[newAttribute],
session: session];
NSFile.Close[file: graphicsFontFile, session: session];
RETURN [continue: TRUE]; --go on to other font files in directory
END;
<<Before rotating the first font, display a message indicating that font rotation is
starting. Also, unload all fonts so that unrotated font file can be deleted after new
one is created.>>
IF
NOT rotationActuallyAttempted
THEN
BEGIN
DecomposerControl.UnloadOldFonts[
! DecomposerControl.DocumentInProgress =>
ERROR PSCommand.Error[[documentInProgress[]]]];
PSCommandInternal.fontsNoticed ← FALSE;
insertArray[0] ← [m: [domain: controlMsgs, key: XKey[mBanshee]]];
PSCommandInternal.PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mBeginFontRotation]],
insertArray: DESCRIPTOR[insertArray]];
rotationActuallyAttempted ← TRUE;
Display name of font file being rotated...
insertArray[0] ← [s: attributes.name];
PSCommandInternal.PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mRotatingFont]],
insertArray: DESCRIPTOR[insertArray]];
fontFileAttributes[1] ← [createdOn[attributes.createdOn]];
fontFileAttributes[2] ← [name[attributes.name]];
oldFontFile ← NSFile.OpenChild[
directory: dirH, id: attributes.fileID, session: session];
Create temporary new font file, which will be made permanent
when rotation is completed...
newFontFile ← NSFile.Create[
directory: NSFile.nullHandle,
attributes:
DESCRIPTOR[fontFileAttributes], session: session
! NSFile.Error =>
BEGIN
NSFile.Close[file: oldFontFile, session: session];
Not enough space even for small temp file!
Display async error message...
insertArray[0] ← [m: [domain: controlMsgs,
key: XKey[mInsufficientVolSpace]]];
PSCommandInternal.PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mRotationError]],
insertArray: DESCRIPTOR[insertArray]];
GOTO Abort;
END;
];
fontConverterError ← FontConverter.ConvertFontFile[
session: session, fileOld: oldFontFile, fileNew: newFontFile,
rotationNew: 90 --degrees--, resolutionNew: dpi300];
IF fontConverterError = none
THEN
BEGIN
Move new font file to font directory, thus making the file permanent...
NSFile.Move[file: newFontFile, destination: dirH, session: session];
NSFile.Close[file: newFontFile, session: session];
Delete the old file...
NSFile.Delete[file: oldFontFile, session: session];
fontsRotated ← fontsRotated + 1;
END
ELSE
BEGIN
NSFile.Close[file: oldFontFile, session: session];
NSFile.Delete[file: newFontFile, session: session];
Display async error message...
insertArray[0] ← [m: [domain: controlMsgs,
key: XKey[SELECT fontConverterError FROM
noFileSpace => mInsufficientVolSpace,
ENDCASE => mUnknown]]];
PSCommandInternal.PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mRotationError]],
insertArray: DESCRIPTOR[insertArray]];
We will continue to list the rest of the font files installed
in case there are smaller ones that can be rotated successfully.
END;
END;
PSAssignedTypes.tFont300Rotated90 => NULL;
ENDCASE => ERROR;
EXITS Abort => RETURN [continue: FALSE];
END; --Rotate90
IF state.option # bansheeDl THEN ERROR;
IF DecomposerControl.Status[].decomposing
THEN
ERROR PSCommand.Error[[documentInProgress[]]];
dirH ← PSVolume.GetDirectory[PSAssignedTypes.tFont300Rotated0];
fontFileAttributes[0] ← [type[PSAssignedTypes.tFont300Rotated90]];
startRotation ← System.GetGMT[];
FontConverter.CreateResources[]; --gets file space for rotating fonts
Have NSFile enumerate each font in the directory and rotate the font if necessary...
NSFile.List[directory: dirH, proc: Rotate90, selections: selections, session: session];
FontConverter.DestroyResources[]; --releases file space used for rotating fonts
endRotation ← System.GetGMT[];
IF rotationActuallyAttempted
THEN
BEGIN
Display closing message giving number of font files rotated...
count.length ← 0;
String.AppendDecimal[s: count, n: fontsRotated];
insertArray[0] ← [s: Str[count]];
PSCommandInternal.PutAsyncMsgFromKey[
msg: [domain: controlMsgs, key: XKey[mRotationDone]],
insertArray: DESCRIPTOR[insertArray]];
Display rotation time if tracing is on...
IF state.formatterTrace # none
AND fontsRotated > 0
THEN
BEGIN
nsRotationTime: NSString.String ← Str[
"Total Rotation Time: <1> minutes, <2> seconds"L];
stringArray: ARRAY [0..2) OF NSString.String;
sMinutes: LONG STRING ← [10];
sSeconds: LONG STRING ← [10];
startSinceEpoch: LONG CARDINAL ← System.SecondsSinceEpoch[startRotation];
endSinceEpoch: LONG CARDINAL ← System.SecondsSinceEpoch[endRotation];
timeElapsed, minElapsed, secElapsed: LONG CARDINAL ← 0;
IF endSinceEpoch > startSinceEpoch
THEN
BEGIN
timeElapsed ← endSinceEpoch - startSinceEpoch;
minElapsed ← timeElapsed/60;
secElapsed ← timeElapsed MOD 60;
END;
String.AppendLongDecimal[sMinutes, minElapsed];
String.AppendLongDecimal[sSeconds, secElapsed];
stringArray[0] ← Str[sMinutes];
stringArray[1] ← Str[sSeconds];
PSAsyncMsg.ExpandArrayAndPutString[nsRotationTime, DESCRIPTOR[stringArray]];
END;
END;
END; --RotateFonts90
======= ======================================
File Operations (for Test Patterns, etc.):
=============================================
ListFiles:
PUBLIC
PROCEDURE [proc: PSCommand.FileProc, filter: PSCommand.FileFilter ← PSCommand.allFiles] =
BEGIN --NOT MONITORED
NOTE: Currently the only type of files that can be listed are test patterns. Must change code if new file types are added.
dirH: NSFile.Handle ← NSFile.nullHandle;
selections: NSFile.Selections = [[createdOn: TRUE, dataSize: TRUE, name: TRUE]];
scope: NSFile.Scope ← [];
nameAttribute: name NSFile.Attribute;
ListFile: NSFile.AttributesProc =
BEGIN
[attributes] RETURNS [continue]--
continue ← proc[testPattern, attributes.name, attributes.dataSize, attributes.createdOn];
END; --ListFile
dirH ← PSVolume.GetDirectory[PSAssignedTypes.tTestPatterns ! PSVolume.Error => GOTO Exit];
IF filter.name # nsNil
THEN
BEGIN
nameAttribute ← [name[filter.name]];
scope.filter ← [matches[nameAttribute]];
END;
NSFile.List[directory: dirH, proc: ListFile, selections: selections, scope: scope, session: session];
EXITS Exit => NULL;
END; --ListFiles
InstallFile:
PUBLIC
PROCEDURE [
type: PSCommand.FileType, name: NSString.String,
createDate: NSFile.Time, data: NSDataStream.Source,
fileSizeHintInBytes: LONG CARDINAL ← 0] =
The only kind of files this proc handles right now are test patterns.
BEGIN --MONITORED OPERATION
fileHandle, tpDirectory: NSFile.Handle;
newFile: BOOLEAN ← FALSE;
storeFileAttributes:
ARRAY [0..3)
OF NSFile.Attribute ← [
[createdOn[createDate]], [type[PSAssignedTypes.tTestPatterns]],
[name[name]]];
replaceFileAttributes:
ARRAY [0..1)
OF NSFile.Attribute ← [
[createdOn[createDate]]];
IF name # NSString.nullString
AND data.type # none
AND type = testPattern
THEN
BEGIN
CheckAndUpdateCurrentMode[fromMode: normal, toMode: fileWrite];
tpDirectory ← PSVolume.GetDirectory[PSAssignedTypes.tTestPatterns];
fileHandle ← NSFile.OpenByName[
tpDirectory, name, , session ! NSFile.Error =>
IF error = [access[fileNotFound]]
THEN {newFile ← TRUE; CONTINUE}
ELSE {ResetCurrentMode[]; REJECT}];
IF newFile
THEN
BEGIN
storeFileAttributes:
ARRAY [0..4)
OF NSFile.Attribute ← [
[createdOn[createDate]], [type[PSAssignedTypes.tTestPatterns]],
[name[name]], [dataSize[fileSizeHintInBytes]]];
storeFileAttributesDesc: LONG DESCRIPTOR FOR ARRAY OF NSFile.Attribute ← DESCRIPTOR[NIL, 0];
IF fileSizeHintInBytes # 0 THEN
<<If a file size hint is provided, describe all the file attributes above,
including the dataSize attribute.>>
storeFileAttributesDesc ← DESCRIPTOR[storeFileAttributes]
ELSE
<<If no file size hint is provided, describe only the first three file attributes,
leaving off the dataSize attribute.>>
storeFileAttributesDesc ← DESCRIPTOR[BASE[storeFileAttributes], 3];
fileHandle ← NSFile.Store[
tpDirectory, data,
LONG[
DESCRIPTOR[storeFileAttributes]], , session !
NSFile.Error => {
ResetCurrentMode[];
SELECT error
FROM
[transfer[aborted]] =>
ERROR PSCommand.Error[[abortedByClient[]]];
[space[mediumFull]] =>
ERROR PSCommand.Error[[insufficientSpace[]]];
ENDCASE => ERROR PSCommand.Error[[systemError[]]]}
]
END
ELSE
BEGIN
--this font package already exist on the server
replaceFileAttributes:
ARRAY [0..2)
OF NSFile.Attribute ← [
[createdOn[createDate]], [dataSize[fileSizeHintInBytes]]];
replaceFileAttributesDesc: LONG DESCRIPTOR FOR ARRAY OF NSFile.Attribute ← DESCRIPTOR[NIL, 0];
IF fileSizeHintInBytes # 0 THEN
<<If a file size hint is provided, describe all the file attributes above, including
the dataSize attribute.>>
replaceFileAttributesDesc ← DESCRIPTOR[replaceFileAttributes]
ELSE
<<If no file size hint is provided, describe only the first file attribute, leaving
off the dataSize attribute.>>
replaceFileAttributesDesc ← DESCRIPTOR[BASE[replaceFileAttributes], 1];
NSFile.Replace[
fileHandle, data,
LONG[
DESCRIPTOR[replaceFileAttributes]], session !
NSFile.Error => {
ResetCurrentMode[];
SELECT error
FROM
[transfer[aborted]] =>
ERROR PSCommand.Error[[abortedByClient[]]];
[space[mediumFull]] =>
ERROR PSCommand.Error[[insufficientSpace[]]];
ENDCASE => ERROR PSCommand.Error[[systemError[]]]}
];
END;
NSFile.Close[fileHandle, session];
PSCommandInternal.testPatternsNoticed ← FALSE;
ResetCurrentMode[];
END
ELSE ERROR PSCommand.Error[[invalidParameters[]]];
END; --InstallFile
DeleteFile: PUBLIC PROCEDURE [name: NSString.String] =
The only kind of files this proc handles right now are test patterns.
BEGIN --MONITORED OPERATION
tpDirectory: NSFile.Handle;
IF name # NSString.nullString
THEN
BEGIN
CheckAndUpdateCurrentMode[fromMode: normal, toMode: fileDelete];
tpDirectory ← PSVolume.GetDirectory[PSAssignedTypes.tTestPatterns];
NSFile.DeleteByName[
tpDirectory, name, session ! NSFile.Error => {
ResetCurrentMode[];
IF error = [access[fileNotFound]]
THEN ERROR PSCommand.Error[[fileNotFound[]]]
ELSE REJECT}];
PSCommandInternal.testPatternsNoticed ← FALSE;
ResetCurrentMode[];
END
ELSE ERROR PSCommand.Error[[invalidParameters[]]];
END; --DeleteFile
PrintFile:
PUBLIC
PROCEDURE [
fileName, senderName: NSString.String, copies: CARDINAL,
options: PSCommand.PrintFileOptions] = BEGIN --NOT MONITORED
fileID: NSFile.ID ← NSFile.nullID;
qOH: PrintQueue.QueueObjectHandle;
wrongPrintingOption, badPhoneNumber, badOptions: BOOLEAN ← FALSE;
WITH o: options
SELECT
FROM
fax495 => IF NOT o.localPrint AND NOT o.transmit THEN RETURN;
ENDCASE;
IF
NOT PSCommandInternal.testPatternsNoticed
THEN
BEGIN
TestPattern.CatalogTPs[];
PSCommandInternal.testPatternsNoticed ← TRUE;
END;
[fileID,] ← TestPattern.Locate[fileName !
TestPattern.NotFound => {ERROR PSCommand.Error[[fileNotFound[]]]}
];
qOH ← PrintQueue.Requeue[
qOH:, fromQueue: tpInactive, toQueue: temp]; -- so we can add info to it
IF qOH = PrintQueue.nilQueueObjectHandle
THEN
BEGIN
-- none in tpInactive queue???
qOH ← PrintQueue.Requeue[
qOH:, fromQueue: inactive, toQueue: temp];
IF qOH = PrintQueue.nilQueueObjectHandle THEN ERROR PSCommand.Error[[systemError[]]];
END;
qOH.fileID ← fileID;
qOH.uid ← System.GetUniversalID[]; --uid needed so that clients can delete tp jobs by listing documents and getting uid of job to cancel; uid is also used in DecomposerControlImpl
qOH.deleteInactiveFile ← FALSE;
PrintQueue.CopyStringIn[qOH: qOH, fromString: senderName, toField: sender];
PrintQueue.CopyStringIn[qOH: qOH, fromString: fileName, toField: fileName];
qOH.numberCopies ← copies;
qOH.currentStatus ← spooled;
qOH.firstPageToPrint ← 1;
qOH.lastPageToPrint ← LAST[CARDINAL];
WITH s: state
SELECT
FROM
bansheeDl =>
BEGIN
dStatus: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: dStatus
SELECT
FROM
bansheeDl => qOH.paper ← d.paper;
ENDCASE => ERROR;
END;
d1 => qOH.paper ← [knownSize: s.paperSize];
fax295 =>
WITH o: options
SELECT
FROM
fax295 =>
IF PaperTypes.PaperMMDimension[o.paperSize].short <= s.paperWidth
THEN
qOH.paper ← [knownSize: o.paperSize]
ELSE badOptions ← TRUE;
ENDCASE => wrongPrintingOption ← TRUE;
fax495 =>
WITH o: options
SELECT
FROM
fax495 =>
IF PaperTypes.PaperMMDimension[o.paperSize].short <= s.paperWidth
THEN
WITH q: qOH
SELECT
FROM
fax495 =>
BEGIN
char: CHARACTER;
blankChar: CHARACTER = ' ;
q.paper ← [knownSize: o.paperSize];
IF o.localPrint THEN q.localPrintStatus ← queued;
IF o.transmit
THEN
BEGIN
IF o.phoneNumber.length > PSCommand.maxPhoneNoLength
THEN badPhoneNumber ← TRUE
ELSE
BEGIN
q.phoneNoCount ← 1;
q.transmitData[0].status ← queued;
q.transmitData[0].phoneNumber.length ← o.phoneNumber.length;
FOR i:
CARDINAL
IN [0..o.phoneNumber.length)
DO
char ← LOOPHOLE[o.phoneNumber.bytes[i]];
SELECT char
FROM
IN ['0..'9], '-, '(, '), 'P, '*, '#, blankChar =>
q.transmitData[0].phoneNumber.bytes[i] ← o.phoneNumber.bytes[i];
ENDCASE => badPhoneNumber ← TRUE;
ENDLOOP;
END;
END;
END;
ENDCASE => ERROR --Queue object and state record do not agree on printing option.
ELSE badOptions ← TRUE;
ENDCASE => wrongPrintingOption ← TRUE;
feps9700 => qOH.paper ← [knownSize: s.paperSupply.size1];
fx3500 =>
WITH o: options
SELECT
FROM
fx3500 =>
BEGIN
dStatus: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: dStatus
SELECT
FROM
fx3500 =>
IF o.tray = top THEN qOH.paper ← [knownSize: d.paperSupply.size2]
ELSE
--tray = bottom or either (forced to bottom)
qOH.paper ← [knownSize: d.paperSupply.size1];
ENDCASE => ERROR;
END;
ENDCASE => wrongPrintingOption ← TRUE;
raven =>
WITH o: options
SELECT
FROM
raven =>
IF o.tray = top THEN qOH.paper ← [knownSize: s.paperSupply.size2]
ELSE
--tray = bottom or either (forced to bottom)
qOH.paper ← [knownSize: s.paperSupply.size1];
ENDCASE => wrongPrintingOption ← TRUE;
ENDCASE => wrongPrintingOption ← TRUE;
IF wrongPrintingOption
THEN
BEGIN
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: temp, toQueue: inactive];
ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
END;
IF badPhoneNumber
THEN
BEGIN
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: temp, toQueue: inactive];
ERROR PSCommand.Error[[invalidPhoneNumber[]]];
END;
IF badOptions
THEN
BEGIN
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: temp, toQueue: inactive];
ERROR PSCommand.Error[[parameterOptionNotAvailable[]]];
END;
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: temp, toQueue: tpSpooled];
state.testPatternsPrinted.total ← state.testPatternsPrinted.total + 1;
Space.ForceOut[stateSpace];
END; --PrintFile
=================================================
Set Operational Parameters: (NONE ARE MONITORED)
=================================================
****Apply to all printing options:****
SetBanner:
PUBLIC
PROCEDURE [banner: PaperHandling.Banner] =
BEGIN
WITH s: state
SELECT
FROM
bansheeDl =>
WITH b: banner
SELECT
FROM
bansheeDl =>
BEGIN
s.banner ← b.banner;
WITH m: markerProcs
SELECT
FROM
bansheeDl => m.setBanner[b.banner];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
DecomposerControl.SetBannerMode[
enableBanner: b.banner # suppressed];
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
d1 =>
WITH b: banner
SELECT
FROM
d1 =>
BEGIN
s.banner ← b.banner;
WITH m: markerProcs
SELECT
FROM
d1 => m.setBanner[b.banner];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
DecomposerControl.SetBannerMode[
enableBanner: b.banner # suppressed];
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
fax295 =>
WITH b: banner
SELECT
FROM
fax295 =>
BEGIN
s.banner ← b.banner;
WITH m: markerProcs
SELECT
FROM
fax295 => m.setBanner[b.banner];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
DecomposerControl.SetBannerMode[
enableBanner: b.banner # suppressed];
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
fax495 =>
WITH b: banner
SELECT
FROM
fax495 =>
BEGIN
s.banner ← b.banner;
WITH m: markerProcs
SELECT
FROM
fax495 => m.setBanner[b.banner];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
DecomposerControl.SetBannerMode[
enableBanner: b.banner.local # suppressed OR b.banner.remote # suppressed];
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
feps9700 => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
fx3500 =>
WITH b: banner
SELECT
FROM
fx3500 =>
BEGIN
s.banner ← b.banner;
WITH m: markerProcs
SELECT
FROM
fx3500 => m.setBanner[b.banner];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
DecomposerControl.SetBannerMode[
enableBanner: b.banner # suppressed];
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
raven =>
WITH b: banner
SELECT
FROM
raven =>
BEGIN
s.banner ← b.banner;
WITH m: markerProcs
SELECT
FROM
raven => m.setBanner[b.banner];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
DecomposerControl.SetBannerMode[
enableBanner: b.banner # suppressed];
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
ENDCASE => ERROR;
Space.ForceOut[stateSpace];
END; --SetBanner
SetPrintOrder:
PUBLIC
PROCEDURE [printOrder: PaperHandling.PrintOrder] =
BEGIN
state.printOrder ← printOrder;
markerProcs.setPrintOrder[state.printOrder];
Space.ForceOut[stateSpace];
END; --SetPrintOrder
****Apply to certain printing options:****
SetMultipleCopies:
PUBLIC
PROCEDURE [
multLocalCopiesAllowed, multRemoteCopiesAllowed: BOOLEAN] =
BEGIN --Applies to fax495
WITH s: state
SELECT
FROM
fax495 =>
BEGIN
s.multLocalCopiesAllowed ← multLocalCopiesAllowed;
s.multRemoteCopiesAllowed ← multRemoteCopiesAllowed;
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
WITH m: markerProcs
SELECT
FROM
fax495 => m.setMultipleCopies[multLocalCopiesAllowed, multRemoteCopiesAllowed];
ENDCASE => ERROR; --state and markerProcs disagree about printing option
Space.ForceOut[stateSpace];
END; --SetMultipleCopies
SetPaperFeed:
PUBLIC
PROCEDURE [paperFeed: PaperHandling.PaperFeed] =
BEGIN --Applies to raven and fx3500
WITH s: state SELECT FROM
raven =>
BEGIN
s.paperFeed ← paperFeed;
WITH m: markerProcs
SELECT
FROM
raven => m.setFeeding[paperFeed];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END;
fx3500 =>
BEGIN
s.paperFeed ← paperFeed;
WITH m: markerProcs
SELECT
FROM
fx3500 => m.setFeeding[paperFeed];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
Space.ForceOut[stateSpace];
END; --SetPaperFeed
SetPaperStacking:
PUBLIC
PROCEDURE [paperStacking: PaperHandling.PaperStacking] =
BEGIN --Applies to raven
WITH s: state
SELECT
FROM
raven =>
IF s.engineBuild > b1
THEN
BEGIN
s.paperStacking ← paperStacking;
WITH m: markerProcs
SELECT
FROM
raven => m.setStacking[paperStacking];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END
ELSE ERROR PSCommand.Error[[parameterOptionNotAvailable[]]];
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
Space.ForceOut[stateSpace];
END; --SetPaperStacking
SetPaperSupply: PUBLIC PROCEDURE [paperSupply: PaperHandling.PaperSupply] =
Currently the only valid paper sizes for the raven are letter, legal and a4. This code will have to be changed if other valid paper sizes are added.
BEGIN --Applies to raven, fax495 and fax295
WITH s: state
SELECT
FROM
raven =>
WITH p: paperSupply
SELECT
FROM
raven =>
BEGIN
SELECT p.paper.size1
FROM
letter, legal, a4 => s.paperSupply.size1 ← p.paper.size1;
ENDCASE => ERROR PSCommand.Error[[parameterOptionNotAvailable[]]];
SELECT p.paper.size2
FROM
letter, legal, a4 => s.paperSupply.size2 ← p.paper.size2;
ENDCASE => ERROR PSCommand.Error[[parameterOptionNotAvailable[]]];
WITH m: markerProcs
SELECT
FROM
raven => m.setPaper[s.paperSupply];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
fax295 =>
WITH p: paperSupply
SELECT
FROM
fax295 =>
BEGIN
SELECT p.paperWidth
FROM
PaperTypes.PaperMMDimension[letter].short, PaperTypes.PaperMMDimension[a4].short =>
s.paperWidth ← p.paperWidth;
ENDCASE => ERROR PSCommand.Error[[parameterOptionNotAvailable[]]];
WITH m: markerProcs
SELECT
FROM
fax295 => m.setPaper[s.paperWidth];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
fax495 =>
WITH p: paperSupply
SELECT
FROM
fax495 =>
BEGIN
SELECT p.paperWidth
FROM
PaperTypes.PaperMMDimension[letter].short, PaperTypes.PaperMMDimension[a4].short =>
s.paperWidth ← p.paperWidth;
ENDCASE => ERROR PSCommand.Error[[parameterOptionNotAvailable[]]];
WITH m: markerProcs
SELECT
FROM
fax495 => m.setPaper[s.paperWidth];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
Space.ForceOut[stateSpace];
END; --SetPaperSupply
SetRegistration:
PUBLIC
PROCEDURE [registration: PaperHandling.Registration] =
BEGIN --Applies to raven and fx3500
WITH s: state
SELECT
FROM
d1 =>
WITH r: registration
SELECT
FROM
d1 =>
BEGIN
s.registration ← r.reg;
WITH m: markerProcs
SELECT
FROM
d1 => m.setRegistration[r.reg];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
fx3500 =>
WITH r: registration
SELECT
FROM
fx3500 =>
BEGIN
s.registration ← r.reg;
WITH m: markerProcs
SELECT
FROM
fx3500 => m.setRegistration[r.reg];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
raven =>
WITH r: registration
SELECT
FROM
raven =>
BEGIN
s.registration ← r.reg;
WITH m: markerProcs
SELECT
FROM
raven => m.setRegistration[r.reg];
ENDCASE => ERROR; --Marker procs engine type disagrees with state record.
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
Space.ForceOut[stateSpace];
END; --SetRegistration
SetTransmissionResolution:
PUBLIC
PROCEDURE [fineResolutionSupported:
BOOLEAN] =
BEGIN --Applies to fax495
WITH s: state
SELECT
FROM
fax495 => s.fineResolutionSupported ← fineResolutionSupported;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
WITH m: markerProcs
SELECT
FROM
fax495 => m.setTransmissionResolution[fineResolutionSupported];
ENDCASE => ERROR; --state and markerProcs disagree about printing option
Space.ForceOut[stateSpace];
END; --SetTransmissionResolution
SetTransmissionRetries:
PUBLIC
PROCEDURE [
retries: CARDINAL, delayInSeconds: LONG CARDINAL,
reason: PSCommand.FaxTransmissionRetryReason ← always] =
BEGIN --Applies to fax495
WITH s: state
SELECT
FROM
fax495 =>
BEGIN
IF reason = noConnectionMade
OR reason = always
THEN
BEGIN
s.retries[noConnection].count ← retries;
s.retries[noConnection].delayInSecs ← delayInSeconds;
END;
IF reason = transmitError
OR reason = always
THEN
BEGIN
s.retries[transmitError].count ← retries;
s.retries[transmitError].delayInSecs ← delayInSeconds;
END;
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
WITH m: markerProcs
SELECT
FROM
fax495 =>
BEGIN
IF reason = noConnectionMade
OR reason = always
THEN
m.setTransmissionRetries[noConnection, retries, delayInSeconds];
IF reason = transmitError
OR reason = always
THEN
m.setTransmissionRetries[transmitError, retries, delayInSeconds];
END;
ENDCASE => ERROR; --state and markerProcs disagree about printing option
Space.ForceOut[stateSpace];
END; --SetTransmissionRetries
=============================================
Remote9700 Operation: (NONE ARE MONITORED)
=============================================
SetTargetPrintService:
PUBLIC
PROCEDURE [address: System.NetworkAddress, name: NSName.Name ←
NIL] =
BEGIN
targetStatus: TargetPSStatus.Current ← [];
targetProperties: TargetPSStatus.Properties ← [];
targetError: TargetPSStatus.Communication ← okay;
WITH s: state
SELECT
FROM
feps9700 =>
BEGIN
OPEN s.targetPSName.record;
s.targetPSAddress ← address;
local.length ← domain.length ← org.length ← 0;
IF name #
NIL
THEN
BEGIN
local ← NSString.AppendString[to: local, from: name.local];
domain ← NSString.AppendString[to: domain, from: name.domain];
org ← NSString.AppendString[to: org, from: name.org];
END;
ForwardingControl.SetTargetPrintService[s.targetPSAddress];
targetStatus ← TargetPS.GetPrinterStatus[s.targetPSAddress
! TargetPS.Error => {targetError ← why; GOTO CantReachTarget}];
targetProperties ← TargetPS.GetPrinterProperties[s.targetPSAddress
! TargetPS.Error => {targetError ← why; GOTO CantReachTarget}];
s.paperSupply.size1 ← targetStatus.paperSupply.size1;
s.paperSupply.size2 ← targetStatus.paperSupply.size2;
s.twoSidedCopy ← targetProperties.twoSided;
s.stapling ← targetProperties.staple;
EXITS CantReachTarget =>
BEGIN
s.paperSupply.size1 ← letter; --default first paper size to letter
s.paperSupply.size2 ← max; --default second paper size to undefined (none)
s.twoSidedCopy ← s.stapling ← FALSE; --default two sided coping and stapling to unavailable
Space.ForceOut[stateSpace];
ERROR PSCommand.Error[[targetPS[targetError]]];
END;
END;
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
Space.ForceOut[stateSpace];
END; --SetTargetPrintService
===================================================
FX3500 Display Operations: (NONE ARE MONITORED)
===================================================
PutPrinterDisplay:
PUBLIC
PROCEDURE [leftChar, rightChar:
CHARACTER ← 0C] =
BEGIN
WITH m: markerProcs
SELECT
FROM
fx3500 =>
IF state.mode.current = repair
THEN
m.putPrinterDisplay[leftChar, rightChar]
ELSE ERROR PSCommand.Error[[disallowedInCurrentMode[]]];
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
END; --PutPrinterDisplay
GetPrinterDisplay:
PUBLIC
PROCEDURE
RETURNS [leftChar, rightChar:
CHARACTER ← 0C] =
BEGIN
WITH m: markerProcs
SELECT
FROM
fx3500 =>
IF state.mode.current = repair
THEN
[leftChar, rightChar] ← m.getPrinterDisplay[]
ELSE ERROR PSCommand.Error[[disallowedInCurrentMode[]]];
ENDCASE => ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
END; --GetPrinterDisplay
=============================================================
Print Service Control Operations: (MONITORED OPERATIONS)
=============================================================
StartDiagnosticMode:
PUBLIC
PROCEDURE =
BEGIN
incompatibleOption: BOOLEAN ← FALSE;
CheckAndUpdateCurrentMode[fromMode: normal, toMode: diagnostic];
PSCommandInternal.DisablePrinting[];
PSCommandInternal.DisableQueuing[disabledForDiag];
SELECT state.option
FROM
bansheeDl => BansheeTest.RunServeTestMode[];
d1 => D1Test.RunServeTestMode[];
fax295 => FaxTest.RunServeTestMode[fax295];
fax495 => FaxTest.RunServeTestMode[fax495];
fx3500 => FX3500Test.RunServeTestMode[];
raven => RavenTest.RunServeTestMode[];
ENDCASE => incompatibleOption ← TRUE;
ResetCurrentMode[];
PSCommandInternal.EnablePrinting[];
PSCommandInternal.EnableQueuing[];
IF incompatibleOption
THEN
ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
END; --StartDiagnosticMode
StartRepairMode:
PUBLIC
PROCEDURE =
BEGIN
incompatibleOption: BOOLEAN ← FALSE;
SELECT state.mode.current
FROM
repair => NULL; --already in repair mode
notStarted => CheckAndUpdateCurrentMode[fromMode: notStarted, toMode: repair]; --can go into repair mode before the Start proc is called
ENDCASE => CheckAndUpdateCurrentMode[fromMode: normal, toMode: repair]; --otherwise must be in normal mode to go into repair mode
PSCommandInternal.DisablePrinting[];
PSCommandInternal.DisableQueuing[disabledForRepair];
SELECT state.option
FROM
bansheeDl => BansheeTest.RunRepairMode[];
d1 => D1Test.RunRepairMode[];
fx3500 => FX3500Test.RunRepairMode[];
raven => RavenTest.RunRepairMode[];
ENDCASE => incompatibleOption ← TRUE;
ResetCurrentMode[];
PSCommandInternal.EnablePrinting[];
PSCommandInternal.EnableQueuing[];
IF incompatibleOption
THEN
ERROR PSCommand.Error[[incompatiblePrintingOption[]]];
END; --StartRepairMode
==========================
PRIVATE PROCEDURES
==========================
CheckAndUpdateCurrentMode:
ENTRY
PROCEDURE [fromMode, toMode: PSState.OperationState] =
BEGIN
IF state.mode.current = fromMode
THEN
BEGIN
state.mode.returnTo ← state.mode.current;
state.mode.current ← toMode;
Space.ForceOut[stateSpace];
END
ELSE ERROR PSCommand.Error[[disallowedInCurrentMode[]]];
END; --CheckAndUpdateCurrentMode
ResetCurrentMode:
ENTRY
PROCEDURE =
BEGIN
state.mode.current ← state.mode.returnTo;
Space.ForceOut[stateSpace];
END; --ResetCurrentMode
XKey:
PROCEDURE [key: ControlMessages.Key]
RETURNS [xKey: XMessage.MsgKey] =
{RETURN[ORD[key]]};
Str:
PROCEDURE [s:
LONG
STRING]
RETURNS [ns: NSString.String] =
INLINE {
RETURN[NSString.StringFromMesaString[s]]};
END. --PSCommandBImpl
LOG (when/who/what)
31-Oct-84 13:45:40 - Jacks - Added SetTargetPrintService.
13-Dec-84 11:41:48 - Jacks - SetTargetPrintService now calls GetPrinterProperties as well as GetPrinterStatus and raises error if can't reach target; removed ControlMessagesExtras.
16-Jan-85 15:50:42 - Jacks - Added "ps" prefix to all new msg keys for 9.0.
28-Feb-85 9:55:31 - Jacks - Added banshee choice to StartDiagnosticMode and StartRepairMode; minor message changes in RotateFonts90; try to rotate all banshee font files even if run out of space with one in RotateFonts90; set file type correctly when doing NSFile.Replace on banshee fonts in InstallFont; now implement InstallFontX and InstallFileX from PSCommandExtras instead of InstallFont and InstallFile from PSCommand (set file sizes prior to reading in files); allow entering repair mode when mode=notStarted.
26-Jun-85 10:12:43 - Jacks - Added d1 code.
15-Aug-85 17:08:07 - Jacks - Catch DecomposerControl.DocumentInProgress in InstallFont and DeleteFont.
11-Sep-85 15:52:49 - Jacks - Went back to a single 300 dpi font dir in Rotate90; went back to ListFonts, InstallFont and DeleteFont as defined in PSCommand not PSCommandExtras.
24-Sep-85 14:08:34 - Jacks - Folded PSCommandExtras into PSCommand.
20-May-86 13:23:09 - Jacks - Unload fonts in Rotate90 so that if fonts have already been cataloged, the old files can be deleted.