/*

File: handler.c
Author: Neil Cafferkey
Copyright (C) 2001-2002 Neil Cafferkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA.

*/

#include "handler_protos.h"

/* Global variables */

struct ExecBase *SysBase;
struct DosLibrary *DOSBase;
struct UtilityBase *UtilityBase;
struct LocaleBase *LocaleBase;

/* Data prototypes */

extern struct ExecBase *AbsExecBase;

/* Global constants */

const TEXT version_string[]="$VER: amber-ram-handler 1.3 (2.2.2002)";
const TEXT dos_name[]=DOSNAME;

/* Function prototypes */

static struct DosPacket *GetPacket(struct MsgPort *port);
static VOID ReplyPacket(struct MsgPort *proc_port,struct DosPacket *packet,
   PINT result1,PINT result2);
static STRPTR BStr(UBYTE *b_str);
static STRPTR BStr2(UBYTE *b_str);



LONG Main()
{
   struct Handler *handler;
   struct MsgPort *proc_port;
   struct DosPacket *packet;
   struct DosLibrary *dos_base;
   PINT result;
   BOOL exit;
   LONG link_type;
   APTR link_target;
   ULONG port_signals;
   struct Message *message;

   /* Open libraries */

   SysBase=AbsExecBase;
   dos_base=(struct DosLibrary *)OpenLibrary(dos_name,DOS_VERSION);
   if(!dos_base)
      return RETURN_FAIL;
   DOSBase=dos_base;

   /* Process start-up packet */

   proc_port=&((*(struct Process *)FindTask(NULL)).pr_MsgPort);
   handler=NULL;

   WaitPort(proc_port);
   packet=GetPacket(proc_port);

   handler=CmdStartup(BStr(BADDR(packet->dp_Arg1)),
      BADDR(packet->dp_Arg3),proc_port);
   exit=handler==NULL;

   ReplyPacket(proc_port,packet,DOSBOOL(!exit),IoErr());

   /* Set up port signals */

   port_signals=1<<(proc_port->mp_SigBit);
   Signal(proc_port->mp_SigTask,port_signals);
   if(!exit)
      port_signals|=1<<(handler->notify_port->mp_SigBit);

   /* Service packet requests */

   while(!exit)
   {
      Wait(port_signals);

      /* Accept returning messages from notification clients */

      while((message=GetMsg(handler->notify_port))!=NULL)
      {
         ReceiveNotifyReply(handler,(APTR)message);
      }

      /* Service packet requests */

      while((packet=GetPacket(proc_port))!=NULL)
      {
         result=DOSTRUE;

         switch(packet->dp_Type)
         {
         case ACTION_DIE:

            if(!CmdDie(handler))
               result=DOSFALSE;
            exit=result;
            break;

         case ACTION_IS_FILESYSTEM:

            if(!CmdIsFileSystem())
               result=DOSFALSE;
            break;

         case ACTION_FINDOUTPUT:

            if(!CmdFind(handler,BADDR(packet->dp_Arg1),
               BADDR(packet->dp_Arg2),BStr(BADDR(packet->dp_Arg3)),
               MODE_NEWFILE))
               result=DOSFALSE;
            break;

         case ACTION_FINDUPDATE:

            if(!CmdFind(handler,BADDR(packet->dp_Arg1),
               BADDR(packet->dp_Arg2),BStr(BADDR(packet->dp_Arg3)),
               MODE_READWRITE))
               result=DOSFALSE;
            break;

         case ACTION_FINDINPUT:

            if(!CmdFind(handler,BADDR(packet->dp_Arg1),
               BADDR(packet->dp_Arg2),BStr(BADDR(packet->dp_Arg3)),
               MODE_OLDFILE))
               result=DOSFALSE;
            break;

         case ACTION_FH_FROM_LOCK:

            result=CmdFHFromLock(BADDR(packet->dp_Arg1),
               BADDR(packet->dp_Arg2));
            break;

         case ACTION_END:

            if(!CmdEnd(handler,(APTR)packet->dp_Arg1))
               result=DOSFALSE;
            break;

         case ACTION_READ:

            result=CmdRead((struct Opening *)packet->dp_Arg1,
               (UBYTE *)packet->dp_Arg2,packet->dp_Arg3);
            break;

         case ACTION_WRITE:

            result=CmdWrite(handler,(struct Opening *)packet->dp_Arg1,
               (UBYTE *)packet->dp_Arg2,packet->dp_Arg3);
            break;

         case ACTION_SEEK:
            result=CmdSeek((struct Opening *)packet->dp_Arg1,
               packet->dp_Arg2,packet->dp_Arg3);
            break;

         case ACTION_SET_FILE_SIZE:

            result=CmdSetFileSize(handler,(APTR)packet->dp_Arg1,
               packet->dp_Arg2,packet->dp_Arg3);
            break;

         case ACTION_LOCATE_OBJECT:

            result=MKBADDR(CmdLocateObject(handler,BADDR(packet->dp_Arg1),
               BStr(BADDR(packet->dp_Arg2)),packet->dp_Arg3));
            break;

         case ACTION_FREE_LOCK:

            if(!CmdFreeLock(handler,BADDR(packet->dp_Arg1)))
               result=DOSFALSE;
            break;

         case ACTION_COPY_DIR:

            result=MKBADDR(CmdCopyDir(handler,BADDR(packet->dp_Arg1)));
            break;

         case ACTION_COPY_DIR_FH:

            result=MKBADDR(CmdCopyDirFH(handler,(APTR)packet->dp_Arg1));
            break;

         case ACTION_PARENT:

            result=MKBADDR(CmdParent(handler,BADDR(packet->dp_Arg1)));
            break;

         case ACTION_PARENT_FH:

            result=MKBADDR(CmdParentFH(handler,(APTR)packet->dp_Arg1));
            break;

         case ACTION_SAME_LOCK:

            if(!CmdSameLock(BADDR(packet->dp_Arg1),BADDR(packet->dp_Arg2)))
               result=DOSFALSE;
            break;

         case ACTION_CREATE_DIR:

            result=MKBADDR(CmdCreateDir(handler,BADDR(packet->dp_Arg1),
               BStr(BADDR(packet->dp_Arg2))));
            break;

         case ACTION_EXAMINE_OBJECT:

            if(!CmdExamineObject(handler,BADDR(packet->dp_Arg1),
               BADDR(packet->dp_Arg2)))
               result=DOSFALSE;
            break;

         case ACTION_EXAMINE_FH:

            if(!CmdExamineFH(handler,(APTR)packet->dp_Arg1,
               BADDR(packet->dp_Arg2)))
               result=DOSFALSE;
            break;

         case ACTION_EXAMINE_NEXT:

            if(!CmdExamineNext(handler,BADDR(packet->dp_Arg2)))
               result=DOSFALSE;
            break;

         case ACTION_INFO:

            if(!CmdInfo(handler,BADDR(packet->dp_Arg2)))
               result=DOSFALSE;
            break;

         case ACTION_DISK_INFO:

            if(!CmdInfo(handler,BADDR(packet->dp_Arg1)))
               result=DOSFALSE;
            break;

         case ACTION_SET_PROTECT:

            if(!CmdSetProtect(handler,BADDR(packet->dp_Arg2),
               BStr(BADDR(packet->dp_Arg3)),packet->dp_Arg4))
               result=DOSFALSE;
            break;

         case ACTION_SET_COMMENT:

            if(!CmdSetComment(handler,BADDR(packet->dp_Arg2),
               BStr(BADDR(packet->dp_Arg3)),BStr2(BADDR(packet->dp_Arg4))
               ))
               result=DOSFALSE;
            break;

         case ACTION_RENAME_OBJECT:

            if(!CmdRenameObject(handler,BADDR(packet->dp_Arg1),
               BStr(BADDR(packet->dp_Arg2)),BADDR(packet->dp_Arg3),
               BStr2(BADDR(packet->dp_Arg4))))
               result=DOSFALSE;
            break;

         case ACTION_RENAME_DISK:

            if(!CmdRenameDisk(handler,BStr(BADDR(packet->dp_Arg1))))
               result=DOSFALSE;
            break;

         case ACTION_SET_DATE:

            if(!CmdSetDate(handler,BADDR(packet->dp_Arg2),
               BStr(BADDR(packet->dp_Arg3)),(APTR)packet->dp_Arg4))
               result=DOSFALSE;
            break;

         case ACTION_DELETE_OBJECT:

            if(!CmdDeleteObject(handler,BADDR(packet->dp_Arg1),
               BStr(BADDR(packet->dp_Arg2))))
               result=DOSFALSE;
            break;

         case ACTION_CURRENT_VOLUME:

            result=MKBADDR(CmdCurrentVolume(handler));
            break;

         case ACTION_CHANGE_MODE:

            result=CmdChangeMode(packet->dp_Arg1,BADDR(packet->dp_Arg2),
               packet->dp_Arg3);
            break;

         case ACTION_MAKE_LINK:

            link_target=(APTR)packet->dp_Arg3;
            link_type=packet->dp_Arg4;
            if(link_type==LINK_HARD)
               link_target=BADDR(link_target);
            if(!CmdMakeLink(handler,BADDR(packet->dp_Arg1),
               BStr(BADDR(packet->dp_Arg2)),link_target,link_type))
               result=DOSFALSE;
            break;

         case ACTION_WRITE_PROTECT:

            if(!CmdWriteProtect(handler,packet->dp_Arg1,
               (ULONG)packet->dp_Arg2))
               result=DOSFALSE;
            break;

         case ACTION_FLUSH:

            if(!CmdFlush())
               result=DOSFALSE;
            break;

         case ACTION_ADD_NOTIFY:

            if(!CmdAddNotify(handler,(APTR)packet->dp_Arg1))
               result=DOSFALSE;
            break;

         case ACTION_REMOVE_NOTIFY:

            if(!CmdRemoveNotify(handler,(APTR)packet->dp_Arg1))
               result=DOSFALSE;
            break;

         default:
            result=DOSFALSE;
            SetIoErr(ERROR_ACTION_NOT_KNOWN);
         }

         ReplyPacket(proc_port,packet,result,IoErr());
      }

   }

   CloseLibrary((APTR)DOSBase);

   return RETURN_OK;
}



