Skip to content
Snippets Groups Projects
MainFormUnit.cpp 128.89 KiB
/* Synchronet Control Panel (GUI Borland C++ Builder Project for Win32) */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright Rob Swindell - http://www.synchro.net/copyright.html			*
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

//---------------------------------------------------------------------------
#include "sbbs.h"           // unixtodstr()
#include <vcl.h>
#include <vcl/Registry.hpp>	/* TRegistry */
#pragma hdrstop
#include <winsock.h>		// IPPORT_TELNET, INADDR_ANY
#include <process.h> 		// _beginthread()
#include <io.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/locking.h>
#include <fcntl.h>
#include <share.h>

#include "MainFormUnit.h"
#include "TelnetFormUnit.h"
#include "EventsFormUnit.h"
#include "ServicesFormUnit.h"
#include "FtpFormUnit.h"
#include "WebFormUnit.h"
#include "MailFormUnit.h"
#include "NodeFormUnit.h"

#include "StatsFormUnit.h"
#include "ClientFormUnit.h"
#include "CtrlPathDialogUnit.h"
#include "TelnetCfgDlgUnit.h"
#include "MailCfgDlgUnit.h"
#include "FtpCfgDlgUnit.h"
#include "WebCfgDlgUnit.h"
#include "ServicesCfgDlgUnit.h"
#include "AboutBoxFormUnit.h"
#include "CodeInputFormUnit.h"
#include "TextFileEditUnit.h"
#include "UserListFormUnit.h"
#include "PropertiesDlgUnit.h"
#include "ConfigWizardUnit.h"
#include "PreviewFormUnit.h"
#include "LoginAttemptsFormUnit.h"

#include "sbbs_ini.h"		// sbbs_read_ini()
#include "userdat.h"		// lastuser()
#include "ntsvcs.h"			// NTSVC_NAME_*

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "trayicon"
#pragma link "Trayicon"
#pragma resource "*.dfm"
TMainForm *MainForm;

#define LOG_TIME_FMT "  m/d  hh:mm:ssa/p"
#define STATUSBAR_LAST_PANEL  6

/* Service functions are NT-only, must call dynamically :-( */
typedef WINADVAPI SC_HANDLE (WINAPI *OpenSCManager_t)(LPCTSTR,LPCTSTR,DWORD);
typedef WINADVAPI SC_HANDLE (WINAPI *OpenService_t)(SC_HANDLE,LPCTSTR,DWORD);
typedef WINADVAPI BOOL (WINAPI *StartService_t)(SC_HANDLE,DWORD,LPCTSTR*);
typedef WINADVAPI BOOL (WINAPI *ControlService_t)(SC_HANDLE,DWORD,LPSERVICE_STATUS);
typedef WINADVAPI BOOL (WINAPI *QueryServiceStatus_t)(SC_HANDLE,LPSERVICE_STATUS);
typedef WINADVAPI BOOL (WINAPI *QueryServiceConfig_t)(SC_HANDLE,LPQUERY_SERVICE_CONFIG,DWORD,LPDWORD);
typedef WINADVAPI BOOL (WINAPI *CloseServiceHandle_t)(SC_HANDLE);

OpenSCManager_t 		openSCManager;
OpenService_t 			openService;
StartService_t  		startService;
ControlService_t    	controlService;
QueryServiceStatus_t    queryServiceStatus;
QueryServiceConfig_t    queryServiceConfig;
CloseServiceHandle_t	closeServiceHandle;

SC_HANDLE       hSCManager;
SC_HANDLE	    bbs_svc;
SC_HANDLE	    ftp_svc;
SC_HANDLE	    web_svc;
SC_HANDLE	    mail_svc;
SC_HANDLE	    services_svc;
SERVICE_STATUS	bbs_svc_status;
SERVICE_STATUS	ftp_svc_status;
SERVICE_STATUS	web_svc_status;
SERVICE_STATUS	mail_svc_status;
SERVICE_STATUS	services_svc_status;
QUERY_SERVICE_CONFIG*	bbs_svc_config;
DWORD					bbs_svc_config_size;
QUERY_SERVICE_CONFIG*	ftp_svc_config;
DWORD					ftp_svc_config_size;
QUERY_SERVICE_CONFIG*	web_svc_config;
DWORD					web_svc_config_size;
QUERY_SERVICE_CONFIG*	mail_svc_config;
DWORD					mail_svc_config_size;
QUERY_SERVICE_CONFIG*	services_svc_config;
DWORD					services_svc_config_size;

const char* LogLevelDesc[] = {   "Emergency"
                                ,"Alert"
                                ,"Critical"
                                ,"Error"
                                ,"Warning"
                                ,"Notice"
                                ,"Normal"
                                ,"Debug"
                            };
const TColor LogLevelColor[] = {
                                 clRed
                                ,clRed
                                ,clRed
                                ,clRed
                                ,clFuchsia	
                                ,clSkyBlue
                                ,clBlack    /* not used */
                                ,clLime
                                };

link_list_t bbs_log_list;
link_list_t event_log_list;
link_list_t mail_log_list;
link_list_t ftp_log_list;
link_list_t web_log_list;
link_list_t services_log_list;
link_list_t	login_attempt_list;

bool clearLoginAttemptList = false;

DWORD	MaxLogLen=20000;
int     threads=1;
time_t  initialized=0;
static	str_list_t recycle_semfiles;
static  str_list_t shutdown_semfiles;
bool    terminating=false;
ulong   errors;
AnsiString ErrorSoundFile;

static void errormsg(void* p, int level, const char* msg)
{
    errors++;

    if(MainForm->SoundToggle->Checked)
        PlaySound(ErrorSoundFile.c_str(), NULL, SND_ASYNC|SND_FILENAME);
}

static void thread_up(void* p, BOOL up, BOOL setuid)
{
	char str[128];
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);
    if(up)
	    threads++;
    else if(threads>0)
    	threads--;
    ReleaseMutex(mutex);
}

int sockets=0;

void socket_open(void* p, BOOL open)
{
	char 	str[128];
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);
    if(open)
	    sockets++;
    else if(sockets>0)
    	sockets--;
    ReleaseMutex(mutex);
}

int clients=0;
int total_clients=0;

static void client_add(void* p, BOOL add)
{
	char 	str[128];

    if(add) {
	    clients++;
        total_clients++;
    } else if(clients>0)
    	clients--;
}

static void client_on(void* p, BOOL on, int sock, client_t* client, BOOL update)
{
    char    str[128];
    int     i,j;
    time_t  t;
	static  HANDLE mutex;
    TListItem*  Item;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);
    WaitForSingleObject(ClientForm->ListMutex,INFINITE);

    /* Search for exising entry for this socket */
    for(i=0;i<ClientForm->ListView->Items->Count;i++) {
        if(ClientForm->ListView->Items->Item[i]->Caption.ToIntDef(0)==sock)
            break;
    }
    if(i>=ClientForm->ListView->Items->Count) {
		if(update)	{ /* Can't update a non-existing entry */
			ReleaseMutex(mutex);
			ReleaseMutex(ClientForm->ListMutex);
			return;
		}
        i=-1;
	}

    if(on) {
	    if(!update)
	        client_add(NULL, TRUE);
    } else { // Off
        client_add(NULL, FALSE);
        if(i>=0)
            ClientForm->ListView->Items->Delete(i);
        ReleaseMutex(mutex);
        ReleaseMutex(ClientForm->ListMutex);
        return;
    }
    if(client!=NULL && client->size==sizeof(client_t)) {
        t=time(NULL);
        if(i>=0) {
            Item=ClientForm->ListView->Items->Item[i];
        } else {
            Item=ClientForm->ListView->Items->Add();
            Item->Data=(void*)t;
            Item->Caption=sock;
        }
        Item->SubItems->Clear();
        Item->SubItems->Add(client->protocol);
        Item->SubItems->Add(client->user);
        Item->SubItems->Add(client->addr);
        Item->SubItems->Add(client->host);
        Item->SubItems->Add(client->port);
        t-=(time_t)Item->Data;
        sprintf(str,"%d:%02d",t/60,t%60);
        Item->SubItems->Add(str);
    }
    ReleaseMutex(mutex);
    ReleaseMutex(ClientForm->ListMutex);
}

static int lputs(void* p, int level, const char *str)
{
    log_msg_t   msg;
	link_list_t* list = (link_list_t*)p;
	log_msg_t*	last;

	msg.repeated = 0;
    msg.level = level;
    GetLocalTime(&msg.time);
    SAFECOPY(msg.buf, str);
	listLock(list);
	BOOL unique = TRUE;
	if(list->last != NULL) {
		last = (log_msg_t*)list->last->data;
		if(strcmp(last->buf, msg.buf) == 0) {
			last->repeated++;
			unique = FALSE;
		}
	}
	if(unique)
		listPushNodeData(list, &msg, sizeof(msg));
	listUnlock(list);
    return strlen(msg.buf);
}

static void log_msg(TRichEdit* Log, log_msg_t* msg)
{
    AnsiString Line=SystemTimeToDateTime(msg->time).FormatString(LOG_TIME_FMT)+"  ";
    Line+=AnsiString(msg->buf).Trim();
	if(msg->repeated)
		Line += " [x" + AnsiString(msg->repeated + 1) + "]";
    Log->SelLength=0;
	Log->SelStart=-1;
    Log->SelAttributes->Assign(
        MainForm->LogAttributes(msg->level, Log->Color, Log->Font));
	Log->Lines->Add(Line);
}

static void logged_msgs(TRichEdit* Log)
{
    while(MaxLogLen && Log->Lines->Count >= MaxLogLen)
        Log->Lines->Delete(0);
	SendMessage(Log->Handle, WM_VSCROLL, SB_BOTTOM, NULL);
}

static void bbs_log_msg(log_msg_t* msg)
{
	log_msg(TelnetForm->Log, msg);
}

static void bbs_status(void* p, const char *str)
{
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

	TelnetForm->Status->Caption=AnsiString(str);

    ReleaseMutex(mutex);
}

static void bbs_clients(void* p, int clients)
{
	static HANDLE mutex;
    static save_clients;

    save_clients=clients;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

    TelnetForm->ProgressBar->Max
    	=(MainForm->bbs_startup.last_node
	    -MainForm->bbs_startup.first_node)+1;
	TelnetForm->ProgressBar->Position=clients;

    ReleaseMutex(mutex);
}
static void bbs_terminated(void* p, int code)
{
	Screen->Cursor=crDefault;
	MainForm->TelnetStart->Enabled=true;
	MainForm->TelnetStop->Enabled=false;
	MainForm->TelnetRecycle->Enabled=false;
    MainForm->TelnetPause->Enabled=false;
    MainForm->TelnetPause->Checked=false;    
    Application->ProcessMessages();
}
static void bbs_started(void* p)
{
	Screen->Cursor=crDefault;
	MainForm->TelnetStart->Enabled=false;
    MainForm->TelnetStop->Enabled=true;
    MainForm->TelnetRecycle->Enabled=true;
    MainForm->TelnetPause->Enabled=true;
    MainForm->TelnetPause->Checked=false;        
    Application->ProcessMessages();
}
static void bbs_start(void)
{
	Screen->Cursor=crAppStart;
    bbs_status(NULL,"Starting");

    FILE* fp=fopen(MainForm->ini_file,"r");
    sbbs_read_ini(fp, MainForm->ini_file
        ,&MainForm->global
        ,NULL   ,&MainForm->bbs_startup
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,NULL
        );
    if(fp!=NULL)
        fclose(fp);

	_beginthread((void(*)(void*))bbs_thread,0,&MainForm->bbs_startup);
    Application->ProcessMessages();
}

static void event_log_msg(log_msg_t* msg)
{
	log_msg(EventsForm->Log, msg);
}

static void services_log_msg(log_msg_t* msg)
{
	log_msg(ServicesForm->Log, msg);
}

static void services_status(void* p, const char *str)
{
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

	ServicesForm->Status->Caption=AnsiString(str);

    ReleaseMutex(mutex);
}

static void services_terminated(void* p, int code)
{
	Screen->Cursor=crDefault;
	MainForm->ServicesStart->Enabled=true;
	MainForm->ServicesStop->Enabled=false;
    MainForm->ServicesRecycle->Enabled=false;
    MainForm->ServicesPause->Enabled=false;
    MainForm->ServicesPause->Checked=false;
    Application->ProcessMessages();
}
static void services_started(void* p)
{
	Screen->Cursor=crDefault;
	MainForm->ServicesStart->Enabled=false;
    MainForm->ServicesStop->Enabled=true;
    MainForm->ServicesRecycle->Enabled=true;
    MainForm->ServicesPause->Enabled=true;
    MainForm->ServicesPause->Checked=false;
    Application->ProcessMessages();
}

static void services_clients(void* p, int clients)
{
}

static void mail_log_msg(log_msg_t* msg)
{
	static FILE* LogStream;

    if(msg==NULL) {
        if(LogStream!=NULL)
            fclose(LogStream);
        LogStream=NULL;
        return;
    }

	log_msg(MailForm->Log, msg);

    if(MainForm->MailLogFile && MainForm->MailStop->Enabled) {
        AnsiString LogFileName
            =AnsiString(MainForm->cfg.logs_dir)
            +"LOGS\\MS"
            +SystemTimeToDateTime(msg->time).FormatString("mmddyy")
            +".LOG";

        if(!FileExists(LogFileName)) {
            if(LogStream!=NULL) {
            	fclose(LogStream);
                LogStream=NULL;
            }
        }
        if(LogStream==NULL)
            LogStream=_fsopen(LogFileName.c_str(),"a",SH_DENYNONE);

        if(LogStream!=NULL) {
			AnsiString Line=SystemTimeToDateTime(msg->time).FormatString("hh:mm:ss")+"  ";
		    Line+=AnsiString(msg->buf).Trim();
			if(msg->repeated)
				Line += " [x" + AnsiString(msg->repeated + 1) + "]";
	        Line+="\n";
        	fwrite(AnsiString(Line).c_str(),1,Line.Length(),LogStream);
        }
	}
}

static void mail_status(void* p, const char *str)
{
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

	MailForm->Status->Caption=AnsiString(str);

    ReleaseMutex(mutex);
}

static void mail_clients(void* p, int clients)
{
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

    MailForm->ProgressBar->Max=MainForm->mail_startup.max_clients;
	MailForm->ProgressBar->Position=clients;

    ReleaseMutex(mutex);
}

static void mail_terminated(void* p, int code)
{
	Screen->Cursor=crDefault;
	MainForm->MailStart->Enabled=true;
	MainForm->MailStop->Enabled=false;
    MainForm->MailRecycle->Enabled=false;
    MainForm->MailPause->Enabled=false;
    MainForm->MailPause->Checked=false;
    Application->ProcessMessages();
}
static void mail_started(void* p)
{
	Screen->Cursor=crDefault;
	MainForm->MailStart->Enabled=false;
    MainForm->MailStop->Enabled=true;
    MainForm->MailRecycle->Enabled=true;
    MainForm->MailPause->Enabled=true;
    MainForm->MailPause->Checked=false;    
    Application->ProcessMessages();
}
static void mail_start(void)
{
	Screen->Cursor=crAppStart;
    mail_status(NULL, "Starting");

    FILE* fp=fopen(MainForm->ini_file,"r");
    sbbs_read_ini(fp, MainForm->ini_file
        ,&MainForm->global
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,&MainForm->mail_startup
        ,NULL   ,NULL
        );
    if(fp!=NULL)
        fclose(fp);

	_beginthread((void(*)(void*))mail_server,0,&MainForm->mail_startup);
    Application->ProcessMessages();
}

static void ftp_log_msg(log_msg_t* msg)
{
	static FILE* LogStream;

    if(msg==NULL) {
        if(LogStream!=NULL)
            fclose(LogStream);
        LogStream=NULL;
        return;
    }

	log_msg(FtpForm->Log, msg);
    if(MainForm->FtpLogFile && MainForm->FtpStop->Enabled) {
        AnsiString LogFileName
            =AnsiString(MainForm->cfg.logs_dir)
            +"LOGS\\FS"
            +SystemTimeToDateTime(msg->time).FormatString("mmddyy")
            +".LOG";

        if(!FileExists(LogFileName)) {
            FileClose(FileCreate(LogFileName));
            if(LogStream!=NULL) {
                fclose(LogStream);
                LogStream=NULL;
            }
        }
        if(LogStream==NULL)
            LogStream=_fsopen(LogFileName.c_str(),"a",SH_DENYNONE);

        if(LogStream!=NULL) {
            AnsiString Line=SystemTimeToDateTime(msg->time).FormatString("hh:mm:ss")+"  ";
            Line+=AnsiString(msg->buf).Trim();
			if(msg->repeated)
				Line += " [x" + AnsiString(msg->repeated + 1) + "]";
            Line+="\n";
        	fwrite(AnsiString(Line).c_str(),1,Line.Length(),LogStream);
        }
	}
}

static void ftp_status(void* p, const char *str)
{
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

	FtpForm->Status->Caption=AnsiString(str);

    ReleaseMutex(mutex);
}

static void ftp_clients(void* p, int clients)
{
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

    FtpForm->ProgressBar->Max=MainForm->ftp_startup.max_clients;
	FtpForm->ProgressBar->Position=clients;

    ReleaseMutex(mutex);
}

