zimbra 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,13 @@
1
+ EXAMPLE USAGE
2
+ =============
3
+
4
+ Zimbra.url = 'http://example.com:7071/soap/service'
5
+ Zimbra.login('admin@example.com','secret')
6
+
7
+ d = Zimbra::Domain.create('luser.com')
8
+
9
+ dl = Zimbra::DistributionList.create('info@luser.com')
10
+ dl.admin_group = true
11
+ dl.save
12
+
13
+
@@ -0,0 +1,55 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__)))
2
+ require 'zimbra/handsoap_service'
3
+ require 'zimbra/auth'
4
+ require 'zimbra/cos'
5
+ require 'zimbra/domain'
6
+ require 'zimbra/distribution_list'
7
+ require 'zimbra/account'
8
+ require 'zimbra/acl'
9
+ require 'zimbra/common_elements'
10
+
11
+ # Manages a Zimbra SOAP session. Offers ability to set the endpoint URL, log in, and enable debugging.
12
+ module Zimbra
13
+ class << self
14
+
15
+ # The URL that will be used to contact the Zimbra SOAP service
16
+ def url
17
+ @@url
18
+ end
19
+ # Sets the URL of the Zimbra SOAP service
20
+ def url=(url)
21
+ @@url = url
22
+ end
23
+
24
+ # Turn debugging on/off. Outputs full SOAP conversations to stdout.
25
+ # Zimbra.debug = true
26
+ # Zimbra.debug = false
27
+ def debug=(val)
28
+ Handsoap::Service.logger = (val ? $stdout : nil)
29
+ @@debug = val
30
+ end
31
+
32
+ # Whether debugging is enabled
33
+ def debug
34
+ @@debug ||= false
35
+ end
36
+
37
+ # Authorization token - obtained after successful login
38
+ def auth_token
39
+ @@auth_token
40
+ end
41
+
42
+ # Log into the zimbra SOAP service. This is required before any other action is performed
43
+ # If a login has already been performed, another login will not be attempted
44
+ def login(username, password)
45
+ return @@auth_token if defined?(@@auth_token) && @@auth_token
46
+ reset_login(username, password)
47
+ end
48
+
49
+ # re-log into the zimbra SOAP service
50
+ def reset_login(username, password)
51
+ puts "Logging into zimbra as #{username}"
52
+ @@auth_token = Auth.login(username, password)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,155 @@
1
+ module Zimbra
2
+ class Account
3
+ class << self
4
+ def all
5
+ AccountService.all
6
+ end
7
+
8
+ def find_by_id(id)
9
+ AccountService.get_by_id(id)
10
+ end
11
+
12
+ def find_by_name(name)
13
+ AccountService.get_by_name(name)
14
+ end
15
+
16
+ def create(options)
17
+ account = new(options)
18
+ AccountService.create(account)
19
+ end
20
+
21
+ def acl_name
22
+ 'account'
23
+ end
24
+ end
25
+
26
+ attr_accessor :id, :name, :password, :acls, :cos_id, :delegated_admin
27
+
28
+ def initialize(options = {})
29
+ self.id = options[:id]
30
+ self.name = options[:name]
31
+ self.password = options[:password]
32
+ self.acls = options[:acls] || []
33
+ self.cos_id = (options[:cos] ? options[:cos].id : options[:cos_id])
34
+ self.delegated_admin = options[:delegated_admin]
35
+ end
36
+
37
+ def delegated_admin=(val)
38
+ @delegated_admin = Zimbra::Boolean.read(val)
39
+ end
40
+ def delegated_admin?
41
+ @delegated_admin
42
+ end
43
+
44
+ def save
45
+ AccountService.modify(self)
46
+ end
47
+
48
+ def delete
49
+ AccountService.delete(self)
50
+ end
51
+ end
52
+
53
+ class AccountService < HandsoapService
54
+ def all
55
+ xml = invoke("n2:GetAllAccountsRequest")
56
+ Parser.get_all_response(xml)
57
+ end
58
+
59
+ def create(account)
60
+ xml = invoke("n2:CreateAccountRequest") do |message|
61
+ Builder.create(message, account)
62
+ end
63
+ Parser.account_response(xml/"//n2:account")
64
+ end
65
+
66
+ def get_by_id(id)
67
+ xml = invoke("n2:GetAccountRequest") do |message|
68
+ Builder.get_by_id(message, id)
69
+ end
70
+ return nil if soap_fault_not_found?
71
+ Parser.account_response(xml/"//n2:account")
72
+ end
73
+
74
+ def get_by_name(name)
75
+ xml = invoke("n2:GetAccountRequest") do |message|
76
+ Builder.get_by_name(message, name)
77
+ end
78
+ return nil if soap_fault_not_found?
79
+ Parser.account_response(xml/"//n2:account")
80
+ end
81
+
82
+ def modify(account)
83
+ xml = invoke("n2:ModifyAccountRequest") do |message|
84
+ Builder.modify(message, account)
85
+ end
86
+ Parser.account_response(xml/'//n2:account')
87
+ end
88
+
89
+ def delete(dist)
90
+ xml = invoke("n2:DeleteAccountRequest") do |message|
91
+ Builder.delete(message, dist.id)
92
+ end
93
+ end
94
+
95
+ class Builder
96
+ class << self
97
+ def create(message, account)
98
+ message.add 'name', account.name
99
+ message.add 'password', account.password
100
+ A.inject(message, 'zimbraCOSId', account.cos_id)
101
+ end
102
+
103
+ def get_by_id(message, id)
104
+ message.add 'account', id do |c|
105
+ c.set_attr 'by', 'id'
106
+ end
107
+ end
108
+
109
+ def get_by_name(message, name)
110
+ message.add 'account', name do |c|
111
+ c.set_attr 'by', 'name'
112
+ end
113
+ end
114
+
115
+ def modify(message, account)
116
+ message.add 'id', account.id
117
+ modify_attributes(message, distribution_list)
118
+ end
119
+ def modify_attributes(message, account)
120
+ if account.acls.empty?
121
+ ACL.delete_all(message)
122
+ else
123
+ account.acls.each do |acl|
124
+ acl.apply(message)
125
+ end
126
+ end
127
+ Zimbra::A.inject(node, 'zimbraCOSId', account.cos_id)
128
+ Zimbra::A.inject(node, 'zimbraIsDelegatedAdminAccount', (delegated_admin ? 'TRUE' : 'FALSE'))
129
+ end
130
+
131
+ def delete(message, id)
132
+ message.add 'id', id
133
+ end
134
+ end
135
+ end
136
+ class Parser
137
+ class << self
138
+ def get_all_response(response)
139
+ (response/"//n2:account").map do |node|
140
+ account_response(node)
141
+ end
142
+ end
143
+
144
+ def account_response(node)
145
+ id = (node/'@id').to_s
146
+ name = (node/'@name').to_s
147
+ acls = Zimbra::ACL.read(node)
148
+ cos_id = Zimbra::A.read(node, 'zimbraCOSId')
149
+ delegated_admin = Zimbra::A.read(node, 'zimbraIsDelegatedAdminAccount')
150
+ Zimbra::Account.new(:id => id, :name => name, :acls => acls, :cos_id => cos_id, :delegated_admin => delegated_admin)
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,61 @@
1
+ module Zimbra
2
+ class ACL
3
+ class TargetObjectNotFound < StandardError; end
4
+
5
+ TARGET_CLASSES = [Zimbra::Domain, Zimbra::DistributionList, Zimbra::Cos]
6
+ TARGET_MAPPINGS = TARGET_CLASSES.inject({}) do |hsh, klass|
7
+ hsh[klass.acl_name] = klass
8
+ hsh[klass] = klass.acl_name
9
+ hsh
10
+ end
11
+
12
+ class << self
13
+ def delete_all(xmldoc)
14
+ A.inject(xmldoc, 'zimbraACE', '', 'c' => '1')
15
+ end
16
+
17
+ def read(node)
18
+ list = A.read(node, 'zimbraACE')
19
+ return nil if list.nil?
20
+ list = [list] unless list.respond_to?(:map)
21
+ acls = list.map do |ace|
22
+ from_s(ace)
23
+ end
24
+ end
25
+
26
+ def from_zimbra(node)
27
+ from_s(node.to_s)
28
+ end
29
+
30
+ def from_s(value)
31
+ target_id, target_name, name = value.split(' ')
32
+ target_class = TARGET_MAPPINGS[target_name]
33
+ raise TargetObjectNotFound, "Target object not found for acl #{acl_string}" if target_class.nil?
34
+ new(:target_id => target_id, :target_class => target_class, :name => name)
35
+ end
36
+ end
37
+
38
+ attr_accessor :target_id, :target_class, :name
39
+
40
+ def initialize(options = {})
41
+ if options[:target]
42
+ self.target_id = options[:target].id
43
+ self.target_class = options[:target].class
44
+ else
45
+ self.target_id = options[:target_id]
46
+ self.target_class = options[:target_class]
47
+ end
48
+ self.name = options[:name]
49
+ end
50
+
51
+ def to_zimbra_acl_value
52
+ id = target_id
53
+ type = target_class.acl_name
54
+ "#{id} #{type} #{name}"
55
+ end
56
+
57
+ def apply(xmldoc)
58
+ A.inject(xmldoc, 'zimbraACE', to_zimbra_acl_value, 'c' => '1')
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,43 @@
1
+ module Zimbra
2
+ class Auth
3
+ def self.login(username, password)
4
+ AuthService.login(username, password)
5
+ end
6
+ end
7
+
8
+ class AuthService < Handsoap::Service
9
+ include HandsoapErrors
10
+ include Zimbra::HandsoapNamespaces
11
+ extend HandsoapUriOverrides
12
+
13
+ def on_create_document(doc)
14
+ request_namespaces(doc)
15
+ end
16
+ def on_response_document(doc)
17
+ response_namespaces(doc)
18
+ end
19
+
20
+ def login(username, password)
21
+ xml = invoke('n2:AuthRequest') do |message|
22
+ Builder.auth(message, username, password)
23
+ end
24
+ Parser.auth_token(xml)
25
+ end
26
+
27
+ class Builder
28
+ class << self
29
+ def auth(message, username, password)
30
+ message.add 'name', username
31
+ message.add 'password', password
32
+ end
33
+ end
34
+ end
35
+ class Parser
36
+ class << self
37
+ def auth_token(response)
38
+ (response/'//n2:authToken').to_s
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,51 @@
1
+ module Zimbra
2
+ class A
3
+ class << self
4
+ def inject(xmldoc, name, value, extra_attributes = {})
5
+ new(name, value, extra_attributes).inject(xmldoc)
6
+ end
7
+
8
+ def read(xmldoc, name)
9
+ nodes = (xmldoc/"//n2:a[@n='#{name}']")
10
+ return nil if nodes.nil?
11
+ if nodes.size > 1
12
+ nodes.map { |n| from_node(n, name).value }
13
+ else
14
+ from_node(nodes, name).value
15
+ end
16
+ end
17
+
18
+ def from_node(node, name)
19
+ new(name, node.to_s)
20
+ end
21
+ end
22
+
23
+ attr_accessor :name, :value, :extra_attributes
24
+
25
+ def initialize(name, value, extra_attributes = {})
26
+ self.name = name
27
+ self.value = value
28
+ self.extra_attributes = extra_attributes || {}
29
+ end
30
+
31
+ def inject(xmldoc)
32
+ xmldoc.add 'a', value do |a|
33
+ a.set_attr 'n', name
34
+ extra_attributes.each do |eaname, eavalue|
35
+ a.set_attr eaname, eavalue
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ class Boolean
42
+ def self.read(value)
43
+ case value
44
+ when 'TRUE' then true
45
+ when 'FALSE' then false
46
+ when true then true
47
+ else false
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,124 @@
1
+ module Zimbra
2
+ class Cos
3
+ class << self
4
+ def find_by_id(id)
5
+ CosService.get_by_id(id)
6
+ end
7
+
8
+ def find_by_name(name)
9
+ CosService.get_by_name(name)
10
+ end
11
+
12
+ def create(name)
13
+ CosService.create(name)
14
+ end
15
+
16
+ def acl_name
17
+ 'cos'
18
+ end
19
+ end
20
+
21
+ attr_accessor :id, :name, :acls
22
+
23
+ def initialize(id, name, acls = [])
24
+ self.id = id
25
+ self.name = name
26
+ self.acls = acls || []
27
+ end
28
+
29
+ def save
30
+ CosService.modify(self)
31
+ end
32
+
33
+ def delete
34
+ CosService.delete(self)
35
+ end
36
+ end
37
+
38
+ class CosService < HandsoapService
39
+ def get_by_id(id)
40
+ response = invoke("n2:GetCosRequest") do |message|
41
+ Builder.get_by_id(message, id)
42
+ end
43
+ return nil if soap_fault_not_found?
44
+ Parser.cos_response(response/"//n2:cos")
45
+ end
46
+
47
+ def get_by_name(name)
48
+ response = invoke("n2:GetCosRequest") do |message|
49
+ Builder.get_by_name(message, name)
50
+ end
51
+ return nil if soap_fault_not_found?
52
+ Parser.cos_response(response/"//n2:cos")
53
+ end
54
+
55
+ def create(name)
56
+ response = invoke("n2:CreateCosRequest") do |message|
57
+ Builder.create(message, name)
58
+ end
59
+ Parser.cos_response(response/"//n2:cos")
60
+ end
61
+
62
+ def modify(cos)
63
+ xml = invoke("n2:ModifyCosRequest") do |message|
64
+ Builder.modify(message, cos)
65
+ end
66
+ Parser.cos_response(xml/'//n2:cos')
67
+ end
68
+
69
+ def delete(cos)
70
+ xml = invoke("n2:DeleteCosRequest") do |message|
71
+ Builder.delete(message, cos)
72
+ end
73
+ end
74
+
75
+ class Builder
76
+ class << self
77
+ def get_by_id(message, id)
78
+ message.add 'cos', id do |c|
79
+ c.set_attr 'by', 'id'
80
+ end
81
+ end
82
+
83
+ def get_by_name(message, name)
84
+ message.add 'cos', name do |c|
85
+ c.set_attr "by", 'name'
86
+ end
87
+ end
88
+
89
+ def create(message, name)
90
+ message.add 'name', name
91
+ end
92
+
93
+ def modify(message, cos)
94
+ message.add 'id', cos.id
95
+ modify_attributes(message, cos)
96
+ end
97
+ def modify_attributes(message, cos)
98
+ if cos.acls.empty?
99
+ ACL.delete_all(message)
100
+ else
101
+ cos.acls.each do |acl|
102
+ acl.apply(message)
103
+ end
104
+ end
105
+ end
106
+
107
+ def delete(message, cos)
108
+ message.add 'id', cos.id
109
+ end
110
+ end
111
+ end
112
+
113
+ class Parser
114
+ class << self
115
+ def cos_response(node)
116
+ id = (node/'@id').to_s
117
+ name = (node/'@name').to_s
118
+ acls = Zimbra::ACL.read(node)
119
+ Zimbra::Cos.new(id, name, acls)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,207 @@
1
+ module Zimbra
2
+ class DistributionList
3
+ class << self
4
+ def all
5
+ DistributionListService.all
6
+ end
7
+
8
+ def find_by_id(id)
9
+ DistributionListService.get_by_id(id)
10
+ end
11
+
12
+ def find_by_name(name)
13
+ DistributionListService.get_by_name(name)
14
+ end
15
+
16
+ def create(name)
17
+ DistributionListService.create(name)
18
+ end
19
+
20
+ def acl_name
21
+ 'grp'
22
+ end
23
+ end
24
+
25
+ attr_accessor :id, :name, :admin_console_ui_components, :admin_group, :members
26
+
27
+ def initialize(options = {})
28
+ options.each { |name, value| self.send("#{name}=", value) }
29
+ @original_members = self.members.dup
30
+ end
31
+
32
+ def admin_console_ui_components
33
+ @admin_console_ui_components ||= []
34
+ end
35
+
36
+ def members
37
+ @members ||= []
38
+ end
39
+
40
+ def new_members
41
+ self.members - @original_members
42
+ end
43
+
44
+ def removed_members
45
+ @original_members - self.members
46
+ end
47
+
48
+ def admin_group=(val)
49
+ @admin_group = Zimbra::Boolean.read(val)
50
+ end
51
+ def admin_group?
52
+ @admin_group
53
+ end
54
+
55
+ def delete
56
+ DistributionListService.delete(self)
57
+ end
58
+
59
+ def save
60
+ DistributionListService.modify(self)
61
+ end
62
+ end
63
+
64
+ class DistributionListService < HandsoapService
65
+ def all
66
+ xml = invoke("n2:GetAllDistributionListsRequest")
67
+ Parser.get_all_response(xml)
68
+ end
69
+
70
+ def get_by_id(id)
71
+ xml = invoke("n2:GetDistributionListRequest") do |message|
72
+ Builder.get_by_id(message, id)
73
+ end
74
+ return nil if soap_fault_not_found?
75
+ Parser.distribution_list_response(xml/'//n2:dl')
76
+ end
77
+
78
+ def get_by_name(name)
79
+ xml = invoke("n2:GetDistributionListRequest") do |message|
80
+ Builder.get_by_name(message, name)
81
+ end
82
+ return nil if soap_fault_not_found?
83
+ Parser.distribution_list_response(xml/'//n2:dl')
84
+ end
85
+
86
+ def create(name)
87
+ xml = invoke("n2:CreateDistributionListRequest") do |message|
88
+ Builder.create(message, name)
89
+ end
90
+ Parser.distribution_list_response(xml/'//n2:dl')
91
+ end
92
+
93
+ def modify(dist)
94
+ xml = invoke("n2:ModifyDistributionListRequest") do |message|
95
+ Builder.modify(message, dist)
96
+ end
97
+ Parser.distribution_list_response(xml/'//n2:dl')
98
+
99
+ modify_members(dist)
100
+ end
101
+
102
+ def modify_members(distribution_list)
103
+ distribution_list.new_members.each do |member|
104
+ add_member(distribution_list, member)
105
+ end
106
+ distribution_list.removed_members.each do |member|
107
+ remove_member(distribution_list, member)
108
+ end
109
+ end
110
+
111
+ def add_member(distribution_list, member)
112
+ xml = invoke("n2:AddDistributionListMemberRequest") do |message|
113
+ Builder.add_member(message, distribution_list.id, member)
114
+ end
115
+ end
116
+
117
+ def remove_member(distribution_list, member)
118
+ xml = invoke("n2:RemoveDistributionListMemberRequest") do |message|
119
+ Builder.remove_member(message, distribution_list.id, member)
120
+ end
121
+ end
122
+
123
+ def delete(dist)
124
+ xml = invoke("n2:DeleteDistributionListRequest") do |message|
125
+ Builder.delete(message, dist.id)
126
+ end
127
+ end
128
+
129
+ module Builder
130
+ class << self
131
+ def create(message, name)
132
+ message.add 'name', name
133
+ end
134
+
135
+ def get_by_id(message, id)
136
+ message.add 'dl', id do |d|
137
+ d.set_attr 'by', 'id'
138
+ end
139
+ end
140
+
141
+ def get_by_name(message, name)
142
+ message.add 'dl', name do |d|
143
+ d.set_attr "by", 'name'
144
+ end
145
+ end
146
+
147
+ def modify(message, distribution_list)
148
+ message.add 'id', distribution_list.id
149
+ modify_attributes(message, distribution_list)
150
+ end
151
+
152
+ def modify_attributes(message, distribution_list)
153
+ modify_admin_console_ui_components(message, distribution_list)
154
+ modify_is_admin_group(message, distribution_list)
155
+ end
156
+
157
+ def modify_admin_console_ui_components(message, distribution_list)
158
+ if distribution_list.admin_console_ui_components.empty?
159
+ A.inject(message, 'zimbraAdminConsoleUIComponents', '')
160
+ else
161
+ distribution_list.admin_console_ui_components.each do |component|
162
+ A.inject(message, 'zimbraAdminConsoleUIComponents', component)
163
+ end
164
+ end
165
+ end
166
+
167
+ def modify_is_admin_group(message, distribution_list)
168
+ A.inject(message, 'zimbraIsAdminGroup', (distribution_list.admin_group? ? 'TRUE' : 'FALSE'))
169
+ end
170
+
171
+ def add_member(message, distribution_list_id, member)
172
+ message.add 'id', distribution_list_id
173
+ message.add 'dlm', member
174
+ end
175
+
176
+ def remove_member(message, distribution_list_id, member)
177
+ message.add 'id', distribution_list_id
178
+ message.add 'dlm', member
179
+ end
180
+
181
+ def delete(message, id)
182
+ message.add 'id', id
183
+ end
184
+ end
185
+ end
186
+ module Parser
187
+ class << self
188
+ def get_all_response(response)
189
+ items = response/"//n2:dl"
190
+ items.map { |i| distribution_list_response(i) }
191
+ end
192
+
193
+ def distribution_list_response(node)
194
+ id = (node/'@id').to_s
195
+ name = (node/'@name').to_s
196
+ ui_components = A.read(node, 'zimbraAdminConsoleUIComponents')
197
+ admin_group = A.read(node, 'zimbraIsAdminGroup')
198
+ members = (node/"//n2:dlm").map { |n| n.to_s }
199
+
200
+ Zimbra::DistributionList.new(:id => id, :name => name,
201
+ :admin_console_ui_components => ui_components, :admin_group => admin_group,
202
+ :members => members)
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,138 @@
1
+ module Zimbra
2
+ class Domain
3
+ class << self
4
+ def all
5
+ DomainService.all
6
+ end
7
+
8
+ def find_by_id(id)
9
+ DomainService.get_by_id(id)
10
+ end
11
+
12
+ def find_by_name(name)
13
+ DomainService.get_by_name(name)
14
+ end
15
+
16
+ def create(name, attributes = {})
17
+ DomainService.create(name, attributes)
18
+ end
19
+
20
+ def acl_name
21
+ 'domain'
22
+ end
23
+ end
24
+
25
+ attr_accessor :id, :name, :acls
26
+
27
+ def initialize(id, name, acls = [])
28
+ self.id = id
29
+ self.name = name
30
+ self.acls = acls || []
31
+ end
32
+
33
+ def save
34
+ DomainService.modify(self)
35
+ end
36
+
37
+ def delete
38
+ DomainService.delete(self)
39
+ end
40
+ end
41
+
42
+ class DomainService < HandsoapService
43
+ def all
44
+ xml = invoke("n2:GetAllDomainsRequest")
45
+ Parser.get_all_response(xml)
46
+ end
47
+
48
+ def create(name, attributes = {})
49
+ xml = invoke("n2:CreateDomainRequest") do |message|
50
+ Builder.create(message, name)
51
+ end
52
+ Parser.domain_response(xml/"//n2:domain")
53
+ end
54
+
55
+ def get_by_id(id)
56
+ xml = invoke("n2:GetDomainRequest") do |message|
57
+ Builder.get_by_id(message, id)
58
+ end
59
+ return nil if soap_fault_not_found?
60
+ Parser.domain_response(xml/"//n2:domain")
61
+ end
62
+
63
+ def get_by_name(name)
64
+ xml = invoke("n2:GetDomainRequest") do |message|
65
+ Builder.get_by_name(message, name)
66
+ end
67
+ return nil if soap_fault_not_found?
68
+ Parser.domain_response(xml/"//n2:domain")
69
+ end
70
+
71
+ def modify(domain)
72
+ xml = invoke("n2:ModifyDomainRequest") do |message|
73
+ Builder.modify(message, domain)
74
+ end
75
+ Parser.domain_response(xml/'//n2:domain')
76
+ end
77
+
78
+ def delete(dist)
79
+ xml = invoke("n2:DeleteDomainRequest") do |message|
80
+ Builder.delete(message, dist.id)
81
+ end
82
+ end
83
+
84
+ class Builder
85
+ class << self
86
+ def create(message, name)
87
+ message.add 'name', name
88
+ end
89
+
90
+ def get_by_id(message, id)
91
+ message.add 'domain', id do |c|
92
+ c.set_attr 'by', 'id'
93
+ end
94
+ end
95
+
96
+ def get_by_name(message, name)
97
+ message.add 'domain', name do |c|
98
+ c.set_attr 'by', 'name'
99
+ end
100
+ end
101
+
102
+ def modify(message, domain)
103
+ message.add 'id', domain.id
104
+ modify_attributes(message, domain)
105
+ end
106
+ def modify_attributes(message, domain)
107
+ if domain.acls.empty?
108
+ ACL.delete_all(message)
109
+ else
110
+ domain.acls.each do |acl|
111
+ acl.apply(message)
112
+ end
113
+ end
114
+ end
115
+
116
+ def delete(message, id)
117
+ message.add 'id', id
118
+ end
119
+ end
120
+ end
121
+ class Parser
122
+ class << self
123
+ def get_all_response(response)
124
+ (response/"//n2:domain").map do |node|
125
+ domain_response(node)
126
+ end
127
+ end
128
+
129
+ def domain_response(node)
130
+ id = (node/'@id').to_s
131
+ name = (node/'@name').to_s
132
+ acls = Zimbra::ACL.read(node)
133
+ Zimbra::Domain.new(id, name, acls)
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,73 @@
1
+ require 'handsoap'
2
+
3
+ module Zimbra
4
+ module HandsoapErrors
5
+ class SOAPFault < StandardError; end
6
+
7
+ @@response = nil
8
+
9
+ def on_http_error(response)
10
+ @@response = response
11
+ return nil if soap_fault_not_found?
12
+ report_error(response) if http_error?
13
+ end
14
+ def report_error(response)
15
+ message = response.body.scan(/<soap:faultstring>(.*)<\/soap:faultstring>/).first
16
+ raise SOAPFault, message
17
+ end
18
+ def on_after_create_http_request(request)
19
+ @@response = nil
20
+ end
21
+
22
+ def soap_fault_not_found?
23
+ @@response && @@response.body =~ /no such/
24
+ end
25
+ def http_error?
26
+ @@response && (500..599).include?(@@response.status)
27
+ end
28
+ def http_not_found?
29
+ @@response && (400..499).include?(@@response.status)
30
+ end
31
+ end
32
+
33
+ module HandsoapNamespaces
34
+ def request_namespaces(doc)
35
+ doc.alias 'n1', "urn:zimbra"
36
+ doc.alias 'n2', "urn:zimbraAdmin"
37
+ doc.alias 'env', 'http://schemas.xmlsoap.org/soap/envelope/'
38
+ end
39
+ def response_namespaces(doc)
40
+ doc.add_namespace 'n2', "urn:zimbraAdmin"
41
+ end
42
+ end
43
+
44
+ module HandsoapUriOverrides
45
+ def uri
46
+ Zimbra.url
47
+ end
48
+ def envelope_namespace
49
+ 'http://www.w3.org/2003/05/soap-envelope'
50
+ end
51
+ def request_content_type
52
+ "application/soap+xml"
53
+ end
54
+ end
55
+
56
+ class HandsoapService < Handsoap::Service
57
+ include HandsoapErrors
58
+ include HandsoapNamespaces
59
+ extend HandsoapUriOverrides
60
+
61
+ def on_create_document(doc)
62
+ request_namespaces(doc)
63
+ header = doc.find("Header")
64
+ header.add "n1:context" do |s|
65
+ s.set_attr "env:mustUnderstand", "0"
66
+ s.add "n1:authToken", Zimbra.auth_token
67
+ end
68
+ end
69
+ def on_response_document(doc)
70
+ response_namespaces(doc)
71
+ end
72
+ end
73
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zimbra
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 4
10
+ version: 0.0.4
11
+ platform: ruby
12
+ authors:
13
+ - Derek Kastner
14
+ - Matt Wilson
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2009-11-18 00:00:00 -05:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rspec
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: handsoap
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ description: Interface to Zimbra management API
51
+ email: derek@vedit.com mwilson@vedit.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - README
60
+ - lib/zimbra/account.rb
61
+ - lib/zimbra/acl.rb
62
+ - lib/zimbra/auth.rb
63
+ - lib/zimbra/common_elements.rb
64
+ - lib/zimbra/cos.rb
65
+ - lib/zimbra/distribution_list.rb
66
+ - lib/zimbra/domain.rb
67
+ - lib/zimbra/handsoap_service.rb
68
+ - lib/zimbra.rb
69
+ has_rdoc: true
70
+ homepage:
71
+ licenses: []
72
+
73
+ post_install_message:
74
+ rdoc_options: []
75
+
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ hash: 3
84
+ segments:
85
+ - 0
86
+ version: "0"
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ hash: 3
93
+ segments:
94
+ - 0
95
+ version: "0"
96
+ requirements: []
97
+
98
+ rubyforge_project:
99
+ rubygems_version: 1.3.7
100
+ signing_key:
101
+ specification_version: 2
102
+ summary: SOAP Interface to Zimbra
103
+ test_files: []
104
+