diff --git a/src/sbbs3/ctrl/AboutBoxFormUnit.cpp b/src/sbbs3/ctrl/AboutBoxFormUnit.cpp
index 3e3aa05a5c514125ee7cea67ccc91bd197bd9ffb..35a5d600cfc6eea40ec895d9b5fa772622a450d6 100644
--- a/src/sbbs3/ctrl/AboutBoxFormUnit.cpp
+++ b/src/sbbs3/ctrl/AboutBoxFormUnit.cpp
@@ -39,9 +39,9 @@
 
 #include "AboutBoxFormUnit.h"
 #include "emulvt.hpp"
-#include "bbs_thrd.h" 	// bbs_startup_t
 #include "mailsrvr.h"
 #include "ftpsrvr.h"
+#include "services.h"
 
 //---------------------------------------------------------------------------
 #pragma package(smart_init)
@@ -106,6 +106,7 @@ void __fastcall TAboutBoxForm::FormShow(TObject *Sender)
     Memo->Lines->Add(bbs_ver());
     Memo->Lines->Add(mail_ver());
     Memo->Lines->Add(ftp_ver());
+    Memo->Lines->Add(services_ver());
     Memo->Lines->Add(ver);
     Memo->Lines->Add("Synchronet Local Spy ANSI Terminal Emulation"
         + CopyRight);
diff --git a/src/sbbs3/ctrl/MainFormUnit.cpp b/src/sbbs3/ctrl/MainFormUnit.cpp
index a38d33faba63c48589b6aa10c531ec6ac6bd05ab..fd15fd9ca76fcd9a5331720d898e37dcbf5dbddb 100644
--- a/src/sbbs3/ctrl/MainFormUnit.cpp
+++ b/src/sbbs3/ctrl/MainFormUnit.cpp
@@ -49,6 +49,7 @@
 #include "MainFormUnit.h"
 #include "TelnetFormUnit.h"
 #include "EventsFormUnit.h"
+#include "ServicesFormUnit.h"
 #include "FtpFormUnit.h"
 #include "MailFormUnit.h"
 #include "NodeFormUnit.h"
@@ -272,6 +273,10 @@ static void bbs_start(void)
     bbs_status("Starting");
     strcpy(MainForm->bbs_startup.ctrl_dir,MainForm->CtrlDirectory.c_str());
 	_beginthread((void(*)(void*))bbs_thread,0,&MainForm->bbs_startup);
+
+    strcpy(MainForm->services_startup.ctrl_dir,MainForm->CtrlDirectory.c_str());
+	_beginthread((void(*)(void*))services_thread,0,&MainForm->services_startup);
+
     Application->ProcessMessages();
 }
 
@@ -293,6 +298,24 @@ static int event_log(char *str)
     return(Line.Length());
 }
 
