#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <dos.h>
#include <exec/types.h>
#include <exec/io.h>
#include <exec/memory.h>
#include <libraries/dosextens.h>
#include <rexx/rxslib.h>
#include <rexx/storage.h>
#include <rexx/errors.h>

#include <dlg/user.h>
#include <dlg/rxint.h>
#include <dlg/dlg.h>

#include <Link/io.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/rexxsyslib.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

#include <private/Version.h>
#define  ObjRev "1"
const UBYTE version[]="\0$VER: DLGRX " BUILDVER "." ObjRev " ©" COPYRIGHT " by Digerati Dreams "__AMIGADATE__;

BOOL  HandleRxMsg(void);
void  reply_rexx_command(struct RexxMsg *,long,char *);
BOOL  LaunchRxScript(char *);
void  CleanUp(char *, BOOL);
void  Usage(void);
void _CXBRK(void);

struct Library *DLGBase     = NULL;
struct Library *RexxSysBase = NULL;

char *port    = NULL;
char *script  = NULL;
char *altname = NULL;
char myaddress[6];

struct MsgPort *rxport = NULL;
struct RxQuery *crxq   = NULL;
struct RexxMsg *crxmsg = NULL;

BPTR sout     = NULL;
BPTR ifh      = NULL;
BPTR ofh      = NULL;
BOOL shutdown = FALSE;

int main(int argc,char **argv)
{
   char  hfile[5];

   sout = Output();

   if (!(DLGBase = OpenLibrary(DLGNAME, 0)))
      CleanUp("Unable to open dlg.library", FALSE);
   if (!(RexxSysBase = OpenLibrary(RXSNAME, 0)))
      CleanUp("Unable to open rexxsyslib.library", FALSE);

   while(--argc>0)
   {
      char *s;

      s = *++argv;
      if (*s++=='-')
      {
         while(*s)
         {
            switch(toupper(*s))
            {
               case 'P':  if (!--argc)  break;
               port   = *++argv;
               break;

               case 'S':  if (!--argc)  break;
               script = *++argv;
               break;

               default:  CleanUp(NULL, TRUE);
               break;
            }

            s++;
         }
      }
   }

   if (!port)    CleanUp("No port specified",   TRUE);
   if (!script)  CleanUp("No script specified", TRUE);

   ASPrintf(NULL, hfile, "%s:", port);

   ifh = Open(hfile, MODE_OLDFILE);
      if (!ifh)  CleanUp("Unable to open handler for input",FALSE);

   ofh = Open(hfile, MODE_NEWFILE);
      if (!ofh)  CleanUp("Unable to open handler for output",FALSE);

   ASPrintf(NULL, myaddress, "%sRX", port);
   Upper(myaddress);

   if(!Exists(script))
   {
      altname=(char *)malloc(strlen(script)+15);
      if(!altname) CleanUp("Unable to allocate memory",FALSE);
      ASPrintf(NULL,altname,"dlgconfig:rexx/%s",script);
      script=altname;

      if(!Exists(script)) CleanUp("Unable to open script file",FALSE);
   }

   if (!(rxport = CreateMsgPort()))
      CleanUp("Unable to open ARexx port", FALSE);

   rxport->mp_Node.ln_Name = myaddress;
   AddPort(rxport);

   LaunchRxScript(script);

   for(;;)
   {
      WaitPort(rxport);
      if (!HandleRxMsg()) break;
   }

   CleanUp(NULL,FALSE);
}


