{$X+,V-,B-}
program ShSAPs;

{ Testprogram for the nwSAP unit / NwTP 0.6 (c) 1993,1995 R.Spronk }

{ Dump all incoming SAP broadcasts on screen;
  Sends -no- packets; receiving packets only }

{ Demonstrates
  -The use of the Service Advertizing Protocol;
  -Asynchronous handling of receiving and processing
   (using 1 receive ESR and intermediate buffers   }

uses crt,nwMisc,nwIPX,nwSAP;

CONST SAPsocket=$0452;
      BUFSIZ=511;
      { May 'hang' your WS if more than 70 SAP broadcast were received
        in a short interval (a few ticks). Increase the BUFSIZ value. }

Type TSAPserver=record
                ObjType:word;
                Name   :array[1..48] of byte; { asciiz }
                Address:TinternetworkAddress;
                Hops   :word;
                end;

     TSAPresponse=record
                  ResponseType:word; { 0002 General server; 0004 nearest server }
                  ServerEntry:array[1..7] of TSAPserver;
                  end;

Type String48=string[48];
     Tservices=record
               InUseFlag  :Byte; { 0: not being accessed by other threads }
               TimeStamp :Word; { Ticks / max 60. minutes }
               ObjType:word;
               Name   :array[1..48] of byte; { asciiz }
               Address:TinternetworkAddress;
               Hops   :word;
               end;

Var ServBuf:array[0..BUFSIZ] of TServices;
    ECBServBufInd:word; { 0..BUFSIZ }
    ServBufInd   :word; { 0..BUFSIZ }

    StartTicks:Longint;

    PktCount:word;

Var ReceiveEcb    :Tecb;
    IpxHdr        :TipxHeader;
    socket        :word;
    IPXreceiveBuffer: array[1..546] of byte;
    SAPreceiveBuffer: TSAPresponse absolute IPXreceiveBuffer;

    ReceivedBufLen:word;
    PacketReceived:boolean;

    RecString     :string;

    NewStack:array[1..1024] of word;  { !! used by ESR }
    StackBottom:word;                 { !! used by ESR }
    ESRctr:byte;                      { !! used by SAP ESR }


{$F+}
Procedure SAPListenESRhandler(Var p:Tpecb);
begin
if SAPreceiveBuffer.Responsetype=$0200 { 0002 hi-lo: general server SAP reply }
 then begin
      ESRctr:=1;
      while (ESRctr<=7) and (SAPreceiveBuffer.ServerEntry[ESRctr].ObjType>$0000)
       do begin
          while ServBuf[ECBservBufInd].inUseFlag>0
           do begin
              inc(ECBServBufInd);
              ECBservBufInd:=ECBservBufInd and BUFSIZ;
              end;
          with SAPreceiveBuffer.ServerEntry[ESRctr]
           do begin
              Move(ObjType,ServBuf[ECBServBufInd].ObjType,SizeOf(TSAPserver));
              ObjType:=$0000; { To mark that the entry has been dealt with;
                                to 'clear' receive buffer }
              end;
          with ServBuf[ECBServBufInd]
           do begin
              IPXgetIntervalMarker(TimeStamp);
              InUseFlag:=$FF;
              end;
          inc(ESRctr);
          end;
      PacketReceived:=true;
      inc(PktCount);
      end;
IPXListenForPacket(ReceiveECB);
end;
{$F-}

{$F+}
Procedure SAPListenESR; 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 SAPListenEsrHandler

    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-}


Var ServerName:string;

begin
IF NOT IpxInitialize
 then begin
      writeln('Ipx needs to be installed.');
      halt(1);
      end;
socket:=SAPSocket;
IF NOT IPXopenSocket(Socket,SHORT_LIVED_SOCKET)
 then begin
      writeln('IPXopenSocket returned error# ',nwIPX.result);
      halt(1);
      end;

PktCount:=0;
ECBservBufInd:=0;
PacketReceived:=False;
{ Empty receive buffer (ReceiveEcb.fragment[2].address^) }
FillChar(IPXreceiveBuffer,546,#0);

{ Setup ECB and IPX header }
IPXsetupListenECB(Addr(SAPListenESR),SAPsocket,@IPXreceiveBuffer,546,
                  IpxHdr,ReceiveEcb);

IPXListenForPacket(ReceiveECB);

ServBufInd:=0;
REPEAT

 WHILE (ServBufInd<512) and (NOT keypressed)
  do begin
     IPXrelinquishControl;

     IF ServBuf[ServBufInd].InUseFlag>0
      then begin
           with ServBuf[ServBufInd]
            do begin
               writeln('---------');
               writeln('BufIndex:',ServBufInd);
               writeln('Timestamp: ',HexStr(TimeStamp,4));
               writeln('ObjType  : ',HexStr(swap(ObjType),4));
               ZStrCopy(ServerName,name[1],48);
               writeln('ServerNm : ',ServerName);
               writeln('Address  : ',HexDumpStr(Address,24));
               writeln('Hops     : ',HexStr(swap(Hops),4));
               end;
           ServBuf[ServBufInd].InUseFlag:=0;
           end;

     inc(ServBufInd);ServBufInd:=ServBufInd and BUFSIZ;
     end;

UNTIL KeyPressed;

IF NOT IPXcloseSocket(SAPsocket)
 then writeln('IPXcloseSocket returned error# ',nwIPX.result);

end.
