/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1987, 1988 The Software Distillery.  All Rights  */
/* |. o.| || Reserved.  This program may not be distributed without the    */
/* | .  | || permission of the authors:                            BBS:    */
/* | o  | ||   John Toebes     Doug Walker    Dave Baker                   */
/* |  . |//                                                                */
/* ======                                                                  */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include "handler.h"

/******************************************************************************/
/******************************************************************************/
/********************* Dispatch table to handle all packets *******************/
/******************************************************************************/
/******************************************************************************/
#define BP1 1
#define BP2 2
#define BP3 4
#define BP4 8

typedef void (*ifuncp)(GLOBAL, struct DosPacket *);
struct LookupTable
   {
   ifuncp subr;
   int flags;
   };

#define LO_FIRST 0
#define LO_LAST  34
struct LookupTable lowork[LO_LAST+1] = {
   { NULL,              0  | 0  | 0  | 0   }, /*  0 - ACTION_NIL           */
   { NULL,              0  | 0  | 0  | 0   }, /*  1 - Unknown              */
   { NULL,              BP1| BP2| BP3| 0   }, /*  2 - ACTION_GET_BLOCK     */
   { NULL,              0  | BP2| BP3| 0   }, /*  3 - Unknown              */
   { NULL,              BP1| BP2| BP3| 0   }, /*  4 - ACTION_SET_MAP       */
   { ActDie,            0  | 0  | 0  | 0   }, /*  5 - ACTION_DIE           */
   { NULL,              0  | 0  | 0  | 0   }, /*  6 - ACTION_EVENT         */
   { ActCurentVol,      BP1| 0  | 0  | 0   }, /*  7 - ACTION_CURRENT_VOLUME*/
   { ActLock,           BP1| BP2| 0  | 0   }, /*  8 - ACTION_LOCATE_OBJECT */
   { ActRenameDisk,     BP1| BP2| 0  | 0   }, /*  9 - ACTION_RENAME_DISK   */
   { NULL,              0  | 0  | 0  | 0   }, /* 10 - Unknown              */
   { NULL,              0  | 0  | 0  | 0   }, /* 11 - Unknown              */
   { NULL,              0  | 0  | 0  | 0   }, /* 12 - Unknown              */
   { NULL,              0  | 0  | 0  | 0   }, /* 13 - Unknown              */
   { NULL,              0  | 0  | 0  | 0   }, /* 14 - Unknown              */
   { ActUnLock,         BP1| 0  | 0  | 0   }, /* 15 - ACTION_FREE_LOCK     */
   { ActDelete,         BP1| BP2| 0  | 0   }, /* 16 - ACTION_DELETE_OBJECT */
   { ActRename,         BP1| BP2| BP3| BP4 }, /* 17 - ACTION_RENAME_OBJECT */
   { NULL,              0  | 0  | 0  | 0   }, /* 18 - ACTION_MORE_CACHE    */
   { ActDupLock,        BP1| 0  | 0  | 0   }, /* 19 - ACTION_COPY_DIR      */
   { NULL,              0  | 0  | 0  | 0   }, /* 20 - ACTION_WAIT_CHAR     */
   { ActSetProtection,  0  | BP2| BP3| 0   }, /* 21 - ACTION_SET_PROTECT   */
   { ActCreateDir,      BP1| BP2| 0  | 0   }, /* 22 - ACTION_CREATE_DIR    */
   { ActExamine,        BP1| BP2| 0  | 0   }, /* 23 - ACTION_EXAMINE_OBJECT*/
   { ActExNext,         BP1| BP2| 0  | 0   }, /* 24 - ACTION_EXAMINE_NEXT  */
   { ActDiskInfo,       BP1| 0  | 0  | 0   }, /* 25 - ACTION_DISK_INFO     */
   { ActInfo,           BP1| BP2| 0  | 0   }, /* 26 - ACTION_INFO          */
   { ActFlush,          0  | 0  | 0  | 0   }, /* 27 - ACTION_FLUSH         */
   { ActSetComment,     0  | BP2| BP3| BP4 }, /* 28 - ACTION_SET_COMMENT   */
   { ActParent,         BP1| 0  | 0  | 0   }, /* 29 - ACTION_PARENT        */
   { NULL,              BP1| 0  | 0  | 0   }, /* 30 - ACTION_TIMER         */
   { ActInhibit,        0  | 0  | 0  | 0   }, /* 31 - ACTION_INHIBIT       */
   { NULL,              BP1| 0  | 0  | 0   }, /* 32 - ACTION_DISK_TYPE     */
   { NULL,              0  | 0  | 0  | 0   }, /* 33 - ACTION_DISK_CHANGE   */
   { ActSetFileDate,    0  | 0  | 0  | 0   }  /* 34 - ACTION_SET_FILE_DATE */
      };

