op-clamav-client 3.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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