ArpaQueryServerImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
John Larson, March 13, 1988 7:43:48 pm PST
DIRECTORY
Arpa USING [Address],
ArpaConfig USING [ specialDomains, topLevelDomains, validDomains, bitnetGateway, csnetGateway, uucpGateway, resolv ],
ArpaName USING [AddressToName, AliasToName, NameToAddress, NameToMailHostList, ReplyStatus],
ArpaQuery,
ArpaQueryRpcControl,
Commander USING [CommandProc, Register],
IO USING [PutF, PutFR, rope],
LupineRuntime USING [BindingError],
Rope USING [ ROPE, Cat, Concat, Equal, Fetch, Find, Length, Substr ],
RPC USING [ Conversation, EncryptionKey, ExportFailed, MakeKey, matchAllVersions, unencrypted ],
QueryServices;
ArpaQueryServerImpl: CEDAR PROGRAM
IMPORTS ArpaConfig, ArpaName, ArpaQueryRpcControl, Commander, LupineRuntime, Rope, RPC, IO, QueryServices
EXPORTS ArpaQuery = {
OPEN ArpaQuery;
ROPE: TYPE = Rope.ROPE;
CheckName: PUBLIC PROC [
shh: RPC.Conversation←RPC.unencrypted, name: Rope.ROPE, abort: REF BOOL]
RETURNS [rope: Rope.ROPENIL] = {
newName: ROPE;
rootDomain: ROPE;
server: ROPE;
addr, source: Arpa.Address;
valid: BOOLEANFALSE;
hostList: LIST OF ROPENIL;
status: ArpaName.ReplyStatus;
IF Rope.Find[name,"@"] > -1 THEN name ← BreakName[name, '@].right;
IF Rope.Find[name, "."] = -1 THEN {
rope ← Rope.Cat[rope, "\nNeed top level domain. The mail gateway default is \".ARPA\".\n"];
name ← Rope.Concat[name, ".ARPA"];};
[valid, rootDomain] ← ValidDomain[name];
IF ~valid THEN {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => \"%g\" is not a known top level domain.\n\nArpanet top level domains we currently know about are:\n", IO.rope[name], IO.rope[BreakName[name].right]]];
FOR list: LIST OF Rope.ROPE ← ArpaConfig.topLevelDomains, list.rest UNTIL list = NIL DO
topLevelDomain: Rope.ROPE ← list.first;
rope ← Rope.Cat[rope, topLevelDomain, " "];
ENDLOOP;
rope ← Rope.Cat[rope, "\n\nSpecial locally recognized domains are:\n\n"];
FOR list: LIST OF Rope.ROPE ← ArpaConfig.specialDomains, list.rest UNTIL list = NIL DO
specialDomain: Rope.ROPE ← list.first;
rope ← Rope.Cat[rope, specialDomain, " "];
ENDLOOP;
rope ← Rope.Cat[rope, "\n\nMail forwarding is supported locally for these domains with the following translation rules.\n Local address => Arpanet address\n\n"];
FOR list: LIST OF Rope.ROPE ← ArpaConfig.specialDomains, list.rest UNTIL list = NIL DO
specialDomain: Rope.ROPE ← list.first;
rope ← Rope.Cat[rope, " ", "user@host."];
SELECT TRUE FROM
Rope.Equal["UUCP", specialDomain, FALSE] => {
rope ← Rope.Cat[rope, specialDomain, " => user%host.", specialDomain];
rope ← Rope.Cat[rope, "@", ArpaConfig.uucpGateway, "\n"];};
Rope.Equal["Bitnet", specialDomain, FALSE] => {
rope ← Rope.Cat[rope, specialDomain, " => user%host.", specialDomain];
rope ← Rope.Cat[rope, "@", ArpaConfig.bitnetGateway, "\n"];};
Rope.Equal["CSNET", specialDomain, FALSE] => {
rope ← Rope.Cat[rope, specialDomain, " => user%host.", specialDomain];
rope ← Rope.Cat[rope, "@", ArpaConfig.csnetGateway, "\n"];};
ENDCASE;
ENDLOOP;
RETURN[rope];
};
IF LocalDomain[rootDomain] THEN {
gateway: ROPE;
host: ROPE ← BreakName[name].left;
SELECT TRUE FROM
Rope.Equal["UUCP", rootDomain, FALSE] => gateway ← ArpaConfig.uucpGateway;
Rope.Equal["Bitnet", rootDomain, FALSE] => gateway ← ArpaConfig.bitnetGateway;
Rope.Equal["CSNET", rootDomain, FALSE] => gateway ← ArpaConfig.csnetGateway;
ENDCASE;
rope ← Rope.Cat[rope, IO.PutFR["\n\"%g\" is not a valid Arpanet name, but Grapevine mail to \"user@%g\" is forwarded by the Arpanet mail gateway to the Arpanet address \"user%%%g@%g\". ", IO.rope[name], IO.rope[name], IO.rope[name], IO.rope[gateway]]];
rope ← Rope.Cat[rope, IO.PutFR["To find out if %g is likely to recognize this name, check the %g host table with:\n\n QFind %g [Indigo]<NetInfo>%g>%g-hosts.txt\n",
IO.rope[gateway], IO.rope[rootDomain], IO.rope[host], IO.rope[rootDomain], IO.rope[rootDomain]]];
RETURN[rope];
};
IF abort^ THEN RETURN[NIL];
[newName, status, source] ← ArpaName.AliasToName[name, ArpaConfig.resolv^];
server ← ArpaName.AddressToName[source, ArpaConfig.resolv^].name;
SELECT status FROM
down => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => Name servers not responding. Try again later.\n", [rope[name]]]];
RETURN[rope];
};
bogus => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => not valid. \n(Name server: %g)\n", IO.rope[name], IO.rope[server]]];
RETURN[rope];
};
ok => {
IF ~Rope.Equal[newName, name, FALSE] THEN {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => Alias for %g.\n(Name server: %g)\n", IO.rope[name], IO.rope[newName], IO.rope[server]]];
RETURN[rope]};
};
ENDCASE;
IF abort^ THEN RETURN[NIL];
[hostList, status, source] ← ArpaName.NameToMailHostList[name, ArpaConfig.resolv^];
server ← ArpaName.AddressToName[source, ArpaConfig.resolv^].name;
SELECT status FROM
down => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => Name servers not responding. Try again later.\n", [rope[name]]]];
RETURN[rope];
};
bogus => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => not valid. \n(Name server: %g)\n", IO.rope[name], IO.rope[server]]];
RETURN[rope];
};
ok => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => ok. \n(Name server: %g)\n", IO.rope[name], IO.rope[server]]];
RETURN[rope];
};
ENDCASE;
IF abort^ THEN RETURN[NIL];
[addr, status, source] ← ArpaName.NameToAddress[name, ArpaConfig.resolv^];
server ← ArpaName.AddressToName[source, ArpaConfig.resolv^].name;
SELECT status FROM
down => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => Name servers not responding. Try again later.\n", [rope[name]]]];
RETURN[rope];
};
bogus => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => not valid. \n(Name server: %g)\n", IO.rope[name], IO.rope[server]]];
RETURN[rope];
};
ok => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => ok. \n(Name server: %g)\n", IO.rope[name], IO.rope[server]]];
RETURN[rope];
};
ENDCASE => {
rope ← Rope.Cat[rope, IO.PutFR["\n%g => Domain name, not valid for mail.\n(Name server: %g)\n", IO.rope[name], IO.rope[server]]];
RETURN[rope];
};
};
Whois: PUBLIC PROC [
shh: RPC.Conversation←RPC.unencrypted, pattern: Rope.ROPE, server: Rope.ROPENIL, abort: REF BOOL]
RETURNS [rope: Rope.ROPE] = {
rope ← QueryServices.Whois[pattern, server, abort];
};
ArpaFinger: PUBLIC PROC [
shh: RPC.Conversation←RPC.unencrypted, pattern: Rope.ROPE, abort: REF BOOL]
RETURNS [rope: Rope.ROPE] = {
rope ← QueryServices.Finger[pattern, abort];
};
LocalDomain: PROC[domain: Rope.ROPE] RETURNS[BOOLEAN] = {
FOR list: LIST OF Rope.ROPE ← ArpaConfig.specialDomains, list.rest UNTIL list = NIL DO
specialDomain: Rope.ROPE ← list.first;
IF Rope.Equal[specialDomain, domain, FALSE] THEN RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];};
ValidDomain: PROC [name: ROPE] RETURNS [valid: BOOLEANFALSE, domain: Rope.ROPENIL] = {
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, domain];
ENDLOOP;
RETURN[FALSE, NIL];};
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] 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]; };
BreakName: PROC[name: Rope.ROPE, char: CHAR ← '.] RETURNS[left, right: Rope.ROPE] =
BEGIN
length: INT = name.Length[];
FOR i: INT DECREASING IN [0..length) DO
IF name.Fetch[i] = char 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;
serverInterfaceName: ArpaQueryRpcControl.InterfaceName;
serverPassword: RPC.EncryptionKey;
serverInstance: ROPE ← "ArpaGateway.ms";
ArpaQueryServerInit: Commander.CommandProc = {
ENABLE
RPC.ExportFailed => { cmd.out.PutF["ArpaQuery export failed"]; GOTO Failed; };
serverInterfaceName ← [
type: serverInstance,
instance: serverInstance];
serverPassword ← RPC.MakeKey["Security??"];
ArpaQueryRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE];
ArpaQueryRpcControl.ExportInterface[
interfaceName: serverInterfaceName,
user: serverInterfaceName.instance,
password: serverPassword];
cmd.out.PutF["Export[ArpaQuery, %g]\n", IO.rope[serverInterfaceName.instance]];
EXITS
Failed => ArpaQueryRpcControl.UnexportInterface[!LupineRuntime.BindingError=>CONTINUE];
};
Commander.Register["ArpaQueryServer", ArpaQueryServerInit,
"ArpaQueryServer\nInitialize and Export ArpaQuery"];
}.