/*


   modify NodeGUI.C so that it has these two lines in the OpenNodeWndWindow()
   function.

                (WA_Left), N_ND->NodeX,
                (WA_Top), N_ND->NodeY,

   and so it has these includes and external definition right after "NodeGUI.H"

   #include "/common/types.h"
   #include "/common/defines.h"
   #include "/common/structures.h"

   extern struct NodeData *N_ND;

   todo:

   add a CheckNodePaths() sub routine..

*/

#include <stdio.h>
#include <exec/types.h>
#include <libraries/locale.h>
#include <exec/memory.h>
#include <dos/dosextens.h>
#include <intuition/screens.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <diskfont/diskfont.h>
#include <utility/utility.h>
#include <graphics/gfxbase.h>
#include <devices/console.h>
#include <devices/serial.h>
#include <devices/timer.h>
#include <workbench/workbench.h>
#include <graphics/scale.h>
#include <clib/locale_protos.h>
#include <clib/exec_protos.h>
#include <clib/wb_protos.h>
#include <clib/intuition_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>
#include <clib/utility_protos.h>
#include <string.h>
#include <clib/diskfont_protos.h>

#include <dos/dos.h>
#include <dos/dostags.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>

#include <libraries/reqtools.h>

#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/reqtools_protos.h>

#include "NodeGUI.h"

#define MAIN

struct ReqToolsBase *ReqToolsBase;

#ifdef __SASC
int CXBRK(void) { return(0); }
int _CXBRK(void) { return(0); }
void chkabort(void) {}
#endif

#include "/common/types.h"
#include "/common/errors.h"
#include "/common/defines.h"
#include "/common/structures.h"
#include "/common/strings.h"
#include "/common/files.h"
#include "/common/options.h"

#include "Node_Options.h"
#include "Node_Console_Protos.h"
#include "Node_Serial_Protos.h"
#include "Node_Input_Protos.h"
#include "Node_Misc_Protos.h"

#include "/library/hbbscommon_protos.h"
#include "/library/hbbscommon_pragmas.h"
#include "nodelibrary/hbbsnode_protos.h"
#include "nodelibrary/hbbsnode_pragmas.h"

long __stack=35000; // *C* how do we change this when the program is running ???

UBYTE *versionstr="$VER: HydraBBS_Node V A9 (20.06.1996)";

struct Library *HBBSCommonBase=NULL;
struct Library *HBBSNodeBase=NULL;

/*** global vars ***/



// ** ALWAYS define pointers as NULL **

struct MsgPort *N_ReplyPort=NULL; // only used in GetBBSGobal so far so might define locally in that..

int N_NodeNum=-1;

char WindowTitle[50];
char InfoTitle[25];
char SettingsTitle[25];

char WatchUserString[80];

struct BBSGlobalData *BBSGlobal=NULL;
struct NodeData *N_ND=NULL;
// *C* put in NodeData ?
struct Screen *scr;
struct TextFont *HBBSFont;
UWORD offx;
UWORD offy;
ULONG InfoWinActive=0; // callers, uploads, downloads

struct List *HistoryList;  // for Get_Line()
ULONG HistoryItems=0;

ULONG rttags[] =
{
  RTGS_Flags, GSREQF_CENTERTEXT,
  RT_Underscore, '_',
  RTEZ_ReqTitle, (ULONG)"Node Message",
  RT_PubScrName, NULL,  // set in main() to BBSGlobal->ScreenInfo.PubScreenName
  TAG_END
};

extern struct ColorSpec ScreenColors[];

#include "/common/shared.c"

void WatchScreenToFront( void )
{
  if (!N_ND->ConOK)
  {
    OpenNodeConsoleWin();
  }
  if (N_ND->ConOK)
  {
    if (N_ND->NodeSettings.UseOwnScreen)
    {
      ScreenToFront(N_ND->ConScr);
    }
    else
    {
      WindowToFront(N_ND->ConWin);
    }
  }
}

BOOL PickConScreen( void )
{
  BOOL retval=FALSE;
  struct rtScreenModeRequester *scrmodereq;

  if (scrmodereq = rtAllocRequestA (RT_SCREENMODEREQ, NULL))
  {
    if (rtScreenModeRequest (scrmodereq, "Select Screen mode:",RTSC_Flags,SCREQF_GUIMODES | SCREQF_DEPTHGAD | SCREQF_SIZEGADS,
                                                               RT_Window,NodeWnd,
                                                               RTSC_MinHeight,200,
                                                               RTSC_MinWidth,640,
                                                               RTSC_MinDepth,1,
                                                               RTSC_MaxDepth,3,
                                                               TAG_END))
    {
      N_ND->NodeSettings.ScrModeID=scrmodereq->DisplayID;
      N_ND->NodeSettings.ScrHeight=scrmodereq->DisplayHeight;
      N_ND->NodeSettings.ScrWidth=scrmodereq->DisplayWidth;
      N_ND->NodeSettings.ScrDepth=scrmodereq->DisplayDepth;
      retval=TRUE;
    }
    rtFreeRequest(scrmodereq);
  }
  return(retval);
}

BOOL CreateNodePorts( void )
{
  N_ND->ReplyPort=NULL; // set to null for FreeNodeData()...
  N_ND->NodePort=NULL;
  if (N_ND->OLMPort=CreateMsgPort())
  {
    if (N_ND->NodePort=CreatePort(N_ND->PortName,0))
    {
      if (N_ND->ReplyPort=CreatePort(0,0)) // don't need to be named..
      {
        return(TRUE);
      }
      else
      {
        DeletePort(N_ND->NodePort);
        N_ND->NodePort=NULL; // set to null for FreeNodeData()...
      }
    }
  }
  return(FALSE);
}

void CloseNodePorts( void )
{
  if (N_ND->OLMPort)
  {
    DeletePort(N_ND->OLMPort);
    N_ND->OLMPort=NULL; // do we need ?
  }
  if (N_ND->NodePort)
  {
    DeletePort(N_ND->NodePort);
    N_ND->NodePort=NULL; // do we need ?
  }
  if (N_ND->ReplyPort)
  {
    DeletePort(N_ND->ReplyPort);
    N_ND->ReplyPort=NULL;
  }
}

