#include <exec/exec.h>
#include <proto/exec.h>
#include <dos/dos.h>
#include <dos/notify.h>
#include <dos/rdargs.h>
#include <proto/dos.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <intuition/gadgetclass.h>
#include <proto/intuition.h>
#include <libraries/gadtools.h>
#include <proto/gadtools.h>
#include <proto/diskfont.h>
#include <proto/graphics.h>
#include <rexx/rxslib.h>
#include <rexx/storage.h>
#include <rexx/errors.h>
#include <proto/rexxsyslib.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>

#include <devices/tpt.h>

#include <dlg/dlg.h>
#include <dlg/resman.h>
#include <dlg/user.h>
#include <dlg/portconfig.h>

#include <link/io.h>

#include <proto/dlg.h>

#include <pragmas/dlg.h>

#include "dlgcp.h"

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

#define WINSIG (1 << win->UserPort->mp_SigBit)
#define MYSIG  (1 << myport->mp_SigBit)

BOOL  OpenDisplay(void);
BOOL  HandleArgs(void);
void  HandleMsg(struct Message *);
void  HandleIMsg(struct IntuiMessage *);
BOOL  HandleRxMsg(struct RexxMsg *);
void  ReplyRexxCommand(struct RexxMsg *,long,char *);
BOOL  LaunchRxScript(char *,char *);
BOOL  SendRexxx(char *,char *, char *);
void  HandleGadgetEvent(struct Gadget *,ULONG);
void  SelectPort(char *);
BOOL  DoCommand(char *,char **, long);
void  GetString(int,char *,char *);
BOOL  OpenSnoopWindow(char *,int *,int *,int *,int *,BOOL,char *,int *);
BOOL  OpenSnoopScreen(char *,int *,int *,int *,char *,BOOL,BOOL,BOOL,char *,int *);
BOOL  SetFlags(char *,char *);
BOOL  SetColors(char *,char *);
BOOL  ConfigButton(int,int,char *,char *);
BOOL  InitBanks(void);
BOOL  ReadConfig(char *);
BOOL  CreateMyListview(int,int);
BOOL  CreateButtons(int,int,int);
void  SelectBank(int);
BOOL  OpenTheWindow(int,int,int,int);
BOOL  DrawGads(void);
BOOL  IconifyWindow(void);
BOOL  DeIconifyWindow(void);
BOOL  MakePortList(void);
BOOL  AddThePort(char *,char *);
void  FreePortList(void);
BOOL  UpdatePortString(char *);
void  InitList(struct List *);
void  FreeBanks(void);
void  CloseGadgets(void);
void  CloseDisplay(void);
void  CleanUp(char *s);
void _CXBRK(void);


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

struct MsgPort  *ReplyPort    = NULL;
struct MsgPort  *myport       = NULL;
struct Screen   *pubscrn      = NULL;
struct Window   *win          = NULL;
struct TextAttr *font         = NULL;
struct TextAttr  b_Attr;
struct TextAttr *b_font       = NULL;
struct Gadget   *glist        = NULL;
struct Gadget   *gads         = NULL;
struct CPBank   *banks        = NULL;
struct Gadget   *mylistview   = NULL;
struct RDArgs   *myargs       = NULL;
struct List      portlist;
void            *vi           = NULL;

char   b_fontname[40] = "";

long   tbord,bbord,rbord,lbord;
long   currbank     = -1;

BOOL   terminated   =  FALSE;
int    numbanks     =  NUMBANKS;
int    numbuttons   =  NUMBANKS * 4;
BOOL   iconified    =  FALSE;
char  *configfile   = "DLGConfig:Misc/dlgcp.cfg";
char  *myaddress    = "DLGCP";

USHORT currcount    = 65535;
struct Gadget *cgad = NULL;
char   currport[3]  = "";

int    x,y,w,h;
char   pubname[256];
int    iconx,icony;

BPTR             sout;
struct USER_DATA UserDat;
struct Ram_File  RStruct;

int   ct[8] = {0x000,0xf00,0x0f0,0xff0,0x00f,0xf0f,0x0ff,0xfff};
ULONG ds    =  0;
ULONG dm    =  0;


/// Main
void main(int argc,char **argv)
{struct IntuiMessage *imsg;
 struct Message      *msg;
 int                  waitsignals;
 int                  signals;

 sout = Output();

 x          = WINXOFS;
 y          = WINYOFS;
 w          = WINWIDTH;
 h          = WINHEIGHT;
 pubname[0] =   0;
 iconx      = 500;
 icony      =  11;

 InitList(&portlist);

 if (!(DLGBase=(struct Library *)OpenLibrary(DLGNAME,DLGVERSION)))
       CleanUp("Unable to open DLG.library");

 if (!(IntutionBase=OpenLibrary("intuition.library",37)))
       CleanUp("Requires V37 intuition.library");

 if (!(GadToolsBase=OpenLibrary("gadtools.library",37)))
       CleanUp("Requires V37 gadtools.library");

 if (!(RexxSysBase=(struct Library *)OpenLibrary(RXSNAME,0)))
       CleanUp("Unable to open rexxsyslib.library");

 if (!HandleArgs())  CleanUp("Bad arguments");

 Forbid();
 myport = FindPort(myaddress);
 Permit();
 if (myport)  CleanUp("DLGCP already running");

 myport = CreateMsgPort();
 if (!myport)  CleanUp("Unable to open message port");
 myport->mp_Node.ln_Name = myaddress;
 AddPort(myport);

 ReplyPort = CreateMsgPort();
 if (!ReplyPort)  CleanUp("Unable to open message port");


 if (!ReadConfig(configfile))  CleanUp("Unable to read config file");
 if (!banks)
     if (!InitBanks())         CleanUp("Unable to allocate banks");
 if (!MakePortList())          CleanUp("Unable to get list of ports");
 if (!OpenDisplay())           CleanUp("Unable to open display");
 SelectBank(0);

 waitsignals = MYSIG | WINSIG;
 do {signals = Wait(waitsignals);

     if (signals & WINSIG)
         while(imsg = GT_GetIMsg(win->UserPort))
               HandleIMsg(imsg);

     if (signals & MYSIG)
         while(msg = GetMsg(myport))
               HandleMsg(msg);
    } while(!terminated);

 CleanUp(NULL);
}
//-

