// Xb2.NET sample showing how to create a simple Telnet server
//------------------------------------------------------------------------------------
#include "xb2net.ch"
#include "common.ch"
#include "xbp.ch"
#pragma library ("xb2net.lib")
#define CRLF (Chr(13)+Chr(10))
#xtranslate NTrim() => LTrim(Str())
procedure Main()
Local nKey, cKey, oServer
// start server on port 23 (the standard Telnet port)
oServer := xbServer():new( INADDR_ANY, 23 )
if oServer:ErrorCode > 0
MsgBox("Unable to start server!" + chr(10) +;
"Error code: " + LTrim(Str(oServer:ErrorCode)) + " (" + oServer:ErrorText(oServer:ErrorCode) + ")" )
Return
endif
// this is the codeblock that will be evaluated when a client connection is accepted
oServer:onConnect := {||ServiceClient()}
// start the server in it's own thread
oServer:start()
SetPos(MaxRow(),0)
? "Server started on host:", oServer:LocalName, ", Thread:", NTrim(oServer:ThreadID) + ", At:", oServer:DateStarted, NTrim(oServer:TimeStarted), "Sec."
?
while .t.
nKey := inkey(0.2)
cKey := Upper(chr(nKey))
do case
case nKey == 27
if ConfirmBox(nil, "Are you sure you want to terminate the telnet server?", "Quit", ;
XBPMB_OKCANCEL, XBPMB_WARNING+XBPMB_MOVEABLE+XBPMB_APPMODAL, XBPMB_DEFBUTTON2) == XBPMB_RET_OK
exit
endif
case cKey == "S"
oServer:Stop()
? Str(ThreadID(),3), "Server stopped"
case cKey == "R"
oServer:start()
? Str(ThreadID(),3), "Server started"
case cKey == "L"
? "ClientList:", oServer:ClientList
endcase
DispOutAt( 0,0, PadR("(ESC)=Exit, (S)=Stop Server, (R)=Restart Server, (L)=List Clients",80), "gr+/bg" )
DispOutAt( 1,0, PadR("ActiveConnections: " + NTrim(oServer:ActiveConnections()) + ", ConnectCount: " + NTrim(oServer:ConnectCount),80), "gr+/bg" )
DispOutAt( 2,0, Space(80))
end
// DON'T FORGET TO DESTROY THE OBJECT !!
oServer:destroy()
Return
//-----------------------------------------------------------------------------
procedure ServiceClient()
Local cRecv, cSend, cFileName, cColor
Local cThreadID := Str(ThreadID(),3)
Local oClient := ThreadObject()
? cThreadID, "** CONNECT: RemoteName:", oClient:RemoteName, " Address:", oClient:InetNtoA(oClient:RemoteAddr), "Port:", NTrim(oClient:RemotePort)
// send welcome message to client with some instructions
oClient:Send( "Hello " + oClient:RemoteName + CRLF +;
"You are connected to my Xbase++ telnet server" + CRLF +;
"Try typing a DOS command like DIR..." + CRLF )
// temp file name to redirect output of DOS commands to
cFileName := "~" + NTrim(oClient:Handle) + ".TMP"
// wait until we receive something on client socket (or error occurs)
// remember this is running in it's own thread
while (cRecv := oClient:RecvLine()) != NIL
cSend := cRecv
cRecv := StrTran(StrTran(cRecv,chr(10),""),chr(13),"")
? cThreadID, cRecv
// execute DOS command received from client
// redirecting output to a temp file
RunShell( "/C " + cRecv + " > " + cFileName,,.f.,.t. )
// read contents from temp file so we can send it to the client
cSend += MemoRead(cFileName)
FErase(cFileName)
if oClient:Send( cSend ) < 0
exit
endif
end
cColor := SetColor("w/r")
? cThreadID, "** QUIT **"
SetColor( cColor )
Return