/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1990 The Software Distillery.  All Rights Reserved.*/
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors.                                                    */
/* | o  | ||                                                                 */
/* |  . |// Written by Doug Walker                                           */
/* ======          BBS:(919)-471-6436      VOICE:(919)-467-4764              */

/*                 BIX: djwalker           USENET: ...!mcnc!rti!sas!walker   */
/*                 405 B3 Gooseneck Dr, Cary, NC 27513, USA                  */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
 * Based on POPCLI III, written by John Toebes
 * Uses Matt Dillon's DNET
 */

#include "netkeys.h"

struct DChannel *chan;

/* Declarations for CBACK */
extern BPTR _Backstdout;         /* standard output when run in background */
long _BackGroundIO = 1;          /* Flag to tell it we want to do I/O      */
long _stack = 4000;              /* Amount of stack space our task needs   */
char *_procname = "NetKeys I";   /* The name of the task to create         */
long _priority = 20;             /* The priority to run us at              */

int InitDevice(int);
int TermDevice(void);

struct InputEvent * __regargs myhandler(struct InputEvent *ev, GLOBAL_DATA *gpt
)
{
   struct InputEvent *ep, *laste;
   struct NETKEYMSG *nkm;

   if(gptr->state < EM_DOIT) return(ev);  /* In the process of quitting */

   /* run down the list of events to see if they pressed the magic button */
   for (ep = ev, laste = NULL; ep != NULL; ep = ep->ie_NextEvent)
   {
      if(ep->ie_Class == IECLASS_RAWKEY || ep->ie_Class == IECLASS_RAWMOUSE)
      {
         if ((ep->ie_Class == IECLASS_RAWKEY)    &&
              ep->ie_Code  == gptr->dokey        &&
             (ep->ie_Qualifier & IEQUALIFIER_LCOMMAND))
         {
            /* Remove the event from the chain */
            if (laste == NULL)
               ev = ep->ie_NextEvent;
            else
               laste->ie_NextEvent = ep->ie_NextEvent;

            /* Telling us to toggle... */
            gptr->state = (gptr->state == EM_DOIT ? EM_LURK : EM_DOIT);

            Signal(gptr->buddy, 1 << gptr->nkmp->mp_SigBit);
         }
         else if(gptr->state != EM_LURK)
         {
            /* Remove the event from the chain */
            if (laste == NULL)
               ev = ep->ie_NextEvent;
            else
               laste->ie_NextEvent = ep->ie_NextEvent;

            if(!(nkm=(struct NETKEYMSG *)GetMsg(gptr->rtnp)) )
            {
               if(gptr->nmsgs > MAXMSGS ||
                  !(nkm = AllocMem(NKMSZ, MEMF_CLEAR|MEMF_PUBLIC)))
               {
                  gptr->state = EM_LURK;
                  break;
               }
            }
            /* Copy the data and queue it to our port */
            nkm->ie = *ep;
            PutMsg((struct MsgPort *)gptr->nkmp, (struct Message *)nkm);
         }
      }
      else
         laste = ep;
   }

   /* pass on the pointer to the event */
   return(ev);
}


