-- 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.