//  ARexx Server Example
//  Use this stub for programs that need an ARexx interface!
//  Ron M. Battle
//  $Id:

char   *Version = "$VER: ARexx Server 06Nov92  V1.0 (" ;


#include <functions.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <clib/rexxsyslib_protos.h>
#include <pragmas/rexxsyslib_lib.h>

#define DEBUG

#define MAXNAME    20L

#define NO_ERR          0
#define REXXLIB_ERR     1
#define REXXPORT_ERR    2
#define REXXMSG_ERR     3
#define ARGSTR_ERR      4

char    *ErrString[] = {
                        "NONE!",
                        "Opening  rexx support library!",
                        "Creating rexx port!",
                        "Allocating rexx message!",
                        "Allocating rexx arg string!"};

char   HelpStr[] = {"\n\
\n  ARexx Server Example 11/92  HyperBorea Studio B\n\
------------------------------------------------------\n"};



#define LISTEN_PORT_NAME "DBS"          /* Data Base Server  (default) */
#define TALK_PORT_NAME   "director0"   /* (default)                   */

struct  RxsLib          *RexxSysBase = NULL ;
struct  MsgPort         *rexx_port   = NULL ;  /* for incoming commands       */
struct  MsgPort         *TalkPort= NULL ;     /* where msgs are sent         */
ULONG                   RexxSigMask ;        /* signal mask used for WAIT() */
char    ResultString[MAXNAME] ;             /* for ARexx returns           */


#define NUMCMDS 3                                 /* add your own commands HERE! */
char    *CmdStr[] = { "quit","test","illegal" } ;
enum    cmds        {  quit,  test,  illegal  } ;

ULONG  wakeupmask ;

USHORT LastErr          = NO_ERR ;
BOOL   TimeToExit       = FALSE  ;
char   Prefix[MAXNAME]           ;   /* appended to start of outgoing msg */
char   TalkPortName[MAXNAME], ListenPortName[MAXNAME] ;


void MyCleanup(USHORT err)
{
  if (err) printf("DBS stopped because: ERROR %s\n",ErrString[err]) ;

  if (rexx_port   != NULL) DeletePort(rexx_port)   ;

}

void MyExit(USHORT err)
{
 MyCleanup(err) ;
 exit(FALSE) ;
}

void ParseCmdLine(char *arg[])   /* global variables will be modified */
{
  ULONG     offset ;
  USHORT    i ;
  char      *talkto, *listento ;
  char      buff[22]         ;

  if (*arg[1]=='?') {                         /* give help */
    printf("%s",HelpStr) ;
    exit(0) ;
  };
  for (i=0; arg[i] != NULL; i++) {      /* look at all cmd line arguments       */
    strcpy(buff,arg[i]) ;              /* save original string                 */
    strlwr(arg[i]) ;                  /* convert to lower case first          */
    if ((listento = strstr(arg[i],"-l"))!= NULL) { /* look for listen port name */
      offset = (listento - arg[i]) + 2L ;
      strncpy(ListenPortName,buff+offset,MAXNAME-1L) ;
    };
    if ((talkto  = strstr(arg[i],"-t"))!= NULL) { /* look for talkto port name   */
      offset = (talkto - arg[i]) + 2L ; /* calculate offset into original str   */
      strncpy(TalkPortName,buff+offset,MAXNAME-1L);
    }
  }
}

/* ARexx routines */

struct MsgPort *SetupRexxPort(void)
{
   struct MsgPort *the_port ;
   int            err       ;

   Forbid() ;
   if (FindPort(ListenPortName)) {
     Permit() ;
     err = printf("A public port called '%s' already exists!\n",ListenPortName);
     return(NULL) ;
   }
   the_port = CreatePort(ListenPortName,0L) ;
   Permit() ;
   return(the_port) ;
}


USHORT InitARexx(void)
{
    RexxSysBase = (struct RxsLib *)OpenLibrary(RXSNAME, 0L) ;
    if (RexxSysBase == NULL)  return(REXXLIB_ERR) ;
    if ((rexx_port = SetupRexxPort()) == NULL) return(REXXPORT_ERR) ;
    RexxSigMask = (1L<<rexx_port->mp_SigBit) ;  /* setup signal for Wait()   */
    Forbid() ;       /* now look and see if there is something to talk to!  */
    if ((TalkPort=FindPort(TalkPortName))==NULL) {
      Permit() ;
      printf("%s port NOT found!\n",TalkPortName) ;

    };
    Permit() ;
    return(NO_ERR) ;
}


USHORT SendRexxMessage(UBYTE *info)
{
    struct RexxMsg *rexxmsg    ;
    char           Temp[MAXIN] ;

    if ( (rexxmsg = CreateRexxMsg(rexx_port,NULL,TalkPortName)) == NULL) {
      return(REXXMSG_ERR) ;
    } ;
    Temp[0] = '\0' ;
    if (*Prefix != '\0') strcpy(Temp,Prefix) ;    /* add any prefix */
    strcat(Temp,info) ;         /* move input string to new buffer */
    rexxmsg->rm_Args[0] = CreateArgstring(Temp,strlen(Temp)) ;
    if (rexxmsg->rm_Args[0]==NULL) {
      DeleteRexxMsg(rexxmsg) ;
      return(ARGSTR_ERR) ;
    } ;
    #ifdef DEBUG
      printf("Rexx msg sent is: %s\n",*info) ;
    #endif
    rexxmsg->rm_Action = RXCOMM ;        /* command mode, NOT function */
    PutMsg(TalkPort,(struct Message *)rexxmsg)  ;
    return(0) ;
}

