ruby-managesieve 0.1.0 → 0.2.0
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/bin/sievectl +238 -57
- data/lib/managesieve.rb +42 -19
- metadata +4 -3
data/bin/sievectl
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
|
3
|
+
#--
|
4
|
+
# Copyright (c) 2004, 2005 Andre Nathan <andre@digirati.com.br>
|
4
5
|
#
|
5
6
|
# Permission to use, copy, modify, and distribute this software for any
|
6
7
|
# purpose with or without fee is hereby granted, provided that the above
|
@@ -13,8 +14,69 @@
|
|
13
14
|
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
14
15
|
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
15
16
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
17
|
+
#++
|
16
18
|
#
|
17
|
-
#
|
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), addact (addactive),
|
55
|
+
# del (delete)
|
56
|
+
#
|
57
|
+
# Examples:
|
58
|
+
# List server capabilities:
|
59
|
+
# sievectl caps
|
60
|
+
#
|
61
|
+
# List available scripts:
|
62
|
+
# sievectl list
|
63
|
+
#
|
64
|
+
# Show contents of a script:
|
65
|
+
# sievectl show scriptname
|
66
|
+
#
|
67
|
+
# Add a script:
|
68
|
+
# sievectl add scriptname script.txt
|
69
|
+
# or
|
70
|
+
# sievectl add scriptname < script.txt
|
71
|
+
# or
|
72
|
+
# cat script.txt | sievectl add scriptname
|
73
|
+
#
|
74
|
+
# Delete a script:
|
75
|
+
# sievectl del scriptname
|
76
|
+
#
|
77
|
+
#--
|
78
|
+
# $Id: sievectl,v 1.15 2005/01/21 14:45:30 andre Exp $
|
79
|
+
#++
|
18
80
|
#
|
19
81
|
|
20
82
|
begin
|
@@ -26,18 +88,18 @@ end
|
|
26
88
|
require 'managesieve'
|
27
89
|
require 'yaml'
|
28
90
|
|
29
|
-
class ManageSieve
|
91
|
+
class ManageSieve # :nodoc:
|
30
92
|
def print_capabilities
|
31
93
|
puts 'Capabilities:'
|
32
|
-
@capabilities.each { |cap| puts " - #{cap}" }
|
94
|
+
@capabilities.sort.each { |cap| puts " - #{cap}" }
|
33
95
|
|
34
96
|
puts 'Login Mechanisms:'
|
35
|
-
@login_mechs.each { |mech| puts " - #{mech}" }
|
97
|
+
@login_mechs.sort.each { |mech| puts " - #{mech}" }
|
36
98
|
end
|
37
99
|
|
38
100
|
def print_scripts
|
39
101
|
puts 'Available scripts:'
|
40
|
-
|
102
|
+
scripts.sort.each do |name, active|
|
41
103
|
print " - #{name}"
|
42
104
|
print active ? " (active)\n" : "\n"
|
43
105
|
end
|
@@ -49,25 +111,124 @@ class ManageSieve
|
|
49
111
|
end
|
50
112
|
end
|
51
113
|
|
52
|
-
class
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
114
|
+
class TemplateError # :nodoc:
|
115
|
+
end
|
116
|
+
|
117
|
+
class ConfigFile < File # :nodoc:
|
118
|
+
def ConfigFile.open(name)
|
119
|
+
begin
|
120
|
+
file = super(name)
|
121
|
+
conf = YAML::load(file)
|
122
|
+
file.close
|
123
|
+
return conf
|
124
|
+
rescue Errno::ENOENT
|
125
|
+
ConfigFile::create_template(name)
|
126
|
+
exit 0
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
def ConfigFile.create_template(name)
|
132
|
+
STDERR.puts <<-__EOF__
|
133
|
+
* Could not find configuration file #{name}.
|
134
|
+
* A template file will be created. Please edit the values to fit your
|
135
|
+
* local configuration and run `#{File::basename $0}' again.
|
136
|
+
__EOF__
|
137
|
+
|
138
|
+
begin
|
139
|
+
file = File::open(name, 'w+')
|
140
|
+
file.puts <<-__EOF__
|
141
|
+
accountname:
|
142
|
+
host: servername
|
143
|
+
port: port
|
144
|
+
user: username
|
145
|
+
euser: effectiveusername
|
146
|
+
password: password
|
147
|
+
auth: authmethod
|
148
|
+
__EOF__
|
149
|
+
rescue => e
|
150
|
+
raise TemplateError, e
|
151
|
+
end
|
58
152
|
end
|
59
153
|
end
|
60
154
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
155
|
+
#
|
156
|
+
# The SieveCtl class is a simple set of wrapper methods around the ones
|
157
|
+
# available on the #ManageSieve class.
|
158
|
+
#
|
159
|
+
class SieveCtl
|
160
|
+
def initialize(conf)
|
161
|
+
@manage_sieve = ManageSieve.new(conf)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Prints the server capabilities.
|
165
|
+
def capabilities
|
166
|
+
@manage_sieve.print_capabilities
|
167
|
+
end
|
168
|
+
|
169
|
+
# Lists the available scripts, specifying which one is active.
|
170
|
+
def list
|
171
|
+
@manage_sieve.print_scripts
|
172
|
+
end
|
173
|
+
|
174
|
+
# Shows the contents of +script+.
|
175
|
+
def show(script)
|
176
|
+
raise ArgumentError, "`show' requires a script name" unless script
|
177
|
+
puts @manage_sieve.get_script(script)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Activates +script+.
|
181
|
+
def activate(script)
|
182
|
+
raise ArgumentError, "`activate' requires a script name" unless script
|
183
|
+
@manage_sieve.set_active(script)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Deactivates +script+. There is no +DEACTIVATE+ command in the MANAGESIEVE
|
187
|
+
# draft, so we fetch the script, remove it and upload it again.
|
188
|
+
def deactivate(script)
|
189
|
+
raise ArgumentError, "`deactivate' requires a script name" unless script
|
190
|
+
data = @manage_sieve.get_script(script)
|
191
|
+
@manage_sieve.delete_script(script)
|
192
|
+
@manage_sieve.put_script(script, data)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Adds a script named +script+, from file +file+. If +file+ is +nil+, read
|
196
|
+
# the script from +STDIN+. Activates the script is +active+ is true.
|
197
|
+
def add(script, file=nil, active=false)
|
198
|
+
action = "add#{active ? 'active' : ''}"
|
199
|
+
raise ArgumentError, "`#{action}' requires a script name" unless script
|
200
|
+
data = file ? File.open(file).readlines : STDIN.readlines
|
201
|
+
@manage_sieve.put_script(script, data.to_s)
|
202
|
+
activate script if active
|
203
|
+
end
|
204
|
+
|
205
|
+
# Deletes +script+
|
206
|
+
def delete(script)
|
207
|
+
raise ArgumentError, "`activate' requires a script name" unless script
|
208
|
+
@manage_sieve.delete_script(script)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def usage(quit=true) # :nodoc: #
|
213
|
+
prog = File::basename $0
|
214
|
+
STDERR.puts <<-__EOF__
|
215
|
+
Usage: #{prog} <account> <action> [script name]
|
216
|
+
Action is one of:
|
217
|
+
capabilities, list, show, activate, deactivate, add, addactive, delete
|
218
|
+
|
219
|
+
You can also try `#{prog} help' for usage examples.
|
220
|
+
__EOF__
|
221
|
+
exit 1 if quit
|
65
222
|
end
|
66
223
|
|
67
|
-
def help
|
224
|
+
def help # :nodoc:
|
68
225
|
prog = File::basename $0
|
69
|
-
|
70
|
-
|
226
|
+
usage(false)
|
227
|
+
puts <<-__EOF__
|
228
|
+
|
229
|
+
Short forms for some actions are also accepted:
|
230
|
+
caps (capabilities), act (activate), deact (deactivate), addact (addactive),
|
231
|
+
del (delete)
|
71
232
|
|
72
233
|
Examples:
|
73
234
|
List server capabilities:
|
@@ -82,11 +243,14 @@ Examples:
|
|
82
243
|
Add a script:
|
83
244
|
#{prog} add scriptname script.txt
|
84
245
|
or
|
246
|
+
#{prog} add scriptname < script.txt
|
247
|
+
or
|
85
248
|
cat script.txt | #{prog} add scriptname
|
86
249
|
|
87
250
|
Delete a script:
|
88
251
|
#{prog} del scriptname
|
89
|
-
__EOF__
|
252
|
+
__EOF__
|
253
|
+
exit 0
|
90
254
|
end
|
91
255
|
|
92
256
|
|
@@ -94,44 +258,61 @@ end
|
|
94
258
|
# Main
|
95
259
|
#
|
96
260
|
|
97
|
-
|
261
|
+
help if ARGV[0] =~ /^h(elp)?$/i
|
262
|
+
|
263
|
+
account, action, name, file = ARGV
|
264
|
+
usage if action.nil?
|
265
|
+
|
266
|
+
begin
|
267
|
+
conf = ConfigFile::open(ENV['HOME'] + '/.sievectlrc')
|
268
|
+
rescue TemplateError => e
|
269
|
+
STDERR.puts "Cannot create template configuration file: #{e}"
|
270
|
+
exit 1
|
271
|
+
rescue => e
|
272
|
+
STDERR.puts "Cannot load configuration file: `#{e}'"
|
273
|
+
exit 1
|
274
|
+
end
|
98
275
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
276
|
+
unless conf.has_key? account
|
277
|
+
STDERR.puts <<-__EOF__
|
278
|
+
* Configuration for account `#{account}' not found.
|
279
|
+
* Maybe your configuration file is in the old format?
|
280
|
+
__EOF__
|
281
|
+
exit 1
|
282
|
+
end
|
283
|
+
|
284
|
+
info = conf[account]
|
285
|
+
|
286
|
+
sievectl = SieveCtl.new(
|
287
|
+
:host => info['host'],
|
288
|
+
:port => info['port'],
|
289
|
+
:user => info['user'],
|
290
|
+
:euser => info['euser'],
|
291
|
+
:password => info['password'],
|
292
|
+
:auth => info['auth']
|
106
293
|
)
|
107
294
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
when /^
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
raise ArgumentError, "`activate' requires a script name" unless name
|
132
|
-
m.delete_script(name)
|
133
|
-
when /^h(elp)?$/
|
134
|
-
help
|
135
|
-
else
|
136
|
-
usage
|
295
|
+
begin
|
296
|
+
case action
|
297
|
+
when /^act(ivate)?$/
|
298
|
+
sievectl.activate(name)
|
299
|
+
when /^add$/
|
300
|
+
sievectl.add(name, file)
|
301
|
+
when /^addact(ive)?/
|
302
|
+
sievectl.add(name, file, true)
|
303
|
+
when /^cap(abilitie)?s$/
|
304
|
+
sievectl.capabilities
|
305
|
+
when /^deact(ivate)?$/
|
306
|
+
sievectl.deactivate(name)
|
307
|
+
when /^del(ete)?$/
|
308
|
+
sievectl.delete(name)
|
309
|
+
when /^list$/
|
310
|
+
sievectl.list
|
311
|
+
when /^show$/
|
312
|
+
sievectl.show(name)
|
313
|
+
else
|
314
|
+
usage
|
315
|
+
end
|
316
|
+
rescue SieveCommandError => e
|
317
|
+
STDERR.puts "* #{e}"
|
137
318
|
end
|
data/lib/managesieve.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004 Andre Nathan <andre@digirati.com.br>
|
4
|
+
# Copyright (c) 2004, 2005 Andre Nathan <andre@digirati.com.br>
|
5
5
|
#
|
6
6
|
# Permission to use, copy, modify, and distribute this software for any
|
7
7
|
# purpose with or without fee is hereby granted, provided that the above
|
@@ -25,13 +25,24 @@
|
|
25
25
|
# See the ManageSieve class for documentation and examples.
|
26
26
|
#
|
27
27
|
#--
|
28
|
-
# $Id: managesieve.rb,v 1.
|
28
|
+
# $Id: managesieve.rb,v 1.10 2005/01/17 11:25:56 andre Exp $
|
29
29
|
#++
|
30
30
|
#
|
31
31
|
|
32
32
|
require 'base64'
|
33
33
|
require 'socket'
|
34
34
|
|
35
|
+
#
|
36
|
+
# Define our own Base64.encode64 for compatibility with ruby <= 1.8.1, which
|
37
|
+
# defines encode64() at the top level.
|
38
|
+
#
|
39
|
+
module Base64 # :nodoc:
|
40
|
+
def encode64(s)
|
41
|
+
[s].pack('m')
|
42
|
+
end
|
43
|
+
module_function :encode64
|
44
|
+
end
|
45
|
+
|
35
46
|
class SieveAuthError < Exception; end
|
36
47
|
class SieveCommandError < Exception; end
|
37
48
|
class SieveResponseError < Exception; end
|
@@ -65,7 +76,7 @@ class SieveResponseError < Exception; end
|
|
65
76
|
# )
|
66
77
|
#
|
67
78
|
# # List installed scripts
|
68
|
-
# m.
|
79
|
+
# m.scripts.sort do |name, active|
|
69
80
|
# print name
|
70
81
|
# print active ? " (active)\n" : "\n"
|
71
82
|
# end
|
@@ -125,17 +136,20 @@ class ManageSieve
|
|
125
136
|
end
|
126
137
|
|
127
138
|
|
128
|
-
#
|
129
|
-
# its name and status as parameters.
|
130
|
-
#
|
131
|
-
|
139
|
+
# If a block is given, calls it for each script stored on the server,
|
140
|
+
# passing its name and status as parameters. Else, and array
|
141
|
+
# of [ +name+, +status+ ] arrays is returned. The status is either
|
142
|
+
# 'ACTIVE' or nil.
|
143
|
+
def scripts
|
132
144
|
begin
|
133
145
|
scripts = send_command('LISTSCRIPTS')
|
134
146
|
rescue SieveCommandError => e
|
135
|
-
raise e, "Cannot list scripts"
|
147
|
+
raise e, "Cannot list scripts: #{e}"
|
136
148
|
end
|
149
|
+
return scripts unless block_given?
|
137
150
|
scripts.each { |name, status| yield(name, status) }
|
138
151
|
end
|
152
|
+
alias :each_script :scripts
|
139
153
|
|
140
154
|
# Returns the contents of +script+ as a string.
|
141
155
|
def get_script(script)
|
@@ -144,7 +158,7 @@ class ManageSieve
|
|
144
158
|
rescue SieveCommandError => e
|
145
159
|
raise e, "Cannot get script: #{e}"
|
146
160
|
end
|
147
|
-
return data.to_s
|
161
|
+
return data.to_s.chomp
|
148
162
|
end
|
149
163
|
|
150
164
|
# Uploads +script+ to the server, using +data+ as its contents.
|
@@ -206,15 +220,15 @@ class ManageSieve
|
|
206
220
|
def auth_plain(euser, user, pass) # :nodoc:
|
207
221
|
args = [ euser, user, pass ]
|
208
222
|
params = sieve_name('PLAIN') + ' '
|
209
|
-
params += sieve_name(encode64(args.join(0.chr)).gsub(/\n/, ''))
|
223
|
+
params += sieve_name(Base64.encode64(args.join(0.chr)).gsub(/\n/, ''))
|
210
224
|
send_command('AUTHENTICATE', params)
|
211
225
|
end
|
212
226
|
|
213
227
|
private
|
214
228
|
def auth_login(user, pass) # :nodoc:
|
215
229
|
send_command('AUTHENTICATE', sieve_name('LOGIN'), false)
|
216
|
-
send_command(sieve_name(encode64(user)).gsub(/\n/, ''), nil, false)
|
217
|
-
send_command(sieve_name(encode64(pass)).gsub(/\n/, ''))
|
230
|
+
send_command(sieve_name(Base64.encode64(user)).gsub(/\n/, ''), nil, false)
|
231
|
+
send_command(sieve_name(Base64.encode64(pass)).gsub(/\n/, ''))
|
218
232
|
end
|
219
233
|
|
220
234
|
private
|
@@ -255,10 +269,19 @@ class ManageSieve
|
|
255
269
|
loop do
|
256
270
|
data = get_line
|
257
271
|
|
258
|
-
# server
|
259
|
-
m =
|
260
|
-
yield :
|
261
|
-
|
272
|
+
# server ok
|
273
|
+
m = /^OK$/.match(data)
|
274
|
+
yield :ok, m.captures.values_at(0, 3) and next if m
|
275
|
+
|
276
|
+
# server error
|
277
|
+
m = /^(NO|BYE)(.*)?$/.match(data)
|
278
|
+
if m
|
279
|
+
err, msg = m.captures
|
280
|
+
size = msg.scan(/\{(\d+)\+?\}/).to_s.to_i
|
281
|
+
yield :error, @socket.read(size.to_i + 2) and next if size > 0
|
282
|
+
yield :error, msg and next
|
283
|
+
end
|
284
|
+
|
262
285
|
# quoted text
|
263
286
|
m = /"([^"]*)"(\s"?([^"]*)"?)?$/.match(data)
|
264
287
|
yield :quoted, m.captures.values_at(0,2) and next if m
|
@@ -278,10 +301,10 @@ class ManageSieve
|
|
278
301
|
response = []
|
279
302
|
parse_each_line do |flag, data|
|
280
303
|
case flag
|
281
|
-
when :
|
282
|
-
type, error = data
|
283
|
-
raise SieveResponseError, error unless type == 'OK'
|
304
|
+
when :ok
|
284
305
|
return response
|
306
|
+
when :error
|
307
|
+
raise SieveResponseError, data.strip.gsub(/\r\n/, ' ')
|
285
308
|
else
|
286
309
|
response << data
|
287
310
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.1
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ruby-managesieve
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date:
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2005-01-21
|
8
8
|
summary: A Ruby library for the MANAGESIEVE protocol
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -12,7 +12,8 @@ author: Andre Nathan
|
|
12
12
|
email: andre@digirati.com.br
|
13
13
|
homepage: http://managesieve.rubyforge.org
|
14
14
|
rubyforge_project: ruby-managesieve
|
15
|
-
description: "ruby-managesieve is a pure-ruby implementation of the MANAGESIEVE protocol,
|
15
|
+
description: "ruby-managesieve is a pure-ruby implementation of the MANAGESIEVE protocol,
|
16
|
+
allowing remote management of Sieve scripts from ruby."
|
16
17
|
autorequire: managesieve
|
17
18
|
default_executable:
|
18
19
|
bindir: bin
|