-- Em3270ComPack:   3270 Communication
-- Copyright (C) 1983, 1984 by Xerox Corporation

-- Last revised for Star 3.3L by Lui:	 5-Jul-84 12:28:31     
-- Owner:  Lui


DIRECTORY
  Auth USING [CallProblem],
  CH USING [ConversationHandle],
  Em3270BufferDefs USING [Release, Reserve],
  Em3270CmdProcessDefs USING [CheckSyntax, ProcessCommands, SyntaxError],
  Em3270ComDefs,
  Em3270Defs USING [Lpttrt3270icondata],
  Em3270PrivDefs,
  Em3270StatusDefs USING [DisplayCode, ClearStatusArea],
  IconDefs USING [Icon, ParentFromIcon, ReferenceFromIcon],
  MessageDefs,
  MessageSwnDefs USING [DisplayMessage],
  GateStream USING [
    abortGetTransaction, abortMark, chain3270, Create, Error, ErrorReason, hostPolling3270,
    hostNotPolling3270, ForeignDevice, infiniteTime, mediumDown, mediumUp, none,
    SessionParameterObject, Transport, TransportObject, unchained3270, unexpectedRemoteBehavior,
    unexpectedSoftwareFailure, unsupportedProtocolFeature],
  NSFile USING [AttributesRecord, Close, Handle, OpenChild],
  NSName USING [FreeName, MakeName, Name, NameFieldsFromString],
  NSString USING [AppendToMesaString, FreeString, String, ValidAsMesaString],
  Process USING [Abort], 
  SchemaDefs  USING [Lschema, lschemaNil],
  StandardDefs USING [Bv],
  Stream USING [
    Block, Byte, CompletionCode, Delete, GetBlock, Handle, PutBlock,
    SetInputOptions, SetSST, SubSequenceType, WaitForAttention],
  SvDefs USING [NumericAppendCv],
  System USING [NetworkAddress],
  TraitDefs USING [MyData],
  UserDefs USING [AcquireConversation],
  ZkeyMessageDefs USING [DisplayMessage],
  ZoneMgrDefs USING [GetPredefinedZone];