/// OpenDisplay
BOOL OpenDisplay(void)
{if (!OpenTheWindow(x,y,w,h))  CleanUp("Unable to open window");
 if (!DrawGads())              CleanUp("Unable to draw gadgets");

 return(TRUE);
}
//-

/// HandleArgs
BOOL HandleArgs(void)
{int  arg;
 long args[15];

 for(arg = 0; arg < 15; arg++)
     args[arg] = NULL;

 myargs = ReadArgs("C=CONFIG/K", args, NULL);
 if (args[0]) configfile=(char *)args[0];

 if (!myargs)
      return(FALSE);
 return(TRUE);
}
//-

/// HandleIMsg
void HandleIMsg(struct IntuiMessage *imsg)
{struct Gadget *gad;
 ULONG          class,code,secs,micros;

 gad    = (struct Gadget *)imsg->IAddress;
 class  =  imsg->Class;
 code   =  imsg->Code;
 secs   =  imsg->Seconds;
 micros =  imsg->Micros;

 GT_ReplyIMsg(imsg);

 switch(class)
       {case IDCMP_GADGETDOWN:
        case IDCMP_MOUSEMOVE:
        case IDCMP_GADGETUP:      HandleGadgetEvent(gad,code);
                                  break;

        case IDCMP_CLOSEWINDOW:   terminated = TRUE;
                                  break;

        case IDCMP_REFRESHWINDOW: GT_BeginRefresh(win);
                                  GT_EndRefresh(win,TRUE);
                                  break;

        case IDCMP_MOUSEBUTTONS:  if (iconified) DeIconifyWindow();
                                  break;

        case IDCMP_INTUITICKS:    break;
       }
}
//-

/// HandleMsg
void HandleMsg(struct Message *msg)
{struct NotifyMessage *nmsg;

 if (msg->mn_Length == sizeof(struct RexxMsg))
     HandleRxMsg((struct RexxMsg *)msg);
   else
    {if (!iconified)
        {nmsg = (struct NotifyMessage *)msg;

         GT_SetGadgetAttrs(mylistview,win,NULL,GTLV_Labels,~0,TAG_END);
         UpdatePortString((char *)nmsg->nm_NReq->nr_UserData);
         GT_SetGadgetAttrs(mylistview,win,NULL,GTLV_Labels,&portlist,GTLV_Selected,currcount,TAG_END);
        }

     ReplyMsg(msg);
    }
}
//-

/// HandleRxMsg
BOOL HandleRxMsg(struct RexxMsg *rxmsg)
{ULONG code;
 char  cmd[256];
 BOOL  result = TRUE;
 char *rxres  = NULL;

 code = rxmsg->rm_Action & RXCODEMASK;

 if (rxmsg->rm_Node.mn_Node.ln_Type==NT_REPLYMSG)
    {DeleteArgstring((char *)rxmsg->rm_Args[0]);
     DeleteRexxMsg(rxmsg);
    }
  else
    {if (code==RXCOMM)
        {ASPrintf(NULL, cmd, "%.254s\n", rxmsg->rm_Args[0]);
         result = DoCommand(cmd, &rxres, -1);
        }
      else
         AFPrintf(NULL, sout, "Wierd code\n");

     ReplyRexxCommand(rxmsg,result ? RC_OK : RC_ERROR, rxres);
    }

 return(TRUE);
}
//-

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

 /* set an error code */
 if (rexxmessage->rm_Action & (1 << 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);
}
//-

/// LaunchRxScript
BOOL LaunchRxScript(char *script, char *ext)
{struct RexxMsg *rm;
 struct MsgPort *resport;

 Forbid();
 resport = FindPort("REXX");
 Permit();
 if (!resport)  return(FALSE);

 rm = (struct RexxMsg *)CreateRexxMsg(myport,ext,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)Input();
 rm->rm_Stdout  = (LONG)Output();

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

 PutMsg(resport, (struct Message *)rm);
 return(TRUE);
}
//-

/// SendRexx
BOOL SendRexx(char *port, char *cmd, char *result)
{struct RexxArg *ra;
 struct MsgPort *RexxPort;
 struct RexxMsg  RexxMsg;
 LONG            retval = 0;

 if (result) *result = 0;

 Forbid();
 RexxPort = FindPort(port);
 Permit();

 if (RexxPort)
    {RexxMsg.rm_Node.mn_ReplyPort = ReplyPort;
     RexxMsg.rm_Node.mn_Length    = sizeof(struct RexxMsg);
     RexxMsg.rm_Action            = RXCOMM | RXFF_RESULT;
     RexxMsg.rm_Args[0]           = cmd;
     PutMsg(RexxPort, (struct Message *)&RexxMsg);

     while(!GetMsg(ReplyPort))
           WaitPort(ReplyPort);

     retval = RexxMsg.rm_Result1;

     if (RexxMsg.rm_Result2)
        {if (result)  strcpy(result, (char *)RexxMsg.rm_Result2);
         ra = (struct RexxArg *)((char *)RexxMsg.rm_Result2 - &((struct RexxArg *)NULL)->ra_Buff[0]);
         FreeMem(ra, ra->ra_Size);
        }
    }
  else
    AFPrintf(NULL, sout, "DLGCP: SendRexx [%s] [%s]\nNo rexx port\n",port,cmd);

 return((BOOL)(retval==RC_OK));
}
//-

/// HandleGadgetEvent
void HandleGadgetEvent(struct Gadget *gad,ULONG code)
{int          id,button,count;
 char        *cmd;
 struct Node *nd;
 char         port[4];

 id = gad->GadgetID;

 if (id==MYLISTVIEW)
    {nd    = portlist.lh_Head;
     count = 0;

     while(nd->ln_Succ)
          {if (count==code) break;

           nd = nd->ln_Succ;
           count++;
          }

     if (count==code)
        {strncpy(port,nd->ln_Name,3);
         port[3]='\0';

         if (cgad)  cgad->Flags &= ~GFLG_SELECTED;

         currcount    = count;
         cgad         = gad;
         cgad->Flags |= GFLG_SELECTED;

         SelectPort(port);
        }
    }
  else
    if (id < (BANKSTART+numbanks))
       {SelectBank(id-BANKSTART);
       }
     else
       {button = id-(BANKSTART+numbanks);
        cmd    = banks[currbank].buttons[button].command;
        if (cmd)
           {if (!DoCommand(cmd, NULL, currbank))
                 AFPrintf(NULL, sout, "Command failed\n");
           }
       }
}
//-