+static int service_log(char *str)
+{
+	static HANDLE mutex;
+
+    if(!mutex)
+    	mutex=CreateMutex(NULL,false,NULL);
+	WaitForSingleObject(mutex,INFINITE);
+
+    while(ServicesForm->Log->Text.Length()>=MAX_LOGLEN)
+        ServicesForm->Log->Lines->Delete(0);
+
+    AnsiString Line=Now().FormatString(LOG_TIME_FMT)+"  ";
+    Line+=AnsiString(str).Trim();
+	ServicesForm->Log->Lines->Add(Line);
+    ReleaseMutex(mutex);
+    return(Line.Length());
+}
+
 static int mail_lputs(char *str)
 {
 	static HANDLE mutex;
@@ -587,6 +610,14 @@ __fastcall TMainForm::TMainForm(TComponent* Owner)
     strcpy(ftp_startup.html_index_file,"00index.html");
     strcpy(ftp_startup.html_index_script,"ftp-html.js");
 
+    memset(&services_startup,0,sizeof(services_startup));
+    services_startup.size=sizeof(services_startup);
+    services_startup.interface_addr=INADDR_ANY;
+    services_startup.lputs=service_log;
+    services_startup.thread_up=thread_up;
+    services_startup.client_on=client_on;
+    services_startup.socket_open=socket_open;
+
     /* Default local "Spy Terminal" settings */
     SpyTerminalFont=new TFont;
     SpyTerminalFont->Name="Terminal";
@@ -1042,6 +1073,7 @@ void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
 {
     bool	TelnetFormFloating=false;
     bool	EventsFormFloating=false;
+    bool	ServicesFormFloating=false;
     bool 	NodeFormFloating=false;
     bool	StatsFormFloating=false;
     bool	ClientFormFloating=false;
@@ -1054,6 +1086,7 @@ void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
     int		EventsFormPage=PAGE_LOWERLEFT;
     int		MailFormPage=PAGE_UPPERRIGHT;
     int		FtpFormPage=PAGE_LOWERRIGHT;
+    int     ServicesFormPage=PAGE_LOWERRIGHT;
 
     AnsiString	Str;
 
@@ -1088,6 +1121,8 @@ void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
             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"))
@@ -1104,6 +1139,8 @@ void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
     	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"))
@@ -1119,6 +1156,8 @@ void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
     ReadFont("TelnetLog",TelnetForm->Log->Font);
     ReadColor(Registry,"EventsLog",EventsForm->Log->Color);
     ReadFont("EventsLog",EventsForm->Log->Font);
+    ReadColor(Registry,"ServicesLog",ServicesForm->Log->Color);
+    ReadFont("ServicesLog",ServicesForm->Log->Font);
     ReadColor(Registry,"MailLog",MailForm->Log->Color);
     ReadFont("MailLog",MailForm->Log->Font);
     ReadColor(Registry,"FtpLog",FtpForm->Log->Color);
@@ -1146,6 +1185,15 @@ void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
 	if(Registry->ValueExists("EventsFormHeight"))
     	EventsForm->Height=Registry->ReadInteger("EventsFormHeight");
 
+	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("FtpFormTop"))
     	FtpForm->Top=Registry->ReadInteger("FtpFormTop");
 	if(Registry->ValueExists("FtpFormLeft"))
@@ -1424,6 +1472,8 @@ void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
     	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);
 
@@ -1433,6 +1483,7 @@ void __fastcall TMainForm::StartupTimerTick(TObject *Sender)
     TelnetForm->Show();
     EventsForm->Show();
     FtpForm->Show();
+    ServicesForm->Show();
     MailForm->Show();
 
 	UpperLeftPageControl->Visible=true;
@@ -1527,6 +1578,11 @@ void __fastcall TMainForm::SaveSettings(TObject* Sender)
     Registry->WriteInteger("EventsFormHeight",EventsForm->Height);
     Registry->WriteInteger("EventsFormWidth",EventsForm->Width);
 
+    Registry->WriteInteger("ServicesFormTop",ServicesForm->Top);
+    Registry->WriteInteger("ServicesFormLeft",ServicesForm->Left);
+    Registry->WriteInteger("ServicesFormHeight",ServicesForm->Height);
+    Registry->WriteInteger("ServicesFormWidth",ServicesForm->Width);
+
     Registry->WriteInteger("FtpFormTop",FtpForm->Top);
     Registry->WriteInteger("FtpFormLeft",FtpForm->Left);
     Registry->WriteInteger("FtpFormHeight",FtpForm->Height);
@@ -1547,6 +1603,7 @@ void __fastcall TMainForm::SaveSettings(TObject* Sender)
 
     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);
@@ -1557,6 +1614,8 @@ void __fastcall TMainForm::SaveSettings(TObject* Sender)
 	    ,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"
@@ -1572,6 +1631,8 @@ void __fastcall TMainForm::SaveSettings(TObject* Sender)
     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);
diff --git a/src/sbbs3/ctrl/MainFormUnit.h b/src/sbbs3/ctrl/MainFormUnit.h
index 8e48699514995b184256a45afa769a5dc0767a77..f109ce9c6b35b653600fa1175cda61de82ee1bd4 100644
--- a/src/sbbs3/ctrl/MainFormUnit.h
+++ b/src/sbbs3/ctrl/MainFormUnit.h
@@ -48,9 +48,9 @@
 #include <ActnList.hpp>
 //---------------------------------------------------------------------------
 #include "scfgdefs.h"  	// scfg_t
-#include "bbs_thrd.h" 	// bbs_startup_t
 #include "mailsrvr.h"
 #include "ftpsrvr.h"
+#include "services.h"   // services_startup_t
 #include <ImgList.hpp>
 #include <Buttons.hpp>
 #include <Graphics.hpp>
