{$X+,V-,B-}
program RecHello3;

{ Simple IPX demonstration program, that uses one receive ESR.

  Run this program on 1 workstation, run S_HELLO or S1_HELLO on another.
  S_HELLO will send "hello world" messages,
  this workstation will receive them.  }

{ This program consists of two concurrent processes:

  1. (background) An ESR that fills a global receive buffer with
                  incoming packets. Only when the buffer is full
                  will packets be discarded.

  2. (foreground) A process that performs its regular task. Whenever
                  there is time, the process will process the
                  received packets. }

uses crt,nwMisc,nwIPX;

CONST IOSocket=$5678;

Var ReceiveEcb    :Tecb;
    IpxHdr        :TipxHeader;
    socket        :word;
    buf           :array[1..546] of byte;
    t             :byte;
    ReceivedBufLen:word;

    ReceivedMsg:array[1..100] of record
                                 InUse:Boolean;
                                 Message:string[25];
                                 end;

    EsrBufInd  :Byte; { used by ESR }

    NewStack:array[1..1024] of word;  { !! used by ESR }
    StackBottom:word;                 { !! used by ESR }


{$F+}
Procedure ListenESRhandler(Var p:Tpecb);
begin
{ look for an empty spot in the global buffer }
EsrBufInd:=1;
while (EsrBufInd<=100) and ReceivedMsg[EsrBufInd].Inuse
 do inc(EsrBufInd);
IF EsrBufInd<=100
 then begin
      { empty place found. Insert msg }
      with ReceivedMsg[EsrBufInd]
       do begin
          Message[0]:=chr(p^.fragment[2].size);
          if Message[0]>#25 then Message[0]:=#25;
          move(p^.fragment[2].address^,Message[1],ord(Message[0]));
          InUse:=True;
          end;
      end
 else ; { entire buffer is filled => discard packet }
{ Setup to listen for next incoming packet }
IPXListenForPacket(ReceiveECB);
end;
{$F-}

{$F+}
Procedure ListenESR; assembler;
asm { ES:SI are the only valid registers when entering this procedure ! }
    mov dx, seg stackbottom
    mov ds, dx

    mov dx,ss  { setup of a new local stack }
    mov bx,sp  { ss:sp copied to dx:bx}
    mov ax,ds
    mov ss,ax
    mov sp,offset stackbottom
    push dx    { push old ss:sp on new stack }
    push bx

    push es    { push es:si on stack as local vars }
    push si
    mov  di,sp

    push ss    { push address of local ptr on stack }
    push di
    CALL ListenEsrHandler

    add sp,4   { skip stack ptr-copy }
    pop bx     { restore ss:sp from new stack }
    pop dx
    mov sp,bx
    mov ss,dx
end;
{$F-}


begin
IF NOT IpxInitialize
 then begin
      writeln('Ipx needs to be installed.');
      halt(1);
      end;
socket:=IOSocket;
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
 then begin
      writeln('IPXopenSocket returned error# ',nwIPX.result);
      halt(1);
      end;

FillChar(buf,546,#0);

{ Setup ECB and IPX header }
IPXsetupListenECB(Addr(ListenESR),IOsocket,@buf,546,
                  IpxHdr,ReceiveEcb);

IPXListenForPacket(ReceiveECB);

writeln('ESR will start filling a global buffer with packets received.');
writeln('Starting foreground process...');
writeln;
writeln('Foreground process just writes a ''dot'' to the screen every second.');
writeln('When a key is pressed, this process is terminated and the received');
writeln('packets are shown.');

REPEAT
IPXrelinquishControl;
delay(1000);
write('.');
UNTIL KeyPressed;

writeln;
writeln('Dumping global receive buffer -- filled by background process.');

for t:=1 to 100
 do if ReceivedMsg[t].Inuse
  then begin
       writeln(ReceivedMsg[t].Message);
       ReceivedMsg[t].Inuse:=False; { give entry in buffer free }
       end;
{ You may also choose to process just 1 entry in the received buffer.
  Set Inuse to False after processing, so the ESR can fill it again }

IF NOT IPXcloseSocket(IOsocket)
 then writeln('IPXcloseSocket returned error# ',nwIPX.result);

end.