/// SelectPort
void SelectPort(char *port)
{strcpy(currport, port);

 ReadUser(&RStruct,&UserDat,port);
}
//-

/// DoCommand
BOOL DoCommand(char *cmd, char **rxres, long bank)
{long               args[DLGCP_MAXARGS];
 long               cmdnum;
 long               count;
 struct DLGCPRxCmd *rxcmd;
 char               tbuf [256];
 struct RDArgs     *rda   = NULL;
 struct RDArgs     *rdres = NULL;
 BOOL               result = TRUE;

 if (*currport)
     TranslateBuffer(cmd,tbuf,256,&UserDat,&RStruct,currport);
   else
    {strncpy(tbuf,cmd,255);
     tbuf[255] = '\0';
    }

 for(count = 0; count < DLGCP_MAXARGS; count++)
     args[count] = NULL;

 for(rxcmd = rxcmds; rxcmd->name && Strnicmp(rxcmd->name,tbuf,strlen(rxcmd->name)); rxcmd++);

 if (!rxcmd->name)
    {if (rxres) *rxres = "BAD COMMAND";
     return(FALSE);
    }

 if (rxcmd->template)
    {rda = AllocDosObjectTags(DOS_RDARGS,TAG_DONE);
     if (rda)
        {rda->RDA_Source.CS_Buffer = tbuf+strlen(rxcmd->name)+1;
         rda->RDA_Source.CS_Length = strlen(rda->RDA_Source.CS_Buffer);
         rda->RDA_Source.CS_CurChr = 0;
         rda->RDA_DAList           = NULL;
         rda->RDA_Buffer           = NULL;
         rda->RDA_BufSiz           = NULL;
         rda->RDA_Flags            = RDAF_NOPROMPT;
         rdres = ReadArgs(rxcmd->template,args,rda);
        }
    }

 if (!rxcmd->template || rdres)
    {cmdnum = ((int)rxcmd-(int)rxcmds)/sizeof(struct DLGCPRxCmd);

     switch(cmdnum)
           {case DLGCP_CONFIGBUTTON: if (!(args[0] && args[1] && args[2]))
                                           result = FALSE;
                                         else
                                           result = ConfigButton(*(int *)args[0],*(int *)args[1],(char *)args[2],(char *)args[3]);
                                     break;

            case DLGCP_NUMBANKS:     if (banks)
                                         result=FALSE;
                                       else
                                         if (args[0])
                                            {numbanks   = *(long *)args[0];
                                             numbuttons = numbanks*4;
                                            }
                                     break;

            case DLGCP_WINDOW:       if (!win)
                                        {if (args[0])  x=*(long *)args[0];
                                         if (args[1])  y=*(long *)args[1];
                                         if (args[2])  w=*(long *)args[2];
                                         if (args[3])  h=*(long *)args[3];
                                        }
                                      else
                                        result = FALSE;
                                     break;

            case DLGCP_PUBSCREEN:    if (!win)
                                         {if (args[0])
                                             {strncpy(pubname, (char *)args[0], 255);
                                              pubname[255] = 0;
                                             }
                                         }
                                       else
                                         result = FALSE;
                                     break;

            case DLGCP_BFONT:        if (!win)
                                        {if (!(args[0] && args[1]))
                                               result = FALSE;
                                             else
                                              {struct TextFont *bfont;

                                               strncpy(b_fontname, (char *)args[0], 40);
                                               b_fontname[39] = 0;
                                               strcat(b_fontname, ".font");

                                               b_Attr.ta_Name  = b_fontname;
                                               b_Attr.ta_YSize = *(long *)args[1];
                                               b_Attr.ta_Style = 0;
                                               b_Attr.ta_Flags = 0;
                                               b_font          = &b_Attr;
                                               if ((bfont = OpenDiskFont(b_font)))
                                                    CloseFont(bfont);
                                                  else
                                                    result = FALSE;
                                              }
                                        }
                                      else
                                        result = FALSE;
                                     break;

            case DLGCP_EXE:          if (args[0])
                                         result = !OverlayProgram((char *)args[0]);
                                     break;

            case DLGCP_RX:           if (args[0])
                                         result = LaunchRxScript((char *)args[0],"cprx")  ||  LaunchRxScript((char *)args[0],"drx");
                                     break;

            case DLGCP_TRAPTELL:     if (!args[0])
                                        {args[0] = (long)(&"TrapDoor");
                                         if (bank >= 0)
                                            {Forbid();
                                             if (FindPort(banks[bank].name))
                                                 args[0] = (long)(&banks[bank].name);
                                             Permit();
                                            }
                                        }

            case DLGCP_SENDREXX:     if (args[1])
                                         result = SendRexx((char *)args[0], (char *)args[1], NULL);
                                     break;

            case DLGCP_DMC:          if (args[0])
                                         result = SendRexx("DLGM_ARexx",(char *)args[0], NULL);
                                     break;

            case DLGCP_TKILL:        if (args[0])
                                        {TSetFlags(T_KILL_ENABLE,(char *)args[0]);
                                         result = (BOOL)(TKill((char *)args[0])==NOERR);
                                        }
                                     break;

            case DLGCP_TBAUD:        if (args[0] & args[1])
                                         result = (BOOL)(TBaud(*(long *)args[1],(char *)args[0])==NOERR);
                                     break;

            case DLGCP_TCOLORS:      if (args[0]&args[1])
                                         result = SetColors((char *)args[1],(char *)args[0]);
                                     break;

            case DLGCP_TCONT:        if (args[0])
                                         result = (BOOL)(TCont((char *)args[0])==NOERR);
                                     break;

            case DLGCP_TFLAGS:       if (args[0]&&args[1])
                                         result = SetFlags((char *)args[1],(char *)args[0]);
                                     break;

            case DLGCP_TFREEZE:      if (args[0])
                                         result = (BOOL)(TFreeze((char *)args[0])==NOERR);
                                     break;

            case DLGCP_TRECOVER:     if (args[0])
                                         result = (BOOL)(TRecover((char *)args[0])==NOERR);
                                     break;

            case DLGCP_TSCREENOPEN:  if (args[0])
                                         result = OpenSnoopScreen((char *)args[0],
                                                                  (int *) args[1],
                                                                  (int *) args[2],
                                                                  (int *) args[3],
                                                                  (char *)args[4],
                                                                  (BOOL)  args[5],
                                                                  (BOOL)  args[6],
                                                                  (BOOL)  args[7],
                                                                  (char *)args[8],
                                                                  (int *) args[9]);
                                     break;

            case DLGCP_TSCREENCLOSE: if (args[0])
                                         TScreen(TCLOSESCREEN,NULL,(char *)args[0]);
                                     break;

            case DLGCP_TSTRING:      if (args[0] && args[1])
                                         result = (BOOL)(TString((char *)args[1],(char *)args[0])==NOERR);
                                     break;

            case DLGCP_TTIMEDELAY:   if (args[0] && args[1])
                                         result = (BOOL)(TTimeDelay(*(int *)args[1],(char *)args[0])==NOERR);
                                     break;

            case DLGCP_TTITLE:       if (args[0]&&args[1])
                                         result = (BOOL)(TTitle((char *)args[1],(char *)args[0])==NOERR);
                                     break;

            case DLGCP_TWINDOWOPEN:  if (args[0])
                                         result = OpenSnoopWindow((char *)args[0],(int *)args[1],(int *)args[2],(int *)args[3],(int *)args[4],(BOOL)args[5],(char *)args[6],(int *)args[7]);
                                     break;

            case DLGCP_TWINDOWCLOSE: if (args[0])
                                         TWindow(TCLOSEWIND,NULL,(char *)args[0]);
                                     break;

            case DLGCP_TRANSLATE:    if (args[0])
                                        {strcpy(tbuf,(char *)args[0]);
                                         if (rxres)  *rxres=tbuf;
                                        }
                                      else
                                        {if (rxres)  *rxres = "ERROR";
                                         result = FALSE;
                                        }
                                     break;

            case DLGCP_GETSTRING:    tbuf[0] = 0;
                                     if (!args[0] || (*(int *)args[0]>255))
                                          GetString(255,(char *)args[1],tbuf);
                                        else
                                          GetString(*(int *)args[0],(char *)args[1],tbuf);

                                     if (rxres)  *rxres=tbuf;
                                     break;

            case DLGCP_ICONIFYLOC:   if (args[0])
                                         iconx = *(int *)args[0];
                                     if (args[1])
                                         icony = *(int *)args[1];
                                     break;

            case DLGCP_ICONIFY:      if (!win)
                                        {result =  FALSE;
                                        *rxres  = "WINDOW NOT OPEN";
                                        }
                                      else
                                        if (iconified)
                                           {result =  FALSE;
                                           *rxres  = "WINDOW ALREADY ICONIFIED";
                                           }
                                         else
                                           result = IconifyWindow();
                                     break;

            case DLGCP_DEICONIFY:    if (!iconified)
                                        {result =  FALSE;
                                        *rxres  = "WINDOW NOT ICONIFIED";
                                        }
                                      else
                                         result = DeIconifyWindow();
                                     break;

            default:                 AFPrintf(NULL, sout, "Unrecognized command [%s]\n",rxcmd->name);
                                     break;
           }

     if (!iconified  &&  *currport)
        {GT_SetGadgetAttrs(mylistview,win,NULL,GTLV_Labels,~0,TAG_END);
         UpdatePortString(currport);
         GT_SetGadgetAttrs(mylistview,win,NULL,GTLV_Labels,&portlist,GTLV_Selected,currcount,TAG_END);
        }
    }
  else
    result = FALSE;

 if (rdres)  FreeArgs(rdres);
 if (rda)    FreeDosObject(DOS_RDARGS,rda);

 return(result);
}
//-