@@ -314,6 +314,7 @@ public:		// User declarations
     bbs_startup_t 	bbs_startup;
     mail_startup_t 	mail_startup;
     ftp_startup_t	ftp_startup;
+    services_startup_t  services_startup;
     int             NodeDisplayInterval;
     int             ClientDisplayInterval;
     int             SpyTerminalWidth;
diff --git a/src/sbbs3/ctrl/ServicesFormUnit.cpp b/src/sbbs3/ctrl/ServicesFormUnit.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4a81e2dbcf4d035368819df87e41710f379582fc
--- /dev/null
+++ b/src/sbbs3/ctrl/ServicesFormUnit.cpp
@@ -0,0 +1,16 @@
+//---------------------------------------------------------------------------
+
+#include <vcl.h>
+#pragma hdrstop
+
+#include "ServicesFormUnit.h"
+//---------------------------------------------------------------------------
+#pragma package(smart_init)
+#pragma resource "*.dfm"
+TServicesForm *ServicesForm;
+//---------------------------------------------------------------------------
+__fastcall TServicesForm::TServicesForm(TComponent* Owner)
+    : TForm(Owner)
+{
+}
+//---------------------------------------------------------------------------
diff --git a/src/sbbs3/ctrl/ServicesFormUnit.dfm b/src/sbbs3/ctrl/ServicesFormUnit.dfm
new file mode 100644
index 0000000000000000000000000000000000000000..352f722f45f435d7a028ffd3b07967828607c0dc
--- /dev/null
+++ b/src/sbbs3/ctrl/ServicesFormUnit.dfm
@@ -0,0 +1,27 @@
+object ServicesForm: TServicesForm
+  Left = 276
+  Top = 318
+  Width = 870
+  Height = 640
+  Caption = 'Services'
+  Color = clBtnFace
+  DragKind = dkDock
+  Font.Charset = DEFAULT_CHARSET
+  Font.Color = clWindowText
+  Font.Height = -13
+  Font.Name = 'MS Sans Serif'
+  Font.Style = []
+  OldCreateOrder = False
+  PixelsPerInch = 120
+  TextHeight = 16
+  object Log: TMemo
+    Left = 0
+    Top = 0
+    Width = 862
+    Height = 608
+    Align = alClient
+    ReadOnly = True
+    ScrollBars = ssBoth
+    TabOrder = 0
+  end
+end
diff --git a/src/sbbs3/ctrl/ServicesFormUnit.h b/src/sbbs3/ctrl/ServicesFormUnit.h
new file mode 100644
index 0000000000000000000000000000000000000000..e05ba9d953c08ad77f369b34d6583ebe761476dd
--- /dev/null
+++ b/src/sbbs3/ctrl/ServicesFormUnit.h
@@ -0,0 +1,22 @@
+//---------------------------------------------------------------------------
+
+#ifndef ServicesFormUnitH
+#define ServicesFormUnitH
+//---------------------------------------------------------------------------
+#include <Classes.hpp>
+#include <Controls.hpp>
+#include <StdCtrls.hpp>
+#include <Forms.hpp>
+//---------------------------------------------------------------------------
+class TServicesForm : public TForm
+{
+__published:	// IDE-managed Components
+    TMemo *Log;
+private:	// User declarations
+public:		// User declarations
+    __fastcall TServicesForm(TComponent* Owner);
+};
+//---------------------------------------------------------------------------
+extern PACKAGE TServicesForm *ServicesForm;
+//---------------------------------------------------------------------------
+#endif
diff --git a/src/sbbs3/ctrl/makelibs.bat b/src/sbbs3/ctrl/makelibs.bat
index b0c047a306d695b7651a04360be9ff94deafd8cc..f709381b00bf754b60eebf4f3f104aaa850b3b07 100755
--- a/src/sbbs3/ctrl/makelibs.bat
+++ b/src/sbbs3/ctrl/makelibs.bat
@@ -3,3 +3,4 @@ set dllsrc=..\msvc.win32.dll.debug
 implib sbbs.lib 	%dllsrc%\sbbs.dll
 implib mailsrvr.lib 	%dllsrc%\mailsrvr.dll
 implib ftpsrvr.lib 	%dllsrc%\ftpsrvr.dll