static void ftp_terminated(void* p, int code)
{
	Screen->Cursor=crDefault;
	MainForm->FtpStart->Enabled=true;
	MainForm->FtpStop->Enabled=false;
    MainForm->FtpRecycle->Enabled=false;
    MainForm->FtpPause->Enabled=false;
    MainForm->FtpPause->Checked=false;
    Application->ProcessMessages();
}
static void ftp_started(void* p)
{
	Screen->Cursor=crDefault;
	MainForm->FtpStart->Enabled=false;
    MainForm->FtpStop->Enabled=true;
    MainForm->FtpRecycle->Enabled=true;
    MainForm->FtpPause->Enabled=true;
    MainForm->FtpPause->Checked=false;    
    Application->ProcessMessages();
}
static void ftp_start(void)
{
	Screen->Cursor=crAppStart;
    ftp_status(NULL, "Starting");

    FILE* fp=fopen(MainForm->ini_file,"r");
    sbbs_read_ini(fp, MainForm->ini_file
        ,&MainForm->global
        ,NULL   ,NULL
        ,NULL   ,&MainForm->ftp_startup
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,NULL
        );
    if(fp!=NULL)
        fclose(fp);

	_beginthread((void(*)(void*))ftp_server,0,&MainForm->ftp_startup);
    Application->ProcessMessages();
}
//---------------------------------------------------------------------------
static void web_log_msg(log_msg_t* msg)
{
	static FILE* LogStream;

    if(msg==NULL) {
        if(LogStream!=NULL)
            fclose(LogStream);
        LogStream=NULL;
        return;
    }

	log_msg(WebForm->Log, msg);
}

static void web_status(void* p, const char *str)
{
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

	WebForm->Status->Caption=AnsiString(str);

    ReleaseMutex(mutex);
}

static void web_clients(void* p, int clients)
{
	static HANDLE mutex;

    if(!mutex)
    	mutex=CreateMutex(NULL,false,NULL);
	WaitForSingleObject(mutex,INFINITE);

    WebForm->ProgressBar->Max=MainForm->web_startup.max_clients;
	WebForm->ProgressBar->Position=clients;

    ReleaseMutex(mutex);
}

