<> <> <> <> <<>> <<>> <> <> <<>> DIRECTORY Commander USING[CommandProc, Register], GVBasics USING [MakeKey, Password], GVNames, IO, IPConfig USING [validDomains, specialDomains], IPName USING [LoadCacheFromName, NameState, NormalizeName], Menus, Process USING [Detach], Rope, UserCredentials USING [Get], ViewerClasses, ViewerOps, ViewerIO USING [CreateViewerStreams, GetViewerFromStream]; FixArpaNames: CEDAR PROGRAM IMPORTS Commander, GVBasics, GVNames, IO, IPConfig, IPName, Menus, Process, Rope, UserCredentials, ViewerIO, ViewerOps SHARES GVNames--GetEntry-- = BEGIN out: IO.STREAM; menu: Menus.Menu; viewer: ViewerClasses.Viewer; stop: BOOLEAN _ FALSE; ABORTED: SIGNAL = CODE; debug: BOOLEAN _ FALSE; groupPattern: Rope.ROPE = "*.*"; BreakName: PROC[name: Rope.ROPE] RETURNS[sn, reg: Rope.ROPE] = BEGIN length: INT = name.Length[]; FOR i: INT DECREASING IN [0..length) DO IF name.Fetch[i] = '. THEN RETURN[ sn: name.Substr[start: 0, len: i], reg: name.Substr[start: i+1, len: length-(i+1)] ]; ENDLOOP; RETURN[sn: NIL, reg: name]; END; BreakNameAt: PROC[name: Rope.ROPE] RETURNS[left, right: Rope.ROPE] = BEGIN length: INT = name.Length[]; FOR i: INT DECREASING IN [0..length) DO IF name.Fetch[i] = '@ THEN RETURN[ left: name.Substr[start: 0, len: i], right: name.Substr[start: i+1, len: length-(i+1)] ]; ENDLOOP; RETURN[left: NIL, right: NIL]; END; Code: PROC[type: GVNames.Outcome] RETURNS[Rope.ROPE] = { RETURN[ SELECT type FROM noChange => "no change", group => "that's a group", individual => "that's an individual", notFound => "name not found", protocolError => "protocol error", wrongServer => "wrong server", allDown => "all suitable servers are down or inaccessible", badPwd => "incorrect password", outOfDate => "out of date", notAllowed => "you're not authorized to do that", ENDCASE => "unknown return code" ] }; EnumInRegistry: PROC[pattern, registry: Rope.ROPE, work: EnumProc, out: IO.STREAM ] = BEGIN enumName: Rope.ROPE = Rope.Cat["Groups.",registry]; info: GVNames.MemberInfo = GVNames.GetMembers[enumName]; WITH info SELECT FROM i: group GVNames.MemberInfo => BEGIN FOR m: GVNames.RListHandle _ i.members, m.rest UNTIL m = NIL DO sn: Rope.ROPE = BreakName[m.first].sn; IF stop THEN SIGNAL ABORTED; IF Rope.Match[pattern: pattern, object: sn, case: FALSE] THEN { IF work[m.first] THEN EXIT }; ENDLOOP; END; ENDCASE => out.PutF["\nCouldn't get members of \"%g\": %g", [rope[enumName]], [rope[Code[info.type]]] ]; END; EnumProc: TYPE = PROC[name: Rope.ROPE] RETURNS[exit: BOOL _ FALSE]; EnumAllNames: PROC[pattern: Rope.ROPE, work: EnumProc, out: IO.STREAM] = BEGIN patternSN, patternReg: Rope.ROPE; RegWork: EnumProc = BEGIN out.PutF["\n\n%t Enumerating names in %g . . .\n", IO.time[], [rope[name]] ]; EnumInRegistry[patternSN, BreakName[name].sn, work, out]; END; [patternSN, patternReg] _ BreakName[pattern]; EnumInRegistry[patternReg, "GV", RegWork, out]; END; RemoveMember: PROC[group, member: Rope.ROPE, out: IO.STREAM] RETURNS[ok: BOOLEAN _ FALSE] = BEGIN user: Rope.ROPE = UserCredentials.Get[].name; pwd: GVBasics.Password = GVBasics.MakeKey[UserCredentials.Get[].password]; outcome: GVNames.Outcome = GVNames.RemoveMember[user, pwd, group, member]; out.PutF["\n*** Removing %g from %g . . . ", [rope[member]], [rope[group]]]; out.PutRope[IF outcome = group THEN "ok" ELSE Code[outcome]]; out.PutRope["\n\n"]; RETURN[outcome = group]; END; AddMember: PROC[group, member: Rope.ROPE, out: IO.STREAM] RETURNS[ok: BOOLEAN _ FALSE] = BEGIN user: Rope.ROPE = UserCredentials.Get[].name; pwd: GVBasics.Password = GVBasics.MakeKey[UserCredentials.Get[].password]; outcome: GVNames.Outcome = GVNames.AddMember[user, pwd, group, member]; out.PutF["\n*** Adding %g to %g . . . ", [rope[member]], [rope[group]]]; out.PutRope[IF outcome = group THEN "ok" ELSE Code[outcome]]; RETURN[outcome = group OR outcome = noChange]; END; CheckGroups: PROC[pattern: Rope.ROPE, out: IO.STREAM] = BEGIN GroupWork: EnumProc = TRUSTED -- The silly compiler can't handle "info" BEGIN info: REF GVNames.GetEntryInfo; rc: GVNames.NameType; [rc, info] _ GVNames.GetEntry[name]; SELECT rc FROM notFound => NULL; group => WITH info^ SELECT FROM i: group GVNames.GetEntryInfo => BEGIN SubListWork[name, i.members.current]; END; ENDCASE => ERROR; ENDCASE => BEGIN out.PutF["\nCouldn't read entry for \"%g\": %g", [rope[name]], [rope[Code[rc]]] ]; exit _ TRUE; END; END; SubListWork: PROC[group: Rope.ROPE, list: GVNames.RListHandle] = BEGIN UNTIL list = NIL DO BEGIN IF stop THEN SIGNAL ABORTED; IF External[list.first] THEN { left,right, new: Rope.ROPE _ NIL; state: IPName.NameState; localDomain: BOOLEAN _ FALSE; [left,right] _ BreakNameAt[list.first]; IF left#NIL AND right#NIL THEN { localDomain _ LocalDomain[right]; IF ~localDomain THEN { state _ IPName.LoadCacheFromName[right, TRUE, FALSE]; IF state ~= down AND state ~= bogus THEN new _ IPName.NormalizeName[right]; }; }; SELECT TRUE FROM localDomain => out.PutF["%g is a member of %g\n", [rope[list.first]], [rope[group]]]; state = down => out.PutF["\n** Unable to load cache for %g on %g \n\n", [rope[list.first]], [rope[group]]]; state = bogus => { out.PutF["\n*** %g is an invalid address on %g \n\n", [rope[list.first]], [rope[group]]]; IF debug THEN out.PutF["\n%g would be removed from %g . . . \n", [rope[list.first]], [rope[group]]] ELSE { IF ~RemoveMember[group, list.first, out] THEN out.PutF["\n*** Failed to remove %g . . . \n\n", [rope[list.first]]]}; }; ~Rope.Equal[right, new,FALSE] => { IF ~ChangeName[list.first, Rope.Cat[left,"@",new], group, out] THEN out.PutF["\n*** Failed to remove %g . . . \n\n", [rope[list.first]]]; }; ENDCASE => out.PutF["%g is a member of %g\n", [rope[list.first]], [rope[group]]]; }; list _ list.rest; END; ENDLOOP; END; EnumAllNames[pattern, GroupWork, out]; END; ChangeName: PROC[oldName, newName, group: Rope.ROPE, out: IO.STREAM] RETURNS[ok: BOOLEAN] = BEGIN IF debug THEN { out.PutF["\n** %g would be changed to %g . . . \n\n", [rope[oldName]], [rope[newName]]]; RETURN[TRUE]}; IF ~AddMember[group, newName, out] THEN RETURN[FALSE] ELSE IF ~RemoveMember[group, oldName, out] THEN RETURN[FALSE]; RETURN[TRUE]; END; LocalDomain: PROC[name: Rope.ROPE] RETURNS[BOOLEAN] = BEGIN FOR list: LIST OF Rope.ROPE _ IPConfig.specialDomains, list.rest UNTIL list = NIL DO domain: Rope.ROPE _ list.first; IF DotTailed[name, domain] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; External: PROC[name: Rope.ROPE] RETURNS[BOOLEAN] = BEGIN IF Rope.Find[name,"@"] > -1 THEN RETURN[TRUE]; FOR list: LIST OF Rope.ROPE _ IPConfig.validDomains, list.rest UNTIL list = NIL DO domain: Rope.ROPE _ list.first; IF DotTailed[name, domain] THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE]; END; Tailed: PROC [body, tail: Rope.ROPE] RETURNS [match: BOOL] = { bodyLength: INT = Rope.Length[body]; tailLength: INT = Rope.Length[tail]; back: Rope.ROPE; IF bodyLength <= tailLength THEN RETURN[FALSE]; back _ Rope.Substr[body, bodyLength-tailLength, tailLength]; IF ~Rope.Equal[back, tail, FALSE] THEN RETURN[FALSE]; RETURN[TRUE]; }; DotTailed: PROC [body, tail: Rope.ROPE] RETURNS [match: BOOL] = { IF ~Tailed[body, tail] THEN RETURN[FALSE]; IF Rope.Fetch[body, Rope.Length[body]-Rope.Length[tail]-1] # '. THEN RETURN[FALSE]; RETURN[TRUE]; }; ReallyDoit: PROC = { out.PutRope["Checking Arpanet names on Grapevine DLs. . ."]; IF debug THEN out.PutRope["Debugging mode . . ."]; CheckGroups[pattern: groupPattern, out: out ! ABORTED => {out.PutRope["\n\nAborted.\n"]; GOTO Exit}]; out.PutRope["\n\nFinished\n"]; EXITS Exit =>{}; }; DoitHit: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> stop _ FALSE; Process.Detach[FORK ReallyDoit[]] ; }; StopHit: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> stop _ TRUE; }; SaveHit: Menus.MenuProc = TRUSTED { <<[parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL]>> IO.Flush[out]; IO.Close[out]; }; log: Rope.ROPE _ "///Mail/FixArpaNames.log"; MakeTool: Commander.CommandProc = <<[cmd: Handle] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL]>> TRUSTED{ out _ ViewerIO.CreateViewerStreams["FixArpaNames",,log].out; viewer _ ViewerIO.GetViewerFromStream[out]; menu _ viewer.menu; Menus.InsertMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[name: "SaveLog", proc: SaveHit, clientData: NIL]]; Menus.InsertMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[name: "Doit", proc: DoitHit, clientData: NIL]]; Menus.InsertMenuEntry[menu: menu, line: 0, entry: Menus.CreateEntry[name: "STOP!", proc: StopHit, clientData: NIL]]; ViewerOps.PaintViewer[viewer, menu]; }; Commander.Register[key: "FixArpaNames", proc: MakeTool, doc: "Fixes up Arpanet names in Grapevine DLs"]; END.