void UpdateNodeWndGadgets( void )
{
  // must update stuff like the chat flag, user on-line, reserved etc.. etc..
  GT_SetGadgetAttrs(NodeWndGadgets[NodeWnd_ChatFlag],NodeWnd,NULL,GTCY_Active,N_ND->NodeSettings.ChatFlag ? 0 : 1,TAG_DONE);
}

void OpenNodeWin( struct Screen *scr )
{
  N_ND->NodeSettings.Iconified=TRUE; // just in case the window does not open..
  if (OpenNodeWndWindow(scr)==0)
  {
    N_ND->NodeWnd=NodeWnd; // update node structure
    offx = NodeWnd->BorderLeft;
    offy = NodeWnd->BorderTop;
    sprintf(WindowTitle,"HBBS Node %d Control Window! (C) Hydra/LSD",N_NodeNum);
    SetWindowTitles(NodeWnd,WindowTitle,(UBYTE *) ~0);
    UpdateNodeWndGadgets();
    N_ND->NodeSettings.Iconified=FALSE;
    DOOR_UpdateNodeStatus(UPD_NAME);
    DOOR_UpdateNodeStatus(UPD_GROUP);
    DOOR_UpdateNodeStatus(UPD_ACTION);
    DOOR_UpdateNodeStatus(UPD_CPSBAUD);
  }
}

void CloseNodeWin(void)
{
  N_ND->NodeX=NodeWnd->LeftEdge;
  N_ND->NodeY=NodeWnd->TopEdge;

  CloseNodeWndWindow();
  N_ND->NodeSettings.Iconified=TRUE;
  N_ND->NodeWnd=NULL; // update node structure
}

/*** GUI ***/

void UpdateInfoWin( void )
{
  if (N_ND->InformationOpen)
  {
    sprintf(InfoTitle,"Info For Node %d",N_NodeNum);
    SetWindowTitles(InfoWin,InfoTitle,(UBYTE *)~0);

    // update the list view..
    // depending on what the user's looking at...

    switch(InfoWinActive)
    {
      case 0:
        GT_SetGadgetAttrs(InfoWinGadgets[InfoWin_LV1],InfoWin,NULL,GTLV_Labels,N_ND->Last_Callers,GTLV_Top,0,TAG_DONE);
        break;
      case 1:
        GT_SetGadgetAttrs(InfoWinGadgets[InfoWin_LV1],InfoWin,NULL,GTLV_Labels,N_ND->Last_Uploads,GTLV_Top,0,TAG_DONE);
        break;
      case 2:
        GT_SetGadgetAttrs(InfoWinGadgets[InfoWin_LV1],InfoWin,NULL,GTLV_Labels,N_ND->Last_Downloads,GTLV_Top,0,TAG_DONE);
        break;
      case 3:
        GT_SetGadgetAttrs(InfoWinGadgets[InfoWin_LV1],InfoWin,NULL,GTLV_Labels,N_ND->Last_Pagers,GTLV_Top,0,TAG_DONE);
        break;
      case 4:
        GT_SetGadgetAttrs(InfoWinGadgets[InfoWin_LV1],InfoWin,NULL,GTLV_Labels,N_ND->Last_PWFails,GTLV_Top,0,TAG_DONE);
        break;
      case 5:
        GT_SetGadgetAttrs(InfoWinGadgets[InfoWin_LV1],InfoWin,NULL,GTLV_Labels,N_ND->Last_Carrier,GTLV_Top,0,TAG_DONE);
        break;
    }

    // update the calls number..
    GT_SetGadgetAttrs(InfoWinGadgets[InfoWin_Calls],InfoWin,NULL,GTNM_Number,N_ND->CallsToday,TAG_DONE);


  }
}

void ProcessWindowInfoWin( LONG Class, UWORD Code, APTR IAddress )
{
struct Gadget *gad;
switch ( Class )
  {
  case IDCMP_GADGETUP :
    /* Gadget message, gadget = gad. */
    gad = (struct Gadget *)IAddress;
    switch ( gad->GadgetID )
      {
      case InfoWin_LV1_Cycle1 :
        /* Cycle changed   , Text of gadget :  */
        InfoWinActive=Code;
        UpdateInfoWin();
        break;
      case InfoWin_LV1 :
        /* ListView pressed, Text of gadget :  */
        break;
      }
    break;
  case IDCMP_CLOSEWINDOW :
    /* CloseWindow Now */
    CloseInfoWinWindow();
    N_ND->InformationOpen=FALSE;
    break;
  case IDCMP_REFRESHWINDOW :
    GT_BeginRefresh( InfoWin);
    /* Refresh window. */
    RendWindowInfoWin( InfoWin, InfoWinVisualInfo );
    GT_EndRefresh( InfoWin, TRUE);
    GT_RefreshWindow( InfoWin, NULL);
    RefreshGList( InfoWinGList, InfoWin, NULL, ~0);
    DOOR_UpdateNodeStatus(UPD_NAME);
    DOOR_UpdateNodeStatus(UPD_GROUP);
    DOOR_UpdateNodeStatus(UPD_ACTION);
    DOOR_UpdateNodeStatus(UPD_CPSBAUD);
    break;
  }
}

void UpdateSettingsWindow( void )
{
  if (N_ND->SettingsOpen)
  {
    sprintf(SettingsTitle,"Settings For Node %d",N_NodeNum);
    SetWindowTitles(SettingsWin,SettingsTitle,(UBYTE *)~0);

    GT_SetGadgetAttrs(SettingsWinGadgets[SettingsWin_ModemDebug],SettingsWin,NULL,GTCB_Checked,N_ND->NodeDevice.ModemDebug,TAG_DONE);
    GT_SetGadgetAttrs(SettingsWinGadgets[SettingsWin_ModemLog],SettingsWin,NULL,GTCB_Checked,N_ND->NodeDevice.ModemLog,TAG_DONE);
    GT_SetGadgetAttrs(SettingsWinGadgets[SettingsWin_WinOrScreen],SettingsWin,NULL,GTCY_Active,N_ND->NodeSettings.UseOwnScreen ? 0 : 1,TAG_DONE);
    GT_SetGadgetAttrs(SettingsWinGadgets[SettingsWin_AllowLogins],SettingsWin,NULL,GTCY_Active,N_ND->AllowLogins ? 0 : 1,TAG_DONE);
  }
}

