#include <exec/types.h>
#include <stdlib.h>
#include <string.h>

#include <devices/tpt.h>

#include <dlg/resman.h>
#include <dlg/cron.h>
#include <dlg/Debug.h>

#include <dos/dostags.h>

#include <exec/lists.h>

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

#include <pragmas/dlg.h>

#include <private/privs.h>

#include "Resman.h"

extern   BOOL                 CheckResource(struct MiscNode *,struct RMMessage *);
extern   struct   AreaNode   *FindTheArea(struct RMMessage *,UBYTE);
extern   struct   Node       *FirstNode(struct List *);
extern   void                 FreeCustomMenu(struct PortNode *);
extern   BOOL                 FreeLang(struct LangNode *);
extern   int                  HandlePending(struct MiscNode *);
extern   struct   Node       *IFindName(struct List *, char *);
extern   void                 LoadCustomMenu(struct PortNode *,UBYTE,char *);
extern   struct   MenuNode   *LoadMenu(char *);
extern   BOOL                 LockInQueue(struct List *);
extern   void                 RemFromPorts(struct MenuNode *);
extern   void                 RemoveArea(struct RMMessage *);
extern   void                 RMFreeMenu(struct MenuNode *);
extern   void                 RMFreeResReport(struct List *);
extern   struct   MiscLock   *RMFreeResource(struct MiscNode *,struct RMMessage *);
extern   struct   List       *RMGetResReport(void);
extern   struct   LangNode   *RMLoadLang(char *);
extern   BOOL                 RMLockResource(struct MiscNode *,struct MiscLock *,struct RMMessage *);
extern   void                 TDebug(char *);
extern   void                 InitDebug(void);
extern   void                 KillDebug(void);

void           HandleMsg(struct RMMessage *);
void           CleanUp(char *);
struct Node   *FirstNode(struct List *list);

/// Old RMMsg, required for TrapDoor
struct OldRMMsg
{
  struct Message mess;
  char type;
  char *port;
  USHORT area;
  UBYTE flags;
  char *passwd;
  char *newpasswd;
  char *reason;
  char priority;
  char *breakcommand;
  void *dataptr;
};
//-

struct MsgPort   *rmctl;
struct MsgPort   *oldrmctl;
struct List       LangList;
struct List       ResourceList;
struct LangNode  *lbak;

long  rmsigbit;
long  oldrmsigbit;
long  signal;

unsigned long locks  = (ULONG)-1;

long  __stack        =  8000;
long  __priority     =  3;
long  __BackGroundIO =  0;

char *__procname     = "DLGResMan";

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

char  tdevname = NULL;

struct FuncName internalfuncs[] =
{
   "DisplayMenu",
   "Help"
};

struct Library *DLGBase         =   NULL;

UBYTE    DLGCW       = 0;  // Capability word. Defines what can and cannot be used.
char    *DLGSERIAL;        // Serial number
char    *DLGOWNER;         // Owner name
ULONG    Logins      = 0;  // How many logins are active
ULONG    NetLogins   = 0;  // How many telnet logins are active

#define  MAXLOGINS     2   // Max logins under demo (either basic or telnet)