/// GetString
void GetString(int numchars,char *prompt,char *buf)
{int sx,sy,sw,sh;
 struct Window *swin=NULL;
 struct Gadget *sglist=NULL,*sgads=NULL;
 struct NewGadget ng;
 struct Gadget *gad;
 ULONG class;
 ULONG code;
 struct IntuiMessage *imsg=NULL;
 BOOL exitflag=FALSE;
 int num;

 num = strlen(prompt);
 if (numchars>num)  num = numchars;

 sy =   y + tbord + 2;
 sw = ((num + 1) * 8) + 15;
 if (sw> (w-40))  sw = w-40;
 sx = x + lbord + (w-sw-25)/2;

 sgads = CreateContext(&sglist);
 if (sgads)
    {ng.ng_LeftEdge        =  lbord+1;
     ng.ng_TopEdge         =  tbord+1;
     ng.ng_Width           = (numchars+1)*8+15;
     if (ng.ng_Width>(sw-2))  ng.ng_Width = sw-2;
     if (b_font)
        {ng.ng_Height      = b_font->ta_YSize+7;
         sh                = b_font->ta_YSize+10;
         ng.ng_TextAttr    = b_font;
        }
       else
        {ng.ng_Height      = font->ta_YSize+7;
         sh                = font->ta_YSize+10;
         ng.ng_TextAttr    = font;
        }
     ng.ng_VisualInfo      = vi;
     ng.ng_GadgetID        = 0;
     ng.ng_Flags           = NULL;
     ng.ng_GadgetText      = NULL;

     sgads = CreateGadget(STRING_KIND,sgads,&ng,GTST_MaxChars,numchars,TAG_END);
     if (sgads)
        {swin = OpenWindowTags(NULL,
                               WA_Left,        sx,
                               WA_Top,         sy,
                               WA_InnerWidth,  sw,
                               WA_InnerHeight, sh,
                               WA_PubScreen,   pubscrn,
                               WA_Flags,       WFLG_SMART_REFRESH|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_ACTIVATE,
                               WA_Title,       prompt,
                               WA_Gadgets,     sglist,
                               WA_IDCMP,       IDCMP_REFRESHWINDOW|IDCMP_INTUITICKS|IDCMP_GADGETUP,
                               WA_AutoAdjust,  TRUE,
                               TAG_DONE);
         if (swin)
            {GT_RefreshWindow(swin,NULL);

             do {WaitPort(swin->UserPort);

                 while(imsg=(struct IntuiMessage *)GT_GetIMsg(swin->UserPort))
                      {gad   = (struct Gadget *)imsg->IAddress;
                       class =  imsg->Class;
                       code  =  imsg->Code;

                       GT_ReplyIMsg(imsg);

                       switch(class)
                             {case IDCMP_GADGETDOWN:
                              case IDCMP_MOUSEMOVE:
                              case IDCMP_GADGETUP:      if (!gad->GadgetID)
                                                           {strcpy(buf,((struct StringInfo *)gad->SpecialInfo)->Buffer);
                                                            exitflag = TRUE;
                                                           }
                                                        break;

                              case IDCMP_REFRESHWINDOW: GT_BeginRefresh(swin);
                                                        GT_EndRefresh(swin,TRUE);
                                                        break;
                             }
                      }
                } while(!exitflag);

             CloseWindow(swin);
            }

        }

     FreeGadgets(sglist);
    }
}
//-

