From 1a9939306fbd835a232c80e127a00633d299e356 Mon Sep 17 00:00:00 2001 From: mysticbbs Date: Tue, 21 Aug 2012 12:23:47 -0400 Subject: [PATCH] Pipes and NodeSpy --- mystic/HISTORY.txt | 7 +- mystic/bbs_core.pas | 7 +- mystic/bbs_edit_full.pas | 31 +-- mystic/bbs_io.pas | 24 ++- mystic/bbs_menus.pas | 2 +- mystic/bbs_nodechat.pas | 2 +- mystic/bbs_nodeinfo.pas | 24 +-- mystic/bbs_user.pas | 4 +- mystic/bbs_userchat.pas | 2 +- mystic/default.txt | 8 +- mystic/mis.pas | 5 +- mystic/mis_ansiwfc.pas | 10 +- mystic/mis_client_telnet.pas | 16 +- mystic/mutil.cfg | 2 +- mystic/mystic.pas | 3 + mystic/nodespy.pas | 388 +++++++++++++++++++++++++++-------- mystic/records.pas | 13 +- mystic/todo.pas | 2 + 18 files changed, 394 insertions(+), 156 deletions(-) diff --git a/mystic/HISTORY.txt b/mystic/HISTORY.txt index 4c208c2..1d64429 100644 --- a/mystic/HISTORY.txt +++ b/mystic/HISTORY.txt @@ -4689,4 +4689,9 @@ list display to not get redrawn after. ! Duplicate IP check in MIS was not working properly. It is now. - + + + MIS telnet in Windows now has an option to hide node windows. + + + Added a new utility called NodeSpy. This utility will allow you to see + who is online from the command line. It will also allow you to snoop/spy + on a node, kick people from a node, and engage in chat with the user. diff --git a/mystic/bbs_core.pas b/mystic/bbs_core.pas index 066cae5..511d3d2 100644 --- a/mystic/bbs_core.pas +++ b/mystic/bbs_core.pas @@ -11,6 +11,7 @@ Uses {$ENDIF} m_FileIO, m_Strings, + m_Pipe_Disk, m_DateTime, BBS_Common, BBS_IO, @@ -26,13 +27,14 @@ Const Type TBBSCore = Class {$IFNDEF UNIX} - Client : TIOBase; + Client : TIOBase; {$ENDIF} User : TBBSUser; Msgs : TMsgBase; FileBase : TFileBase; Menu : TMenuEngine; IO : TBBSIO; + Pipe : TPipeDisk; EventFile : File of EventRec; ThemeFile : File of RecTheme; VoteFile : File of VoteRec; @@ -142,6 +144,7 @@ End; Destructor TBBSCore.Destroy; Begin + Pipe.Free; Msgs.Free; FileBase.Free; Menu.Free; @@ -161,7 +164,7 @@ Procedure TBBSCore.UpdateHistory; Var History : RecHistory; Begin - If User.ThisUser.Flags AND UserNoHistory = 0 Then Exit; + If User.ThisUser.Flags AND UserNoHistory <> 0 Then Exit; Assign (HistoryFile, Config.DataPath + 'history.dat'); ioReset (HistoryFile, SizeOf(RecHistory), fmRWDN); diff --git a/mystic/bbs_edit_full.pas b/mystic/bbs_edit_full.pas index bf2f8fb..d79e414 100644 --- a/mystic/bbs_edit_full.pas +++ b/mystic/bbs_edit_full.pas @@ -13,18 +13,9 @@ Uses bbs_Common, bbs_Core; -Procedure Print (S: String); -Begin - {$IFNDEF UNIX} - If Not Session.LocalMode Then Session.io.BufAddStr(S); - {$ENDIF} - - Screen.WriteStr(S); -End; - Procedure PrintLn (S: String); Begin - Print (S + #13#10); + Session.io.BufAddStr(S + #13#10); End; Function AnsiEditor (Var Lines: Integer; WrapPos: Byte; MaxLines: Integer; TEdit, Forced: Boolean; Var Subj: String) : Boolean; @@ -70,7 +61,7 @@ Begin B := CurLine; Repeat - If B <= TotalLine Then Print(Session.Msgs.MsgText[B]); + If B <= TotalLine Then Session.io.BufAddStr(Session.Msgs.MsgText[B]); If B <= TotalLine + 1 Then Begin Session.io.AnsiClrEOL; PrintLn(''); @@ -101,7 +92,7 @@ Begin A := WinStart; Repeat - If B <= TotalLine Then Print(Session.Msgs.MsgText[B]); + If B <= TotalLine Then Session.io.BufAddStr(Session.Msgs.MsgText[B]); Session.io.AnsiClrEOL; PrintLn(''); Inc (A); @@ -208,7 +199,7 @@ Begin Repeat If (CurY + (A - CurLine) <= WinEnd) and (A <= TotalLine) Then Begin - Print(Session.Msgs.MsgText[A]); + Session.io.BufAddStr(Session.Msgs.MsgText[A]); Session.io.AnsiClrEOL; PrintLn(''); End Else @@ -291,7 +282,7 @@ Begin Delete (Session.Msgs.MsgText[CurLine], CurX, 1); If CurX < Length(Session.Msgs.MsgText[CurLine]) + 1 Then Begin - Print (Copy(Session.Msgs.MsgText[CurLine], CurX, Length(Session.Msgs.MsgText[CurLine])) + ' '); + Session.io.BufAddStr (Copy(Session.Msgs.MsgText[CurLine], CurX, Length(Session.Msgs.MsgText[CurLine])) + ' '); UpdatePosition; End; End Else @@ -391,13 +382,13 @@ Procedure AddChar (Ch: Char); Begin If InsertMode Then Begin Insert (Ch, Session.Msgs.MsgText[Curline], CurX); - Print (Copy(Session.Msgs.MsgText[CurLine], CurX, Length(Session.Msgs.MsgText[CurLine]))); + Session.io.BufAddStr (Copy(Session.Msgs.MsgText[CurLine], CurX, Length(Session.Msgs.MsgText[CurLine]))); End Else Begin If CurX > Length(Session.Msgs.MsgText[CurLine]) Then Inc(Session.Msgs.MsgText[CurLine][0]); Session.Msgs.MsgText[CurLine][CurX] := Ch; - Print (Ch); + Session.io.BufAddStr (Ch); End; Inc (CurX); @@ -412,7 +403,7 @@ Begin Session.io.AnsiColor (Session.io.ScreenInfo[3].A); Session.io.AnsiGotoXY (Session.io.ScreenInfo[3].X, Session.io.ScreenInfo[3].Y); - If InsertMode Then Print('INS') else Print('OVR'); { ++lang } + If InsertMode Then Session.io.BufAddStr('INS') else Session.io.BufAddStr('OVR'); { ++lang } Session.io.AnsiGotoXY (CurX, CurY); Session.io.AnsiColor (WinText); @@ -520,7 +511,7 @@ Var Else Session.io.AnsiColor (Session.io.ScreenInfo[2].A); - Print (strPadR(QText[QuoteTopPage + QuoteCurLine], 79, ' ')); + Session.io.BufAddStr (strPadR(QText[QuoteTopPage + QuoteCurLine], 79, ' ')); End; Procedure UpdateWindow; @@ -531,7 +522,7 @@ Var Session.io.AnsiColor (Session.io.ScreenInfo[2].A); For Count := QuoteTopPage to QuoteTopPage + 5 Do Begin - If Count <= QuoteLines Then Print (QText[Count]); + If Count <= QuoteLines Then Session.io.BufAddStr (QText[Count]); Session.io.AnsiClrEOL; @@ -805,7 +796,7 @@ Begin #82 : ToggleInsert(True); #83 : If CurX <= Length(Session.Msgs.MsgText[CurLine]) Then Begin Delete (Session.Msgs.MsgText[CurLine], CurX, 1); - Print (Copy(Session.Msgs.MsgText[CurLine], CurX, Length(Session.Msgs.MsgText[CurLine])) + ' '); + Session.io.BufAddStr (Copy(Session.Msgs.MsgText[CurLine], CurX, Length(Session.Msgs.MsgText[CurLine])) + ' '); UpdatePosition; End Else If CurLine < TotalLine Then diff --git a/mystic/bbs_io.pas b/mystic/bbs_io.pas index 52e97c0..565ec35 100644 --- a/mystic/bbs_io.pas +++ b/mystic/bbs_io.pas @@ -56,11 +56,11 @@ Type InputPos : Byte; GetKeyCallBack : TGetKeyCallBack; LastSecond : LongInt; + OutBuffer : Array[0..TBBSIOBufferSize] of Char; + OutBufPos : SmallInt; {$IFDEF WINDOWS} - OutBuffer : Array[0..TBBSIOBufferSize] of Char; - OutBufPos : SmallInt; - SocketEvent : THandle; + SocketEvent : THandle; {$ENDIF} Constructor Create (Var Owner: Pointer); @@ -143,11 +143,11 @@ Begin LastMCIValue := ''; InputPos := 0; + FillChar(OutBuffer, SizeOf(OutBuffer), 0); + + OutBufPos := 0; + {$IFDEF WINDOWS} - FillChar(OutBuffer, SizeOf(OutBuffer), 0); - - OutBufPos := 0; - If Not TBBSCore(Core).LocalMode Then SocketEvent := WSACreateEvent; {$ENDIF} @@ -168,13 +168,11 @@ End; Procedure TBBSIO.BufAddChar (Ch: Char); Begin - {$IFDEF WINDOWS} OutBuffer[OutBufPos] := Ch; Inc (OutBufPos); If OutBufPos = TBBSIOBufferSize Then BufFlush; - {$ENDIF} Term.Process(Ch); End; @@ -194,11 +192,19 @@ Begin If Not TBBSCore(Core).LocalMode Then TBBSCore(Core).Client.WriteBuf(OutBuffer, OutBufPos); + If Session.Pipe.Connected Then + Session.Pipe.SendToPipe(OutBuffer, OutBufPos); + OutBufPos := 0; End; {$ENDIF} {$IFDEF UNIX} + If Session.Pipe.Connected Then + Session.Pipe.SendToPipe(OutBuffer, OutBufPos); + + OutBufPos := 0; + Screen.BufFlush; {$ENDIF} End; diff --git a/mystic/bbs_menus.pas b/mystic/bbs_menus.pas index c7130ce..e108cad 100644 --- a/mystic/bbs_menus.pas +++ b/mystic/bbs_menus.pas @@ -275,7 +275,7 @@ Begin 'C' : Node_Chat; 'P' : PageUserForChat; 'S' : Send_Node_Message (3, CmdData, 0); - 'W' : Show_Whos_Online; + 'W' : WhosOnline; End; 'O' : Case Cmd[2] of 'S' : Session.Msgs.ToggleNewScan(True); diff --git a/mystic/bbs_nodechat.pas b/mystic/bbs_nodechat.pas index c521a50..1d555a7 100644 --- a/mystic/bbs_nodechat.pas +++ b/mystic/bbs_nodechat.pas @@ -450,7 +450,7 @@ Begin End Else If Str2 = '/WHO' Then Begin Session.io.AnsiClear; - Show_Whos_Online; + WhosOnline; Chat_Template; FullReDraw; End Else diff --git a/mystic/bbs_nodeinfo.pas b/mystic/bbs_nodeinfo.pas index 426b0c1..4e4d92f 100644 --- a/mystic/bbs_nodeinfo.pas +++ b/mystic/bbs_nodeinfo.pas @@ -9,7 +9,7 @@ Uses Function GetChatRecord (Node: Byte; Var Chat: ChatRec) : Boolean; Function IsUserOnline (UserName: String) : Word; -Procedure Show_Whos_Online; +Procedure WhosOnline; Procedure Send_Node_Message (MsgType: Byte; Data: String; Room: Byte); Function CheckNodeMessages : Boolean; Procedure Set_Node_Action (Action: String); @@ -87,7 +87,7 @@ Begin {$ENDIF} End; -Procedure Show_Whos_Online; +Procedure WhosOnline; Var TChat : ChatRec; Count : Word; @@ -97,19 +97,12 @@ Begin For Count := 1 to Config.INetTNNodes Do Begin Session.io.PromptInfo[1] := strI2S(Count); - Assign (ChatFile, Config.DataPath + 'chat' + strI2S(Count) + '.dat'); - - {$I-} Reset(ChatFile); {$I+} - - If IoResult <> 0 Then Begin + If Not GetChatRecord (Count, TChat) Then Begin Session.io.OutFullLn (Session.GetPrompt(268)); Continue; End; - Read (ChatFile, TChat); - Close (ChatFile); - If TChat.Active and ((Not TChat.Invisible) or (TChat.Invisible and Session.User.Access(Config.AcsSeeInvis))) Then Begin Session.io.PromptInfo[2] := TChat.Name; Session.io.PromptInfo[3] := TChat.Action; @@ -141,7 +134,7 @@ Begin Repeat Session.io.OutFull (Session.GetPrompt(146)); Str := Session.io.GetInput(3, 3, 12, ''); - If Str = '?' Then Show_Whos_Online Else Break; + If Str = '?' Then WhosOnline Else Break; Until False; ToNode := strS2I(Str); @@ -230,8 +223,7 @@ Var MsgFile : File of NodeMsgRec; SplitChat : Boolean; Begin - Result := False; - FileMode := 66; + Result := False; Assign (MsgFile, Session.TempPath + 'chat.tmp'); @@ -276,6 +268,12 @@ Begin OpenUserChat(SplitChat, True, Msg.FromNode); End; 10: OpenUserChat(SplitChat, False, Msg.FromNode); + 11: Begin + Session.Pipe.CreatePipe; + Session.Pipe.WaitForPipe(300); + End; + 12: If Session.Pipe.Connected Then Session.Pipe.Disconnect; + 13: Halt(0); End; If Result And (Msg.MsgType = 3) Then diff --git a/mystic/bbs_user.pas b/mystic/bbs_user.pas index 687de1d..47d49f3 100644 --- a/mystic/bbs_user.pas +++ b/mystic/bbs_user.pas @@ -1081,7 +1081,7 @@ Begin ThisUser.CallsToday := 0; ThisUser.DLsToday := 0; ThisUser.DLkToday := 0; - ThisUser.TimeLeft := Security.Time + ThisUser.TimeLeft := Security.Time; End; If Not Session.LocalMode And (ThisUser.Flags AND UserNoLastCall = 0) Then Begin @@ -1138,8 +1138,6 @@ Begin If (Session.TimeOffset = 0) or (Session.TimeOffset > ThisUser.TimeLeft) Then Session.SetTimeLeft (ThisUser.TimeLeft); - // check account expired -- DONE - // check password change -- DONE // check auto-upgrades posts/calls/downloads/uploads/etc If DateValid(Session.User.ThisUser.Expires) Then diff --git a/mystic/bbs_userchat.pas b/mystic/bbs_userchat.pas index b61b48a..3b3efa7 100644 --- a/mystic/bbs_userchat.pas +++ b/mystic/bbs_userchat.pas @@ -29,7 +29,7 @@ Begin Str := Session.io.GetInput(3, 3, 12, ''); - If Str = '?' Then Show_Whos_Online Else + If Str = '?' Then WhosOnline Else If Str = 'Q' Then Exit Else Break; Until False; diff --git a/mystic/default.txt b/mystic/default.txt index 282a3a6..a4122b9 100644 --- a/mystic/default.txt +++ b/mystic/default.txt @@ -373,7 +373,7 @@ ; &1 = File base name 203 |CR |11|&1 will NOT be scanned in new file scan!|CR ; &1 = File base name -204 |CR| 11|&1 will be scanned in new file scan!|CR +204 |CR |11|&1 will be scanned in new file scan!|CR ; Displayed if file already exists when user trys to upload. 205 File already exists. ; Displayed before running uploads processor @@ -938,11 +938,11 @@ ; User2User sending chat request &1=User &2=Node 482 |CR|15Sending chat request to |&1...|DE|DE|CR ; User2User chat mode starting -483 |CL|09|17 ° |15Chat mode engaged.|$X70 ESC/Quit |16|CR +483 |16|CL|09|17 ° |15Chat mode engaged.|$X70 ESC/Quit |16|CR ; User2User chat mode ended -484 |CL|09|17 ° |15Chat mode end.|$X79 |16|DE|DE +484 |16|CL|09|17 ° |15Chat mode end.|$X79 |16|DE|DE ; User2User accept chat page request? &1=user &2=Node -485 |CL|15|&1 is requesting private user chat. Accept? |11 +485 |16|CL|15|&1 is requesting private user chat. Accept? |11 ; MsgBase quickscan header prompt 486 |CR|12Starting Quick Scan|CR ; MsgBase quickscan Scanning prompt diff --git a/mystic/mis.pas b/mystic/mis.pas index f10912e..81f8b80 100644 --- a/mystic/mis.pas +++ b/mystic/mis.pas @@ -419,6 +419,7 @@ Begin End; {$IFDEF UNIX} +(* Procedure Snoop; Begin If FocusCurrent <> FocusTelnet Then Exit; @@ -453,7 +454,7 @@ Begin SwitchFocus; End; End; - +*) Procedure DaemonEventSignal (Sig : LongInt); cdecl; Begin Case Sig of @@ -592,7 +593,7 @@ Begin End; End; #09 : SwitchFocus; - #13 : {$IFDEF UNIX}Snoop{$ENDIF}; +// #13 : {$IFDEF UNIX}Snoop{$ENDIF}; #27 : Break; #32 : LocalLogin; End; diff --git a/mystic/mis_ansiwfc.pas b/mystic/mis_ansiwfc.pas index 08e12c8..d5af681 100644 --- a/mystic/mis_ansiwfc.pas +++ b/mystic/mis_ansiwfc.pas @@ -31,7 +31,7 @@ Const #1,'³',#25,'K','³', #8,'°',#24,'°', #1,'³',#25,'K','³', #8,'°',#24, '°', #1,'À',#26,'K','Ä','Ù', #8,'°',#24,#26,'O','°',#24,#23,' ', #1, 'T','A','B','/','S','w','i','t','c','h',' ','W','i','n','d','o','w', - #25, #2,'E','N','T','E','R','/','S','n','o','o','p',#25, #2,'S','P', + #25, #2,' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',#25, #2,'S','P', 'A','C','E','/','L','o','c','a','l',#25, #2,'A','L','T','-','K','/', 'K','i','l','l',' ','U','s','e','r',#25, #2,'E','S','C','/','S','h', 'u','t','d','o','w','n',' ',#24); @@ -39,10 +39,6 @@ Begin Console.LoadScreenImage(ImageData, ImageData_Length, ImageData_Width, 1, 1); //Console.WriteXY (25, 1, 113, strPadC(mysVersionText, 30, ' ')); - - {$IFDEF UNIX} - Console.WriteXY (1, 25, 113, strPadC('ENTER/Snoop SPACE/Local TELNET TAB/Switch ESC/Shutdown', 79, ' ')); - {$ELSE} - Console.WriteXY (1, 25, 113, strPadC('SPACE/Local TELNET TAB/Switch ESC/Shutdown', 79, ' ')); - {$ENDIF} + + Console.WriteXY (1, 25, 113, strPadC('SPACE/Local TELNET TAB/Switch ESC/Shutdown', 79, ' ')); End; diff --git a/mystic/mis_client_telnet.pas b/mystic/mis_client_telnet.pas index e4bfe75..c453518 100644 --- a/mystic/mis_client_telnet.pas +++ b/mystic/mis_client_telnet.pas @@ -28,7 +28,7 @@ Function CreateTelnet (Owner: TServerManager; Config: RecConfig; ND: TNodeData; Type TTelnetServer = Class(TServerClient) ND : TNodeData; - Snooping : Boolean; +// Snooping : Boolean; Constructor Create (Owner: TServerManager; ND: TNodeData; CliSock: TIOSocket); Procedure Execute; Override; Destructor Destroy; Override; @@ -46,7 +46,7 @@ Begin Inherited Create(Owner, CliSock); Self.ND := ND; - Snooping := False; +// Snooping := False; End; {$IFDEF WINDOWS} @@ -84,8 +84,12 @@ Begin FillChar(SI, SizeOf(SI), 0); FillChar(PI, SizeOf(PI), 0); - SI.dwFlags := STARTF_USESHOWWINDOW; - SI.wShowWindow := SW_SHOWMINNOACTIVE; + SI.dwFlags := STARTF_USESHOWWINDOW; + + If bbsConfig.inetTNHidden Then + SI.wShowWindow := SW_HIDE + Else + SI.wShowWindow := SW_SHOWMINNOACTIVE; If CreateProcess(NIL, PChar(@Cmd[1]), NIL, NIL, True, Create_New_Console + Normal_Priority_Class, NIL, NIL, SI, PI) Then @@ -140,8 +144,8 @@ Begin bRead := Proc.Output.Read(Buffer, BufferSize); Client.WriteBufEscaped (Buffer, bRead); - If Snooping Then - Term.ProcessBuf(Buffer[0], bRead); +// If Snooping Then +// Term.ProcessBuf(Buffer[0], bRead); End; End Else If Client.DataWaiting Then Begin diff --git a/mystic/mutil.cfg b/mystic/mutil.cfg index 5503739..6732ee4 100644 --- a/mystic/mutil.cfg +++ b/mystic/mutil.cfg @@ -40,7 +40,7 @@ Import_FIDONET.NA = false Import_FILEBONE.NA = false - Import_FILES.BBS = false + Import_FILES.BBS = true MassUpload = false GenerateTopLists = false diff --git a/mystic/mystic.pas b/mystic/mystic.pas index 7feb41b..517931b 100644 --- a/mystic/mystic.pas +++ b/mystic/mystic.pas @@ -40,6 +40,7 @@ Uses m_DateTime, m_Output, m_Input, + m_Pipe_Disk, bbs_Common, bbs_Core, bbs_NodeInfo, @@ -233,6 +234,8 @@ Begin Session.TempPath := Config.SystemPath + 'temp' + strI2S(Session.NodeNum) + PathChar; + Session.Pipe := TPipeDisk.Create(Config.DataPath, False, Session.NodeNum); + {$I-} MkDir (Config.SystemPath + 'temp' + strI2S(Session.NodeNum)); {$I+} diff --git a/mystic/nodespy.pas b/mystic/nodespy.pas index 44c4d0f..be0269b 100644 --- a/mystic/nodespy.pas +++ b/mystic/nodespy.pas @@ -1,5 +1,12 @@ Program NodeSpy; +// page chat +// user editor +// split chat +// auto snoop +// local login +// terminal mode + {$I M_OPS.PAS} Uses @@ -22,9 +29,21 @@ Uses Const HiddenNode = 255; - UpdateTimer = 500; + UpdateNode = 500; + UpdateStats = 6000 * 10; + + AutoSnoop : Boolean = True; + +Type + PNodeInfo = ^TNodeInfo; + TNodeInfo = Record + Node : Byte; + User : String[30]; + Action : String[50]; + End; Var + NodeInfo : Array[1..255] of PNodeInfo; ChatFile : File of ChatRec; Chat : ChatRec; ConfigFile : File of RecConfig; @@ -35,6 +54,75 @@ Var Screen : TOutput; Keyboard : TInput; +{$I NODESPY_ANSI.PAS} + +Procedure ApplicationShutdown; +Var + Count : Byte; +Begin + For Count := Config.inetTNNodes DownTo 1 Do + If Assigned(NodeInfo[Count]) Then + Dispose(NodeInfo[Count]); + + Keyboard.Free; + Screen.Free; +End; + +Procedure ApplicationInit; +Var +{$IFDEF UNIX} + Info : Stat; +{$ENDIF} + Count : Byte; +Begin + {$IFDEF UNIX} + If fpStat('nodespy', Info) = 0 Then Begin + fpSetGID (Info.st_GID); + fpSetUID (Info.st_UID); + End; + {$ENDIF} + + ExitProc := @ApplicationShutdown; + Screen := TOutput.Create(True); + Keyboard := TInput.Create; + + Assign (ConfigFile, 'mystic.dat'); + Reset (ConfigFile); + + If IoResult <> 0 Then Begin + BasePath := GetENV('mysticbbs'); + + If BasePath <> '' Then BasePath := DirSlash(BasePath); + + Assign (ConfigFile, BasePath + 'mystic.dat'); + Reset (ConfigFile); + + If IoResult <> 0 Then Begin + Screen.WriteLine ('ERROR: Unable to read MYSTIC.DAT' + #13#10); + Screen.WriteLine ('MYSTIC.DAT must exist in the same directory as NodeSpy, or in the'); + Screen.WriteLine ('path defined by the MYSTICBBS environment variable.'); + + Halt (1); + End; + End; + + Read (ConfigFile, Config); + Close (ConfigFile); + + If Config.DataChanged <> mysDataChanged Then Begin + Screen.WriteLine ('ERROR: NodeSpy has detected a version mismatch' + #13#10); + Screen.WriteLine ('NodeSpy or another BBS utility is an older incompatible version. Make'); + Screen.WriteLine ('sure you have upgraded properly!'); + + Halt (1); + End; + + DirCreate(Config.SystemPath + 'temp' + strI2S(HiddenNode)); + + For Count := 1 to Config.inetTNNodes Do + New (NodeInfo[Count]); +End; + Function ShowMsgBox (BoxType: Byte; Str: String) : Boolean; Var Len : Byte; @@ -119,6 +207,7 @@ Begin MsgBox.Free; Screen.CursorXY (SavedX, SavedY); + Screen.TextAttr := SavedA; End; @@ -277,8 +366,8 @@ Begin Screen.TextAttr := 7; Screen.ClearScreen; - Screen.WriteXY (1, 1, 31, strRep(' ', 79)); - Screen.WriteXY (2, 1, 31, 'Chat mode engaged'); + Screen.WriteXY ( 1, 1, 31, strRep(' ', 79)); + Screen.WriteXY ( 2, 1, 31, 'Chat mode engaged'); Screen.WriteXY (71, 1, 31, 'ESC/Quit'); Screen.CursorXY (1, 3); @@ -355,6 +444,7 @@ Begin Erase(fIn); Screen.TextAttr := 7; + Screen.ClearScreen; End; @@ -378,43 +468,42 @@ Var Screen.WriteXY ( 1, 25, Config.StatusColor1, strRep(' ', 79)); Screen.WriteXY ( 2, 25, Config.StatusColor1, 'User'); Screen.WriteXY ( 7, 25, Config.StatusColor2, Chat.Name); - Screen.WriteXY (56, 25, Config.StatusColor3, 'ALT: C)hat K)ick e(X)it'); + Screen.WriteXY (54, 25, Config.StatusColor3, 'ALT (C)hat (K)ick e(X)it'); Screen.SetWindow ( 1, 1, 80, 24, True); Screen.CursorXY (SX, SY); + Screen.TextAttr := SA; End; End; Begin - WriteLn; - WriteLn('Requesting snoop session for node ', Node, '...'); - WriteLn; + GetChatRecord(Node, Chat); + + If Not Chat.Active Then Begin + ShowMsgBox(0, 'Node ' + strI2S(Node) + ' is not in use'); + Exit; + End; + + ShowMsgBox (3, 'Requesting snoop session for node ' + strI2S(Node)); SendNodeMessage(Node, 11); Pipe := TPipeDisk.Create(Config.DataPath, True, Node); If Not Pipe.ConnectPipe(1500) Then Begin - WriteLn('NodeSpy was not able to establish a snoop session. Sessions'); - WriteLn('cannot be created if a user is in a door or a file transfer.'); - + ShowMsgBox (0, 'Unable to establish a session. Try again'); Pipe.Free; - Exit; End; - WriteLn('Connection established'); + Term := TTermAnsi.Create(Screen); - Keyboard := TInput.Create; - Screen := TOutput.Create(True); - Term := TTermAnsi.Create(Screen); - - Screen.SetWindowTitle('Snooping node ' + strI2S(Node)); + Screen.SetWindowTitle('[NodeSpy] Snooping ' + strI2S(Node)); DrawStatus; - Update := TimerSet(UpdateTimer); + Update := TimerSet(UpdateNode); While Pipe.Connected Do Begin Pipe.ReadFromPipe(Buffer, SizeOf(Buffer), BufRead); @@ -443,7 +532,7 @@ Begin DrawStatus; - Update := TimerSet(UpdateTimer); + Update := TimerSet(UpdateNode); End; End; @@ -457,88 +546,219 @@ Begin Pipe.Disconnect; Pipe.Free; Term.Free; - Screen.Free; - - WriteLn; - WriteLn; - WriteLn ('Session closed'); End; -Procedure ShowWhosOnline; +Procedure UpdateOnlineStatus; Var - Count : Word; + Count : LongInt; Begin - WriteLn; - WriteLn('### UserName Action'); - WriteLn(strRep('=', 79)); - - For Count := 1 to Config.INetTNNodes Do Begin - If GetChatRecord(Count, Chat) Then Begin - WriteLn (strPadL(strI2S(Count), 3, '0') + ' ' + - strPadR(Chat.Name, 25, ' ') + ' ' + - strPadR(Chat.Action, 45, ' ')); - End Else - WriteLn (strPadL(strI2S(Count), 3, '0') + ' ' + - strPadR('Waiting', 25, ' ') + ' ' + - strPadR('Waiting', 45, ' ')); - End; - - WriteLn (strRep('=', 79)); - WriteLn ('Execute NodeSpy [node number] to spy on a node'); + For Count := 1 to Config.inetTNNodes Do + If GetChatRecord(Count, Chat) and (Chat.Active) Then Begin + NodeInfo[Count]^.Node := Count; + NodeInfo[Count]^.User := Chat.Name; + NodeInfo[Count]^.Action := Chat.Action; + End Else Begin + NodeInfo[Count]^.Node := Count; + NodeInfo[Count]^.User := 'Waiting'; + NodeInfo[Count]^.Action := 'Waiting'; + End; End; +Procedure MainMenu; Var - NodeNum : Byte; - {$IFDEF UNIX} - Info : Stat; - {$ENDIF} -Begin - {$IFDEF UNIX} - If fpStat('nodespy', Info) = 0 Then Begin - fpSetGID (Info.st_GID); - fpSetUID (Info.st_UID); + StatTotalDays : LongInt = 0; + StatTodayCalls : LongInt = 0; + StatTotalCalls : LongInt = 0; + StatTodayNewUsers : LongInt = 0; + StatTotalNewUsers : LongInt = 0; + StatTodayPosts : LongInt = 0; + StatTotalPosts : LongInt = 0; + StatTodayEmail : LongInt = 0; + StatTotalEmail : LongInt = 0; + StatTodayDownloads : LongInt = 0; + StatTotalDownloads : LongInt = 0; + StatTodayUploads : LongInt = 0; + StatTotalUploads : LongInt = 0; + + NodeTimer : LongInt; + TopPage : SmallInt = 1; + CurNode : SmallInt = 1; + + Procedure DrawStats; + Begin + Screen.WriteXY (12, 18, 9, strPadL(strI2S(StatTodayCalls), 6, ' ')); + Screen.WriteXY (12, 19, 9, strPadL(strI2S(StatTodayNewUsers), 6, ' ')); + Screen.WriteXY (12, 20, 9, strPadL(strI2S(StatTodayPosts), 6, ' ')); + Screen.WriteXY (12, 21, 9, strPadL(strI2S(StatTodayEmail), 6, ' ')); + Screen.WriteXY (12, 22, 9, strPadL(strI2S(StatTodayDownloads), 6, ' ')); + Screen.WriteXY (12, 23, 9, strPadL(strI2S(StatTodayUploads), 6, ' ')); + + Screen.WriteXY (19, 18, 9, strPadL(strComma(StatTotalCalls), 12, ' ')); + Screen.WriteXY (19, 19, 9, strPadL(strComma(StatTotalNewUsers), 12, ' ')); + Screen.WriteXY (19, 20, 9, strPadL(strComma(StatTotalPosts), 12, ' ')); + Screen.WriteXY (19, 21, 9, strPadL(strComma(StatTotalEmail), 12, ' ')); + Screen.WriteXY (19, 22, 9, strPadL(strComma(StatTotalDownloads), 12, ' ')); + Screen.WriteXY (19, 23, 9, strPadL(strComma(StatTotalUploads), 12, ' ')); End; - {$ENDIF} - Assign (ConfigFile, 'mystic.dat'); - Reset (ConfigFile); + Procedure UpdateStats; + Var + HistFile : File of RecHistory; + Hist : RecHistory; + Begin + FileMode := 66; - If IoResult <> 0 Then Begin - BasePath := GetENV('mysticbbs'); + Assign (HistFile, Config.DataPath + 'history.dat'); + Reset (HistFile); - If BasePath <> '' Then BasePath := DirSlash(BasePath); + If IoResult <> 0 Then Exit; - Assign (ConfigFile, BasePath + 'mystic.dat'); - Reset (ConfigFile); + StatTotalDays := 0; + + While Not Eof(HistFile) Do Begin + Read (HistFile, Hist); + + Inc (StatTotalDays); + + Inc (StatTotalCalls, Hist.Calls); + Inc (StatTotalNewUsers, Hist.NewUsers); + Inc (StatTotalDownloads, Hist.Downloads); + Inc (StatTotalPosts, Hist.Posts); + Inc (StatTotalEmail, Hist.Emails); + Inc (StatTotalUploads, Hist.Uploads); + + If DateDos2Str(Hist.Date, 1) = DateDos2Str(CurDateDos, 1) Then Begin + Inc (StatTodayCalls, Hist.Calls); + Inc (StatTodayNewUsers, Hist.NewUsers); + Inc (StatTodayDownloads, Hist.Downloads); + Inc (StatTodayPosts, Hist.Posts); + Inc (StatTodayEmail, Hist.Emails); + Inc (StatTodayUploads, Hist.Uploads); + End; + End; + + Close (HistFile); + + DrawStats; + End; + + Procedure DrawNodes; + Var + CN : Byte; + Count : Byte; + Attr : Byte; + Begin + For Count := 1 to 5 Do Begin + CN := Count + TopPage - 1; + + If CN > Config.inetTNNodes Then Break; + + If CurNode = CN Then Attr := 31 Else Attr := 7; + + Screen.WriteXY (1, 10 + Count, Attr, + ' ' + + strPadL(strI2S(NodeInfo[CN]^.Node), 3, ' ') + ' ' + + strPadR(NodeInfo[CN]^.User, 25, ' ') + ' ' + + strPadR(NodeInfo[CN]^.Action, 43, ' ') + ' ' + ); - If IoResult <> 0 Then Begin - WriteLn ('ERROR: Unable to read MYSTIC.DAT'); - WriteLn; - WriteLn ('MYSTIC.DAT must exist in the same directory as NodeSpy, or in the'); - WriteLn ('path defined by the MYSTICBBS environment variable.'); - Halt (1); End; End; - Read (ConfigFile, Config); - Close (ConfigFile); +Var + Count : Byte; +Begin + DrawNodeSpyScreen; + UpdateStats; + UpdateOnlineStatus; - If Config.DataChanged <> mysDataChanged Then Begin - WriteLn ('ERROR: NodeSpy has detected a version mismatch'); - WriteLn; - WriteLn ('NodeSpy or another BBS utility is an older incompatible version. Make'); - WriteLn ('sure you have upgraded properly!'); - Halt (1); - End; + DrawNodes; - DirCreate(Config.SystemPath + 'temp' + strI2S(HiddenNode)); + NodeTimer := TimerSet(UpdateNode); - If ParamCount < 1 Then - ShowWhosOnline - Else Begin - NodeNum := strS2I(ParamStr(1)); + Repeat + If Keyboard.KeyWait(1000) Then + Case Keyboard.ReadKey of + #00 : Case Keyboard.ReadKey of + #71 : Begin + TopPage := 1; + CurNode := 1; - If (NodeNum > 0) and (NodeNum <= Config.INetTNNodes) Then - SnoopNode(NodeNum); - End; -End. + DrawNodes; + End; + #72 : If CurNode > 1 Then Begin + Dec (CurNode); + + If CurNode < TopPage Then Dec(TopPage); + + DrawNodes; + End; + #73, + #75 : Begin + Dec (TopPage, 5); + Dec (CurNode, 5); + + If TopPage < 1 Then TopPage := 1; + If CurNode < 1 Then CurNode := 1; + + DrawNodes; + End; + #77, + #81 : Begin + Inc (TopPage, 5); + Inc (CurNode, 5); + + If TopPage + 4 > Config.inetTNNodes Then TopPage := Config.inetTNNodes - 4; + If CurNode > Config.inetTNNodes Then CurNode := Config.inetTNNodes; + + If TopPage < 1 Then TopPage := 1; + + DrawNodes; + End; + #79 : Begin + TopPage := Config.inetTNNodes - 4; + CurNode := Config.inetTNNodes; + + If Toppage < 1 Then TopPage := 1; + + DrawNodes; + End; + #80 : If CurNode < Config.inetTNNodes Then Begin + Inc (CurNode); + If TopPage + 4 < CurNode Then Inc(TopPage); + DrawNodes; + End; + End; + #13 : Begin + SnoopNode(NodeInfo[CurNode]^.Node); + DrawNodeSpyScreen; + UpdateOnlineStatus; + DrawNodes; + DrawStats; + End; + #27 : Break; + End; + + If TimerUp(NodeTimer) Then Begin + UpdateOnlineStatus; + DrawNodes; + + NodeTimer := TimerSet(UpdateNode); + + For Count := 1 to Config.inetTNNodes Do + If NodeInfo[Count]^.User <> 'Waiting' Then Begin + SnoopNode(NodeInfo[Count]^.Node); + DrawNodeSpyScreen; + UpdateOnlineStatus; + DrawNodes; + DrawStats; + End; + End; + Until False; +End; + +Begin + ApplicationInit; + + MainMenu; +End. \ No newline at end of file diff --git a/mystic/records.pas b/mystic/records.pas index 61bd042..c3a8981 100644 --- a/mystic/records.pas +++ b/mystic/records.pas @@ -11,6 +11,13 @@ {$PACKRECORDS 1} +// Add minutes to history +// Change file listing size to Int64 +// Extend msg and file base names to 70 chars? +// local qwk download/upload? +// rewrite event system... +// event types, exec commands, weekly/monthly option? + Const mysSoftwareID = 'Mystic'; // no idea mysCopyYear = '1997-2012'; // its been a long time! @@ -259,7 +266,8 @@ Type inetNNTPDupes : Byte; inetNNTPTimeOut : Word; // UNSORTED - Reserved : Array[1..846] of Char; + inetTNHidden : Boolean; + Reserved : Array[1..845] of Char; End; Const @@ -769,5 +777,8 @@ Type { 8 = user 2 user page } { 9 = user 2 user forced } { 10 = chat accepted } + { 11 = start pipe session } + { 12 = end pipe session } + { 13 = terminte node } Room : Byte; { Chat room number. 0 = chat broadcast } End; diff --git a/mystic/todo.pas b/mystic/todo.pas index 1148dfa..c5074e1 100644 --- a/mystic/todo.pas +++ b/mystic/todo.pas @@ -19,6 +19,8 @@ BUGS AND POSSIBLE ISSUES FPC BUG? DirAttr is suspect in MPL is it 1 byte or 4 in size? ! View archive not working if its external view? [Griffin] ! Test MIS blocking features or just rewrite MIS completely. +! Test midnight rollovers for time (flag for user to be immune to timecheck) +! Elasped time will need to be recalculated based on flag above ^^ FUTURE / IDEAS / WORK IN PROGRESS / NOTES =========================================