FixArpaNames.mesa
Copyright © 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)
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: BOOLEANFALSE;
ABORTED: SIGNAL = CODE;
debug: BOOLEANFALSE;
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: BOOLFALSE];
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: BOOLEANFALSE] =
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: BOOLEANFALSE] =
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.ROPENIL;
state: IPName.NameState;
localDomain: BOOLEANFALSE;
[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: REFNIL, msg: Rope.ROPENIL]
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.