-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmonitorshell.pas
More file actions
198 lines (150 loc) · 4.34 KB
/
Copy pathmonitorshell.pas
File metadata and controls
198 lines (150 loc) · 4.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
unit monitorshell;
{$mode objfpc}{$H+}
interface
uses
Classes,
SysUtils,
Shell,
GlobalTypes,
Threads;
const
MAX_ACTIVE_MESSAGES = 1000;
type
TMonitorShellCommand = class(TShellCommand)
fcs : trtlcriticalsection;
FMessageReady : TSemaphoreHandle;
FMessageList : TStringList;
FCommandActive : boolean;
FLastMessage : string;
public
constructor Create;
destructor Destroy; override;
private
function GetLastMessage : string;
public
function DoHelp(AShell:TShell;ASession:TShellSession):Boolean; override;
function DoInfo(AShell:TShell;ASession:TShellSession):Boolean; override;
function DoCommand(AShell:TShell;ASession:TShellSession;AParameters:TStrings):Boolean; override;
procedure Log(amsg : string);
property Message : string write Log;
property LastMessage : string read GetLastMessage;
end;
var
moncmd : TMonitorShellCommand;
implementation
uses
remoteshell,
services,
strutils,
winsock2,
GlobalConst;
constructor TMonitorShellCommand.Create;
begin
inherited Create;
Name:='MON';
Flags:=SHELL_COMMAND_FLAG_INFO or SHELL_COMMAND_FLAG_HELP;
initcriticalsection(fcs);
FMessageReady := SemaphoreCreate(1);
FMessageList := TStringList.Create;
FCommandActive := False;
FLastMessage:='';
end;
destructor TMonitorShellCommand.Destroy;
begin
SemaphoreDestroy(FMessageReady);
inherited Destroy;
end;
function TMonitorShellCommand.DoHelp(AShell:TShell;ASession:TShellSession):Boolean;
begin
Result:=False;
if AShell = nil then Exit;
AShell.DoOutput(ASession,'Monitor logging output from your application.');
AShell.DoOutput(ASession,'');
AShell.DoOutput(ASession,'MON - monitor output indefinitely.');
AShell.DoOutput(ASession,' Use the escape sequence and quit telnet to terminate.');
AShell.DoOutput(ASession,'MON <timeout> - monitor for <timeout> seconds');
Result := True;
end;
function TMonitorShellCommand.DoInfo(AShell:TShell;ASession:TShellSession):Boolean;
begin
Result:=False;
if AShell = nil then Exit;
AShell.DoOutput(ASession,'Monitor logging output from your application.');
Result := True;
end;
function TMonitorShellCommand.DoCommand(AShell:TShell;ASession:TShellSession;AParameters:TStrings):Boolean;
var
CommandSecs : String;
msg : string;
starttime : qword;
timeused : integer;
timeout : integer;
StopNow : boolean;
begin
Result:=False;
if AShell = nil then Exit;
CommandSecs := AShell.ParameterIndex(0,AParameters);
StopNow := False;
FCommandActive := true;
if (CommandSecs <> '') then
begin
try
timeout := strtoint(CommandSecs);
except
timeout := MAXLONGINT;
end;
AShell.DoOutput(ASession, 'Monitoring for ' + inttostr(timeout) + ' seconds.');
end
else
begin
timeout := MAXLONGINT;
AShell.DoOutput(ASession, 'Monitoring until session closed (usually use <ctrl> ] and then type quit to close the session)');
end;
timeused := 0;
starttime := gettickcount64;
while (timeused < timeout) and (not StopNow) do
begin
// wait here until we have something to do.
SemaphoreWaitEx(FMessageReady, 1000);
//now lock the fmessage list so we can safely remove the
//first message from it.
EnterCriticalSection(fcs);
While (FMessageList.Count > 0) do
begin
msg := FMessageList[0];
FMessageList.Delete(0);
LeaveCriticalSection(fcs);
// and send that message to the output.
StopNow := not AShell.DoOutput(ASession, msg);
EnterCriticalSection(fcs);
end;
LeaveCriticalSection(fcs);
// calculate time we have been runnin for in seconds.
timeused := (gettickcount64 - starttime) div 1000;
end;
Result := true;
FCommandActive := False;
end;
procedure TMonitorShellCommand.Log(amsg : string);
begin
// if not active, we can still store the last n messages.
if (not FCommandActive) then
if (FMessageList.Count > MAX_ACTIVE_MESSAGES) then
FMessageList.Delete(0);
entercriticalsection(fcs);
FMessageList.Add(amsg);
FLastMessage := amsg;
leavecriticalsection(fcs);
// signal the semaphore to make the thread run.
SemaphoreSignal(FMessageReady);
end;
function TMonitorShellCommand.GetLastMessage : string;
begin
entercriticalsection(fcs);
Result := FLastMessage;
leavecriticalsection(fcs);
end;
initialization
moncmd := TMonitorShellCommand.Create;
ShellRegisterCommand(moncmd);
end.