DIRECTORY Ascii USING[ Lower ], Basics USING[ Comparison ], Commander, GVBasics USING[ MakeKey, Password ], GVNames, IO, Rope, UserCredentials USING[ Get ]; DBPurge: CEDAR PROGRAM IMPORTS Ascii, Commander, GVBasics, GVNames, IO, Rope, UserCredentials SHARES GVNames--GetEntry-- = BEGIN BreakName: PROC[name: Rope.ROPE] RETURNS[sn, reg: Rope.ROPE] = BEGIN FOR i: INT DECREASING IN [0..name.Length[]) DO IF name.Fetch[i] = '. THEN RETURN[ sn: name.Substr[start: 0, len: i], reg: name.Substr[start: i+1, len: name.Length[]-(i+1)] ]; ENDLOOP; RETURN[ sn: NIL, reg: name ] END; Compare: PROC[a, b: Rope.ROPE] RETURNS[Basics.Comparison] = BEGIN aL: INT = a.Length[]; bL: INT = b.Length[]; FOR i: INT IN [0..MIN[aL, bL]) DO ac: CHAR = Ascii.Lower[a.Fetch[i]]; bc: CHAR = Ascii.Lower[b.Fetch[i]]; IF ac < bc THEN RETURN[less]; IF ac > bc THEN RETURN[greater]; ENDLOOP; IF aL < bL THEN RETURN[less]; IF aL > bL THEN RETURN[greater]; RETURN[equal] 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" ] }; NameClass: TYPE = { individuals, groups, dead }; EnumInRegistry: PROC[pattern, registry: Rope.ROPE, which: NameClass, work: EnumProc, out: IO.STREAM ] = BEGIN enumName: Rope.ROPE = Rope.Cat[ SELECT which FROM individuals => "Individuals.", groups => "Groups.", dead => "Dead.", ENDCASE => ERROR, 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 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, which: NameClass, work: EnumProc, out: IO.STREAM ] = BEGIN patternSN, patternReg: Rope.ROPE; RegWork: EnumProc = BEGIN out.PutF["\n\nEnumerating names in %g . . .\n", [rope[name]] ]; EnumInRegistry[patternSN, BreakName[name].sn, which, work, out]; END; [patternSN, patternReg] _ BreakName[pattern]; out.PutRope["\n\nFinding the registries . . ."]; EnumInRegistry[patternReg, "GV", groups, RegWork, out]; END; ListType: TYPE = { m, o, f }; Remove: PROC[entry, element: Rope.ROPE, which: ListType, out: IO.STREAM] = BEGIN user: Rope.ROPE = UserCredentials.Get[].name; pwd: GVBasics.Password = GVBasics.MakeKey[UserCredentials.Get[].password]; outcome: GVNames.Outcome = SELECT which FROM m => GVNames.RemoveMember[user, pwd, entry, element], o => GVNames.RemoveOwner[user, pwd, entry, element], f => GVNames.RemoveFriend[user, pwd, entry, element], ENDCASE => ERROR; out.PutRope[IF outcome = group THEN "ok" ELSE Code[outcome]]; out.PutChar['\n]; END; RemoveAll: PROC[deadList: GVNames.RListHandle, 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, m]; SubListWork[name, i.owners.current, o]; SubListWork[name, i.friends.current, f]; 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[name: Rope.ROPE, list: GVNames.RListHandle, which: ListType] = BEGIN d: GVNames.RListHandle _ deadList; UNTIL d = NIL OR list = NIL DO SELECT Compare[d.first, list.first] FROM greater => list _ list.rest; less => d _ d.rest; equal => BEGIN victim: Rope.ROPE = d.first; out.PutF["%g is a%g of %g: removing . . . ", [rope[victim]], [rope[SELECT which FROM m => " member", o => "n owner", f => " friend", ENDCASE => ERROR]], [rope[name]] ]; Remove[entry: name, element: victim, which: which, out: out]; list _ list.rest; d _ d.rest; END; ENDCASE => ERROR; ENDLOOP; END; out.PutRope["\n\nNames to be removed:\n"]; FOR d: GVNames.RListHandle _ deadList, d.rest UNTIL d = NIL DO out.PutRope[d.first]; out.PutChar[' ]; ENDLOOP; EnumAllNames[pattern, groups, GroupWork, out]; END; PurgeEnum: PROC[members, groups: Rope.ROPE, out: IO.STREAM] = BEGIN deadList: GVNames.RListHandle _ NIL; DeadWork: EnumProc = BEGIN prev: GVNames.RListHandle _ NIL; out.PutRope[name]; out.PutChar[' ]; FOR d: GVNames.RListHandle _ deadList, d.rest UNTIL d = NIL DO IF Compare[name, d.first] = less THEN EXIT; prev _ d; ENDLOOP; IF prev = NIL THEN deadList _ CONS[first: name, rest: deadList] ELSE prev.rest _ CONS[first: name, rest: prev.rest]; END; out.PutRope["Finding all \"dead\" names . . ."]; EnumAllNames[members, dead, DeadWork, out]; RemoveAll[deadList, groups, out]; out.PutRope["\n\nFinished\n"]; END; DoIt: Commander.CommandProc--[cmd: Handle]-- = { PurgeEnum[members: "*.*", groups: "*.*", out: cmd.out] }; Commander.Register[key: "DBPurge", proc: DoIt, doc: "Purges dead members from groups in the Grapevine database"]; END. ÐGrapevine: program to purge dead members from groups DBPurge.mesa Andrew Birrell October 20, 1983 9:43 am This is NOT the same as Rope.Compare: GV's collating sequence forces upper case to lower case Êf˜Jšœ4™4Jšœ ™ Jšœ(™(J˜šÏk ˜ Jšœœ ˜Jšœœ˜J˜ Jšœ œ˜$J˜Jšœ˜J˜Jšœœ˜—J˜šœ œ˜Jšœ&œ˜FJšœÏc œ˜—J˜Jš˜J˜š Ïn œœ œœœ˜>Jš˜Jšœœ œœ˜+šœœ˜šœœ˜ Jšœ"˜"Jšœ6˜6Jšœ˜——Jšœ˜Jšœœ ˜Jšœ˜—J˜šŸœœ œœ˜;Jšœ^™^Jš˜Jšœœ˜Jšœœ˜Jšœœœœ ˜šœœ˜&Jšœœ˜#Jšœ œœ˜Jšœ œœ ˜ —Jšœ˜Jšœ œœ˜Jšœ œœ ˜ Jšœ˜ Jšœ˜—J˜šŸœœœœ˜6šœœœ˜Jšœ˜Jšœ˜Jšœ%˜%Jšœ˜Jšœ"˜"Jšœ˜Jšœ;˜;Jšœ˜Jšœ˜Jšœ1˜1Jšœ˜%——J˜Jšœ œ!˜0J˜š Ÿœœœ)œœ˜gJš˜šœœ ˜šœ˜Jšœ˜Jšœ˜Jšœ˜—Jšœœ˜J˜ —J˜8šœœ˜˜Jš˜Jšœ,œ˜<šœ œ˜)Jšœ0œ˜8Jšœœœœ˜$—Jšœ˜Jšœ˜——šœ˜ šœ0˜0Jšœ,˜,——Jšœ˜—J˜JšŸœœœ œœœœ˜CJ˜š Ÿ œœœ)œœ˜[Jš˜Jšœœ˜!šœ˜Jš˜J˜?J˜@Jšœ˜—J˜-J˜0J˜7Jšœ˜—J˜Jšœ œ˜J˜š Ÿœœœœœ˜JJš˜Jšœ œ˜-JšœJ˜Jšœœ˜,Jšœ5˜5Jšœ4˜4Jšœ5˜5—Jšœœ˜Jšœ œœœ˜=J˜Jšœ˜—J˜š Ÿ œœ.œœœ˜TJš˜šœœž)˜GJš˜Jšœœ˜Jšœ˜Jšœ$˜$šœ˜Jšœ œ˜˜šœœ˜šœ ˜ Jš˜J˜(Jšœ'˜'Jšœ(˜(Jšœ˜——Jšœœ˜——šœ˜ Jš˜šœ0˜0Jšœ!˜!—Jšœœ˜ Jšœ˜—Jšœ˜—šŸ œœ œ/˜PJš˜Jšœ"˜"Jšœœœ˜šœœ˜+Jšœ˜J˜˜Jš˜Jšœ œ ˜˜-J˜šœœ˜J˜/Jšœœ˜—J˜—Jšœ=˜=Jšœ˜Jšœ˜—Jšœœ˜—Jšœ˜Jšœ˜—J˜*Jšœ+œ˜;Jšœ(œ˜2Jšœ.˜.Jšœ˜—J˜š Ÿ œœœœœ˜=Jš˜Jšœ œ˜$šœ˜Jš˜Jšœœ˜ Jšœ#˜#Jšœ+œ˜;šœœœœ˜.J˜ —Jšœ˜Jšœ˜ Jšœ œ˜1Jšœ œ˜4Jšœ˜—J˜0J˜+Jšœ!˜!J˜Jšœ˜—J˜šœžœ˜.Jšœ;˜;—J˜˜.J˜BJ˜—Jšœ˜—…—|²