{ Routines to allow access to files on another filestore }

{ Genealogy:       RWT begat eftp,                                       }
{              and RDW ripped off bits for the first version of sethost, }
{              and FDC expanded it somewhat                              }

%include "INC:UTIL.IMP"
%include "INC:FS.IMP"

%own %short free port = 3


{ THESE NEXT TWO PROCEDURES ARE RIPPED OFF FROM EFTP, THANKS RAINER}
%predicate gotack(%integer port)
! Wait for ACK and return TRUE.
! Return FALSE if fed up waiting.
%integer bit,deadline
  bit = 1<<port
  deadline = cputime+15000
  %cycle
    %if ack&bit#0 %start
      %trueif nak&bit=0
      nak = nak!!bit
      %false
    %finish
  %repeatuntil cputime>deadline
  %false
%end

%predicate gotdtx(%integer port)
! Wait for DTX and TRUE.  FALSE when fed up
%integer bit,deadline
  bit = 1<<port
  deadline = cputime+15000
  %cycle
    %trueif dtx&bit#0
  %repeatuntil cputime>deadline
  %false
%end

{ Crummy language doesn't allow constant record arrrays }
{ Back to FORTRAN-speak }
%constant %integer Max Fs = 5
%constant %string (16) %array FNames(1:Max Fs) =
   "Alpha",    "Bravo",    "Charlie",
   "Portable", "Vax"
%constant %integer %array FNumbers(1:Max Fs) =
   16_14, 16_15, 16_1B, 16_3F, 16_72


{---------- FILESTORE NAME ----------}
%external %string (255) %function Filestore Name (%integer n)
   %integer i

   %for i = 1, 1, Max Fs %cycle
      %result = FNames(i) %if FNumbers(i) = n
   %repeat
   %result = "Unknown"
%end {Filestore Name}

{---------- FILESTORE NUMBER ----------}
%external %integer %function Filestore Number (%string (*) %name Fs)
   %integer i

   %predicate Prefix Match(%string (*) %name s1, s2)
   { Does s1 match a prefix of s2 ? }
      %integer i

      %false %if Length(s1) > Length(s2)
      %for i = 1, 1, Length(s1) %cycle
         %false %if (charno(s1, i) ! 32) # (charno(s2, i) ! 32)
      %repeat
      %true
   %end { Prefix Match }

   %for i = 1, 1, Max Fs %cycle
      %result = FNumbers(i) %if Prefix Match(Fs, FNames(i))
   %repeat
   %signal 10, 0, 1, "Filestore ".Fs." unknown"
%end {Filestore Number}


{---------- CURRENT HOST ----------}
{ Returns a token which identifies the current host. } 

%external %integer %function Current Host
   %result = (lsap << 16) ! userno %if fsport = lsap
   %signal 3, 9, 99, "fsport and lsap differ !"
%end


{---------- SELECT HOST ----------}
{ Switches to the filestore identified by 'token'.                      }
{ 'token' must have been returned by Current Host or Connect to Host.   }

%external %routine Select Host(%integer token)
   userno = token & 16_FFFF
   lsap = token >> 16
   fsport = lsap
%end

{---------- CONNECT TO HOST ----------}
{ Given a generalised directory name, this function logs on to it  }
{ and returns a token which can be used in calls to Select Host,   }
{ and which must be used in a call to Disconnect Host before the   }
{ caller terminates.  It is the caller's responsibility to save    }
{ Current Host before calling this function and reselect it before }
{ terminating.                                                     }

{ <Generalised Directory> = <Filestore Name>::<Directory Name>,<Password> /
{                           ::<Filestore Name>:<Directory Name>,<Password>
{ <Filestore Name>        = Alpha / Bravo / Charlie / Portable / Vax
{ <Directory Name>        = Up to 6 alphanumerics
{ <Password>              = Any string

{ Filestore Name default to Bravo,  Directory Name defaults to PUB }
{ and Password defaults to "".                                     }

{ Events: 10 0 1 - Unknown filestore                               }
{ Events: 10 0 2 - No response from filestore                      }
{         10 0 3 - Illegal connect attempted                       }

%external %integer %function Connect to Host(%string (255) GDir)

   %string (255) Name, Dir Pass
   %integer Number, i
   %byte facil = 2
   %byte %array buff(0:63)
   %label dunparsin

   Name = ""
   Dir Pass = ""
   -> dunparsin %if GDir = ""
   %if GDir -> Name.("::").Dir Pass %start
      -> dunparsin %if Length(Dir Pass) = 0                 { e.g. B:: }
      -> dunparsin %if Dir Pass -> Name.(":").Dir Pass      { ::B:D }
      -> dunparsin                                          { B::D or ::B }
   %else
      Dir Pass = GDir
   %finish
   dunparsin:
   Name = "Bravo" %if Length(Name) = 0
   Number = Filestore Number(Name)

   %if Number # RDTE %or Dir Pass # "" %start
      Dir Pass = "PUB" %if Length(Dir Pass) = 0
      etheropen(free port, Number << 8)
      etherwrite(free port, facil, 1)
      %if %not gotack(free port) %and gotdtx(free port) %then %c
         %signal 10, 0, 2, "No response from ".Name."::"
      i = etherread(free port, buff(0), 64)
      %if i # 2 %or buff(1) # 10 %or buff(0) < '0' %then %c
         %signal 10, 0, 3, "Illegal Connect attempted to ".Name."::"
      buff(0) = buff(0) - '0'
      etheropen(free port, (Number << 8) ! buff(0))
      lsap = free port
      fsport = lsap
      userno = fcomm('L0', Dir Pass)
      free port = free port + 1
   %finish

   %result = Current Host 
   
%end

{---------- DISCONNECT HOST ----------}
{ Disconnect from the host identified by 'token' }

%external %routine Disconnect Host(%integer Token)
   %byte eot = 12
   %byte port

   port = Token >> 16
   %return %if port = 1       { don't disconnect from boot port }
   etherwrite(port, eot, 1)
   { do not worry about not getting ack that would only screw us up }
   etherclose(port)
%end
