-- Transport mechanism: Maintain: small procedures
-- [Juniper]<Grapevine>Maintain>MaintainDetails.mesa
-- Andrew Birrell 13-Jan-82 15:47:42
-- Philip Karlton 15-May-81 16:05:16
DIRECTORY
Ascii,
BodyDefs USING[ Connect, maxRNameLength, Password, RName ],
GlassDefs USING[ Handle ],
MaintainPrivate USING[ Command, Del, Handle ],
NameInfoDefs USING[ CheckStamp, StampInfo ],
ProtocolDefs USING[ MakeKey, RNameType ],
PupDefs USING[ GetPupAddress, PupAddress, PupNameTrouble ],
String USING[ AppendString, UpperCase ],
Storage USING[ Prune ];
MaintainDetails: PROGRAM
IMPORTS MaintainPrivate, NameInfoDefs, ProtocolDefs, PupDefs, String,
Storage
EXPORTS MaintainPrivate =
BEGIN
OPEN MaintainPrivate;
CopyName: PUBLIC PROC[from, to: BodyDefs.RName] =
{ to.length ←0; String.AppendString[to, from] };
CantCheckName: PUBLIC SIGNAL[bad: BodyDefs.RName] = CODE;
BadName: PUBLIC SIGNAL[bad: BodyDefs.RName] = CODE;
BadConnect: PUBLIC SIGNAL[bad: BodyDefs.Connect] = CODE;
VerifyOnOff: PUBLIC PROC[handle: MaintainPrivate.Handle] =
BEGIN
handle.glass.WriteString[IF handle.verifying THEN " ← off"L ELSE " ← on"L];
IF Confirm[handle.glass] THEN handle.verifying ← NOT handle.verifying;
END;
CheckMailName: PUBLIC PROC[name: BodyDefs.RName] =
{ CheckRealName[name ! BadName => {CheckForeignName[name];CONTINUE} ] };
CheckRealName: PUBLIC PROC[name: BodyDefs.RName] =
BEGIN
info: NameInfoDefs.StampInfo = NameInfoDefs.CheckStamp[name];
SELECT info FROM
allDown => SIGNAL CantCheckName[name];
notFound => SIGNAL BadName[name];
ENDCASE => NULL;
END;
CheckForeignName: PUBLIC PROC[name: BodyDefs.RName] =
BEGIN
foreign: BodyDefs.RName = [BodyDefs.maxRNameLength];
MakeRNameHaveNA["Foreign"L, name, foreign];
CheckRealName[foreign !
CantCheckName => { SIGNAL CantCheckName[name]; RESUME };
BadName => { SIGNAL BadName[name]; RESUME } ];
END;
CheckConnect: PUBLIC PROC[connect: BodyDefs.Connect] =
BEGIN
addr: PupDefs.PupAddress;
PupDefs.GetPupAddress[@addr, connect ! PupDefs.PupNameTrouble =>
SELECT code FROM
errorFromServer => { SIGNAL BadConnect[connect]; CONTINUE };
noRoute => CONTINUE;
ENDCASE => { SIGNAL CantCheckName[connect]; CONTINUE } ];
END;
MakeRNameHaveNA: PROC[nname, sname, destination: BodyDefs.RName] =
BEGIN
-- nname is of the form "NA" or "NA.something"
-- sname is of form "something.SN" or "SN"
-- assumes that SN and NA do not contain '.
-- constructs "SN.NA", truncating NA if needed
SNstart: CARDINAL;
sep: CHARACTER = '.;
destination.length ← 0;
SNstart ← sname.length;
DO IF SNstart = 0 OR sname[SNstart-1] = sep THEN EXIT;
SNstart ← SNstart - 1;
ENDLOOP;
FOR index: CARDINAL IN [SNstart..sname.length)
DO IF destination.length = destination.maxlength THEN ERROR;
destination[destination.length] ← sname[index];
destination.length ← destination.length + 1;
ENDLOOP;
IF destination.length = destination.maxlength THEN RETURN;
destination[destination.length] ← sep;
destination.length ← destination.length + 1;
FOR index: CARDINAL IN [0..nname.length)
WHILE nname[index] # sep
DO IF destination.length = destination.maxlength THEN EXIT;
destination[destination.length] ← nname[index];
destination.length ← destination.length + 1;
ENDLOOP;
END;
ReadWord: PUBLIC PROC[str: GlassDefs.Handle,
prompt, dest: STRING] =
{ IF str.ReadString[prompt, dest, word] = Ascii.DEL THEN ERROR Del[] };
ReadPassword: PUBLIC PROC[str: GlassDefs.Handle,
text, pwd: STRING]
RETURNS[key: BodyDefs.Password] =
BEGIN
IF str.ReadString[text, pwd, word] = Ascii.DEL THEN ERROR Del[];
key ← ProtocolDefs.MakeKey[pwd]
END;
Confirm: PUBLIC PROC[str: GlassDefs.Handle] RETURNS[ ok: BOOLEAN ] =
BEGIN
OPEN str;
WriteString[" [Confirm] "L];
DO SELECT ReadChar[] FROM
Ascii.CR, 'Y, 'y => { WriteString["Yes"L]; ok ← TRUE; EXIT };
'N, 'n => { WriteString["No"L]; ok ← FALSE; EXIT };
Ascii.DEL => ERROR Del[];
ENDCASE => WriteChar['?];
ENDLOOP;
END;
TypeType: PUBLIC PROC[str: GlassDefs.Handle,
type: ProtocolDefs.RNameType] =
BEGIN
OPEN str;
WriteString[", type = "L];
WriteString[SELECT type FROM
group => "group"L,
individual => "individual"L,
notFound => "not found"L,
dead => "deleted"L,
ENDCASE => "???"L];
END;
Scan: PROC[handle: MaintainPrivate.Handle,
list: DESCRIPTOR FOR ARRAY OF MaintainPrivate.Command,
prompt: STRING] =
BEGIN
OPEN handle.glass;
inline: STRING ← [256];
inchar: CHARACTER;
i, nMatches, prevMatch, maxPrefixLength, commonPrefixLength: CARDINAL;
Match: PROCEDURE [i: CARDINAL] RETURNS [BOOLEAN] =
BEGIN
j: CARDINAL;
FOR j IN [0..inline.length)
DO IF String.UpperCase [list[i].name[j]]~=
String.UpperCase [inline[j]]
THEN RETURN[FALSE];
ENDLOOP;
RETURN[TRUE]
END;
[] ← Storage.Prune[];
inline.length ← 0;
WriteString[prompt];
DO inchar ← ReadChar[];
SELECT inchar FROM
'? =>
BEGIN
WriteString["? Commands are:"]; WriteChar[Ascii.CR];
FOR i IN [0..LENGTH[list])
DO WriteString[list[i].name];
IF i+1 # LENGTH[list] THEN WriteString[", "L];
ENDLOOP;
WriteChar[Ascii.CR]; WriteString[prompt]; WriteString[inline];
END;
Ascii.DEL =>
ERROR MaintainPrivate.Del[];
Ascii.BS, Ascii.ControlA =>
IF inline.length~=0 THEN
BEGIN
inline.length ← inline.length-1;
WriteChar[("\\"L)[0] -- because \ is escape char in cedar--];
END;
ENDCASE =>
BEGIN
IF (inchar = Ascii.SP OR inchar = Ascii.CR
OR inchar = Ascii.ESC) AND inline.length = 0
THEN { WriteChar[Ascii.CR]; WriteString[prompt]; LOOP };
inline[inline.length] ← inchar;
inline.length ← inline.length+1;
nMatches ← 0;
FOR i IN [0..LENGTH[list]) DO
IF Match[i] THEN
BEGIN
IF nMatches > 0 THEN
BEGIN
maxPrefixLength ← MIN[list[i].name.length, commonPrefixLength];
FOR commonPrefixLength ← inline.length, commonPrefixLength+1 DO
IF list[i].name[commonPrefixLength]~=
list[prevMatch].name[commonPrefixLength] OR
commonPrefixLength=maxPrefixLength THEN EXIT
ENDLOOP;
END
ELSE
commonPrefixLength ← list[i].name.length;
nMatches ← nMatches+1;
prevMatch ← i
END
ENDLOOP;
IF nMatches=0 THEN
BEGIN
WriteChar[inchar];
DO WriteString["?"];
IF ReadChar[] = Ascii.DEL THEN ERROR MaintainPrivate.Del[];
ENDLOOP
END
ELSE
BEGIN
WriteChar[list[prevMatch].name[inline.length-1]];
FOR i IN [inline.length..commonPrefixLength) DO
WriteChar[inline[i]←list[prevMatch].name[i]]
ENDLOOP;
inline.length ← commonPrefixLength;
END;
IF nMatches=1 THEN EXIT;
END;
ENDLOOP;
list[prevMatch].work[handle]
END;
Parse: PUBLIC PROC[handle: MaintainPrivate.Handle,
list: DESCRIPTOR FOR ARRAY OF MaintainPrivate.Command,
prompt: STRING] =
{ DO handle.glass.WriteChar[Ascii.CR]; Scan[handle, list, prompt];
ENDLOOP };
END.