FetchCommanderImpl.Mesa
Copyright Ó 1987, 1988 by Xerox Corporation. All rights reserved.
Bill Jackson (bj) July 25, 1988 5:59:29 pm PDT
Bloomenthal, November 25, 1987 3:29:22 pm PST
DIRECTORY
Args USING [ Arg, ArgsGet, Error, NArgs ],
Ascii USING [ SP, TAB, CR, LF ],
BasicTime USING [ GMT, Now ],
CHNameP2V0 USING [ ],
Commander USING [ CommandProc, Register ],
Convert USING [ NetFormat, RopeFromXNSAddress, TimeFromRope ],
CourierBinding USING [ Bind ],
CrRPC USING [ CreateClientHandle, DestroyClientHandle, Error, Handle, PutArgsProc, PutRope ],
FetchP70V1 USING [ BadRelease, FileNotFound, Find, Predicate ],
IO USING [ PutF, rope, STREAM, time ],
Process USING [ CheckForAbort ],
Rope USING [ Cat, Concat, InlineFetch, Length, ROPE, Substr ],
TiogaMenuOps USING [ Open ],
UserCredentials USING [ CredentialsChangeProc, RegisterForChange ],
UserProfile USING [ CallWhenProfileChanges, Line, ProfileChangedProc ],
ViewerClasses USING [ Viewer ],
XNS USING [ Address, unknownAddress, unknownSocket ],
XNSCH USING [ LookupAddressFromRope ],
XNSCHName USING [ Name, RopeFromName ];
FetchCommanderImpl: CEDAR MONITOR
IMPORTS Args, BasicTime, Commander, Convert, CourierBinding, CrRPC, FetchP70V1, IO, Process, Rope, TiogaMenuOps, UserCredentials, UserProfile, XNSCH, XNSCHName ~ {
OPEN Fetch1: FetchP70V1;
ROPE: TYPE ~ Rope.ROPE;
UserProfile stuff
FORMAT: ROPE ~ "Fetch.Format"; defaultFormat: Convert.NetFormat ← octal;
RELEASE: ROPE ~ "Fetch.Release"; defaultRelease: ROPE ← "Mesa14.0";
SERVICE: ROPE ~ "Fetch.Service"; defaultService: ROPE ← "Anonymous Server::";
SOCKET: ROPE ~ "Fetch.Socket";HACK: BOOLTRUE;
GetDefaultsFromProfile: PROC ~ {
defaultFormat ← octal; -- UserProfile.Line[FORMAT, octal];
defaultRelease ← UserProfile.Line[RELEASE, "Mesa14.0"];
defaultService ← UserProfile.Line[SERVICE, "Anonymous Server::"];
HACKTRUE;
};
NewProfile: UserProfile.ProfileChangedProc ~ {
GetDefaultsFromProfile[];
};
NewUser: UserCredentials.CredentialsChangeProc ~ {
GetDefaultsFromProfile[];
};
Magic contants
(for Expanding Ring Broadcast)
program: CARD32 ← 70;
version: CARD16 ← 1;
maxhops: CARD16 ← 6;
(for the commander)
fetchinfo: ROPE ~ "FetchInfo";
fetchinfodoc: ROPE ~ "<NamePattern> [-h <serviceName> -r <releaseName> -d -v]
Query Fetch service for release information.
Switches:
-h <serviceName> query a particular service
-r <releaseName> specify which 'VersionMap' to use
-d list enclosing df
-v list server used";
fetchinfousage: ROPE ~ Rope.Concat["Usage: FetchInfo ", fetchinfodoc];
fetchopen: ROPE ~ "FetchOpen";
fetchopendoc: ROPE ~ "<NamePattern> [-h <serviceName> -r <releaseName> -d -v]
Query Fetch service for release information, then open viewer on relevant files.
Switches:
-h <serviceName> query a particular service
-r <releaseName> specify which 'VersionMap' to use
-d retrieve enclosing df
-v list server used";
fetchopenusage: ROPE ~ Rope.Concat["Usage: FetchOpen ", fetchopendoc];
Types
CachedServerObject: TYPE ~ RECORD [
address: XNS.Address,
lastCall: BasicTime.GMT,
name: ROPE
];
InfoList: TYPE ~ LIST OF REF InfoRec;
InfoRec: TYPE ~ RECORD [
date: BasicTime.GMT,
df: ROPE,
name: ROPE
];
Error handling
ErrorType: TYPE ~ { name, bind };
Error: ERROR [ type: ErrorType, msg: ROPE ] ~ CODE;
FIREWALL: SIGNAL ~ CODE;
Monitor
cachedServer: CachedServerObject;
GetCachedServer: ENTRY PROC [ ]
RETURNS
[ address: XNS.Address, lastCall: BasicTime.GMT, name: ROPE ] ~ {
address ← cachedServer.address;
lastCall ← cachedServer.lastCall;
name ← cachedServer.name;
};
SetCachedServer: ENTRY PROC [ name: ROPE, address: XNS.Address ] ~ {
IF ( ( address.socket # XNS.unknownSocket ) AND ( HACK ) )
THEN address.socket ← XNS.unknownSocket;
cachedServer.address ← address;
cachedServer.lastCall ← BasicTime.Now[];
cachedServer.name ← name;
};
UpdateTimestamp: ENTRY PROC [ ] ~ {
cachedServer.lastCall ← BasicTime.Now[];
};
Worker Procs
FindServer: PROC [ release: ROPE, host: ROPENIL ]
RETURNS [ addr: XNS.Address, distingName: XNSCHName.Name ] ~ {
PutArgsClosure: CrRPC.PutArgsProc ~ {
CrRPC.PutRope[s, release];
};
validServer: BOOL;
[distingName, addr] ← XNSCH.LookupAddressFromRope[host];
SELECT TRUE FROM
( addr # XNS.unknownAddress ) => { NULL };
( ( addr ← GetCachedServer[].address ) = XNS.unknownAddress ) => {
host ← "Anonymous Server::";
distingName ← [NIL, NIL, "Anonymous Server"];
addr ← CourierBinding.Bind[program, [version, version], maxhops, PutArgsClosure];
IF ( addr = XNS.unknownAddress )
THEN
ERROR Error[bind, "No Server located"];
};
ENDCASE => {
ENABLE { CrRPC.Error => { validServer ← FALSE; CONTINUE }; };
h: CrRPC.Handle ← CrRPC.CreateClientHandle[$SPP, NEW[XNS.Address ← addr]];
validServer ← Fetch1.Predicate[h, release];
CrRPC.DestroyClientHandle[h];
IF ( validServer ) THEN RETURN;
};
SetCachedServer[host, addr];
};
GetToken: PROC [ source: ROPE, offset: CARD16 ]
RETURNS [ token: ROPENIL, nextpos: CARD16 ] ~ {
FindToken: PROC [ source: ROPE, offset: CARD16 ]
RETURNS [ firstpos, nextpos: CARD16 ] ~ {
slen: CARD ~ Rope.Length[source];
hostPending: BOOL;
WhiteSpace: PROC [ ch: CHAR ] RETURNS [ yes: BOOL ] ~ INLINE {
yes ← SELECT ch FROM
( Ascii.SP ) => TRUE,
( Ascii.TAB ) => TRUE,
( Ascii.CR) => TRUE,
( Ascii.LF) => TRUE,
ENDCASE => FALSE;
};
FOR firstpos ← offset, firstpos ← firstpos.SUCC WHILE ( ( firstpos < slen ) AND ( WhiteSpace[Rope.InlineFetch[source, firstpos]] ) ) DO
ENDLOOP;
IF ( firstpos >= slen ) THEN FIREWALL;
hostPending ← ( Rope.InlineFetch[source, firstpos] = '[ );
FOR nextpos ← firstpos, nextpos ← nextpos.SUCC WHILE ( nextpos < slen ) DO
ch: CHAR ← Rope.InlineFetch[source, nextpos];
SELECT TRUE FROM
( ( NOT hostPending ) AND ( WhiteSpace[ch] ) ) => EXIT;
( hostPending ) => hostPending ← ( ch # '] );
ENDCASE;
ENDLOOP;
};
firstpos: CARD16;
[firstpos, nextpos] ← FindToken[source, offset];
token ← Rope.Substr[source, firstpos, (nextpos - firstpos)];
};
BustUpResults: PROC [ dfList, pathList, dateList: ROPE, nMatches: CARD16 ]
RETURNS [ list: InfoList ← NIL ] ~ {
n1, n2, n3: CARD16 ← 0;
fileName: ROPE;
dfName: ROPE;
date1, date2, date3: ROPE;
date: BasicTime.GMT;
FOR i: CARD16 IN [0..nMatches) DO
[fileName, n1] ← GetToken[pathList, n1];
[dfName, n2] ← GetToken[dfList, n2];
[date1, n3] ← GetToken[dateList, n3];
[date2, n3] ← GetToken[dateList, n3];
[date3, n3] ← GetToken[dateList, n3];
date ← Convert.TimeFromRope[Rope.Cat[date1, " ", date2, " ", date3]];
list ← CONS [NEW [InfoRec ← [date, dfName, fileName]], list];
ENDLOOP;
};
InfoInternal: PROC [ pattern: ROPE, host: ROPE, release: ROPE ]
RETURNS [ list: InfoList ← NIL, service: ROPENIL, place: ROPENIL ] ~ {
dfName: ROPE; filePath: ROPE; createDate: ROPE; nMatches: CARD16;
addr: XNS.Address; distingName: XNSCHName.Name; h: CrRPC.Handle;
CleanUp: PROC ~ {
CrRPC.DestroyClientHandle[h];
service ← XNSCHName.RopeFromName[distingName];
place ← Convert.RopeFromXNSAddress[addr, defaultFormat];
};
[addr, distingName] ← FindServer[release, host];
IF ( addr = XNS.unknownAddress ) THEN ERROR Error[name, "Server not found"];
IF ( ( addr.socket # XNS.unknownSocket ) AND ( HACK ) )
THEN addr.socket ← XNS.unknownSocket;
h ← CrRPC.CreateClientHandle[$SPP, NEW[XNS.Address ← addr]];
[dfName, filePath, createDate, nMatches] ←
Fetch1.Find[h, pattern, release, TRUE, TRUE, TRUE
! Fetch1.FileNotFound => { CleanUp[]; GOTO Finish };
Fetch1.BadRelease => { CleanUp[]; GOTO Finish }
];
list ← BustUpResults[dfName, filePath, createDate, nMatches];
CleanUp[];
EXITS
Finish => { NULL };
};
FillViewer: PROC [ name: ROPE ] RETURNS [ viewer: ViewerClasses.Viewer ] ~ {
viewer ← TiogaMenuOps.Open[name];
};
Commander Procs
FetchOpenProc: Commander.CommandProc ~ {
ENABLE { UNWIND => NULL };
out: IO.STREAM ~ cmd.out;
host, pattern, release, getDF, verbose: Args.Arg;
list: InfoList; service: ROPE; place: ROPE;
IF ( Args.NArgs[cmd] = 0 ) THEN { msg ← fetchopenusage; GOTO Failed };
[pattern, host, release, getDF, verbose] ← Args.ArgsGet[cmd, "%s-h%s-r%s-d%b-v%b"
! Args.Error => { msg ← reason; CONTINUE }];
IF ( msg # NIL ) THEN RETURN[$Failure, "Command syntax error."];
IF ( NOT host.ok ) THEN host.rope ← defaultService;
IF ( NOT release.ok ) THEN release.rope ← defaultRelease;
Process.CheckForAbort[];
[list, service, place] ← InfoInternal[pattern.rope, host.rope, release.rope];
SELECT TRUE FROM
( list = NIL ) => {
msg ← Rope.Cat["Sorry, '", pattern.rope, ".*' is not in the ", release.rope, " release."];
GOTO Failed;
};
ENDCASE => { NULL };
IF ( verbose.bool ) THEN IO.PutF[out, "[%g] at %g\n", IO.rope[service], IO.rope[place] ];
IF ( list.rest = NIL )
THEN IO.PutF[out, "%s =>\n", IO.rope[pattern.rope] ]
ELSE IO.PutF[out, "%s.* =>\n", IO.rope[pattern.rope] ];
FOR tail: InfoList ← list, tail.rest WHILE ( tail # NIL ) DO
IO.PutF[out, " %g\n %g\n", IO.rope[tail.first.name], IO.time[tail.first.date] ];
[] ← FillViewer[tail.first.name];
IF ( getDF.bool ) THEN {
IO.PutF[out, " From: %g\n", IO.rope[tail.first.df] ];
[] ← FillViewer[tail.first.df];
};
ENDLOOP;
EXITS
Failed => { result ← $Failure };
};
FetchInfoProc: Commander.CommandProc ~ {
ENABLE { UNWIND => NULL };
out: IO.STREAM ~ cmd.out;
host, pattern, release, listDF, verbose: Args.Arg;
list: InfoList; service: ROPE; place: ROPE;
IF ( Args.NArgs[cmd] = 0 ) THEN { msg ← fetchinfousage; GOTO Failed };
[pattern, host, release, listDF, verbose] ← Args.ArgsGet[cmd, "%s-h%s-r%s-d%b-v%b"
! Args.Error => { msg ← reason; CONTINUE }];
IF ( msg # NIL ) THEN RETURN[$Failure, "Command syntax error."];
IF ( NOT host.ok ) THEN host.rope ← defaultService;
IF ( NOT release.ok ) THEN release.rope ← defaultRelease;
Process.CheckForAbort[];
[list, service, place] ← InfoInternal[pattern.rope, host.rope, release.rope];
SELECT TRUE FROM
( list = NIL ) => {
msg ← Rope.Cat["Sorry, '", pattern.rope, ".*' is not in the ", release.rope, " release."];
GOTO Failed;
};
ENDCASE => { NULL };
IF ( verbose.bool ) THEN IO.PutF[out, "[%g] at %g\n", IO.rope[service], IO.rope[place] ];
IF ( list.rest = NIL )
THEN IO.PutF[out, "%s =>\n", IO.rope[pattern.rope] ]
ELSE IO.PutF[out, "%s.* =>\n", IO.rope[pattern.rope] ];
FOR tail: InfoList ← list, tail.rest WHILE ( tail # NIL ) DO
IO.PutF[out, " %g\n %g\n", IO.rope[tail.first.name], IO.time[tail.first.date] ];
IF ( listDF.bool ) THEN IO.PutF[out, " From: %g\n", IO.rope[tail.first.df] ];
ENDLOOP;
EXITS
Failed => { result ← $Failure };
};
Initialization
Init: PROC ~ {
GetDefaultsFromProfile[];
UserProfile.CallWhenProfileChanges[NewProfile];
UserCredentials.RegisterForChange[NewUser];
SetCachedServer[defaultService, XNS.unknownAddress];
Commander.Register[fetchinfo, FetchInfoProc, fetchinfodoc];
Commander.Register[fetchopen, FetchOpenProc, fetchopendoc];
};
Init[];
}.