zmldifexport 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,296 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+
3
+ <objectclasses group="ZimbraObjectClass" groupid="2">
4
+
5
+ <objectclass id="1" name="zimbraAccount" type="AUXILIARY">
6
+ <sup>zimbraMailRecipient</sup>
7
+ <desc>Account object</desc>
8
+ <comment>
9
+ zimbraAccount extends zimbraMailRecipient. It represents a real
10
+ account in the system (either admin or end-user) that can be logged
11
+ into, etc.
12
+
13
+ It is defined as AUXILIARY in case it needs to be mixed to an
14
+ existing directory deployment.
15
+
16
+ cn - full name, common name
17
+ co - country friendly name
18
+ company - company (company name)
19
+ displayName - name to display in admin tool, outlook uses as well
20
+ (cn is multi-valued)
21
+ gn - first name (given name)
22
+ initials - middle initial
23
+ l - city (locality)
24
+ ou - organizational unit
25
+ physicalDeliveryOfficeName - office
26
+ street - street address
27
+ postalCode - zip code
28
+ sn - last name (sir name)
29
+ st - state
30
+ telephoneNumber - phone
31
+ </comment>
32
+ </objectclass>
33
+
34
+ <objectclass id="3" name="zimbraCOS" type="STRUCTURAL">
35
+ <sup>top</sup>
36
+ <desc>Class of Service data</desc>
37
+ <comment>
38
+ zimbraCOS is the class of service object. it should have attributes
39
+ that are used as default values for accounts that belong to the COS
40
+ and do not have the same attribute defined in the account directory
41
+ entry.
42
+ </comment>
43
+ </objectclass>
44
+
45
+ <objectclass id="4" name="zimbraDomain" type="AUXILIARY">
46
+ <sup>zimbraMailRecipient</sup>
47
+ <desc>Domain object</desc>
48
+ <comment>
49
+ zimbraDomain is used to represent a domain in the directory. For
50
+ example, if we created the foo.com domain, then the dc=foo,dc=com
51
+ entry in LDAP would have an objectclass of zimbraDomain.
52
+ domain-specific configuration information (if so-needed) could be
53
+ added here.
54
+ </comment>
55
+ </objectclass>
56
+
57
+ <objectclass id="5" name="zimbraSecurityGroup" type="AUXILIARY">
58
+ <sup>top</sup>
59
+ <desc>Security Group</desc>
60
+ <comment>
61
+ zimbraSecurityGroup is used to represent a security group in the
62
+ directory. Members of this group have a zimbraMemberOf attr with
63
+ this group's zimbraId. If this group is a member of other groups,
64
+ then it will have those group's zimbraIds in its own zimbraMemberOf
65
+ list.
66
+ </comment>
67
+ </objectclass>
68
+
69
+ <objectclass id="6" name="zimbraDistributionList" type="STRUCTURAL">
70
+ <sup>top</sup>
71
+ <desc>Distribution List object</desc>
72
+ <comment>
73
+ zimbraDistributionList represents a distribution/mailing list. It
74
+ inherits from zimbraMailRecipient. Members (who can be
75
+ internal/external) are represented as zimbraMailForwardingAddress
76
+ attrs.
77
+ </comment>
78
+ </objectclass>
79
+
80
+ <objectclass id="7" name="zimbraMailRecipient" type="AUXILIARY">
81
+ <sup>top</sup>
82
+ <desc>Mail recipient object</desc>
83
+ <comment>
84
+ zimbraMailRecipient is used to represent entries in the directory
85
+ that can receive mail. i.e., they have a visible external address, that
86
+ gets expanded into one or more internal/external addresses.
87
+ </comment>
88
+ </objectclass>
89
+
90
+ <objectclass id="8" name="zimbraServer" type="STRUCTURAL">
91
+ <sup>top</sup>
92
+ <desc>Server in the cluster</desc>
93
+ <comment>
94
+ zimbraServer is used to represent a defined server within a zimbra
95
+ install. server-specific configuration information will be added
96
+ here. This includes information like which services should be
97
+ running on a server, whether or not the server is normally a
98
+ master/slave, etc.
99
+ </comment>
100
+ </objectclass>
101
+
102
+ <objectclass id="9" name="zimbraGlobalConfig" type="AUXILIARY">
103
+ <sup>top</sup>
104
+ <desc>global config</desc>
105
+ <comment>
106
+ zimbraGlobalConfig is the entry that holds all the global
107
+ configuration attrs.
108
+ </comment>
109
+ </objectclass>
110
+
111
+ <objectclass id="11" name="zimbraAlias" type="STRUCTURAL">
112
+ <sup>top</sup>
113
+ <desc>An alias to another zimbra object</desc>
114
+ <comment>
115
+ zimbraAlias is used to privision aliases
116
+ </comment>
117
+ </objectclass>
118
+
119
+ <objectclass id="12" name="zimbraMimeEntry" type="STRUCTURAL">
120
+ <sup>top</sup>
121
+ <desc>MIME type info</desc>
122
+ <comment>
123
+ zimbraMimeEntry is used to represent status about mime types
124
+ </comment>
125
+ </objectclass>
126
+
127
+ <objectclass id="13" name="zimbraObjectEntry" type="STRUCTURAL">
128
+ <sup>top</sup>
129
+ <desc>Object type info</desc>
130
+ <comment>
131
+ zimbraObjectEntry is used to represent status about object types
132
+ </comment>
133
+ </objectclass>
134
+
135
+ <objectclass id="14" name="zimbraTimeZone" type="STRUCTURAL">
136
+ <sup>top</sup>
137
+ <desc>Time Zone info</desc>
138
+ <comment>
139
+ zimbraTimeZone is used to define a timezone with daylight savings
140
+ time rules. Used in calendar.
141
+ </comment>
142
+ </objectclass>
143
+
144
+ <objectclass id="15" name="zimbraZimletEntry" type="STRUCTURAL">
145
+ <sup>top</sup>
146
+ <desc>Zimlet info</desc>
147
+ <comment>
148
+ zimbraZimletEntry is used to represent Zimlets
149
+ </comment>
150
+ </objectclass>
151
+
152
+ <objectclass id="16" name="zimbraCalendarResource" type="AUXILIARY">
153
+ <sup>top</sup>
154
+ <desc>Calendar resource object</desc>
155
+ <comment>
156
+ zimbraCalendarResource is used to represent a calendar resource This
157
+ objectclass should be mixed in to a zimbraAccount entry.
158
+ </comment>
159
+ </objectclass>
160
+
161
+ <objectclass id="17" name="zimbraIdentity" type="STRUCTURAL">
162
+ <sup>top</sup>
163
+ <desc>Account Email Identity information</desc>
164
+ <comment>
165
+ zimbraIdentity is the account identity object, which stores information about
166
+ Email "identities"
167
+ </comment>
168
+ </objectclass>
169
+
170
+ <objectclass id="18" name="zimbraDataSource" type="STRUCTURAL">
171
+ <sup>top</sup>
172
+ <desc>base class for data source objects</desc>
173
+ <comment>
174
+ zimbraDataSource is the base class for data source objects
175
+ </comment>
176
+ </objectclass>
177
+
178
+ <objectclass id="19" name="zimbraPop3DataSource" type="STRUCTURAL">
179
+ <sup>zimbraDataSource</sup>
180
+ <desc>POP3 data source object</desc>
181
+ <comment>
182
+ zimbraPop3DataSource is the base class for POP3 data source objects
183
+ </comment>
184
+ </objectclass>
185
+
186
+ <objectclass id="20" name="zimbraImapDataSource" type="STRUCTURAL">
187
+ <sup>zimbraDataSource</sup>
188
+ <desc>IMAP data source object</desc>
189
+ <comment>
190
+ zimbraImapDataSource is the base class for IMAP data source objects
191
+ </comment>
192
+ </objectclass>
193
+
194
+ <objectclass id="21" name="zimbraSignature" type="STRUCTURAL">
195
+ <sup>top</sup>
196
+ <desc>Account Email Signature information</desc>
197
+ <comment>
198
+ zimbraSignature is the account Signature object, which stores information about
199
+ Email "signatures"
200
+ </comment>
201
+ </objectclass>
202
+
203
+ <objectclass id="22" name="zimbraXMPPComponent" type="STRUCTURAL">
204
+ <sup>top</sup>
205
+ <desc>XMPP Component Configuration Record</desc>
206
+ <comment>
207
+ zimbraXMPPComponent defines information about routable XMPP services such as conference
208
+ rooms, file transfer servies, etc
209
+ </comment>
210
+ </objectclass>
211
+
212
+ <objectclass id="23" name="zimbraAclTarget" type="STRUCTURAL">
213
+ <sup>top</sup>
214
+ <desc>acl target</desc>
215
+ <comment>
216
+ target entries on which rights(acl) can be granted
217
+ </comment>
218
+ </objectclass>
219
+
220
+ <objectclass id="24" name="zimbraRssDataSource" type="STRUCTURAL">
221
+ <sup>zimbraDataSource</sup>
222
+ <desc>RSS data source object</desc>
223
+ <comment>
224
+ Represents an RSS data source.
225
+ </comment>
226
+ </objectclass>
227
+
228
+ <objectclass id="25" name="zimbraLiveDataSource" type="STRUCTURAL">
229
+ <sup>zimbraDataSource</sup>
230
+ <desc>Hotmail data source object</desc>
231
+ <comment>
232
+ Represents a Hotmail data source.
233
+ </comment>
234
+ </objectclass>
235
+
236
+ <objectclass id="26" name="zimbraGalDataSource" type="STRUCTURAL">
237
+ <sup>zimbraDataSource</sup>
238
+ <desc>GAL data source object</desc>
239
+ <comment>
240
+ Represents a GAL data source.
241
+ </comment>
242
+ </objectclass>
243
+
244
+ <objectclass id="27" name="zimbraGroup" type="AUXILIARY">
245
+ <sup>top</sup>
246
+ <desc>hold attributes for dynamic groups</desc>
247
+ <comment>
248
+ hold attributes for dynamic groups
249
+ </comment>
250
+ </objectclass>
251
+
252
+ <objectclass id="28" name="zimbraGroupDynamicUnit" type="AUXILIARY">
253
+ <sup>top</sup>
254
+ <desc>hold attributes for the dynamic entry of dynamic groups.</desc>
255
+ <comment>
256
+ Dynamic entry of a dynamic group is for members provisioned on the system.
257
+ </comment>
258
+ </objectclass>
259
+
260
+ <objectclass id="29" name="zimbraGroupStaticUnit" type="STRUCTURAL">
261
+ <sup>top</sup>
262
+ <desc>hold attributes for the static entry of dynamic groups.</desc>
263
+ <comment>
264
+ Static entry of a dynamic group is for members not provisioned on the system.
265
+ </comment>
266
+ </objectclass>
267
+
268
+ <objectclass id="30" name="zimbraShareLocator" type="STRUCTURAL">
269
+ <sup>top</sup>
270
+ <desc>Share locator</desc>
271
+ <comment>
272
+ A share locator points to the current location of the share. This
273
+ allows shared data to be relocated transparently without requiring
274
+ the share users to update their mountpoint definition.
275
+ </comment>
276
+ </objectclass>
277
+
278
+ <objectclass id="31" name="zimbraUCService" type="STRUCTURAL">
279
+ <sup>top</sup>
280
+ <desc>Unified Communication service in the cluster</desc>
281
+ <comment>
282
+ zimbraUCService is used to represent a third party UC service.
283
+ This includes information like URLs to the UC providers service and
284
+ Zimbra extensions to load for the service, etc.
285
+ </comment>
286
+ </objectclass>
287
+
288
+ <objectclass id="32" name="zimbraAlwaysOnCluster" type="STRUCTURAL">
289
+ <sup>top</sup>
290
+ <desc>AlwaysOn Cluster</desc>
291
+ <comment>
292
+ zimbraAlwaysOnCluster is used to represent a alwaysOn cluster.
293
+ </comment>
294
+ </objectclass>
295
+
296
+ </objectclasses>
@@ -0,0 +1,487 @@
1
+ require 'open-uri'
2
+ require 'nokogiri'
3
+ require 'net-ldap'
4
+
5
+ module ZmLdifExport
6
+
7
+ class << self
8
+ @options = nil
9
+ @file_path = nil
10
+
11
+ def ldif_file
12
+ begin
13
+ open @file_path
14
+ rescue Errno::ENOENT => _
15
+ puts "File #{@file_path} not found"
16
+ end
17
+ end
18
+
19
+ # Load the LDIF in Memory
20
+ def ldif_data
21
+ ldif_data = Net::LDAP::Dataset.read_ldif ldif_file
22
+ puts "File #{@file_path} not a valid LDIF file" if ldif_data.empty?
23
+ ldif_data
24
+ end
25
+
26
+ def parse_ldif
27
+ ldif_data.to_entries.each do |entry|
28
+ Domain.add Domain.new(entry) if entry.objectclass.include?(OCLASS_DOMAIN)
29
+ DistributionList.add DistributionList.new(entry) if entry.objectclass.include?(OCLASS_DL)
30
+ Account.add Account.new(entry) if valid_account_entry?(entry)
31
+ end
32
+ end
33
+
34
+ def valid_account_entry?(entry)
35
+ entry.objectclass.include?(OCLASS_ACCOUNT) && entry.dn =~ /(#{domain_to_ldif_dc}$|uid=admin|uid=spam|uid=virus|uid=nospam)/
36
+ end
37
+
38
+ # Entry point do all
39
+ def run(options)
40
+ @options = options
41
+ @file_path = @options[:ldif_file]
42
+ @domain = @options[:domain]
43
+ @command = @options[:command]
44
+
45
+ parse_ldif
46
+ self.send(@command)
47
+ end
48
+
49
+ def exportAccounts
50
+ puts "export LC_ALL=en_US.UTF-8"
51
+ puts "export LANG=en_US.UTF-8"
52
+ Account.all.each do |a|
53
+ next if a.name.first =~ /(admin|spam|ham|galsync|virus|wiki)/
54
+ puts "# zmprov ca #{a.name(:zmprov, @domain)}"
55
+ puts a.zmprov_ca(domain: @domain)
56
+ puts ""
57
+ end
58
+ end
59
+
60
+ def exportAliases
61
+ Account.all.each do |a|
62
+ next unless a.has_alias?
63
+ puts "# zmprov aaa #{a.name(:zmprov, @domain)}"
64
+ puts a.zmprov_aaa(domain: @domain)
65
+ puts ""
66
+ end
67
+ end
68
+
69
+ def exportDls
70
+ puts "export LC_ALL=en_US.UTF-8"
71
+ puts "export LANG=en_US.UTF-8"
72
+ DistributionList.all.each do |dl|
73
+ next if dl.name(:zmprov) =~ /archive/i
74
+ puts "# Create DistributionList #{dl.name(:zmprov, @domain)}"
75
+ puts dl.zmprov_cdl domain: "@#{@domain}"
76
+ puts ""
77
+ puts "# Add members to DistributionList #{dl.name(:zmprov, @domain)}"
78
+ puts dl.zmprov_adlm domain: "@#{@domain}"
79
+ puts ""
80
+ puts "# Add Alias to DistributionList #{dl.name(:zmprov, @domain)}"
81
+ puts dl.zmprov_adla domain: "@#{@domain}"
82
+ puts ""
83
+ end
84
+ end
85
+
86
+ def domain_to_ldif_dc
87
+ "dc=#{@domain.split('.').join(',dc=')}"
88
+ end
89
+
90
+ # Build the resulting command
91
+ # @param zm_cmd [String] `zmprov` or `zmmailbox`
92
+ # @param command [String] command to excute, like `ca` or `createDomain`
93
+ # @param attributes [Array] Array of attributes to pass to the command
94
+ # @param full [Boolean] If print `zm_cmd` or just the `command`
95
+ # @returns [String]
96
+ def mk_command(zm_cmd: 'zmprov', command:, resource:, attributes: {}, full: true)
97
+ comment = "# #{zm_cmd} #{command} #{resource}"
98
+ command = full ? "#{zm_cmd} #{command} #{resource}" : "#{command} #{resource}"
99
+ command = command + " \\" if attributes.keys.any?
100
+ attributes = attrs_to_cmd(attributes)
101
+
102
+ [comment, command, attributes].compact.join("\n")
103
+ end
104
+
105
+ # Return an array of attributes
106
+ def attrs_to_cmd(attributes = {})
107
+ lines = []
108
+ attributes.each do |k,v|
109
+ values = [v].flatten.compact
110
+ values.each do |value|
111
+ lines.push "#{k} #{value} \\"
112
+ end
113
+ end
114
+ return nil if lines.empty?
115
+ lines.last.gsub!(' \\', '')
116
+ return lines
117
+ end
118
+
119
+ end
120
+
121
+ # CONSTANTS
122
+ ZIMBRA_ATTRS_FILE = './data/zimbra-attrs.xml'.freeze
123
+ LDIF_FILE = ARGV[0]
124
+ OCLASS_DOMAIN = 'zimbraDomain'
125
+ OCLASS_ACCOUNT = 'zimbraAccount'
126
+ OCLASS_DL = 'zimbraDistributionList'
127
+
128
+ # LDIF_DATA = Net::LDAP::Dataset.read_ldif(open(LDIF_FILE)).to_entries
129
+ @domains = nil
130
+ @accounts = nil
131
+ @aliases = nil
132
+
133
+ class Attribute
134
+ attr_reader :name, :type
135
+
136
+ WHITE_LIST = ['zimbraId', 'zimbraMailAlias'].freeze
137
+
138
+ def initialize(xml_attr)
139
+ @name = xml_attr.attributes['name'].value
140
+ @singular = attr_is_singular?(xml_attr)
141
+ @immutable = attr_is_immutable?(xml_attr)
142
+ @type = xml_attr.attributes['type'].value
143
+ end
144
+
145
+ def singular?
146
+ @singular
147
+ end
148
+
149
+ def immutable?
150
+ @immutable
151
+ end
152
+
153
+ def multiline?
154
+ name == 'zimbraPrefMailSignatureHTML' || name == 'zimbraMailSieveScript' || name == 'zimbraPrefOutOfOfficeReply' || name == 'zimbraPrefOutOfOfficeExternalReply'
155
+ end
156
+
157
+ def text?
158
+ type == 'string' || type == 'duration' || name == 'zimbraACE' || type == 'regex'
159
+ end
160
+
161
+ def number?
162
+ type == 'integer' || type == 'long'
163
+ end
164
+
165
+ def enum?
166
+ type == 'enum'
167
+ end
168
+
169
+ def boolean?
170
+ type == "boolean"
171
+ end
172
+
173
+ def to_zmprov(value, plus = false)
174
+ if multiline?
175
+ command_multiline attr_name: name, value: value
176
+ elsif singular?
177
+ return " \\\n#{name} '#{value.join('').to_s}'" if text?
178
+ return " \\\n#{name} #{value.join('').to_i}" if number?
179
+ return " \\\n#{name} #{value.join('').to_s}"
180
+ else
181
+ line = " \\\n#{name} "
182
+ value = text? ? value.map {|v| "'#{v}'"} : value
183
+ if plus
184
+ line << value.join(" +#{name} ")
185
+ else
186
+ line << value.join(" \\\n#{name} ")
187
+ end
188
+
189
+ line
190
+ end
191
+ end
192
+
193
+ def command_multiline(attr_name:,value:)
194
+ final_wrapper = attr_name == 'zimbraMailSieveScript' ? "'" : '"'
195
+ original_wrapper = attr_name == 'zimbraMailSieveScript' ? '"' : "'"
196
+ line = "#{attr_name} #{final_wrapper}"
197
+ line << value.join('').to_s.gsub(final_wrapper, original_wrapper).split(/\n/).join("\n")
198
+ line << "#{final_wrapper} \\\n"
199
+ line
200
+ end
201
+
202
+ private
203
+
204
+ def attr_is_singular?(attr)
205
+ return false if attr.attributes['cardinality'].nil?
206
+ return true if attr.attributes['type'] == 'astring'
207
+ attr.attributes['cardinality'].value == 'single'
208
+ end
209
+
210
+ def attr_is_immutable?(attr)
211
+ return false if WHITE_LIST.include?(name)
212
+ return false if attr.attributes['immutable'].nil?
213
+ attr.attributes['immutable'].value == '1'
214
+ end
215
+ end
216
+
217
+ class ZimbraResource
218
+
219
+ BLACK_LIST_ATTRS = [
220
+ "dn", "objectclass", "o", "dc", "structuralobjectclass", "entryuuid", "creatorsname",
221
+ "createtimestamp", "entrycsn", "modifiersname", "modifytimestamp", "uid",
222
+ "zimbraaggregatequotalastusage", "zimbradomainstatus", "zimbramailstatus", "zimbraauthtokens",
223
+ "amavisarchivequarantineto", 'zimbramailhost', 'zimbramailtransport', 'zimbramailquota',
224
+ 'zimbraaccountstatus', 'zimbraarchiveaccount', 'zimbraarchiveenabled', 'zimbraauthtokenvalidityvalue',
225
+ 'zimbraPasswordModifiedTime', 'zimbrapreftimezoneid', 'zimbraquotalastwarntime', 'zimbracsrftokendata',
226
+ 'zimbraprefpop3downloadsince', 'zimbrapasswordmodifiedtime', 'zimbracosid',
227
+ 'zimbrapreflistviewcolumns', 'zimbraisadminaccount', 'zimbraisadminaccount', 'zimbraAdminSavedSearches',
228
+ 'zimbraisadmingroup', 'zimbraadminconsoleuicomponents'
229
+ ]
230
+
231
+ attr_reader :attributes, :name, :real_attrs
232
+
233
+ @immutable_attrs = nil
234
+ @attrs_xml = nil
235
+
236
+ def self.attrs_xml
237
+ return @attrs_xml if @attrs_xml
238
+ xml_doc = Nokogiri::XML(open(ZIMBRA_ATTRS_FILE))
239
+ @attrs_xml = xml_doc.xpath('//attr')
240
+ return @attrs_xml
241
+ end
242
+
243
+ def zimbra_attrs
244
+ return @zimbra_attrs if @zimbra_attrs
245
+ @zimbra_attrs = {}
246
+ ZimbraResource.attrs_xml.each do |attr|
247
+ zm_attr = Attribute.new(attr)
248
+ @zimbra_attrs[zm_attr.name.downcase] = zm_attr
249
+ end
250
+ return @zimbra_attrs
251
+ end
252
+
253
+ def name(mode = nil, domain = '')
254
+ return @name if mode.nil?
255
+ return "#{@name.join('').to_s}@#{domain}" if mode == :zmprov
256
+ end
257
+
258
+ def id
259
+ attributes['zimbraid'].first.to_s
260
+ end
261
+
262
+ def parse_attributes(ldif:, exclude: [])
263
+ attrs = {}
264
+ ldif.each_attribute do |a|
265
+ value = ldif[a]
266
+ next if invalid_attribute?(a.to_s) || exclude.include?(a) || invalid_value?(value)
267
+ attrs[a.to_s] = value
268
+ end
269
+ attrs
270
+ end
271
+
272
+ def invalid_value?(value)
273
+ return true if value.join('').to_s =~ /null/
274
+ end
275
+
276
+ def invalid_attribute?(attr_name)
277
+ return true if BLACK_LIST_ATTRS.include?(attr_name)
278
+ zm_attr = zimbra_attrs[attr_name]
279
+ zm_attr.nil? ? false : zm_attr.immutable?
280
+ end
281
+
282
+ def to_zmprov(command: 'ca')
283
+ zmprov_ca if command == 'ca'
284
+ zmprov_aaa if command == 'aaa'
285
+ zmprov_cdl if command == 'cdl'
286
+ zmprov_adlm if command == 'adlm'
287
+ zmprov_adla if command == 'adla'
288
+ end
289
+
290
+ def attr_to_zmprov(attr_name:, value:, plus: false)
291
+ zm_attr = zimbra_attrs[attr_name]
292
+ zm_attr.to_zmprov(value, plus)
293
+ end
294
+ end
295
+
296
+ class Domain < ZimbraResource
297
+ @resources = []
298
+
299
+ def self.all
300
+ return @resources
301
+ end
302
+
303
+ def self.add(resource)
304
+ @resources.push resource
305
+ end
306
+
307
+ def initialize(ldif)
308
+ @name = ldif[:zimbradomainname]
309
+ @attributes = parse_attributes(ldif: ldif, exclude: [:zimbradomainname])
310
+ end
311
+
312
+ def zmprov_cd
313
+ line = ['cd', name]
314
+ attributes.each do |name, value|
315
+ line << attr_to_zmprov(attr_name: name, value: value)
316
+ end
317
+ line.join(' ')
318
+ end
319
+
320
+ end
321
+
322
+ class Account < ZimbraResource
323
+ @resources = []
324
+ attr_accessor :ldif
325
+
326
+ def self.all
327
+ return @resources
328
+ end
329
+
330
+ def self.add(resource)
331
+ @resources.push resource
332
+ end
333
+
334
+ def has_alias?
335
+ attributes['zimbramailalias'] ? attributes['zimbramailalias'].any? : false
336
+ end
337
+
338
+ def initialize(ldif)
339
+ @name = ldif[:uid]
340
+ @ldif = ldif
341
+ @attributes = parse_attributes(ldif: ldif, exclude: [:uid])
342
+ end
343
+
344
+
345
+ def zmprov_ca(domain: '', mail_host: nil, skip: [], print: false)
346
+ line = [
347
+ '/opt/zimbra/bin/zmprov ca',
348
+ name(:zmprov, domain),
349
+ 'P4ssW04r..,. '
350
+ ]
351
+ line.push "zimbraMailHost #{mail_host} " unless mail_host.nil?
352
+ attributes.each do |name, value|
353
+ next if name =~ /(zimbramailalias|admin|zimbracosid|zimbraace|zimbrasharedItem|signature|zimbramailsievescript)/i
354
+ next if skip.include?(name)
355
+ line << attr_to_zmprov(attr_name: name, value: value)
356
+ end
357
+ cmd = line.join(' ')
358
+ puts cmd if print
359
+ return cmd
360
+ end
361
+
362
+ def zmprov_aaa(print: false, domain:)
363
+ aliases = attributes['zimbramailalias']
364
+ return if aliases.nil? || aliases.empty?
365
+ lines = []
366
+ aliases.each do |mail|
367
+ lines.push("aaa #{name(:zmprov, domain)} #{mail}")
368
+ end
369
+
370
+ cmd = lines.join("\n")
371
+ puts cmd if print
372
+ return cmd
373
+ end
374
+
375
+ def ace_to_json(zm_attr = '')
376
+ ace = {}
377
+ keys_and_values = zm_attr.split(';')
378
+ keys_and_values.each do |kv|
379
+ key, value = kv.split(':')
380
+ ace[key] = kv[value]
381
+ end
382
+ return ace
383
+ end
384
+
385
+ def aces(zma)
386
+ aces = []
387
+ zma.each do |zm|
388
+ aces.push(ace_to_json(zm))
389
+ end
390
+
391
+ return aces
392
+ end
393
+
394
+ def zmprov_sharing(print: false, domain:)
395
+ return nil if attributes['zimbrashareditem'].nil?
396
+ line = []
397
+ zimbra_shares = aces(attributes['zimbrashareditem'])
398
+ zimbra_shares.each do |ace|
399
+ next if ace['granteeName'] == 'null'
400
+ line.push("zmmailbox -z -m #{name(:zmprov, domain)} mfg '#{ace['folderPath']}' account #{ace['granteeName']} #{ace['rights']}")
401
+ end
402
+
403
+ cmd = line.size > 0 ? line.join("\n") + "\n" : nil
404
+ puts cmd if print
405
+ return cmd
406
+ end
407
+
408
+ def zmprov_signatures(print: false, domain:)
409
+ return nil if attributes['zimbraprefmailsignaturehtml'].nil?
410
+ line = []
411
+ zimbra_shares = attributes['zimbraprefmailsignaturehtml']
412
+ zimbra_shares.each do |ace|
413
+ ace = ace.gsub(/'/, '"')
414
+ line.push("ma #{name(:zmprov, domain)} zimbraPrefMailSignatureHtml '#{ace}'")
415
+ end
416
+
417
+ cmd = line.size > 0 ? line.join("\n") + "\n" : nil
418
+ puts cmd if print
419
+ return cmd
420
+ end
421
+
422
+ end
423
+
424
+ class DistributionList < ZimbraResource
425
+ @resources = []
426
+
427
+ def self.all
428
+ return @resources
429
+ end
430
+
431
+ def self.add(resource)
432
+ @resources.push resource
433
+ end
434
+
435
+ def initialize(ldif)
436
+ @name = ldif[:uid]
437
+ @attributes = parse_attributes(ldif: ldif, exclude: [:uid])
438
+ end
439
+
440
+ def zmprov_cdl(domain: '', print: false)
441
+ line = ['zmprov cdl', name(:zmprov, domain)]
442
+ attributes.each do |name, value|
443
+ next if name =~ /(zimbraMailForwardingAddress)|(zimbraMailAlias)/i
444
+ line << attr_to_zmprov(attr_name: name, value: value)
445
+ end
446
+ cmd = line.join(' ')
447
+ puts cmd if print
448
+ return cmd
449
+ end
450
+
451
+ def zmprov_adlm(domain:, print: false)
452
+ line = ['adlm', name(:zmprov, domain)]
453
+ attributes.each do |name, value|
454
+ next unless name =~ /zimbraMailForwardingAddress/i
455
+ line << value.join(' ')
456
+ end
457
+ cmd = line.join(' ')
458
+ puts cmd if print
459
+ return cmd
460
+ end
461
+
462
+ def zmprov_adla(domain:, print: false)
463
+ lines = []
464
+ attributes.each do |name, value|
465
+ next unless name =~ /zimbraMailAlias/i
466
+ value.each do |v|
467
+ lines << "adla #{name(:zmprov, domain)} #{v}"
468
+ end
469
+ end
470
+ cmd = lines.join(' ')
471
+ puts cmd if print
472
+ return cmd
473
+ end
474
+ end
475
+
476
+
477
+
478
+
479
+ # Domain.all.each do |domain|
480
+ # next if domain.name(:zmprov) =~ /archive/i
481
+ # puts domain.zmprov_cd
482
+ # puts "\n"
483
+ # end
484
+
485
+
486
+ end
487
+