<> <> <> DIRECTORY Arpa, ArpaNameBuf USING [domainPort, Port], ArpaName USING [AddressToName, AliasToName, MyName, NameToAddress, ReplyStatus], ArpaNameSupport USING [IsAddressRope], ArpaNameQuery USING [ARR, NsRR, CNameRR, PtrRR, MbRR, MgRR, MrRR, MdRR, MfRR, SoaRR, WksRR, HinfoRR, MinfoRR, MxRR, Error, Protocol, QClass, QType, Query, QuestionRecord, RRClass, RRType, Reply, ResourceRecord, Seconds], ArpaUDP USING [Milliseconds], Atom USING [GetPName], Buttons USING [Button, ButtonProc, Create, Destroy, SetDisplayStyle], Commander USING [CommandProc, Register], Containers USING [ChildXBound, ChildYBound, Create], Convert USING [CardFromRope], ConvertExtras USING [RopeFromArpaAddress], IO USING [Flush, PutF, PutFR, PutRope, STREAM, Value], Labels USING [Create], Loader USING [BCDBuildTime], Rope USING [ROPE, IsEmpty], 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]; ArpaNameTool: CEDAR MONITOR IMPORTS ArpaName, ArpaNameSupport, ArpaNameQuery, Atom, Buttons, Commander, Containers, Convert, ConvertExtras, IO, Labels, Loader, Rope, Rules, TypeScript, ViewerIO, ViewerOps, ViewerTools = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Viewer: TYPE = ViewerClasses.Viewer; <> buttonHeight: INTEGER _ 0; buttonWidth: INTEGER _ 0; ClientData: TYPE = REF ClientDataRep; ClientDataRep: TYPE = RECORD [ log: STREAM _ NIL, in: STREAM _ NIL, class: ArpaNameQuery.QClass _ in, protocol: ArpaNameQuery.Protocol _ udpOnly, recursionDesired: BOOL _ FALSE, showErr: BOOL _ TRUE, target, timeout, query: Viewer _ NIL ]; sequenceNumber: CARDINAL _ 0; defaultDomainServer: ROPE _ "Arisia"; Create: Commander.CommandProc = TRUSTED { data: ClientData _ NEW[ClientDataRep _ []]; viewer, buttons, log: Viewer _ NIL; viewer _ ViewerOps.CreateViewer [ flavor: $Container, info: [name: "ArpaNameTool", column: right, iconic: TRUE, scrollable: FALSE]]; ViewerOps.AddProp[viewer, $ArpaNameTool, data]; { -- Kludge to find Button size temp: Buttons.Button = Buttons.Create[ info: [name: "Length:", 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: "ArpaNameTool.log", wy: 27+4, parent: viewer, border: FALSE], FALSE]; [data.in, data.log] _ ViewerIO.CreateViewerStreams [ name: "ArpaNameTool.log", backingFile: "ArpaNameTool.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, "ArpaNameTool of %G.\n", [time[Loader.BCDBuildTime[Create]]]]; 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.target _ MakeLabeledText[ parent: kids, sibling: child, name: "Server:", data: defaultDomainServer, prev: data.target ]; child _ data.query _ MakeLabeledText[ parent: kids, sibling: child, name: "Query:", data: ArpaName.MyName[], prev: data.query]; child _ data.timeout _ MakeLabeledText[ parent: kids, sibling: child, name: "Timeout:", data: "30000", prev: data.timeout ]; child _ MakeRule[kids, child]; child _ MakeBool[kids, child, data, "recurse", NEW[BOOL _ FALSE], RecurseP]; child _ MakeBool[kids, child, data, "errors", NEW[BOOL _ TRUE], ShowErr]; child _ MakeSelector[kids, child, data, LIST[$in, $ch, $star], " QClass ", NEW[ATOM _ $in], QClassP]; child _ MakeSelector[kids, child, data, LIST[$udp, $tcp], " Protocol ", NEW[ATOM _ $udp], ProtocolP]; child _ MakeRule[kids, child]; child _ MakeLabel[kids, child, "QType:"]; child _ MakeButton[kids, child, data, " A ", Address]; child _ MakeButton[kids, child, data, "NS", Server]; child _ MakeButton[kids, child, data, "CN", CName]; child _ MakeButton[kids, child, data, "MX", MX]; child _ MakeButton[kids, child, data, "SOA", SOA]; child _ MakeButton[kids, child, data, " * ", Star]; child _ MakeRule[kids, child]; child _ MakeButton[kids, child, data, "Inv", Inverse]; child _ MakeButton[kids, child, data, "MB", MB]; child _ MakeButton[kids, child, data, "MG", MG]; child _ MakeButton[kids, child, data, "MR", MR]; child _ MakeButton[kids, child, data, "Null", Null]; child _ MakeButton[kids, child, data, "WKS", Wks]; child _ MakeRule[kids, child]; child _ MakeButton[kids, child, data, "Ptr", Ptr]; child _ MakeButton[kids, child, data, "HInfo", HInfo]; child _ MakeButton[kids, child, data, "MInfo", MInfo]; child _ MakeButton[kids, child, data, "MailA", Maila]; child _ MakeButton[kids, child, data, "MailB", Mailb]; child _ MakeButton[kids, child, data, "AXFR", Axfr]; <<>> 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]; }; }; QClassP: SelectorProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; data.class _ SELECT value FROM $in => in, $ch => ch, ENDCASE => star; }; ProtocolP: SelectorProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; data.protocol _ SELECT value FROM $udp => udpOnly, ENDCASE => tcpOnly; }; RecurseP: BoolProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; data.recursionDesired _ value; }; ShowErr: BoolProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; data.showErr _ value; }; Address: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, a]; }; Server: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, ns]; }; CName: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, cName]; }; Star: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, star]; }; SOA: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, soa]; }; MX: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, mx]; }; MB: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, mb]; }; MG: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, mg]; }; MR: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, mr]; }; Null: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, null]; }; Wks: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, wks]; }; Ptr: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, ptr]; }; HInfo: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, hinfo]; }; MInfo: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, minfo]; }; Maila: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, maila]; }; Mailb: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, mailb]; }; Axfr: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; Query[data, axfr]; }; Inverse: Buttons.ButtonProc = TRUSTED { <> data: ClientData _ NARROW[clientData]; log: IO.STREAM _ data.log; serverName: ROPE = ViewerTools.GetContents[data.target]; rope: ROPE _ ViewerTools.GetContents[data.query]; port: ArpaNameBuf.Port _ ArpaNameBuf.domainPort; timeoutRope: ROPE _ ViewerTools.GetContents[data.timeout]; timeout: ArpaUDP.Milliseconds _ Convert.CardFromRope[timeoutRope]; server, address, source: Arpa.Address; query: ROPE; reply: ArpaNameQuery.Reply _ NIL; status: ArpaName.ReplyStatus; IF Rope.IsEmpty[serverName] THEN RETURN; IF Rope.IsEmpty[rope] THEN RETURN; [server, status, source] _ ArpaName.NameToAddress[serverName]; SELECT status FROM bogus => {Report[log, serverName, ": not a valid name (", ArpaName.AddressToName[source].name, ").\n"]; RETURN}; down => {Report[log, "Name servers not responding.\n"]; RETURN}; other => {Report[log, serverName, ": no address for this name (", ArpaName.AddressToName[source].name, ").\n"]; RETURN}; ENDCASE; IF server = Arpa.nullAddress THEN {Report[log, serverName, ": unable to lookup name.\n"]}; IF ~ArpaNameSupport.IsAddressRope[rope] THEN {Report[log, "Needs to be an Arpa address.\n"]; RETURN}; address _ ArpaName.NameToAddress[rope].addr; IF address = Arpa.nullAddress THEN {Report[log, "Needs to be an Arpa address.\n"]; RETURN}; query _ IO.PutFR["%G.%G.%G.%G.IN-ADDR.ARPA", [integer[address.d]], [integer[address.c]], [integer[address.b]], [integer[address.a]]]; PrintOutgoing[server, serverName, query, ptr, data.class, data.recursionDesired, log]; reply _ DoQuery[server, query, ptr, data.class, data.protocol, data.recursionDesired, port, timeout, data.showErr, log]; PrintReply[server, reply, log]; }; Query: PROC [data: ClientData, type: ArpaNameQuery.QType] = { log: IO.STREAM _ data.log; server, source: Arpa.Address; reply: ArpaNameQuery.Reply _ NIL; serverName: ROPE = ViewerTools.GetContents[data.target]; query: ROPE _ ViewerTools.GetContents[data.query]; port: ArpaNameBuf.Port _ ArpaNameBuf.domainPort; timeoutRope: ROPE _ ViewerTools.GetContents[data.timeout]; timeout: ArpaUDP.Milliseconds _ Convert.CardFromRope[timeoutRope]; status: ArpaName.ReplyStatus; IF Rope.IsEmpty[serverName] THEN RETURN; IF Rope.IsEmpty[query] THEN RETURN; [server, status, source] _ ArpaName.NameToAddress[serverName]; SELECT status FROM bogus => {Report[log, serverName, ": not a valid name (", ArpaName.AddressToName[source].name, ").\n"]; RETURN}; down => {Report[log, "Name servers not responding.\n"]; RETURN}; other => {Report[log, serverName, ": no address for this name (", ArpaName.AddressToName[source].name, ").\n"]; RETURN}; ENDCASE; IF server = Arpa.nullAddress THEN {Report[log, serverName, ": unable to lookup name.\n"]}; PrintOutgoing[server, serverName, query, type, data.class, data.recursionDesired, log]; reply _ DoQuery[server, query, type, data.class, data.protocol, data.recursionDesired, port, timeout, data.showErr, log]; PrintReply[server, reply, log]; }; DoQuery: PROC [ server: Arpa.Address, query: Rope.ROPE, type: ArpaNameQuery.QType, class: ArpaNameQuery.QClass, protocol: ArpaNameQuery.Protocol, recurDesired: BOOL, port: ArpaNameBuf.Port, timeout: ArpaUDP.Milliseconds, showErrs: BOOL, log: IO.STREAM] RETURNS[reply: ArpaNameQuery.Reply] = { {ENABLE {UNWIND => NULL; ArpaNameQuery.Error => {PrintCode[code, log]; GOTO Quit}}; reply _ ArpaNameQuery.Query[server: server, query: query, type: type, class: class, recurDesired: recurDesired, protocol: protocol, port: port, timeout: timeout, retry: 0, acceptErrors: showErrs]; }; EXITS Quit => {}; }; PrintCode: PROC [code: ATOM, log: IO.STREAM] = { SELECT code FROM $destUnreachable => Report[log, "\nError: Destination unreachable.\n"]; $badRemoteAddress => Report[log, "\nError: Attempt to use broadcast address.\n"]; $nullDestination => Report[log, "\nError: Attempt to use null address.\n"]; $netUnreachable => Report[log, "\nICMP message: Net unreachable.\n"]; $hostUnreachable => Report[log, "\nICMP message: Host unreachable.\n"]; $portUnreachable => Report[log, "\nICMP message: Port unreachable.\n"]; $mustFragment => Report[log, "\nICMP message: Must fragment.\n"]; $sourceRouteFailure => Report[log, "\nICMP message: Source route failure.\n"]; $timeoutTimeToLive => Report[log, "\nICMP message: Timeout TimeToLive.\n"]; $parameterProblem => Report[log, "\nICMP message: Parameter problem.\n"]; $sourceQuench => Report[log, "\nICMP message: Source quench.\n"]; ENDCASE => Report[log, "\nError: ", Atom.GetPName[code], "\n"]; }; PrintOutgoing: PROC [ server: Arpa.Address, serverName: ROPE, query: Rope.ROPE, type: ArpaNameQuery.QType, class: ArpaNameQuery.QClass, recurDesired: BOOLEAN, log: IO.STREAM] = { IF log = NIL THEN RETURN; IF ArpaNameSupport.IsAddressRope[serverName] THEN Report[log, "\nAsking ", serverName, " = ", ArpaName.AddressToName[server].name, "\n"] ELSE Report[log, "\nAsking ", ArpaName.AliasToName[serverName].name, " = ", ConvertExtras.RopeFromArpaAddress[server], "\n"]; PrintQuery[query, type, class, log]; Report[log, "Recursion desired: "]; SELECT recurDesired FROM TRUE => Report[log, "TRUE\n"]; ENDCASE => Report[log, "FALSE\n"]; Report[log, "\n"]; IO.Flush[log]; }; Report: PROC [log: IO.STREAM, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10: ROPE _ NIL] = { IF log = NIL THEN RETURN; IF r1 # NIL THEN {IO.PutRope[log, r1]}; IF r2 # NIL THEN {IO.PutRope[log, r2]}; IF r3 # NIL THEN {IO.PutRope[log, r3]}; IF r4 # NIL THEN {IO.PutRope[log, r4]}; IF r5 # NIL THEN {IO.PutRope[log, r5]}; IF r6 # NIL THEN {IO.PutRope[log, r6]}; IF r7 # NIL THEN {IO.PutRope[log, r7]}; IF r8 # NIL THEN {IO.PutRope[log, r8]}; IF r9 # NIL THEN {IO.PutRope[log, r9]}; IF r10 # NIL THEN {IO.PutRope[log, r10]}; }; PrintReply: PROC [server: Arpa.Address, reply: ArpaNameQuery.Reply, log: IO.STREAM] = { IF log = NIL THEN RETURN; IF reply = NIL THEN {Report[log, "No reply to query.\n"]; RETURN;}; IF reply.source # server THEN Report[log, IO.PutFR["Strange source address: expected %G, found %G.\n", [rope[ConvertExtras.RopeFromArpaAddress[server]]], [rope[ConvertExtras.RopeFromArpaAddress[reply.source]]]]]; Report[log, "Reply: \n"]; SELECT reply.hdr.qr FROM query => Report[log, "qr: query, "]; response => Report[log, "qr: response, "]; ENDCASE => ERROR; SELECT reply.hdr.opcode FROM query => Report[log, "opcode: query"]; iquery => Report[log, "opcode: iquery"]; cquerym => Report[log, "opcode: cquerym"]; cqueryu => Report[log, "opcode: cqueryu"]; ENDCASE => ERROR; Report[log, IO.PutFR[", length: %G bytes.\n", [integer[reply.domainPacketLength]]]]; Report[log, IO.PutFR["aa: %G, tc: %G, rd: %G, ra: %G, ", [boolean[reply.hdr.authoritative]], [boolean[reply.hdr.truncated]], [boolean[reply.hdr.recurDesired]], [boolean[reply.hdr.recurAvail]]]]; SELECT reply.hdr.rcode FROM ok => Report[log, "rcode: ok"]; format => Report[log, "rcode: format"]; serverFailed => Report[log, "rcode: serverFailed"]; nameError => Report[log, "rcode: nameError"]; notImplemented => Report[log, "rcode: notImplemented"]; refused => Report[log, "rcode: refused"]; ENDCASE => ERROR; IF reply.hdr.truncated THEN Report[log, " ** TRUNCATED **"]; Report[log, "\n"]; Report[log, IO.PutFR["qdCount: %G, anCount: %G, nsCount: %G, arCount: %G\n", [integer[reply.hdr.qdCount]], [integer[reply.hdr.anCount]], [integer[reply.hdr.nsCount]], [integer[reply.hdr.arCount]]]]; IF reply.hdr.qdCount # reply.qdCount THEN Report[log, IO.PutFR[" ** INCORRECT QUERY RECORD COUNT.\n ** Query records found: %g.\n", [integer[reply.qdCount]]]]; IF reply.hdr.anCount # reply.anCount THEN Report[log, IO.PutFR[" ** INCORRECT ANSWER RR COUNT.\n ** Answer RRs found: %g.\n", [integer[reply.anCount]]]]; IF reply.hdr.nsCount # reply.nsCount THEN Report[log, IO.PutFR[" ** INCORRECT AUTHORITY RR COUNT.\n ** Authority RRs found: %g.\n", [integer[reply.nsCount]]]]; IF reply.hdr.arCount # reply.arCount THEN Report[log, IO.PutFR[" ** INCORRECT ADDITIONAL RR COUNT.\n ** Additional RRs found: %g.\n", [integer[reply.arCount]]]]; PrintQueries[reply, log]; PrintAnswerRRs[reply, log]; PrintAuthorityRRs[reply, log]; PrintAdditionalRRs[reply, log]; Report[log, "\n"]; Report[log, IO.PutFR["The response time was %G ms.\n", [integer[reply.responseTime]]]]; Report[log, "\n"]; IO.Flush[log]; }; PrintQueries: PROC [reply: ArpaNameQuery.Reply, log: IO.STREAM] = { IF reply.questions = NIL THEN RETURN; FOR i: INT IN[0..reply.qdCount) DO q: ArpaNameQuery.QuestionRecord _ reply.questions[i]; IF q = NIL THEN RETURN; PrintQuery[q.name, q.type, q.class, log]; ENDLOOP; }; PrintQuery: PROC [name: ROPE, type: ArpaNameQuery.QType, class: ArpaNameQuery.QClass, log: IO.STREAM] = { Report[log, IO.PutFR["Query Name: \"%G\", ", [rope[name]]]]; PrintQType[log, "Type: %G, ", type]; PrintQClass[log, "Class: %G\n", class]; }; PrintAnswerRRs: PROC [reply: ArpaNameQuery.Reply, log: IO.STREAM] = { IF reply.answers = NIL THEN RETURN; FOR i: INT IN[0..reply.anCount) DO an: ArpaNameQuery.ResourceRecord _ reply.answers[i]; IF an = NIL THEN RETURN; PrintRR[an, log]; ENDLOOP; }; PrintAuthorityRRs: PROC [reply: ArpaNameQuery.Reply, log: IO.STREAM] = { IF reply.authority = NIL THEN RETURN; FOR i: INT IN[0..reply.nsCount) DO ns: ArpaNameQuery.ResourceRecord _ reply.authority[i]; IF ns = NIL THEN RETURN; PrintRR[ns, log]; ENDLOOP; }; PrintAdditionalRRs: PROC [reply: ArpaNameQuery.Reply, log: IO.STREAM] = { IF reply.additional = NIL THEN RETURN; FOR i: INT IN[0..reply.arCount) DO ar: ArpaNameQuery.ResourceRecord _ reply.additional[i]; IF ar = NIL THEN RETURN; PrintRR[ar, log]; ENDLOOP; }; PrintRR: PROC [thisRR: ArpaNameQuery.ResourceRecord, log: IO.STREAM] = { OPEN ArpaNameQuery; name: ROPE _ thisRR.name; type: RRType _ thisRR.type; class: RRClass _ thisRR.class; ttl: ArpaNameQuery.Seconds _ thisRR.ttl; rDataLength: CARDINAL _ thisRR.dataLength; Report[log, IO.PutFR["RR Name: \"%G\", ", [rope[name]]]]; PrintRRType[log, "Type: %G, ", type]; PrintRRClass[log, "Class: %G", class]; Report[log, ".\n"]; Report[log, IO.PutFR[" TTL: %G, ", [cardinal[ttl]]]]; Report[log, IO.PutFR["RDataLength: %G", [integer[rDataLength]]]]; WITH thisRR SELECT FROM rr: ARR => { IF rDataLength = 4 THEN { rope: ROPE _ ConvertExtras.RopeFromArpaAddress[rr.address]; IO.PutF[log, " Addr: %G\n", [rope[rope]]]; } ELSE { Report[log, "Funny Length for type A.\n"]; }; }; rr: NsRR => IO.PutF[log, " Server is \"%G\".\n", [rope[rr.serverRope]]]; rr: MdRR => IO.PutF[log, " Mail Host is \"%G\".\n", [rope[rr.mdRope]]]; rr: MfRR => IO.PutF[log, " Forwarding Host is \"%G\".\n", [rope[rr.mfRope]]]; rr: CNameRR => IO.PutF[log, " Alias for \"%G\".\n", [rope[rr.cNameRope]]]; rr: SoaRR => { IO.PutRope[log, "\n"]; IO.PutF[log, " Primary server is \"%G\".\n", [rope[rr.soaRec.primaryServer]]]; IO.PutF[log, " Contact is \"%G\".\n", [rope[rr.soaRec.domainContact]]]; IO.PutF[log, " Serial: %G", [cardinal[rr.soaRec.serial]]]; IO.PutF[log, ", Refresh: %G", [cardinal[rr.soaRec.refresh]]]; IO.PutF[log, ", Retry: %G", [cardinal[rr.soaRec.retry]]]; IO.PutF[log, ", Expire: %G", [cardinal[rr.soaRec.expire]]]; IO.PutF[log, ", Min TTL: %G\n", [cardinal[rr.soaRec.minTtl]]]; }; rr: MbRR => IO.PutF[log, " Mail Host \"%G\".\n", [rope[rr.mbRope]]]; rr: MgRR => IO.PutF[log, " Member is \"%G\".\n", [rope[rr.mgRope]]]; rr: MrRR => IO.PutF[log, " New Name is \"%G\".\n", [rope[rr.mrRope]]]; rr: WksRR => { rope: ROPE _ ConvertExtras.RopeFromArpaAddress[rr.wksRec.address]; IO.PutF[log, " Addr: %G\n", [rope[rope]]]; IO.PutF[log, " Protocol: %G, Ports: ", [integer[rr.wksRec.protocol]]]; FOR i: INT IN [0..rr.wksRec.nPorts) DO IO.PutF[log, " %G ", [integer[rr.wksRec.ports[i]]]]; ENDLOOP; IO.PutRope[log, "\n"]; }; rr: PtrRR => IO.PutF[log, " PTR is \"%G\".\n", [rope[rr.ptrRope]]]; rr: HinfoRR => { IO.PutF[log, " CPU: %G, OS: %G.\n", [rope[rr.hinfoRec.cpu]], [rope[rr.hinfoRec.os]]];}; rr: MinfoRR => { IO.PutF[log, " List owner: %G, Errors-To: %G.\n", [rope[rr.minfoRec.rmailbx]], [rope[rr.minfoRec.emailbx]]];}; rr: MxRR => { IO.PutF[log, " Preference Value: %G,", [cardinal[rr.mxRec.preference]]]; IO.PutF[log, " Host Name: \"%G\".\n", [rope[rr.mxRec.host]]]}; ENDCASE => { IO.PutRope[log, ", Unknown Type.\n"]; }; }; PrintQType: PROC [ log: IO.STREAM, arg: ROPE, type: ArpaNameQuery.QType] = { text: ROPE _ SELECT type FROM a => "a", ns => "ns", md => "md", mf => "mf", cName => "cName", soa => "soa", mb => "mb", mg => "mg", mr => "mr", null => "null", wks => "wks", ptr => "ptr", hinfo => "hinfo", minfo => "minfo", mx => "mx", axfr => "axfr", mailb => "mailb", maila => "maila", star => "*", ENDCASE => " * Unknown Query Type *"; IO.PutF[log, arg, [rope[text]]]; }; PrintQClass: PROC [ log: IO.STREAM, arg: ROPE, class: ArpaNameQuery.QClass] = { text: ROPE _ SELECT class FROM in => "in", cs => "cs", ch => "ch", star => "*", ENDCASE => " * Unknown Query Class *"; IO.PutF[log, arg, [rope[text]]]; }; PrintRRType: PROC [ log: IO.STREAM, arg: ROPE, type: ArpaNameQuery.RRType] = { text: ROPE _ SELECT type FROM a => "a", ns => "ns", md => "md", mf => "mf", cName => "cName", soa => "soa", mb => "mb", mg => "mg", mr => "mr", null => "null", wks => "wks", ptr => "ptr", hinfo => "hinfo", minfo => "minfo", mx => "mx", ENDCASE => " * Unknown RR Type *"; IO.PutF[log, arg, [rope[text]]]; }; PrintRRClass: PROC [ log: IO.STREAM, arg: ROPE, class: ArpaNameQuery.RRClass] = { text: ROPE _ SELECT class FROM in => "in", cs => "cs", ch => "ch", ENDCASE => " * Unknown RR Class *"; IO.PutF[log, arg, [rope[text]]]; }; 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]; }; SelectorProc: TYPE = PROC [parent: Viewer, clientData: REF, value: ATOM]; Selector: TYPE = REF SelectorRec; SelectorRec: TYPE = RECORD [ value: REF ATOM, change: PROC [parent: Viewer, clientData: REF, value: ATOM], clientData: REF, buttons: LIST OF Buttons.Button, values: LIST OF ATOM ]; MakeSelector: PROC [parent, sibling: Viewer, clientData: REF _ NIL, values: LIST OF ATOM, name: ROPE, init: REF ATOM _ NIL, change: SelectorProc _ NIL] RETURNS [child: Viewer] = { selector: Selector _ NEW [SelectorRec _ [ value: IF init # NIL THEN init ELSE NEW [ATOM _ values.first], change: change, clientData: clientData, buttons: NIL, values: values ] ]; last: LIST OF Buttons.Button _ NIL; child _ Labels.Create[info: [name: name, parent: parent, border: FALSE, wx: sibling.wx + buttonWidth - 1, wy: sibling.wy] ]; FOR a: LIST OF ATOM _ values, a.rest UNTIL a = NIL DO child _ Buttons.Create[ info: [name: Atom.GetPName[a.first], parent: parent, border: TRUE, wx: child.wx + child.ww + 2, wy: child.wy], proc: SelectorHelper, clientData: selector, fork: TRUE, paint: TRUE]; IF last = NIL THEN last _ selector.buttons _ LIST[child] ELSE { last.rest _ LIST[child]; last _ last.rest }; IF a.first = selector.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack]; ENDLOOP; }; SelectorHelper: Buttons.ButtonProc = { <> self: Buttons.Button = NARROW[parent]; selector: Selector = NARROW[clientData]; buttons: LIST OF Buttons.Button _ selector.buttons; FOR a: LIST OF ATOM _ selector.values, a.rest UNTIL a = NIL DO IF self = buttons.first THEN { selector.value^ _ a.first; IF selector.change # NIL THEN selector.change[self.parent, selector.clientData, a.first]; Buttons.SetDisplayStyle[buttons.first, $WhiteOnBlack]; } ELSE Buttons.SetDisplayStyle[buttons.first, $BlackOnWhite]; buttons _ buttons.rest; ENDLOOP; }; 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: REF _ NIL, name: ROPE, init: REF BOOL _ NIL, change: BoolProc _ NIL] RETURNS [child: Viewer] = { bool: Bool _ NEW [BoolRec _ [ value: IF init = NIL THEN NEW [BOOL _ FALSE] ELSE init, change: change, clientData: clientData, button: NIL ] ]; child _ Buttons.Create[ info: [name: name, parent: parent, border: TRUE, wx: sibling.wx + buttonWidth - 1, wy: sibling.wy, ww: buttonWidth], proc: BoolHelper, clientData: bool, fork: TRUE, paint: TRUE]; bool.button _ child; IF bool.value^ THEN Buttons.SetDisplayStyle[child, $WhiteOnBlack]; }; BoolHelper: Buttons.ButtonProc = { <> 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: BOOL _ TRUE] 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 = { <> 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["ArpaNameTool", Create, "Probe Arpa Name Servers."]; END.