source: Network/synapse/clamsend.pas

Last change on this file was 300, checked in by chronos, 13 years ago
  • Added: Synapse library with package file. Cryptlib units are not included in package file list.
File size: 9.0 KB
Line 
1{==============================================================================|
2| Project : Ararat Synapse | 001.001.000 |
3|==============================================================================|
4| Content: ClamAV-daemon client |
5|==============================================================================|
6| Copyright (c)2005-2009, 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-2009. |
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
57unit clamsend;
58
59interface
60
61uses
62 SysUtils, Classes,
63 synsock, blcksock, synautil;
64
65const
66 cClamProtocol = '3310';
67
68type
69
70 {:@abstract(Implementation of ClamAV-daemon client protocol)
71 By this class you can scan any your data by ClamAV opensource antivirus.
72
73 This class can connect to ClamD by TCP channel, send your data to ClamD
74 and read result.}
75 TClamSend = class(TSynaClient)
76 private
77 FSock: TTCPBlockSocket;
78 FDSock: TTCPBlockSocket;
79 FSession: boolean;
80 function Login: boolean; virtual;
81 function Logout: Boolean; virtual;
82 function OpenStream: Boolean; virtual;
83 public
84 constructor Create;
85 destructor Destroy; override;
86
87 {:Call any command to ClamD. Used internally by other methods.}
88 function DoCommand(const Value: AnsiString): AnsiString; virtual;
89
90 {:Return ClamAV version and version of loaded databases.}
91 function GetVersion: AnsiString; virtual;
92
93 {:Scan content of TStrings.}
94 function ScanStrings(const Value: TStrings): AnsiString; virtual;
95
96 {:Scan content of TStream.}
97 function ScanStream(const Value: TStream): AnsiString; virtual;
98
99 {:Scan content of TStrings by new 0.95 API.}
100 function ScanStrings2(const Value: TStrings): AnsiString; virtual;
101
102 {:Scan content of TStream by new 0.95 API.}
103 function ScanStream2(const Value: TStream): AnsiString; virtual;
104 published
105 {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.}
106 property Sock: TTCPBlockSocket read FSock;
107
108 {:Socket object used for TCP data transfer operation. Good for seting OnStatus hook, etc.}
109 property DSock: TTCPBlockSocket read FDSock;
110
111 {:Can turn-on session mode of communication with ClamD. Default is @false,
112 because ClamAV developers design their TCP code very badly and session mode
113 is broken now (CVS-20051031). Maybe ClamAV developers fix their bugs
114 and this mode will be possible in future.}
115 property Session: boolean read FSession write FSession;
116 end;
117
118implementation
119
120constructor TClamSend.Create;
121begin
122 inherited Create;
123 FSock := TTCPBlockSocket.Create;
124 FDSock := TTCPBlockSocket.Create;
125 FTimeout := 60000;
126 FTargetPort := cClamProtocol;
127 FSession := false;
128end;
129
130destructor TClamSend.Destroy;
131begin
132 Logout;
133 FDSock.Free;
134 FSock.Free;
135 inherited Destroy;
136end;
137
138function TClamSend.DoCommand(const Value: AnsiString): AnsiString;
139begin
140 Result := '';
141 if not FSession then
142 FSock.CloseSocket
143 else
144 FSock.SendString(Value + LF);
145 if not FSession or (FSock.LastError <> 0) then
146 begin
147 if Login then
148 FSock.SendString(Value + LF)
149 else
150 Exit;
151 end;
152 Result := FSock.RecvTerminated(FTimeout, LF);
153end;
154
155function TClamSend.Login: boolean;
156begin
157 Result := False;
158 Sock.CloseSocket;
159 FSock.Bind(FIPInterface, cAnyPort);
160 if FSock.LastError <> 0 then
161 Exit;
162 FSock.Connect(FTargetHost, FTargetPort);
163 if FSock.LastError <> 0 then
164 Exit;
165 if FSession then
166 FSock.SendString('SESSION' + LF);
167 Result := FSock.LastError = 0;
168end;
169
170function TClamSend.Logout: Boolean;
171begin
172 FSock.SendString('END' + LF);
173 Result := FSock.LastError = 0;
174 FSock.CloseSocket;
175end;
176
177function TClamSend.GetVersion: AnsiString;
178begin
179 Result := DoCommand('nVERSION');
180end;
181
182function TClamSend.OpenStream: Boolean;
183var
184 S: AnsiString;
185begin
186 Result := False;
187 s := DoCommand('nSTREAM');
188 if (s <> '') and (Copy(s, 1, 4) = 'PORT') then
189 begin
190 s := SeparateRight(s, ' ');
191 FDSock.CloseSocket;
192 FDSock.Bind(FIPInterface, cAnyPort);
193 if FDSock.LastError <> 0 then
194 Exit;
195 FDSock.Connect(FTargetHost, s);
196 if FDSock.LastError <> 0 then
197 Exit;
198 Result := True;
199 end;
200end;
201
202function TClamSend.ScanStrings(const Value: TStrings): AnsiString;
203begin
204 Result := '';
205 if OpenStream then
206 begin
207 DSock.SendString(Value.Text);
208 DSock.CloseSocket;
209 Result := FSock.RecvTerminated(FTimeout, LF);
210 end;
211end;
212
213function TClamSend.ScanStream(const Value: TStream): AnsiString;
214begin
215 Result := '';
216 if OpenStream then
217 begin
218 DSock.SendStreamRaw(Value);
219 DSock.CloseSocket;
220 Result := FSock.RecvTerminated(FTimeout, LF);
221 end;
222end;
223
224function TClamSend.ScanStrings2(const Value: TStrings): AnsiString;
225var
226 i: integer;
227 s: AnsiString;
228begin
229 Result := '';
230 if not FSession then
231 FSock.CloseSocket
232 else
233 FSock.sendstring('nINSTREAM' + LF);
234 if not FSession or (FSock.LastError <> 0) then
235 begin
236 if Login then
237 FSock.sendstring('nINSTREAM' + LF)
238 else
239 Exit;
240 end;
241 s := Value.text;
242 i := length(s);
243 FSock.SendString(CodeLongint(i) + s + #0#0#0#0);
244 Result := FSock.RecvTerminated(FTimeout, LF);
245end;
246
247function TClamSend.ScanStream2(const Value: TStream): AnsiString;
248var
249 i: integer;
250 s: AnsiString;
251begin
252 Result := '';
253 if not FSession then
254 FSock.CloseSocket
255 else
256 FSock.sendstring('nINSTREAM' + LF);
257 if not FSession or (FSock.LastError <> 0) then
258 begin
259 if Login then
260 FSock.sendstring('nINSTREAM' + LF)
261 else
262 Exit;
263 end;
264 i := value.Size;
265 FSock.SendString(CodeLongint(i));
266 FSock.SendStreamRaw(Value);
267 FSock.SendString(#0#0#0#0);
268 Result := FSock.RecvTerminated(FTimeout, LF);
269end;
270
271end.
Note: See TracBrowser for help on using the repository browser.