/// OpenSnoopWindow
BOOL OpenSnoopWindow(char *port,int *x,int *y,int *w,int *h,BOOL bkgrnd,char *font,int *fontsize)
{struct Port     MyPort;
 struct Displays MyDisplay;
 char            filename[80];

 MyDisplay.Window.x      =   0;
 MyDisplay.Window.y      =  11;
 MyDisplay.Window.width  = 640;
 MyDisplay.Window.height = 109;
 strcpy(MyDisplay.Window.fontname,"topaz");
 MyDisplay.Window.fontsize = 8;
 MyDisplay.Window.flags    = 0;

 ASPrintf(NULL, filename, "DlgConfig:Port/%s.port", port);
 if (GetFirstStruct(filename, (char *)&MyPort, sizeof(MyPort)) != -1)
    {ASPrintf(NULL, filename, "DlgConfig:Port/%s", MyPort.DisplayFile);
     GetFirstStruct(filename, (char *)&MyDisplay, sizeof(MyDisplay));
    }

 if (x)        MyDisplay.Window.x        = *x;
 if (y)        MyDisplay.Window.y        = *y;
 if (w)        MyDisplay.Window.width    = *w;
 if (h)        MyDisplay.Window.height   = *h;
 if (bkgrnd)   MyDisplay.Window.flags   |=  DISP_BKGRND;
 if (font)     strcpy(MyDisplay.Window.fontname,font);
 if (fontsize) MyDisplay.Window.fontsize = *fontsize;

 TWindow(TPOPWIND,&(MyDisplay.Window),port);
 return(TRUE);
}
//-

/// OpenSnoopScreen
BOOL OpenSnoopScreen(char *port,int *width,int *height,int *depth,char *colors,BOOL hires,BOOL lace,BOOL bkgrnd,char *font,int *fontsize)
{struct Port MyPort;
 struct Displays MyDisplay;
 int count;
 char filename[80];

 MyDisplay.Screen.width=640; MyDisplay.Screen.height=200;
 MyDisplay.Screen.depth=3;
 MyDisplay.Screen.hires=1; MyDisplay.Screen.interlace=0;
 MyDisplay.Screen.flags=0;

 strcpy(MyDisplay.Screen.fontname,"topaz");
 MyDisplay.Screen.fontsize=8;

 ASPrintf(NULL, filename,"DlgConfig:Port/%s.port",port);
 if (GetFirstStruct(filename, (char *)&MyPort, sizeof(MyPort)) != -1)
    {ASPrintf(NULL, filename, "DlgConfig:Port/%s", MyPort.DisplayFile);
     GetFirstStruct(filename, (char *)&MyDisplay, sizeof(MyDisplay));
    }

 if (width)    MyDisplay.Screen.width=*width;
 if (height)   MyDisplay.Screen.height=*height;
 if (depth)    MyDisplay.Screen.depth=*depth;
 if (font)     strcpy(MyDisplay.Screen.fontname,font);
 if (fontsize) MyDisplay.Screen.fontsize=*fontsize;
 if (hires)    MyDisplay.Screen.hires=1;
 if (lace)     MyDisplay.Screen.interlace=1;
 if (bkgrnd)   MyDisplay.Screen.flags|=DISP_BKGRND;

 for(count = 0; count < 8; count++)
     ct[count] = (int)MyDisplay.Screen.colortable[count];

 if (colors)
     sscanf(colors,"%x%x%x%x%x%x%x%x",ct,ct+1,ct+2,ct+3,ct+4,ct+5,ct+6,ct+7);

 for(count = 0; count < 8; count++)
     MyDisplay.Screen.colortable[count]=(unsigned short)ct[count];

 TScreen(TPOPSCREEN,&(MyDisplay.Screen),port);
 return(TRUE);
}
//-