Em3270ComPack: PROGRAM 
  IMPORTS
    Em3270BufferDefs, Em3270CmdProcessDefs, Em3270PrivDefs,
    Em3270StatusDefs, GateStream, IconDefs, MessageSwnDefs, NSFile, 
    NSName, NSString, Process, Stream, SvDefs, TraitDefs,
    UserDefs, ZkeyMessageDefs, ZoneMgrDefs
  
  EXPORTS Em3270ComDefs, Em3270PrivDefs
  SHARES IconDefs =
  
  BEGIN OPEN Em3270ComDefs, Em3270PrivDefs;
  
  -- ====================
  --     Types 
  -- ====================
  LptComData: TYPE = LONG POINTER TO ComData;
  ComData: PUBLIC TYPE = RECORD [
    streamHandle: Stream.Handle ← NIL,
    lschemaWn: SchemaDefs.Lschema ← SchemaDefs.lschemaNil,
    streamWaitAttentionProcess: PROCESS,  -- a forked process which calls procdure DoStreamWaitAttention
    streamGetProcess: PROCESS,	    -- a forked process which calls procedure DoStreamGet
    lptCmdData: LptCmdData ← LOOPHOLE[LONG[NIL]],   -- points to Command processor's instance data.
    bvHostPolling: StandardDefs.Bv ← TRUE,    -- will assume host is polling unless told otherwise.
    bvHostGone: StandardDefs.Bv ← FALSE  -- true => no longer connected to host. -- ];
  Status: TYPE = {okay, abort, stop, wrongOrder};
  ErrorCode: TYPE = {unexpectedRemotebehavior, unexpectedSoftwarefailure, unsupportedProtocol, undefinedError, none};
  
  -- ====================
  --   Global Variables 
  -- ====================
  NoHostName: ERROR = CODE;
  RetypeHostName: ERROR = CODE;
  AbortOpen: PUBLIC ERROR = CODE;	 -- raised if a stream cannot be created. Whoever called Start should be prepare to catch this error.
  comZone: UNCOUNTED ZONE ← ZoneMgrDefs.GetPredefinedZone[session];
  spredefinedZone: UNCOUNTED ZONE ← ZoneMgrDefs.GetPredefinedZone[
    short];
  -- ====================
  
  StartCom: PUBLIC PROC [lschemaWn: SchemaDefs.Lschema, icon: IconDefs.Icon, lptCmdData: LptCmdData] RETURNS [comHandle: LptComData] =
    -- Start will call procedure Init to
    BEGIN
    comHandle ← comZone.NEW[ComData];
    comHandle.lschemaWn ← lschemaWn;
    comHandle.lptCmdData ← lptCmdData;     -- store handle to instance data of its corresponding command processor 
    comHandle.streamHandle ← CreateStream[lschemaWn, icon ! 
		  AbortOpen => comZone.FREE[@comHandle];];      -- creates a stream to an IBM Host. AbortOpen is raised and should be caught by whoever Called StartCom
    END; 
    
  ForkComProcesses: PUBLIC PROC[my: LptComData] =
    BEGIN
    -- This procedure forks 2 processes. Get and WaitAttention.
    -- The procedure ForkComProcesses should only be called after the 3270Window have been created because the two forked processes calles Em3270StatusDefs indirectly with a window schema.
    my.streamGetProcess ← FORK DoStreamGet[my];   -- need a handle to command processor's instance data, and its own instance data
    my.streamWaitAttentionProcess ← FORK DoStreamWaitAttention[my];   -- need to know streamHandle, bvHostGone
    END;
   
  EndCom: PUBLIC PROC [my: LptComData]=
    BEGIN
    -- EndCom will be called by Em3270Pack when the user wants to end the current session by buging close.
    -- It will delete the stream to host, and free up all communication related spaces allocated to the given instance of the 3270.
    -- The forked process associated with communication will be joined.
    -- If bvHostGone = False; send SST+Attention of cleanUp to host(initiated by user). 
    --     Otherwise host has already gone down, thus ABORT is not required.
    
    IF ~my.bvHostGone THEN    -- End of session is initiated by user thus must notify GateStream 
      BEGIN
      Process.Abort[my.streamGetProcess];
      Process.Abort[my.streamWaitAttentionProcess]
      END;   
    JOIN my.streamGetProcess;    -- does the order of join matters?
    JOIN my.streamWaitAttentionProcess;
    Stream.Delete[my.streamHandle];      -- any attempt to send data down the stream after this point is an error.
    my.streamHandle ← NIL;
    comZone.FREE[@my];    -- free communication instance data.
    END;
     
  DoStreamGet: PROC [my: LptComData] =   
    BEGIN
    -- DoStreamGet will continously polls the stream for data.
    -- A second poll will not be issued unless all datas recieved during the previous poll have been procesed.
    -- The required ordering of SSTs and data are: "chained" or "unchained" follow by "none" then data.
    -- Any inputs recieved which does not follows the required pattern will be discarded.
    
    bvChain: BOOLEAN ← FALSE;	-- True => chained command
    status: Status ← okay;     -- TRUE => SSTs are not arriving in the required order
    bvSyntaxErr: BOOLEAN ← FALSE;   
    sst: Stream.SubSequenceType;
    why: Stream.CompletionCode;
    block: Stream.Block;
    lastBytePlusOne: CARDINAL ← 0;
    totalBytesPlusOne: CARDINAL ← 0;
    myStream: Stream.Handle ← my.streamHandle;
    lptBuf: LptBufOfChar ← NIL;
    
    Stream.SetInputOptions[myStream, [TRUE, FALSE, FALSE, FALSE, FALSE, FALSE]];
    lptBuf ← comZone.NEW[BufOfChar];     -- allocate a buffer to store data from host 
    block ← [blockPointer: LOOPHOLE[@(lptBuf.hostData)], startIndex: 0, stopIndexPlusOne: maxComBufCt];    -- note: this is temporary. need to free up space afterward.
    [lastBytePlusOne, why, sst] ← Stream.GetBlock[myStream, block];  --   +++++ This is temporary because gateStream sends an SST of none during the start of the world. This statment should be removed the problem is resolved.
    
    BEGIN
    DO
      ENABLE
	GateStream.Error, 
	ABORTED =>  {
	  DisplayWarningMessage[my];   -- display communicationCheck status to tell user communication line is down.
	  my.bvHostGone ← TRUE;
	  GOTO exit };
	
      status ← okay;
      block ← [blockPointer: LOOPHOLE[@(lptBuf.hostData)], startIndex: 0, stopIndexPlusOne: maxComBufCt];
      [lastBytePlusOne, why, sst] ← Stream.GetBlock[myStream, block];
      SELECT why FROM
        endOfStream => {my.bvHostGone ← TRUE; GOTO exit };
        ENDCASE => NULL;
      SELECT sst FROM	-- expecting to see the sst chained, or unchained.
	GateStream.chain3270 => 
	  BEGIN
	  bvChain ← TRUE;
	  [status, totalBytesPlusOne] ← GetDataFromHost[lptBuf, myStream, block];  
	  END;
	GateStream.unchained3270 => 
	  BEGIN
	  bvChain ← FALSE;
	  [status, totalBytesPlusOne] ← GetDataFromHost[lptBuf, myStream, block];
	  END;
      ENDCASE => status ← wrongOrder;
      SELECT status FROM
	stop => { my.bvHostGone ← TRUE; GOTO exit };
	abort => NULL;  -- ignor the data just recieved. 
	wrongOrder => DisplayWarningMessage[my];    -- SST's were not in the required order
	okay => 
	   BEGIN  -- process the data
	   bvSyntaxErr ← FALSE;
	   Em3270CmdProcessDefs.CheckSyntax[my.lptCmdData, lptBuf, totalBytesPlusOne ! 
	       Em3270CmdProcessDefs.SyntaxError => { bvSyntaxErr ← TRUE; CONTINUE; }; ];  -- the command contains syntax error.
	   IF ~bvSyntaxErr THEN
	     Em3270CmdProcessDefs.ProcessCommands[my.lptCmdData, lptBuf, totalBytesPlusOne, bvChain];   -- will process commands only if it is syntactically correct
	   END;
      ENDCASE;   
      FreeBuffer[lptBuf];
    ENDLOOP;
    EXITS
      exit =>{
	FreeBuffer[lptBuf];       -- the all nodes except for first.
	comZone.FREE[@lptBuf];    -- free the first node.
	};
    END;
    END;   -- of DoStreamGet;
    
    
  GetDataFromHost: PRIVATE PROC [lptBuf: LptBufOfChar, myStream: Stream.Handle, block: Stream.Block] 
   RETURNS [s: Status, totalBytesPlusOne: CARDINAL] =
    BEGIN
    -- get data from the host and store it in a temporary buffer while dynamically allocates buffer storages as needed.
    
    sst: Stream.SubSequenceType;
    why: Stream.CompletionCode;
    lptBlock: LptBufOfChar ← lptBuf;
    lastBytePlusOne: CARDINAL ← 0;
    totalBytesPlusOne ← 0;
    [lastBytePlusOne, why, sst] ← Stream.GetBlock[myStream, block];
    -- we are expecting to see an SST of none from this GetBlock
    SELECT why FROM
        endOfStream => RETURN [stop, totalBytesPlusOne];
        ENDCASE => NULL;
    SELECT sst FROM       -- any sequence of data must be preceded by the sst "none".
      GateStream.abortMark => RETURN [abort, totalBytesPlusOne];
      GateStream.none => NULL;
    ENDCASE => RETURN [wrongOrder, totalBytesPlusOne];
    DO
      block ← [blockPointer:LOOPHOLE[@(lptBlock.hostData)], startIndex: 0, stopIndexPlusOne: maxComBufCt];
      [lastBytePlusOne, why, sst] ← Stream.GetBlock[myStream, block];  -- if things crap out in here, the data in the last transmission are ignored. Which is probably cool because the line went down abnormally.
      totalBytesPlusOne ← lastBytePlusOne + totalBytesPlusOne;
      SELECT why FROM 
	sstChange => 
	  SELECT sst FROM 
	    GateStream.abortMark => RETURN [abort, totalBytesPlusOne];
	  ENDCASE => RETURN [wrongOrder, totalBytesPlusOne];    
	endRecord => RETURN [okay, totalBytesPlusOne]; 
	endOfStream => RETURN [stop, totalBytesPlusOne];   
	normal => { -- the current buffer is full must allocate another buffer
	  lptBlock.nextBuf ← comZone.NEW[BufOfChar];
	  lptBlock ← lptBlock.nextBuf;  }
      ENDCASE => RETURN [wrongOrder, totalBytesPlusOne];
    ENDLOOP;
    END;    -- of GetDataFromHost
 
    
  FreeBuffer: PROC [lptBkChain: LptBufOfChar] =
    BEGIN
    -- free linked list of temporary buffers except for first node.
    tempPtr: LptBufOfChar;
    WHILE lptBkChain.nextBuf # NIL DO
      tempPtr ← lptBkChain.nextBuf;
      lptBkChain.nextBuf ← tempPtr.nextBuf;
      comZone.FREE[@tempPtr];
      ENDLOOP;
    RETURN;
    END;     -- of FreeBuffer
    
    
  DoStreamWaitAttention: PROC [my: LptComData] =
    -- this is a forked process which waits on Attentions coming through the stream.
    -- Note: It is still unclear what type of action should be taken if the host goes down unexpectedly.
    BEGIN
    errorReason: ErrorCode; 
    attention: Stream.Byte;
    DO
      errorReason ← none;
      attention ← Stream.WaitForAttention[my.streamHandle ! 
	 GateStream.Error, ABORTED => { 
	    DisplayWarningMessage[my];   -- display communicationCheck status to user so he knows communication line is down.
	    my.bvHostGone ← TRUE;
	    GOTO exit} ];
      SELECT attention FROM
	GateStream.abortGetTransaction, GateStream.mediumUp => LOOP;
	GateStream.mediumDown => {my.bvHostGone ← TRUE; GOTO exit };
	GateStream.hostPolling3270 => {
	IF ~my.bvHostPolling THEN { 
	  my.bvHostPolling ← TRUE; 
	  RemoveWarningMessage[my];};
	LOOP; };
	GateStream.hostNotPolling3270 => {my.bvHostPolling ← FALSE;  DisplayWarningMessage[my];  LOOP; };
	GateStream.unexpectedRemoteBehavior => errorReason ← unexpectedRemotebehavior;
	GateStream.unexpectedSoftwareFailure => errorReason ← unexpectedSoftwarefailure;
	GateStream.unsupportedProtocolFeature => errorReason ← unsupportedProtocol;
      ENDCASE => errorReason ← undefinedError;
      IF errorReason # none THEN DisplayWarningMessage[my];  -- the attentions recieved are not used by gate stream in Star2 release => communication line problem
    ENDLOOP;
    EXITS
      exit => my.bvHostGone ← TRUE;
    END;
    
    
  DoStreamPut: PUBLIC PROC [my: LptComData, mdtStream: MDTStream, sstType: Stream.SubSequenceType] =
    -- DoStreamPut is called to send a linked list of data to the host.
    -- mdtStream contains a pointer to the head of the list. and the lastCharPlusOne in the last block of the list.
    -- The parameter sstType is send first, followed by the SST GateStream.none, then data. (this ordering is required by GateWay protocol) 
    -- readModified3270, testRequest3270, and status3270 are the only SST currently supported.
    BEGIN
    node: LptBufOfChar;
    IF (my.bvHostGone = TRUE) OR (my.bvHostPolling = FALSE) THEN     -- the communication line to host is down. or host is not polling ECS.
      BEGIN
      DisplayWarningMessage[my];
      END
    ELSE
      BEGIN
      Stream.SetSST[sH: my.streamHandle, sst: sstType];
      Stream.SetSST[sH: my.streamHandle, sst: GateStream.none];
      FOR node ← mdtStream.lptbuf, node.nextBuf UNTIL node = NIL
	DO
	IF node.nextBuf = NIL THEN 
	  Stream.PutBlock[sH: my.streamHandle,
	     block: [blockPointer: LOOPHOLE[@(node.hostData)], startIndex: 0, stopIndexPlusOne: mdtStream.blkIx],
	     endRecord: TRUE]
	ELSE
	  Stream.PutBlock[sH: my.streamHandle,
	     block: [blockPointer: LOOPHOLE[@(node.hostData)], startIndex: 0, stopIndexPlusOne: maxComBufCt],
	     endRecord: FALSE];
      ENDLOOP;
      END;
    END;  -- DoStreamPut


  CreateStream: PROC [lschemaWn: SchemaDefs.Lschema, icon: IconDefs.Icon] RETURNS [myStream: Stream.Handle ← NIL] =
    -- create a stream to the specified  host and terminal address.
    
    BEGIN 
    ENABLE 
      BEGIN 
      NoHostName => 
	BEGIN
	MessageSwnDefs.DisplayMessage[key3270NoHostName];
	GOTO exit;
	END;
      RetypeHostName =>
	BEGIN 
	MessageSwnDefs.DisplayMessage[key3270IllegalHostName];
	GOTO exit;
	END;
      END;
    
    My: Em3270Defs.Lpttrt3270icondata ← TraitDefs.MyData[icon.iconInstance, trt3270icon];
    file3270: NSFile.Handle ← NSFile.OpenChild[
      IconDefs.ParentFromIcon[icon], IconDefs.ReferenceFromIcon[icon].fileID];
      
    rs232PortName: NSString.String;
    port: NSName.Name;
    hostControllerName: LONG STRING;
    controllerAddr, totalbyteLength: CARDINAL;
    attributesRecord: NSFile.AttributesRecord;
    mySessionObject: ibm3270Host GateStream.SessionParameterObject ← [ibm3270Host[]];
    myTransportObjectArrayOfOne: ARRAY [0..1) OF GateStream.TransportObject;
    chat: CH.ConversationHandle;  --/* 3.3: needed for GateStream */
    problem: Auth.CallProblem ← other;
    
    -- Construct by Concatination HostControllerName ← (PortName + "#" + controller address + "B")
   [ , ,controllerAddr, , , rs232PortName] ← GetFileData[file3270, @attributesRecord, spredefinedZone];  -- get PortName and controller address
   
    IF rs232PortName.length = 0 THEN {
      ClearFileData[@attributesRecord];
      NSString.FreeString[spredefinedZone, rs232PortName]; 
      ERROR RetypeHostName;};
    IF (NSString.ValidAsMesaString[rs232PortName] = FALSE) THEN {
      ClearFileData[@attributesRecord];
      NSString.FreeString[spredefinedZone, rs232PortName];
      ERROR RetypeHostName;};
     
    totalbyteLength ← rs232PortName.maxlength + SIZE[CHARACTER] + szMaxCAChars + SIZE[CHARACTER];
    hostControllerName ← LOOPHOLE[comZone.NEW[StringBody[totalbyteLength]]];
    -- get space for entire concatinated hostControllerName
    hostControllerName.length ← 0;  -- insure we start appending from the first character
    
    port  ← NSName.MakeName[spredefinedZone, totalbyteLength, totalbyteLength, totalbyteLength];