int _main(char *cmd);
int _main(char *cmd)
{
   struct MsgPort  *inputDevPort = NULL;
   struct MsgPort  *oldport;
   struct IOStdReq *inputRequestBlock = NULL;
   struct Interrupt handlerStuff;
   GLOBAL_DATA global;
   struct NETKEYMSG *msg, *oldmsg, *tmpmsg;
   int quit = 0;
   int force = 0;

   MSG(_Backstdout, BANNER);

   memset(&global, 0, sizeof(global));
   global.buddy = FindTask(0L);
   global.dokey  = DEFDOKEY;
   global.state = EM_LURK;
   if(!(global.rtnp = CreatePort(0,0)))
   {
      MSG(_Backstdout, "Can't CreatePort\n");
      goto abort;
   }

   oldport = FindPort(NKMPNAME);

   if(cmd && *cmd)
   {
      long tmpl = DEFDOKEY;
      while(*cmd != ' ') cmd++;
      while(*cmd == ' ') cmd++;
      if(cmd[0] == '0' && cmd[1] == 'x')
      {
        stch_l(cmd+2, &tmpl);
        global.dokey = tmpl;
      }
      else if(cmd[0] == 'Q' || cmd[0] == 'q')
      {
         quit = 1;
      }
      else if(cmd[0] == 'F' || cmd[0] == 'f')
      {
         force = 1;
      }
   }

   if(!(oldmsg = AllocMem(NKMSZ, MEMF_CLEAR|MEMF_PUBLIC)))
   {
      MSG(_Backstdout, "No memory\n");
      goto abort;
   }
   if(quit)
   {
      if(!oldport)
      {
         MSG(_Backstdout, "Netkeys not installed\n");
         goto abort;
      }
      else
      {
         oldmsg->msgtype = NKM_QUIT;
         oldmsg->ie.ie_Class = force;
         oldmsg->m.mn_Node.ln_Type = NT_MESSAGE;
         oldmsg->m.mn_ReplyPort = global.rtnp;
         PutMsg(oldport, (struct Message *)oldmsg);
         WaitPort(global.rtnp);
         MSG(_Backstdout, "NetKeys removed\n");
         goto abort;      
      }
   }

   if(oldport)
   {
      /* Modify the hotkey for the existing guy */
      oldmsg->msgtype = NKM_CONTROL;
      oldmsg->ie.ie_Class = global.dokey;
      PutMsg(oldport, (struct Message *)oldmsg);
      WaitPort(global.rtnp);
      MSG(_Backstdout, "NetKeys now using 0x%02.2x\n");
      goto abort;
   }

   FreeMem(oldmsg, NKMSZ);
   oldmsg = NULL;

   MSG(_Backstdout, INSTR);

   if (
       ((global.nkmp = CreatePort(NKMPNAME, 0)) == NULL)                    ||

       ((inputDevPort = CreatePort(0,0)) == NULL)                           ||

       InitDevice(NKM_HANDLER)                                              ||

       ((inputRequestBlock = 
               CreateIOReq(inputDevPort, sizeof(struct IOStdReq))) == NULL) ||

      OpenDevice("input.device",0,(struct IORequest *)inputRequestBlock,0))
      {
         MSG(_Backstdout, "Can't initialize\n");
         goto abort;
      }

   MSG(_Backstdout, "NetKeys installed\n");

   if(_Backstdout) Close(_Backstdout);
   _Backstdout = 0;

   handlerStuff.is_Data = (APTR)&global;
   handlerStuff.is_Code = (VOID (*)()) myhandler;
   handlerStuff.is_Node.ln_Pri = 52;

   inputRequestBlock->io_Command = IND_ADDHANDLER;
   inputRequestBlock->io_Data    = (APTR)&handlerStuff;

   DoIO((struct IORequest *)inputRequestBlock);

   while(global.state >= EM_DOIT && 
        !(SIGBREAKF_CTRL_C & Wait((1<<global.nkmp->mp_SigBit) | SIGBREAKF_CTRL_
)))
   {
      while(msg=(struct NETKEYMSG *)GetMsg(global.nkmp))
      {
         if(msg->msgtype == NKM_QUIT)
         {
            ReplyMsg((struct Message *)msg);
            goto abort;
         }
         else if(msg->msgtype == NKM_CONTROL)
         {
            global.dokey = msg->ie.ie_Code;
            ReplyMsg((struct Message *)msg);
            continue;
         }

         tmpmsg = NULL;
         if( msg->ie.ie_Class == IECLASS_RAWMOUSE &&
             msg->ie.ie_Code == IECODE_NOBUTTON)
         {
            while((tmpmsg = (struct NETKEYMSG *)GetMsg(global.nkmp)) &&
                   tmpmsg->msgtype == NKM_IEVENT &&
                   tmpmsg->ie.ie_Class == IECLASS_RAWMOUSE &&
                   tmpmsg->ie.ie_Code == IECODE_NOBUTTON &&
                   (tmpmsg->ie.ie_Qualifier & IEQUALIFIER_RELATIVEMOUSE))
            {
               tmpmsg->ie.ie_X += msg->ie.ie_X;
               tmpmsg->ie.ie_Y += msg->ie.ie_Y;
               PutMsg(global.rtnp, (struct Message *)msg);
               msg = tmpmsg;
               tmpmsg = NULL;
            }
         }
putit:
         if(DWrite(chan, (char *)&msg->ie, IESZ) != IESZ)
            break;

         PutMsg(global.rtnp, (struct Message *)msg);

         if(tmpmsg)
         {
            msg = tmpmsg;
            tmpmsg = NULL;
            goto putit;
         }
      }
   }

abort:
   TermDevice();

   if (inputRequestBlock != NULL)
   {
      if (inputRequestBlock->io_Device != NULL)
      {
         inputRequestBlock->io_Command = IND_REMHANDLER;
         inputRequestBlock->io_Data = (APTR)&handlerStuff;
         DoIO((struct IORequest *)inputRequestBlock);

         CloseDevice((struct IORequest *)inputRequestBlock);
      }
      DeleteIOReq(inputRequestBlock);
   }

   if (inputDevPort != NULL)  DeletePort(inputDevPort);

   if(global.nkmp)
   {
      while(msg=(struct NETKEYMSG *)GetMsg(global.nkmp)) FreeMem(msg, NKMSZ);
      DeletePort(global.nkmp);
   }

   if(global.rtnp)
   {
      while(msg=(struct NETKEYMSG *)GetMsg(global.rtnp)) FreeMem(msg, NKMSZ);
      DeletePort(global.rtnp);
   }

   if(_Backstdout) Close(_Backstdout);

   return(0);
}

int active = 0;
struct DChannel *chan = NULL;

int InitDevice(int which)
{
   if(active) return(1);
   active = 1;

   if(!(chan=(struct DChannel *)DOpen(NULL, (uword)(PORT_NETKEYS), 127, 127)))
      return(1);

   return(0);
}

int TermDevice(void)
{
   if(!active) return(1);

   active = 0;

   if(chan) DClose(chan);

   chan = NULL;

   return(0);
}

void MemCleanup(void);
void MemCleanup(){}