static struct DosPacket *GetPacket(struct MsgPort *port)
{
   struct Message *message;
   struct DosPacket *packet;

   message=GetMsg(port);
   if(message!=NULL)
      packet=(struct DosPacket *)((struct Node *)message)->ln_Name;
   else
      packet=NULL;

   return packet;
}



static VOID ReplyPacket(struct MsgPort *proc_port,struct DosPacket *packet,
   PINT result1,PINT result2)
{
   struct MsgPort *port;
   struct Message *message;

   port=packet->dp_Port;
   message=packet->dp_Link;

   packet->dp_Port=proc_port;
   packet->dp_Res1=result1;
   packet->dp_Res2=result2;

   PutMsg(port,message);

   return;
}



TEXT b_buffer[256];
TEXT b_buffer2[256];



static STRPTR BStr(UBYTE *b_str)
{
   UBYTE length;

   length=*b_str;
   if(length!=0)
      CopyMem(b_str+1,b_buffer,length);
   *(b_buffer+length)='\0';

   return b_buffer;
}



static STRPTR BStr2(UBYTE *b_str)
{
   UBYTE length;

   length=*b_str;
   if(length!=0)
      CopyMem(b_str+1,b_buffer2,length);
   *(b_buffer2+length)='\0';

   return b_buffer2;
}



UBYTE *MkBStr(STRPTR str)
{
   UBYTE length;

   length=StrLen(str);
   if(length!=0)
      CopyMem(str,b_buffer+1,length);
   *b_buffer=length;

   return b_buffer;
}



