ArpaNameCacheTool.mesa
John Larson, March 13, 1988 8:23:24 pm PST
DIRECTORY
Arpa,
ArpaExtras,
ArpaName,
ArpaNameCache,
ArpaNameSupport,
ArpaNameLogSupport,
ArpaNameQuery,
BasicTime USING [GMT, Now, Period],
Buttons USING [Button, ButtonProc, Create, Destroy, SetDisplayStyle],
Commander USING [CommandProc, Register],
Containers USING [ChildXBound, ChildYBound, Create],
ConvertExtras USING [ArpaAddressFromRope, RopeFromArpaAddress],
IO USING [Flush, PutF, PutRope, STREAM, Value],
Labels USING [Create],
Loader USING [BCDBuildTime],
Rope USING [Cat, Equal, IsEmpty, ROPE],
Rules USING [Create],
TypeScript USING [ChangeLooks, Create],
ViewerClasses USING [Viewer],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [AddProp, ComputeColumn, CreateViewer, MoveViewer, OpenIcon, SetOpenHeight],
ViewerTools USING [GetContents, MakeNewTextViewer, SetContents, SetSelection];
ArpaNameCacheTool: CEDAR MONITOR
IMPORTS
ArpaExtras, ArpaName, ArpaNameCache, ArpaNameLogSupport, ArpaNameSupport, BasicTime, Buttons, Commander, Containers, ConvertExtras, IO, Labels, Loader, Rope, Rules, TypeScript, ViewerIO, ViewerOps, ViewerTools =
BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Viewer: TYPE = ViewerClasses.Viewer;
Viewer layout parameters
buttonHeight: INTEGER ← 0;
buttonWidth: INTEGER ← 0;
ClientData: TYPE = REF ClientDataRep;
ClientDataRep: TYPE = RECORD [
log: STREAMNIL,
in: STREAMNIL,
resolv: REF BOOLNEW[BOOL TRUE],
key: Viewer,
value: Viewer];
sequenceNumber: CARDINAL ← 0;
NameEntry: TYPE = ArpaNameCache.NameEntry;
AliasEntry: TYPE = ArpaNameCache.AliasEntry;
MXEntry: TYPE = ArpaNameCache.MXEntry;
BogusNameEntry: TYPE = ArpaNameCache.BogusNameEntry;
DownNameEntry: TYPE = ArpaNameCache.DownNameEntry;
AddressEntry: TYPE = ArpaNameCache.AddressEntry;
BogusAddressEntry: TYPE = ArpaNameCache.BogusAddressEntry;
DownAddressEntry: TYPE = ArpaNameCache.DownAddressEntry;
DownServerEntry: TYPE = ArpaNameCache.DownServerEntry;
ZoneEntry: TYPE = ArpaNameCache.ZoneEntry;
SoaEntry: TYPE = ArpaNameCache.SoaEntry;
Create: Commander.CommandProc = { CreateOne[]; };
CreateOne: PROC = {
data: ClientData ← NEW[ClientDataRep ← []];
viewer, buttons, log: Viewer ← NIL;
viewer ← ViewerOps.CreateViewer [
flavor: $Container,
info: [name: "ArpaNameCacheTool", column: left, iconic: TRUE, scrollable: FALSE]];
ViewerOps.AddProp[viewer, $ArpaNameCacheTool, data];
{ -- Kludge to find Button size
temp: Buttons.Button = Buttons.Create[
info: [name: "Aliases:", parent: viewer, border: FALSE,
wx: 0, wy: 0],
proc: NIL, clientData: NIL, fork: FALSE, paint: FALSE];
buttonWidth ← temp.ww;
buttonHeight ← temp.wh;
Buttons.Destroy[temp]; };
log ← TypeScript.Create[
[name: "ArpaNameCacheTool.log", wy: 27+4, parent: viewer, border: FALSE], FALSE];
[data.in, data.log] ← ViewerIO.CreateViewerStreams [
name: "ArpaNameCacheTool.log", backingFile: "ArpaNameCacheTool.log", viewer: log, editedStream: FALSE];
Containers.ChildXBound[viewer, log];
Containers.ChildYBound[viewer, log];
CreateButtons[data, viewer, log];
TypeScript.ChangeLooks[log, 'f];
IO.PutF[data.log, "ArpaNameCache Tool of %G.\n", [time[Loader.BCDBuildTime[Create]]]];
IF FALSE THEN ViewerOps.OpenIcon[viewer]; };
CreateButtons: PROC[data: ClientData, parent, log: Viewer] = {
child: Viewer ← NIL;
kids: Viewer = Containers.Create[
info: [parent: parent, border: FALSE, scrollable: FALSE, wx: 0, wy: -9999, ww: 9999, wh: 0] ];
Containers.ChildXBound[parent, kids];
child ← MakeRule[kids, child];
child ← data.key ← MakeLabeledText[
parent: kids,
sibling: child,
name: "Key:",
data: "Xerox.COM",
prev: data.key];
child ← data.value ← MakeLabeledText[
parent: kids,
sibling: child,
name: "Value:",
data: "[a.b.c.d]",
prev: data.value];
child ← MakeBool[kids, child, data, "Resolv", data.resolv];
child ← MakeRule[kids, child];
child ← MakeLabel[kids, child, "Query:"];
child ← MakeButton[kids, child, data, "N=>A", N2A];
child ← MakeButton[kids, child, data, "N=>MX", N2MX];
child ← MakeButton[kids, child, data, "N=>N", N2N];
child ← MakeButton[kids, child, data, "N=>S", N2Servers];
child ← MakeButton[kids, child, data, "N=>I", N2Info];
child ← MakeButton[kids, child, data, "A=>N", A2N];
child ← MakeLabel[kids, child, "Cache:"];
child ← MakeButton[kids, child, data, "PrSlot", PrintSlot];
child ← MakeButton[kids, child, data, "PrOne", PrintOne];
child ← MakeButton[kids, child, data, "PrAll", Quick];
child ← MakeButton[kids, child, data, "Names", Names];
child ← MakeButton[kids, child, data, "Addrs", Addrs];
child ← MakeButton[kids, child, data, "Aliases", Aliases];
child ← MakeButton[kids, child, data, "MXs", MXs];
child ← MakeButton[kids, child, data, "Bogus", Bogus];
child ← MakeButton[kids, child, data, "Down", Down];
child ← MakeButton[kids, child, data, "Zones", Zones];
child ← MakeButton[kids, child, data, "ZapSlot", FlushEntry];
child ← MakeButton[kids, child, data, "ZapOne", FlushCache];
child ← MakeButton[kids, child, data, "ZapAll", Zap];
child ← MakeButton[kids, child, data, "AddV", AddV];
child ← MakeRule[kids, child];
{
kidsY: INTEGER = 2;
kidsH: INTEGER = child.wy + child.wh + 2;
ViewerOps.MoveViewer[viewer: log, x: 0, y: kidsY + kidsH, w: log.ww, h: parent.ch - (kids.wy + kidsH), paint: FALSE];
ViewerOps.SetOpenHeight[parent, kidsY + kidsH + 12 * buttonHeight];
IF ~parent.iconic THEN ViewerOps.ComputeColumn[parent.column];
ViewerOps.MoveViewer[viewer: kids, x: kids.wx, y: kidsY, w: kids.ww, h: kidsH]; };
};
ResolvProc: BoolProc = {
parent: Viewer, clientData: REF, value BOOL
};
Zap: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
ArpaNameCache.FlushAll[];
IO.PutRope[log, "Zapped all name and server caches.\n\n"]; };
AddV: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
key: ROPE ← ViewerTools.GetContents[data.key];
value: ROPE ← ViewerTools.GetContents[data.value];
addr: Arpa.Address ← ConvertExtras.ArpaAddressFromRope[value];
addrList: LIST OF Arpa.Address ← LIST[addr];
IF Rope.IsEmpty[key] THEN RETURN;
IF Rope.IsEmpty[value] THEN RETURN;
IF addrList.first = Arpa.nullAddress THEN RETURN;
[] ← ArpaNameCache.UpdateName[key, ArpaExtras.MyAddress[], 1333, FALSE, addrList];
IO.PutRope[log, key];
PrintListOfAddresses[log, " => ", addrList]; };
FlushCache: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
cacheRope: ROPE ← ViewerTools.GetContents[data.key];
cache: ArpaNameCache.CacheType;
IF Rope.IsEmpty[cacheRope] THEN RETURN;
SELECT TRUE FROM
Rope.Equal[cacheRope, "name", FALSE] => cache ← name;
Rope.Equal[cacheRope, "alias", FALSE] => cache ← alias;
Rope.Equal[cacheRope, "mx", FALSE] => cache ← mx;
Rope.Equal[cacheRope, "zone", FALSE] => cache ← zone;
Rope.Equal[cacheRope, "soa", FALSE] => cache ← soa;
Rope.Equal[cacheRope, "downName", FALSE] => cache ← downName;
Rope.Equal[cacheRope, "bogusName", FALSE] => cache ← bogusName;
Rope.Equal[cacheRope, "address", FALSE] => cache ← address;
Rope.Equal[cacheRope, "downAddress", FALSE] => cache ← downAddress;
Rope.Equal[cacheRope, "bogusAddress", FALSE] => cache ← bogusAddress;
Rope.Equal[cacheRope, "downServer", FALSE] => cache ← downServer;
ENDCASE;
ArpaNameCache.FlushCache[cache];
IO.PutRope[log, "Zapped "];
IO.PutRope[log, cacheRope];
IO.PutRope[log, " cache.\n\n"]; };
FlushEntry: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
entry: ROPE ← ViewerTools.GetContents[data.key];
IF Rope.IsEmpty[entry] THEN RETURN;
FOR cache: ArpaNameCache.CacheType IN [ArpaNameCache.CacheType.FIRST..ArpaNameCache.CacheType.LAST] DO
ArpaNameCache.Delete[entry, cache];
ENDLOOP;
IO.PutRope[log, "Zapped entry.\n\n"]; };
N2A: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.key];
addresses: LIST OF Arpa.Address;
status: ArpaName.ReplyStatus;
[addresses, status, ] ← ArpaName.NameToAddressList[query, data.resolv^];
SELECT status FROM
bogus => {IO.PutRope[log, Rope.Cat[query, " => bogus\n"]]; RETURN};
down => {IO.PutRope[log, Rope.Cat[query, " => down\n"]]; RETURN};
other => {IO.PutRope[log, Rope.Cat[query, " => other\n"]]; RETURN};
ENDCASE;
IO.PutRope[log, query];
PrintListOfAddresses[log, " => ", addresses]; };
N2N: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.key];
name: ROPE;
status: ArpaName.ReplyStatus;
[name, status, ] ← ArpaName.AliasToName[query, data.resolv^];
SELECT status FROM
bogus => {IO.PutRope[log, Rope.Cat[query, " => bogus\n"]]; RETURN};
down => {IO.PutRope[log, Rope.Cat[query, " => down\n"]]; RETURN};
other => {IO.PutRope[log, Rope.Cat[query, " => other\n"]]; RETURN};
ENDCASE;
IO.PutF[log, "%G => %G.\n", [rope[query]], [rope[name]]]; };
N2Servers: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.key];
status: ArpaName.ReplyStatus;
servers: LIST OF ROPE;
[servers, status, ] ← ArpaName.DomainServers[query, data.resolv^];
SELECT status FROM
bogus => {IO.PutRope[log, Rope.Cat[query, " => bogus\n"]]; RETURN};
down => {IO.PutRope[log, Rope.Cat[query, " => down\n"]]; RETURN};
other => {IO.PutRope[log, Rope.Cat[query, " => other\n"]]; RETURN};
ENDCASE;
IO.PutF[log, "%G => ", [rope[query]]];
PrintListOfNames[log, "servers are: ", servers];
IO.PutRope[log, "\n"];
};
N2Info: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.key];
status: ArpaName.ReplyStatus;
contact: ROPE;
primaryServer: ROPE;
[contact, primaryServer, status, ] ← ArpaName.DomainInfo[query, data.resolv^];
SELECT status FROM
bogus => {IO.PutRope[log, Rope.Cat[query, " => bogus\n"]]; RETURN};
down => {IO.PutRope[log, Rope.Cat[query, " => down\n"]]; RETURN};
other => {IO.PutRope[log, Rope.Cat[query, " => other\n"]]; RETURN};
ENDCASE;
IO.PutF[log, "%G => ", [rope[query]]];
IO.PutF[log, " contact: %G, ", [rope[contact]]];
IO.PutF[log, " server: %G.\n", [rope[primaryServer]]];
IO.PutRope[log, "\n"];
};
N2MX: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.key];
status: ArpaName.ReplyStatus;
mxEntry: ArpaNameCache.MXEntry ← NIL;
Log: PROC [rope: ROPE] ~ {
IO.PutRope[log, rope];
IO.Flush[log]};
status ← ArpaName.NameToMailHostList[query, data.resolv^].status;
SELECT status FROM
bogus => {IO.PutRope[log, Rope.Cat[query, " => bogus\n"]]; RETURN};
down => {IO.PutRope[log, Rope.Cat[query, " => down\n"]]; RETURN};
other => {IO.PutRope[log, Rope.Cat[query, " => other\n"]]; RETURN};
ENDCASE;
[,, mxEntry] ← ArpaNameCache.FetchMX[query];
IF mxEntry # NIL THEN ArpaNameLogSupport.MXSummaryLine[mxEntry, FALSE, TRUE, Log];
};
A2N: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
query: ROPE ← ViewerTools.GetContents[data.key];
where: LIST OF Arpa.Address ← ArpaName.NameToAddressList[query, data.resolv^].addrs;
name: Rope.ROPE;
status: ArpaName.ReplyStatus;
[where, status,] ← ArpaName.NameToAddressList[query, data.resolv^];
SELECT status FROM
bogus => {IO.PutRope[log, Rope.Cat[query, " => bogus\n"]]; RETURN};
down => {IO.PutRope[log, Rope.Cat[query, " => down\n"]]; RETURN};
other => {IO.PutRope[log, Rope.Cat[query, " => other\n"]]; RETURN};
ENDCASE;
IF where = NIL THEN {
IO.PutF[log, "\"Query\" needs to be a valid Address.\n"]; RETURN[]; };
name ← ArpaName.AddressToName[where.first, data.resolv^].name;
IO.PutF[log, "%G => %G.\n", [rope[ConvertExtras.RopeFromArpaAddress[where.first]]], [rope[name]]]; };
PrintOne: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
cacheRope: ROPE ← ViewerTools.GetContents[data.key];
cache: ArpaNameCache.CacheType ← name;
SummaryEnum: ArpaNameCache.EnumerateProc = {
PROC [key: ROPE, val: Entry] RETURNS [quit: BOOLFALSE]
WITH val SELECT FROM
e: ArpaNameCache.NameEntry =>
ArpaNameLogSupport.NameSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.AliasEntry =>
ArpaNameLogSupport.AliasSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.AddressEntry =>
ArpaNameLogSupport.AddressSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.MXEntry =>
ArpaNameLogSupport.MXSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.ZoneEntry =>
ArpaNameLogSupport.ZoneSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.SoaEntry =>
ArpaNameLogSupport.SoaSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.BogusNameEntry =>
ArpaNameLogSupport.BogusNameSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.BogusAddressEntry =>
ArpaNameLogSupport.BogusAddressSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.DownNameEntry =>
ArpaNameLogSupport.DownNameSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.DownAddressEntry =>
ArpaNameLogSupport.DownAddressSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.DownServerEntry =>
ArpaNameLogSupport.DownServerSummaryLine[e, FALSE, TRUE, Log];
ENDCASE;
};
Log: PROC [rope: ROPE] ~ {
IO.PutRope[log, rope];
IO.Flush[log]};
IF Rope.IsEmpty[cacheRope] THEN RETURN;
IO.PutRope[log, "\n"];
IO.PutRope[log, cacheRope];
IO.PutRope[log, " cache Summary:\n"];
SELECT TRUE FROM
Rope.Equal[cacheRope, "name", FALSE] => cache ← name;
Rope.Equal[cacheRope, "alias", FALSE] => cache ← alias;
Rope.Equal[cacheRope, "mx", FALSE] => cache ← mx;
Rope.Equal[cacheRope, "zone", FALSE] => cache ← zone;
Rope.Equal[cacheRope, "soa", FALSE] => cache ← soa;
Rope.Equal[cacheRope, "downName", FALSE] => cache ← downName;
Rope.Equal[cacheRope, "bogusName", FALSE] => cache ← bogusName;
Rope.Equal[cacheRope, "address", FALSE] => cache ← address;
Rope.Equal[cacheRope, "downAddress", FALSE] => cache ← downAddress;
Rope.Equal[cacheRope, "bogusAddress", FALSE] => cache ← bogusAddress;
Rope.Equal[cacheRope, "downServer", FALSE] => cache ← downServer;
ENDCASE => {IO.PutRope[log, "No such cache.\n"]; RETURN};
IF ArpaNameCache.CountCache[cache] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[cache, SummaryEnum]};
};
Quick: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
SummaryEnum: ArpaNameCache.EnumerateProc = {
PROC [key: ROPE, val: Entry] RETURNS [quit: BOOLFALSE]
WITH val SELECT FROM
e: ArpaNameCache.NameEntry =>
ArpaNameLogSupport.NameSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.AliasEntry =>
ArpaNameLogSupport.AliasSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.AddressEntry =>
ArpaNameLogSupport.AddressSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.MXEntry =>
ArpaNameLogSupport.MXSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.ZoneEntry =>
ArpaNameLogSupport.ZoneSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.SoaEntry =>
ArpaNameLogSupport.SoaSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.BogusNameEntry =>
ArpaNameLogSupport.BogusNameSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.BogusAddressEntry =>
ArpaNameLogSupport.BogusAddressSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.DownNameEntry =>
ArpaNameLogSupport.DownNameSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.DownAddressEntry =>
ArpaNameLogSupport.DownAddressSummaryLine[e, FALSE, TRUE, Log];
e: ArpaNameCache.DownServerEntry =>
ArpaNameLogSupport.DownServerSummaryLine[e, FALSE, TRUE, Log];
ENDCASE;
};
Log: PROC [rope: ROPE] ~ {
IO.PutRope[log, rope];
IO.Flush[log]};
IO.PutRope[log, "\nCache Summary:\n"];
IO.PutRope[log, "\nNames: "];
IF ArpaNameCache.CountCache[name] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[name, SummaryEnum]};
IO.PutRope[log, "\nAliases:"];
IF ArpaNameCache.CountCache[alias] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[alias, SummaryEnum]};
IO.PutRope[log, "\nMXs:"];
IF ArpaNameCache.CountCache[mx] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[mx, SummaryEnum]};
IO.PutRope[log, "\nZoneServers:"];
IF ArpaNameCache.CountCache[zone] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[zone, SummaryEnum]};
IO.PutRope[log, "\nZoneInfo:"];
IF ArpaNameCache.CountCache[soa] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[soa, SummaryEnum]};
IO.PutRope[log, "\nBogus Names:"];
IF ArpaNameCache.CountCache[bogusName] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[bogusName, SummaryEnum]};
IO.PutRope[log, "\nDown Names:"];
IF ArpaNameCache.CountCache[downName] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[downName, SummaryEnum]};
IO.PutRope[log, "\nAddresses:"];
IF ArpaNameCache.CountCache[address] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[address, SummaryEnum]};
IO.PutRope[log, "\nBogus Addresses:"];
IF ArpaNameCache.CountCache[bogusAddress] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[bogusAddress, SummaryEnum]};
IO.PutRope[log, "\nDown Addresses:"];
IF ArpaNameCache.CountCache[downAddress] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[downAddress, SummaryEnum]};
IO.PutRope[log, "\nDown Servers:"];
IF ArpaNameCache.CountCache[downServer] = 0 THEN IO.PutRope[log, "empty."]
ELSE {
IO.PutRope[log, "\n"];
ArpaNameCache.EnumerateCache[downServer, SummaryEnum]};
IO.PutRope[log, "\n\n"];
IO.Flush[log]; };
PrintSlot: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
this: NameEntry;
alias: AliasEntry;
mx: MXEntry;
bogusName: BogusNameEntry;
downName: DownNameEntry;
zone: ZoneEntry;
soa: SoaEntry;
address: AddressEntry;
downAddress: DownAddressEntry;
bogusAddress: BogusAddressEntry;
downServer: DownServerEntry;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
found: BOOLEANFALSE;
query: ROPE ← ViewerTools.GetContents[data.key];
SELECT ArpaNameSupport.IsAddressRope[query] FROM
FALSE => {
this ← ArpaNameCache.FetchName[query].entry;
alias ← ArpaNameCache.FetchAlias[query].entry;
mx ← ArpaNameCache.FetchMX[query].entry;
bogusName ← ArpaNameCache.FetchBogusName[query].entry;
downName ← ArpaNameCache.FetchDownName[query].entry;
zone ← ArpaNameCache.FetchZone[query].entry;
soa ← ArpaNameCache.FetchSoa[query].entry;
};
TRUE => {
address ← ArpaNameCache.FetchAddressRope[query].entry;
downAddress ← ArpaNameCache.FetchDownAddressRope[query].entry;
bogusAddress ← ArpaNameCache.FetchBogusAddressRope[query].entry;
downServer ← ArpaNameCache.FetchDownServerRope[query].entry;
};
ENDCASE;
IO.PutRope[log, "\n"];
IF this # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[this.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
found ← TRUE;
IO.PutF[log, "Name Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]],[integer[this.ttl]]];
IO.PutF[log, " Name: %G.\n", [rope[this.key]]];
PrintListOfAddresses[log, " Addresses: ", this.addresses];
IO.PutRope[log, "\n"];};
IF alias # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[alias.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: alias.expires];
found ← TRUE;
IO.PutF[log, "Alias Loaded: %G, From: %G", [time[alias.loaded]], [rope[source]]];
IF ~alias.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[alias.referenced]], [integer[expires]], [integer[alias.ttl]]];
IO.PutF[log, " Alias: %G.\n", [rope[alias.key]]];
IO.PutF[log, " Canonical Name: %G.\n", [rope[alias.canonicalName]]];
IO.PutRope[log, "\n"];};
IF mx # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[mx.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: mx.expires];
found ← TRUE;
IO.PutF[log, "MX Loaded: %G, From: %G", [time[mx.loaded]], [rope[source]]];
IF ~mx.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[mx.referenced]], [integer[expires]], [integer[mx.ttl]]];
IO.PutF[log, " Name: %G.\n", [rope[mx.key]]];
FOR list: LIST OF ArpaNameQuery.MailForwardRecord ← mx.mxList, list.rest UNTIL list = NIL DO
IO.PutF[log, " MX Host: %G", [rope[list.first.host]]];
IO.PutF[log,", Preference: %G", [integer[list.first.preference]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.PutRope[log, "\n"];
};
IF bogusName # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[bogusName.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: bogusName.expires];
found ← TRUE;
IO.PutF[log, "Bogus Name Loaded: %G, From: %G", [time[bogusName.loaded]], [rope[source]]];
IF ~bogusName.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[bogusName.referenced]], [integer[expires]], [integer[bogusName.ttl]]];
IO.PutF[log, " Bogus Name: %G.\n", [rope[bogusName.key]]];
IO.PutRope[log, "\n"];};
IF downName # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
expires: INT ← BasicTime.Period[from: now, to: downName.expires];
found ← TRUE;
IO.PutF[log, "Down Name Loaded: %G", [time[downName.loaded]]];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[downName.referenced]], [integer[expires]], [integer[downName.ttl]]];
IO.PutF[log, " Down Name: %G.\n", [rope[downName.key]]];
IO.PutRope[log, "\n"];};
IF zone # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[zone.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: zone.expires];
found ← TRUE;
IO.PutF[log, "Zone Loaded: %G, From: %G", [time[zone.loaded]], [rope[source]]];
IF ~zone.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[zone.referenced]], [integer[expires]], [integer[zone.ttl]]];
IO.PutF[log, " Zone: %G.\n", [rope[zone.key]]];
PrintListOfNames[log, " Servers: ", zone.servers];
IO.PutRope[log, "\n"];};
IF soa # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[soa.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: soa.expires];
found ← TRUE;
IO.PutF[log, "Soa Loaded: %G, From: %G", [time[soa.loaded]], [rope[source]]];
IF ~soa.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[soa.referenced]], [integer[expires]], [integer[soa.ttl]]];
IO.PutF[log, " Soa: %G.\n", [rope[soa.key]]];
IO.PutF[log, " Domain contact: %G.\n", [rope[soa.soaRef.domainContact]]];
IO.PutF[log, " Primary server: %G.\n", [rope[soa.soaRef.primaryServer]]];
IO.PutRope[log, "\n"];};
IF address # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[address.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: address.expires];
found ← TRUE;
IO.PutF[log, "Address Loaded: %G, From: %G", [time[address.loaded]], [rope[source]]];
IF ~address.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[address.referenced]], [integer[expires]], [integer[address.ttl]]];
IO.PutF[log, " Address: %G.\n", [rope[address.key]]];
PrintListOfNames[log, " Name: ", address.names];
IO.PutRope[log, "\n"];};
IF downAddress # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[downAddress.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: downAddress.expires];
found ← TRUE;
IO.PutF[log, "Address Loaded: %G, From: %G", [time[downAddress.loaded]], [rope[source]]];
IF ~downAddress.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[downAddress.referenced]], [integer[expires]], [integer[downAddress.ttl]]];
IO.PutF[log, " Down Address: %G.\n", [rope[downAddress.key]]];
IO.PutF[log, " Name: %G.\n", [rope[ArpaName.AddressRopeToName[downAddress.key, data.resolv^].name]]];
IO.PutRope[log, "\n"];};
IF bogusAddress # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[bogusAddress.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: bogusAddress.expires];
found ← TRUE;
IO.PutF[log, "Address Loaded: %G, From: %G", [time[bogusAddress.loaded]], [rope[source]]];
IF ~bogusAddress.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[bogusAddress.referenced]], [integer[expires]], [integer[bogusAddress.ttl]]];
IO.PutF[log, " Bogus Address: %G.\n", [rope[bogusAddress.key]]];
IO.PutRope[log, "\n"];};
IF downServer # NIL THEN {
now: BasicTime.GMT ← BasicTime.Now[];
source: ROPE ← ArpaName.AddressToName[downServer.source, data.resolv^].name;
expires: INT ← BasicTime.Period[from: now, to: downServer.expires];
found ← TRUE;
IO.PutF[log, "Address Loaded: %G, From: %G", [time[downServer.loaded]], [rope[source]]];
IF ~downServer.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[downServer.referenced]], [integer[expires]], [integer[downServer.ttl]]];
IO.PutF[log, " Down Server: %G.\n", [rope[downServer.key]]];
IO.PutF[log, " Name: %G.\n", [rope[ArpaName.AddressRopeToName[downServer.key, data.resolv^].name]]];
IO.PutRope[log, "\n"];};
IF ~found THEN IO.PutRope[log, "Entry not found.\n"];
IO.PutRope[log, "\n"];
IO.Flush[log]; };
Addrs: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
addresses: LIST OF AddressEntry = ArpaNameCache.GetAddresses[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF AddressEntry ← addresses, list.rest UNTIL list = NIL DO
this: AddressEntry ← list.first;
source: ROPE ← ArpaName.AddressToName[this.source].addr;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Address slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Address: %G.\n", [rope[ArpaName.AddressToRope[this.address]]]];
PrintListOfRopes[log, " Names: ", this.names];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
Aliases: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
aliases: LIST OF AliasEntry = ArpaNameCache.GetAliases[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF AliasEntry ← aliases, list.rest UNTIL list = NIL DO
this: AliasEntry ← list.first;
source: ROPE ← ArpaName.AddressToName[this.source].addr;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Alias slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Alias: %G.\n", [rope[this.alias]]];
IO.PutF[log, " Name: %G.\n", [rope[this.name]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
MXs: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
mxList: LIST OF MXEntry = ArpaNameCache.GetMXList[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF MXEntry ← mxList, list.rest UNTIL list = NIL DO
mx: MXEntry ← list.first;
source: ROPE ← ArpaName.AddressToName[mx.source].addr;
expires: INT ← BasicTime.Period[from: now, to: mx.expires];
n ← n + 1;
IO.PutF[log, "MX slot %G.\n", [integer[n]]];
IO.PutF[log, "Loaded: %G, From: %G", [time[mx.loaded]], [rope[source]]];
IF ~mx.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[mx.referenced]], [integer[expires]], [integer[mx.ttl]]];
IO.PutF[log, " Name: %G.\n", [rope[mx.name]]];
FOR list: LIST OF ArpaNameCache.MXHostInfo ← mx.mxHosts, list.rest UNTIL list = NIL DO
IO.PutF[log, " MX Host: %G", [rope[list.first.host]]];
IO.PutF[log, ", Preference: %G", [integer[list.first.preference]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
Bogus: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
bogusAddresses: LIST OF BogusAddressEntry = ArpaNameCache.GetBogusAddresses[];
bogusNames: LIST OF BogusNameEntry = ArpaNameCache.GetBogusNames[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF BogusNameEntry ← bogusNames, list.rest UNTIL list = NIL DO
this: BogusNameEntry ← list.first;
source: ROPE ← ArpaName.AddressToName[this.source].addr;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Bogus slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Name: %G.\n", [rope[this.bogus]]];
IO.PutRope[log, "\n"];
ENDLOOP;
FOR list: LIST OF BogusAddressEntry ← bogusAddresses, list.rest UNTIL list = NIL DO
this: BogusAddressEntry ← list.first;
source: ROPE ← ArpaName.AddressToName[this.source].addr;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Bogus slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Address: %G.\n", [rope[ArpaName.AddressToRope[this.bogus]]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };

Down: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
downAddresses: LIST OF DownAddressEntry = ArpaNameCache.GetDownAddresses[];
downNames: LIST OF DownNameEntry = ArpaNameCache.GetDownNames[];
downServers: LIST OF DownServerEntry = ArpaNameCache.GetDownServers[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF DownNameEntry ← downNames, list.rest UNTIL list = NIL DO
this: DownNameEntry ← list.first;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Down name slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G", [time[this.loaded]]];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Name: %G.\n", [rope[this.name]]];
IO.PutRope[log, "\n\n"];
ENDLOOP;
n ← 0;
FOR list: LIST OF DownAddressEntry ← downAddresses, list.rest UNTIL list = NIL DO
this: DownAddressEntry ← list.first;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Down address slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G", [time[this.loaded]]];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Address: %G.\n", [rope[ArpaName.AddressToRope[this.address]]]];
IO.PutRope[log, "\n\n"];
ENDLOOP;
n ← 0;
FOR list: LIST OF DownServerEntry ← downServers, list.rest UNTIL list = NIL DO
this: DownServerEntry ← list.first;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Down server slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G", [time[this.loaded]]];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Address: %G.\n", [rope[ArpaName.AddressToRope[this.address]]]];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };

Names: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
names: LIST OF NameEntry = ArpaNameCache.GetNames[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF NameEntry ← names, list.rest UNTIL list = NIL DO
this: NameEntry ← list.first;
source: ROPE ← ArpaName.AddressToName[this.source].addr;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Name slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutRope[log, ".\n"];
IO.PutF[log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Name: %G.\n", [rope[this.name]]];
PrintListOfAddresses[log, " Addresses: ", this.addresses];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
Zones: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
ENABLE UNWIND => NULL;
data: ClientData ← NARROW[clientData];
log: IO.STREAM ← data.log;
servers: LIST OF ZoneEntry = ArpaNameCache.GetZones[];
now: BasicTime.GMT ← BasicTime.Now[];
n: INT ← 0;
FOR list: LIST OF ZoneEntry ← servers, list.rest UNTIL list = NIL DO
this: ZoneEntry ← list.first;
source: ROPE ← ArpaName.AddressToName[this.source].addr;
expires: INT ← BasicTime.Period[from: now, to: this.expires];
n ← n + 1;
IO.PutF[log, "Zone slot %G.\n", [integer[n]]];
IO.PutF[log, " Loaded: %G, From: %G", [time[this.loaded]], [rope[source]]];
IF ~this.authoritative THEN IO.PutF[log, ", NOT Authoritative **"];
IO.PutF[log, ".\n"];
IO.PutF[data.log, " Referenced: %G, Expires: %G, TTL: %G.\n", [time[this.referenced]], [integer[expires]], [integer[this.ttl]]];
IO.PutF[log, " Zone: %G\n", [rope[this.zone]]];
PrintListOfRopes[log, " Servers: ", this.servers];
IO.PutRope[log, "\n"];
ENDLOOP;
IO.Flush[log]; };
ListLength: PROCEDURE [arg: REF ANY] RETURNS [length: INT ← 0] = TRUSTED {
FOR list: LIST OF REF ANYLOOPHOLE[arg], list.rest UNTIL list = NIL DO
length ← length + 1;
ENDLOOP; };
PrintListOfRopes: PROC [log: IO.STREAM, header: ROPE, ropes: LIST OF ROPE] = {
IO.PutRope[log, header];
FOR list: LIST OF ROPE ← ropes, list.rest UNTIL list = NIL DO
IF list # ropes THEN IO.PutRope[log, ", "];
IO.PutF[log, "\"%G\"", [rope[list.first]]];
ENDLOOP;
IO.PutRope[log, "\n"]; };
PrintListOfAddresses: PROC [log: IO.STREAM, header: ROPE, addresses: LIST OF Arpa.Address] = {
IO.PutRope[log, header];
FOR list: LIST OF Arpa.Address ← addresses, list.rest UNTIL list = NIL DO
IF list # addresses THEN IO.PutRope[log, ", "];
IO.PutRope[log, ConvertExtras.RopeFromArpaAddress[list.first]];
ENDLOOP;
IO.PutRope[log, "\n"]; };
PrintListOfNames: PROC [log: IO.STREAM, header: ROPENIL, names: LIST OF ROPE] = {
IF header # NIL THEN IO.PutRope[log, header];
FOR list: LIST OF ROPE ← names, list.rest UNTIL list = NIL DO
IF list # names THEN IO.PutRope[log, ", "];
IO.PutRope[log, list.first];
ENDLOOP;
IO.PutRope[log, "\n"]; };
MakeRule: PROC [parent, sibling: Viewer] RETURNS [child: Viewer] = {
child ← Rules.Create[
info: [parent: parent, border: FALSE,
wy: IF sibling = NIL THEN 0 ELSE sibling.wy + sibling.wh + 2, wx: 0, ww: parent.ww, wh: 1],
paint: FALSE ];
Containers.ChildXBound[parent, child]; };
MakeButton: PROC [parent, sibling: Viewer, data: REF ANY, name: ROPE, proc: Buttons.ButtonProc] RETURNS[child: Viewer] = {
child ← Buttons.Create[
info: [name: name, parent: parent, border: TRUE,
wy: sibling.wy, wx: sibling.wx + buttonWidth - 1, ww: buttonWidth],
proc: proc,
clientData: data,
fork: TRUE,
paint: FALSE]; };
BoolProc: TYPE = PROC [parent: Viewer, clientData: REF, value: BOOL];
Bool: TYPE = REF BoolRec;
BoolRec: TYPE = RECORD [
value: REF BOOL,
change: BoolProc,
clientData: REF,
button: Viewer ];
MakeBool: PROC
[parent, sibling: Viewer, clientData: REFNIL, name: ROPE, init: REF BOOL, change: BoolProc ← NIL, x, y: INTEGER ← 0]
RETURNS [child: Viewer] = {
bool: Bool ← NEW [BoolRec ← [
value: IF init # NIL THEN init ELSE NEW [BOOLTRUE],
change: change,
clientData: clientData,
button: NIL ] ];
IF y = 0 THEN y ← sibling.wy + sibling.wh;
IF x = 0 THEN x ← 2;
child ← Buttons.Create[
info: [name: name, parent: parent, border: TRUE, wx: x, wy: y],
proc: BoolHelper, clientData: bool, fork: TRUE, paint: TRUE];
bool.button ← child;
IF bool.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack]; };
BoolHelper: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
self: Buttons.Button = NARROW[parent];
bool: Bool = NARROW[clientData];
bool.value^ ← ~bool.value^;
IF bool.value^ THEN Buttons.SetDisplayStyle[bool.button, $WhiteOnBlack]
ELSE Buttons.SetDisplayStyle[bool.button, $BlackOnWhite];
IF bool.change # NIL THEN bool.change[self.parent, bool.clientData, bool.value^]; };
MakeLabel: PROC [parent, sibling: Viewer, name: ROPE] RETURNS [child: Viewer] = {
child ← Labels.Create[
info: [name: name, parent: parent, border: FALSE,
wy: sibling.wy + sibling.wh + (IF sibling.class.flavor = $Button THEN -1 ELSE 2),
wx: 2],
paint: FALSE ]; };
MakeLabeledText: PROC [
parent, sibling: Viewer, name, data: ROPE, prev: Viewer, newline: BOOLTRUE] RETURNS [child: Viewer] = {
x: INTEGER = IF newline THEN 2 ELSE sibling.wx + sibling.ww + 10;
y: INTEGER = IF newline THEN sibling.wy + sibling.wh + 1 ELSE sibling.wy;
child ← ViewerTools.MakeNewTextViewer[
info: [parent: parent, wh: buttonHeight, ww: 999, scrollable: TRUE,
data: IF prev = NIL THEN data ELSE ViewerTools.GetContents[prev],
border: FALSE,
wx: x + buttonWidth + 2, wy: y],
paint: FALSE ];
Containers.ChildXBound[parent, child];
[] ← Buttons.Create[
info: [name: name, parent: parent, wh: buttonHeight, border: FALSE, wx: x, wy: y],
proc: LabeledTextProc, clientData: child, fork: FALSE, paint: FALSE];
RETURN[child]; };
LabeledTextProc: Buttons.ButtonProc = {
parent: REF, clientData: REF, mouseButton: MouseButton, shift, control: BOOL
text: Viewer = NARROW[clientData];
SELECT mouseButton FROM
red => ViewerTools.SetSelection[text, NIL];
yellow => NULL;
blue => { ViewerTools.SetContents[text, NIL]; ViewerTools.SetSelection[text, NIL] };
ENDCASE => ERROR; };
Commander.Register["ArpaNameCacheTool", Create, "ArpaName Cache Tool."];
END.