BOOL HandleRxMsg(void)
{
   struct Message *msg;
   struct RexxMsg *rxmsg;
   struct RxQuery *rxq;
   static char     cmdbuf[256];

   while((msg = (struct Message *)GetMsg(rxport)))
   {
      if (msg->mn_Length==sizeof(struct RxQuery))
      {
         rxq = (struct RxQuery *)msg;

         if (crxq)
         {
            sprintf(cmdbuf,"Error");
            rxq->command = cmdbuf;
            ReplyMsg(msg);
         }
         else
         crxq = rxq;

         if (!rxq->user&&!rxq->ram)
         {
            shutdown = TRUE;
            ReplyMsg(msg);
         }
      }
      else
      {
         rxmsg = (struct RexxMsg *)msg;

         if (crxmsg)
         {
            DeleteArgstring((char *)rxmsg->rm_Args[0] );
            DeleteRexxMsg(rxmsg);
         }
         else
         crxmsg = rxmsg;
      }

      if (crxmsg && shutdown)
      {
         if (crxmsg->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
         {
            DeleteArgstring((char *)crxmsg->rm_Args[0]);
            DeleteRexxMsg(crxmsg);

            return(FALSE);
         }

         reply_rexx_command(crxmsg,RC_FATAL,NULL);
         crxmsg = NULL;
      }
      else
      if (crxq && crxmsg)
      {
         if (crxmsg->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
         {
            crxq->command = NULL;
            ReplyMsg((struct Message *)crxq);

            DeleteArgstring((char *)crxmsg->rm_Args[0]);
            DeleteRexxMsg(crxmsg);

            crxq   = NULL;
            crxmsg = NULL;

            return(FALSE);
         }

         strcpy(cmdbuf,crxmsg->rm_Args[0]);
         crxq->command = cmdbuf;
         ReplyMsg((struct Message *)crxq);
         WaitPort(rxport);
         rxq = (struct RxQuery *)GetMsg(rxport);

         if (!rxq->user && !rxq->ram)
         {
            shutdown = TRUE;
            reply_rexx_command(crxmsg,RC_FATAL,NULL);
         }
         else
         reply_rexx_command(crxmsg,rxq->rcode,rxq->rstr);

         ReplyMsg((struct Message *)rxq);
         crxq   = NULL;
         crxmsg = NULL;
      }
   }

   return(TRUE);
}


void reply_rexx_command(struct RexxMsg *rexxmessage, long primary, char *result)
{
   long secondary = NULL;

   /* set an error code */
   if (rexxmessage->rm_Action & 1L<<RXFB_RESULT)
   {
      secondary = result ? (long) CreateArgstring(result,(long)strlen(result)) : NULL;
      primary   = 0;
   }

   rexxmessage->rm_Result1 = primary;
   rexxmessage->rm_Result2 = secondary;
   ReplyMsg((struct Message *)rexxmessage);
}


BOOL LaunchRxScript(char *script)

{
   struct RexxMsg *rm;
   struct MsgPort *resport;

   rm = (struct RexxMsg *)CreateRexxMsg(rxport, "drx", myaddress);
   if (!rm)  return(FALSE);

   rm->rm_Action  =  RXCOMM|RXFF_TOKEN;
   rm->rm_Args[0] = (STRPTR)CreateArgstring(script,strlen(script));
   rm->rm_Result1 =  0;
   rm->rm_Result2 =  NULL;
   rm->rm_Stdin   = (LONG)ifh;
   rm->rm_Stdout  = (LONG)ofh;

   if (!rm->rm_Args[0])
   {
      DeleteRexxMsg(rm);
      return(FALSE);
   }

   Forbid();
   resport = FindPort("REXX");
   Permit();

   if (resport)
   {
      PutMsg(resport, (struct Message *)rm);
      return(TRUE);
   }

   /* no port, clean up... */
   DeleteArgstring((char *)rm->rm_Args[0] );
   DeleteRexxMsg(rm);
   return(FALSE);
}


void _CXBRK()

{
   CleanUp(NULL, FALSE);
}


void CleanUp(char *s, BOOL usage)

{
   if (s)
   {
      Write(sout, "\n Error: ", 9);
      Write(sout, s, strlen(s));
      Write(sout, "\n\n", 2);
   }


   if (usage)  Usage();

   if (ifh)  Close(ifh);
   if (ofh)  Close(ofh);

   if (rxport)
   {
      RemPort(rxport);
      DeleteMsgPort(rxport);
   }

   if (altname)      free(altname);
   if (RexxSysBase)  CloseLibrary(RexxSysBase);
   if (DLGBase)      CloseLibrary(DLGBase);

   exit(s?5:0);
}


void Usage(void)
{
   Write(sout, "\n Usage: DLGRx -p <port> -s <script>\n\n", 38);
}