+implib services.lib	%dllsrc%\services.dll
\ No newline at end of file
diff --git a/src/sbbs3/ctrl/sbbsctrl.bpr b/src/sbbs3/ctrl/sbbsctrl.bpr
index 809944f16247a8d2fd1326a63737521f9d18a583..b95fb1596c9155f7797a1f268e1c7a36fe31a861 100644
--- a/src/sbbs3/ctrl/sbbsctrl.bpr
+++ b/src/sbbs3/ctrl/sbbsctrl.bpr
@@ -10,7 +10,8 @@
       NodeFormUnit.obj StatsFormUnit.obj AboutBoxFormUnit.obj 
       StatsLogFormUnit.obj CodeInputFormUnit.obj ClientFormUnit.obj 
       SpyFormUnit.obj ..\ringbuf.obj UserListFormUnit.obj UserMsgFormUnit.obj 
-      PropertiesDlgUnit.obj EventsFormUnit.obj ConfigWizardUnit.obj"/>
+      PropertiesDlgUnit.obj EventsFormUnit.obj ConfigWizardUnit.obj 
+      ServicesFormUnit.obj"/>
     <RESFILES value="sbbsctrl.res"/>
     <IDLFILES value=""/>
     <IDLGENFILES value=""/>
@@ -21,8 +22,8 @@
       StatsFormUnit.dfm AboutBoxFormUnit.dfm StatsLogFormUnit.dfm 
       CodeInputFormUnit.dfm ClientFormUnit.dfm SpyFormUnit.dfm 
       UserListFormUnit.dfm UserMsgFormUnit.dfm PropertiesDlgUnit.dfm 
-      EventsFormUnit.dfm ConfigWizardUnit.dfm"/>
-    <LIBFILES value="sbbs.lib mailsrvr.lib ftpsrvr.lib"/>
+      EventsFormUnit.dfm ConfigWizardUnit.dfm ServicesFormUnit.dfm"/>
+    <LIBFILES value="sbbs.lib mailsrvr.lib ftpsrvr.lib services.lib"/>
     <LIBRARIES value="VCLX50.lib bcbsmp50.lib vcl50.lib"/>
     <SPARELIBS value="vcl50.lib bcbsmp50.lib VCLX50.lib"/>
     <PACKAGES value="vcl50.bpi vclx50.bpi vcljpg50.bpi bcbsmp50.bpi vclmid50.bpi vcldb50.bpi 
diff --git a/src/sbbs3/ctrl/sbbsctrl.cpp b/src/sbbs3/ctrl/sbbsctrl.cpp
index b39675e1a6f36d437739d8b2decece0ca9621e9f..e969c3f0614e4b5f6326199595ff53f6bc4509ab 100644
--- a/src/sbbs3/ctrl/sbbsctrl.cpp
+++ b/src/sbbs3/ctrl/sbbsctrl.cpp
@@ -43,6 +43,7 @@ USEFORM("TelnetCfgDlgUnit.cpp", TelnetCfgDlg);
 USELIB("sbbs.lib");
 USELIB("mailsrvr.lib");
 USELIB("ftpsrvr.lib");
+USELIB("services.lib");
 USEFORM("MailCfgDlgUnit.cpp", MailCfgDlg);
 USEFORM("FtpCfgDlgUnit.cpp", FtpCfgDlg);
 USEFORM("TextFileEditUnit.cpp", TextFileEditForm);
@@ -63,6 +64,7 @@ USEFORM("UserMsgFormUnit.cpp", UserMsgForm);
 USEFORM("PropertiesDlgUnit.cpp", PropertiesDlg);
 USEFORM("EventsFormUnit.cpp", EventsForm);
 USEFORM("ConfigWizardUnit.cpp", ConfigWizardForm);
+USEFORM("ServicesFormUnit.cpp", ServicesForm);
 //---------------------------------------------------------------------------
 #include "MainFormUnit.h"
 #include "SpyFormUnit.h"
@@ -85,6 +87,7 @@ WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR cmd, int)
          Application->CreateForm(__classid(TClientForm), &ClientForm);
          Application->CreateForm(__classid(TUserListForm), &UserListForm);
          Application->CreateForm(__classid(TEventsForm), &EventsForm);
+         Application->CreateForm(__classid(TServicesForm), &ServicesForm);
          Application->Run();
     }
     catch (Exception &exception)