-- File: TestTranslation.mesa 
-- HGM, March 16, 1981  9:28 PM

DIRECTORY
  AddressTranslation USING [
    AppendMyHostNumber, AppendNetworkAddress, StringToNetworkAddress],
  BufferDefs USING [BufferAccessHandle, OisBuffer],
  FormSW USING [
    AllocateItemDescriptor, ClientItemsProcType, CommandItem,
    ItemHandle, newLine,
    ProcType, StringItem],
  MsgSW USING [Post],
  OISCPTypesAdditions USING [pupAddrTransPacket],
  OISCP USING [
    OiscpPackageDestroy, OiscpPackageMake,
    GetFreeSendOisBufferFromPool, ReturnFreeOisBuffer,
    GetOisPacketTextLength, SetOisPacketTextLength],
  OISCPConstants USING [unknownSocketID],
  OISCPConstantsAdditions USING [pupAddressTranslation],
  Put USING [Char, CR, Line, Text],
  PupDefs USING [AppendPupAddress, PupAddress],
  Socket USING [
    Abort, AssignNetworkAddress, Create, Delete, GetPacket, PutPacket,
    SetWaitTime, TimeOut, TransferStatus],
  SocketInternal USING [GetBufferPool, SocketHandle],
  SpecialSystem USING [NetworkAddress, HostNumber],
  Storage USING [Free, FreeStringNil, String],
  String USING [AppendString],
  System USING [],
  Tool USING [
    Create, UnusedLogName, MakeFormSW, MakeFileSW, MakeMsgSW, MakeSWsProc],
  ToolWindow USING [TransitionProcType],
  Window USING [Handle];

