/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* |_o_o|\\ Copyright (c) 1988 The Software Distillery.  All Rights Reserved */
/* |. o.| || This program may not be distributed without the permission of   */
/* | .  | || the authors:                             BBS: (919) 481-6436    */
/* | o  | ||   John Toebes     John Mainwaring    Jim Cooper                 */
/* |  . |//    Bruce Drake     Gordon Keener      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         */
   { ActTimer,          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    */
   { NULL,              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 */
   { ActFindin,         BP1| BP2| BP3| 0   }, /* ACTION_FIND_INPUT  - 1005 */
   { ActFindout,        BP1| BP2| BP3| 0   }, /* ACTION_FIND_OUTPUT - 1006 */
   { ActEnd,            0  | 0  | 0  | 0   }, /* ACTION_END         - 1007 */
   { ActSeek,           0  | 0  | 0  | 0   }  /* ACTION_SEEK        - 1008 */
   };

struct DosLibrary *DOSBase;

void __saveds handler()
{
   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.self   = (struct Process *) FindTask(0L);  /* find myself        */
   global.run    = 1;
   global.port   = &(global.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.line1.FrontPen = global.line1.BackPen = -1;
   global.line1.DrawMode = JAM1;
   global.line1.LeftEdge = global.line1.TopEdge = 4;
   global.line2 = global.line1;
   global.line3 = global.line1;
   global.retrytxt = global.line1;
   global.canceltxt = global.line1;
#else
   *(long *)&global.line1.FrontPen     = 0x00010000L | (JAM1<<8);
   *(long *)&global.line1.LeftEdge     = 0x00040004L;  /* 4,4  */
   *(long *)&global.line2.FrontPen     = 0x00010000L | (JAM1<<8);
   *(long *)&global.line2.LeftEdge     = 0x0004000EL;  /* 4,14 */
   *(long *)&global.line3.FrontPen     = 0x00010000L | (JAM1<<8);
   *(long *)&global.line3.LeftEdge     = 0x00040018L;  /* 4,24 */
   *(long *)&global.retrytxt.FrontPen  = 0x00010000L | (JAM1<<8);
   *(long *)&global.retrytxt.LeftEdge  = 0x00040004L;
   *(long *)&global.canceltxt.FrontPen = 0x00010000L | (JAM1<<8);
   *(long *)&global.canceltxt.LeftEdge = 0x00040004L;
#endif
   global.retrytxt.IText = "Retry";
   global.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 */

#ifdef DEBUG
   initdebug();
#endif

   global.devname  = (((char *)BADDR(mypkt->dp_Arg1))+1);  /* BSTR name passed to handler */
#if 0
   global.extra    = mypkt->dp_Arg2;          /* Extra Info passed           */
#endif

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

   InitDevice(&global);

   /* Now mount the disk */
   Mount(&global);

   OpenTimer(&global);

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

   PostTimerReq(&global);

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

      action = mypkt->dp_Type;

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

      switch (action)
         {
         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;

         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.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;

         if (global.changedisk)
            Mount(&global);

         (*subr)(&global, mypkt);

         if (global.changedisk)
            Mount(&global);
         }
      else
         {
         BUG(("Unknown packet type %ld\n",mypkt->dp_Type));
         }

      /* Now return the packet to them */
      if (global.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);
   FreeBlkBuffs(&global);
}