--/* Set rs232 port name */
    NSName.NameFieldsFromString[spredefinedZone, rs232PortName, port];
    NSString.AppendToMesaString[to:hostControllerName, from:port.local];
    NSName.FreeName[spredefinedZone, port];

    hostControllerName[hostControllerName.length] ← chNameSeporator;  -- set "#"
    hostControllerName.length ← hostControllerName.length + 1;
    SvDefs.NumericAppendCv[svDest:hostControllerName, cvSource:controllerAddr, cvRadix:8];
      -- set controller Address
    hostControllerName[hostControllerName.length] ← 'B; -- set "B" for controllerAddr in octal
    hostControllerName.length ← hostControllerName.length + 1;
    
    myTransportObjectArrayOfOne[0] ← [polledBSCTerminal[hostControllerName, My.terminalAddress]];

    --/* Obtain conversation handle */
    THROUGH [0..2) DO
	[chat, problem] ← UserDefs.AcquireConversation[];
	IF chat = [NIL, NIL] THEN LOOP ELSE EXIT;
	ENDLOOP;
    IF chat = [NIL, NIL] THEN {
      SELECT problem FROM 
	tooBusy => ZkeyMessageDefs.DisplayMessage[keyZ1114];
	cannotReachAS => ZkeyMessageDefs.DisplayMessage[keyZ1115];
        keysUnavailable => ZkeyMessageDefs.DisplayMessage[keyZ1116]
      ENDCASE => ZkeyMessageDefs.DisplayMessage[keyZ1116];
      GOTO exit};

    -- Create Stream to the specified ECS
    myStream ← GateStream.Create[
      service: My.sysNetAddrECS,
      sessionParameterHandle: @mySessionObject,
      transportList: DESCRIPTOR[myTransportObjectArrayOfOne],
      createTimeout: GateStream.infiniteTime,
      conversation: chat.conversation  ! 
	GateStream.Error => 
	  BEGIN
	  ErrorHandling[reason];
	  NSFile.Close[file3270];
	  ClearFileData[@attributesRecord];  -- throw away rs232cport string name
	  comZone.FREE[@hostControllerName];
	  NSString.FreeString[spredefinedZone, rs232PortName];
	  GOTO exit;
	  END; -- of catchphrase for GateStream.Error --];
    NSFile.Close[file3270];
    ClearFileData[@attributesRecord];  -- throw away rs232cport string name
    NSString.FreeString[spredefinedZone, rs232PortName];
    comZone.FREE[@hostControllerName];
    EXITS 
      exit => 
	BEGIN
	IF myStream # NIL THEN Stream.Delete[myStream];      -- NOTE: might need to set myStream to NIL
	ERROR AbortOpen;
	END;
    END;   -- end CreateStream
	
	
  ErrorHandling: PROCEDURE [reason: GateStream.ErrorReason] =
    BEGIN
      SELECT reason FROM
	controllerDoesNotExist =>
		    -- display the message Illegal host controller name - please try again.
		    MessageSwnDefs.DisplayMessage[key3270IllegalHostName]; 
	deviceAddressInvalid =>
		    -- display the message Illegal terminal address - please try again.
		    MessageSwnDefs.DisplayMessage[key3270IllegalTerminalAddress];
	deviceAddressInUse =>
		    --  display the message Specified terminal address busy .
		    MessageSwnDefs.DisplayMessage[key3270TermInUse];
	tooManyGateStreams => --+!+
		    -- display: The Communication Server is too busy to accept additional users.
		    ZkeyMessageDefs.DisplayMessage[keyZ1096];
	bugInGAPCode => --+!+
		    -- display: Network communication error: bug in protocol handler
		    ZkeyMessageDefs.DisplayMessage[keyZ1097]; 
	gapNotExported =>
		    -- display Communication server is disabled - Contact system administrator;
		    MessageSwnDefs.DisplayMessage[key3270UnexpectedError]; -- aka keyZ49
	gapCommunicationError => --+!+
		    -- display: Could not establish network connection with server
		    ZkeyMessageDefs.DisplayMessage[keyZ1099];
	userNotAuthenticated => --+!+
		    -- display: The Communication Server could not verify your identity.
		    ZkeyMessageDefs.DisplayMessage[keyZ1100];
	userNotAuthorized => --+!+
		    -- display: You are not authorized to use this line.
		    ZkeyMessageDefs.DisplayMessage[keyZ1101];

        illegalTransport => ZkeyMessageDefs.DisplayMessage[keyZ1090];		-- keyEmIllegalTransport:  "The specified transport is not supported."
        mediumConnectFailed => ZkeyMessageDefs.DisplayMessage[keyZ1091];	-- keyEmMediumConnectFailed:  "Dialing failed: no answer or busy signal."
        noDialingHardware,
	dialingHardwareProblem => ZkeyMessageDefs.DisplayMessage[keyZ1093];	-- keyEmNoDialingHardware:  "Tried to dial, but dialing hardware does not exist or is powered down."
        serviceNotFound => ZkeyMessageDefs.DisplayMessage[keyZ1102];		-- keyEmServiceNotFound:  "The server does not support the service you requested."
        networkTransmissionMediumHardwareProblem => ZkeyMessageDefs.DisplayMessage[keyZ1103];	-- keyEmNetTransMediumHWProblem:  "Hardware problem while accessing network."
        networkTransmissionMediumNotReady => ZkeyMessageDefs.DisplayMessage[keyZ1104];		-- keyEmNetTransMediumNotReady:  "Hardware requires manual intervention."
        networkNoAnswerOrBusy => ZkeyMessageDefs.DisplayMessage[keyZ1105];	-- keyEmNetNoAnswerOrBusy:  "Remote modem didn't answer or was busy."
        noRouteToGAPService => ZkeyMessageDefs.DisplayMessage[keyZ1106];	-- keyEmNoRouteToGAPService:  "No route to remote service."
        gapServiceNotResponding => ZkeyMessageDefs.DisplayMessage[keyZ1107];	-- keyEmGapServiceNotResponding:  "Remote service doesn't respond, and is probably dead."
        courierProtocolMismatch => ZkeyMessageDefs.DisplayMessage[keyZ1108];	-- keyEmcourierProtocolMismatch:  "Server and workstation are incompatible (Courier)."
        gapVersionMismatch => ZkeyMessageDefs.DisplayMessage[keyZ1109];		-- keyEmGapVersionMismatch:  "Server and workstation are incompatible (GAP)."
        ENDCASE => MessageSwnDefs.DisplayMessage[key3270ConnectionProblem];	-- Display the message Cannot connect to Host controller at present.
    END;  -- ErrorHandling 

    
  DisplayWarningMessage: PROC [my: LptComData] =
    BEGIN
    Em3270PrivDefs.SetInputStatus[my.lschemaWn, inputInhibited];
    Em3270StatusDefs.DisplayCode[lschema: my.lschemaWn, code:communicationCheck];
    END;
    
  RemoveWarningMessage: PROC [my: LptComData] =   
    BEGIN
    Em3270BufferDefs.Reserve[GetBufferHandle[my.lschemaWn]];
    SetInputStatus[my.lschemaWn, systemAvailable];
    Em3270StatusDefs.ClearStatusArea[lschema: my.lschemaWn];
    Em3270StatusDefs.DisplayCode[my.lschemaWn, Ready3276];
    Em3270StatusDefs.DisplayCode[my.lschemaWn, onlineA];
    Em3270StatusDefs.DisplayCode[my.lschemaWn, myJob];
    Em3270BufferDefs.Release[GetBufferHandle[my.lschemaWn]];
    END;
  
       
