diff --git a/mystic/mis.pas b/mystic/mis.pas index 4e1c3ae..5ecbd71 100644 --- a/mystic/mis.pas +++ b/mystic/mis.pas @@ -352,7 +352,6 @@ Begin Console.SetWindowTitle(WinTitle); - {$IFDEF WINDOWS} If bbsConfig.InetTNUse Then Begin TelnetServer := TServerManager.Create(bbsConfig, bbsConfig.InetTNPort, bbsConfig.INetTNNodes, NodeData, @CreateTelnet); @@ -361,7 +360,6 @@ Begin Started := True; End; - {$ENDIF} If bbsConfig.InetSMTPUse Then Begin SMTPServer := TServerManager.Create(bbsConfig, bbsConfig.INetSMTPPort, bbsConfig.inetSMTPMax, NodeData, @CreateSMTP); diff --git a/mystic/mis_client_telnet.pas b/mystic/mis_client_telnet.pas index e9d37c1..60a7cb6 100644 --- a/mystic/mis_client_telnet.pas +++ b/mystic/mis_client_telnet.pas @@ -7,7 +7,9 @@ Interface Uses {$IFDEF UNIX} Unix, - //TPROCESS unit? + Classes, + Process, + SysUtils, {$ENDIF} {$IFDEF WINDOWS} Windows, @@ -46,21 +48,21 @@ End; {$IFDEF WINDOWS} Procedure TTelnetServer.Execute; Var - Cmd : String; - SI : TStartupInfo; - PI : TProcessInformation; - Num : LongInt; - NI : TNodeInfoRec; + Cmd : String; + SI : TStartupInfo; + PI : TProcessInformation; + Num : LongInt; + NI : TNodeInfoRec; PassHandle : LongInt; Begin - If Not DuplicateHandle ( - GetCurrentProcess, - Client.FSocketHandle, - GetCurrentProcess, - @PassHandle, - 0, - TRUE, - DUPLICATE_SAME_ACCESS) Then Exit; + If Not DuplicateHandle ( + GetCurrentProcess, + Client.FSocketHandle, + GetCurrentProcess, + @PassHandle, + 0, + TRUE, + DUPLICATE_SAME_ACCESS) Then Exit; Num := ND.GetFreeNode; Cmd := 'mystic.exe -n' + strI2S(Num) + ' -TID' + strI2S(PassHandle) + ' -IP' + Client.FPeerIP + ' -HOST' + Client.FPeerName + #0; @@ -82,7 +84,7 @@ Begin SI.wShowWindow := SW_SHOWMINNOACTIVE; If CreateProcess(NIL, PChar(@Cmd[1]), - NIL, NIL, True, create_new_console + normal_priority_class, NIL, NIL, SI, PI) Then + NIL, NIL, True, Create_New_Console + Normal_Priority_Class, NIL, NIL, SI, PI) Then WaitForSingleObject (PI.hProcess, INFINITE); NI.Busy := False; @@ -96,13 +98,22 @@ End; {$IFDEF UNIX} Procedure TTelnetServer.Execute; +Const + BufferSize = 4096; Var - Cmd : String; - Num : LongInt; - NI : TNodeInfoRec; + Cmd : String; + Num : LongInt; + NI : TNodeInfoRec; + Proc : TProcess; + Buffer : Array[1..BufferSize] of Char; + bRead : LongInt; + bWrite : LongInt; Begin - Num := ND.GetFreeNode; - Cmd := './mystic -n' + strI2S(Num) + ' -IP' + Client.FPeerIP + ' -HOST' + Client.FPeerName; + Proc := TProcess.Create(Nil); + Num := ND.GetFreeNode; + + Proc.CommandLine := 'mystic -n' + strI2S(Num) + ' -IP' + Client.FPeerIP + ' -HOST' + Client.FPeerName; + Proc.Options := [poUsePipes]; FillChar(NI, SizeOf(NI), 0); @@ -114,22 +125,27 @@ Begin ND.SetNodeInfo(Num, NI); - // setup and execute Cmd as defined above, setting up STDIO handles + Proc.Execute; - fpSystem(Cmd); // placeholder for above + While Proc.Running Do Begin + If Proc.Output.NumBytesAvailable > 0 Then Begin + While Proc.Output.NumBytesAvailable > 0 Do Begin + bRead := Proc.Output.Read(Buffer, BufferSize); + Client.WriteBuf (Buffer, bRead); + End; + End Else + If Client.DataWaiting Then Begin + bWrite := Client.ReadBuf(Buffer, BufferSize); - // redirection of STDIO psuedocode loop here - // NOTE client class already escapes telnet protocol, no need for that! - // - // while processGoing do begin - // case waitEvent(Input, output, close, wait INFINITY) - // input : push input from client to STDIO handle - // output : push output from STDIO to client class - // close : break; - // end + If bWrite < 0 Then Break; - // it seems there might be a TProcess in FCL with FPC that can do this - // already... research! + If bWrite > 0 Then + Proc.Input.Write(Buffer, bWrite); + End Else + Sleep(25); + End; + + Proc.Free; NI.Busy := False; NI.IP := ''; @@ -146,3 +162,107 @@ Begin End; End. + + + +program procoutlarge; +{ + Copyright (c) 2004-2011 by Marc Weustink and contributors + + This example is created in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +} +// This is a +// WORKING +// demo program that shows +// how to launch an external program +// and read from its output. + +uses + Classes, Process, SysUtils; + +const + READ_BYTES = 2048; + +var + OurCommand: String; + OutputLines: TStringList; + MemStream: TMemoryStream; + OurProcess: TProcess; + NumBytes: LongInt; + BytesRead: LongInt; + +begin + // A temp Memorystream is used to buffer the output + MemStream := TMemoryStream.Create; + BytesRead := 0; + + OurProcess := TProcess.Create(nil); + // Recursive dir is a good example. + OurCommand:='invalid command, please fix the IFDEFS.'; + {$IFDEF Windows} + //Can't use dir directly, it's built in + //so we just use the shell: + OurCommand:='cmd.exe /c "dir /s d:\dev\code\mystic\"'; + {$ENDIF Windows} + {$IFDEF Unix} + //Needs to be tested on Linux/Unix: + OurCommand := 'ls --recursive --all -l /'; + {$ENDIF Unix} + writeln('-- Going to run: ' + OurCommand); + OurProcess.CommandLine := OurCommand; + + // We cannot use poWaitOnExit here since we don't + // know the size of the output. On Linux the size of the + // output pipe is 2 kB; if the output data is more, we + // need to read the data. This isn't possible since we are + // waiting. So we get a deadlock here if we use poWaitOnExit. + OurProcess.Options := [poUsePipes]; + WriteLn('-- External program run started'); + OurProcess.Execute; + while OurProcess.Running do + begin + // make sure we have room + MemStream.SetSize(BytesRead + READ_BYTES); + + // try reading it + NumBytes := OurProcess.Output.Read((MemStream.Memory + BytesRead)^, READ_BYTES); + if NumBytes > 0 + then begin + Inc(BytesRead, NumBytes); + Write('.') //Output progress to screen. + end + else begin + // no data, wait 100 ms + Sleep(100); + end; + end; + // read last part + repeat + // make sure we have room + MemStream.SetSize(BytesRead + READ_BYTES); + // try reading it + NumBytes := OurProcess.Output.Read((MemStream.Memory + BytesRead)^, READ_BYTES); + if NumBytes > 0 + then begin + Inc(BytesRead, NumBytes); + Write('.'); + end; + until NumBytes <= 0; + if BytesRead > 0 then WriteLn; + MemStream.SetSize(BytesRead); + WriteLn('-- External program run complete'); + + OutputLines := TStringList.Create; + OutputLines.LoadFromStream(MemStream); + WriteLn('-- External program output line count = ', OutputLines.Count, ' --'); + for NumBytes := 0 to OutputLines.Count - 1 do + begin + WriteLn(OutputLines[NumBytes]); + end; + WriteLn('-- Program end'); + OutputLines.Free; + OurProcess.Free; + MemStream.Free; +end.