TestTranslation: PROGRAM
  IMPORTS
    FormSW, MsgSW, Put, Storage, String, Tool,
    AddressTranslation, OISCP, Socket, SocketInternal, PupDefs
  EXPORTS Socket, System
  SHARES BufferDefs =
  BEGIN

  -- From PupAddressTranslationServer.mesa
  translationRequest: CARDINAL = 1;
  translationResponse: CARDINAL = 2;
  translationError: CARDINAL = 3;

  -- EXPORTED TYPE(S)
  NetworkAddress: PUBLIC TYPE = SpecialSystem.NetworkAddress;
  ChannelHandle: PUBLIC TYPE = SocketInternal.SocketHandle;

  -- global variable declarations
  msg, log, form: Window.Handle ← NIL;
  machine, server: STRING ← NIL;
  localAddr: SpecialSystem.NetworkAddress;

  Init: PROCEDURE =
    BEGIN
    [] ← Tool.Create[
      name: "Test Translation of March 16, 1981"L, makeSWsProc: MakeThisTool,
      clientTransition: Transition];
    END;

  MakeThisTool: Tool.MakeSWsProc =
    BEGIN
    logFileName: STRING = [40];
    msg ← Tool.MakeMsgSW[window: window, lines: 1];
    form ← Tool.MakeFormSW[window: window, formProc: MakeItemArray];
    Tool.UnusedLogName[logFileName, "TestTranslation.log$"L];
    log ← Tool.MakeFileSW[window: window, name: logFileName];
    END;

  MakeItemArray: FormSW.ClientItemsProcType =
    BEGIN
    nItems: CARDINAL = 3;
    i: INTEGER ← -1;
    items ← FormSW.AllocateItemDescriptor[nItems];
    items[i ← i + 1] ← FormSW.CommandItem[
      tag: "Poke"L, place: FormSW.newLine, proc: Poke];
    items[i ← i + 1] ← FormSW.StringItem[
      tag: "Server"L, string: @server, inHeap: TRUE];
    items[i ← i + 1] ← FormSW.StringItem[
      tag: "Machine (network address format)"L, string: @machine, place: FormSW.newLine, inHeap: TRUE];
    IF (i + 1) # nItems THEN ERROR;
    RETURN[items, TRUE];
    END;

  Transition: ToolWindow.TransitionProcType =
    BEGIN
    IF old = inactive THEN -- tool is becomming active
      BEGIN
      OISCP.OiscpPackageMake[];
      localAddr ← Socket.AssignNetworkAddress[];
      server ← Storage.String[40];
      String.AppendString[server,"0#*#"L];
      machine ← Storage.String[40];
      String.AppendString[machine,"0#"L];
      AddressTranslation.AppendMyHostNumber[machine];
      END
    ELSE
      IF new = inactive THEN
	BEGIN
	server ← Storage.FreeStringNil[server];
	machine ← Storage.FreeStringNil[machine];
	OISCP.OiscpPackageDestroy[];
	END;
    END;

  Poke: FormSW.ProcType =
    BEGIN
    remoteAddr, who: SpecialSystem.NetworkAddress;
    cH: ChannelHandle;
    where: LONG POINTER TO SpecialSystem.HostNumber;
    myBufferAccessHandle: BufferDefs.BufferAccessHandle;
    b: BufferDefs.OisBuffer;
    status: Socket.TransferStatus;
    errFlag, hit: BOOLEAN ← FALSE;

    MsgSW.Post[msg, ""L];
    remoteAddr ← AddressTranslation.StringToNetworkAddress[server !
      ANY =>
	BEGIN
	MsgSW.Post[msg, "RemoteAddress is incorrectly specified; try again."L];
	errFlag ← TRUE;
	CONTINUE;
	END];
    who ← AddressTranslation.StringToNetworkAddress[machine !
      ANY =>
	BEGIN
	MsgSW.Post[msg, "Machine is incorrectly specified; try again."L];
	errFlag ← TRUE;
	CONTINUE;
	END];
    IF errFlag THEN RETURN;
    IF remoteAddr.socket=OISCPConstants.unknownSocketID THEN
      remoteAddr.socket ← OISCPConstantsAdditions.pupAddressTranslation;
    cH ← Socket.Create[localAddr];
    myBufferAccessHandle ← SocketInternal.GetBufferPool[cH];
    Socket.SetWaitTime[cH, 1500]; -- milli-seconds

    FOR i: CARDINAL IN [0..10) UNTIL hit DO
      b ← OISCP.GetFreeSendOisBufferFromPool[myBufferAccessHandle];
      OISCP.SetOisPacketTextLength[b, 2*(3+SIZE[SpecialSystem.HostNumber])];
      b.ois.transCntlAndPktTp.packetType ← OISCPTypesAdditions.pupAddrTransPacket;
      b.ois.destination ← remoteAddr;
      b.ois.oisWords[0] ← b.ois.oisWords[1] ← i;
      b.ois.oisWords[2] ← translationRequest;
      where ← LOOPHOLE[@b.ois.oisWords[3]];
      where↑ ← who.host;
      Socket.PutPacket[cH, b];
      DO
	b ← Socket.GetPacket[ cH !
	  Socket.TimeOut => BEGIN IF ~hit THEN Put.Char[log, '?]; EXIT; END];
	status ← LOOPHOLE[b.status];
        IF remoteAddr#b.ois.source THEN
          BEGIN
          temp: STRING = [50];
          Put.Text[log, "Response from: "L];
          AddressTranslation.AppendNetworkAddress[temp, b.ois.source];
          Put.Line[log, temp];
          END;
	SELECT TRUE FROM
	  (status # goodCompletion) =>
	    BEGIN -- some kind of error occurred
	    --PrintSocketEchoError[b, status];
	    Put.Char[log, 'e];
	    END;
          (b.ois.oisWords[2] = translationError) =>
	    BEGIN
	    n: CARDINAL ← OISCP.GetOisPacketTextLength[b];
	    text: LONG POINTER TO PACKED ARRAY [0..0) OF CHARACTER;
	    text ← LOOPHOLE[@b.ois.oisWords[0]];
	    FOR i: CARDINAL IN [6..n) DO Put.Char[log, text[i]]; ENDLOOP;
	    Put.CR[log];
	    END;
	  OISCP.GetOisPacketTextLength[b] # 2*(3 + SIZE[PupDefs.PupAddress])
          OR (b.ois.oisWords[2] # translationResponse) =>
	    BEGIN
	    Put.Char[log, '#];
	    END;
	  ENDCASE =>
	    BEGIN -- the response we were looking for
            temp: STRING = [50];
            answer: LONG POINTER TO PupDefs.PupAddress;
            answer ← LOOPHOLE[@b.ois.oisWords[3]];
            hit ← TRUE;
            Put.Text[log, "Answer: "L];
            PupDefs.AppendPupAddress[temp, answer↑];
            Put.Line[log, temp];
	    Put.CR[log];
	    END;
	  OISCP.ReturnFreeOisBuffer[b];
	ENDLOOP;
      ENDLOOP;
    Put.CR[log];
    Socket.Abort[cH];
    Socket.Delete[cH];
    MsgSW.Post[msg, ""L];
    END;

  Init[]; -- this gets string out of global frame
  END...