op-clamav-client 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,209 @@
1
+ # ClamAV::Client
2
+
3
+ ClamAV::Client is a client library that can talk to the clam daemon.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'op-clamav-client', require: 'clamav/client'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install op-client-client
18
+
19
+ Alternatively, you can spawn a `pry` console right away by just running:
20
+
21
+ $ rake console
22
+
23
+ ### Installing ClamAV's daemon
24
+
25
+ #### On OSX
26
+
27
+ If you are using brew, just run
28
+
29
+ ```shell
30
+ brew install clamav
31
+ ```
32
+ #### On Linux (Ubuntu)
33
+ ```shell
34
+ sudo apt-get install clamav-daemon clamav-freshclam clamav-unofficial-sigs
35
+ sudo freshclam
36
+ sudo service clamav-daemon start
37
+ ```
38
+ #### On Linux (RedHat, CentOS)
39
+ ```shell
40
+ sudo yum install clamd clamav clamav-db
41
+ sudo freshclam
42
+ sudo service clamd start
43
+ ```
44
+ Under RedHat/CentOS the UNIX Socket, located at `/var/run/clamav/clamd.sock`
45
+
46
+ ## Requirements
47
+
48
+ * Ruby >= 2.4
49
+ * clamd
50
+
51
+ ## Usage
52
+
53
+ The `ClamAV::Client` class is responsible for opening a connection to a remote
54
+ ClamAV clam daemon.
55
+
56
+ See the implemented commands below.
57
+
58
+ ### PING => Boolean
59
+
60
+ Pings the daemon to check whether it is alive.
61
+
62
+ ```ruby
63
+ client = ClamAV::Client.new
64
+ client.execute(ClamAV::Commands::PingCommand.new)
65
+ # => true
66
+ ```
67
+
68
+ ### SCAN <file_or_directory> => Array[Response]
69
+
70
+ Scans a file or a directory for the existence of a virus.
71
+
72
+ The absolute path must be given to that command.
73
+
74
+ ```ruby
75
+ client = ClamAV::Client.new
76
+
77
+ client.execute(ClamAV::Commands::ScanCommand.new('/tmp/path/foo.c'))
78
+ # => [#<ClamAV::SuccessResponse:0x007fbf314b9478 @file="/tmp/foo.c">]
79
+
80
+ client.execute(ClamAV::Commands::ScanCommand.new('/tmp/path'))
81
+ # => [#<ClamAV::SuccessResponse:0x007fc30c273298 @file="/tmp/path/foo.c">,
82
+ # #<ClamAV::SuccessResponse:0x007fc30c272910 @file="/tmp/path/foo.cpp">]
83
+ ```
84
+
85
+ ### INSTREAM => Response
86
+
87
+ Scans an IO-like object for the existence of a virus.
88
+
89
+ ```ruby
90
+ client = ClamAV::Client.new
91
+
92
+ io = StringIO.new('some data')
93
+ client.execute(ClamAV::Commands::InstreamCommand.new(io))
94
+ # => [#<ClamAV::SuccessResponse:0x007fe471cabe50 @file="stream">]
95
+ ```
96
+
97
+ ### Custom commands
98
+
99
+ Custom commands can be given to the client. The contract between the client
100
+ and the command is through the `Command#call` method. The `call` method will
101
+ receive a `Connection` object.
102
+
103
+ Here's a simple example implementing the `VERSION` command:
104
+
105
+ ```ruby
106
+ # Build the client
107
+ client = ClamAV::Client.new
108
+
109
+ # Create the command lambda
110
+ version_command = lambda { |conn| conn.send_request("VERSION") }
111
+ # => #<Proc:0x007fc0d0c14b28>
112
+
113
+ # Execute the command
114
+ client.execute(version_command)
115
+ # => "1: ClamAV 0.98.1/18489/Tue Feb 18 16:00:05 2014"
116
+ ```
117
+
118
+ ## Defaults
119
+
120
+ The default values in use are:
121
+
122
+ * clamd socket: UNIX Socket, located at `/var/run/clamav/clamd.ctl`;
123
+ * New-line terminated commands.
124
+
125
+ These defaults can be changed:
126
+
127
+ * by creating the object graph manually;
128
+ * by setting environment variables.
129
+
130
+ ### The object graph
131
+
132
+ #### Client
133
+
134
+ The main object is the `Client` object. It is responsible for executing the commands.
135
+ It can receive a custom connection object.
136
+
137
+ #### Connection
138
+
139
+ The `Connection` object is the bridge between the raw socket object and the
140
+ protocol used between the client and the daemon.
141
+
142
+ `clamd` supports two kinds of delimiters:
143
+
144
+ * NULL terminated commands
145
+ * New-line terminated commands
146
+
147
+ The management of those delimiters is done with the wrapper argument.
148
+
149
+ #### Wrapper
150
+
151
+ The wrapper is responsible for taking the incoming request with the
152
+ `wrap_request` method, and parsing the response with the `read_response`
153
+ method.
154
+
155
+ ### Environment variables
156
+
157
+ The variables can be set programmatically in your Ruby programs like
158
+
159
+ ```ruby
160
+ # from a ruby script
161
+ ENV['CLAMD_UNIX_SOCKET'] = '/some/path'
162
+
163
+ # Now the defaults are changed for any new ClamAV::Client instantiation
164
+ ```
165
+
166
+ or by setting the variables before starting the Ruby process:
167
+
168
+ ```
169
+ # from the command-line
170
+ export CLAMD_UNIX_SOCKET = '/some/path'
171
+ ruby my_program.rb
172
+ # or
173
+ CLAMD_UNIX_SOCKET = '/some/path' ruby my_program.rb
174
+ ```
175
+
176
+ Please note that setting the `CLAMD_TCP_*` variables will have the precedence
177
+ over the `CLAMD_UNIX_SOCKET`.
178
+
179
+ #### CLAMD_UNIX_SOCKET
180
+
181
+ Sets the socket path of the ClamAV daemon.
182
+
183
+ Under RedHat/CentOS this can either be set via an environment variable (above) or in the ClamAV::Connection call
184
+ ```
185
+ connection = ClamAV::Connection.new(socket: ::UNIXSocket.new('/var/run/clamav/clamd.sock'), wrapper: ::ClamAV::Wrappers::NewLineWrapper.new)
186
+ client = ClamAV::Client.new(connection)
187
+ ```
188
+
189
+ #### CLAMD_TCP_HOST and CLAMD_TCP_PORT
190
+
191
+ Sets the host and port of the ClamAV daemon.
192
+
193
+ ## Licensing
194
+
195
+ GPLv3. COMMERCIAL license available upon request.
196
+
197
+ ## Contributing
198
+
199
+ 1. Fork it ( https://github.com/opf/clamav-client/fork )
200
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
201
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
202
+ 4. Push to the branch (`git push origin my-new-feature`)
203
+ 5. Create new Pull Request
204
+
205
+ ### Testing
206
+
207
+ The test suite can be run locally before pushing changes :
208
+
209
+ $ docker run --rm -it $(docker build -f test/Dockerfile --build-arg RUBY_VERSION=3.2-slim -q .) rake
data/Rakefile ADDED
@@ -0,0 +1,104 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'rubygems'
18
+ require 'rubygems/specification'
19
+
20
+ require 'bundler'
21
+ Bundler::GemHelper.install_tasks
22
+
23
+ $:<< 'lib'
24
+ require 'clamav/client'
25
+
26
+ $stdout.puts """
27
+ ClamAV::Client Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
28
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `rake license'.
29
+ This is free software, and you are welcome to redistribute it
30
+ under certain conditions; type `rake license' for details.
31
+
32
+ """
33
+
34
+ require 'rake/testtask'
35
+ Rake::TestTask.new do |t|
36
+ t.libs << "test"
37
+ t.pattern = "test/**/*_test.rb"
38
+ #t.verbose = true
39
+ #t.warning = true
40
+ end
41
+
42
+ Rake::TestTask.new(:unit_tests) do |t|
43
+ t.libs << "test"
44
+ t.pattern = "test/unit/**/*_test.rb"
45
+ #t.verbose = true
46
+ #t.warning = true
47
+ end
48
+
49
+ Rake::TestTask.new(:integration_tests) do |t|
50
+ t.libs << "test"
51
+ t.pattern = "test/integration/**/*_test.rb"
52
+ #t.verbose = true
53
+ #t.warning = true
54
+ end
55
+
56
+
57
+ def gemspec
58
+ @gemspec ||= begin
59
+ file = File.expand_path('../clamav-client.gemspec', __FILE__)
60
+ eval(File.read(file), binding, file)
61
+ end
62
+ end
63
+
64
+ desc "Clean the current directory"
65
+ task :clean do
66
+ rm_rf 'tmp'
67
+ rm_rf 'pkg'
68
+ end
69
+
70
+ desc "Run the full spec suite"
71
+ task :full => ["clean", "test"]
72
+
73
+ desc "install the gem locally"
74
+ task :install => :package do
75
+ sh %{gem install pkg/#{gemspec.name}-#{gemspec.version}}
76
+ end
77
+
78
+ desc "validate the gemspec"
79
+ task :gemspec do
80
+ gemspec.validate
81
+ end
82
+
83
+ desc "Build the gem"
84
+ task :gem => [:gemspec, :build] do
85
+ mkdir_p "pkg"
86
+ sh "gem build clamav-client.gemspec"
87
+ mv "#{gemspec.full_name}.gem", "pkg"
88
+ end
89
+
90
+ desc "Install ClamAV::Client"
91
+ task :install => :gem do
92
+ sh "gem install pkg/#{gemspec.full_name}.gem"
93
+ end
94
+
95
+ task :default => :full
96
+
97
+ task :license do
98
+ `open http://www.gnu.org/licenses/gpl.txt`
99
+ end
100
+
101
+ task :console do
102
+ require 'pry'
103
+ Pry.start
104
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ $:<< 'lib'
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = "op-clamav-client"
6
+ spec.version = "3.4.2"
7
+ spec.authors = ["Franck Verrot"]
8
+ spec.email = ["franck@verrot.fr"]
9
+ spec.summary = %q{ClamAV::Client connects to a Clam Anti-Virus clam daemon and send commands.}
10
+ spec.description = spec.summary
11
+ spec.homepage = "https://github.com/franckverrot/clamav-client"
12
+ spec.license = "GPL-v3"
13
+ spec.required_ruby_version = '>= 2.5'
14
+
15
+ spec.files = Dir['{lib,test}/**/*', 'LICENSE.txt', 'ChangeLog.md', 'Rakefile', 'README.md', 'Gemfile', 'clamav-client.gemspec'].reject { |f| f['test/fixtures'] }
16
+
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "pry"
24
+ spec.add_development_dependency "minitest"
25
+ end
@@ -0,0 +1,182 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'socket'
18
+ require 'timeout'
19
+
20
+ module ClamAV
21
+ class Client
22
+ class Error < StandardError; end
23
+ class ConnectionError < Error; end
24
+ class ConnectTimeoutError < ConnectionError; end
25
+ class ReadTimeoutError < ConnectionError; end
26
+ class WriteTimeoutError < ConnectionError; end
27
+
28
+ attr_accessor :options
29
+
30
+ def initialize(*args)
31
+ @options = env_options
32
+
33
+ args.each do |arg|
34
+ case arg
35
+ when Connection
36
+ @connection = arg
37
+ when Hash
38
+ @options = env_options.inject({}) do |acc, (option, default)|
39
+ acc[option] = arg[option] || default
40
+ acc
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ [
47
+ :unix_socket,
48
+ :tcp_host,
49
+ :tcp_port,
50
+ :connect_timeout,
51
+ :write_timeout,
52
+ :read_timeout,
53
+ ].each do |m|
54
+ define_method(m) do
55
+ options[m]
56
+ end
57
+
58
+ define_method("#{m}=") do |value|
59
+ options[m] = value
60
+ end
61
+ end
62
+
63
+ def env_options
64
+ @env_options ||= {
65
+ unix_socket: ENV.fetch('CLAMD_UNIX_SOCKET', '/var/run/clamav/clamd.ctl'),
66
+ tcp_host: ENV.fetch('CLAMD_TCP_HOST', nil),
67
+ tcp_port: ENV.fetch('CLAMD_TCP_PORT', nil),
68
+ connect_timeout: ENV.fetch("CLAMD_TCP_CONNECT_TIMEOUT", nil),
69
+ write_timeout: ENV.fetch("CLAMD_TCP_WRITE_TIMEOUT", nil),
70
+ read_timeout: ENV.fetch("CLAMD_TCP_READ_TIMEOUT", nil),
71
+ }
72
+ end
73
+
74
+ def execute(command)
75
+ begin
76
+ command.call(connection)
77
+ rescue Errno::ETIMEDOUT => e
78
+ disconnect!
79
+
80
+ raise ConnectTimeoutError.new(e.to_s)
81
+ rescue SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ENETDOWN => e
82
+ disconnect!
83
+
84
+ raise ConnectionError.new(e.to_s)
85
+ rescue => e
86
+ disconnect!
87
+
88
+ raise e
89
+ end
90
+ end
91
+
92
+ def connection
93
+ @connection ||= default_connection.tap do |conn|
94
+ connect!(conn)
95
+ end
96
+ end
97
+
98
+ def default_connection
99
+ ClamAV::Connection.new(
100
+ client: self,
101
+ socket: build_socket,
102
+ wrapper: ::ClamAV::Wrappers::NewLineWrapper.new
103
+ )
104
+ end
105
+
106
+ def connect!(conn=nil)
107
+ (conn || @connection).establish_connection
108
+ rescue Errno::ETIMEDOUT => e
109
+ @connection = nil
110
+
111
+ raise ConnectTimeoutError.new(e.to_s)
112
+ rescue SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED => e
113
+ @connection = nil
114
+
115
+ raise ConnectionError.new(e.to_s)
116
+ end
117
+
118
+ def disconnect!
119
+ return true if @connection.nil?
120
+
121
+ @connection.disconnect!.tap do
122
+ @connection = nil
123
+ end
124
+ end
125
+
126
+ def tcp?
127
+ !!tcp_host && !!tcp_port
128
+ end
129
+
130
+ def file?
131
+ !tcp
132
+ end
133
+
134
+ def build_socket
135
+ return Socket.tcp(tcp_host, tcp_port, connect_timeout: connect_timeout) if tcp?
136
+
137
+ ::UNIXSocket.new(unix_socket)
138
+ rescue Errno::ETIMEDOUT => e
139
+ raise ConnectTimeoutError.new(e.to_s)
140
+ rescue SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED => e
141
+ raise ConnectionError.new(e.to_s)
142
+ end
143
+
144
+ def ping
145
+ execute Commands::PingCommand.new
146
+ end
147
+
148
+ def safe?(target)
149
+ return instream(target).virus_name.nil? if target.is_a?(StringIO)
150
+ scan(target).all? { |file| file.virus_name.nil? }
151
+ end
152
+
153
+ private
154
+
155
+ def instream(io)
156
+ execute Commands::InstreamCommand.new(io)
157
+ end
158
+
159
+ def scan(file_path)
160
+ execute Commands::ScanCommand.new(file_path)
161
+ end
162
+
163
+ def quit
164
+ execute Commands::QuitCommand.new
165
+ end
166
+ end
167
+ end
168
+
169
+ require_relative "connection"
170
+ require_relative "commands/command"
171
+ require_relative "commands/ping_command"
172
+ require_relative "commands/quit_command"
173
+ require_relative "commands/scan_command"
174
+ require_relative "commands/instream_command"
175
+ require_relative "response"
176
+ require_relative "responses/error_response"
177
+ require_relative "responses/success_response"
178
+ require_relative "responses/virus_response"
179
+ require_relative "util"
180
+ require_relative "wrapper"
181
+ require_relative "wrappers/new_line_wrapper"
182
+ require_relative "wrappers/null_termination_wrapper"
@@ -0,0 +1,38 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module ClamAV
18
+ module Commands
19
+ class Command
20
+
21
+ def call; raise NotImplementedError.new; end
22
+
23
+ protected
24
+
25
+ # OK response looks like "1: stream: OK" or "1: /tmp/NOT_A_VIRUS.TXT: OK"
26
+ # FOUND response looks like "1: stream: Eicar-Test-Signature FOUND" or "1: /tmp/EICAR.COM: Eicar-Test-Signature FOUND"
27
+ def get_status_from_response(str)
28
+ /^(?<id>\d+): (?<filepath>.*): (?<virus_name>.*)\s?(?<status>(OK|FOUND))$/ =~ str
29
+ case status
30
+ when 'OK' then ClamAV::SuccessResponse.new(filepath)
31
+ when 'FOUND' then ClamAV::VirusResponse.new(filepath, virus_name.strip)
32
+ else ClamAV::ErrorResponse.new(str)
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module ClamAV
18
+ module Commands
19
+ class InstreamCommand < Command
20
+
21
+ def initialize(io, max_chunk_size = 1024)
22
+ @io = begin io rescue raise ArgumentError, 'io is required', caller; end
23
+ @max_chunk_size = max_chunk_size
24
+ end
25
+
26
+ def call(conn)
27
+ conn.write_request("INSTREAM")
28
+
29
+ while(packet = @io.read(@max_chunk_size))
30
+ packet_size = [packet.size].pack("N")
31
+ conn.raw_write("#{packet_size}#{packet}")
32
+ end
33
+ conn.raw_write("\x00\x00\x00\x00")
34
+ get_status_from_response(conn.read_response)
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,25 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module ClamAV
18
+ module Commands
19
+ class PingCommand < Command
20
+ def call(conn)
21
+ !!(/\d+: PONG/.match(conn.send_request("PING")))
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module ClamAV
18
+ module Commands
19
+ class QuitCommand < Command
20
+ def call(conn)
21
+ conn.send_request("QUIT").nil?
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,35 @@
1
+ # clamav-client - ClamAV client
2
+ # Copyright (C) 2014 Franck Verrot <franck@verrot.fr>
3
+
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module ClamAV
18
+ module Commands
19
+ class ScanCommand < Command
20
+
21
+ def initialize(path, path_finder = Util)
22
+ @path, @path_finder = path, path_finder
23
+ end
24
+
25
+ def call(conn)
26
+ @path_finder.path_to_files(@path).map { |file| scan_file(conn, file) }
27
+ end
28
+
29
+ def scan_file(conn, file)
30
+ get_status_from_response(conn.send_request("SCAN #{file}"))
31
+ end
32
+
33
+ end
34
+ end
35
+ end