albanpeignier-ruby-managesieve 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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
+