albanpeignier-ruby-managesieve 0.3.1

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.
Files changed (3) hide show
  1. data/bin/sievectl +358 -0
  2. data/lib/managesieve.rb +351 -0
  3. metadata +53 -0
data/bin/sievectl ADDED
@@ -0,0 +1,358 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ #--
4
+ # Copyright (c) 2004-2006 Andre Nathan <andre@digirati.com.br>
5
+ #
6
+ # Permission to use, copy, modify, and distribute this software for any
7
+ # purpose with or without fee is hereby granted, provided that the above
8
+ # copyright notice and this permission notice appear in all copies.
9
+ #
10
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ #++
18
+ #
19
+ # = Overview
20
+ #
21
+ # Sievectl is a utility that allows for management of
22
+ # Sieve[http://www.cyrusoft.com/sieve/] scripts from the command line. It
23
+ # supports multiple accounts, configured in the .sievectlrc file located in
24
+ # the user's home directory.
25
+ #
26
+ # == Configuration file example
27
+ #
28
+ # accountA:
29
+ # host: sieve.accounta.tld
30
+ # port: 2000
31
+ # user: johndoe
32
+ # euser: johndoe
33
+ # password: secret
34
+ # auth: PLAIN
35
+ #
36
+ # accountB:
37
+ # host: mail.accountb.tld
38
+ # user: john
39
+ # password: secret
40
+ # auth: PLAIN
41
+ #
42
+ # The +port+ and +euser+ parameters can be ommited, and will respectively
43
+ # default to 2000 and the value of the +user+ parameter. If the +auth+
44
+ # parameter is ommited, it will default to +ANONYMOUS+.
45
+ #
46
+ # == Usage and examples
47
+ #
48
+ # $ sievectl help
49
+ # Usage: sievectl <account> <action> [script name]
50
+ # Action is one of:
51
+ # capabilities, list, show, activate, deactivate, add, addactive, delete
52
+ #
53
+ # Short forms for some actions are also accepted:
54
+ # caps (capabilities), act (activate), deact (deactivate),
55
+ # addact (addactive), del (delete)
56
+ #
57
+ # Examples:
58
+ # List server capabilities:
59
+ # sievectl myaccount caps
60
+ #
61
+ # List available scripts:
62
+ # sievectl myaccount list
63
+ #
64
+ # Show contents of a script:
65
+ # sievectl myaccount show scriptname
66
+ #
67
+ # Add a script:
68
+ # sievectl myaccount add scriptname script.txt
69
+ # or
70
+ # sievectl myaccount add scriptname < script.txt
71
+ # or
72
+ # cat script.txt | sievectl myaccount add scriptname
73
+ #
74
+ # Delete a script:
75
+ # sievectl myaccount del scriptname
76
+ #
77
+ #--
78
+ # $Id: sievectl,v 1.27 2006/08/30 18:06:21 andre Exp $
79
+ #++
80
+ #
81
+
82
+ begin
83
+ require 'rubygems'
84
+ rescue LoadError
85
+ end
86
+ require 'managesieve'
87
+
88
+ $has_termios = true
89
+ begin
90
+ require_gem 'termios'
91
+ rescue LoadError
92
+ begin
93
+ require 'termios'
94
+ rescue LoadError
95
+ $has_termios = false
96
+ end
97
+ end
98
+
99
+ require 'yaml'
100
+
101
+ class ManageSieve # :nodoc:
102
+ def print_capabilities
103
+ puts 'Capabilities:'
104
+ @capabilities.sort.each { |cap| puts " - #{cap}" }
105
+
106
+ puts 'Login Mechanisms:'
107
+ @login_mechs.sort.each { |mech| puts " - #{mech}" }
108
+ end
109
+
110
+ def print_scripts
111
+ puts 'Available scripts:'
112
+ scripts.sort.each do |name, active|
113
+ print " - #{name}"
114
+ print active ? " (active)\n" : "\n"
115
+ end
116
+ end
117
+
118
+ def upload_script(name, script, active=false)
119
+ put_script(name, script)
120
+ set_active(name)
121
+ end
122
+ end
123
+
124
+ class TemplateError < Exception # :nodoc:
125
+ end
126
+
127
+ class ConfigFile < File # :nodoc:
128
+ def ConfigFile.open(name)
129
+ begin
130
+ conf = nil
131
+ super(name) do |file|
132
+ conf = YAML::load(file)
133
+ end
134
+ conf.each_key do |acct|
135
+ conf[acct].each_key { |k| conf[acct][k] = conf[acct][k].to_s }
136
+ end
137
+ conf
138
+ rescue Errno::ENOENT
139
+ ConfigFile::create_template(name)
140
+ exit 0
141
+ end
142
+ end
143
+
144
+ private
145
+ def ConfigFile.create_template(name)
146
+ STDERR.puts <<-__EOF__
147
+ * Could not find configuration file #{name}.
148
+ * A template file will be created. Please edit the values to fit your
149
+ * local configuration and run `#{File::basename $0}' again.
150
+ __EOF__
151
+
152
+ begin
153
+ file = File.new(name, 'w', 0600)
154
+ file.puts <<-__EOF__
155
+ accountname:
156
+ host: servername
157
+ port: port
158
+ user: username
159
+ euser: effectiveusername
160
+ password: password
161
+ auth: authmethod
162
+ __EOF__
163
+ rescue => e
164
+ raise TemplateError, e
165
+ end
166
+ end
167
+ end
168
+
169
+ #
170
+ # The SieveCtl class is a simple set of wrapper methods around the ones
171
+ # available on the #ManageSieve class.
172
+ #
173
+ class SieveCtl
174
+ def initialize(conf)
175
+ @manage_sieve = ManageSieve.new(conf)
176
+ end
177
+
178
+ # Prints the server capabilities.
179
+ def capabilities
180
+ @manage_sieve.print_capabilities
181
+ end
182
+
183
+ # Lists the available scripts, specifying which one is active.
184
+ def list
185
+ @manage_sieve.print_scripts
186
+ end
187
+
188
+ # Shows the contents of +script+.
189
+ def show(script)
190
+ raise ArgumentError, "`show' requires a script name" unless script
191
+ puts @manage_sieve.get_script(script)
192
+ end
193
+
194
+ # Activates +script+.
195
+ def activate(script)
196
+ raise ArgumentError, "`activate' requires a script name" unless script
197
+ @manage_sieve.set_active(script)
198
+ end
199
+
200
+ # Deactivates +script+. There is no +DEACTIVATE+ command in the MANAGESIEVE
201
+ # draft, so we fetch the script, remove it and upload it again.
202
+ def deactivate(script)
203
+ raise ArgumentError, "`deactivate' requires a script name" unless script
204
+ data = @manage_sieve.get_script(script)
205
+ @manage_sieve.delete_script(script)
206
+ @manage_sieve.put_script(script, data)
207
+ end
208
+
209
+ # Adds a script named +script+, from file +file+. If +file+ is +nil+, read
210
+ # the script from +STDIN+. Activates the script is +active+ is true.
211
+ def add(script, file=nil, active=false)
212
+ action = "add#{active ? 'active' : ''}"
213
+ raise ArgumentError, "`#{action}' requires a script name" unless script
214
+ data = file ? File.open(file).readlines.to_s : STDIN.readlines.to_s
215
+ unless @manage_sieve.have_space?(script, data.length)
216
+ raise SieveCommandError, "not enough space for script `#{script}' " +
217
+ "(#{data.length} bytes)"
218
+ end
219
+ @manage_sieve.put_script(script, data)
220
+ activate script if active
221
+ end
222
+
223
+ # Deletes +script+
224
+ def delete(script)
225
+ raise ArgumentError, "`activate' requires a script name" unless script
226
+ @manage_sieve.delete_script(script)
227
+ end
228
+ end
229
+
230
+ def usage(quit=true, out=STDERR) # :nodoc: #
231
+ prog = File.basename $0
232
+ out.puts <<-__EOF__
233
+ Usage: #{prog} <account> <action> [script name]
234
+ Action is one of:
235
+ capabilities, list, show, activate, deactivate, add, addactive, delete
236
+
237
+ You can also try `#{prog} help' for usage examples.
238
+ __EOF__
239
+ exit 1 if quit
240
+ end
241
+
242
+ def help # :nodoc:
243
+ prog = File::basename $0
244
+ usage(false, STDOUT)
245
+ puts <<-__EOF__
246
+
247
+ Short forms for some actions are also accepted:
248
+ caps (capabilities), act (activate), deact (deactivate), addact (addactive),
249
+ del (delete)
250
+
251
+ Examples:
252
+ List server capabilities:
253
+ #{prog} myaccount caps
254
+
255
+ List available scripts:
256
+ #{prog} myaccount list
257
+
258
+ Show contents of a script:
259
+ #{prog} myaccount show scriptname
260
+
261
+ Add a script:
262
+ #{prog} myaccount add scriptname script.txt
263
+ or
264
+ #{prog} myaccount add scriptname < script.txt
265
+ or
266
+ cat script.txt | #{prog} myaccount add scriptname
267
+
268
+ Delete a script:
269
+ #{prog} myaccount del scriptname
270
+ __EOF__
271
+ exit 0
272
+ end
273
+
274
+
275
+ #
276
+ # Main
277
+ #
278
+
279
+ help if ARGV[0] =~ /^h(elp)?$/i
280
+
281
+ account, action, name, file = ARGV
282
+ usage if action.nil?
283
+
284
+ begin
285
+ conf = ConfigFile::open(ENV['HOME'] + '/.sievectlrc')
286
+ rescue TemplateError => e
287
+ STDERR.puts "Cannot create template configuration file: #{e}"
288
+ exit 1
289
+ rescue => e
290
+ STDERR.puts "Cannot load configuration file: `#{e}'"
291
+ exit 1
292
+ end
293
+
294
+ unless conf.has_key? account
295
+ STDERR.puts <<-__EOF__
296
+ * Configuration for account `#{account}' not found.
297
+ * Maybe your configuration file is in the old format?
298
+ __EOF__
299
+ exit 1
300
+ end
301
+
302
+ info = conf[account]
303
+
304
+ if $has_termios and info['password'].nil?
305
+ oldt = Termios.tcgetattr(STDIN)
306
+ newt = oldt.dup
307
+ newt.lflag &= ~Termios::ECHO
308
+ Termios.tcsetattr(STDIN, Termios::TCSANOW, newt)
309
+ print 'Password: '
310
+ info['password'] = STDIN.gets
311
+ Termios.tcsetattr(STDIN, Termios::TCSANOW, oldt)
312
+ end
313
+
314
+ if info['password'].nil?
315
+ STDERR.puts "* Password not given."
316
+ exit 1
317
+ end
318
+
319
+ info['password'].chomp!
320
+
321
+ begin
322
+ sievectl = SieveCtl.new(
323
+ :host => info['host'],
324
+ :port => info['port'] || 2000,
325
+ :user => info['user'],
326
+ :euser => info['euser'] || info['user'],
327
+ :password => info['password'],
328
+ :auth => info['auth']
329
+ )
330
+ rescue SieveNetworkError => e
331
+ STDERR.puts "* #{e}"
332
+ exit 1
333
+ end
334
+
335
+ begin
336
+ case action
337
+ when /^act(ivate)?$/
338
+ sievectl.activate(name)
339
+ when /^add$/
340
+ sievectl.add(name, file)
341
+ when /^addact(ive)?/
342
+ sievectl.add(name, file, true)
343
+ when /^cap(abilitie)?s$/
344
+ sievectl.capabilities
345
+ when /^deact(ivate)?$/
346
+ sievectl.deactivate(name)
347
+ when /^del(ete)?$/
348
+ sievectl.delete(name)
349
+ when /^list$/
350
+ sievectl.list
351
+ when /^show$/
352
+ sievectl.show(name)
353
+ else
354
+ usage
355
+ end
356
+ rescue ArgumentError, SieveCommandError => e
357
+ STDERR.puts "* sievectl: #{e}"
358
+ end
@@ -0,0 +1,351 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ #--
4
+ # Copyright (c) 2004-2006 Andre Nathan <andre@digirati.com.br>
5
+ #
6
+ # Permission to use, copy, modify, and distribute this software for any
7
+ # purpose with or without fee is hereby granted, provided that the above
8
+ # copyright notice and this permission notice appear in all copies.
9
+ #
10
+ # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
+ # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
+ # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
+ # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
+ # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
+ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
+ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
+ #++
18
+ #
19
+ # == Overview
20
+ #
21
+ # This library is a pure-ruby implementation of the MANAGESIEVE protocol, as
22
+ # specified in its
23
+ # Draft[http://managesieve.rubyforge.org/draft-martin-managesieve-04.txt].
24
+ #
25
+ # See the ManageSieve class for documentation and examples.
26
+ #
27
+ #--
28
+ # $Id: managesieve.rb,v 1.13 2006/08/30 14:23:58 andre Exp $
29
+ #++
30
+ #
31
+
32
+ require 'base64'
33
+ require 'socket'
34
+
35
+ begin
36
+ require 'openssl'
37
+ rescue LoadError
38
+ end
39
+
40
+ #
41
+ # Define our own Base64.encode64 for compatibility with ruby <= 1.8.1, which
42
+ # defines encode64() at the top level.
43
+ #
44
+ module Base64 # :nodoc:
45
+ def encode64(s)
46
+ [s].pack('m')
47
+ end
48
+ module_function :encode64
49
+ end
50
+
51
+ class SieveAuthError < Exception; end
52
+ class SieveCommandError < Exception; end
53
+ class SieveNetworkError < Exception; end
54
+ class SieveResponseError < Exception; end
55
+
56
+ #
57
+ # ManageSieve implements MANAGESIEVE, a protocol for remote management of
58
+ # Sieve[http://www.cyrusoft.com/sieve/] scripts.
59
+ #
60
+ # The following MANAGESIEVE commands are implemented:
61
+ # * CAPABILITY
62
+ # * DELETESCRIPT
63
+ # * GETSCRIPT
64
+ # * HAVESPACE
65
+ # * LISTSCRIPTS
66
+ # * LOGOUT
67
+ # * PUTSCRIPT
68
+ # * SETACTIVE
69
+ #
70
+ # The AUTHENTICATE command is partially implemented. Currently the +LOGIN+
71
+ # and +PLAIN+ authentication mechanisms are implemented.
72
+ #
73
+ # = Example
74
+ #
75
+ # # Create a new ManageSieve instance
76
+ # m = ManageSieve.new(
77
+ # :host => 'sievehost.mydomain.com',
78
+ # :port => 2000,
79
+ # :user => 'johndoe',
80
+ # :password => 'secret',
81
+ # :auth => 'PLAIN'
82
+ # )
83
+ #
84
+ # # List installed scripts
85
+ # m.scripts.sort do |name, active|
86
+ # print name
87
+ # print active ? " (active)\n" : "\n"
88
+ # end
89
+ #
90
+ # script = <<__EOF__
91
+ # require "fileinto";
92
+ # if header :contains ["to", "cc"] "ruby-talk@ruby-lang.org" {
93
+ # fileinto "Ruby-talk";
94
+ # }
95
+ # __EOF__
96
+ #
97
+ # # Test if there's enough space for script 'foobar'
98
+ # puts m.have_space?('foobar', script.length)
99
+ #
100
+ # # Upload it
101
+ # m.put_script('foobar', script)
102
+ #
103
+ # # Show its contents
104
+ # puts m.get_script('foobar')
105
+ #
106
+ # # Close the connection
107
+ # m.logout
108
+ #
109
+ class ManageSieve
110
+ SIEVE_PORT = 2000
111
+
112
+ attr_reader :host, :port, :user, :euser, :capabilities, :login_mechs, :use_tls
113
+
114
+ # Create a new ManageSieve instance. The +info+ parameter is a hash with the
115
+ # following keys:
116
+ #
117
+ # [<i>:host</i>] the sieve server
118
+ # [<i>:port</i>] the sieve port (defaults to 2000)
119
+ # [<i>:user</i>] the name of the user
120
+ # [<i>:euser</i>] the name of the effective user (defaults to +:user+)
121
+ # [<i>:password</i>] the password of the user
122
+ # [<i>:auth_mech</i>] the authentication mechanism (defaults to +"ANONYMOUS"+)
123
+ # [<i>:use_tls</i>] if true, try to use tls when server supports it
124
+ #
125
+ def initialize(info)
126
+ @host = info[:host]
127
+ @port = info[:port] || 2000
128
+ @user = info[:user]
129
+ @euser = info[:euser] || @user
130
+ @password = info[:password]
131
+ @auth_mech = info[:auth] || 'ANONYMOUS'
132
+ @use_tls = info[:use_tls] || true
133
+
134
+ @capabilities = []
135
+ @login_mechs = []
136
+ @implementation = ''
137
+ @supports_tls = false
138
+ @socket = TCPSocket.new(@host, @port)
139
+
140
+ data = get_response
141
+ server_features(data)
142
+
143
+ starttls if use_tls and supports_tls?
144
+
145
+ authenticate
146
+ @password = nil
147
+ end
148
+
149
+
150
+ # If a block is given, calls it for each script stored on the server,
151
+ # passing its name and status as parameters. Else, and array
152
+ # of [ +name+, +status+ ] arrays is returned. The status is either
153
+ # 'ACTIVE' or nil.
154
+ def scripts
155
+ begin
156
+ scripts = send_command('LISTSCRIPTS')
157
+ rescue SieveCommandError => e
158
+ raise e, "Cannot list scripts: #{e}"
159
+ end
160
+ return scripts unless block_given?
161
+ scripts.each { |name, status| yield(name, status) }
162
+ end
163
+ alias :each_script :scripts
164
+
165
+ # Returns the contents of +script+ as a string.
166
+ def get_script(script)
167
+ begin
168
+ data = send_command('GETSCRIPT', sieve_name(script))
169
+ rescue SieveCommandError => e
170
+ raise e, "Cannot get script: #{e}"
171
+ end
172
+ return data.to_s.chomp
173
+ end
174
+
175
+ # Uploads +script+ to the server, using +data+ as its contents.
176
+ def put_script(script, data)
177
+ args = sieve_name(script)
178
+ args += ' ' + sieve_string(data) if data
179
+ send_command('PUTSCRIPT', args)
180
+ end
181
+
182
+ # Deletes +script+ from the server.
183
+ def delete_script(script)
184
+ send_command('DELETESCRIPT', sieve_name(script))
185
+ end
186
+
187
+ # Sets +script+ as active.
188
+ def set_active(script)
189
+ send_command('SETACTIVE', sieve_name(script))
190
+ end
191
+
192
+ # Returns true if there is space on the server to store +script+ with
193
+ # size +size+ and false otherwise.
194
+ def have_space?(script, size)
195
+ begin
196
+ args = sieve_name(script) + ' ' + size.to_s
197
+ send_command('HAVESPACE', args)
198
+ return true
199
+ rescue SieveCommandError
200
+ return false
201
+ end
202
+ end
203
+
204
+ # Returns true if the server supports TLS and false otherwise.
205
+ def supports_tls?
206
+ @supports_tls
207
+ end
208
+
209
+ # Disconnect from the server.
210
+ def logout
211
+ send_command('LOGOUT')
212
+ @socket.close
213
+ end
214
+
215
+ private
216
+ def authenticate # :nodoc:
217
+ unless @login_mechs.include? @auth_mech
218
+ raise SieveAuthError, "Server doesn't allow #{@auth_mech} authentication"
219
+ end
220
+ case @auth_mech
221
+ when /PLAIN/i
222
+ auth_plain(@euser, @user, @password)
223
+ when /LOGIN/i
224
+ auth_login(@user, @password)
225
+ else
226
+ raise SieveAuthError, "#{@auth_mech} authentication is not implemented"
227
+ end
228
+ end
229
+
230
+ private
231
+ def auth_plain(euser, user, pass) # :nodoc:
232
+ args = [ euser, user, pass ]
233
+ params = sieve_name('PLAIN') + ' '
234
+ params += sieve_name(Base64.encode64(args.join(0.chr)).gsub(/\n/, ''))
235
+ send_command('AUTHENTICATE', params)
236
+ end
237
+
238
+ private
239
+ def auth_login(user, pass) # :nodoc:
240
+ send_command('AUTHENTICATE', sieve_name('LOGIN'), false)
241
+ send_command(sieve_name(Base64.encode64(user)).gsub(/\n/, ''), nil, false)
242
+ send_command(sieve_name(Base64.encode64(pass)).gsub(/\n/, ''))
243
+ end
244
+
245
+ private
246
+ def server_features(lines) # :nodoc:
247
+ lines.each do |type, data|
248
+ case type
249
+ when 'IMPLEMENTATION'
250
+ @implementation = data
251
+ when 'SASL'
252
+ @login_mechs = data.split
253
+ when 'SIEVE'
254
+ @capabilities = data.split
255
+ when 'STARTTLS'
256
+ @supports_tls = true
257
+ end
258
+ end
259
+ end
260
+
261
+ private
262
+ def get_line # :nodoc:
263
+ begin
264
+ return @socket.readline.chomp
265
+ rescue EOFError => e
266
+ raise SieveNetworkError, "Network error: #{e}"
267
+ end
268
+ end
269
+
270
+ private
271
+ def send_command(cmd, args=nil, wait_response=true) # :nodoc:
272
+ cmd += ' ' + args if args
273
+ begin
274
+ @socket.write(cmd + "\r\n")
275
+ resp = get_response if wait_response
276
+ rescue SieveResponseError => e
277
+ raise SieveCommandError, "Command error: #{e}"
278
+ end
279
+ return resp
280
+ end
281
+
282
+ private
283
+ def parse_each_line # :nodoc:
284
+ loop do
285
+ data = get_line
286
+
287
+ # server ok
288
+ m = /^OK(.*)?$/.match(data)
289
+ yield :ok, m.captures.values_at(0, 3) and next if m
290
+
291
+ # server error
292
+ m = /^(NO|BYE)(.*)?$/.match(data)
293
+ if m
294
+ err, msg = m.captures
295
+ size = msg.scan(/\{(\d+)\+?\}/).to_s.to_i
296
+ yield :error, @socket.read(size.to_i + 2) and next if size > 0
297
+ yield :error, msg and next
298
+ end
299
+
300
+ # quoted text
301
+ m = /"([^"]*)"(\s"?([^"]*)"?)?$/.match(data)
302
+ yield :quoted, m.captures.values_at(0,2) and next if m
303
+
304
+ # literal
305
+ m = /\{(\d+)\+?\}/.match(data)
306
+ size = m.captures.first.to_i
307
+ yield :literal, @socket.read(size + 2) and next if m # + 2 for \r\n
308
+
309
+ # other
310
+ yield :other, data
311
+ end
312
+ end
313
+
314
+ private
315
+ def get_response # :nodoc:
316
+ response = []
317
+ parse_each_line do |flag, data|
318
+ case flag
319
+ when :ok
320
+ return response
321
+ when :error
322
+ raise SieveResponseError, data.strip.gsub(/\r\n/, ' ')
323
+ else
324
+ response << data
325
+ end
326
+ end
327
+ end
328
+
329
+ private
330
+ def sieve_name(name) # :nodoc:
331
+ return "\"#{name}\""
332
+ end
333
+
334
+ private
335
+ def sieve_string(string) # :nodoc:
336
+ return "{#{string.length}+}\r\n#{string}"
337
+ end
338
+
339
+ private
340
+ def starttls
341
+ send_command 'STARTTLS'
342
+
343
+ @socket = OpenSSL::SSL::SSLSocket.new @socket
344
+ @socket.sync_close = true
345
+ @socket.connect
346
+
347
+ data = get_response
348
+ server_features(data)
349
+ end
350
+
351
+ end
metadata ADDED
@@ -0,0 +1,53 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: albanpeignier-ruby-managesieve
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ platform: ruby
6
+ authors:
7
+ - Andre Nathan
8
+ autorequire: managesieve
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-11 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: ruby-managesieve is a pure-ruby implementation of the MANAGESIEVE protocol, allowing remote management of Sieve scripts from ruby.
17
+ email: andre@digirati.com.br
18
+ executables:
19
+ - sievectl
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - lib/managesieve.rb
26
+ has_rdoc: true
27
+ homepage: http://managesieve.rubyforge.org
28
+ post_install_message:
29
+ rdoc_options: []
30
+
31
+ require_paths:
32
+ - lib
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: "0"
38
+ version:
39
+ required_rubygems_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ requirements:
46
+ - A network connection and a MANAGESIEVE server.
47
+ rubyforge_project: ruby-managesieve
48
+ rubygems_version: 1.2.0
49
+ signing_key:
50
+ specification_version: 2
51
+ summary: A Ruby library for the MANAGESIEVE protocol
52
+ test_files: []
53
+