void LoadWindowSettings( void )
{
  struct CfgFileData *WindowCFG;
  char tmpstr[BIG_STR],optionstr[10],*paramstr;
  ULONG loop;
  ULONG col1,col2,col3;
  N_ND->ConX=0;
  N_ND->ConY=11;
  N_ND->ConW=640;
  N_ND->ConH=200-11;


  sprintf(tmpstr,"%sScreen.CFG",N_ND->NodeLocation);

  if (WindowCFG=HBBS_LoadConfig(tmpstr,LCFG_NONE))
  {
    HBBS_GetSetting(WindowCFG,(void *)&N_ND->NodeX,VTYPE_BIGNUM,"NodeWnd_LeftEdge",OPT_SINGLE);
    HBBS_GetSetting(WindowCFG,(void *)&N_ND->NodeY,VTYPE_BIGNUM,"NodeWnd_TopEdge",OPT_SINGLE);

    HBBS_GetSetting(WindowCFG,(void *)&N_ND->ConX,VTYPE_BIGNUM,"ConWin_LeftEdge",OPT_SINGLE);
    HBBS_GetSetting(WindowCFG,(void *)&N_ND->ConY,VTYPE_BIGNUM,"ConWin_TopEdge",OPT_SINGLE);
    HBBS_GetSetting(WindowCFG,(void *)&N_ND->ConW,VTYPE_BIGNUM,"ConWin_Width",OPT_SINGLE);
    HBBS_GetSetting(WindowCFG,(void *)&N_ND->ConH,VTYPE_BIGNUM,"ConWin_Height",OPT_SINGLE);

    HBBS_GetSetting(WindowCFG,(void *)&N_ND->NodeSettings.ScrModeID,VTYPE_BIGNUM,OPT_NODE_ScrModeID,OPT_SINGLE);
    HBBS_GetSetting(WindowCFG,(void *)&N_ND->NodeSettings.ScrHeight,VTYPE_BIGNUM,OPT_NODE_ScrHeight,OPT_SINGLE);
    HBBS_GetSetting(WindowCFG,(void *)&N_ND->NodeSettings.ScrWidth,VTYPE_BIGNUM,OPT_NODE_ScrWidth,OPT_SINGLE);
    HBBS_GetSetting(WindowCFG,(void *)&N_ND->NodeSettings.ScrDepth,VTYPE_BIGNUM,OPT_NODE_ScrDepth,OPT_SINGLE);

    for (loop=0;loop<8;loop++)
    {
      sprintf(optionstr,"Colour_%d",loop);
      paramstr=NULL;
      if (HBBS_GetSetting(WindowCFG,(void *)&paramstr,VTYPE_STRING,optionstr,OPT_SINGLE))
      {
        if (sscanf(paramstr,"%ld %ld %ld",&col1,&col2,&col3)==3)
        {
          ScreenColors[loop].Red=(UWORD)col1;
          ScreenColors[loop].Green=(UWORD)col2;
          ScreenColors[loop].Blue=(UWORD)col3;
        }
        FreeStr(paramstr);
      }
    }

    HBBS_FlushConfig(WindowCFG);
  }

}

void SaveWindowSettings( void )
{
  struct CfgFileData *WindowCFG;
  char tmpstr[BIG_STR],optionstr[BIG_STR];
  ULONG loop;

  sprintf(tmpstr,"%sScreen.CFG",N_ND->NodeLocation);
//  sprintf(tmpstr,"HBBS:System/Data/Node%d_Private.CFG",N_NodeNum);

  if (WindowCFG=HBBS_CreateConfig(tmpstr))
  {
    sprintf(tmpstr,"%d",NodeWnd->LeftEdge);
    HBBS_AddCfgItemQuick(WindowCFG,"NodeWnd_LeftEdge",tmpstr);   // *C* make strings into variables!
    sprintf(tmpstr,"%d",NodeWnd->TopEdge);
    HBBS_AddCfgItemQuick(WindowCFG,"NodeWnd_TopEdge",tmpstr);

    sprintf(tmpstr,"%d",N_ND->ConWin->LeftEdge);
    HBBS_AddCfgItemQuick(WindowCFG,"ConWin_LeftEdge",tmpstr);
    sprintf(tmpstr,"%d",N_ND->ConWin->TopEdge);
    HBBS_AddCfgItemQuick(WindowCFG,"ConWin_TopEdge",tmpstr);
    sprintf(tmpstr,"%d",N_ND->ConWin->Width);
    HBBS_AddCfgItemQuick(WindowCFG,"ConWin_Width",tmpstr);
    sprintf(tmpstr,"%d",N_ND->ConWin->Height);
    HBBS_AddCfgItemQuick(WindowCFG,"ConWin_Height",tmpstr);

    sprintf(tmpstr,"%d",N_ND->NodeSettings.ScrModeID);
    HBBS_AddCfgItemQuick(WindowCFG,OPT_NODE_ScrModeID,tmpstr);
    sprintf(tmpstr,"%d",N_ND->NodeSettings.ScrHeight);
    HBBS_AddCfgItemQuick(WindowCFG,OPT_NODE_ScrHeight,tmpstr);
    sprintf(tmpstr,"%d",N_ND->NodeSettings.ScrWidth);
    HBBS_AddCfgItemQuick(WindowCFG,OPT_NODE_ScrWidth,tmpstr);
    sprintf(tmpstr,"%d",N_ND->NodeSettings.ScrDepth);
    HBBS_AddCfgItemQuick(WindowCFG,OPT_NODE_ScrDepth,tmpstr);

    for (loop=0;loop<8;loop++)
    {
      sprintf(tmpstr,"%ld %ld %ld",ScreenColors[loop].Red,ScreenColors[loop].Green,ScreenColors[loop].Blue);
      sprintf(optionstr,"Colour_%d",loop);
      HBBS_AddCfgItemQuick(WindowCFG,optionstr,tmpstr);
    }

    HBBS_SaveConfig(WindowCFG); // *C* add errorchecking and error message
    HBBS_FlushConfig(WindowCFG);
  }
}