END.  -- of Em3270ComPack
  
  
LOG
15-Dec-81  - Lui	- Created	
 1-Feb-82  - Lui	- Updated CreateStream to reflect changes on trt3270icon
 3-Feb-82  - Lui	- Added myWnData
10-Feb-82  - Lui	- added lptData to DoStreamGet
13-Feb-82  - Lui	- added StartCom, EndCom
18-Feb-82  - Lui	- added Em3270PrivDefs
23-Mar-82  - Kernaghan  - Replace code in CreateStream to aquire and build hostcontrollername from the icon's backing file attribute record. 
29-Mar-82  - Lui	- added ForkComProcesses, fixed GateStream.Error[gapNotExported],
14-Apr-82  - Lui	- Added the message Terminal address in use. Re: AR #6737.
19-Apr-82  - Lui	- Added Codes to CatchPhrase of GateStream.Create.
21-Apr-82  - Lui	- Added ProcessTransactionDefs.BeginProcessTransaction and ProcessTransactionDefs.EndProcessTransaction (AR 7109)
22-Apr-82  - Lui	- Added codes to select arm of GateStream.create. (AR 7178) 
29-Apr-82  - Lui	- Added Attentions unusedSST1 and unusedSST2. Re: AR #7562;  unusedSST1 => host is polling ECS. unusedSST2 => host is not polling ECS. 
30-Apr-82  - Lui	- changed code in DoStreamPut to fix a bug introduced by last fix. 
25-Aug-82  - Lui	- added more fields to record constructor returned by GetFileData 
 4-Oct-82  - Lui	- replaced keyZ47 with key3270GapError; keyZ48 with key3270TooManyGateStream; keyZ49 with key3270UnexpectedError;