/// SetFlags
BOOL SetFlags(char *flags,char *port)
{int enableflags  = 0;
 int disableflags = 0;

  while(*flags)
       {switch(*flags++)
              {case 'B':  enableflags  |= T_BREAK;
                          break;

               case 'b':  disableflags |= T_BREAK;
                          break;

               case 'C':  enableflags  |= T_CRLF;
                          break;

               case 'c':  disableflags |= T_CRLF;
                          break;

               case 'D':  enableflags  |= T_CTLD;
                          break;

               case 'd':  disableflags |= T_CTLD;
                          break;

               case 'E':  enableflags  |= T_ECHO;
                          break;

               case 'e':  disableflags |= T_ECHO;
                          break;

               case 'F':  enableflags  |= T_LINEFREEZE;
                          break;

               case 'f':  disableflags |= T_LINEFREEZE;
                          break;

               case 'K':  enableflags  |= T_KILL_ENABLE;
                          break;

               case 'k':  disableflags |= T_KILL_ENABLE;
                          break;

               case 'W':  enableflags  |= T_DO_PEND;
                          break;

               case 'w':  disableflags |= T_DO_PEND;
                          break;

               case 'X':  enableflags  |= T_PASS_THRU;
                          break;

               case 'x':  disableflags |= T_PASS_THRU;
                          break;

               case 'S':  enableflags  |= T_PAUSE;
                          break;

               case 's':  disableflags |= T_PAUSE;
                          break;

               case 'R':  enableflags  |= T_RAW;
                          break;

               case 'r':  disableflags |= T_RAW;
                          break;

               case 'T':  enableflags  |= T_DO_TIMEOUT;
                          break;

               case 't':  disableflags |= T_DO_TIMEOUT;
                          break;

               case 'V':  enableflags  |= T_VERB_PAUSE;
                          break;

               case 'v':  disableflags |= T_VERB_PAUSE;
                          break;
              }
       }

 if (enableflags)   TSetFlags(enableflags,port);
 if (disableflags)  TUnSetFlags(disableflags,port);

 return(TRUE);
}
//-

/// SetColors
BOOL SetColors(char *colors,char *port)
{unsigned short colortable[8];
 int            count;

 sscanf(colors,"%x%x%x%x%x%x%x%x",ct,ct+1,ct+2,ct+3,ct+4,ct+5,ct+6,ct+7);

 for(count=0; count < 8; count++)
     colortable[count] = (unsigned short)ct[count];

 return((BOOL)(TColors(colortable,port)==NOERR));
}
//-

/// ConfigButton
BOOL ConfigButton(int bank,int button,char *name,char *cmd)
{struct CPButton      *cpbut;
 struct NotifyRequest *nr;
 int                   len;

 if (!banks)
      if (!InitBanks()) return(FALSE);

 if (bank > numbanks  ||  button > numbuttons)
     return(FALSE);

 bank--;

 if (button == 0)
    {strncpy(banks[bank].name, name, 35);
     banks[bank].name[35] = 0;

     if (cmd)
        {strncpy(banks[bank].port, cmd, 3);
         banks[bank].port[3] = 0;

         while(*cmd)
              {if (*cmd == ' ')  break;
               if (*cmd == 9)    break;
               cmd++;
              }

         while(*cmd)
              {if (*cmd != ' '  &&  *cmd != 9)  break;
               cmd++;
              }

         if (*cmd)
            {nr              = &banks[bank].nr;
             nr->nr_Name     = (char *)malloc(strlen(cmd)+1);;
             nr->nr_UserData = (ULONG)(&banks[bank].port[0]);

             if (nr->nr_Name)
                {strcpy(nr->nr_Name, cmd);
                 nr->nr_Flags                = NRF_SEND_MESSAGE;
                 nr->nr_stuff.nr_Msg.nr_Port = myport;

                 StartNotify(nr);
                }
            }
        }
    }
  else
    {cpbut = &(banks[bank].buttons[button-1]);
     strncpy(cpbut->name, name, 35);
     cpbut->name[35] = 0;

     if (cmd)
        {if (cpbut->command)  free(cpbut->command);
         len            =  strlen(cmd);
         cpbut->command = (char *)malloc(len+2);
         if (!cpbut->command)  CleanUp("Unable to allocate memory");

         strcpy(cpbut->command, cmd);
         cpbut->command[len]   = '\n';
         cpbut->command[len+1] = '\0';
        }
    }

 return(TRUE);
}
//-

/// InitBanks
BOOL InitBanks(void)
{int bank;
 int button;

 banks = (struct CPBank *)malloc(numbanks*sizeof(struct CPBank));
 if (!banks)  return(FALSE);

 for(bank=0; bank < numbanks; bank++)
     banks[bank].buttons = NULL;

 for(bank=0;bank<numbanks;bank++)
    {strcpy(banks[bank].name,"-*-");

     banks[bank].port[0]        =   0;
     banks[bank].nr.nr_Name     =  NULL;
     banks[bank].nr.nr_UserData =  NULL;
     banks[bank].gad            =  NULL;
     banks[bank].glist          =  NULL;
     banks[bank].buttons        = (struct CPButton *)malloc(numbuttons*sizeof(struct CPButton));
     if (!banks[bank].buttons)  return(FALSE);

     for(button=0;button<numbuttons;button++)
        {strcpy(banks[bank].buttons[button].name,"-*-");
         banks[bank].buttons[button].command = NULL;
         banks[bank].buttons[button].gad     = NULL;
        }
    }

 return(TRUE);
}
//-

/// ReadConfig
BOOL ReadConfig(char *name)
{FILE *cfp     = NULL;
 long  linenum =  0;
 BOOL  result  = TRUE;
 char  buf[256];
 long  c;

 if (!(cfp=fopen(name,"r"))) return(FALSE);

 while(fgets(buf,256,cfp))
      {linenum++;

       if(buf[0] != '\n'  &&  buf[0] != ';')
         {c = 0;
          while(!buf[c])
               {if (buf[c] == '"')
                   {c++;
                    while(buf[c] != '"'  &&  !buf[c])
                          c++;
                   }

                if (buf[c] == ';')
                   {buf[c++] = '\n';
                    buf[c]   =   0;
                    break;
                   }
               }

          if (!DoCommand(buf, NULL, -1))
             {AFPrintf(NULL, sout, " Error on line %d of config file [%s]\n",linenum,name);
              AFPrintf(NULL, sout, " -> %s\n",buf);

              result = FALSE;
              break;
             }
         }
      }

 fclose(cfp);
 return(result);
}
//-

/// CreateMyListview
BOOL CreateMyListview(int w,int h)
{struct NewGadget ng;

 ng.ng_LeftEdge     = lbord;
 ng.ng_TopEdge      = tbord;
 ng.ng_Width        = w;
 ng.ng_Height       = h/2;
 if (b_font)
     ng.ng_TextAttr = b_font;
   else
     ng.ng_TextAttr = font;
 ng.ng_VisualInfo   = vi;
 ng.ng_GadgetID     = MYLISTVIEW;
 ng.ng_Flags        = NULL;

 mylistview = gads  = CreateGadget(LISTVIEW_KIND,gads,&ng,GTLV_ShowSelected,NULL,GTLV_Labels,&portlist,TAG_END);

 if (!gads)
      return(FALSE);
 return(TRUE);
}
//-