void ProcessWindowSettingsWin( LONG Class, UWORD Code, APTR IAddress )
{
char tmpstr[1024],filename[1024];
struct Gadget *gad;
switch ( Class )
  {
  case IDCMP_GADGETUP :
    /* Gadget message, gadget = gad. */
    gad = (struct Gadget *)IAddress;
    switch ( gad->GadgetID )
      {
      case SettingsWin_ScreenMode :
        if (PickConScreen())
        {
          if (N_ND->NodeSettings.UseOwnScreen)
          {
            if (N_ND->ConOK) CleanupNodeConsoleWin();
            OpenNodeConsoleWin();
          }
        }
        break;
/*
      case SettingsWin_Save :
        break;
*/
      case SettingsWin_SaveWin:
        SaveWindowSettings();
        break;
      case SettingsWin_WinOrScreen :
        ChangeConsoleMode(Code); // 0 for screen or 1 for window,2 for reverse
        break;
      case SettingsWin_ModemDebug :
        N_ND->NodeDevice.ModemDebug=!N_ND->NodeDevice.ModemDebug;
        break;
      case SettingsWin_ModemLog :
        N_ND->NodeDevice.ModemLog=!N_ND->NodeDevice.ModemLog;
        break;
      case SettingsWin_AllowLogins :
        N_ND->AllowLogins=!N_ND->AllowLogins;
        break;
      case SettingsWin_NodeConfig :
        strcpy(tmpstr,BBSGlobal->EditorCMD);
        sprintf(filename,"%sNodeLocal",N_ND->NodeLocation);
        replace(tmpstr,tmpstr,"{FILE}",filename);
        HBBS_RunDOSCMD(tmpstr,TRUE);
        break;
      case SettingsWin_CallersLog:
        strcpy(tmpstr,BBSGlobal->EditorCMD);
        replace(tmpstr,tmpstr,"{FILE}",N_ND->NodeSettings.CallersLogFile);
        HBBS_RunDOSCMD(tmpstr,TRUE);
        break;
      case SettingsWin_DeviceConfig :
        strcpy(tmpstr,BBSGlobal->EditorCMD);
        sprintf(filename,"%sDevice",N_ND->NodeLocation);
        replace(tmpstr,tmpstr,"{FILE}",filename);
        HBBS_RunDOSCMD(tmpstr,TRUE);
        break;
      }
    break;
  case IDCMP_CLOSEWINDOW :
    CloseSettingsWinWindow();
    N_ND->SettingsOpen=FALSE;
    // updatesettings();
    break;
  case IDCMP_REFRESHWINDOW :
    GT_BeginRefresh( SettingsWin);
    /* Refresh window. */
  RendWindowSettingsWin( SettingsWin, SettingsWinVisualInfo );
    GT_EndRefresh( SettingsWin, TRUE);
  GT_RefreshWindow( SettingsWin, NULL);
  RefreshGList( SettingsWinGList, SettingsWin, NULL, ~0);
    break;
  }
}

void ProcessWindowNodeWnd( LONG Class, UWORD Code, APTR IAddress )
{
struct Gadget *gad;
switch ( Class )
  {
  case IDCMP_GADGETUP :
    /* Gadget message, gadget = gad. */
    gad = (struct Gadget *)IAddress;
    switch ( gad->GadgetID )
      {
      case NodeWnd_ChatFlag :
        N_ND->NodeSettings.ChatFlag= Code == 0 ? TRUE : FALSE;
        break;
      case NodeWnd_OffHook :
        /* Button pressed  , Text of gadget : OffHook */

        if (N_ND->OnlineStatus==OS_OFFLINE)
        {
          if (Code==0) // onhook...
          {
            InitModem();
          }
          if (Code==1) // off hook
          {
            OffHook();
          }
        }
        else
        {
          if (Code==0) Code = 1; else Code=0;
          // put the gadget back to what it was!
          GT_SetGadgetAttrs(NodeWndGadgets[NodeWnd_OffHook],NodeWnd,NULL,GTCY_Active,Code,TAG_DONE);
        }
        break;
      case NodeWnd_InitModem :
        /* Button pressed  , Text of gadget : Init Modem */

        // only do it if no one's online..

        if (N_ND->OnlineStatus==OS_OFFLINE) InitModem();
        break;
      case NodeWnd_Reserve :
        break;
      case NodeWnd_Screen :
        if (N_ND->ConOK)
        {
          CleanupNodeConsoleWin();
        }
        else
        {
          WatchScreenToFront();
        }
        break;
      case NodeWnd_ChatNow :
        /* Button pressed  , Text of gadget : Chat Now */

        if (N_ND->OnlineStatus==OS_ONLINE)
        {
          // open watch window if closed and/or bring it to the front.

          WatchScreenToFront();

          if (N_ND->ConOK) // check again as if we had to open the watch window it might not have actually opened...
          {
            if ((N_ND->ActiveDoor==NULL) || (N_ND->ActiveDoor) && (iposition("SYSOPCHAT",N_ND->ActiveDoor->node.ln_Name)<0))
            {
              // only start the door if it's not already started..

              GoSystemDoor("SYSOPCHAT",NULL);
            }
          }
        }
        else DisplayBeep(scr); // Doh! Can't chat to user if no-one's logged on m8! :-)

        break;
      case NodeWnd_Settings :
        /* Button pressed  , Text of gadget : Settings */
        if (N_ND->SettingsOpen==FALSE)
        {
          if (OpenSettingsWinWindow(scr)==0) // success!
          {
            N_ND->SettingsOpen=TRUE;
            UpdateSettingsWindow();
          }
        }
        else
        {
          WindowToFront(SettingsWin);
        }
        break;
      case NodeWnd_Information :
        /* Button pressed  , Text of gadget : Information */
        if (N_ND->InformationOpen==FALSE)
        {
          if (OpenInfoWinWindow(scr)==0) // success!
          {
            N_ND->InformationOpen=TRUE;
            UpdateInfoWin();
          }
        }
        break;
      }
    break;
  case IDCMP_CLOSEWINDOW :
    /* CloseWindow Now */
    if (N_ND->NodeSettings.Iconified==FALSE)
    {
      CloseNodeWin();
// *R* moved to clodenodewin();
//      N_ND->NodeX=N_ND->NodeWnd->LeftEdge;
//      N_ND->NodeY=N_ND->NodeWnd->TopEdge;
    }
    break;
  case IDCMP_REFRESHWINDOW :
    GT_BeginRefresh( NodeWnd);
    /* Refresh window. */
  RendWindowNodeWnd( NodeWnd, NodeWndVisualInfo );
    GT_EndRefresh( NodeWnd, TRUE);
  GT_RefreshWindow( NodeWnd, NULL);
  RefreshGList( NodeWndGList, NodeWnd, NULL, ~0);
    break;
  case IDCMP_VANILLAKEY :
    /* Processed key press */
    /* gadgets need processing perhaps. */
    break;
  }
}

