#include <clib/exec_protos.h>
#include <amipx.h>
#include <amipx_protos.h>
#include <amipx_pragmas.h>

struct AMIPX_Library *AMIPX_Library;

struct myECB {
 struct AMIPX_ECB ECB;
 struct AMIPX_Fragment extra[2];
};

unsigned char pd[12]={00,00,00,00,02,00,02,00,00,00,00,00
                   };

/*****************************************************************************
 * This program fools DOOM2 into thinking it found a second DOOM2 node in    *
 * IPX game setup time.                                                      *
 * All this program does is first sending the packet data above with a DOOM  *
 * timeval of -1, and then listening for one packet, after which it exits.   *
 * Typically, you would start IPX setup on the PC or Mac, then run this      *
 * program, after which the PC or Mac will think the other node has been     *
 * found. By the way: because both 'number of players found' and 'number of  *
 * players requested' are set to 2 in pd, the PC or Mac will send its        *
 * network start packet and wait.                                            *
 * In that situation, the first packet received by this program is probably  *
 * the network start packet.                                                 *
 *                                                                           *
 * Alternatively, you can first start this program and then PC or Mac DOOM2. *
 * In this case, the first packet received by this program is DOOM2's        *
 * broadcast. PC DOOM2 can then be stopped by pressing 'Esc'.                *
 *                                                                           *
 * Yes! This program busy-waits. However, between polling, a game can do     *
 * more interesting stuff.                                                   * 
 *****************************************************************************/

struct myECB LECB[4];
struct AMIPX_PacketHeader Lheader[4];
BYTE Ltime[4][4];
BYTE Luserdata[4][512];

main(int argc,char **argv)
{
 struct myECB ECB;
 unsigned char myaddrbuff[20];
 int t,lp;
 UWORD mysocket;
 int socknum;
 struct AMIPX_PacketHeader header;
 BYTE time[4];
 BYTE userdata[512];

 socknum=0x869b;

 if(argc>1)
  sscanf(argv[1],"%x",&socknum);

 for(lp=0;lp<4;lp++) { /* set up 4 listen requests */
  for(t=0;t<sizeof(struct myECB);t++)
   ((char *)&(LECB[lp]))[t]=0;

  LECB[lp].ECB.Fragment[0].FragData=&(Lheader[lp]);
  LECB[lp].ECB.Fragment[0].FragSize=sizeof(struct AMIPX_PacketHeader);
  LECB[lp].ECB.FragCount=3;
  LECB[lp].ECB.Fragment[1].FragData=&(Ltime[lp]);
  LECB[lp].ECB.Fragment[1].FragSize=4;
  LECB[lp].ECB.Fragment[2].FragData=&(Luserdata[lp]);
  LECB[lp].ECB.Fragment[2].FragSize=12;
  LECB[lp].ECB.InUse=0x00;
 }

 for(t=0;t<10;t++)
  myaddrbuff[t]=10-t;

 for(t=0;t<4;t++)
  time[t]=0xff;

 for(t=0;t<12;t++)
  userdata[t]=pd[t];

 for(t=0;t<sizeof(ECB);t++)
  ((char *)&ECB)[t]=0;

 header.Checksum[0]=0xff;
 header.Checksum[1]=0xff;
 header.Length[0]=0;
 header.Length[1]=0x2e;
 header.Tc=0;
 header.Type=0;

 ECB.ECB.Fragment[0].FragData=&header;
 ECB.ECB.Fragment[0].FragSize=sizeof(header);
 ECB.ECB.FragCount=3;
 ECB.ECB.Fragment[1].FragData=&time;
 ECB.ECB.Fragment[1].FragSize=4;
 ECB.ECB.Fragment[2].FragData=&userdata;
 ECB.ECB.Fragment[2].FragSize=12;
 ECB.ECB.InUse=0x00;
 for(t=0;t<6;t++)
  ECB.ECB.ImmedAddr[t]=0xff;

 AMIPX_Library=(struct AMIPX_Library *)OpenLibrary("amipx.library",0);

 if(AMIPX_Library) {
  printf("Library opened.\n");
  AMIPX_GetLocalAddr(myaddrbuff);
  for(t=0;t<10;t++)
   printf("%02x ",(unsigned int)myaddrbuff[t]);
  printf("\n");
  if((mysocket=AMIPX_OpenSocket(socknum))!=0) {
   printf("Socket %04x opened\n",(unsigned int)mysocket);
   for(t=0;t<4;t++) {
    header.Dst.Network[t]=myaddrbuff[t];
    header.Src.Network[t]=myaddrbuff[t];
   }

   for(t=0;t<6;t++) {
    header.Dst.Node[t]=0xff;
    header.Src.Node[t]=myaddrbuff[t+4];
   }

   header.Dst.Socket[0]=(mysocket/256)&0xff;
   header.Dst.Socket[1]=(mysocket)    &0xff;
   header.Src.Socket[0]=(mysocket/256)&0xff;
   header.Src.Socket[1]=(mysocket)    &0xff;
   ECB.ECB.Socket=mysocket;



   printf("Now submitting Listen ECBs...\n");

   for(lp=0;lp<4;lp++) {
    LECB[lp].ECB.Socket=mysocket;
    AMIPX_ListenForPacket(&LECB[lp]);
   }

   for(lp=0;lp<4;lp++) { /* since all requests are queued for the same socket,
                            they are satisfied in the same order */
    printf("Now submitting Send ECB...");
    printf("Return value: %d\n",AMIPX_SendPacket(&ECB));

    printf("Waiting for Listen to return...\n");
    while(LECB[lp].ECB.InUse) 
      ;


    printf("header : ");
    for(t=0;t<sizeof(header);t++)
     printf("%02x ",((unsigned char *)&Lheader[lp])[t]);

    printf("\nTime : ");

    for(t=0;t<4;t++)
     printf("%02x ",(unsigned char)Ltime[lp][t]);

    printf("\n");
    for(t=0;t<512 && t<(Lheader[lp].Length[1]+Lheader[lp].Length[0]*256-34);t++)
     printf("%02x ",(unsigned char)Luserdata[lp][t]);

    printf("\n");
    printf("Now waiting for Send to return\n");
    while(ECB.ECB.InUse) 
     ;
   }
   
   AMIPX_CloseSocket(mysocket);
  }
  else {
   printf("Panic! Socket not opened!\n");
  }
  printf("Now exiting...\n");
  CloseLibrary(AMIPX_Library);
 }
}