/// Main
void main(int argc,char **argv)
{
   struct RMMessage  *mymsg;
   struct OldRMMsg   *myoldmsg;

   Forbid();
   rmctl = FindPort(RMCONTROL);
   Permit();

   if (rmctl)  exit(5);

   if (!(DLGBase = OpenLibrary("dlg.library", 4L)))
      CleanUp("Unable to open DLG.library");

   InitDebug();

   //if(System("Run DLG:BGChk",NULL)) Cleanup("System error!");

 // Initialize and open control port, abort if it fails.
   if (!(rmctl = CreateMsgPort())) CleanUp("Error");

   rmctl->mp_Node.ln_Name = RMCONTROL;
   AddPort(rmctl);

// debug
   TDebug("Opened control port");
// end debug

// V2.1 -- added so that TPTRM calls can be interpreted.
   rmsigbit = 1 << rmctl->mp_SigBit;

   if (!(oldrmctl = CreateMsgPort())) CleanUp("Error");

   oldrmctl->mp_Node.ln_Name = "tptrm.control";
   AddPort(oldrmctl);
   oldrmsigbit = 1 << oldrmctl->mp_SigBit;
// End V2.1 Additions

   NewList(&LangList);
   NewList(&ResourceList);

// debug
   TDebug("Initialization complete");
// end debug

   if(SystemTags("Run DLG:BGChk",SYS_Asynch, TRUE)) CleanUp("System error!");

 // This is the main loop of the program. We call HandleMsg() if we see
 // anything interesting.

 do{
      signal = Wait(rmsigbit | oldrmsigbit);

      if(signal & rmsigbit)
         while((mymsg = (struct RMMessage *)GetMsg(rmctl)))
         {
            HandleMsg(mymsg);
         }
//    Added 2.1
      if(signal & oldrmsigbit)
         while((myoldmsg = (struct OldRMMsg *)GetMsg(oldrmctl)))
         {
            myoldmsg->type=RMNOERR;
            ReplyMsg((struct Message *)myoldmsg);
         }
// end 2.1 additions
   } while(TRUE);
}
//-
/// HandleMsg
// This is the main part of the program in terms of handling messages to TpTRM.
void HandleMsg(struct RMMessage *message)
{
   switch(message->type)
   {
///     RMEXIT - shut down ResMan
        case RMEXIT:          message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              CleanUp(NULL);
                              break;
//-
///     ACTIVATEPORT - Activate a port
        case ACTIVATEPORT:   {struct PortNode *port;
                              struct RootNode *rn;
                              struct DosInfo  *dosi;
                              struct DevInfo  *devi;
                              char            *dname;

//                            debug
                              TDebug("ACTIVATEPORT");
//                            end debug

                              // If the port is already active we return
                              // immediately.

                              if (IFindName(&ResourceList, message->port))
                                 {message->type = PORTACTIVE;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              Forbid();
                              rn   = (struct RootNode *)DOSBase->dl_Root;
                              dosi = (struct DosInfo *) BADDR(rn->rn_Info);
                              devi = (struct DevInfo *) BADDR(dosi->di_DevInfo);

                              while(devi)
                                   {if (devi->dvi_Type==DLT_DEVICE)
                                       {dname = (char *)BADDR(devi->dvi_Name);
                                        dname++;
                                        if (!Stricmp(dname, message->port))  break;
                                       }

                                    devi = (struct DevInfo *)BADDR(devi->dvi_Next);
                                   }

                              Permit();

                              if (!devi)
                                 {message->type = GENERALERR;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              // Otherwise, let's set up the port.

                              port = malloc(sizeof(struct PortNode) + 5 + strlen(message->breakcommand));
                              port->mn.users        = 0;
                              port->mn.type         = 0;
                              port->mn.node.ln_Type = NODE_PORT;

                              port->mn.node.ln_Name = ((char *)port + sizeof(struct PortNode));
                              port->bgcommand = stpcpy(port->mn.node.ln_Name, message->port);
                                                strcpy(++port->bgcommand,     message->breakcommand);

                              NewList(&(port->mn.locklist));
                              NewList(&(port->mn.activelocks));

                              port->custnum = -1;
                              port->custnov = NULL;
                              port->custint = NULL;
                              AddTail(&ResourceList,(struct Node *)port);

                              port->ln   = NULL;
                              port->menu = NULL;

                              // If a background task is specified for this port, launch it.
                              if (*(port->bgcommand))  CronEvent(ADDEVENT, 0, port->bgcommand);

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     DEACTIVATEPORT - Deactivate a port
        case DEACTIVATEPORT: {struct PortNode  *port;
                              struct PortLock  *pl;
                              struct RMMessage *tempmess;

//                            debug
                              TDebug("DEACTIVATEPORT");
//                            end debug

                              port = (struct PortNode *)IFindName(&ResourceList,message->port);
                              // If port doesn't exist, we can't deactivate it.

                              if (!port)
                                 {message->type = BADPORT;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (!(pl=(struct PortLock *)RMFreeResource((struct MiscNode *)port,message)))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              free(pl->breakcommand);
                              free(pl);

                              // Fail on pending locks
                              while(pl=(struct PortLock *)RemHead(&(port->mn.locklist)))
                                   {tempmess = pl->ml.rm;

                                    free(pl->ml.node.ln_Name);
                                    free(pl->ml.reason);
                                    free(pl->breakcommand);
                                    free(pl);

                                    tempmess->type = BADPORT;
                                    ReplyMsg((struct Message *)tempmess);
                                   }

                              Remove((struct Node *)port);
                              if (port->ln) FreeLang(port->ln);
                              free(port);

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     LOCKPORT - Lock a port
        case LOCKPORT:       {struct PortNode *port;
                              struct PortLock *pl;
                              struct PortLock *tpl;

//                            debug
                              TDebug("LOCKPORT");
//                            end debug

                              port = (struct PortNode *)IFindName(&ResourceList,message->port);
                              if (!port)
                                 {message->type = BADPORT;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (IsListEmpty(&(port->mn.activelocks)))
                                 {if (!locks)
                                     {message->type = NOTLOCKED;
                                      ReplyMsg((struct Message *)message);
                                      break;
                                     }

                                  locks--;
                                 }

                              if (!(message->flags & PENDLOCK) && !CheckResource((struct MiscNode *)port,message))
                                 {tpl = (struct PortLock *)FirstNode(&(port->mn.activelocks));

                                  if (tpl && ((tpl->ml.node.ln_Pri>=0) || (message->priority<0)))
                                     {message->type = NOTLOCKED;
                                      ReplyMsg((struct Message *)message);
                                      break;
                                     }
                                 }

                              pl = malloc(sizeof(struct PortLock));
                              if (!pl)
                                 {message->type = RMNOMEM;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              pl->breakcommand = malloc(strlen(message->breakcommand)+1);
                              strcpy(pl->breakcommand, message->breakcommand);

                              if (RMLockResource((struct MiscNode *)port,(struct MiscLock *)pl,message))
                                 {message->type = RMNOERR;
                                  ReplyMsg((struct Message *)message);
                                 }
                               else
                                 {tpl = (struct PortLock *)FirstNode(&(port->mn.activelocks));

                                  if ((tpl->ml.node.ln_Pri<0)&&(pl->ml.node.ln_Pri>=0))
                                     {tpl->ml.node.ln_Pri = 0;
                                      if (*(tpl->breakcommand))
                                            CronEvent(ADDEVENT, 0, tpl->breakcommand);
                                     }
                                 }

                              break;
                             }
//-
///     FREEPORT - Free a port
        case FREEPORT:       {struct PortNode  *port;
                              struct PortLock  *pl;

//                            debug
                              TDebug("FREEPORT");
//                            end debug

                              port = (struct PortNode *)IFindName(&ResourceList,message->port);
                              if (!port)
                                 {message->type = BADPORT;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (!(pl = (struct PortLock *)RMFreeResource((struct MiscNode *)port,message)))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              free(pl->breakcommand);
                              free(pl);

                              if (IsListEmpty(&(port->mn.activelocks)))
                                 {if (*(port->bgcommand))  CronEvent(ADDEVENT, 0, port->bgcommand);
                                  locks++;
                                 }

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     GETPORTINFO - Get info on a port.
        case GETPORTINFO:    {struct PortNode *port;
                              struct PortLock *pl;
                              struct PortInfo *pinfo;

//                            debug
                              TDebug("GETPORTINFO");
//                            end debug

                              port = (struct PortNode *)IFindName(&ResourceList,message->port);
                              if (!port)
                                 {message->type = BADPORT;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (IsListEmpty(&(port->mn.activelocks)))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              pinfo = (struct PortInfo *)message->dataptr;
                              pl    = (struct PortLock *)port->mn.activelocks.lh_Head;

                              pinfo->passwd       = malloc(strlen(pl->ml.node.ln_Name) + strlen(pl->ml.reason) + strlen(pl->breakcommand) + 3);
                              pinfo->reason       = stpcpy(pinfo->passwd,         pl->ml.node.ln_Name);
                              pinfo->breakcommand = stpcpy(++pinfo->reason,       pl->ml.reason);
                                                    strcpy(++pinfo->breakcommand, pl->breakcommand);
                              pinfo->priority     = pl->ml.node.ln_Pri;

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     FREEPORTINFO
        case FREEPORTINFO:
//                            debug
                              TDebug("FREEPORTINFO");
//                            end debug

                              free(((struct PortInfo *)message->dataptr)->passwd);
                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
//-
///     TRANSFERPORT
        case TRANSFER:       {struct PortNode  *port;
                              struct PortLock  *pl;

//                            debug
                              TDebug("TRANSFER");
//                            end debug

                              port = (struct PortNode *)IFindName(&ResourceList,message->port);
                              if (!port)
                                 {message->type = BADPORT;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              pl = (struct PortLock *)IFindName(&(port->mn.activelocks),message->passwd);
                              if (!pl)
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              // Free old info
                              free(pl->ml.node.ln_Name);
                              free(pl->ml.reason);
                              free(pl->breakcommand);

                              // Replace with new info
                              pl->ml.node.ln_Pri  = message->priority;
                              pl->ml.node.ln_Name = malloc(strlen(message->newpasswd) + 1);
                              strcpy(pl->ml.node.ln_Name, message->newpasswd);
                              pl->ml.reason       = malloc(strlen(message->reason) + 1);
                              strcpy(pl->ml.reason, message->reason);
                              pl->breakcommand    = malloc(strlen(message->breakcommand)+1);
                              strcpy(pl->breakcommand, message->breakcommand);

                              if (!IsListEmpty(&(port->mn.locklist)) && (pl->ml.node.ln_Pri<0))
                                   if (*(pl->breakcommand))  CronEvent(ADDEVENT, 0, pl->breakcommand);

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     LISTPORTS
        case LISTPORTS:      {char            *s;
                              struct Node     *nd;
                              struct PortNode *port;

//                            debug
                              TDebug("LISTPORTS");
//                            end debug

                              nd = ResourceList.lh_Head;
                              s  = message->port;
                             *s  = 0;

                              while(nd->ln_Succ)
                                   {port = (struct PortNode *)nd;
                                    if ((port->mn.node.ln_Type==NODE_PORT)  &&
                                        (!message->passwd    ||
                                         !(*message->passwd) ||
                                         IFindName(&(port->mn.activelocks), message->passwd)))
                                        {s = stpcpy(s, port->mn.node.ln_Name);
                                        }

                                    nd = nd->ln_Succ;
                                   }

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     LOCKAREA
        case LOCKAREA:       {struct AreaNode *area;
                              struct AreaLock *al;

//                            debug
                              TDebug("LOCKAREA");
//                            end debug

                              area = FindTheArea(message, 1);
                              al   = malloc(sizeof(struct AreaLock));
                              if (!al)
                                 {message->type = RMNOMEM;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (RMLockResource((struct MiscNode *)area, (struct MiscLock *)al, message))
                                 {message->type = RMNOERR;
                                  ReplyMsg((struct Message *)message);
                                 }
                              break;
                             }
//-
///     ENTERAREA
        case ENTERAREA:      {struct AreaNode *area;

//                            debug
                              TDebug("ENTERAREA");
//                            end debug

                              area = FindTheArea(message, 1);
                              if (LockInQueue(&(area->mn.activelocks))  ||
                                 (LockInQueue(&(area->mn.locklist))))
                                 {message->type = AREAINUSE;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }
         
                              area->mn.users++;
                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     LEAVEAREA
        case LEAVEAREA:     {struct AreaNode *area;

//                            debug
                              TDebug("LEAVEAREA");
//                            end debug

                             area = FindTheArea(message, 0);
                             if (!area)
                                 {message->type = BADAREA;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (area->mn.users)
                                 {area->mn.users--;
                                 }
                               else
                                 {message->type = AREAEMPTY;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (!area->mn.users  &&
                                 (IsListEmpty(&(area->mn.activelocks)) ||
                                  !(area->mn.type&WRITELOCK)))
                                 {HandlePending((struct MiscNode *)area);
                                  if (IsListEmpty(&(area->mn.activelocks)))
                                      RemoveArea(message);
                                 }

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     FREEAREA
        case FREEAREA:       {struct AreaNode *area;
                              struct AreaLock *al;

//                            debug
                              TDebug("FREEAREA");
//                            end debug

                              area = FindTheArea(message, 0);
                              if (!area)
                                 {message->type = BADAREA;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (!(al=(struct MiscLock *)RMFreeResource((struct MiscNode *)area,message)))
                                 {message->type=NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              free(al);
                              if (IsListEmpty(&(area->mn.activelocks)) && !area->mn.users)
                                  RemoveArea(message);

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     GETAREAINFO
        case GETAREAINFO:    {struct DLGAreaInfo *ainfo;
                              struct AreaNode    *area;
                              struct AreaLock    *al;

//                            debug
                              TDebug("GETAREAINFO");
//                            end debug

                              area = FindTheArea(message, 0);
                              if (!area)
                                 {message->type = BADAREA;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              ainfo = (struct DLGAreaInfo *)message->dataptr;
                              if (IsListEmpty(&(area->mn.activelocks)))
                                 {ainfo->passwd = (char *)malloc(22);
                                  ainfo->reason = stpcpy(ainfo->passwd,   "NOT LOCKED");
                                                  strcpy(++ainfo->reason, "NOT LOCKED");
                                  ainfo->priority = 0;
                                  ainfo->users    = area->mn.users;
                                 }
                               else
                                 {al = (struct AreaLock *)area->mn.activelocks.lh_Head;

                                  ainfo->passwd = malloc(strlen(al->node.ln_Name) + strlen(al->reason) + 2);
                                  ainfo->reason = stpcpy(ainfo->passwd,   al->node.ln_Name);
                                                  strcpy(++ainfo->reason, al->reason);
                                  ainfo->priority = al->node.ln_Pri;
                                  ainfo->users    = area->mn.users;
                                 }

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     FREEAREAINFO
        case FREEAREAINFO:
//                            debug
                              TDebug("FREEAREAINFOT");
//                            end debug

                              free(((struct DLGAreaInfo *)message->dataptr)->passwd);
                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
//-
///     LOADLANG
        case LOADLANG:       {struct PortNode  *port;

//                            debug
                              TDebug("LOADLANG");
//                            end debug

                              port = (struct PortNode *)IFindName(&ResourceList,message->port);

                              if (!port)
                                 {message->type = BADPORT;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (!port->ln || Stricmp(port->ln->ls.name, (char *)message->dataptr))
                                 {if (port->ln)
                                     {lbak = port->ln;
                                     }
                                   else
                                     {lbak = NULL;
                                     }

                                  if (port->ln = (struct LangNode *)RMLoadLang((char *)message->dataptr))
                                     {if (lbak)  FreeLang(lbak);
                                      message->type = RMNOERR;
                                     }
                                   else
                                     {if (lbak)  port->ln = lbak;
                                      message->type = NOLANG;
                                     }
                                 }
                               else
                                 {message->type = RMNOERR;
                                 }

                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     GETLANG
        case GETLANG:        {struct PortNode  *port;

//                            debug
                              TDebug("GETLANG");
//                            end debug

                              port = (struct PortNode *)IFindName(&ResourceList,message->port);
                              if (!port)
                                 {message->type = BADPORT;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (port->ln)
                                 {message->dataptr = &(port->ln->ls);
                                  message->type    =   RMNOERR;
                                 }
                               else
                                 {message->dataptr = NULL;
                                  message->type    = NOLANG;
                                 }

                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     LOCKRESOURCE
        case LOCKRESOURCE:   {struct MiscLock *ml;
                              struct MiscNode *mn;

//                            debug
                              TDebug("LOCKRESOURCE");
//                            end debug

                              if (!(mn=(struct MiscNode *)IFindName(&ResourceList,message->dataptr)))
                                 {mn = (struct MiscNode *)malloc(sizeof(struct MiscNode) + strlen(message->dataptr) + 1);
                                  if (!mn)
                                     {message->type = RMNOMEM;
                                      ReplyMsg((struct Message *)message);
                                      break;
                                     }

                                  mn->users        =  0;
                                  mn->type         =  0;
                                  mn->node.ln_Type =  NODE_MISC;
                                  mn->node.ln_Name = (char *)mn + sizeof(struct MiscNode);
                                  strcpy(mn->node.ln_Name, message->dataptr);

                                  NewList(&(mn->activelocks));
                                  NewList(&(mn->locklist));
                                  AddTail(&ResourceList,(struct Node *)mn);
                                 }

                              if (!(message->flags&PENDLOCK) && !CheckResource(mn,message))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              ml = (struct MiscLock *)malloc(sizeof(struct MiscLock));
                              if (!ml)
                                 {message->type = RMNOMEM;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (RMLockResource(mn, ml, message))
                                 {message->type = RMNOERR;
                                  ReplyMsg((struct Message *)message);
                                 }
                              break;
                             }
//-
///     FREERESOURCE
        case FREERESOURCE:   {struct MiscLock  *ml;
                              struct MiscNode  *mn;

//                            debug
                              TDebug("FREERESOURCE");
//                            end debug

                              if (!(mn = (struct MiscNode *)IFindName(&ResourceList, message->dataptr)))
                                 {message->type = BADRES;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (!(ml=(struct MiscLock *)RMFreeResource(mn, message)))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }
                              free(ml);

                              if (IsListEmpty(&(mn->activelocks)))
                                 {Remove((struct Node *)mn);
                                  free(mn);
                                 }

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     LOCKMENU
        case LOCKMENU:       {struct PortNode  *port;
                              struct MiscLock  *ml;
                              struct MenuNode  *mun;
                              struct MenuStuff *ms;

//                            debug
                              TDebug("LOCKMENU");
//                            end debug

                              ms = (struct MenuStuff *)message->dataptr;
                              if (*(message->port))
                                 {port = (struct PortNode *)IFindName(&ResourceList, message->port);
                                 }
                               else
                                 {port = NULL;
                                 }

                              if (!ms->name)
                                 {if (!port)
                                     {message->type = BADPORT;
                                      ReplyMsg((struct Message *)message);
                                      break;
                                     }

                                  if (port->menu)
                                     {mun = port->menu;
                                     }
                                   else
                                     {message->type = NOTLOCKED;
                                      ReplyMsg((struct Message *)message);
                                      break;
                                     }
                                 }
                               else
                                 {if (!(mun=(struct MenuNode *)IFindName(&ResourceList,ms->name)))
                                     {if (!(mun=(struct MenuNode *)LoadMenu(ms->name)))
                                         {message->type = NOLOADMENU;
                                          ReplyMsg((struct Message *)message);
                                          break;
                                         }
                                     }
                                 }


                              if (port)
                                 {if (mun!=port->menu  ||  message->area!=port->custnum)
                                      FreeCustomMenu(port);

                                  if (mun!=port->menu || message->area!=port->custnum)
                                      LoadCustomMenu(port,message->area,mun->mn.node.ln_Name);
                                 }
      
                              ms->custnum = port->custnum;
                              ms->custnov = port->custnov;
                              ms->custint = port->custint;

                              if (port)  port->menu = mun;

                              ms->mun = mun;
                              if (!(message->flags&PENDLOCK) && !CheckResource((struct MiscNode *)mun,message))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              ml = malloc(sizeof(struct MiscLock));
                              if (!ml)
                                 {message->type = RMNOMEM;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (RMLockResource((struct MiscNode *)mun,(struct MiscLock *)ml,message))
                                 {message->type = RMNOERR;
                                  ReplyMsg((struct Message *)message);
                                 }
                              break;
                             }
//-
///     FREEMENU
        case FREEMENU:       {struct PortNode  *port;
                              struct MiscLock  *ml;
                              struct MenuNode  *mun;

//                            debug
                              TDebug("FREEMENU");
//                            end debug

                              if (!message->dataptr)
                                 {port = (struct PortNode *)IFindName(&ResourceList,message->port);
                                  if (!port)
                                     {message->type = BADPORT;
                                      ReplyMsg((struct Message *)message);
                                      break;
                                     }

                                  if (!port->menu)
                                     {message->type = NOTLOCKED;
                                      ReplyMsg((struct Message *)message);
                                      break;
                                     }

                                  mun = port->menu;
                                 }
                               else
                                 {if (!(mun = (struct MenuNode *)IFindName(&ResourceList,message->dataptr)))
                                     {message->type = BADRES;
                                      ReplyMsg((struct Message *)message);
                                      break;
                                     }
                                 }

                              if (!(ml = (struct MiscLock *)RMFreeResource((struct MiscNode *)mun,message)))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              free(ml);
                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     PURGEMENU
        case PURGEMENU:      {struct PortNode  *port;
                              struct MiscLock  *ml;
                              struct MenuNode  *mun;

//                            debug
                              TDebug("PURGEMENU");
//                            end debug

                              if (*(message->port))
                                 {port = (struct PortNode *)IFindName(&ResourceList,message->port);
                                 }
                               else
                                 {port = NULL;
                                 }

                              if (!message->dataptr)
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (!(mun = (struct MenuNode *)IFindName(&ResourceList,message->dataptr)))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }

                              if (!(ml = (struct MiscLock *)RMFreeResource((struct MiscNode *)mun,message)))
                                 {message->type = NOTLOCKED;
                                  ReplyMsg((struct Message *)message);
                                  break;
                                 }
                              free(ml);

                              RemFromPorts(mun);
                              RMFreeMenu(mun);
                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
                             }
//-
///     GETRESREPORT
        case GETRESREPORT:
//                            debug
                              TDebug("GETRESREPORT");
//                            end debug

                              message->dataptr = RMGetResReport();
                              message->type    = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
//-
///     FREERESREPORT
        case FREERESREPORT:
//                            debug
                              TDebug("FREERESREPORT");
//                            end debug

                              RMFreeResReport(message->dataptr);
                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
//-
///     LOGIN
        case LOGIN:           TDebug("LOGIN");
                              Logins++;   // We increment anyway. If it's too many, the extra will be
                                          // removed.

                              if(ISDEMO())   // Keep more than max number of users from logging in in demo
                              {
                                 if(Logins > MAXLOGINS)
                                    message->type = RMGENERALERR;
                                 else
                                    message->type = RMNOERR;
                              }
                              else
                              {
                                 message->type = RMNOERR;
                              }

                              ReplyMsg((struct Message *)message);
                              break;
//-
///     LOGOUT
        case LOGOUT:          TDebug("LOGOUT");
                              Logins--;

                              if(Logins < 0)
                              {
                                 Logins = 0;
                                 message->type = GENERALERR;
                              }
                              else
                              {
                                 message->type = RMNOERR;
                              }

                              ReplyMsg((struct Message *)message);
                              break;
//-
///     TNLOGIN
        case TNLOGIN:         TDebug("LOGIN");
                              NetLogins++;

                              if(ISDEMO() || !ISTELNET())   // Keep more than max number of users from logging in in demo
                              {
                                 if(NetLogins >= MAXLOGINS)
                                    message->type = RMGENERALERR;
                                 else
                                    message->type = RMNOERR;
                              }
                              else
                              {
                                 message->type = RMNOERR;
                              }

                              ReplyMsg((struct Message *)message);
                              break;
//-
///     TNLOGOUT
        case TNLOGOUT:        TDebug("TNLOGOUT");
                              NetLogins--;

                              if(NetLogins < 0)
                              {
                                 NetLogins = 0;
                                 message->type = GENERALERR;
                              }
                              else
                              {
                                 message->type = RMNOERR;
                              }

                              ReplyMsg((struct Message *)message);
                              break;
//-
///     GETLOGINS
        case GETLOGINS:
//                            debug
                              TDebug("GETLOGINS");
//                            end debug

                              message->area    = Logins;
                              message->type    = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
//-
///     GETTNLOGINS
        case GETTNLOGINS:
//                            debug
                              TDebug("GETTNLOGINS");
//                            end debug

                              message->area    = NetLogins;
                              message->type    = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
//-
///     Undocumented: get CW, serial, owner from BGChk.
        case 99:              //TDebug("Agent 99");
                              DLGCW = message->priority;
                              DLGSERIAL = strdup(message->passwd);
                              DLGOWNER  = strdup(message->reason);
/*
                              if(ISDEMO())   TDebug("Demo");

                              if(ISBOSS())
                              {
                                 TDebug("Boss Package!");
                              }

                              if(ISTELNET())
                              {
                                 TDebug("Telnet enabled");
                              }

                              if(ISFIDO())
                              {
                                 TDebug("Fido Enabled");
                              }

                              if(ISBASIC())  TDebug("Basic enabled");
*/
                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
//-
///     Undocumented: Send serial number
        case 98:              //TDebug("Agent 98");

                              if(ISDEMO())
                                 message->passwd = strdup("DEMO");
                              else
                                 message->passwd = strdup(DLGSERIAL);

                              message->type = RMNOERR;
                              ReplyMsg((struct Message *)message);
                              break;
//-
        default:
//                            debug
                              TDebug("Unknown command type");
//                            end debug

                              message->type = RMBAD;
                              ReplyMsg((struct Message *)message);
                              break;
       }
}
//-
/// CleanUp
void CleanUp(char *s)
{
   //if (rmsigbit) FreeSignal(rmsigbit);
   if (rmctl)    DeleteMsgPort(rmctl);
   //if (oldrmctl) DeleteMsgPort(oldrmctl);

   KillDebug();

   if (DLGBase)  CloseLibrary(DLGBase);

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

/// FirstNode -- returns first node in list, or NULL if list is empty
struct Node *FirstNode(struct List *list)
{
   struct Node *nd;

   nd = list->lh_Head;

   if (nd->ln_Succ)
      return(nd);
   else
      return(NULL);
}
//-