void ProcessConWindow( LONG Class, UWORD Code, APTR IAddress )
{
//  struct Gadget *gad;

  switch ( Class )
  {
    case IDCMP_CLOSEWINDOW :
      /* CloseWindow Now */

      // get thesetings for the window position now so that it will open in the same place
      CleanupNodeConsoleWin();
      break;
    case IDCMP_REFRESHWINDOW :
      GT_BeginRefresh( NodeWnd);
      /* Refresh window. */
      RendWindowNodeWnd( NodeWnd, NodeWndVisualInfo );
      GT_EndRefresh( NodeWnd, TRUE);
      GT_RefreshWindow( NodeWnd, NULL);
      RefreshGList( NodeWndGList, NodeWnd, NULL, ~0);
      break;
  }
}

void SendStatus(V_BIGNUM status)
{
  struct StatusMsg *SMsg;

  if (SMsg=(struct StatusMsg *)AllocVec(sizeof(struct StatusMsg),MEMF_PUBLIC))
  {
    SMsg->message.mn_Node.ln_Type = NT_MESSAGE;
    SMsg->message.mn_ReplyPort=NULL;//N_ND->ReplyPort;
    SMsg->message.mn_Length=sizeof(struct StatusMsg);
    SMsg->MsgType=mtype_STATUS;
    SMsg->NodeNum=N_ND->NodeNum;
    SMsg->Status=status;
    SendMessage((struct Message*)SMsg,CtrlMainPortName);
  }
}

void SendRequest(V_BIGNUM requesttype)
{
  struct RequestMsg *RMsg;

  if (RMsg=(struct RequestMsg *)AllocVec(sizeof(struct RequestMsg),MEMF_PUBLIC))
  {
    RMsg->message.mn_Node.ln_Type = NT_MESSAGE;
    RMsg->message.mn_ReplyPort=NULL;//N_ND->ReplyPort;
    RMsg->message.mn_Length=sizeof(struct RequestMsg);
    RMsg->MsgType=mtype_REQUEST;
    RMsg->NodeNum=N_ND->NodeNum;
    RMsg->Flags=requesttype;
    SendMessage((struct Message*)RMsg,CtrlMainPortName);
  }
}


void ClearDeviceData(struct DeviceData *DD)
{
  // small subroutine to set all the default values
  // never call if you've allocated mem for strings!
  DD->DeviceName=NULL;
  DD->SerialDevice=NULL;
  DD->SerialUnit=0;
  DD->SerialBaud=0;
  DD->NullModemCable=FALSE;
  DD->ModemDebug=FALSE;
  DD->ModemLog=FALSE;
  DD->EchoRetries=0;
  DD->ReOpenRetries=0;
  DD->ReOpenDelay=0;
  DD->LockUpScript=NULL;
  DD->MaxCommandWait=0;
  DD->CommandRetries=0;
  DD->DelayBetweenCmds=0;
  DD->TildeDelay=0;
  DD->TurnOnEcho=NULL;
  DD->TurnOnEchoDelay=0;
  DD->ModemInit=NULL;
  DD->StrictConnect=FALSE;
  DD->StrictConnectStr=NULL;
  DD->RelaxedConnectStr=NULL;
  DD->CommandModeString=NULL;
  DD->DropDTRHangup=FALSE;
  DD->HangUpString=NULL;
  DD->OffHookString=NULL;
  DD->Incoming=NULL;
  DD->ImmediateAnswer=NULL;
}

void SetDeviceDataDefaults(struct DeviceData *DD)
{
  // small subroutine to set all the default values

  DD->EchoRetries=4;
  DD->ReOpenRetries=2;
  DD->ReOpenDelay=25;
  DD->MaxCommandWait=10;
  DD->CommandRetries=3;
  DD->DelayBetweenCmds=1;
  DD->TildeDelay=22;
  DD->TurnOnEchoDelay=20;
  DD->DropDTRHangup=TRUE;
}

void FreeDeviceData(struct DeviceData *DD)
{
  FreeStr(DD->DeviceName);
  FreeStr(DD->SerialDevice);
  FreeStr(DD->LockUpScript);
  FreeStr(DD->HangUpString);
  FreeStr(DD->OffHookString);
  FreeStr(DD->Incoming);
  FreeStr(DD->ImmediateAnswer);
  FreeStrList(DD->TurnOnEcho);
  FreeStrList(DD->ModemInit);
  FreeStrList(DD->StrictConnectStr);
  FreeStrList(DD->CommandModeString);
  FreeStrList(DD->RelaxedConnectStr);
}

