/*

File: handler.c
Author: Neil Cafferkey
Copyright (C) 2001 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.

*/



/*

TO DO:

Allow directory creation from Workbench.
Sort out problems relating to ACTION_WRITE result (prevents "disk full"
   requester being displayed).
Record locking.
Implement ACTION_EXAMINE_ALL and ACTION_EXAMINE_ALL_END.

Implement soft links.
Respect R and W flags for directories?
Find out about CreateDir() deleting objects.


NOTES:

Links implementation:

If a real object is linked, the object and its links are linked, via their
"hard_link" node, into the "elements" list of one of the links. The link
whose list is used is called the master link. The linked object is always
first in the list and the master link is always second. An object without
links has both fields of "hard_link" set to NULL.

*/


#include "handler_protos.h"


/* Global variables */

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

/* Data prototypes */

extern struct ExecBase *AbsExecBase;

/* Global constants */

const TEXT version_string[]="$VER: amber-ram-handler 1.1 (13.3.2001)";
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;
}



