IO.
{
ENABLE
{PupStream.StreamClosing =>
GOTO Closing; PupStream.Timeout =>
GOTO TimeOut};
string: REF TEXT ← NEW [TEXT [180]];
password: ROPE;
account: ROPE;
quitting: BOOLEAN ← FALSE;
accessAllowed: BOOLEAN ← TRUE;
echo: BOOLEAN ← TRUE;
flushed: BOOLEAN ← FALSE;
commandCode: CommandCode;
lastRequest: INT ← -1;
PutChar: PROC [char: CHAR] = { IO.PutChar[stream, char]; flushed ← FALSE; };
PutString: PROC [string: ROPE] = { IO.PutRope[stream, string]; flushed ← FALSE; };
PutOK: PROC = {PutString["\n\lok\n\l"]};
PutXXX: PROC = { PutString[" XXX\n\l"]};
sep: CHAR ← ' ;
DelHit: ERROR = CODE;
SendNow: PROC = {IO.Flush[stream]; flushed ← TRUE};
GetChar:
PROC
RETURNS [
CHAR] =
TRUSTED {c:
CHAR; ignore:
INT ← 0;
IF NOT flushed THEN SendNow[];
WHILE ignore >= 0
DO
mark: NAT ← 0; timingMark: NAT = 5; timingMarkReply: NAT = 6; dataMark: NAT = 1;
charsAvail: INT ← 0; bytes: PACKED ARRAY [0..4] OF CHAR;
charsAvail ← IO.UnsafeGetBlock[stream, [LOOPHOLE[LONG[@bytes]], 0, 1]];
IF charsAvail # 0
THEN c ← bytes[0]
ELSE {gotMark:
BOOL ←
FALSE;
IF stream.GetInfo.class = $Pup
THEN {gotMark ←
TRUE;
mark ← PupStream.ConsumeMark[stream ! RuntimeError.UNCAUGHT => {gotMark ← FALSE; CONTINUE}]}};
SELECT mark FROM 0 => NULL; dataMark => {ignore ← 1};
timingMark => {ignore ← 1}; ENDCASE => ignore ← 2;
ignore ← ignore - 1;
ENDLOOP;
IF c = '\177 THEN {PutXXX[]; ERROR DelHit};
RETURN [c]
};
GetStringToSpace:
PROC [stopper1:
CHAR ← ' , stopper2:
CHAR ← '\t]
RETURNS [r:
ROPE] = {c:
CHAR ← GetChar[];
dashCount: NAT ← 0;
inComment: BOOLEAN ← FALSE;
commentHit: BOOLEAN ← FALSE;
string.length ← 0;
UNTIL string.length = string.maxLength
OR (NOT inComment AND (c=stopper1 OR c=stopper2))
OR c='\n
DO
IF c= 'H - 100B
OR c= 'A - 100B
THEN {
IF commentHit THEN {PutXXX[]; ERROR DelHit};
IF string.length > 0
THEN {
IF echo THEN PutChar[c];
string.length ← string.length - 1;
};
}
ELSE IF c= 'W - 100B
THEN {
IF commentHit THEN {PutXXX[]; ERROR DelHit};
WHILE string.length > 0
DO
IF echo THEN PutChar['H - 100B];
string.length ← string.length - 1;
ENDLOOP;
}
ELSE {
IF echo THEN PutChar[c];
IF c = '-
THEN {
commentHit ← TRUE;
dashCount ← dashCount + 1;
IF dashCount = 2
THEN {
inComment ← NOT inComment;
dashCount ← 0;
};
}
ELSE {
WHILE dashCount > 0
DO
IF
NOT inComment
THEN {
string[string.length] ← '-;
string.length ← string.length + 1;
};
dashCount ← dashCount - 1;
ENDLOOP;
IF
NOT inComment
THEN {
string[string.length] ← c;
string.length ← string.length + 1;
};
};
};
c ← GetChar[];
ENDLOOP;
IF string.length <= string.maxLength THEN sep ← c ELSE sep ← ' ;
IF string.length = 0
AND sep # '\n
THEN {
PutChar[sep];
IO.Flush[stream];
RETURN[GetStringToSpace[stopper1, stopper2]];
};
IO.Flush[stream];
RETURN [Rope.FromRefText[string]];
};
GetStringToCR:
PROC []
RETURNS [
ROPE] = {
RETURN[GetStringToSpace['\n, '\n]];
};
GetNumber:
PROC [default:
INT ← 1]
RETURNS [value:
INT ← 0] = {
r: ROPE ← GetStringToSpace[];
IF Rope.Length[r] = 0 THEN value ← default ELSE value ← Convert.IntFromRope[r ! Convert.Error => {PutString["Not a vailid number.\n\l"]; value ← default; CONTINUE}];
};
Confirm:
PROC
RETURNS [yes:
BOOLEAN ←
FALSE] = {
response: ROPE ← GetStringToSpace[];
IF Rope.Equal[response, "Yes",
FALSE]
THEN {
RETURN [TRUE]
}
ELSE
IF Rope.Length[response] = 0
OR Upper[Rope.Fetch[response, 0]] # 'N
THEN {
PutString["Sorry, you must say Yes in just the right way.\n\l"];
RETURN [FALSE]
}
ELSE PutXXX[]
};
EasyConfirm:
PROC
RETURNS [yes:
BOOLEAN ←
FALSE] = {
response: ROPE ← GetStringToSpace[];
IF Rope.Equal[response, "Yes",
FALSE]
OR Rope.Equal[response, "Y",
FALSE]
THEN {
RETURN [TRUE]
}
ELSE
IF Rope.Length[response] = 0
OR Upper[Rope.Fetch[response, 0]] # 'N
THEN {
PutString["Sorry, you must say Yes in just the right way.\n\l"];
RETURN [FALSE]
}
ELSE PutXXX[]
};
GetCommand:
PROC = {
nMatches: NAT ← 0;
matchLength: NAT ← 0;
command: ROPE;
commandCode ← illegal;
PutString[">>"];
command ← GetStringToSpace[];
IF Rope.Length[command] = 0 THEN {PutChar['\n]; PutChar['\l]; IO.Flush[stream]; GetCommand[]}
ELSE {
FOR cmd: CommandCode
IN [login..quit]
DO
candidate: ROPE ← commandTable[cmd];
IF Rope.Length[command] <= Rope.Length[candidate]
THEN {
matchLength ← 0;
FOR i:
INT
IN [0 .. Rope.Length[command])
DO
IF Upper[Rope.Fetch[command, i]] = Upper[Rope.Fetch[candidate, i]]
THEN matchLength ← i+1 ELSE EXIT;
ENDLOOP;
IF matchLength = Rope.Length[command]
THEN {
commandCode ← cmd;
IF matchLength = Rope.Length[candidate] THEN {nMatches ← 1; EXIT};
nMatches ← nMatches + 1;
IF NOT loggedIn THEN EXIT
};
};
ENDLOOP;
IF nMatches > 1 THEN commandCode ← ambiguous
ELSE
IF commandCode <= quit
THEN {
candidate: ROPE ← commandTable[commandCode];
FOR i:
INT
IN [Rope.Length[command] .. Rope.Length[candidate])
DO
PutChar[Rope.Fetch[candidate, i]];
ENDLOOP;
IO.Flush[stream];
};
};
};
DoCommand:
PROC = {
GetCommand[];
IF
NOT loggedIn
AND commandCode # login
AND commandCode # quit
THEN {
PutString["Please log in.\n\l"]
}
ELSE {
SELECT commandCode
FROM
login => {
registryMissing: BOOLEAN ← TRUE;
PutString[" --User-- "];
user ← GetStringToSpace[];
registryMissing ← Rope.Find[user, "."] < 0;
IF registryMissing
THEN {
user ← Rope.Concat[user, defaultRegistry];
PutString[defaultRegistry];
};
PutString[" --Password-- "];
echo ← FALSE;
password ← GetStringToSpace[ ! UNWIND => echo ← TRUE];
echo ← TRUE;
IF sep # '\n
THEN {
PutString[" --Account-- "];
account ← GetStringToSpace[];
};
PutString[" -- Authenticating ... "];
SendNow[];
SELECT GVNames.Authenticate[user, password]
FROM
individual => {PutString["OK"]; loggedIn ← TRUE};
allDown => {PutString["all GV servers down; I'll have to trust you."]; loggedIn ← TRUE};
badPwd => {PutString["bad password"]; loggedIn ← FALSE};
ENDCASE => {PutString["bad name"]; loggedIn ← FALSE};
PutChar['\n];
PutChar['\l];
IO.Flush[stream];
IF loginMessage.Length > 0
THEN {
IO.PutF1[stream, "%g\n\l", IO.rope[loginMessage]];
};
};
listFiles =>
{
{ -- For enable
ENABLE
FS.Error => {PutString[error.explanation]; PutString["\n\l"];
GOTO Bad};
Proc:
FS.NameProc =
TRUSTED {
-- [fullFName: ROPE] RETURNS [continue: BOOL];
PutString[fullFName];
PutString["\n\l"];
RETURN [TRUE];
};
fileNames: ROPE; cp: FS.ComponentPositions;
PutString[" --Pattern-- "];
fileNames ← GetStringToSpace[];
IF fileNames =
NIL
THEN {
PutString[" No file specified.\n\l"];
GOTO Bad;
};
[fileNames, cp, ] ← FS.ExpandName[fileNames];
IF cp.server.length # 0
THEN {
PutString[" Illegal file specified (not a local file).\n\l"];
GOTO Bad;
};
FS.EnumerateForNames[fileNames, Proc];
}; -- For enable
PutChar['\n]; PutChar['\l];
EXITS Bad => NULL
};
listQueue => {
Proc:
PROC [id: PrintingP4V3.RequestID,
status: PrintingP4V3.InterpressMasterStatus,
printAttributes: PrintingP4V3.PrintAttributes,
printOptions: PrintingP4V3.PrintOptions]
RETURNS [continue:
BOOL] =
TRUSTED {
md: MACHINE DEPENDENT RECORD [lo, hi: CARDINAL];
md.lo ← id[4]; md.hi ← id[3];
IO.PutF[stream, "ID: %g\tStatus: %g\n\l",
IO.card[
LOOPHOLE[md]],
IO.rope[(
SELECT status
FROM
pending => "pending", inProgress => "in progress",
completed => "completed",
completedWithWarning => "completed with warnings",
unknown => "unknown", rejected => "rejected", aborted => "aborted",
canceled => "canceled", held => "held", ENDCASE => NIL)]
];
IO.PutRope[stream, "Print Attributes:\n\l"];
IF printAttributes
# NIL THEN
FOR i:
CARDINAL
IN [0 .. printAttributes.length)
DO
option: Attribute ← printAttributes.body[i];
WITH option: option
SELECT
FROM
printObjectName => {IO.PutF1[stream, " name: %g\n\l", IO.rope[option.printObjectName]]};
printObjectCreateDate => {
time: BasicTime.GMT ← BasicTime.FromNSTime[option.printObjectCreateDate];
IO.PutF1[stream, " createTime: %g\n\l", IO.time[time]]};
senderName => {IO.PutF1[stream, " name: %g\n\l", IO.rope[option.senderName]]};
ENDCASE => NULL;
ENDLOOP;
IO.PutRope[stream, "Print Options:\n\l"];
IF printOptions #
NIL
THEN
FOR i:
CARDINAL
IN [0 .. printOptions.length)
DO
option: Option ← printOptions.body[i];
WITH option: option
SELECT
FROM
printObjectSize => IO.PutF1[stream, " size: %g\n\l", IO.card[option.printObjectSize]];
recipientName => IO.PutF1[stream, " recipientName: %g\n\l", IO.rope[option.recipientName]];
message => IO.PutF1[stream, " message: %g\n\l", IO.rope[option.message]];
copyCount => IO.PutF1[stream, " copies: %g\n\l", IO.card[option.copyCount]];
ENDCASE => NULL;
ENDLOOP;
IO.Flush[stream];
RETURN[TRUE];
};
XNSPSSpooler.EnumerateQueue[Proc];
};
messages => {
action:
PROC [message:
ROPE]
RETURNS [continue:
BOOLEAN ←
TRUE] = {
IF Match[message]
THEN {
PutString[message];
PutChar['\n]; PutChar['\l];
};
};
key: ROPE ← NIL;
Match:
PROC [message:
ROPE]
RETURNS [
BOOLEAN] = {
IF Rope.IsEmpty[key] THEN RETURN [TRUE];
RETURN [Rope.Find[s1: message, s2: key, case: FALSE]>=0];
};
IF sep # '\n
THEN {
PutString[" --matching string-- "];
key ← GetStringToCR[];
};
PutChar['\n]; PutChar['\l];
XNSPSMessages.EnumerateMessages[action];
};
setPrinterParams => {
sMargin, fMargin, newsMargin, newfMargin: CARDINAL;
PutString[" \n\lGetting current parameters. "];
[sMargin, fMargin] ← XNSPSPrint.GetMargins[];
PutString[IO.PutFR[" -- Current Parameters: sMargin: %g, fMargin: %g \n\l",
IO.card[sMargin], IO.card[fMargin]]];
PutString[" -- New sMargin<"];
IO.Put[stream, IO.card[sMargin]];
PutString[">-- "];
newsMargin ← GetNumber[default: sMargin];
IF newsMargin
NOT
IN [1..30]
THEN {
PutString[" --must be in [1..30]-- "];
PutChar['\n]; PutChar['\l];
RETURN;
};
PutString[" -- New fMargin<"];
IO.Put[stream, IO.card[fMargin]];
PutString[">-- "];
newfMargin ← GetNumber[default: fMargin];
IF newfMargin
NOT
IN [10..43]
THEN {
PutString[" --must be in [10..43]-- "];
PutChar['\n]; PutChar['\l];
RETURN;
};
PutString[" -- You sure? -- "];
IF EasyConfirm[]
THEN {
PutOK[];
XNSPSPrint.SetMargins[newsMargin, newfMargin];
[sMargin, fMargin] ← XNSPSPrint.GetMargins[];
XNSPSMessages.LogMessage[
IO.PutFR["Setting margins to: sMargin: %g, fMargin: %g",
IO.card[sMargin], IO.card[fMargin]]];
};
};
help, illegal => {
PutString["\n\lValid commands are: "];
FOR cmd: CommandCode
IN [login..quit]
DO
candidate: ROPE ← commandTable[cmd];
PutString[candidate];
IF cmd # quit THEN PutString[", "];
ENDLOOP;
PutChar['\n]; PutChar['\l];
};
quit => {loggedIn ← FALSE; PutChar['\n]; PutChar['\l]; SendNow[]; quitting ← TRUE};
watch => {
stats: WatchStats.WatchStatsRecord ← WatchStats.GetWatchStats[];
IO.PutF[stream, " Free disk:\t%g\n\l", IO.int[stats.diskFree]];
IO.PutF[stream, " Free mds:\t%g\n\l", IO.int[stats.mdsFree]];
IO.PutF[stream, " Free gfi:\t%g\n\l", IO.int[stats.gfiFree]];
IO.PutF[stream, " Free VM:\t%g\n\l", IO.int[stats.vmFree]];
IO.PutF[stream, " VM run:\t%g\n\l", IO.int[stats.vmRun]];
IO.PutF[stream, " Load:\t%g\n\l", IO.real[stats.cpuLoad]];
flushed ← FALSE;
};
ambiguous => {
PutString["\n\lAmbiguous command (type Help<CR> for help)\n\l"];
};
ENDCASE => ERROR;
};
};
IO.PutF1[stream, "\n\l%g\n\l", IO.rope[helloMsg]];
UNTIL loggedIn OR quitting DO DoCommand[! DelHit => CONTINUE] ENDLOOP;
IF loggedIn THEN XNSPSMessages.LogMessage[IO.PutFR1["Login: %g", IO.rope[user]]];
WHILE loggedIn DO DoCommand[! DelHit => CONTINUE] ENDLOOP;
XNSPSMessages.LogMessage[IO.PutFR1["%g logout", IO.rope[user]]];
EXITS Closing => {
IF loggedIn THEN XNSPSMessages.LogMessage[IO.PutFR1["%g logged off due to remote close", IO.rope[user]]];
};
TimeOut => {
IF loggedIn THEN XNSPSMessages.LogMessage[IO.PutFR1["%g logged off due to TimeOut", IO.rope[user]]];
};
};