FixArpaNames.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Sharon Johnson, June 29, 1987 3:05:32 pm PDT
John Larson, March 24, 1988 5:58:36 pm PST
Fixup Arpanet names in Grapevine DLs
Note: This program can only be run only on the machine running the Arpanet mail gateway. (Uses ArpaConfig)
DIRECTORY
Commander USING[CommandProc, Register],
GVBasics USING [MakeKey, Password],
GVNames,
IO,
ArpaConfig USING [validDomains, specialDomains, resolv],
ArpaName USING [AliasToName, ReplyStatus],
Menus,
Process USING [Detach],
Rope,
UserCredentials USING [Get],
ViewerClasses,
ViewerOps,
ViewerIO USING [CreateViewerStreams, GetViewerFromStream];
FixArpaNames:
CEDAR
PROGRAM
IMPORTS Commander, GVBasics, GVNames, IO, ArpaConfig, ArpaName, 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, temp, new: Rope.ROPE ← NIL;
specialDomain: BOOLEAN ← FALSE;
status: ArpaName.ReplyStatus;
[left,right] ← BreakNameAt[list.first];
IF left#
NIL
AND right#
NIL
THEN {
specialDomain ← SpecialDomain[right];
IF ~specialDomain
THEN {
[temp, status,] ← ArpaName.AliasToName[right, ArpaConfig.resolv^];
IF ~Rope.IsEmpty[temp] AND ~Rope.Equal[temp, right, FALSE] THEN new ← temp;
};
};
SELECT
TRUE
FROM
specialDomain =>
out.PutF["%g is a member of %g\n", [rope[list.first]], [rope[group]]];
status = 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]]]};
};
status = down =>
out.PutF["\n** Unable to load cache for %g on %g \n\n", [rope[list.first]], [rope[group]]];
new #
NIL
AND ~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];
SpecialDomain:
PROC[name: Rope.
ROPE]
RETURNS[
BOOLEAN] =
BEGIN
FOR list:
LIST
OF Rope.
ROPE ← ArpaConfig.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 ← ArpaConfig.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.