void RecycleRexxMessage(struct RexxMsg *rexxmessage)
{
    DeleteArgstring(rexxmessage->rm_Args[0]) ;
    DeleteRexxMsg(rexxmessage) ;
}

/* ******** */

long DoCommand(char *cmd, char *arg1, char *arg2, char *rawstr)
{
  USHORT    CurrentCmd=0 ;
  long      result=0L    ;

  ResultString[0] = '\0' ;    /* start with null for return string */
  strlwr(cmd) ;  /* convert command to lower case */
  /*  now check first 5 letters of command and get an index into CmdStr[]  */
while((CurrentCmd< NUMCMDS)&&(strncmp(cmd,CmdStr[CurrentCmd],5L)!= 0))CurrentCmd++;

  switch (CurrentCmd) {

    case quit       : TimeToExit = TRUE  ;
                      puts("   DBS DONE!!") ;
                      break ;

    case test       : printf("You sent: %s\n",rawstr) ;
                      break ;

    default         : result = 2L ;  /* return error if not valid command */
                      #ifdef DEBUG
                        puts("ILLEGAL command received!") ;
                      #endif
                      break ;


  };  /* switch */
  return(result) ;
}


void ReplyRexxMessage(struct RexxMsg *rexxmessage, long result)
{
  rexxmessage->rm_Result1 = result ;
  rexxmessage->rm_Result2 = 0L  ;
  if ((result==0)&&(*ResultString != '\0')) {  /* send back result string       */
    rexxmessage->rm_Result2 = ResultString ;  /* point to global result string */
  };
  ReplyMsg((struct Message *)rexxmessage)  ;
}

void ProcessRexxCommand(struct RexxMsg *rexxmessage)
{
  char    *temp      ;
  char    rawstr[MAXOUT] ;  /* storage for whole string, no cmd         */
  char    *token[3]  ;     /* token[0]=Command, other=arguments        */
  USHORT  x          ;    /* token buffer full of pointers to strings */
  long    result=0L  ;

  temp = strchr((char *)rexxmessage->rm_Args[0],' ') ;   /* look for first space */
  temp++ ;                                         /* increment past the space! */
  strcpy(rawstr,temp) ;                           /* save raw                  */
  for (x=0; x<3; token[x]=NULL,x++) ;            /* clear out token buffer    */
  token[0] = (char *)rexxmessage->rm_Args[0] ;  /* parse ARexx string,       */
  token[0] = strtok(token[0],(char *)" ,") ;   /* look for space or ,       */
  token[1] = strtok(NULL," ,") ;
  token[2] = strtok(NULL," ,") ;
  result = DoCommand(token[0],token[1],token[2],rawstr) ;
  ReplyRexxMessage(rexxmessage,result) ;
}


void ProcessEvents(void)
{
  struct RexxMsg      *rexxmessage ;

  while (!TimeToExit)  {

    wakeupmask = Wait(RexxSigMask);  /* wait for events, add yours with '|'  */

    if (wakeupmask & RexxSigMask) {               /* process Rexx commands */
      while ( (rexxmessage = (struct RexxMsg *)GetMsg(rexx_port)) ) {
        if (rexxmessage->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
          RecycleRexxMessage(rexxmessage) ; /* recycle if only a reply message */
        }
        else ProcessRexxCommand(rexxmessage)   ;
      }
    }
  };  /* while !TimeToExit */

  while ( (rexxmessage = (struct RexxMsg *)GetMsg(rexx_port)) ) { /* CLEANUP! */
   if (rexxmessage->rm_Node.mn_Node.ln_Type == NT_REPLYMSG) {
     RecycleRexxMessage(rexxmessage) ;
   }
   else ReplyMsg( (struct Message *) rexxmessage );
  }    /* cleanup while */
}     /* proc          */


/*  *******  MAIN  PROGRAM  ******  */

main(int argc, char *argv[])
{
  USHORT  err   ;

  ListenPortName[0]='\0' ;     /* initialize */
  TalkPortName[0]  ='\0' ;
  Prefix[0]        ='\0' ;

  if (argc>1) ParseCmdLine(argv) ;         /* look for cmd line args     */

  if (ListenPortName[0]=='\0') {
    strcpy(ListenPortName,LISTEN_PORT_NAME) ;   /* default              */
  } ;
  if (TalkPortName[0]=='\0') strcpy(TalkPortName,TALK_PORT_NAME) ;

  if ((err = InitARexx()) != NO_ERR) MyExit(err) ; /* setup ARexx port */

  ProcessEvents()    ;

  MyExit(LastErr) ;

}