static void web_terminated(void* p, int code)
{
	Screen->Cursor=crDefault;
	MainForm->WebStart->Enabled=true;
	MainForm->WebStop->Enabled=false;
    MainForm->WebRecycle->Enabled=false;
    MainForm->WebPause->Enabled=false;  // caused exception
    MainForm->WebPause->Checked=false;
    Application->ProcessMessages();
}
static void web_started(void* p)
{
	Screen->Cursor=crDefault;
	MainForm->WebStart->Enabled=false;
    MainForm->WebStop->Enabled=true;
    MainForm->WebRecycle->Enabled=true;
    MainForm->WebPause->Enabled=true;
    MainForm->WebPause->Checked=false;    
    Application->ProcessMessages();
}
static void web_start(void)
{
	Screen->Cursor=crAppStart;
    web_status(NULL, "Starting");

    FILE* fp=fopen(MainForm->ini_file,"r");
    sbbs_read_ini(fp, MainForm->ini_file
        ,&MainForm->global
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,&MainForm->web_startup
        ,NULL   ,NULL
        ,NULL   ,NULL
        );
    if(fp!=NULL)
        fclose(fp);

	_beginthread((void(*)(void*))web_server,0,&MainForm->web_startup);
    Application->ProcessMessages();
}
//---------------------------------------------------------------------------
/* Server recycle callback (read relevant startup .ini file section)		*/
static void recycle(void* cbdata)
{
    char            str[MAX_PATH*2];
    FILE*           fp=NULL;
	bbs_startup_t*  bbs=NULL;
	ftp_startup_t*  ftp=NULL;
	web_startup_t*  web=NULL;
	mail_startup_t* mail=NULL;
	services_startup_t* services=NULL;

    SAFEPRINTF(str,"Reading %s",MainForm->ini_file);
	if(cbdata==(void*)&bbs_log_list) {
		bbs=&MainForm->bbs_startup;
        lputs(cbdata,LOG_INFO,str);
	} else if(cbdata==(void*)&ftp_log_list) {
		ftp=&MainForm->ftp_startup;
        lputs(cbdata,LOG_INFO,str);
    } else if(cbdata==(void*)&web_log_list) {
		web=&MainForm->web_startup;
        lputs(cbdata,LOG_INFO,str);
    } else if(cbdata==(void*)&mail_log_list) {
		mail=&MainForm->mail_startup;
        lputs(cbdata,LOG_INFO,str);
	} else if(cbdata==(void*)&services_log_list) {
		services=&MainForm->services_startup;
        lputs(cbdata,LOG_INFO,str);
    }

    fp=fopen(MainForm->ini_file,"r");
    sbbs_read_ini(fp, MainForm->ini_file
        ,&MainForm->global
        ,NULL   ,bbs
        ,NULL   ,ftp
        ,NULL   ,web
        ,NULL   ,mail
        ,NULL   ,services
        );
    if(fp!=NULL)
        fclose(fp);
	MainForm->SetControls();
}
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent* Owner)
        : TForm(Owner)
{
    /* Defaults */
    memset(&global,0,sizeof(global));
    SAFECOPY(global.ctrl_dir,"c:\\sbbs\\ctrl\\");
    global.js.max_bytes=JAVASCRIPT_MAX_BYTES;
    global.js.time_limit=JAVASCRIPT_TIME_LIMIT;
    global.js.gc_interval=JAVASCRIPT_GC_INTERVAL;
    global.js.yield_interval=JAVASCRIPT_YIELD_INTERVAL;
    global.sem_chk_freq=DEFAULT_SEM_CHK_FREQ;		/* seconds */

    /* These are SBBSCTRL-specific */
    LoginCommand="telnet://127.0.0.1";
    ConfigCommand="%sscfg.exe %s -l25";
    MinimizeToSysTray=false;
    UndockableForms=false;
    UseFileAssociations=true;
    Initialized=false;

	loginAttemptListInit(&login_attempt_list);

    char* p;
    if((p=getenv("SBBSCTRL"))!=NULL)
        SAFECOPY(global.ctrl_dir,p);
   	p=lastchar(global.ctrl_dir);
	if(*p!='/' && *p!='\\')
    	strcat(global.ctrl_dir,"\\");
        
    memset(&bbs_startup,0,sizeof(bbs_startup));
    bbs_startup.size=sizeof(bbs_startup);
    bbs_startup.cbdata=&bbs_log_list;
    bbs_startup.event_cbdata=&event_log_list;    
    bbs_startup.first_node=1;
    bbs_startup.last_node=4;
	bbs_startup.options=BBS_OPT_XTRN_MINIMIZED;
	bbs_startup.telnet_port=IPPORT_TELNET;
    bbs_startup.rlogin_port=513;
	bbs_startup.lputs=lputs;
    bbs_startup.event_lputs=lputs;
    bbs_startup.errormsg=errormsg;
    bbs_startup.status=bbs_status;
    bbs_startup.clients=bbs_clients;
    bbs_startup.started=bbs_started;
    bbs_startup.recycle=recycle;
    bbs_startup.terminated=bbs_terminated;
    bbs_startup.thread_up=thread_up;
    bbs_startup.client_on=client_on;
    bbs_startup.socket_open=socket_open;
	bbs_startup.login_attempt_list=&login_attempt_list;

    memset(&mail_startup,0,sizeof(mail_startup));
    mail_startup.size=sizeof(mail_startup);
    mail_startup.cbdata=&mail_log_list;
    mail_startup.smtp_port=IPPORT_SMTP;
    mail_startup.relay_port=IPPORT_SMTP;
    mail_startup.pop3_port=110;
	mail_startup.lputs=lputs;
    mail_startup.errormsg=errormsg;
    mail_startup.status=mail_status;
    mail_startup.clients=mail_clients;
    mail_startup.started=mail_started;
    mail_startup.recycle=recycle;
    mail_startup.terminated=mail_terminated;
    mail_startup.options=MAIL_OPT_ALLOW_POP3;
    mail_startup.thread_up=thread_up;
    mail_startup.client_on=client_on;
    mail_startup.socket_open=socket_open;
    mail_startup.max_delivery_attempts=50;
    mail_startup.rescan_frequency=3600;  /* 60 minutes */
    mail_startup.lines_per_yield=10;
    mail_startup.max_clients=10;
    mail_startup.max_msg_size=10*1024*1024;
	mail_startup.login_attempt_list=&login_attempt_list;

    memset(&ftp_startup,0,sizeof(ftp_startup));
    ftp_startup.size=sizeof(ftp_startup);
    ftp_startup.cbdata=&ftp_log_list;
    ftp_startup.port=IPPORT_FTP;
	ftp_startup.lputs=lputs;
    ftp_startup.errormsg=errormsg;
    ftp_startup.status=ftp_status;
    ftp_startup.clients=ftp_clients;
    ftp_startup.started=ftp_started;
    ftp_startup.recycle=recycle;
    ftp_startup.terminated=ftp_terminated;
    ftp_startup.thread_up=thread_up;
    ftp_startup.client_on=client_on;
    ftp_startup.socket_open=socket_open;
	ftp_startup.options
        =FTP_OPT_INDEX_FILE | FTP_OPT_ALLOW_QWK;
    ftp_startup.max_clients=10;
    strcpy(ftp_startup.index_file_name,"00index");
	ftp_startup.login_attempt_list=&login_attempt_list;

    memset(&web_startup,0,sizeof(web_startup));
    web_startup.size=sizeof(web_startup);
    web_startup.cbdata=&web_log_list;
	web_startup.lputs=lputs;
    web_startup.errormsg=errormsg;
    web_startup.status=web_status;
    web_startup.clients=web_clients;
    web_startup.started=web_started;
    web_startup.recycle=recycle;
    web_startup.terminated=web_terminated;
    web_startup.thread_up=thread_up;
    web_startup.client_on=client_on;
    web_startup.socket_open=socket_open;
	web_startup.login_attempt_list=&login_attempt_list;

    memset(&services_startup,0,sizeof(services_startup));
    services_startup.size=sizeof(services_startup);
    services_startup.cbdata=&services_log_list;
    services_startup.lputs=lputs;
    services_startup.errormsg=errormsg;
    services_startup.status=services_status;
    services_startup.clients=services_clients;
    services_startup.started=services_started;
    services_startup.recycle=recycle;    
    services_startup.terminated=services_terminated;
    services_startup.thread_up=thread_up;
    services_startup.client_on=client_on;
    services_startup.socket_open=socket_open;
	services_startup.login_attempt_list=&login_attempt_list;

    bbs_log=INVALID_HANDLE_VALUE;
    event_log=INVALID_HANDLE_VALUE;
    ftp_log=INVALID_HANDLE_VALUE;
    web_log=INVALID_HANDLE_VALUE;    
    mail_log=INVALID_HANDLE_VALUE;
    services_log=INVALID_HANDLE_VALUE;

    /* Default local "Spy Terminal" settings */
    SpyTerminalFont=new TFont;
    SpyTerminalFont->Name="Terminal";
    SpyTerminalFont->Size=9;
    SpyTerminalFont->Pitch=fpFixed;
    SpyTerminalWidth=434;
    SpyTerminalHeight=365;
    SpyTerminalKeyboardActive=true;

    Application->OnMinimize=FormMinimize;

    /* Get pointers to NT Service functions */
	HANDLE hSCMlib = LoadLibrary("ADVAPI32.DLL");
	if(hSCMlib!=NULL) {
		openSCManager=(OpenSCManager_t)GetProcAddress(hSCMlib, "OpenSCManagerA");
		openService=(OpenService_t)GetProcAddress(hSCMlib,"OpenServiceA");
		startService=(StartService_t)GetProcAddress(hSCMlib,"StartServiceA");
		controlService=(ControlService_t)GetProcAddress(hSCMlib,"ControlService");
		queryServiceStatus=(QueryServiceStatus_t)GetProcAddress(hSCMlib,"QueryServiceStatus");
		queryServiceConfig=(QueryServiceConfig_t)GetProcAddress(hSCMlib,"QueryServiceConfigA");
		closeServiceHandle=(CloseServiceHandle_t)GetProcAddress(hSCMlib,"CloseServiceHandle");
		FreeLibrary(hSCMlib);
    }

    /* Open Service Manager */
    if(openSCManager!=NULL)
        hSCManager = openSCManager(
                            NULL,                   // machine (NULL == local)
                            NULL,                   // database (NULL == default)
                            SC_MANAGER_CONNECT		// access required
                            );

	/* Open Synchronet Services */
    if(hSCManager!=NULL) {
		bbs_svc =  openService(hSCManager, NTSVC_NAME_BBS, GENERIC_READ|GENERIC_EXECUTE);
		ftp_svc =  openService(hSCManager, NTSVC_NAME_FTP, GENERIC_READ|GENERIC_EXECUTE);
		web_svc =  openService(hSCManager, NTSVC_NAME_WEB, GENERIC_READ|GENERIC_EXECUTE);        
		mail_svc =  openService(hSCManager, NTSVC_NAME_MAIL, GENERIC_READ|GENERIC_EXECUTE);
		services_svc =  openService(hSCManager, NTSVC_NAME_SERVICES, GENERIC_READ|GENERIC_EXECUTE);
    }

    {
        int i;

        for(i=LOG_EMERG;i<=LOG_DEBUG;i++) {
            LogFont[i] = new TFont;
            LogFont[i]->Color=LogLevelColor[i];
            if(i <= LOG_CRIT)
                LogFont[i]->Style = TFontStyles()<< fsBold;
        }
    }

    listInit(&bbs_log_list, LINK_LIST_MUTEX);
    listInit(&event_log_list, LINK_LIST_MUTEX);    
    listInit(&ftp_log_list, LINK_LIST_MUTEX);
    listInit(&web_log_list, LINK_LIST_MUTEX);
    listInit(&mail_log_list, LINK_LIST_MUTEX);
    listInit(&services_log_list, LINK_LIST_MUTEX);

    TelnetPause->DisableIfNoHandler=false;
    MailPause->DisableIfNoHandler=false;
    WebPause->DisableIfNoHandler=false;
    FtpPause->DisableIfNoHandler=false;
    ServicesPause->DisableIfNoHandler=false;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FileExitMenuItemClick(TObject *Sender)
{
        Close();
}
void __fastcall TMainForm::FormCreate(TObject *Sender)
{
	Height=400;	// Just incase we mess it up in the IDE
    Width=700;

    // Verify SBBS.DLL version
    long bbs_ver = bbs_ver_num();
    if(bbs_ver != VERSION_HEX) {
        char str[128];
        sprintf(str,"Incorrect SBBS.DLL Version (%lX, expected %lx)", bbs_ver, VERSION_HEX);
    	Application->MessageBox(str,"ERROR",MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
    }

    // Read Registry keys
	TRegistry* Registry=new TRegistry;
    if(!Registry->OpenKey(REG_KEY,true)) {
    	Application->MessageBox("Error opening registry key"
        	,REG_KEY,MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
        return;
    }
   	if(Registry->ValueExists("MainFormTop"))
	   	Top=Registry->ReadInteger("MainFormTop");
   	if(Registry->ValueExists("MainFormLeft"))
	   	Left=Registry->ReadInteger("MainFormLeft");
   	if(Registry->ValueExists("MainFormHeight"))
	   	Height=Registry->ReadInteger("MainFormHeight");
   	if(Registry->ValueExists("MainFormWidth"))
	   	Width=Registry->ReadInteger("MainFormWidth");
    else
        WindowState=wsMaximized;    // Default to fullscreen
   	if(Registry->ValueExists("SpyTerminalWidth"))
	   	SpyTerminalWidth=Registry->ReadInteger("SpyTerminalWidth");
   	if(Registry->ValueExists("SpyTerminalHeight"))
	   	SpyTerminalHeight=Registry->ReadInteger("SpyTerminalHeight");
   	if(Registry->ValueExists("SpyTerminalFontName"))
	   	SpyTerminalFont->Name=Registry->ReadString("SpyTerminalFontName");
   	if(Registry->ValueExists("SpyTerminalFontSize"))
	   	SpyTerminalFont->Size=Registry->ReadInteger("SpyTerminalFontSize");
   	if(Registry->ValueExists("SpyTerminalKeyboardActive"))
	   	SpyTerminalKeyboardActive
            =Registry->ReadBool("SpyTerminalKeyboardActive");

    Registry->CloseKey();
    delete Registry;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormShow(TObject *Sender)
{
	StartupTimer->Enabled=true;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ViewToolbarMenuItemClick(TObject *Sender)
{
	Toolbar->Visible=ViewToolbarMenuItem->Checked;
}
//---------------------------------------------------------------------------
BOOL NTsvcEnabled(SC_HANDLE svc, QUERY_SERVICE_CONFIG* config, DWORD config_size)
{
	if(svc==NULL || startService==NULL || queryServiceStatus==NULL || config==NULL)
    	return(FALSE);

	DWORD ret;
	if(!queryServiceConfig(svc,config,config_size,&ret))
		return(FALSE);
	if(config->dwStartType==SERVICE_DISABLED)
		return(FALSE);
	return(TRUE);
}
//---------------------------------------------------------------------------
BOOL __fastcall TMainForm::bbsServiceEnabled(void)
{
    return NTsvcEnabled(bbs_svc,bbs_svc_config,bbs_svc_config_size);
}
BOOL __fastcall TMainForm::mailServiceEnabled(void)
{
    return NTsvcEnabled(mail_svc,mail_svc_config,mail_svc_config_size);
}
BOOL __fastcall TMainForm::ftpServiceEnabled(void)
{
    return NTsvcEnabled(ftp_svc,ftp_svc_config,ftp_svc_config_size);
}
BOOL __fastcall TMainForm::webServiceEnabled(void)
{
    return NTsvcEnabled(web_svc,web_svc_config,web_svc_config_size);
}
BOOL __fastcall TMainForm::servicesServiceEnabled(void)
{
    return NTsvcEnabled(services_svc,services_svc_config,services_svc_config_size);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormClose(TObject *Sender, TCloseAction &Action)
{
    UpTimer->Enabled=false; /* Stop updating the status bar */
	StatsTimer->Enabled=false;

    if(TrayIcon->Visible)           /* minimized to tray? */
        TrayIcon->Visible=false;    /* restore to avoid crash */
        
    /* This is necessary to save form sizes/positions */
    if(Initialized) /* Don't overwrite registry and .ini settings with defaults */
        SaveSettings(Sender);

	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Terminating servers...";
    time_t start=time(NULL);
	while( (TelnetStop->Enabled     && !bbsServiceEnabled())
        || (MailStop->Enabled       && !mailServiceEnabled())
        || (FtpStop->Enabled        && !ftpServiceEnabled())
        || (WebStop->Enabled        && !webServiceEnabled())
    	|| (ServicesStop->Enabled   && !servicesServiceEnabled())) {
        if(time(NULL)-start>30)
            break;
        Application->ProcessMessages();
        YIELD();
    }
	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Closing...";
    Application->ProcessMessages();
    
	LogTimer->Enabled=false;

	ServiceStatusTimer->Enabled=false;
	NodeForm->Timer->Enabled=false;
	ClientForm->Timer->Enabled=false;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormCloseQuery(TObject *Sender, bool &CanClose)
{
	CanClose=false;

    if(TelnetStop->Enabled && !bbsServiceEnabled()) {
     	if(!terminating && TelnetForm->ProgressBar->Position
	        && Application->MessageBox("Shut down the Terminal Server?"
        	,"Synchronet Terminal Server In Use", MB_OKCANCEL)!=IDOK)
            return;
        TelnetStopExecute(Sender);
	}

    if(MailStop->Enabled && !mailServiceEnabled()) {
    	if(!terminating && MailForm->ProgressBar->Position
    		&& Application->MessageBox("Shut down the Mail Server?"
        	,"Synchronet Mail Server In Use", MB_OKCANCEL)!=IDOK)
            return;
        MailStopExecute(Sender);
    }

    if(FtpStop->Enabled && !ftpServiceEnabled()) {
    	if(!terminating && FtpForm->ProgressBar->Position
    		&& Application->MessageBox("Shut down the FTP Server?"
	       	,"Synchronet FTP Server In Use", MB_OKCANCEL)!=IDOK)
            return;
        FtpStopExecute(Sender);
    }

    if(WebStop->Enabled && !webServiceEnabled()) {
    	if(!terminating && WebForm->ProgressBar->Position
    		&& Application->MessageBox("Shut down the Web Server?"
	       	,"Synchronet Web Server In Use", MB_OKCANCEL)!=IDOK)
            return;
        WebStopExecute(Sender);
    }

    if(ServicesStop->Enabled && !servicesServiceEnabled())
	    ServicesStopExecute(Sender);

    CanClose=true;
}

//---------------------------------------------------------------------------
BOOL StartNTsvc(SC_HANDLE svc, SERVICE_STATUS* status, QUERY_SERVICE_CONFIG* config, DWORD config_size)
{
	if(svc==NULL || startService==NULL || queryServiceStatus==NULL || config==NULL)
    	return(FALSE);

	DWORD ret;
	if(!queryServiceConfig(svc,config,config_size,&ret))
		return(FALSE);
	if(config->dwStartType==SERVICE_DISABLED)
		return(FALSE);
    if(!queryServiceStatus(svc,status))
    	return(FALSE);
    if(status->dwCurrentState!=SERVICE_STOPPED)
    	return(TRUE);
    if(!startService(svc,0,NULL))
       	Application->MessageBox(AnsiString("ERROR " + IntToStr(GetLastError()) +
            " starting " + config->lpDisplayName).c_str()
            ,"ERROR"
            ,MB_OK|MB_ICONEXCLAMATION);
    return(TRUE);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::TelnetStartExecute(TObject *Sender)
{
	if(!StartNTsvc(bbs_svc,&bbs_svc_status,bbs_svc_config,bbs_svc_config_size))
		bbs_start();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ServicesStartExecute(TObject *Sender)
{
	if(StartNTsvc(services_svc,&services_svc_status,services_svc_config,services_svc_config_size))
    	return;
	Screen->Cursor=crAppStart;
    services_status(NULL, "Starting");

    FILE* fp=fopen(ini_file,"r");
    sbbs_read_ini(fp, MainForm->ini_file
        ,&MainForm->global
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,&services_startup
        );
    if(fp!=NULL)
        fclose(fp);

	_beginthread((void(*)(void*))services_thread,0,&services_startup);
    Application->ProcessMessages();
}

//---------------------------------------------------------------------------
BOOL StopNTsvc(SC_HANDLE svc, SERVICE_STATUS* status)
{
	if(svc==NULL || controlService==NULL)
    	return(FALSE);

    return controlService(svc,SERVICE_CONTROL_STOP,status);
}

//---------------------------------------------------------------------------

void __fastcall TMainForm::ServicesStopExecute(TObject *Sender)
{
	if(StopNTsvc(services_svc,&services_svc_status))
    	return;
    Screen->Cursor=crAppStart;
    services_status(NULL, "Terminating");
    services_terminate();
    Application->ProcessMessages();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TelnetStopExecute(TObject *Sender)
{
	if(StopNTsvc(bbs_svc,&bbs_svc_status))
    	return;
    Screen->Cursor=crAppStart;
    bbs_status(NULL, "Terminating");
    bbs_terminate();
    Application->ProcessMessages();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TelnetConfigureExecute(TObject *Sender)
{
    static inside;
    if(inside) return;
    inside=true;

	Application->CreateForm(__classid(TTelnetCfgDlg), &TelnetCfgDlg);
	TelnetCfgDlg->ShowModal();
    delete TelnetCfgDlg;
    
    inside=false;
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::NodeListStartExecute(TObject *Sender)
{
	NodeForm->Timer->Enabled=true;
    NodeListStart->Enabled=false;
    NodeListStop->Enabled=true;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::NodeListStopExecute(TObject *Sender)
{
    NodeForm->Timer->Enabled=false;
    NodeListStart->Enabled=true;
    NodeListStop->Enabled=false;
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::MailConfigureExecute(TObject *Sender)
{
    static inside;
    if(inside) return;
    inside=true;

	Application->CreateForm(__classid(TMailCfgDlg), &MailCfgDlg);
	MailCfgDlg->ShowModal();
    delete MailCfgDlg;

    inside=false;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::MailStartExecute(TObject *Sender)
{
	if(!StartNTsvc(mail_svc,&mail_svc_status,mail_svc_config,mail_svc_config_size))
	    mail_start();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::MailStopExecute(TObject *Sender)
{
	if(StopNTsvc(mail_svc,&mail_svc_status))
    	return;
    Screen->Cursor=crAppStart;
    mail_status(NULL, "Terminating");
    mail_terminate();
    Application->ProcessMessages();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewTelnetExecute(TObject *Sender)
{
	TelnetForm->Visible=ViewTelnet->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewEventsExecute(TObject *Sender)
{
	EventsForm->Visible=ViewEvents->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ViewNodesExecute(TObject *Sender)
{
	NodeForm->Visible=ViewNodes->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ViewMailServerExecute(TObject *Sender)
{
	MailForm->Visible=ViewMailServer->Checked;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ViewFtpServerExecute(TObject *Sender)
{
	FtpForm->Visible=ViewFtpServer->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewWebServerExecute(TObject *Sender)
{
    WebForm->Visible=ViewWebServer->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewServicesExecute(TObject *Sender)
{
    ServicesForm->Visible=ViewServices->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewStatsExecute(TObject *Sender)
{
	StatsForm->Visible=ViewStats->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewClientsExecute(TObject *Sender)
{
	ClientForm->Visible=ViewClients->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FtpStartExecute(TObject *Sender)
{
	if(!StartNTsvc(ftp_svc,&ftp_svc_status,ftp_svc_config,ftp_svc_config_size))
		ftp_start();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FtpStopExecute(TObject *Sender)
{
	if(StopNTsvc(ftp_svc,&ftp_svc_status))
    	return;
    Screen->Cursor=crAppStart;
    ftp_status(NULL, "Terminating");
    ftp_terminate();
    Application->ProcessMessages();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FtpConfigureExecute(TObject *Sender)
{
    static inside;
    if(inside) return;
    inside=true;

	Application->CreateForm(__classid(TFtpCfgDlg), &FtpCfgDlg);
	FtpCfgDlg->ShowModal();
    delete FtpCfgDlg;

    inside=false;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::WebStartExecute(TObject *Sender)
{
	if(!StartNTsvc(web_svc,&web_svc_status,web_svc_config,web_svc_config_size))
		web_start();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::WebStopExecute(TObject *Sender)
{
	if(StopNTsvc(web_svc,&web_svc_status))
    	return;
    Screen->Cursor=crAppStart;
    web_status(NULL, "Terminating");
    web_terminate();
    Application->ProcessMessages();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::WebConfigureExecute(TObject *Sender)
{
    static inside;
    if(inside) return;
    inside=true;

	Application->CreateForm(__classid(TWebCfgDlg), &WebCfgDlg);
	WebCfgDlg->ShowModal();
    delete WebCfgDlg;

    inside=false;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::BBSConfigureMenuItemClick(TObject *Sender)
{
	char str[256];

    sprintf(str,ConfigCommand.c_str()
    	,cfg.exec_dir, cfg.ctrl_dir);
    STARTUPINFO startup_info={0};
    PROCESS_INFORMATION process_info;
    startup_info.cb=sizeof(startup_info);
    startup_info.lpTitle="Synchronet Configuration Utility";
	if(!CreateProcess(
		NULL,			// pointer to name of executable module
		str,  			// pointer to command line string
		NULL,  			// process security attributes
		NULL,   		// thread security attributes
		FALSE, 			// handle inheritance flag
		CREATE_NEW_CONSOLE|CREATE_SEPARATE_WOW_VDM, // creation flags
        NULL,  			// pointer to new environment block
		cfg.ctrl_dir,	// pointer to current directory name
		&startup_info,  // pointer to STARTUPINFO
		&process_info  	// pointer to PROCESS_INFORMATION
		))
       	Application->MessageBox(AnsiString("ERROR " + IntToStr(GetLastError()) +
            " executing " + str).c_str()
            ,"ERROR"
            ,MB_OK|MB_ICONEXCLAMATION);
	// Resource leak if you don't close these:
	CloseHandle(process_info.hThread);
	CloseHandle(process_info.hProcess);
}
//---------------------------------------------------------------------------




void __fastcall TMainForm::NodeCloseButtonClick(TObject *Sender)
{
	ViewNodesExecute(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TelnetCloseButtonClick(TObject *Sender)
{
	ViewTelnetExecute(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::MailCloseButtonClick(TObject *Sender)
{
	ViewMailServerExecute(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FtpCloseButtonClick(TObject *Sender)
{
	ViewFtpServerExecute(Sender);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::StatsTimerTick(TObject *Sender)
{
	char 	str[128];
	int 	i;
	static stats_t stats;
	static users;
	static newusers;
	static counter;

	if(!StatsForm->Visible)
		return;

    getstats(&cfg,0,&stats);

	StatsForm->TotalLogons->Caption=AnsiString(stats.logons);
    StatsForm->LogonsToday->Caption=AnsiString(stats.ltoday);
    StatsForm->TotalTimeOn->Caption=AnsiString(minutes_to_str(stats.timeon, str, sizeof(str)));
    StatsForm->TimeToday->Caption=AnsiString(stats.ttoday);
    StatsForm->TotalEMail->Caption=AnsiString(getmail(&cfg,0,0,0));
	StatsForm->EMailToday->Caption=AnsiString(stats.etoday);
	StatsForm->TotalFeedback->Caption=AnsiString(getmail(&cfg,1,0,0));
	StatsForm->FeedbackToday->Caption=AnsiString(stats.ftoday);
	/* Don't scan a large user database more often than necessary */
	if(!counter || users<100 || (counter%(users/100))==0 || stats.nusers!=newusers)
		users=total_users(&cfg);
    StatsForm->TotalUsers->Caption=AnsiString(users);
    StatsForm->NewUsersToday->Caption=AnsiString(newusers=stats.nusers);
    StatsForm->PostsToday->Caption=AnsiString(stats.ptoday);
    StatsForm->UploadedFiles->Caption=AnsiString(stats.uls);
	if(stats.ulb>=1024*1024)
    	sprintf(str,"%.1fM",stats.ulb/(1024.0*1024.0));
    else if(stats.ulb>=1024)
    	sprintf(str,"%luK",stats.ulb/1024);
    else
    	sprintf(str,"%lu",stats.ulb);
    StatsForm->UploadedBytes->Caption=AnsiString(str);
    StatsForm->DownloadedFiles->Caption=AnsiString(stats.dls);
	if(stats.dlb>=1024*1024)
    	sprintf(str,"%.1fM",stats.dlb/(1024.0*1024.0));
    else if(stats.dlb>=1024)
    	sprintf(str,"%luK",stats.dlb/1024);
    else
    	sprintf(str,"%lu",stats.dlb);
    StatsForm->DownloadedBytes->Caption=AnsiString(str);

	counter++;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::StatsCloseButtonClick(TObject *Sender)
{
	ViewStatsExecute(Sender);
}
//---------------------------------------------------------------------------
enum {
	 PAGE_UPPERLEFT
    ,PAGE_UPPERRIGHT
    ,PAGE_LOWERRIGHT
    ,PAGE_LOWERLEFT
    };
TPageControl* __fastcall TMainForm::PageControl(int num)
{
	switch(num)
    {
    	case PAGE_UPPERLEFT:
        	return(UpperLeftPageControl);
        case PAGE_UPPERRIGHT:
        	return(UpperRightPageControl);
        case PAGE_LOWERRIGHT:
        	return(LowerRightPageControl);
        case PAGE_LOWERLEFT:
        	return(LowerLeftPageControl);
    }
    return(NULL);
}
int __fastcall TMainForm::PageNum(TPageControl* obj)
{
    if(obj==UpperLeftPageControl)
       	return(PAGE_UPPERLEFT);
    if(obj==UpperRightPageControl)
       	return(PAGE_UPPERRIGHT);
    if(obj==LowerRightPageControl)
       	return(PAGE_LOWERRIGHT);
    if(obj==LowerLeftPageControl)
       	return(PAGE_LOWERLEFT);
	return(PAGE_LOWERRIGHT);
}
TColor __fastcall TMainForm::ReadColor(TRegistry* Registry
    ,AnsiString name, TColor deflt)
{
    if(Registry->ValueExists(name + "Color"))
        return(StringToColor(Registry->ReadString(name + "Color")));
        
    return deflt;
}
void __fastcall TMainForm::WriteColor(TRegistry* Registry
    ,AnsiString name, TColor color)
{
    Registry->WriteString(name + "Color", ColorToString(color));
}

int FontStyleToInt(TFont* Font)
{
    int style=0;
    for(int i=fsBold;i<=fsStrikeOut;i++)
    	if(Font->Style.Contains((TFontStyle)i))
        	style|=(1<<i);
    return(style);
}

void IntToFontStyle(int style, TFont* Font)
{
    Font->Style=Font->Style.Clear();
    for(int i=fsBold;i<=fsStrikeOut;i++)
        if(style&(1<<i))
            Font->Style=Font->Style<<(TFontStyle)i;
}

void __fastcall TMainForm::ReadFont(AnsiString subkey, TFont* Font)
{
    // Read Registry keys
	TRegistry* Registry=new TRegistry;
    AnsiString key = REG_KEY + subkey + "Font";
    if(!Registry->OpenKey(key,true)) {
    	Application->MessageBox("Error opening registry key"
        	,key.c_str(),MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
        return;
    }
    if(Registry->ValueExists("Name"))
        Font->Name=Registry->ReadString("Name");
    if(Registry->ValueExists("Color"))
        Font->Color=StringToColor(Registry->ReadString("Color"));
    if(Registry->ValueExists("Height"))
        Font->Height=Registry->ReadInteger("Height");
    if(Registry->ValueExists("Size"))
        Font->Size=Registry->ReadInteger("Size");

    if(Registry->ValueExists("Style"))
        IntToFontStyle(Registry->ReadInteger("Style"),Font);

    Registry->CloseKey();
    delete Registry;
}
void __fastcall TMainForm::WriteFont(AnsiString subkey, TFont* Font)
{
    // Read Registry keys
	TRegistry* Registry=new TRegistry;
    AnsiString key = REG_KEY + subkey + "Font";
    if(!Registry->OpenKey(key,true)) {
    	Application->MessageBox("Error opening registry key"
        	,key.c_str(),MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
        return;
    }
    Registry->WriteString("Name",Font->Name);
    Registry->WriteString("Color",ColorToString(Font->Color));
    Registry->WriteInteger("Height",Font->Height);
    Registry->WriteInteger("Size",Font->Size);
    Registry->WriteInteger("Style",FontStyleToInt(Font));

    Registry->CloseKey();
    delete Registry;
}

void __fastcall TMainForm::SetControls(void)
{
    TelnetForm->LogLevelUpDown->Position=bbs_startup.log_level;
    TelnetForm->LogLevelText->Caption=LogLevelDesc[bbs_startup.log_level];
    FtpForm->LogLevelUpDown->Position=ftp_startup.log_level;
    FtpForm->LogLevelText->Caption=LogLevelDesc[ftp_startup.log_level];
    MailForm->LogLevelUpDown->Position=mail_startup.log_level;
    MailForm->LogLevelText->Caption=LogLevelDesc[mail_startup.log_level];
    WebForm->LogLevelUpDown->Position=web_startup.log_level;
    WebForm->LogLevelText->Caption=LogLevelDesc[web_startup.log_level];
    ServicesForm->LogLevelUpDown->Position=services_startup.log_level;
    ServicesForm->LogLevelText->Caption=LogLevelDesc[services_startup.log_level];

    if(cfg.total_faddrs)
        FidonetMenuItem->Visible = true;
    else
        FidonetMenuItem->Visible = false;
}

void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
{
    bool	TelnetFormFloating=false;
    bool	EventsFormFloating=false;
    bool	ServicesFormFloating=false;
    bool 	NodeFormFloating=false;
    bool	StatsFormFloating=false;
    bool	ClientFormFloating=false;
    bool 	MailFormFloating=false;
    bool	FtpFormFloating=false;
    bool	WebFormFloating=false;
    int		NodeFormPage=PAGE_UPPERLEFT;
    int		StatsFormPage=PAGE_UPPERLEFT;
    int		ClientFormPage=PAGE_UPPERLEFT;
    int		TelnetFormPage=PAGE_LOWERLEFT;
    int		EventsFormPage=PAGE_LOWERLEFT;
    int		MailFormPage=PAGE_UPPERRIGHT;
    int		FtpFormPage=PAGE_LOWERRIGHT;
    int		WebFormPage=PAGE_LOWERRIGHT;
    int     ServicesFormPage=PAGE_LOWERRIGHT;

	StartupTimer->Enabled = false;
	if(Initialized) { // second time (fresh install)
		delete StartupTimer;
        BBSConfigWizardMenuItemClick(Sender);
		DisplayMainPanels(Sender);
		return;
	}

    AnsiString	Str;
    // Read Registry keys
	TRegistry* Registry=new TRegistry;
    if(!Registry->OpenKey(REG_KEY,true)) {
    	Application->MessageBox("Error opening registry key"
        	,REG_KEY,MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
        return;
    }

    TopPanel->Height=Height/3;
    UpperLeftPageControl->Width=Width/2;
    LowerLeftPageControl->Width=Width/2;

    if(Registry->ValueExists("TopPanelHeight"))
    	TopPanel->Height=Registry->ReadInteger("TopPanelHeight");
    if(Registry->ValueExists("UpperLeftPageControlWidth"))
    	UpperLeftPageControl->Width
        	=Registry->ReadInteger("UpperLeftPageControlWidth");
    if(Registry->ValueExists("LowerLeftPageControlWidth"))
    	LowerLeftPageControl->Width
        	=Registry->ReadInteger("LowerLeftPageControlWidth");
    if(Registry->ValueExists("UndockableForms"))
        UndockableForms=Registry->ReadBool("UndockableForms");

    if(UndockableForms) {
        if(Registry->ValueExists("TelnetFormFloating"))
            TelnetFormFloating=Registry->ReadBool("TelnetFormFloating");
        if(Registry->ValueExists("EventsFormFloating"))
            EventsFormFloating=Registry->ReadBool("EventsFormFloating");
        if(Registry->ValueExists("ServicesFormFloating"))
            ServicesFormFloating=Registry->ReadBool("ServicesFormFloating");
        if(Registry->ValueExists("NodeFormFloating"))
            NodeFormFloating=Registry->ReadBool("NodeFormFloating");
        if(Registry->ValueExists("StatsFormFloating"))
            StatsFormFloating=Registry->ReadBool("StatsFormFloating");
        if(Registry->ValueExists("ClientFormFloating"))
            ClientFormFloating=Registry->ReadBool("ClientFormFloating");
        if(Registry->ValueExists("MailFormFloating"))
            MailFormFloating=Registry->ReadBool("MailFormFloating");
        if(Registry->ValueExists("FtpFormFloating"))
            FtpFormFloating=Registry->ReadBool("FtpFormFloating");
        if(Registry->ValueExists("WebFormFloating"))
            WebFormFloating=Registry->ReadBool("WebFormFloating");
    }
    if(Registry->ValueExists("TelnetFormPage"))
    	TelnetFormPage=Registry->ReadInteger("TelnetFormPage");
    if(Registry->ValueExists("EventsFormPage"))
    	EventsFormPage=Registry->ReadInteger("EventsFormPage");
    if(Registry->ValueExists("ServicesFormPage"))
    	ServicesFormPage=Registry->ReadInteger("ServicesFormPage");
    if(Registry->ValueExists("NodeFormPage"))
    	NodeFormPage=Registry->ReadInteger("NodeFormPage");
    if(Registry->ValueExists("StatsFormPage"))
    	StatsFormPage=Registry->ReadInteger("StatsFormPage");
    if(Registry->ValueExists("ClientFormPage"))
    	ClientFormPage=Registry->ReadInteger("ClientFormPage");
    if(Registry->ValueExists("MailFormPage"))
    	MailFormPage=Registry->ReadInteger("MailFormPage");
    if(Registry->ValueExists("FtpFormPage"))
    	FtpFormPage=Registry->ReadInteger("FtpFormPage");
    if(Registry->ValueExists("WebFormPage"))
    	WebFormPage=Registry->ReadInteger("WebFormPage");

    TelnetForm->Log->Color=ReadColor(Registry,"TelnetLog",TelnetForm->Log->Color);
    ReadFont("TelnetLog",TelnetForm->Log->Font);
    EventsForm->Log->Color=ReadColor(Registry,"EventsLog",EventsForm->Log->Color);
    ReadFont("EventsLog",EventsForm->Log->Font);
    ServicesForm->Log->Color=ReadColor(Registry,"ServicesLog",ServicesForm->Log->Color);
    ReadFont("ServicesLog",ServicesForm->Log->Font);
    MailForm->Log->Color=ReadColor(Registry,"MailLog",MailForm->Log->Color);
    ReadFont("MailLog",MailForm->Log->Font);
    FtpForm->Log->Color=ReadColor(Registry,"FtpLog",FtpForm->Log->Color);
    ReadFont("FtpLog",FtpForm->Log->Font);
    WebForm->Log->Color=ReadColor(Registry,"WebLog",WebForm->Log->Color);
    ReadFont("WebLog",WebForm->Log->Font);
    NodeForm->ListBox->Color=ReadColor(Registry,"NodeList",NodeForm->ListBox->Color);
    ReadFont("NodeList",NodeForm->ListBox->Font);
    ClientForm->ListView->Color=ReadColor(Registry,"ClientList",ClientForm->ListView->Color);
    ReadFont("ClientList",ClientForm->ListView->Font);

    {
        int i;

		for(i=LOG_EMERG; i<=LOG_DEBUG; i++) {
			if(i != LOG_INFO)
				ReadFont("Log" + AnsiString(LogLevelDesc[i]), LogFont[i]);
		}
    }

	if(Registry->ValueExists("TelnetFormTop"))
    	TelnetForm->Top=Registry->ReadInteger("TelnetFormTop");
	if(Registry->ValueExists("TelnetFormLeft"))
    	TelnetForm->Left=Registry->ReadInteger("TelnetFormLeft");
	if(Registry->ValueExists("TelnetFormWidth"))
    	TelnetForm->Width=Registry->ReadInteger("TelnetFormWidth");
	if(Registry->ValueExists("TelnetFormHeight"))
    	TelnetForm->Height=Registry->ReadInteger("TelnetFormHeight");
	if(Registry->ValueExists("TelnetFormMonitor"))
    	TelnetForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("TelnetFormMonitor");

	if(Registry->ValueExists("EventsFormTop"))
    	EventsForm->Top=Registry->ReadInteger("EventsFormTop");
	if(Registry->ValueExists("EventsFormLeft"))
    	EventsForm->Left=Registry->ReadInteger("EventsFormLeft");
	if(Registry->ValueExists("EventsFormWidth"))
    	EventsForm->Width=Registry->ReadInteger("EventsFormWidth");
	if(Registry->ValueExists("EventsFormHeight"))
    	EventsForm->Height=Registry->ReadInteger("EventsFormHeight");
	if(Registry->ValueExists("EventsFormMonitor"))
    	EventsForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("EventsFormMonitor");

	if(Registry->ValueExists("ServicesFormTop"))
    	ServicesForm->Top=Registry->ReadInteger("ServicesFormTop");
	if(Registry->ValueExists("ServicesFormLeft"))
    	ServicesForm->Left=Registry->ReadInteger("ServicesFormLeft");
	if(Registry->ValueExists("ServicesFormWidth"))
    	ServicesForm->Width=Registry->ReadInteger("ServicesFormWidth");
	if(Registry->ValueExists("ServicesFormHeight"))
    	ServicesForm->Height=Registry->ReadInteger("ServicesFormHeight");
	if(Registry->ValueExists("ServicesFormMonitor"))
    	ServicesForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("ServicesFormMonitor");

	if(Registry->ValueExists("FtpFormTop"))
    	FtpForm->Top=Registry->ReadInteger("FtpFormTop");
	if(Registry->ValueExists("FtpFormLeft"))
    	FtpForm->Left=Registry->ReadInteger("FtpFormLeft");
	if(Registry->ValueExists("FtpFormWidth"))
    	FtpForm->Width=Registry->ReadInteger("FtpFormWidth");
	if(Registry->ValueExists("FtpFormHeight"))
    	FtpForm->Height=Registry->ReadInteger("FtpFormHeight");
	if(Registry->ValueExists("FtpFormMonitor"))
    	FtpForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("FtpFormMonitor");

	if(Registry->ValueExists("WebFormTop"))
    	WebForm->Top=Registry->ReadInteger("WebFormTop");
	if(Registry->ValueExists("WebFormLeft"))
    	WebForm->Left=Registry->ReadInteger("WebFormLeft");
	if(Registry->ValueExists("WebFormWidth"))
    	WebForm->Width=Registry->ReadInteger("WebFormWidth");
	if(Registry->ValueExists("WebFormHeight"))
    	WebForm->Height=Registry->ReadInteger("WebFormHeight");
	if(Registry->ValueExists("WebFormMonitor"))
    	WebForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("WebFormMonitor");

	if(Registry->ValueExists("MailFormTop"))
    	MailForm->Top=Registry->ReadInteger("MailFormTop");
	if(Registry->ValueExists("MailFormLeft"))
    	MailForm->Left=Registry->ReadInteger("MailFormLeft");
	if(Registry->ValueExists("MailFormWidth"))
    	MailForm->Width=Registry->ReadInteger("MailFormWidth");
	if(Registry->ValueExists("MailFormHeight"))
    	MailForm->Height=Registry->ReadInteger("MailFormHeight");
	if(Registry->ValueExists("MailFormMonitor"))
    	MailForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("MailFormMonitor");

	if(Registry->ValueExists("NodeFormTop"))
    	NodeForm->Top=Registry->ReadInteger("NodeFormTop");
	if(Registry->ValueExists("NodeFormLeft"))
    	NodeForm->Left=Registry->ReadInteger("NodeFormLeft");
	if(Registry->ValueExists("NodeFormWidth"))
    	NodeForm->Width=Registry->ReadInteger("NodeFormWidth");
	if(Registry->ValueExists("NodeFormHeight"))
    	NodeForm->Height=Registry->ReadInteger("NodeFormHeight");
	if(Registry->ValueExists("NodeFormMonitor"))
    	NodeForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("NodeFormMonitor");

	if(Registry->ValueExists("StatsFormTop"))
    	StatsForm->Top=Registry->ReadInteger("StatsFormTop");
	if(Registry->ValueExists("StatsFormLeft"))
    	StatsForm->Left=Registry->ReadInteger("StatsFormLeft");
	if(Registry->ValueExists("StatsFormWidth"))
    	StatsForm->Width=Registry->ReadInteger("StatsFormWidth");
	if(Registry->ValueExists("StatsFormHeight"))
    	StatsForm->Height=Registry->ReadInteger("StatsFormHeight");
	if(Registry->ValueExists("StatsFormMonitor"))
    	StatsForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("StatsFormMonitor");

	if(Registry->ValueExists("ClientFormTop"))
    	ClientForm->Top=Registry->ReadInteger("ClientFormTop");
	if(Registry->ValueExists("ClientFormLeft"))
    	ClientForm->Left=Registry->ReadInteger("ClientFormLeft");
	if(Registry->ValueExists("ClientFormWidth"))
    	ClientForm->Width=Registry->ReadInteger("ClientFormWidth");
	if(Registry->ValueExists("ClientFormHeight"))
    	ClientForm->Height=Registry->ReadInteger("ClientFormHeight");
	if(Registry->ValueExists("ClientFormMonitor"))
    	ClientForm->DefaultMonitor=(TDefaultMonitor)Registry->ReadInteger("ClientFormMonitor");

    for(int i=0;i<ClientForm->ListView->Columns->Count;i++) {
        char str[128];
        sprintf(str,"ClientListColumn%dWidth",i);
        if(Registry->ValueExists(str))
            ClientForm->ListView->Columns->Items[i]->Width
                =Registry->ReadInteger(str);
    }

    if(Registry->ValueExists("ToolbarVisible"))
    	Toolbar->Visible=Registry->ReadBool("ToolbarVisible");

    ViewToolbarMenuItem->Checked=Toolbar->Visible;
    ViewStatusBarMenuItem->Checked=StatusBar->Visible;

    if(Registry->ValueExists("MaxLogLen"))
    	MaxLogLen=Registry->ReadInteger("MaxLogLen");

    if(Registry->ValueExists("LoginCommand"))
    	LoginCommand=Registry->ReadString("LoginCommand");
    if(Registry->ValueExists("ConfigCommand"))
    	ConfigCommand=Registry->ReadString("ConfigCommand");
    if(Registry->ValueExists("Password"))
    	Password=Registry->ReadString("Password");
    if(Registry->ValueExists("MinimizeToSysTray"))
    	MinimizeToSysTray=Registry->ReadBool("MinimizeToSysTray");
    if(Registry->ValueExists("UseFileAssociations"))
    	UseFileAssociations=Registry->ReadBool("UseFileAssociations");
	if(Registry->ValueExists("NodeDisplayInterval"))
    	NodeForm->Timer->Interval=Registry->ReadInteger("NodeDisplayInterval")*1000;
	if(Registry->ValueExists("ClientDisplayInterval"))
    	ClientForm->Timer->Interval=Registry->ReadInteger("ClientDisplayInterval")*1000;
    if(Registry->ValueExists("ErrorSoundFile"))
        ErrorSoundFile=Registry->ReadString("ErrorSoundFile");

    if(Registry->ValueExists("MailLogFile"))
    	MailLogFile=Registry->ReadInteger("MailLogFile");
    else
    	MailLogFile=true;

    if(Registry->ValueExists("FtpLogFile"))
    	FtpLogFile=Registry->ReadInteger("FtpLogFile");
    else
    	FtpLogFile=true;

	Registry->CloseKey();
    delete Registry;

    FILE* fp;
    if((fp=fopen(ini_file,"r"))==NULL) {
        char err[MAX_PATH*2];
        sprintf(err,"Error %d opening initialization file: %s",errno,ini_file);
        Application->MessageBox(err,"ERROR",MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
        return;
    }
    sbbs_read_ini(fp, MainForm->ini_file
        ,&global
        ,&SysAutoStart   		,&bbs_startup
        ,&FtpAutoStart 			,&ftp_startup
        ,&WebAutoStart 			,&web_startup
        ,&MailAutoStart 	    ,&mail_startup
        ,&ServicesAutoStart     ,&services_startup
        );
    StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Read " + AnsiString(ini_file);
    fclose(fp);

    AnsiString CtrlDirectory = AnsiString(global.ctrl_dir);
    if(!FileExists(CtrlDirectory+"MAIN.CNF")) {
		Application->CreateForm(__classid(TCtrlPathDialog), &CtrlPathDialog);
    	if(CtrlPathDialog->ShowModal()!=mrOk) {
        	Application->Terminate();
            return;
        }
        CtrlDirectory=CtrlPathDialog->Edit->Text;
        delete CtrlPathDialog;
    }
    if(CtrlDirectory.UpperCase().AnsiPos("MAIN.CNF"))
		CtrlDirectory.SetLength(CtrlDirectory.Length()-8);
    SAFECOPY(global.ctrl_dir,CtrlDirectory.c_str());
    memset(&cfg,0,sizeof(cfg));
    SAFECOPY(cfg.ctrl_dir,global.ctrl_dir);
    cfg.size=sizeof(cfg);
    cfg.node_num=bbs_startup.first_node;
    char error[256];
	SAFECOPY(error,UNKNOWN_LOAD_ERROR);

   	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Loading configuration...";
	if(!load_cfg(&cfg, /* text: */NULL, /* prep: */TRUE, /* node: */FALSE, error, sizeof(error))) {
    	Application->MessageBox(error,"ERROR Loading Configuration"
	        ,MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
        return;
    }
   	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Configuration loaded";

   	if(!NodeFormFloating)
    	NodeForm->ManualDock(PageControl(NodeFormPage),NULL,alClient);
	if(!ClientFormFloating)
    	ClientForm->ManualDock(PageControl(ClientFormPage),NULL,alClient);
	if(!StatsFormFloating)
    	StatsForm->ManualDock(PageControl(StatsFormPage),NULL,alClient);
	if(!MailFormFloating)
    	MailForm->ManualDock(PageControl(MailFormPage),NULL,alClient);
	if(!TelnetFormFloating)
    	TelnetForm->ManualDock(PageControl(TelnetFormPage),NULL,alClient);
	if(!EventsFormFloating)
    	EventsForm->ManualDock(PageControl(EventsFormPage),NULL,alClient);
	if(!ServicesFormFloating)
    	ServicesForm->ManualDock(PageControl(ServicesFormPage),NULL,alClient);
	if(!FtpFormFloating)
    	FtpForm->ManualDock(PageControl(FtpFormPage),NULL,alClient);
	if(!WebFormFloating)
    	WebForm->ManualDock(PageControl(WebFormPage),NULL,alClient);

	recycle_semfiles=semfile_list_init(cfg.ctrl_dir,"recycle","ctrl");
	semfile_list_add(&recycle_semfiles,ini_file);
	semfile_list_check(&initialized,recycle_semfiles);

	shutdown_semfiles=semfile_list_init(cfg.ctrl_dir,"shutdown","ctrl");
	semfile_list_check(&initialized,shutdown_semfiles);

    if(cfg.new_install) {
		Application->BringToFront();
		StartupTimer->Interval = 2500;	// Let 'em see the logo for a bit
		StartupTimer->Enabled = true;
	} else {
		DisplayMainPanels(Sender);
	}
    Initialized=true;
}

void __fastcall TMainForm::DisplayMainPanels(TObject* Sender)
{
	if(sound_muted(&cfg))
		SoundToggle->Checked=false;
	else
		SoundToggle->Checked=true;

	if(sysop_available(&cfg))
		ChatToggle->Checked=true;
	else
		ChatToggle->Checked=false;

    NodeForm->Show();
    ClientForm->Show();
    StatsForm->Show();
    TelnetForm->Show();
    EventsForm->Show();
    FtpForm->Show();
    WebForm->Show();
    MailForm->Show();
    ServicesForm->Show();

	UpperLeftPageControl->Visible=true;
	UpperRightPageControl->Visible=true;
	LowerLeftPageControl->Visible=true;
	LowerRightPageControl->Visible=true;
	HorizontalSplitter->Visible=true;
	BottomPanel->Visible=true;
	TopPanel->Visible=true;

    // Work-around for CB5 PageControl anomaly
    int i;

    for(i=1;i<UpperLeftPageControl->PageCount;i++)
        UpperLeftPageControl->ActivePageIndex=i;
    UpperLeftPageControl->ActivePageIndex=0;

    for(i=1;i<UpperRightPageControl->PageCount;i++)
        UpperRightPageControl->ActivePageIndex=i;
    UpperRightPageControl->ActivePageIndex=0;

    for(i=1;i<LowerRightPageControl->PageCount;i++)
        LowerRightPageControl->ActivePageIndex=i;
    LowerRightPageControl->ActivePageIndex=0;

    for(i=1;i<LowerLeftPageControl->PageCount;i++)
        LowerLeftPageControl->ActivePageIndex=i;
    LowerLeftPageControl->ActivePageIndex=0;

    /* Open Log Mailslots */
    LogTimerTick(Sender);

    /* Query service config lengths */
	ServiceStatusTimerTick(Sender);

    if(SysAutoStart)
       TelnetStartExecute(Sender);
    if(MailAutoStart)
        MailStartExecute(Sender);
    if(FtpAutoStart)
        FtpStartExecute(Sender);
    if(WebAutoStart)
        WebStartExecute(Sender);
    if(ServicesAutoStart)
        ServicesStartExecute(Sender);

    NodeForm->Timer->Enabled=true;
    ClientForm->Timer->Enabled=true;

    SemFileTimer->Interval=global.sem_chk_freq*1000;
    SemFileTimer->Enabled=true;

    StatsTimer->Interval=cfg.node_stat_check*1000;
	StatsTimer->Enabled=true;

    UpTimer->Enabled=true; /* Start updating the status bar */
    LogTimer->Enabled=true;
                
    ServiceStatusTimer->Enabled=true;

	SetControls();

	if(!Application->Active)	/* Starting up minimized? */
		FormMinimize(Sender);   /* Put icon in systray */
}

//---------------------------------------------------------------------------
void __fastcall TMainForm::SaveRegistrySettings(TObject* Sender)
{
	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Saving Registry Settings...";

    // Write Registry keys
	TRegistry* Registry=new TRegistry;
    if(!Registry->OpenKey(REG_KEY,true)) {
    	Application->MessageBox("Error creating registry key"
        	,REG_KEY,MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
        return;
    }
    Registry->WriteInteger("MainFormTop",Top);
    Registry->WriteInteger("MainFormLeft",Left);
    Registry->WriteInteger("MainFormHeight",Height);
    Registry->WriteInteger("MainFormWidth",Width);

    Registry->WriteInteger("NodeFormTop",NodeForm->Top);
    Registry->WriteInteger("NodeFormLeft",NodeForm->Left);
    Registry->WriteInteger("NodeFormHeight",NodeForm->Height);
    Registry->WriteInteger("NodeFormWidth",NodeForm->Width);
    Registry->WriteInteger("NodeFormMonitor",NodeForm->DefaultMonitor);

    Registry->WriteInteger("StatsFormTop",StatsForm->Top);
    Registry->WriteInteger("StatsFormLeft",StatsForm->Left);
    Registry->WriteInteger("StatsFormHeight",StatsForm->Height);
    Registry->WriteInteger("StatsFormWidth",StatsForm->Width);
    Registry->WriteInteger("StatsFormMonitor",StatsForm->DefaultMonitor);

    Registry->WriteInteger("ClientFormTop",ClientForm->Top);
    Registry->WriteInteger("ClientFormLeft",ClientForm->Left);
    Registry->WriteInteger("ClientFormHeight",ClientForm->Height);
    Registry->WriteInteger("ClientFormWidth",ClientForm->Width);
    Registry->WriteInteger("ClientFormMonitor",ClientForm->DefaultMonitor);

    for(int i=0;i<ClientForm->ListView->Columns->Count;i++) {
        char str[128];
        sprintf(str,"ClientListColumn%dWidth",i);
        Registry->WriteInteger(str
            ,ClientForm->ListView->Columns->Items[i]->Width);
    }
    
    Registry->WriteInteger("TelnetFormTop",TelnetForm->Top);
    Registry->WriteInteger("TelnetFormLeft",TelnetForm->Left);
    Registry->WriteInteger("TelnetFormHeight",TelnetForm->Height);
    Registry->WriteInteger("TelnetFormWidth",TelnetForm->Width);
    Registry->WriteInteger("TelnetFormMonitor",TelnetForm->DefaultMonitor);

    Registry->WriteInteger("EventsFormTop",EventsForm->Top);
    Registry->WriteInteger("EventsFormLeft",EventsForm->Left);
    Registry->WriteInteger("EventsFormHeight",EventsForm->Height);
    Registry->WriteInteger("EventsFormWidth",EventsForm->Width);
    Registry->WriteInteger("EventsFormMonitor",EventsForm->DefaultMonitor);

    Registry->WriteInteger("ServicesFormTop",ServicesForm->Top);
    Registry->WriteInteger("ServicesFormLeft",ServicesForm->Left);
    Registry->WriteInteger("ServicesFormHeight",ServicesForm->Height);
    Registry->WriteInteger("ServicesFormWidth",ServicesForm->Width);
    Registry->WriteInteger("ServicesFormMonitor",ServicesForm->DefaultMonitor);

    Registry->WriteInteger("FtpFormTop",FtpForm->Top);
    Registry->WriteInteger("FtpFormLeft",FtpForm->Left);
    Registry->WriteInteger("FtpFormHeight",FtpForm->Height);
    Registry->WriteInteger("FtpFormWidth",FtpForm->Width);
    Registry->WriteInteger("FtpFormMonitor",FtpForm->DefaultMonitor);

    Registry->WriteInteger("WebFormTop",WebForm->Top);
    Registry->WriteInteger("WebFormLeft",WebForm->Left);
    Registry->WriteInteger("WebFormHeight",WebForm->Height);
    Registry->WriteInteger("WebFormWidth",WebForm->Width);
    Registry->WriteInteger("WebFormMonitor",WebForm->DefaultMonitor);

    Registry->WriteInteger("MailFormTop",MailForm->Top);
    Registry->WriteInteger("MailFormLeft",MailForm->Left);
    Registry->WriteInteger("MailFormHeight",MailForm->Height);
    Registry->WriteInteger("MailFormWidth",MailForm->Width);
    Registry->WriteInteger("MailFormMonitor",MailForm->DefaultMonitor);    

    Registry->WriteInteger("TopPanelHeight",TopPanel->Height);
 	Registry->WriteInteger("UpperLeftPageControlWidth"
    	,UpperLeftPageControl->Width);
    Registry->WriteInteger("LowerLeftPageControlWidth"
    	,LowerLeftPageControl->Width);
    Registry->WriteBool("UndockableForms",UndockableForms);

    Registry->WriteBool("TelnetFormFloating",TelnetForm->Floating);
    Registry->WriteBool("EventsFormFloating",EventsForm->Floating);
    Registry->WriteBool("ServicesFormFloating",ServicesForm->Floating);
    Registry->WriteBool("NodeFormFloating",NodeForm->Floating);
    Registry->WriteBool("StatsFormFloating",StatsForm->Floating);
    Registry->WriteBool("ClientFormFloating",ClientForm->Floating);
    Registry->WriteBool("FtpFormFloating",FtpForm->Floating);
    Registry->WriteBool("WebFormFloating",WebForm->Floating);
    Registry->WriteBool("MailFormFloating",MailForm->Floating);

    Registry->WriteBool("TelnetFormVisible",TelnetForm->Visible);
    Registry->WriteBool("EventsFormVisible",EventsForm->Visible);
    Registry->WriteBool("ServicesFormVisible",ServicesForm->Visible);
    Registry->WriteBool("NodeFormVisible",NodeForm->Visible);
    Registry->WriteBool("StatsFormVisible",StatsForm->Visible);
    Registry->WriteBool("ClientFormVisible",ClientForm->Visible);
    Registry->WriteBool("FtpFormVisible",FtpForm->Visible);
    Registry->WriteBool("WebFormVisible",WebForm->Visible);
    Registry->WriteBool("MailFormVisible",MailForm->Visible);

    Registry->WriteInteger("TelnetFormPage"
	    ,PageNum((TPageControl*)TelnetForm->HostDockSite));
    Registry->WriteInteger("EventsFormPage"
	    ,PageNum((TPageControl*)EventsForm->HostDockSite));
    Registry->WriteInteger("ServicesFormPage"
	    ,PageNum((TPageControl*)ServicesForm->HostDockSite));
    Registry->WriteInteger("NodeFormPage"
    	,PageNum((TPageControl*)NodeForm->HostDockSite));
    Registry->WriteInteger("MailFormPage"
    	,PageNum((TPageControl*)MailForm->HostDockSite));
    Registry->WriteInteger("FtpFormPage"
    	,PageNum((TPageControl*)FtpForm->HostDockSite));
    Registry->WriteInteger("WebFormPage"
    	,PageNum((TPageControl*)WebForm->HostDockSite));
    Registry->WriteInteger("StatsFormPage"
    	,PageNum((TPageControl*)StatsForm->HostDockSite));
    Registry->WriteInteger("ClientFormPage"
    	,PageNum((TPageControl*)ClientForm->HostDockSite));

    WriteColor(Registry,"TelnetLog",TelnetForm->Log->Color);
    WriteFont("TelnetLog",TelnetForm->Log->Font);
    WriteColor(Registry,"EventsLog",EventsForm->Log->Color);
    WriteFont("EventsLog",EventsForm->Log->Font);
    WriteColor(Registry,"ServicesLog",ServicesForm->Log->Color);
    WriteFont("ServicesLog",ServicesForm->Log->Font);
    WriteColor(Registry,"MailLog",MailForm->Log->Color);
    WriteFont("MailLog",MailForm->Log->Font);
    WriteColor(Registry,"FtpLog",FtpForm->Log->Color);
    WriteFont("FtpLog",FtpForm->Log->Font);
    WriteColor(Registry,"WebLog",WebForm->Log->Color);
    WriteFont("WebLog",WebForm->Log->Font);
    WriteColor(Registry,"NodeList",NodeForm->ListBox->Color);
    WriteFont("NodeList",NodeForm->ListBox->Font);
    WriteColor(Registry,"ClientList",ClientForm->ListView->Color);
    WriteFont("ClientList",ClientForm->ListView->Font);

    {
        int i;

        for(i=LOG_EMERG;i<=LOG_DEBUG;i++) {
			if(i != LOG_INFO)
				WriteFont("Log" + AnsiString(LogLevelDesc[i]), LogFont[i]);
		}
    }

    Registry->WriteBool("ToolBarVisible",Toolbar->Visible);
    Registry->WriteBool("StatusBarVisible",StatusBar->Visible);
    Registry->WriteInteger("MaxLogLen",MaxLogLen);

    Registry->WriteString("LoginCommand",LoginCommand);
    Registry->WriteString("ConfigCommand",ConfigCommand);
    Registry->WriteString("Password",Password);
    Registry->WriteBool("MinimizeToSysTray",MinimizeToSysTray);
    Registry->WriteBool("UseFileAssociations",UseFileAssociations);
    Registry->WriteInteger("NodeDisplayInterval",NodeForm->Timer->Interval/1000);
    Registry->WriteInteger("ClientDisplayInterval",ClientForm->Timer->Interval/1000);
    Registry->WriteString("ErrorSoundFile",ErrorSoundFile);

	Registry->WriteInteger( "SpyTerminalWidth"
                            ,SpyTerminalWidth);
	Registry->WriteInteger( "SpyTerminalHeight"
                            ,SpyTerminalHeight);
   	Registry->WriteString(  "SpyTerminalFontName"
                            ,SpyTerminalFont->Name);
	Registry->WriteInteger( "SpyTerminalFontSize"
                            ,SpyTerminalFont->Size);
	Registry->WriteBool(    "SpyTerminalKeyboardActive"
                            ,SpyTerminalKeyboardActive);

    Registry->CloseKey();
    delete Registry;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::SaveSettings(TObject* Sender)
{
    SaveIniSettings(Sender);
    SaveRegistrySettings(Sender);
}
//---------------------------------------------------------------------------
bool __fastcall TMainForm::SaveIniSettings(TObject* Sender)
{
    FILE* fp=NULL;
   	if(ini_file[0]==0 || !Initialized)
        return(false);

    if((fp=fopen(ini_file,"r+"))==NULL) {
        char err[MAX_PATH*2];
        SAFEPRINTF2(err,"Error %d opening initialization file: %s",errno,ini_file);
        Application->MessageBox(err,"ERROR",MB_OK|MB_ICONEXCLAMATION);
        return(false);
    }

	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Saving Settings to " + AnsiString(ini_file) + " ...";

    bool success = sbbs_write_ini(fp
        ,&cfg
        ,&global
        ,SysAutoStart		,&bbs_startup
        ,FtpAutoStart		,&ftp_startup
        ,WebAutoStart		,&web_startup
        ,MailAutoStart		,&mail_startup
        ,ServicesAutoStart	,&services_startup
        );
    fclose(fp);

	if(!success) {
		char err[MAX_PATH*2];
        SAFEPRINTF(err,"Failure writing initialization file: %s",ini_file);
        Application->MessageBox(err,"ERROR",MB_OK|MB_ICONEXCLAMATION);
	}

   	semfile_list_check(&initialized,recycle_semfiles);    
    return(success);
}

//---------------------------------------------------------------------------
void __fastcall TMainForm::ImportFormSettings(TMemIniFile* IniFile, const char* section, TForm* Form)
{
   	Form->Top=IniFile->ReadInteger(section,"Top",Form->Top);
   	Form->Left=IniFile->ReadInteger(section,"Left",Form->Left);
   	Form->Width=IniFile->ReadInteger(section,"Width",Form->Width);
   	Form->Height=IniFile->ReadInteger(section,"Height",Form->Height);
   	Form->DefaultMonitor=(TDefaultMonitor)IniFile->ReadInteger(section,"Monitor",Form->DefaultMonitor);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ExportFormSettings(TMemIniFile* IniFile, const char* section, TForm* Form)
{
    IniFile->WriteInteger(section,"Top",Form->Top);
    IniFile->WriteInteger(section,"Left",Form->Left);
    IniFile->WriteInteger(section,"Width",Form->Width);
    IniFile->WriteInteger(section,"Height",Form->Height);
    IniFile->WriteInteger(section,"Page",PageNum((TPageControl*)Form->HostDockSite));
    IniFile->WriteBool(section,"Floating",Form->Floating);
    IniFile->WriteInteger(section,"Monitor",Form->DefaultMonitor);    
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ImportFont(TMemIniFile* IniFile, const char* section, AnsiString prefix, TFont* Font)
{
    Font->Name=IniFile->ReadString(section,prefix + "Name",Font->Name);
    Font->Color=StringToColor(IniFile->ReadString(section,prefix + "Color",ColorToString(Font->Color)));
    Font->Height=IniFile->ReadInteger(section,prefix + "Height",Font->Height);
    Font->Size=IniFile->ReadInteger(section,prefix + "Size", Font->Size);
    IntToFontStyle(IniFile->ReadInteger(section,prefix + "Style",FontStyleToInt(Font)),Font);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ExportFont(TMemIniFile* IniFile, const char* section, AnsiString prefix, TFont* Font)
{
    IniFile->WriteString(section,prefix+"Name",Font->Name);
    IniFile->WriteString(section,prefix+"Color",ColorToString(Font->Color));
    IniFile->WriteInteger(section,prefix+"Height",Font->Height);
    IniFile->WriteInteger(section,prefix+"Size",Font->Size);
    IniFile->WriteInteger(section,prefix+"Style",FontStyleToInt(Font));
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ImportSettings(TObject* Sender)
{
    OpenDialog->Filter="Settings files (*.ini)|*.ini|All files|*.*";
    OpenDialog->FileName=AnsiString(global.ctrl_dir)+"sbbsctrl*.ini";
    if(!OpenDialog->Execute())
    	return;

	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Importing Settings...";

	TMemIniFile* IniFile=new TMemIniFile(OpenDialog->FileName);

    const char* section = "Properties";

   	LoginCommand=IniFile->ReadString(section,"LoginCommand",LoginCommand);
    ConfigCommand=IniFile->ReadString(section,"ConfigCommand",ConfigCommand);
   	Password=IniFile->ReadString(section,"Password",Password);
   	MinimizeToSysTray=IniFile->ReadBool(section,"MinimizeToSysTray",MinimizeToSysTray);
   	UseFileAssociations=IniFile->ReadBool(section,"UseFileAssociations"	,UseFileAssociations);
    UndockableForms=IniFile->ReadBool(section,"UndockableForms",UndockableForms);

    ImportFormSettings(IniFile,section="MainForm",MainForm);
   	TopPanel->Height=IniFile->ReadInteger(section,"TopPanelHeight",TopPanel->Height);
   	UpperLeftPageControl->Width=IniFile->ReadInteger(section,"UpperLeftPageControlWidth",UpperLeftPageControl->Width);
   	LowerLeftPageControl->Width=IniFile->ReadInteger(section,"LowerLeftPageControlWidth",LowerLeftPageControl->Width);
    Toolbar->Visible=IniFile->ReadBool(section,"ToolBarVisible",Toolbar->Visible);
    StatusBar->Visible=IniFile->ReadBool(section,"StatusBarVisible",StatusBar->Visible);

    ImportFormSettings(IniFile,section="TelnetForm",TelnetForm);
    ImportFont(IniFile,section,"LogFont",TelnetForm->Log->Font);
    TelnetForm->Log->Color=StringToColor(IniFile->ReadString(section,"LogColor",clWindow));

    ImportFormSettings(IniFile,section="EventsForm",EventsForm);
    ImportFont(IniFile,section,"LogFont",EventsForm->Log->Font);
    EventsForm->Log->Color=StringToColor(IniFile->ReadString(section,"LogColor",clWindow));

    ImportFormSettings(IniFile,section="ServicesForm",ServicesForm);
    ImportFont(IniFile,section,"LogFont",ServicesForm->Log->Font);
    ServicesForm->Log->Color=StringToColor(IniFile->ReadString(section,"LogColor",clWindow));

    ImportFormSettings(IniFile,section="FtpForm",FtpForm);
    ImportFont(IniFile,section,"LogFont",FtpForm->Log->Font);
   	FtpLogFile=IniFile->ReadInteger(section,"LogFile",true);
    FtpForm->Log->Color=StringToColor(IniFile->ReadString(section,"LogColor",clWindow));

    ImportFormSettings(IniFile,section="WebForm",WebForm);
    ImportFont(IniFile,section,"LogFont",WebForm->Log->Font);
    WebForm->Log->Color=StringToColor(IniFile->ReadString(section,"LogColor",clWindow));

    ImportFormSettings(IniFile,section="MailForm",MailForm);
    ImportFont(IniFile,section,"LogFont",MailForm->Log->Font);
   	MailLogFile=IniFile->ReadInteger(section,"LogFile",true);
    MailForm->Log->Color=StringToColor(IniFile->ReadString(section,"LogColor",clWindow));

    ImportFormSettings(IniFile,section="NodeForm",NodeForm);
    ImportFont(IniFile,section,"ListFont",NodeForm->ListBox->Font);
    NodeForm->Timer->Interval=IniFile->ReadInteger(section,"DisplayInterval"
        ,NodeForm->Timer->Interval/1000)*1000;
    NodeForm->ListBox->Color=StringToColor(IniFile->ReadString(section,"ListColor",clWindow));

    ImportFormSettings(IniFile,section="StatsForm",StatsForm);

    ImportFormSettings(IniFile,section="ClientForm",ClientForm);
    ImportFont(IniFile,section,"ListFont",ClientForm->ListView->Font);
    ClientForm->ListView->Color=StringToColor(IniFile->ReadString(section,"ListColor",clWindow));
    ClientForm->Timer->Interval=IniFile->ReadInteger(section,"DisplayInterval"
        ,ClientForm->Timer->Interval/1000)*1000;
    for(int i=0;i<ClientForm->ListView->Columns->Count;i++) {
        char str[128];
        sprintf(str,"Column%dWidth",i);
        if(IniFile->ValueExists(section,str))
            ClientForm->ListView->Columns->Items[i]->Width
                =IniFile->ReadInteger(section,str,0);
    }

    {
        int i;

        for(i=LOG_EMERG; i<=LOG_DEBUG; i++) {
			if(i != LOG_INFO)
				ImportFont(IniFile, ("Log" + AnsiString(LogLevelDesc[i]) + "Font").c_str(), "", LogFont[i]);
		}
    }

    section = "SpyTerminal";
	SpyTerminalWidth=IniFile->ReadInteger(section, "Width", SpyTerminalWidth);
	SpyTerminalHeight=IniFile->ReadInteger(section, "Height", SpyTerminalHeight);
   	SpyTerminalFont->Name=IniFile->ReadString(section, "FontName", SpyTerminalFont->Name);
	SpyTerminalFont->Size=IniFile->ReadInteger(section, "FontSize", SpyTerminalFont->Size);
	SpyTerminalKeyboardActive=IniFile->ReadBool(section, "KeyboardActive", SpyTerminalKeyboardActive);

    delete IniFile;

    Application->MessageBox(AnsiString("Successfully imported SBBSCTRL settings from "
    	+ OpenDialog->FileName).c_str(),"Successful Import",MB_OK);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ExportSettings(TObject* Sender)
{
	char str[128];

    SaveDialog->Filter="Settings files (*.ini)|*.ini|All files|*.*";
    SaveDialog->FileName=AnsiString(global.ctrl_dir)+"sbbsctrl.ini";
    if(!SaveDialog->Execute())
    	return;

	TMemIniFile* IniFile=new TMemIniFile(SaveDialog->FileName);

	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Exporting Settings...";

    const char* section = "Properties";

    IniFile->WriteString(section,"LoginCommand",LoginCommand);
    IniFile->WriteString(section,"ConfigCommand",ConfigCommand);
    IniFile->WriteString(section,"Password",Password);
    IniFile->WriteBool(section,"MinimizeToSysTray",MinimizeToSysTray);
    IniFile->WriteBool(section,"UseFileAssociations",UseFileAssociations);
    IniFile->WriteBool(section,"UndockableForms",UndockableForms);

    ExportFormSettings(IniFile,section="MainForm",MainForm);
    IniFile->WriteInteger(section,"TopPanelHeight",TopPanel->Height);
 	IniFile->WriteInteger(section,"UpperLeftPageControlWidth",UpperLeftPageControl->Width);
    IniFile->WriteInteger(section,"LowerLeftPageControlWidth",LowerLeftPageControl->Width);
    IniFile->WriteBool(section,"ToolBarVisible",Toolbar->Visible);
    IniFile->WriteBool(section,"StatusBarVisible",StatusBar->Visible);

    ExportFormSettings(IniFile,section = "NodeForm",NodeForm);
    ExportFont(IniFile,section,"ListFont",NodeForm->ListBox->Font);
    IniFile->WriteString(section,"ListColor",ColorToString(NodeForm->ListBox->Color));
    IniFile->WriteInteger(section,"DisplayInterval",NodeForm->Timer->Interval/1000);

    ExportFormSettings(IniFile,section = "StatsForm",StatsForm);

    ExportFormSettings(IniFile,section = "ClientForm",ClientForm);
    ExportFont(IniFile,section,"ListFont",ClientForm->ListView->Font);
    IniFile->WriteString(section,"ListColor",ColorToString(ClientForm->ListView->Color));
    IniFile->WriteInteger(section,"DisplayInterval",ClientForm->Timer->Interval/1000);
    for(int i=0;i<ClientForm->ListView->Columns->Count;i++) {
        char str[128];
        sprintf(str,"Column%dWidth",i);
        IniFile->WriteInteger(section,str
            ,ClientForm->ListView->Columns->Items[i]->Width);
    }

    ExportFormSettings(IniFile,section = "TelnetForm",TelnetForm);
    ExportFont(IniFile,section,"LogFont",TelnetForm->Log->Font);
    IniFile->WriteString(section,"LogColor",ColorToString(TelnetForm->Log->Color));

    ExportFormSettings(IniFile,section = "EventsForm",EventsForm);
    ExportFont(IniFile,section,"LogFont",EventsForm->Log->Font);
    IniFile->WriteString(section,"LogColor",ColorToString(EventsForm->Log->Color));

    ExportFormSettings(IniFile,section = "ServicesForm",ServicesForm);
    ExportFont(IniFile,section,"LogFont",ServicesForm->Log->Font);
    IniFile->WriteString(section,"LogColor",ColorToString(ServicesForm->Log->Color));

    ExportFormSettings(IniFile,section = "FtpForm",FtpForm);
    ExportFont(IniFile,section,"LogFont",FtpForm->Log->Font);
    IniFile->WriteString(section,"LogColor",ColorToString(FtpForm->Log->Color));

    ExportFormSettings(IniFile,section = "MailForm",MailForm);
    ExportFont(IniFile,section,"LogFont",MailForm->Log->Font);
    IniFile->WriteString(section,"LogColor",ColorToString(MailForm->Log->Color));

    ExportFormSettings(IniFile,section = "WebForm",WebForm);
    ExportFont(IniFile,section,"LogFont",WebForm->Log->Font);
    IniFile->WriteString(section,"LogColor",ColorToString(WebForm->Log->Color));

    {
        int i;

        for(i=LOG_EMERG; i<=LOG_DEBUG; i++) {
			if(i != LOG_INFO)
				ExportFont(IniFile, ("Log" + AnsiString(LogLevelDesc[i]) + "Font").c_str(), "", LogFont[i]);
		}
    }

    section = "SpyTerminal";
	IniFile->WriteInteger(section, "Width"
                            ,SpyTerminalWidth);
	IniFile->WriteInteger(section, "Height"
                            ,SpyTerminalHeight);
   	IniFile->WriteString(section,  "FontName"
                            ,SpyTerminalFont->Name);
	IniFile->WriteInteger(section, "FontSize"
                            ,SpyTerminalFont->Size);
	IniFile->WriteBool(section,    "KeyboardActive"
                            ,SpyTerminalKeyboardActive);

    IniFile->UpdateFile();

    delete IniFile;

    Application->MessageBox(AnsiString("Successfully exported SBBSCTRL settings to "
    	+ SaveDialog->FileName).c_str(),"Successful Export",MB_OK);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ViewStatusBarMenuItemClick(TObject *Sender)
{
	StatusBar->Visible=!StatusBar->Visible;
    ViewStatusBarMenuItem->Checked=StatusBar->Visible;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::HelpAboutMenuItemClick(TObject *Sender)
{
	Application->CreateForm(__classid(TAboutBoxForm), &AboutBoxForm);
    AboutBoxForm->ShowModal();
    delete AboutBoxForm;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::SoundToggleExecute(TObject *Sender)
{
    SoundToggle->Checked=!SoundToggle->Checked;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::BBSStatisticsLogMenuItemClick(TObject *Sender)
{
	StatsForm->LogButtonClick(Sender);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ForceTimedEventMenuItemClick(TObject *Sender)
{
	int i,file;
	char str[MAX_PATH+1];
	static int selection;

	Application->CreateForm(__classid(TCodeInputForm), &CodeInputForm);
	CodeInputForm->Label->Caption="Event Internal Code";
    CodeInputForm->ComboBox->Items->Clear();
    for(i=0;i<cfg.total_events;i++)
    	CodeInputForm->ComboBox->Items->Add(
            AnsiString(cfg.event[i]->code).UpperCase());
    CodeInputForm->ComboBox->ItemIndex=selection;
    if(CodeInputForm->ShowModal()==mrOk
       	&& CodeInputForm->ComboBox->Text.Length()) {
        for(i=0;i<cfg.total_events;i++) {
			if(!stricmp(CodeInputForm->ComboBox->Text.c_str(),cfg.event[i]->code)) {
				sprintf(str,"%s%s.now",cfg.data_dir,cfg.event[i]->code);
            	if((file=_sopen(str,O_CREAT|O_TRUNC|O_WRONLY
	                ,SH_DENYRW,S_IREAD|S_IWRITE))!=-1)
	                close(file);
				selection = CodeInputForm->ComboBox->ItemIndex;
                break;
	   		}
        }
        if(i>=cfg.total_events)
	    	Application->MessageBox(CodeInputForm->ComboBox->Text.c_str()
                ,"Event Code Not Found",MB_OK|MB_ICONEXCLAMATION);
    }
    delete CodeInputForm;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ForceNetworkCalloutMenuItemClick(
      TObject *Sender)
{
	int i,file;
	char str[MAX_PATH+1];

	Application->CreateForm(__classid(TCodeInputForm), &CodeInputForm);
	CodeInputForm->Label->Caption="Hub QWK-ID";
    CodeInputForm->ComboBox->Items->Clear();
    for(i=0;i<cfg.total_qhubs;i++)
    	CodeInputForm->ComboBox->Items->Add(
            AnsiString(cfg.qhub[i]->id).UpperCase());
    CodeInputForm->ComboBox->ItemIndex=0;
    if(CodeInputForm->ShowModal()==mrOk
    	&& CodeInputForm->ComboBox->Text.Length()) {
        for(i=0;i<cfg.total_qhubs;i++) {
			if(!stricmp(CodeInputForm->ComboBox->Text.c_str(),cfg.qhub[i]->id)) {
				sprintf(str,"%sqnet/%s.now",cfg.data_dir,cfg.qhub[i]->id);
            	if((file=_sopen(str,O_CREAT|O_TRUNC|O_WRONLY
                	,SH_DENYRW,S_IREAD|S_IWRITE))!=-1)
	                close(file);
                break;
	   		}
        }
        if(i>=cfg.total_qhubs)
	    	Application->MessageBox(CodeInputForm->ComboBox->Text.c_str()
                ,"QWKnet Hub ID Not Found",MB_OK|MB_ICONEXCLAMATION);
    }
    delete CodeInputForm;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TextMenuItemEditClick(TObject *Sender)
{
	char filename[MAX_PATH+1];

    sprintf(filename,"%s%s"
    	,MainForm->cfg.text_dir
        ,((TMenuItem*)Sender)->Hint.c_str());
    EditFile(filename,((TMenuItem*)Sender)->Caption);
}

//---------------------------------------------------------------------------
void __fastcall TMainForm::CtrlMenuItemEditClick(TObject *Sender)
{
	char filename[MAX_PATH+1];

    iniFileName(filename,sizeof(filename)
    	,MainForm->cfg.ctrl_dir
        ,((TMenuItem*)Sender)->Hint.c_str());
    EditFile(filename,((TMenuItem*)Sender)->Caption);
}
void __fastcall TMainForm::DataMenuItemClick(TObject *Sender)
{
	char filename[MAX_PATH+1];

    sprintf(filename,"%s%s"
    	,MainForm->cfg.data_dir
        ,((TMenuItem*)Sender)->Hint.c_str());
    EditFile(filename,((TMenuItem*)Sender)->Caption);
}
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------

void __fastcall TMainForm::UpTimerTick(TObject *Sender)
{
	char    str[128];
    char    days[64];
    static  time_t start;
    ulong   up;
    static  bool sysop_available;
	static	bool sound_muted;

    if(ChatToggle->Checked != sysop_available) {
        sysop_available = ChatToggle->Checked;
        set_sysop_availability(&cfg, sysop_available);
    }
	
    if(SoundToggle->Checked != !sound_muted) {
        sound_muted = !SoundToggle->Checked;
        set_sound_muted(&cfg, sound_muted);
    }
	
	if(clearLoginAttemptList) {
		loginAttemptListClear(&login_attempt_list);
		clearLoginAttemptList = false;
	}

    if(!start)
        start=time(NULL);
    up=time(NULL)-start;

    days[0]=0;
    if((up/(24*60*60))>=2) {
        sprintf(days,"%u days ",up/(24*60*60));
        up%=(24*60*60);
    }
		
	for(int i = 0; i <= STATUSBAR_LAST_PANEL; i++) {
		switch(i) {
			case 0:
				sprintf(str,"Threads: %u",threads);
				break;
			case 1:
				sprintf(str,"Sockets: %u",sockets);
				break;
			case 2:
				sprintf(str,"Clients: %u",clients);
				break;
			case 3:
			    sprintf(str,"Served: %u",total_clients);
				break;
			case 4:
				sprintf(str,"Failed: %u",loginAttemptListCount(&login_attempt_list));
				break;
			case 5:
				sprintf(str,"Errors: %u",errors);
				break;
			default:
				sprintf(str,"Up: %s%u:%02u"
					,days
					,up/(60*60)
					,(up/60)%60
					);
		}
		TStatusPanel* panel = MainForm->StatusBar->Panels->Items[i];	
		
		AnsiString Str = AnsiString(str);
		if(panel->Text != Str) {
			panel->Text = Str;
//			panel->Bevel = pbRaised;
		} else {
//			panel->Bevel = pbLowered;
		}
	}
	
    if(TrayIcon->Visible) {
        /* Animate TrayIcon when in use */
        AnsiString NumClients;
        try {
            if(clients) {
                TrayIcon->IconIndex=(TrayIcon->IconIndex==4) ? 59 : 4;
                NumClients=" ("+AnsiString(clients)+" client";
                if(clients>1)
                    NumClients+="s";
                NumClients+=")";
            } else if(TrayIcon->IconIndex!=4)
                TrayIcon->IconIndex=4;
            TrayIcon->Hint=AnsiString(APP_TITLE)+NumClients;
        } catch(...) { /* ignore exceptions here */ };
    }
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::ChatToggleExecute(TObject *Sender)
{
    ChatToggle->Checked=!ChatToggle->Checked;
}

//---------------------------------------------------------------------------
void __fastcall TMainForm::UserEditExecute(TObject *Sender)
{
    char str[256];

    sprintf(str,"%sUSEREDIT %s",cfg.exec_dir,cfg.data_dir);
    WinExec(str,SW_SHOWNORMAL);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::BBSPreviewMenuItemClick(TObject *Sender)
{
    TOpenDialog* dlg=new TOpenDialog((TComponent*)Sender);

    dlg->Options << ofNoChangeDir;
    dlg->Filter = "ANSI/Ctrl-A files (*.asc; *.msg; *.ans)|*.ASC;*.MSG;*.ANS"
                "|All files|*.*";
    dlg->InitialDir=cfg.text_dir;
    if(dlg->Execute()==true) {
        Application->CreateForm(__classid(TPreviewForm), &PreviewForm);
        PreviewForm->Filename=AnsiString(dlg->FileName);
        PreviewForm->ShowModal();
        delete PreviewForm;
    }
    delete dlg;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::BBSLoginMenuItemClick(TObject *Sender)
{
    if(!strnicmp(LoginCommand.c_str(),"start ",6)) /* Doesn't work on NT */
        ShellExecute(Handle, "open", LoginCommand.c_str()+6,
            NULL,NULL,SW_SHOWDEFAULT);
    else if(!strnicmp(LoginCommand.c_str(),"telnet:",7))
        ShellExecute(Handle, "open", LoginCommand.c_str(),
            NULL,NULL,SW_SHOWDEFAULT);
    else
        WinExec(LoginCommand.c_str(),SW_SHOWNORMAL);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewLogClick(TObject *Sender)
{
    char    str[128];
	char    filename[MAX_PATH+1];
    struct  tm* tm;
    time_t  t;
    TModalResult mr;

    if(((TMenuItem*)Sender)->Tag==-1) {
    	Application->CreateForm(__classid(TCodeInputForm), &CodeInputForm);
    	CodeInputForm->Label->Caption="Date";
        CodeInputForm->ComboBox->Items->Clear();
       	CodeInputForm->ComboBox->Text=AnsiString(unixtodstr(&cfg,time(NULL),str));
        mr=CodeInputForm->ShowModal();
        t=dstrtounix(&cfg,CodeInputForm->ComboBox->Text.c_str());
        delete CodeInputForm;
        if(mr!=mrOk)
            return;
    } else {
        t=time(NULL);
        t-=((TMenuItem*)Sender)->Tag*24*60*60;
    }
    tm=localtime(&t);
    if(tm==NULL)
        return;

    /* Close Mail/FTP logs */
    mail_log_msg(NULL);
    ftp_log_msg(NULL);

    if(strchr(((TMenuItem*)Sender)->Hint.c_str(),'.')==NULL)
        sprintf(filename,"%sLOGS\\%s%02d%02d%02d.LOG"
            ,MainForm->cfg.logs_dir
            ,((TMenuItem*)Sender)->Hint.c_str()
            ,tm->tm_mon+1
            ,tm->tm_mday
            ,tm->tm_year%100
            );
    else
        sprintf(filename,"%s\\%s"
            ,MainForm->cfg.logs_dir
            ,((TMenuItem*)Sender)->Hint.c_str()
        );
    ViewFile(filename,((TMenuItem*)Sender)->Caption);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::RunJSClick(TObject *Sender)
{
	char    cmdline[MAX_PATH+1];

    SAFEPRINTF2(cmdline,"%sjsexec.exe -p %s"
        ,MainForm->cfg.exec_dir
        ,((TMenuItem*)Sender)->Hint.c_str()
        );
    STARTUPINFO startup_info={0};
    PROCESS_INFORMATION process_info;
    startup_info.cb=sizeof(startup_info);
    startup_info.lpTitle = cmdline;
	if(!CreateProcess(
		NULL,			// pointer to name of executable module
		cmdline,        // pointer to command line string
		NULL,  			// process security attributes
		NULL,   		// thread security attributes
		FALSE, 			// handle inheritance flag
		0,              // creation flags
        NULL,  			// pointer to new environment block
		cfg.ctrl_dir,	// pointer to current directory name
		&startup_info,  // pointer to STARTUPINFO
		&process_info  	// pointer to PROCESS_INFORMATION
		))
       	Application->MessageBox(AnsiString("ERROR " + IntToStr(GetLastError()) +
            " executing " + cmdline).c_str()
            ,"ERROR"
            ,MB_OK|MB_ICONEXCLAMATION);
	// Resource leak if you don't close these:
	CloseHandle(process_info.hThread);
	CloseHandle(process_info.hProcess);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::UserListExecute(TObject *Sender)
{
    UserListForm->Show();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::WebPageMenuItemClick(TObject *Sender)
{
    ShellExecute(Handle, "open", ((TMenuItem*)Sender)->Hint.c_str(),
        NULL,NULL,SW_SHOWDEFAULT);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormMinimize(TObject *Sender)
{
    if(MinimizeToSysTray) {
    	if(Password.Length()) {
        	TrayIcon->RestoreOn=imNone;
            CloseTrayMenuItem->Enabled=false;
            ConfigureTrayMenuItem->Enabled=false;
            UserEditTrayMenuItem->Enabled=false;
        } else {
        	TrayIcon->RestoreOn=imLeftClickUp;
            CloseTrayMenuItem->Enabled=true;
            ConfigureTrayMenuItem->Enabled=true;
            UserEditTrayMenuItem->Enabled=true;
        }
        if(!TrayIcon->Visible)
	        TrayIcon->Visible=true;
   	    TrayIcon->Minimize();
    }
}

void __fastcall TMainForm::TrayIconRestore(TObject *Sender)
{
    TrayIcon->Visible=false;
}

//---------------------------------------------------------------------------

void __fastcall TMainForm::PropertiesExecute(TObject *Sender)
{
    char str[128];
    static inside;
    if(inside) return;
    inside=true;

    Application->CreateForm(__classid(TPropertiesDlg), &PropertiesDlg);
    PropertiesDlg->LoginCmdEdit->Text=LoginCommand;
    PropertiesDlg->ConfigCmdEdit->Text=ConfigCommand;
    PropertiesDlg->HostnameEdit->Text=global.host_name;
    PropertiesDlg->CtrlDirEdit->Text=global.ctrl_dir;
    PropertiesDlg->TempDirEdit->Text=global.temp_dir;
    PropertiesDlg->NodeIntUpDown->Position=NodeForm->Timer->Interval/1000;
    PropertiesDlg->ClientIntUpDown->Position=ClientForm->Timer->Interval/1000;
    PropertiesDlg->SemFreqUpDown->Position=global.sem_chk_freq;
    PropertiesDlg->TrayIconCheckBox->Checked=MinimizeToSysTray;
    PropertiesDlg->UndockableCheckBox->Checked=UndockableForms;
    PropertiesDlg->FileAssociationsCheckBox->Checked=UseFileAssociations;
    PropertiesDlg->PasswordEdit->Text=Password;
    PropertiesDlg->JS_MaxBytesEdit->Text=byte_count_to_str(global.js.max_bytes, str, sizeof(str));
    PropertiesDlg->JS_TimeLimitEdit->Text=IntToStr(global.js.time_limit);
    PropertiesDlg->JS_GcIntervalEdit->Text=IntToStr(global.js.gc_interval);
    PropertiesDlg->JS_YieldIntervalEdit->Text=IntToStr(global.js.yield_interval);
    PropertiesDlg->JS_LoadPathEdit->Text=global.js.load_path;
    PropertiesDlg->ErrorSoundEdit->Text=ErrorSoundFile;
    PropertiesDlg->LoginAttemptDelayEdit->Text=IntToStr(global.login_attempt.delay);
    PropertiesDlg->LoginAttemptThrottleEdit->Text=IntToStr(global.login_attempt.throttle);
    PropertiesDlg->LoginAttemptHackThresholdEdit->Text
        =global.login_attempt.hack_threshold ? IntToStr(global.login_attempt.hack_threshold) : AnsiString("<disabled>");
    PropertiesDlg->LoginAttemptFilterThresholdEdit->Text
        =global.login_attempt.filter_threshold ? IntToStr(global.login_attempt.filter_threshold) : AnsiString("<disabled>");
    PropertiesDlg->LoginAttemptTempBanThresholdEdit->Text
        =global.login_attempt.tempban_threshold ? IntToStr(global.login_attempt.tempban_threshold) : AnsiString("<disabled>");
    PropertiesDlg->LoginAttemptTempBanDurationEdit->Text
        =global.login_attempt.tempban_duration ? AnsiString(duration_to_str(global.login_attempt.tempban_duration, str, sizeof(str)))
            : AnsiString("<disabled>");

    if(MaxLogLen==0)
		PropertiesDlg->MaxLogLenEdit->Text="<unlimited>";
    else
	    PropertiesDlg->MaxLogLenEdit->Text=IntToStr(MaxLogLen);
	if(PropertiesDlg->ShowModal()==mrOk) {
        LoginCommand=PropertiesDlg->LoginCmdEdit->Text;
        ConfigCommand=PropertiesDlg->ConfigCmdEdit->Text;
        SAFECOPY(global.host_name,PropertiesDlg->HostnameEdit->Text.c_str());
        SAFECOPY(global.ctrl_dir,PropertiesDlg->CtrlDirEdit->Text.c_str());
        SAFECOPY(global.temp_dir,PropertiesDlg->TempDirEdit->Text.c_str());
        global.sem_chk_freq=PropertiesDlg->SemFreqUpDown->Position;
        SemFileTimer->Interval=global.sem_chk_freq;

        /* Copy global values to server startup structs */
        /* We don't support per-server unique values here (yet) */
        SAFECOPY(bbs_startup.host_name,global.host_name);
        SAFECOPY(bbs_startup.ctrl_dir,global.ctrl_dir);
        SAFECOPY(bbs_startup.temp_dir,global.temp_dir);
        bbs_startup.sem_chk_freq=global.sem_chk_freq;

        SAFECOPY(ftp_startup.host_name,global.host_name);
        SAFECOPY(ftp_startup.ctrl_dir,global.ctrl_dir);
        SAFECOPY(ftp_startup.temp_dir,global.temp_dir);
        ftp_startup.sem_chk_freq=global.sem_chk_freq;

        SAFECOPY(web_startup.host_name,global.host_name);
        SAFECOPY(web_startup.ctrl_dir,global.ctrl_dir);
        SAFECOPY(web_startup.temp_dir,global.temp_dir);
        web_startup.sem_chk_freq=global.sem_chk_freq;

        SAFECOPY(mail_startup.host_name,global.host_name);
        SAFECOPY(mail_startup.ctrl_dir,global.ctrl_dir);
        SAFECOPY(mail_startup.temp_dir,global.temp_dir);
        mail_startup.sem_chk_freq=global.sem_chk_freq;

        SAFECOPY(services_startup.host_name,global.host_name);
        SAFECOPY(services_startup.ctrl_dir,global.ctrl_dir);
        SAFECOPY(services_startup.temp_dir,global.temp_dir);
        services_startup.sem_chk_freq=global.sem_chk_freq ;

        Password=PropertiesDlg->PasswordEdit->Text;
        NodeForm->Timer->Interval=PropertiesDlg->NodeIntUpDown->Position*1000;
        ClientForm->Timer->Interval=PropertiesDlg->ClientIntUpDown->Position*1000;
        MinimizeToSysTray=PropertiesDlg->TrayIconCheckBox->Checked;
        UndockableForms=PropertiesDlg->UndockableCheckBox->Checked;
        UseFileAssociations=PropertiesDlg->FileAssociationsCheckBox->Checked;
        ErrorSoundFile=PropertiesDlg->ErrorSoundEdit->Text;

        /* JavaScript operating parameters */
        js_startup_t js=global.js; // save for later comparison
        global.js.max_bytes
        	=parse_byte_count(PropertiesDlg->JS_MaxBytesEdit->Text.c_str(), 1);
        global.js.time_limit
        	=PropertiesDlg->JS_TimeLimitEdit->Text.ToIntDef(JAVASCRIPT_TIME_LIMIT);
        global.js.gc_interval
        	=PropertiesDlg->JS_GcIntervalEdit->Text.ToIntDef(JAVASCRIPT_GC_INTERVAL);
        global.js.yield_interval
        	=PropertiesDlg->JS_YieldIntervalEdit->Text.ToIntDef(JAVASCRIPT_YIELD_INTERVAL);
        SAFECOPY(global.js.load_path, PropertiesDlg->JS_LoadPathEdit->Text.c_str());

        /* Copy global settings, if appropriate (not unique) */
        if(memcmp(&bbs_startup.js,&js,sizeof(js))==0)       bbs_startup.js=global.js;
        if(memcmp(&web_startup.js,&js,sizeof(js))==0)       web_startup.js=global.js;
        if(memcmp(&mail_startup.js,&js,sizeof(js))==0)      mail_startup.js=global.js;
        if(memcmp(&services_startup.js,&js,sizeof(js))==0)  services_startup.js=global.js;

        /* Security parameters */
        global.login_attempt.delay = PropertiesDlg->LoginAttemptDelayEdit->Text.ToIntDef(0);
        global.login_attempt.throttle = PropertiesDlg->LoginAttemptThrottleEdit->Text.ToIntDef(0);
        global.login_attempt.hack_threshold = PropertiesDlg->LoginAttemptHackThresholdEdit->Text.ToIntDef(0);
        global.login_attempt.filter_threshold = PropertiesDlg->LoginAttemptFilterThresholdEdit->Text.ToIntDef(0);
        global.login_attempt.tempban_threshold = PropertiesDlg->LoginAttemptTempBanThresholdEdit->Text.ToIntDef(0);
        global.login_attempt.tempban_duration = parse_duration(PropertiesDlg->LoginAttemptTempBanDurationEdit->Text.c_str());

        MaxLogLen
        	=PropertiesDlg->MaxLogLenEdit->Text.ToIntDef(0);
        SaveSettings(Sender);
    }
    delete PropertiesDlg;

    inside=false;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::CloseTrayMenuItemClick(TObject *Sender)
{
    Close();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::RestoreTrayMenuItemClick(TObject *Sender)
{
#if 0
    TrayIcon->Visible=false;
    Application->Restore();
#else
	static inside;
    if(inside)
    	return;
    inside=true;
    
	if(Password.Length()) {
    	Application->CreateForm(__classid(TCodeInputForm), &CodeInputForm);
    	CodeInputForm->Label->Caption="Password";
        CodeInputForm->Edit->Visible=true;
        CodeInputForm->Edit->PasswordChar='*';
	    if(CodeInputForm->ShowModal()==mrOk
        	&& CodeInputForm->Edit->Text.AnsiCompareIC(Password)==0)
            TrayIcon->Restore();
        delete CodeInputForm;
    } else
        TrayIcon->Restore();

    inside=false;
#endif
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::BBSConfigWizardMenuItemClick(TObject *Sender)
{
    TConfigWizard* ConfigWizard;
    static inside;
    if(inside) return;
    inside=true;

    Application->CreateForm(__classid(TConfigWizard), &ConfigWizard);
	if(ConfigWizard->ShowModal()==mrOk) {
        SaveSettings(Sender);
//        ReloadConfigExecute(Sender);  /* unnecessary since refresh_cfg() is already called */
    }
	delete ConfigWizard;

    inside=false;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::PageControlUnDock(TObject *Sender,
      TControl *Client, TWinControl *NewTarget, bool &Allow)
{
    if(NewTarget==NULL) /* Desktop */
        Allow=UndockableForms;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::reload_config(void)
{
	char error[256];
	SAFECOPY(error,UNKNOWN_LOAD_ERROR);
   	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Reloading configuration...";
	if(!load_cfg(&cfg, /* text: */NULL, /* prep: */TRUE, /* node: */FALSE, error, sizeof(error))) {
    	Application->MessageBox(error,"ERROR Re-loading Configuration"
	        ,MB_OK|MB_ICONEXCLAMATION);
        Application->Terminate();
    }
    FILE* fp=fopen(MainForm->ini_file,"r");
    sbbs_read_ini(fp, MainForm->ini_file
        ,&MainForm->global
        ,NULL   ,&MainForm->bbs_startup
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,NULL
        ,NULL   ,NULL
        );
    if(fp!=NULL)
        fclose(fp);
   	StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text="Configuration reloaded";
   	semfile_list_check(&initialized,recycle_semfiles);

    if(sysop_available(&cfg))
    	ChatToggle->Checked=true;
    else
    	ChatToggle->Checked=false;

	if(sound_muted(&cfg))
    	SoundToggle->Checked=false;
    else
    	SoundToggle->Checked=true;

	SetControls();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ReloadConfigExecute(TObject *Sender)
{
	FtpRecycleExecute(Sender);
	WebRecycleExecute(Sender);
	MailRecycleExecute(Sender);
    TelnetRecycleExecute(Sender);
	ServicesRecycleExecute(Sender);

    reload_config();
#if 0   /* This appears to be redundant */
    node_t node;
    for(int i=0;i<cfg.sys_nodes;i++) {
    	int file;
       	if(NodeForm->getnodedat(i+1,&node,&file))
            break;
        node.misc|=NODE_RRUN;
        if(NodeForm->putnodedat(i+1,&node,file))
            break;
    }
#endif
}

//---------------------------------------------------------------------------


void __fastcall TMainForm::ServicesConfigureExecute(TObject *Sender)
{
    static inside;
    if(inside) return;
    inside=true;

	Application->CreateForm(__classid(TServicesCfgDlg), &ServicesCfgDlg);
	ServicesCfgDlg->ShowModal();
    delete ServicesCfgDlg;

    inside=false;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::UserTruncateMenuItemClick(TObject *Sender)
{
    int usernumber;
    int deleted=0;
    user_t user;

    Screen->Cursor=crHourGlass;
    while((user.number=lastuser(&cfg))!=0) {
        if(getuserdat(&cfg,&user)!=0)
            break;
        if(!(user.misc&DELETED))
            break;
        if(!del_lastuser(&cfg))
            break;
        deleted++;
    }
    Screen->Cursor=crDefault;
    char str[128];
    sprintf(str,"%u Deleted User Records Removed",deleted);
   	Application->MessageBox(str,"Users Truncated",MB_OK);
}

BOOL RecycleService(SC_HANDLE svc, SERVICE_STATUS* status)
{
	if(svc==NULL || controlService==NULL)
    	return(FALSE);

	return controlService(svc, SERVICE_CONTROL_RECYCLE, status);
}

//---------------------------------------------------------------------------
void __fastcall TMainForm::MailRecycleExecute(TObject *Sender)
{
	if(!RecycleService(mail_svc,&mail_svc_status)) {
		mail_startup.recycle_now=true;
	    MailRecycle->Enabled=false;
    }
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FtpRecycleExecute(TObject *Sender)
{
	if(!RecycleService(ftp_svc,&ftp_svc_status)) {
		ftp_startup.recycle_now=true;
	    FtpRecycle->Enabled=false;
    }
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::WebRecycleExecute(TObject *Sender)
{
	if(!RecycleService(web_svc,&web_svc_status)) {
		web_startup.recycle_now=true;
	    WebRecycle->Enabled=false;
    }
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ServicesRecycleExecute(TObject *Sender)
{
	if(!RecycleService(services_svc,&services_svc_status)) {
		services_startup.recycle_now=true;
	    ServicesRecycle->Enabled=false;
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::TelnetRecycleExecute(TObject *Sender)
{
    if(!RecycleService(bbs_svc,&bbs_svc_status)) {
		bbs_startup.recycle_now=true;
	    TelnetRecycle->Enabled=false;
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FileEditTextFilesClick(TObject *Sender)
{
	TOpenDialog* dlg=new TOpenDialog((TComponent*)Sender);

    dlg->Options << ofNoChangeDir;
    dlg->Filter = 	"Text files (*.txt)|*.TXT"
    				"|All files|*.*";
    dlg->InitialDir=cfg.text_dir;
    if(dlg->Execute()==true)
        EditFile(dlg->FileName.c_str());
    delete dlg;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::BBSEditBajaMenuItemClick(TObject *Sender)
{
	TOpenDialog* dlg=new TOpenDialog((TComponent*)Sender);

    dlg->Options << ofNoChangeDir;
    dlg->Filter = "Baja Source Code (*.src)|*.SRC";
    dlg->InitialDir=cfg.exec_dir;
    if(dlg->Execute()==true) {
        Application->CreateForm(__classid(TTextFileEditForm), &TextFileEditForm);
        TextFileEditForm->Filename=AnsiString(dlg->FileName);
        TextFileEditForm->Caption="Edit";
        if(TextFileEditForm->ShowModal()==mrOk) {
        	/* Compile Baja Source File (requires Baja v2.33+) */
        	char cmdline[512];
            sprintf(cmdline,"%sbaja -p %s",cfg.exec_dir,dlg->FileName);
            WinExec(cmdline,SW_SHOW);
		}
        delete TextFileEditForm;
    }
    delete dlg;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FileEditJavaScriptClick(TObject *Sender)
{
	TOpenDialog* dlg=new TOpenDialog((TComponent*)Sender);
    dlg->Options << ofNoChangeDir;
    dlg->Filter = "JavaScript Files (*.js)|*.JS";
    dlg->InitialDir=cfg.exec_dir;
    if(dlg->Execute()==true)
        EditFile(dlg->FileName.c_str());
    delete dlg;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::FileEditConfigFilesClick(TObject *Sender)
{
	TOpenDialog* dlg=new TOpenDialog((TComponent*)Sender);

    dlg->Options << ofNoChangeDir;
    dlg->Filter = "Configuration Files (*.cfg; *.ini; *.conf)|*.cfg;*.ini;*.conf";
    dlg->InitialDir=cfg.ctrl_dir;
    if(dlg->Execute()==true)
        EditFile(dlg->FileName.c_str());
    delete dlg;
}

void __fastcall TMainForm::BBSEditFileClick(TObject *Sender)
{
   TOpenDialog* dlg=new TOpenDialog((TComponent*)Sender);

   dlg->Options << ofNoChangeDir;
    dlg->Filter = "ANSI/Ctrl-A files (*.asc; *.msg; *.ans)|*.ASC;*.MSG;*.ANS"
                "|All files|*.*";
    dlg->InitialDir=cfg.text_dir;
    if(dlg->Execute()==true) {
        Application->CreateForm(__classid(TTextFileEditForm), &TextFileEditForm);
        TextFileEditForm->Filename=AnsiString(dlg->FileName);
        TextFileEditForm->Caption="Edit";
        if(TextFileEditForm->ShowModal()==mrOk) {
	        Application->CreateForm(__classid(TPreviewForm), &PreviewForm);
    	    PreviewForm->Filename=AnsiString(dlg->FileName);
            PreviewForm->ShowModal();
	        delete PreviewForm;
        }
        delete TextFileEditForm;
    }
    delete dlg;
}
//---------------------------------------------------------------------------
bool GetServerLogLine(HANDLE& log, const char* name, log_msg_t* msg)
{
	char fname[256];

	if(log==INVALID_HANDLE_VALUE) {
		sprintf(fname,"\\\\.\\mailslot\\%s.log",name);
        log = CreateMailslot(
            fname,					// pointer to string for mailslot name
            0,						// maximum message size
            0,						// milliseconds before read time-out
            NULL);                  // pointer to security structure
        if(log==INVALID_HANDLE_VALUE)
        	return(false);
    }
    DWORD msgs=0;
    if(!GetMailslotInfo(
        log,   // mailslot handle
        NULL,  // address of maximum message size
        NULL,  // address of size of next message
        &msgs, // address of number of messages
        NULL   // address of read time-out
        ) || !msgs)
        return(false);

	memset(msg, 0, sizeof(*msg));
    DWORD rd=0;
    if(!ReadFile(
        log,				// handle of file to read
        msg,		        // pointer to buffer that receives data
        sizeof(*msg),	   	// number of bytes to read
        &rd,				// pointer to number of bytes read
        NULL				// pointer to structure for data
        ) || !rd)
		return(false);

	return(true);
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::LogTimerTick(TObject *Sender)
{
    log_msg_t   msg;
    log_msg_t*  pmsg;
	ulong count;
	const int max_lines = 1000;

    if(!TelnetPause->Checked) {
		count = 0;
        while(count < max_lines && GetServerLogLine(bbs_log,NTSVC_NAME_BBS,&msg))
            bbs_log_msg(&msg), count++;

        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&bbs_log_list)) != NULL) {
            bbs_log_msg(pmsg);
            free(pmsg);
			count++;
        }
		if(count)
			logged_msgs(TelnetForm->Log);

		count = 0;
        while(count < max_lines && GetServerLogLine(event_log,NTSVC_NAME_EVENT,&msg))
            event_log_msg(&msg), count++;

        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&event_log_list)) != NULL) {
            event_log_msg(pmsg);
            free(pmsg);
			count++;
        }
		if(count)
			logged_msgs(EventsForm->Log);
    }

    if(!FtpPause->Checked) {
		count = 0;
        while(count < max_lines && GetServerLogLine(ftp_log,NTSVC_NAME_FTP,&msg))
            ftp_log_msg(&msg), count++;

        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&ftp_log_list)) != NULL) {
            ftp_log_msg(pmsg);
            free(pmsg);
			count++;
        }
		if(count)
			logged_msgs(FtpForm->Log);
    }
    if(!MailPause->Checked) {
		count = 0;
        while(count < max_lines && GetServerLogLine(mail_log,NTSVC_NAME_MAIL,&msg))
            mail_log_msg(&msg), count++;

        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&mail_log_list)) != NULL) {
            mail_log_msg(pmsg);
            free(pmsg);
			count++;
        }
		if(count)
			logged_msgs(MailForm->Log);
    }
    if(!WebPause->Checked) {
		count = 0;
        while(count < max_lines && GetServerLogLine(web_log,NTSVC_NAME_WEB,&msg))
            web_log_msg(&msg), count++;

        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&web_log_list)) != NULL) {
            web_log_msg(pmsg);
            free(pmsg);
			count++;
        }
		if(count)
			logged_msgs(WebForm->Log);
    }
    if(!ServicesPause->Checked) {
		count = 0;
        while(count < max_lines && GetServerLogLine(services_log,NTSVC_NAME_SERVICES,&msg))
            services_log_msg(&msg), count++;

        while(count < max_lines && (pmsg=(log_msg_t*)listShiftNode(&services_log_list)) != NULL) {
            services_log_msg(pmsg);
            free(pmsg);
			count++;
        }
		if(count)
			logged_msgs(ServicesForm->Log);
    }
}
//---------------------------------------------------------------------------
void CheckServiceStatus(
	 SC_HANDLE svc
	,SERVICE_STATUS* status
	,QUERY_SERVICE_CONFIG* &config
	,DWORD &config_size
	,TStaticText* text
    ,TAction* start
    ,TAction* stop
    ,TAction* recycle
    ,TProgressBar* bar
    )
{
	if(svc==NULL)
    	return;

	DWORD ret;

	if(!queryServiceConfig(svc,config,config_size,&ret)) {
		if(GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
			config_size=ret;
			if(config!=NULL)
				free(config);
			config = (QUERY_SERVICE_CONFIG*)malloc(config_size);
		}
		return;
	}

	if(config->dwStartType==SERVICE_DISABLED)
		return;

	if(!queryServiceStatus(svc,status)) {
    	text->Caption="QueryServiceStatus Error "; // + GetLastError());
        return;
	}

    bool running=false;

	switch(status->dwCurrentState) {
    	case SERVICE_STOPPED:
        	text->Caption="Stopped NT Service";
            break;
        case SERVICE_STOP_PENDING:
        	text->Caption="Stopping NT Service";
            break;
        case SERVICE_RUNNING:
        	text->Caption="Running NT Service";
            running=true;
            break;
        case SERVICE_START_PENDING:
        	text->Caption="Starting NT Service";
            running=true;
            break;
        default:
        	text->Caption="!UNKNOWN: " +  status->dwCurrentState;
            break;
    }

    start->Enabled=!running;
    stop->Enabled=running;
    recycle->Enabled=running;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ServiceStatusTimerTick(TObject *Sender)
{
	if(queryServiceStatus==NULL || queryServiceConfig==NULL
    	|| (bbs_svc==NULL
        && ftp_svc==NULL
		&& web_svc==NULL
        && mail_svc==NULL
        && services_svc==NULL)) {
    	ServiceStatusTimer->Enabled=false;
        return;
    }

    CheckServiceStatus(
    	 bbs_svc
    	,&bbs_svc_status
		,bbs_svc_config
		,bbs_svc_config_size
        ,TelnetForm->Status
        ,TelnetStart
        ,TelnetStop
        ,TelnetRecycle
        ,TelnetForm->ProgressBar
        );
    CheckServiceStatus(
    	 ftp_svc
    	,&ftp_svc_status
		,ftp_svc_config
		,ftp_svc_config_size
        ,FtpForm->Status
        ,FtpStart
        ,FtpStop
        ,FtpRecycle
        ,FtpForm->ProgressBar
        );
    CheckServiceStatus(
    	 web_svc
    	,&web_svc_status
		,web_svc_config
		,web_svc_config_size
        ,WebForm->Status
        ,WebStart
        ,WebStop
        ,WebRecycle
        ,WebForm->ProgressBar
        );
    CheckServiceStatus(
    	 mail_svc
    	,&mail_svc_status
		,mail_svc_config
		,mail_svc_config_size
        ,MailForm->Status
        ,MailStart
        ,MailStop
        ,MailRecycle
        ,MailForm->ProgressBar
        );
    CheckServiceStatus(
    	 services_svc
    	,&services_svc_status
		,services_svc_config
		,services_svc_config_size
        ,ServicesForm->Status
        ,ServicesStart
        ,ServicesStop
        ,ServicesRecycle
        ,NULL
        );

}
//---------------------------------------------------------------------------
void __fastcall TMainForm::EditFile(AnsiString filename, AnsiString Caption)
{
   if(!UseFileAssociations
        || (int)ShellExecute(Handle, "edit", filename.c_str(), NULL,NULL,SW_SHOWDEFAULT)<=32) {
        Application->CreateForm(__classid(TTextFileEditForm), &TextFileEditForm);
        TextFileEditForm->Filename=filename;
        TextFileEditForm->Caption=Caption;
        TextFileEditForm->ShowModal();
        delete TextFileEditForm;
    }
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewFile(AnsiString filename, AnsiString Caption)
{
   if(!UseFileAssociations
        || (int)ShellExecute(Handle, "open", filename.c_str(), NULL,NULL,SW_SHOWDEFAULT)<=32) {
        Application->CreateForm(__classid(TTextFileEditForm), &TextFileEditForm);
        TextFileEditForm->Filename=filename;
        TextFileEditForm->Caption=Caption;
        TextFileEditForm->Memo->ReadOnly=true;
        TextFileEditForm->ShowModal();
        delete TextFileEditForm;
    }
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::SemFileTimerTick(TObject *Sender)
{
    char* p;

    if((p=semfile_list_check(&initialized,shutdown_semfiles))!=NULL) {
	    StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text=AnsiString(p) + " signaled";
        terminating=true;
        Close();
    }
    else if((p=semfile_list_check(&initialized,recycle_semfiles))!=NULL) {
	    StatusBar->Panels->Items[STATUSBAR_LAST_PANEL]->Text=AnsiString(p) + " signaled";
        reload_config();
    }
}
//---------------------------------------------------------------------------
TFont* __fastcall TMainForm::LogAttributes(int log_level, TColor Color, TFont* Font)
{
    if(log_level==LOG_INFO || LogFont[log_level]->Color==Color
        || log_level > LOG_DEBUG)
        return Font;

    return LogFont[log_level];
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ClearErrorsExecute(TObject *Sender)
{
    errors=0;

    node_t node;
    for(int i=0;i<cfg.sys_nodes;i++) {
    	int file;
       	if(NodeForm->getnodedat(i+1,&node, /*lockit: */true))
            break;
        node.errors=0;
        if(NodeForm->putnodedat(i+1,&node))
            break;
    }
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewErrorLogExecute(TObject *Sender)
{
	char filename[MAX_PATH+1];

    sprintf(filename,"%sERROR.LOG"
    	,MainForm->cfg.logs_dir);
    ViewFile(filename,"Error Log");
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::ViewLoginAttemptsMenuItemClick(TObject *Sender)
{
    LoginAttemptsForm->Show();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::LogPopupPauseClick(TObject *Sender)
{
    if(/*(TRichEdit*)*/Sender == TelnetForm->Log) {
        TelnetPause->Execute();
    }
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::LogPopupCopyAllClick(TObject *Sender)
{
    TRichEdit* Log = (TRichEdit*)LogPopupMenu->PopupComponent;
    Log->SelectAll();
    Log->CopyToClipboard();
    Log->SelLength=0;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::LogPopupCopyClick(TObject *Sender)
{
    TRichEdit* Log = (TRichEdit*)LogPopupMenu->PopupComponent;
    Log->CopyToClipboard();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::ClearFailedLoginsPopupMenuItemClick(
      TObject *Sender)
{
    clearLoginAttemptList = true;
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::RefreshLogClick(TObject *Sender)
{
    TRichEdit* Log = (TRichEdit*)LogPopupMenu->PopupComponent;
    Log->Refresh();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FidonetConfigureMenuItemClick(TObject *Sender)
{
	char str[MAX_PATH + 1];

    SAFEPRINTF(str, "%sechocfg.exe", cfg.exec_dir);
    STARTUPINFO startup_info={0};
    PROCESS_INFORMATION process_info;
    startup_info.cb=sizeof(startup_info);
    startup_info.lpTitle="Fidonet Configuration";
	if(!CreateProcess(
		NULL,			// pointer to name of executable module
		str,  			// pointer to command line string
		NULL,  			// process security attributes
		NULL,   		// thread security attributes
		FALSE, 			// handle inheritance flag
		0,              // creation flags
        NULL,  			// pointer to new environment block
		cfg.ctrl_dir,	// pointer to current directory name
		&startup_info,  // pointer to STARTUPINFO
		&process_info  	// pointer to PROCESS_INFORMATION
		))
       	Application->MessageBox(AnsiString("ERROR " + IntToStr(GetLastError()) +
            " executing " + str).c_str()
            ,"ERROR"
            ,MB_OK|MB_ICONEXCLAMATION);
	// Resource leak if you don't close these:
	CloseHandle(process_info.hThread);
	CloseHandle(process_info.hProcess);
}
//---------------------------------------------------------------------------



void __fastcall TMainForm::FidonetPollMenuItemClick(TObject *Sender)
{
	char path[MAX_PATH + 1];

    SAFEPRINTF(path, "%sbinkpoll.now", cfg.data_dir);
    int file=_sopen(path,O_CREAT|O_TRUNC|O_WRONLY
	                ,SH_DENYRW,S_IREAD|S_IWRITE);
    if (file!=-1)
        close(file);
}
//---------------------------------------------------------------------------


void __fastcall TMainForm::FileRunJSMenuItemClick(TObject *Sender)
{
	TOpenDialog* dlg=new TOpenDialog((TComponent*)Sender);

    dlg->Options << ofNoChangeDir;
    dlg->Filter = 	"JavaScript files (*.js)|*.js";
    dlg->InitialDir=cfg.exec_dir;
    if(dlg->Execute()==true) {
    	char    cmdline[MAX_PATH+1];
        SAFEPRINTF2(cmdline,"%sjsexec.exe -p %s"
            ,MainForm->cfg.exec_dir
            ,dlg->FileName.c_str()
            );
        STARTUPINFO startup_info={0};
        PROCESS_INFORMATION process_info;
        startup_info.cb=sizeof(startup_info);
        startup_info.lpTitle = cmdline;
    	if(!CreateProcess(
    		NULL,			// pointer to name of executable module
    		cmdline,        // pointer to command line string
    		NULL,  			// process security attributes
    		NULL,   		// thread security attributes
    		FALSE, 			// handle inheritance flag
    		0,              // creation flags
            NULL,  			// pointer to new environment block
    		cfg.ctrl_dir,	// pointer to current directory name
    		&startup_info,  // pointer to STARTUPINFO
    		&process_info  	// pointer to PROCESS_INFORMATION
    		))
           	Application->MessageBox(AnsiString("ERROR " + IntToStr(GetLastError()) +
                " executing " + cmdline).c_str()
                ,"ERROR"
                ,MB_OK|MB_ICONEXCLAMATION);
    	// Resource leak if you don't close these:
    	CloseHandle(process_info.hThread);
    	CloseHandle(process_info.hProcess);
    }
    delete dlg;

}
//---------------------------------------------------------------------------