source: trunk/Packages/synapse/source/lib/clamsend.pas

Last change on this file was 2, checked in by chronos, 12 years ago
  • Přidáno: Základní kostra projektu.
  • Přidáno: Knihovna synapse.
File size: 9.1 KB
Line 
1{==============================================================================|
2| Project : Ararat Synapse | 001.001.001 |
3|==============================================================================|
4| Content: ClamAV-daemon client |
5|==============================================================================|
6| Copyright (c)2005-2010, Lukas Gebauer |
7| All rights reserved. |
8| |
9| Redistribution and use in source and binary forms, with or without |
10| modification, are permitted provided that the following conditions are met: |
11| |
12| Redistributions of source code must retain the above copyright notice, this |
13| list of conditions and the following disclaimer. |
14| |
15| Redistributions in binary form must reproduce the above copyright notice, |
16| this list of conditions and the following disclaimer in the documentation |
17| and/or other materials provided with the distribution. |
18| |
19| Neither the name of Lukas Gebauer nor the names of its contributors may |
20| be used to endorse or promote products derived from this software without |
21| specific prior written permission. |
22| |
23| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
24| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
27| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
29| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
30| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
33| DAMAGE. |
34|==============================================================================|
35| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
36| Portions created by Lukas Gebauer are Copyright (c)2005-2010. |
37| All Rights Reserved. |
38|==============================================================================|
39| Contributor(s): |
40|==============================================================================|
41| History: see HISTORY.HTM from distribution package |
42| (Found at URL: http://www.ararat.cz/synapse/) |
43|==============================================================================}
44
45{:@abstract( ClamAV-daemon client)
46
47This unit is capable to do antivirus scan of your data by TCP channel to ClamD
48daemon from ClamAV. See more about ClamAV on @LINK(http://www.clamav.net)
49}
50
51{$IFDEF FPC}
52 {$MODE DELPHI}
53{$ENDIF}
54{$Q-}
55{$H+}
56
57{$IFDEF UNICODE}
58 {$WARN IMPLICIT_STRING_CAST OFF}
59 {$WARN IMPLICIT_STRING_CAST_LOSS OFF}
60{$ENDIF}
61
62unit clamsend;
63
64interface
65
66uses
67 SysUtils, Classes,
68 synsock, blcksock, synautil;
69
70const
71 cClamProtocol = '3310';
72
73type
74
75 {:@abstract(Implementation of ClamAV-daemon client protocol)
76 By this class you can scan any your data by ClamAV opensource antivirus.
77
78 This class can connect to ClamD by TCP channel, send your data to ClamD
79 and read result.}
80 TClamSend = class(TSynaClient)
81 private
82 FSock: TTCPBlockSocket;
83 FDSock: TTCPBlockSocket;
84 FSession: boolean;
85 function Login: boolean; virtual;
86 function Logout: Boolean; virtual;
87 function OpenStream: Boolean; virtual;
88 public
89 constructor Create;
90 destructor Destroy; override;
91
92 {:Call any command to ClamD. Used internally by other methods.}
93 function DoCommand(const Value: AnsiString): AnsiString; virtual;
94
95 {:Return ClamAV version and version of loaded databases.}
96 function GetVersion: AnsiString; virtual;
97
98 {:Scan content of TStrings.}
99 function ScanStrings(const Value: TStrings): AnsiString; virtual;
100
101 {:Scan content of TStream.}
102 function ScanStream(const Value: TStream): AnsiString; virtual;
103
104 {:Scan content of TStrings by new 0.95 API.}
105 function ScanStrings2(const Value: TStrings): AnsiString; virtual;
106
107 {:Scan content of TStream by new 0.95 API.}
108 function ScanStream2(const Value: TStream): AnsiString; virtual;
109 published
110 {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.}
111 property Sock: TTCPBlockSocket read FSock;
112
113 {:Socket object used for TCP data transfer operation. Good for seting OnStatus hook, etc.}
114 property DSock: TTCPBlockSocket read FDSock;
115
116 {:Can turn-on session mode of communication with ClamD. Default is @false,
117 because ClamAV developers design their TCP code very badly and session mode
118 is broken now (CVS-20051031). Maybe ClamAV developers fix their bugs
119 and this mode will be possible in future.}
120 property Session: boolean read FSession write FSession;
121 end;
122
123implementation
124
125constructor TClamSend.Create;
126begin
127 inherited Create;
128 FSock := TTCPBlockSocket.Create;
129 FSock.Owner := self;
130 FDSock := TTCPBlockSocket.Create;
131 FDSock.Owner := self;
132 FTimeout := 60000;
133 FTargetPort := cClamProtocol;
134 FSession := false;
135end;
136
137destructor TClamSend.Destroy;
138begin
139 Logout;
140 FDSock.Free;
141 FSock.Free;
142 inherited Destroy;
143end;
144
145function TClamSend.DoCommand(const Value: AnsiString): AnsiString;
146begin
147 Result := '';
148 if not FSession then
149 FSock.CloseSocket
150 else
151 FSock.SendString(Value + LF);
152 if not FSession or (FSock.LastError <> 0) then
153 begin
154 if Login then
155 FSock.SendString(Value + LF)
156 else
157 Exit;
158 end;
159 Result := FSock.RecvTerminated(FTimeout, LF);
160end;
161
162function TClamSend.Login: boolean;
163begin
164 Result := False;
165 Sock.CloseSocket;
166 FSock.Bind(FIPInterface, cAnyPort);
167 if FSock.LastError <> 0 then
168 Exit;
169 FSock.Connect(FTargetHost, FTargetPort);
170 if FSock.LastError <> 0 then
171 Exit;
172 if FSession then
173 FSock.SendString('SESSION' + LF);
174 Result := FSock.LastError = 0;
175end;
176
177function TClamSend.Logout: Boolean;
178begin
179 FSock.SendString('END' + LF);
180 Result := FSock.LastError = 0;
181 FSock.CloseSocket;
182end;
183
184function TClamSend.GetVersion: AnsiString;
185begin
186 Result := DoCommand('nVERSION');
187end;
188
189function TClamSend.OpenStream: Boolean;
190var
191 S: AnsiString;
192begin
193 Result := False;
194 s := DoCommand('nSTREAM');
195 if (s <> '') and (Copy(s, 1, 4) = 'PORT') then
196 begin
197 s := SeparateRight(s, ' ');
198 FDSock.CloseSocket;
199 FDSock.Bind(FIPInterface, cAnyPort);
200 if FDSock.LastError <> 0 then
201 Exit;
202 FDSock.Connect(FTargetHost, s);
203 if FDSock.LastError <> 0 then
204 Exit;
205 Result := True;
206 end;
207end;
208
209function TClamSend.ScanStrings(const Value: TStrings): AnsiString;
210begin
211 Result := '';
212 if OpenStream then
213 begin
214 DSock.SendString(Value.Text);
215 DSock.CloseSocket;
216 Result := FSock.RecvTerminated(FTimeout, LF);
217 end;
218end;
219
220function TClamSend.ScanStream(const Value: TStream): AnsiString;
221begin
222 Result := '';
223 if OpenStream then
224 begin
225 DSock.SendStreamRaw(Value);
226 DSock.CloseSocket;
227 Result := FSock.RecvTerminated(FTimeout, LF);
228 end;
229end;
230
231function TClamSend.ScanStrings2(const Value: TStrings): AnsiString;
232var
233 i: integer;
234 s: AnsiString;
235begin
236 Result := '';
237 if not FSession then
238 FSock.CloseSocket
239 else
240 FSock.sendstring('nINSTREAM' + LF);
241 if not FSession or (FSock.LastError <> 0) then
242 begin
243 if Login then
244 FSock.sendstring('nINSTREAM' + LF)
245 else
246 Exit;
247 end;
248 s := Value.text;
249 i := length(s);
250 FSock.SendString(CodeLongint(i) + s + #0#0#0#0);
251 Result := FSock.RecvTerminated(FTimeout, LF);
252end;
253
254function TClamSend.ScanStream2(const Value: TStream): AnsiString;
255var
256 i: integer;
257begin
258 Result := '';
259 if not FSession then
260 FSock.CloseSocket
261 else
262 FSock.sendstring('nINSTREAM' + LF);
263 if not FSession or (FSock.LastError <> 0) then
264 begin
265 if Login then
266 FSock.sendstring('nINSTREAM' + LF)
267 else
268 Exit;
269 end;
270 i := value.Size;
271 FSock.SendString(CodeLongint(i));
272 FSock.SendStreamRaw(Value);
273 FSock.SendString(#0#0#0#0);
274 Result := FSock.RecvTerminated(FTimeout, LF);
275end;
276
277end.
Note: See TracBrowser for help on using the repository browser.