V_ERROR LoadDeviceData(ULONG NodeNum,struct DeviceData *DD )
{
  struct CfgFileData *DeviceCFG;
  V_ERROR error=TYPE_NONE;
  UBYTE *filename=NULL;
  struct NodeData *ND;

  if (ND=HBBS_NodeDataPtr(NodeNum))
  {
    if (filename=AllocVec(strlen(ND->NodeLocation)+strlen(FILENAME_DEVICE)+1,MEMF_PUBLIC))
    {
      strcpy(filename,ND->NodeLocation);
      strcat(filename,FILENAME_DEVICE);
    }
  }

  if (filename)
  {
    if (DeviceCFG=HBBS_LoadConfig(filename,LCFG_NONE))
    {
      // get settings!
      HBBS_GetSetting(DeviceCFG,(void *)&DD->DeviceName       ,VTYPE_STRING,OPT_DEVICE_DeviceName       ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->SerialDevice     ,VTYPE_STRING,OPT_DEVICE_SerialDevice     ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->SerialUnit       ,VTYPE_BIGNUM,OPT_DEVICE_SerialUnit       ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->SerialBaud       ,VTYPE_BIGNUM,OPT_DEVICE_SerialBaud       ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->NullModemCable   ,VTYPE_BOOL,OPT_DEVICE_NullModemCable     ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->ModemDebug       ,VTYPE_BOOL,OPT_DEVICE_ModemDebug         ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->ModemLog         ,VTYPE_BOOL,OPT_DEVICE_ModemLog           ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->EchoRetries      ,VTYPE_SMALLNUM,OPT_DEVICE_EchoRetries    ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->ReOpenRetries    ,VTYPE_SMALLNUM,OPT_DEVICE_ReOpenRetries  ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->ReOpenDelay      ,VTYPE_TIME,OPT_DEVICE_ReOpenDelay        ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->LockUpScript     ,VTYPE_STRING,OPT_DEVICE_LockUpScript     ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->MaxCommandWait   ,VTYPE_TIME,OPT_DEVICE_MaxCommandWait     ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->CommandRetries   ,VTYPE_SMALLNUM,OPT_DEVICE_CommandRetries ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->DelayBetweenCmds ,VTYPE_TIME,OPT_DEVICE_DelayBetweenCmds   ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->TildeDelay       ,VTYPE_TIME,OPT_DEVICE_TildeDelay         ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->TurnOnEcho       ,VTYPE_STRINGLIST,OPT_DEVICE_TurnOnEcho   ,OPT_MULTI);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->TurnOnEchoDelay  ,VTYPE_BIGNUM,OPT_DEVICE_TurnOnEcho       ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->ModemInit        ,VTYPE_STRINGLIST,OPT_DEVICE_ModemInit    ,OPT_MULTI);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->StrictConnect    ,VTYPE_BOOL,OPT_DEVICE_StrictConnect      ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->StrictConnectStr ,VTYPE_STRINGLIST,OPT_DEVICE_StrictConnectStr ,OPT_MULTI);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->RelaxedConnectStr,VTYPE_STRINGLIST,OPT_DEVICE_RelaxedConnectStr,OPT_MULTI);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->DropDTRHangup    ,VTYPE_BOOL,OPT_DEVICE_DropDTRHangup      ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->CommandModeString,VTYPE_STRINGLIST,OPT_DEVICE_CommandModeString,OPT_MULTI);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->HangUpString     ,VTYPE_STRING,OPT_DEVICE_HangUpString     ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->OffHookString    ,VTYPE_STRING,OPT_DEVICE_OffHookString    ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->Incoming         ,VTYPE_STRING,OPT_DEVICE_Incoming         ,OPT_SINGLE);
      HBBS_GetSetting(DeviceCFG,(void *)&DD->ImmediateAnswer  ,VTYPE_STRING,OPT_DEVICE_ImmediateAnswer  ,OPT_SINGLE);

      HBBS_FlushConfig(DeviceCFG);
      DD->SysopNode=FALSE;
    }
    else
    {
      DD->SysopNode=TRUE;
    }
    FreeVec(filename);
  }
  return(error);
}


static VOID cleanup(ULONG num)
{
  if (HBBSNodeBase)
  {
    HBBS_CleanUpNode();
    CloseLibrary (HBBSNodeBase);
  }

  if (HBBSCommonBase)
  {
    HBBS_CleanUpCommon();
    CloseLibrary (HBBSCommonBase);
  }

  if (N_ReplyPort)
    DeleteMsgPort(N_ReplyPort);

  if (num)
  {
    HBBS_DoErrorMessage(num,N_NodeNum,NULL);
  }

  if (ReqToolsBase)
    CloseLibrary ((struct Library *)ReqToolsBase);

  exit(0);
}

static VOID init(VOID)
{
  if (!(ReqToolsBase = (struct ReqToolsBase *) OpenLibrary (REQTOOLSNAME, REQTOOLSVERSION)))
  {
    cleanup(EMSG_NOREQTOOLS);
  }

  if (!(N_ReplyPort=CreateMsgPort()))
  {
    cleanup(EMSG_NOMEM);
  }

  if(!(HBBSCommonBase = OpenLibrary("HBBSCommon.library",0)))
  {
    cleanup(EMSG_NOCOMMON);
  }

  if (!(HBBS_InitCommon()))
  {
    cleanup(EMSG_COMMONERR);
  }

  if(!(HBBSNodeBase = OpenLibrary("HBBSNode.library",0)))
  {
    cleanup(EMSG_NONODE);
  }

  if (!(HBBS_InitNode(N_NodeNum)))
  {
    cleanup(EMSG_NODEERR);
  }
}