/// CreateButtons
BOOL CreateButtons(int y,int w,int h)
{struct NewGadget ng;
 int              gadwidth;
 int              gadheight;
 int              bank;
 int              button;

 gadwidth  = (w-5)/5;
 gadheight =  h / numbanks;

 ng.ng_LeftEdge     = lbord;
 ng.ng_TopEdge      = y;
 ng.ng_Width        = gadwidth;

 if (b_font)
     ng.ng_TextAttr = b_font;
   else
     ng.ng_TextAttr = font;

  ng.ng_Height = ng.ng_TextAttr->ta_YSize + 3;
  if (gadheight > ng.ng_Height)
      ng.ng_Height = gadheight;
    else
      gadheight    = ng.ng_Height;

 ng.ng_VisualInfo   = vi;
 ng.ng_GadgetID     = BANKSTART;
 ng.ng_Flags        = NULL;

 for(bank=0; bank<numbanks; bank++)
    {ng.ng_GadgetText = banks[bank].name;
     banks[bank].gad  = gads = CreateGadget(BUTTON_KIND,gads,&ng,TAG_END);
     ng.ng_TopEdge   += gadheight;
     ng.ng_GadgetID++;
    }
 if (!gads)  return(FALSE);

 for(bank=0; bank<numbanks; bank++)
    {gads = CreateContext(&(banks[bank].glist));

     ng.ng_GadgetID = BANKSTART+numbanks;
     ng.ng_LeftEdge = lbord+gadwidth+5;
     ng.ng_TopEdge  = y;

     for(button=0;button<numbuttons;button++)
        {if (button&&!(button%4))
            {ng.ng_TopEdge += gadheight;
             ng.ng_LeftEdge = lbord+gadwidth+5;
            }

         ng.ng_GadgetText = banks[bank].buttons[button].name;
         banks[bank].buttons[button].gad = gads = CreateGadget(BUTTON_KIND,gads,&ng,TAG_END);
         ng.ng_LeftEdge  += gadwidth;
         ng.ng_GadgetID++;
        }

     if (!gads) return(FALSE);
    }

 return(TRUE);
}
//-

/// SelectBank
void SelectBank(int bank)
{UWORD pos;

 if (currbank >= 0)
     pos = RemoveGList(win,banks[currbank].buttons[0].gad,numbuttons);
  else
     pos = (UWORD)~0;

 AddGList(win,banks[bank].buttons[0].gad,pos,numbuttons,NULL);
 RefreshGList(banks[bank].buttons[0].gad,win,NULL,numbuttons);

 GT_RefreshWindow(win, NULL);

 currbank = bank;
}
//-

/// OpenTheWindow
BOOL OpenTheWindow(int x,int y,int w,int h)
{if (!pubname[0])
      pubscrn = LockPubScreen(NULL);
    else
      pubscrn = LockPubScreen(pubname);
 if (!pubscrn)  return(FALSE);

 font  = pubscrn->Font;
 tbord = pubscrn->WBorTop+font->ta_YSize+1;
 bbord = pubscrn->WBorBottom;
 rbord = pubscrn->WBorRight;
 lbord = pubscrn->WBorLeft;

 vi = GetVisualInfo(pubscrn,TAG_END);
 if (!vi) return(FALSE);

 win = OpenWindowTags(NULL,
                      WA_Left,        x,
                      WA_Top,         y,
                      WA_InnerWidth,  w,
                      WA_InnerHeight, h,
                      WA_PubScreen,   pubscrn,
                      WA_Flags,       WFLG_SMART_REFRESH | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET,
                      WA_Title,      "DLGControlPanel",
                      WA_AutoAdjust,  TRUE,
                      WA_IDCMP,       IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | SLIDERIDCMP | BUTTONIDCMP,
                      TAG_DONE);

 UnlockPubScreen(NULL, pubscrn);

 if (!win)
      return(FALSE);
 return(TRUE);
}
//-

/// DrawGads
BOOL DrawGads(void)
{gads = CreateContext(&glist);
 if (!gads)                            CleanUp("Unable to create gadtools context");
 if (!CreateMyListview(w,h))           CleanUp("Unable to create listview gadget");
 if (!CreateButtons(tbord+h/2,w,h/2))  CleanUp("Unable to create buttons");

 AddGList(win,glist,~0,999,NULL);
 RefreshGList(glist,win,NULL,999);
 GT_RefreshWindow(win,NULL);

 return(TRUE);
}
//-

/// IconifyWindow
BOOL IconifyWindow(void)
{if (!pubname[0])
      pubscrn = LockPubScreen(NULL);
    else
      pubscrn = LockPubScreen(pubname);
 if (!pubscrn)  return(FALSE);

 CloseDisplay();

 font = pubscrn->Font;
 win  = OpenWindowTags(NULL,
                       WA_Left,       iconx,
                       WA_Top,        icony,
             WA_Width,      100,
                       WA_Height,     font->ta_YSize+3,
             WA_PubScreen,  pubscrn,
             WA_Flags,      WFLG_SMART_REFRESH|WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET,
                       WA_Title,     "DLGCP",
                       WA_AutoAdjust, TRUE,
                       WA_IDCMP,      IDCMP_CLOSEWINDOW|IDCMP_REFRESHWINDOW|IDCMP_MOUSEBUTTONS,
                       TAG_DONE);
 if (!win)  return(FALSE);

 UnlockPubScreen(NULL,pubscrn);
 iconified = TRUE;
 return(TRUE);
}
//-

/// DeIconifyWindow
BOOL DeIconifyWindow(void)
{CloseWindow(win);

 OpenDisplay();
 iconified = FALSE;

 return(TRUE);
}
//-

