/*
** $VER: netinput.c 1.3 (24 Jul 1995)(14 Jul 1995)
**
** AMIGA netinput server code
**
** (C) Copyright 1995 Marius Gröger
**     All Rights Reserved
**
** $HISTORY:
**
** 24 Jul 1995 : 001.003 :  added "default:" in main loop switch()
**                          return status was broken
** 14 Jul 1995 : 001.002 :  some code cleanup
** 06 Mar 1995 : 001.001 :  version id added
** 05 Mar 1995 : 001.000 :  created
*/

#define DEBUG 0

/*F*/ /* includes */
#include <NETINCLUDE:sys/types.h>
#include <NETINCLUDE:sys/stat.h>
#include <NETINCLUDE:stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <clib/netlib_protos.h>
#include <netdb.h>

#include <clib/dos_protos.h>
#include <pragmas/dos_pragmas.h>

#include <clib/exec_protos.h>
#include <pragmas/exec_sysbase_pragmas.h>

#include <exec/memory.h>
#include <exec/io.h>
#include <exec/interrupts.h>

#include <devices/input.h>
#include <devices/inputevent.h>

#include "netinput.h"
#include "unixsem.h"
#include "compiler.h"
#include "debug.h"

/*E*/
/*F*/ /* global data */
extern struct Library *SocketBase, *DOSBase;

typedef struct GlobalData
{
   struct Library   *gd_SysBase,
                    *gd_UtilityBase,
                    *gd_DOSBase;
   struct MsgPort   *gd_IPort;
   struct IOStdReq  *gd_IReq;
   UBYTE             gd_ProgramName[100];
   ULONG             gd_Flags;
   int               gd_Socket;
   struct Task      *gd_We;
   struct foPacket   gd_Request;
} *GD;

#ifdef __SASC
     /*
     ** redirect all shared library bases to our device base.
     */
#  define SysBase      gd->gd_SysBase
#  define DOSBase      gd->gd_DOSBase
#  define UtilityBase  gd->gd_UtilityBase
     /*
     ** This macro declares a local variable which temporary gets
     ** SysBase directly from AbsExecBase.
     */
#  define LOCALSYSBASE struct { void *gd_SysBase; } *gd = (void*)0x4
#else
#  error Please define library bases for your compiler
#endif

/*E*/

/*F*/ /* revision */
#define VERSION 37
#define REVISION 2
#define DATE "24.07.95"
#define VERS "netinputd 37.2"
#define VSTRING "netinputd 37.2 (24.07.95)"
#define VERSTAG "\0$VER: netinputd 37.2 (24.07.95)"
const STATIC UBYTE version[]=VERSTAG;
/*E*/

/*F*/ /* private symbols */
static VOID freeall(GD gd);
static BOOL openall(GD gd);
static GD creategd(VOID);
static BOOL getrequest(GD gd);
/*E*/
/*F*/ /* exported symbols */
extern int main(VOID);
/*E*/

/*F*/ static VOID freeall(GD gd)
{
   if (gd->gd_IReq)
   {
      if (gd->gd_IReq->io_Device) CloseDevice((struct IORequest*)gd->gd_IReq);
      DeleteIORequest(gd->gd_IReq);
   }
   if (gd->gd_IPort) DeleteMsgPort(gd->gd_IPort);
   if (DOSBase) CloseLibrary(DOSBase);
   if (UtilityBase) CloseLibrary(UtilityBase);
   FreeVec(gd);
}
/*E*/
/*F*/ static BOOL openall(GD gd)
{
   BOOL rv = FALSE;

   gd->gd_We = FindTask(NULL);

   d(("opening dos.library\n"));
   if (DOSBase = OpenLibrary("dos.library", 37))
   {
      d(("opening utility.library\n"));
      if (UtilityBase = OpenLibrary("utility.library", 37))
      {
         d(("creating msg port\n"));
         if (gd->gd_IPort = CreateMsgPort())
         {
            d(("creating io request\n"));
            if (gd->gd_IReq = CreateIORequest(gd->gd_IPort, sizeof(struct IOStdReq)))
            {
               d(("opening input.device\n"));
               if (!OpenDevice("input.device",0,(struct IORequest*)gd->gd_IReq, 0))
               {
                  rv = TRUE;
               }
            }
         }
      }
   }

   return rv;
}
/*E*/
/*F*/ static GD creategd(VOID)
{
   GD new;
   LOCALSYSBASE;

   new = AllocVec(sizeof(struct GlobalData), MEMF_ANY | MEMF_CLEAR);
   new->gd_SysBase = SysBase;

   return new;
}
/*E*/

/*F*/ static BOOL getrequest(GD gd)
{
   int l;

   l = recv((LONG)gd->gd_Socket, (UBYTE*)&gd->gd_Request, sizeof(struct foPacket), 0);
   d(("recv(%ld) = %ld bytes\n",sizeof(struct foPacket), l));
   return (BOOL)(l == sizeof(struct foPacket));
}
/*E*/

/*F*/ extern int main(VOID)
{
   int rc = RETURN_FAIL;
   GD gd;

   if (gd = creategd())
   {
      d(("gd at %lx\n",gd));

      if (openall(gd))
      {
         GetProgramName(gd->gd_ProgramName, sizeof(gd->gd_ProgramName));

         gd->gd_Socket = init_inet_daemon();
         if (gd->gd_Socket >= 0)
         {
            BOOL running = TRUE;

            while(running)
            {
               if (getrequest(gd))
               {
                  switch(gd->gd_Request.Type)
                  {
                     case FOPT_Event:
                     {
                        struct InputEvent event;
                        if (recv((LONG)gd->gd_Socket, (UBYTE*)&event, sizeof(struct InputEvent), 0) == sizeof(struct InputEvent))
                        {
                           //d(("received input event %lx %lx %lx\n",event.ie_Class,event.ie_Code,event.ie_Qualifier));
                           gd->gd_IReq->io_Command = IND_WRITEEVENT;
                           gd->gd_IReq->io_Data = (APTR)&event;
                           gd->gd_IReq->io_Length = sizeof(struct InputEvent);
                           event.ie_NextEvent = NULL;
                           DoIO((struct IORequest*)gd->gd_IReq);
                        }
                        else
                        {
                           d(("couldn't receive input event\n"));
                        }
                     }
                     break;

                     case FOPT_Finish:
                        d(("finnish\n"));
                        running = FALSE;
                        rc = RETURN_OK;
                     break;

                     default:
                        d(("bad command 0x%08lx\n", gd->gd_Request.Type));
                        running = FALSE;
                     break;
                  }

               }
               else
               {
                  /* recv() didn't work properly */
                  running = FALSE;
               }
            }
         }
      }

      freeall(gd);
   }

   d(("returning rc=%ld\n",rc));
   return rc;
}
/*E*/