/*
V_ERROR GetBBSGlobal(void)
{
  struct AskMsg *AMsg,*Reply;
  V_ERROR error=TYPE_CRITICAL;

  if (AMsg=(struct AskMsg *)AllocVec(sizeof(struct AskMsg),MEMF_PUBLIC))
  {
    // create the message
    AMsg->message.mn_Node.ln_Type = NT_MESSAGE;
    AMsg->message.mn_ReplyPort=N_ReplyPort;
    AMsg->message.mn_Length=sizeof(struct AskMsg);
    AMsg->MsgType=mtype_ASK; // so CONTROL knows what type of message structe to typecast to..
    AMsg->NodeNum=N_NodeNum; // can't use N_ND->NodeNum yet.. as we don't know N_ND
    AMsg->Flags=ASK_BBSGLOBAL;

    // now send it to ctrlmain, note we can't use N_ND->ReplyPort as we don't know N_ND yet!!

    if (SafePutToPort((struct Message *)AMsg,CtrlMainPortName))
    {
      if (1L << N_ReplyPort->mp_SigBit==Wait(1L << N_ReplyPort->mp_SigBit))
      {
        Reply=(struct AskMsg*)GetMsg(N_ReplyPort);
        if (Reply)
        {
          BBSGlobal=(struct BBSGlobalData *)Reply->Pointer;
          error=TYPE_NONE;
        }
      }
    }
    FreeVec(AMsg);
  }
  return(error);
}
*/
V_BOOL InitNode(void)
{
  int loop;
  struct Node *node;
  V_BOOL error=FALSE;

  // *C* add error messages and return codes here ?
  if (CreateNodePorts())
  {
    // ports must be created before sendstatus will work..
    SendStatus(STAT_INITIALIZING);

    if (N_ND->BBSCols=(struct BBSColsData*)AllocVec(sizeof(struct BBSColsData),MEMF_CLEAR|MEMF_PUBLIC))
    {
      if (N_ND->OLMList=HBBS_CreateList())
      {
        N_ND->OLMCount=0;
        if (N_ND->Last_Callers=HBBS_CreateList())
        {
          if (N_ND->Last_Uploads=HBBS_CreateList())
          {
            if (N_ND->Last_Downloads=HBBS_CreateList())
            {
              if (N_ND->Last_PWFails=HBBS_CreateList())
              {
                if (N_ND->Last_Carrier=HBBS_CreateList())
                {
                  if (N_ND->Last_Pagers=HBBS_CreateList())
                  {
                    if (N_ND->User.ConfAcs.See=HBBS_CreateList())
                    {
                      for (loop=0;(!error) && (loop<BBSGlobal->Conferences);loop++)
                      {
                        if (node=AllocVec(sizeof(struct BoolNode),MEMF_CLEAR|MEMF_PUBLIC))
                        {
                          AddTail(N_ND->User.ConfAcs.See,node);
                        }
                        else error=TRUE;
                      }
                      if (!error)
                      {
                        if (N_ND->User.ConfAcs.Access=HBBS_CreateList())
                        {
                          for (loop=0;(!error) && (loop<BBSGlobal->Conferences);loop++)
                          {
                            if (node=AllocVec(sizeof(struct BoolNode),MEMF_CLEAR|MEMF_PUBLIC))
                            {
                              AddTail(N_ND->User.ConfAcs.Access,node);
                            }
                            else error=TRUE;
                          }
                          if (!error)
                          {

                            ClearNodeData(&N_ND->NodeSettings);
                            ClearDeviceData(&N_ND->NodeDevice);
                            SetDeviceDataDefaults(&N_ND->NodeDevice);
                            CopyNodeSettings(&N_ND->NodeSettings,&BBSGlobal->NodeGlobalData->NodeSettings);
                            N_ND->NodeFlags=NFLG_NONE;
                            if (LoadNodeSettingsData(N_NodeNum,&N_ND->NodeSettings)==TYPE_NONE)
                            {
                              HBBS_SetBBSCols();
                              if (N_ND->NodeTimer=InitTimer())
                              {
                                if (N_ND->NodeSettings.UseDevice)
                                {
                                  if (LoadDeviceData(N_NodeNum,&N_ND->NodeDevice)==TYPE_NONE)
                                  {
                                    if (OpenSerial())
                                    {
                                      SendStatus(STAT_READY);
                                      return(TRUE);
                                    }
                                  } else HBBS_DoErrorMessage(EMSG_DEVICEFILEERR,N_ND->NodeNum,NULL);
                                }
                                else
                                {
                                  return(TRUE);
                                }
                              } else HBBS_DoErrorMessage(EMSG_NOTIMER,N_ND->NodeNum,NULL);
                            } else HBBS_LogError(FILE_ERRORLOG,ERR_NODESETTINGS,NULL,TYPE_FATAL); // *C* add error message too ?
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    SendStatus(STAT_CLOSED);
  }
  return(FALSE);
}

void FreeNode( void )
{
  SendStatus(STAT_CLOSING);
  if (N_ND->NodeTimer) CleanupTimer(N_ND->NodeTimer);
  FreeStrList(N_ND->Last_Callers);
  FreeStrList(N_ND->Last_Uploads);
  FreeStrList(N_ND->Last_Downloads);
  FreeStrList(N_ND->Last_Pagers);
  FreeStrList(N_ND->Last_PWFails);
  FreeStrList(N_ND->Last_Carrier);
  FreeStrList(N_ND->OLMList);
  N_ND->OLMList=NULL; //must be done!!

  FreeStrList(N_ND->User.ConfAcs.See);
  FreeStrList(N_ND->User.ConfAcs.Access);
  FreeStr(N_ND->User.ConfAcs.Name);

  if (N_ND->BBSCols)
  {
    FreeVec(N_ND->BBSCols->MenuTextANSI);
    FreeVec(N_ND->BBSCols->MenuOpenBracket);
    FreeVec(N_ND->BBSCols->MenuCloseBracket);
    FreeVec(N_ND->BBSCols->MenuHighlightANSI);
    FreeVec(N_ND->BBSCols->MenuDefaultOptANSI);
    FreeVec(N_ND->BBSCols->MenuPromptANSI);
    FreeVec(N_ND->BBSCols);
  }
  FreeDeviceData(&N_ND->NodeDevice);
  FreeNodeSettingsData(&N_ND->NodeSettings);
  SendStatus(STAT_CLOSED);
  // must be done last cos status won't work otherwise..
  CloseNodePorts();
  HBBS_ResetNodeData(N_ND);
}

/*
void HandleAsk(struct AskMsg *AMsg)
{
  switch(AMsg->Flags)
  {
    case ASK_STATUS:
      AMsg->Value=N_ND->Status;
      break;
  }
  ReplyMsg((struct Message *)AMsg);
}
*/

// returns 1 if quit..
void HandleStatus(struct StatusMsg *SMsg)
{
  switch(SMsg->Status)
  {
    case STAT_REQUESTCLOSE:
      // node must NOT be doing anything if we want to shut it down
      if (N_ND->Status==STAT_READY) N_ND->RequestShutdown=TRUE;
      break;

    case STAT_OPENWINDOW:
      if (N_ND->NodeSettings.Iconified==TRUE)
      {
        OpenNodeWin(scr);
      }
      break;
    case STAT_CLOSEWINDOW:
      // *C* change to abort con if window closed pressed as we can't actually
      // care about the console coming in if we're closing the window!
      // ah, but what if a door does care ??? Umm.. fuck it.. who cares it's staying
      if (N_ND->NodeSettings.Iconified==FALSE && N_ND->ConWaiting==FALSE)
      {
        CloseNodeWin();
      }
      break;
    case STAT_OPENSCREEN:
      WatchScreenToFront();
      break;
    case STAT_CLOSESCREEN:
      if (N_ND->ConOK==TRUE)
      {
        CleanupNodeConsoleWin();
      }
      break;
  }

  // a status message MAY be sent to the node without the control or other program wanting to be told
  // that the NODE has recived the message, all messages sent that DONT want a reply WILL be freed..

  if (SMsg->message.mn_ReplyPort)
  {
    ReplyMsg((struct Message *)SMsg);
  }
  else
  {
    FreeVec(SMsg);
  }
}

void HandleDoorActivityMsg(struct DoorActivityMsg *DMsg)
{
  switch(DMsg->Status)
  {
    case DMSG_DOORSTARTED:
//      printf("Door Started! (%s)\n",N_ND->ActiveDoor->node.ln_Name);
      break;
    case DMSG_DOORFINISHED:
//      printf("Door Finished!\n");
      break;
  }
  // a door message MAY be sent to the node without the control or other program wanting to be told
  // that the NODE has recived the message, all messages sent that DONT want a reply WILL be freed..

  if (DMsg->message.mn_ReplyPort)
  {
    ReplyMsg((struct Message *)DMsg);
  }
  else
  {
    FreeVec(DMsg);
  }
}

void HandleCheckMsg(struct NodeMsg *NMsg)  // *R* needed ?
{
  if (NMsg->message.mn_ReplyPort)
  {
    ReplyMsg((struct Message *)NMsg);
  }
  else
  {
    FreeVec(NMsg);
  }
}

void HandleMsg( void )
{
  struct NodeMsg *NMsg;


  while (NMsg=(struct NodeMsg*)GetMsg(N_ND->NodePort))
  {
    if ( (NMsg->MsgType==mtype_DOORIO) && ( ((struct DoorIOMsg *)NMsg)->Status==DOORIO_WRITESTR ) )
    {
      if (((struct DoorIOMsg *)NMsg)->Data)
      {
        if (N_ND->ConOK)
        {
          N_ND->ConWrite->io_Command  = CMD_WRITE;
          N_ND->ConWrite->io_Data     = ((struct DoorIOMsg *)NMsg)->Data;
          N_ND->ConWrite->io_Length   = -1;
          DoIO((struct IORequest *)N_ND->ConWrite);
        }
        if ((N_ND->LoginType==LOGIN_REMOTE) && (!(N_ND->NodeFlags & NFLG_BLOCKSERIAL)))
        {
          AbortSerRead();
          N_ND->SerWrite->IOSer.io_Command  = CMD_WRITE;
          N_ND->SerWrite->IOSer.io_Data     = ((struct DoorIOMsg *)NMsg)->Data;
          N_ND->SerWrite->IOSer.io_Length   = -1;
          DoIO((struct IORequest *)N_ND->SerWrite);
        }
      }
      ReplyMsg((struct Message *)NMsg);
    }
    else
    {
      switch(NMsg->MsgType)
      {
//        case mtype_ASK:
//          HandleAsk((struct AskMsg *)NMsg);
//          break;
        case mtype_STATUS:
          HandleStatus((struct StatusMsg *)NMsg);
          break;
        case mtype_DOORACTIVITY:
          HandleDoorActivityMsg((struct DoorActivityMsg *)NMsg);
          break;
        case mtype_DOORIO:
          HandleDoorIOMsg((struct DoorIOMsg *)NMsg);
          break;
        case mtype_CHECK:   // all we want to do is get the node to check some stuff
          HandleCheckMsg(NMsg); // depending on what it's doing...
          break;
      }
    }
    // we might get a message that does not want a reply.. (like a request shutdown message..)
  }
}

// copied and modified from NodeGUI.c as the version in there does NOT free the fonts!!!!

int OpenTheDiskFonts( void )
{
  int OKSoFar = 1; // reveresed numbers
  if ((HBBSFont = OpenDiskFont( &HBBS8066 ))==NULL )
  OKSoFar = 0;
return ( OKSoFar );
}

void NodeMain(void)
{
  if (OpenLibs()==0)
  {
    if (OpenTheDiskFonts())
    {
      if (scr=LockPubScreen(BBSGlobal->ScreenInfo.PubScreenName))
      {
        if (InitNode())
        {
          HBBS_LoadCallsData();
          LoadWindowSettings();
          if (N_ND->NodeSettings.Iconified==FALSE) OpenNodeWin(scr);
          if (N_ND->NodeSettings.StartScreen) OpenNodeConsoleWin();

          AwaitConnect();
          if (N_ND->NodeSettings.Iconified==FALSE) CloseNodeWin();
          if (N_ND->SettingsOpen) CloseSettingsWinWindow();
          if (N_ND->InformationOpen) CloseInfoWinWindow();
          if (N_ND->ConOK) CleanupNodeConsoleWin();
          if (N_ND->SerOK) CleanupSerial();
        }
        FreeNode();
        UnlockPubScreen(NULL, scr);
      } else HBBS_DoErrorMessage(EMSG_NOSCREEN,0,NULL);
      CloseFont( HBBSFont ) ;
    }
    else  HBBS_DoErrorMessage(EMSG_NOFONT,0,NULL);
    CloseLibs();
  } else HBBS_DoErrorMessage(EMSG_NOLIBS,0,NULL);
}

int main(int argc,char *argv[])
{
  struct MsgPort *tmpport;
  char tmpstr[20];

  if ((argc!=2) || (sscanf(argv[1],"%d",&N_NodeNum)==0))
  {
    printf("Invalid/No Paramaters for node!\n");
    exit (20);
  }
  sprintf(tmpstr,"HBBS_Node %d",N_NodeNum);
  SetProgramName(tmpstr);
  init();
  if (BBSGlobal=HBBS_GimmeBBS())
  {
    rttags[7]=(ULONG)BBSGlobal->ScreenInfo.PubScreenName;
    if (N_NodeNum >= BBSGlobal->BBSNodes)
    {
      HBBS_DoErrorMessage(EMSG_NODEINVALID,N_NodeNum,NULL);
    }
    else
    {
      if (N_ND=HBBS_NodeDataPtr(N_NodeNum)) // this should not fail in normal circumstances..
      {
        Forbid();
        tmpport=FindPort(N_ND->PortName);
        Permit();
        if (tmpport)
        {
          HBBS_DoErrorMessage(EMSG_NODEALREADYUP,N_NodeNum,NULL);
        }
        else
        {
          // actually already set by control..
          //N_ND->NodeNum=N_NodeNum; // set the node number (as gained from command line parms)
          NodeMain();
        }
      }
    }
  } else HBBS_DoErrorMessage(EMSG_NOCTRL,0,NULL);
  cleanup(0);
}