13-Oct-82  - Lui	- NS conversion
14-Oct-82  - Lui	- replaced extraSSTValue1 with hostPolling3270, and extraSSTValue2 with hostNotPolling3270.
28-Oct-82  - Lui	- edited CreateStream 
25-Jan-83  - Lui	- instead of allocating the first buffer inside the DO loop(in proc DoStreamGet) it is now done on the outside. rewrite FreeBuffer was need as a result of change.
18-Feb-83  - Lui	- Removed all references to ProcessTransactionDefs, because ProcessTransactionDefs have been change to NoOp.
14-Jul-83  - Lui	- Support for read modified.
30-Nov-83 - Pettit - Klamath conversion: GateStream.ErrorReason's terminalAddressInUse/Invalid
  -> deviceAddressInUse/Invalid.
 9-Jan-84 16:22:49  - BLee	- Klamath conversion: catch ABORTED in a few places.  "The new GateStream uses the ERROR ABORTED in place of the attention byte cleanup.  You (the Star TTY implementation) should catch the ERROR ABORTED and do what you would have done had you gotten the attention byte cleanup."
16-Jan-84 17:23:03  - BLee	- add SELECT why FROM in DoStreamGet
 9-Apr-84 13:54:41 - Caro - Upgraded GateStream calls to 8.0
10-Apr-84 13:11:14 - Caro - Added loop to AcquireConversation calls in CreateStream
16-Apr-84 10:40:31 - Caro - Changes CreateStream to use ZKeys
26-Apr-84 13:53:37 - Caro - Fixed hostControllerName in CreateStream
18-May-84 13:00:04 - Caro - Changed error messages for GateStream
			    errors: tooManyGateStreams, bugInGAPCode, 
			    gapCommunicationError (to fix AR3989).
			    Substituted ZKeys from TTY.  Message
			    key "key3270TooManyGateStream" now defunct
			    and should probably be deleted.
25-May-84 15:54:09 - Caro - Added userNotAuthenticated, userNotAuthorized
			    to GateStream.Create error catching.
20-Jun-84 10:50:50 - Caro - Ported ErrorHandling[] routine from EmgttyComPack
			    to fix AR 8827.
29-Jun-84 13:24:56 - Caro - Put all messages in ErrorHandling. 
 5-Jul-84 12:28:45 - Lui -  Removed all references to GateStream.cleanup. Ie, complete upgraded to Services8.0.