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.ROPE ← NIL] = {
newName: ROPE;
rootDomain: ROPE;
server: ROPE;
addr, source: Arpa.Address;
valid: BOOLEAN ← FALSE;
hostList: LIST OF ROPE ← NIL;
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.ROPE ← NIL, 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: 
BOOLEAN←
FALSE, domain: Rope.
ROPE←
NIL] = {
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"];
 
}.