zimbra 0.0.4

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 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
+