/// MakePortList
BOOL MakePortList(void)
{char *c;
 char  buf [512];
 char  port[4];

 if (ListPorts(buf, "") != RMNOERR)
     return(FALSE);

 port[3] = 0;
 for(c = buf; *c; c+=3)
    {strncpy(port, c, 3);
     if (!UpdatePortString(port))
          CleanUp("Unable to add a port node");
    }

 return(TRUE);
}
//-

/// AddThePort
BOOL AddThePort(char *port,char *info)
{struct Node       *nd;
 struct CPPortNode *cpn;

 nd = portlist.lh_Head;

 while(nd->ln_Succ)
      {if (!Strnicmp(nd->ln_Name,port,3))
          {if (info)
              {strcpy(nd->ln_Name,info);
               return(TRUE);
              }
          }

       nd = nd->ln_Succ;
      }

 cpn = (struct CPPortNode *)malloc(sizeof(struct CPPortNode));
 if (!cpn) return(FALSE);

 cpn->nr.nr_Name     = 0;
 cpn->nr.nr_UserData = 0;

 nd = &(cpn->node);
 nd->ln_Name = (char *)malloc(80);
 if (!nd->ln_Name)  return(FALSE);

 if (info)
     strcpy(nd->ln_Name,info);
   else
     strcpy(nd->ln_Name,port);

 cpn->nr.nr_Name = (char *)malloc(14);
 if (!cpn->nr.nr_Name)  return(FALSE);

 ASPrintf(NULL, cpn->nr.nr_Name, "T:%s.user", port);
 cpn->nr.nr_Flags                = NRF_SEND_MESSAGE;
 cpn->nr.nr_stuff.nr_Msg.nr_Port = myport;

 cpn->nr.nr_UserData = (ULONG)(cpn->nr.nr_Name+11);
 strncpy((char *)cpn->nr.nr_UserData, port, 3);
 *((char *)cpn->nr.nr_UserData+3) = 0;

 StartNotify(&(cpn->nr));
 AddTail(&portlist,nd);

 return(TRUE);
}
//-

/// FreePortList
void FreePortList(void)
{struct Node       *nd;
 struct Node       *tmp;
 struct CPPortNode *cpn;

 nd = portlist.lh_Head;

 while(nd->ln_Succ)
      {if (nd->ln_Name)  free(nd->ln_Name);

       cpn = (struct CPPortNode *)nd;
       if (cpn->nr.nr_Name)
          {EndNotify(&(cpn->nr));
           free(cpn->nr.nr_Name);
          }

       tmp = nd;
       nd  = nd->ln_Succ;

       free(tmp);
      }
}
//-

/// UpdatePortString
BOOL UpdatePortString(char *port)
{long            bank;
 char           *pname = NULL;

 char            trap[80];
 char            buf [80];

 struct Ram_File RStruct;
 struct PortInfo istruct;


 if (ReadRam(&RStruct, port))
    {ASPrintf(NULL, buf, "%s %.20s %.50s", port, RStruct.Name, RStruct.Action);
     return(AddThePort(port, buf));
    }

 ASPrintf(NULL, buf,"%s", port);

 for(bank = 0; bank < numbanks; bank++)
     if (!Stricmp(banks[bank].port, port))
        {Forbid();
         if (FindPort(banks[bank].name))  pname = banks[bank].name;
         Permit();

         if (pname)
            {Delay(30);

             if (SendRexx(pname, "@Status S", trap))
                {
                 ASPrintf(NULL, buf, "%s %.20s: %.50s", port, pname, trap);
                 return(AddThePort(port, buf));
                }
            }
        }

 istruct.port = port;
 if (GetPortInfo(&istruct) == RMNOERR)
    {if (Stricmp(istruct.passwd, "BBS"))
         ASPrintf(NULL, buf, "%s %.20s: %.50s", port, istruct.passwd, istruct.reason);

     FreePortInfo(&istruct);
    }

 return(AddThePort(port, buf));
}
//-

/// InitList
void InitList(struct List *list)
{list->lh_Head     = (struct Node *)&(list->lh_Tail);
 list->lh_TailPred = (struct Node *)&(list->lh_Head);
 list->lh_Tail     =  NULL;
 list->lh_Type     =  NT_UNKNOWN;
}
//-

/// FreeBanks
void FreeBanks(void)
{int                   bank;
 int                   button;

 for(bank = 0; bank < numbanks; bank++)
    {if (banks[bank].buttons)
        {for(button = 0; button < numbuttons; button++)
            {if (banks[bank].buttons[button].command)
                 free(banks[bank].buttons[button].command);
            }

         free(banks[bank].buttons);
         banks[bank].buttons = NULL;
        }

     if (banks[bank].nr.nr_Name)
        {EndNotify(&banks[bank].nr);
         free(banks[bank].nr.nr_Name);
         banks[bank].nr.nr_Name = NULL;
        }
    }
}
//-

/// CloseGadgets
void CloseGadgets(void)
{int bank;

 if (glist)  FreeGadgets(glist);
 glist = NULL;

 for(bank = 0; bank < numbanks; bank++)
     if (banks[bank].glist)
        {FreeGadgets(banks[bank].glist);
         banks[bank].glist = NULL;
        }
}
//-

/// CloseDisplay
void CloseDisplay(void)
{if (win)
    {if (currbank!=-1)  RemoveGList(win,banks[currbank].buttons[0].gad,numbuttons);

     if (win) CloseWindow(win);
     win = NULL;
     CloseGadgets();

     if (vi)  FreeVisualInfo(vi);
     vi = NULL;
    }

 currbank=-1;
}
//-

/// CleanUp
void CleanUp(char *s)
{CloseDisplay();

 if (banks) FreeBanks();
 banks = NULL;

 FreePortList();

 if (ReplyPort)
     DeleteMsgPort(ReplyPort);

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

 if (IntutionBase)  CloseLibrary(IntutionBase);
 if (GadToolsBase)  CloseLibrary(GadToolsBase);
 if (RexxSysBase)   CloseLibrary(RexxSysBase);
 if (DLGBase)       CloseLibrary(DLGBase);

 if (myargs)        FreeArgs(myargs);

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

 exit(s?5:0);
}
//-

/// _CXBRK
void _CXBRK(void)
{return;
}
//-