#define HI_FIRST 1004
#define HI_LAST  1008
struct LookupTable hiwork[5] = {
   { ActFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_WRITE  - 1004 */
   { ActFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_INPUT  - 1005 */
   { ActFindwrite,      BP1| BP2| BP3| 0   }, /* ACTION_FIND_OUTPUT - 1006 */
   { ActEnd,            0  | 0  | 0  | 0   }, /* ACTION_END         - 1007 */
   { ActSeek,           0  | 0  | 0  | 0   }  /* ACTION_SEEK        - 1008 */
   };

#define USER_FIRST 2010
#define USER_LAST  2012
struct LookupTable userwork[3] = {
   { ActSetDebug,       0  | 0  | 0  | 0   }, /* ACTION_HANDLER_DEBUG 2010 */
   { NULL,              BP1| 0  | 0  | 0   }, /* ACTION_SET_TRANS_TYPE2011 */
   { ActNetHello,       BP1| 0  | 0  | 0   }, /* ACTION_NETWORK_HELLO 2012 */
   };

struct DosLibrary *DOSBase;

void _main(x)
char *x;
{
   struct DosPacket   *mypkt;      /* a pointer to the dos packet sent       */
   int                action;
   ifuncp             subr;
   int                flags;
   struct global      global;

   DOSBase = (struct DosLibrary *)OpenLibrary(DOSNAME,0);

   /* Initialize our global data structure */
   memset((char *)&global, 0, sizeof(struct global));
   global.n.self   = (struct Process *) FindTask(0L);  /* find myself      */
   global.n.run    = 1;
   global.n.port   = &(global.n.self->pr_MsgPort);
                    /* install our taskid ...   */


   /* Initialize the intuitext structures for the requesters we might have   */
   /* to display                                                             */
   /* Because we have no scruples we can cheat and do this with a couple of  */
   /* long word assignments.  We leave the acual C code commented out here   */
   /* so that if this structure ever changed we will still be able to work   */
#if 0
   global.n.line1.FrontPen = global.n.line1.BackPen = -1;
   global.n.line1.DrawMode = JAM1;
   global.n.line1.LeftEdge = global.n.line1.TopEdge = 4;
   global.n.line2 = global.n.line1;
   global.n.line3 = global.n.line1;
   global.n.retrytxt = global.n.line1;
   global.n.canceltxt = global.n.line1;
#else
   *(long *)&global.n.line1.FrontPen     = 0x00010000L | (JAM1<<8);
   *(long *)&global.n.line1.LeftEdge     = 0x00040004L;  /* 4,4  */
   *(long *)&global.n.line2.FrontPen     = 0x00010000L | (JAM1<<8);
   *(long *)&global.n.line2.LeftEdge     = 0x0004000EL;  /* 4,14 */
   *(long *)&global.n.line3.FrontPen     = 0x00010000L | (JAM1<<8);
   *(long *)&global.n.line3.LeftEdge     = 0x00040018L;  /* 4,24 */
   *(long *)&global.n.retrytxt.FrontPen  = 0x00010000L | (JAM1<<8);
   *(long *)&global.n.retrytxt.LeftEdge  = 0x00040004L;
   *(long *)&global.n.canceltxt.FrontPen = 0x00010000L | (JAM1<<8);
   *(long *)&global.n.canceltxt.LeftEdge = 0x00040004L;
#endif
   global.n.retrytxt.IText = "Retry";
   global.n.canceltxt.IText = "Cancel";

   /* since we were started as a non-BCPL module we get sent the parameter */
   /* packet (ie. parameter packet not in D1) */

   mypkt = taskwait(&global);  /* wait for parameter packet */

   global.n.devname  = (((char *)BADDR(mypkt->dp_Arg1))+1);  /* BSTR name */

   /* get pointer to our device node */
   global.node = (struct DeviceNode *) BADDR(mypkt->dp_Arg3);
   global.node->dn_Task = global.n.port;

   InitDevice(&global);

   Mount(&global, NULL);

/*   OpenTimer(&global); */

   mypkt->dp_Res1 = DOS_TRUE;
   retpkt(&global, mypkt);

/*   PostTimerReq(&global); */

   while(global.n.run)   /* start of the real work */
   {
      BUG(("Waiting for packet. . ."));
      mypkt = taskwait(&global);  /* wait for a packet */

      action = mypkt->dp_Type;

      BUG(("action #%ld\n", action));

      switch (action)
      {

         case ACTION_NETWORK_KLUDGE:
            subr = ActNetKludge;
            flags = (BP1 | BP2);
            break;

         case ACTION_READ:
            subr = ActRead;
            flags = 0;
            break;
         case ACTION_WRITE:
            subr = ActWrite;
            flags = 0;
            break;

         case ACTION_SET_RAW_MODE:
            subr = NULL;
            flags = 0;
            break;

         case ACTION_FIND_WRITE:  /* 1004 */
         case ACTION_FIND_INPUT:  /* 1005 */
         case ACTION_FIND_OUTPUT: /* 1006 */
         case ACTION_END:         /* 1007 */
         case ACTION_SEEK:        /* 1008 */
            subr = hiwork[action-HI_FIRST].subr;
            flags = hiwork[action-HI_FIRST].flags;
            break;

         case ACTION_HANDLER_DEBUG:  /* 2010 */
         case ACTION_SET_TRANS_TYPE: /* 2011 */
         case ACTION_NETWORK_HELLO:  /* 2012 */
            subr = userwork[action-USER_FIRST].subr;
            flags = userwork[action-USER_FIRST].flags;
            break;

         default:            
            if ((action >= LO_FIRST) && (action <= LO_LAST))
            {
               subr = lowork[action-LO_FIRST].subr;
               flags = lowork[action-LO_FIRST].flags;
            }
            else
               subr = NULL;
      }
 
      mypkt->dp_Res1 = DOS_FALSE;
      mypkt->dp_Res2 = ERROR_ACTION_NOT_KNOWN;

      if (subr != NULL)
      {
         global.n.reply = 1;
         if (flags & BP1)
            mypkt->dp_Arg1 <<= 2;
         if (flags & BP2)
            mypkt->dp_Arg2 <<= 2;
         if (flags & BP3)
            mypkt->dp_Arg3 <<= 2;
         if (flags & BP4)
            mypkt->dp_Arg4 <<= 2;

         (*subr)(&global, mypkt);

      }
#if DEBUG
      else
      {
         BUG(("Unknown packet type %ld\n",mypkt->dp_Type));
      }
#endif

      /* Now return the packet to them */
      if (global.n.reply)
         retpkt(&global, mypkt);
  
      BUG(("-----\n"));
   }

   /* do our final cleanup */
   global.node->dn_Task = FALSE; /* zero the taskid field of device node */
   global.node->dn_SegList = 0;  /* make us be gone */

   DisMount(&global);
   TermDevice(&global);

   BUGTERM()
}

void ActSetDebug(global, pkt)  /* ACTION_HANDLER_DEBUG */
GLOBAL global;
struct DosPacket *pkt;
/* DP_Arg1 - LONG type/flags 0=nodebug                  */
/* DP_Arg2 - BPTR FileHandle to do debugging to or NULL */
/* DP_Res1 - BPTR old filehandle                        */
{
   /********************************************************************/
   /*                                                                  */
   /* Several possibilities:                                           */
   /* 1. Arg1 is 0:                                                    */
   /*       All debugging is turned off.  Arg2 is not looked at.       */
   /*       Res1 is DOS_TRUE, Res2 is a BPTR to the old filehandle.    */
   /*                                                                  */
   /* 2. Arg1 is a special handler-defined code:                       */
   /*       If the second bit from the top is ON, the code is a special*/
   /*       debugging command to the handler.  If the handler knows the*/
   /*       command, it returns DOS_TRUE in Res1.  If it doesn't, it   */
   /*       returns DOS_FALSE in Res1 and Res2.                        */
   /*                                                                  */
   /* 3. Neither of the above:                                         */
   /*       Arg2 contains a BPTR to a FileHandle to send debugging to. */
   /*       Note that if this is NULL, debugging will be turned off.   */
   /*       Res1 contains DOS_TRUE, Res2 contains a BPTR to the old    */
   /*       debugging FileHandle, which may of course be NULL if no    */
   /*       debugging was on before.                                   */
   /*                                                                  */
   /********************************************************************/

#define DEBUG_SPECIAL 0x40000000   /* Mask for handler-defined dbg type*/
#define DEBUG_SERVER  0x20000000   /* Mask indicating server command   */
#define DEBUG_WAIT    0x40000001   /* Wait for debugger to catch us    */
#define DEBUG_INFO    0x40000002   /* Send transmit info to msgport in */
                                   /* dp_Arg2                          */

   struct NetNode *netnode;
   extern BPTR debuglog;

   pkt->dp_Res1 = DOS_TRUE;
   if(pkt->dp_Arg1 & DEBUG_SPECIAL)
   {
      BUG(("ActSetDebug: Special debug packet %lx\n", pkt->dp_Arg1))
      if(pkt->dp_Arg1 == DEBUG_WAIT)
      {
         pkt->dp_Res2 = NULL;
         cprwait(global);
      }
      else if(pkt->dp_Arg1 == DEBUG_INFO)
      {
         global->n.infoport = (struct MsgPort *)BADDR(pkt->dp_Arg2);
         global->n.ntirec.m.mn_Node.ln_Type =
         global->n.ntitrans.m.mn_Node.ln_Type = NT_MESSAGE;
         if(!global->n.ntirec.m.mn_ReplyPort)
            global->n.ntirec.m.mn_ReplyPort =
            global->n.ntitrans.m.mn_ReplyPort = CreatePort(NULL,0);
         global->n.inf_rec = global->n.inf_trans = 0L;
      }
      else if(pkt->dp_Arg1 & DEBUG_SERVER)
      {
         global->RP.Type = ACTION_HANDLER_DEBUG;
         global->RP.Arg1 = pkt->dp_Arg1 & ~(DEBUG_SERVER|DEBUG_SPECIAL);
         BUG(("Remote debugging code %lx\n", global->RP.Arg1))
         for(netnode=global->netchain.next;
             netnode;
             netnode=netnode->next)
         {
            if(netnode->status == NODE_UP &&
               netnode->RootLock.RDevice)
            {
               RemotePacket(global, &netnode->RootLock);
            }
         }
      }
      else
      {
         pkt->dp_Res1 = 
         pkt->dp_Res2 = DOS_FALSE;
      }
   }
#if DEBUG
   else if(pkt->dp_Arg1)
      pkt->dp_Res2 = initdebug((BPTR)pkt->dp_Arg2);
   else
   {
      pkt->dp_Res2 = debuglog;
      debuglog = NULL;
   }
#endif   
}




