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 { stop _ FALSE; Process.Detach[FORK ReallyDoit[]] ; }; StopHit: Menus.MenuProc = TRUSTED { stop _ TRUE; }; SaveHit: Menus.MenuProc = TRUSTED { IO.Flush[out]; IO.Close[out]; }; log: Rope.ROPE _ "///Mail/FixArpaNames.log"; MakeTool: Commander.CommandProc = 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. ¦FixArpaNames.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. John Larson, July 12, 1987 2:33:08 am PDT Sharon Johnson, June 29, 1987 3:05:32 pm PDT Fixup Arpanet names in Grapevine DLs Note: This program can only be run on the machine running the Arpanet mail gateway right now. (Uses NormalizeName and LoadCacheFromName from IPName, and IPConfig) [parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL] [parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL] [parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL] [cmd: Handle] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL] Κ ˜Jšœ™Jšœ Οmœ1™<™)Icode™,K™—J™Jšœ$™$Jšœ£™£J™šΟk ˜ Jšœ žœ˜'Jšœ žœ˜#J˜Jšžœ˜Jšœ žœ ˜.Jšœžœ/˜;J˜Jšœžœ ˜Jšœ˜Jšœžœ˜J˜Jšœ ˜ Jšœ žœ,˜:—J˜šΟn œžœž˜JšžœžœN˜vJšžœΟc œ˜—J˜Jšž˜J˜Jšœžœžœ˜Jšœ˜J˜Jšœžœžœ˜Jšžœžœžœ˜J˜Jšœžœžœ˜Jšœžœ ˜ J˜K˜š Ÿ œžœ žœžœžœ˜>Jšž˜Jšœžœ˜š žœžœž œžœ ž˜'šžœžœžœ˜"Jšœ"˜"Jšœ2˜2—Jšžœ˜—Jšžœžœ ˜Jšžœ˜—J˜š Ÿ œžœ žœžœžœ˜DJšž˜Jšœžœ˜š žœžœž œžœ ž˜'šžœžœžœ˜"Jšœ$˜$Jšœ4˜4—Jšžœ˜—Jšžœžœ žœ˜Jšžœ˜—J˜J˜šŸœžœžœžœ˜6šœžœžœž˜Jšœ˜Jšœ˜Jšœ%˜%Jšœ˜Jšœ"˜"Jšœ˜Jšœ;˜;Jšœ˜Jšœ˜Jšœ1˜1Jšžœ˜%——J˜J˜š Ÿœžœžœžœžœ˜UJšž˜Jšœžœ ˜3J˜8šžœžœž˜˜Jšž˜Jšžœ,žœžœž˜?Jšœ žœ˜&Jšžœžœžœžœ˜Jšžœ0žœ˜8šžœžœžœžœ˜$Jšžœ˜—Jšžœ˜——šžœ˜ šœ0˜0Jšœ,˜,——Jšžœ˜—J˜Jš œ žœžœ žœžœžœžœ˜CJ˜š Ÿ œžœžœžœžœ˜HJšž˜Jšœžœ˜!šŸœ ˜Jšž˜Jšœ3žœ˜MJ˜9Jšžœ˜—J˜-J˜/Jšžœ˜—J˜J˜šŸ œžœžœžœžœžœžœžœ˜[Jšž˜Jšœ žœ˜-JšœJ˜JJšœK˜KJšœM˜MJšœ žœžœžœ˜=Jšœ˜Jšžœ˜Jšžœ˜J˜—šŸ œžœžœžœžœžœžœžœ˜XJšž˜Jšœ žœ˜-JšœJ˜JJšœH˜HJšœI˜IJšœ žœžœžœ˜=Jšžœžœ˜.Jšžœ˜J˜—J˜š Ÿ œžœžœžœžœ˜7Jšž˜šŸ œ žœ )˜GJšž˜Jšœžœ˜Jšœ˜Jšœ$˜$šžœž˜Jšœ žœ˜˜šžœžœž˜šœ ˜ Jšž˜J˜%Jšžœ˜—Jšžœžœ˜——šžœ˜ Jšž˜šœ0˜0Jšœ!˜!—Jšœžœ˜ Jšžœ˜——Jšžœ˜JšŸ œžœ žœ˜@Jšž˜šžœžœž˜Jšž˜Jšžœžœžœžœ˜J˜šžœžœ˜Jšœžœžœ˜!Jšœ˜Jšœ žœžœ˜J˜Jšœ'˜'J˜š žœžœžœžœžœ˜ Jšœ!˜!šžœžœ˜Jšœ(žœžœ˜5Jšžœžœžœ&˜N—Jšœ˜—šžœžœž˜šœ˜JšœF˜FJ˜—šœ˜Jšœ[˜[—J˜šœ˜šœZ˜ZJšžœžœW˜dJšžœ˜Jšœžœ'žœ˜0JšœJ˜JJšœ˜J˜——šœžœ˜"šžœ=ž˜CJšœE˜E—˜J˜——šžœ˜ JšœF˜F——Jšœ˜Jšœ˜Jšžœ˜—Jšžœ˜—Jšžœ˜—Jšœ&˜&Jšžœ˜—J˜J˜šŸ œžœžœžœžœžœžœ˜[Jšž˜šžœžœ˜J˜XJšžœžœ˜—Jšžœ!žœžœžœ˜5Jš žœžœ$žœžœžœ˜>Jšžœžœ˜ šžœ˜J˜J˜——š Ÿ œžœ žœžœžœ˜5Jšž˜š žœžœžœžœ&žœžœž˜TJšœ žœ˜Jšžœžœžœžœ˜-Jšžœ˜—Jšžœžœ˜Jšžœ˜J˜—J˜š Ÿœžœ žœžœžœ˜2Jšž˜Jšžœž œžœ˜.š žœžœžœžœ$žœžœž˜RJšœ žœ˜Jšžœžœžœžœ˜-Jšžœ˜—Jšžœžœ˜Jšžœ˜—J˜code2š Ÿœžœžœžœ žœ˜>Jšœ žœ˜$Jšœ žœ˜$Jšœ žœ˜Jšžœžœžœžœ˜/Jšœ<˜žœžœžœ˜SJšžœžœ˜J˜—J˜šŸ œžœ˜J˜