epp-client-afnic 0.11.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.
@@ -0,0 +1,5 @@
1
+ 2010-05-14 mat
2
+ * first release
3
+
4
+ 2010-05-04 mat
5
+ * Initial commit
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require 'rubygems'
5
+ require 'epp-client/afnic'
6
+
7
+ c = EPPClient::AFNIC.new(
8
+ :client_id => '-test-.fr',
9
+ :password => 'pass',
10
+ :ssl_cert => 'server.crt',
11
+ :ssl_key => 'server.key',
12
+ :test => true
13
+ )
14
+
15
+ begin
16
+
17
+ c.open_connection
18
+ c.login
19
+ if c.msgQ_count > 0
20
+ pp msg = c.poll_req
21
+ pp c.poll_ack if Hash === msg[:obj]
22
+ end
23
+ pp c.domain_check('mat.fr', 'nonexistantdomain.fr', 'paris.fr', 'trafiquants.fr', 'toto.wf')
24
+ pp c.domain_info('afnic.fr')
25
+ # pas de contact check
26
+ pp c.contact_info('A7534') # legal
27
+ pp c.contact_info('CT214') # particulier
28
+ pp contact = c.contact_create( {
29
+ :email=>"foo@example.org",
30
+ :authInfo => "foobar",
31
+ :voice=>"+33.123456787",
32
+ :postalInfo=> { "loc"=> { :addr=> { :city=>"Paris", :cc=>"FR", :pc=>"75001", :street=>["BP 18", "1, rue Royale"] }, :name=>"Dupond", :org => 'FooBar Inc.' }, },
33
+ #:list => 'restrictedPublication',
34
+ #:individualInfos => {:birthDate => '1978-01-01', :birthCc => 'FR', :birthPc => '75013', :birthCity => 'Paris'},
35
+ #:firstName => 'Jean',
36
+ :legalEntityInfos=> {:siren=>"418565404", :legalStatus=>"company"},
37
+ #:legalEntityInfos=> {:siren=>"418565404", :legalStatus=>"association", :asso => { :decl => '2001-01-01', :publ => {:date => '2001-01-02', :announce => 5, :page => 3}}},
38
+ #:legalEntityInfos=> {:siren=>"418565404", :legalStatus=>"association", :asso => { :waldec => 2 }},
39
+ })
40
+ pp c.contact_info(contact[:id])
41
+ pp c.contact_update({
42
+ :id => contact[:id],
43
+ :chg => {
44
+ :email => 'bazar@example.com',
45
+ }})
46
+ pp c.contact_info(contact[:id])
47
+ pp c.contact_info(contact[:id])
48
+ pp c.domain_create({
49
+ :registrant => "A7534",
50
+ :contacts => {:tech => ["ADM3"], :admin => ["ADM3"]},
51
+ :name => "truc-#{$$}.fr",
52
+ :authInfo => "PN16IZ0V"
53
+ })
54
+ pp c.domain_info(:name => "truc-#{$$}.fr")
55
+ pp c.domain_update({
56
+ :name => "truc-#{$$}.fr",
57
+ #:chg => { :authInfo => 'bazar' },
58
+ :add => {
59
+ :ns => %w(ns1.absolight.net ns2.absolight.net ns3.absolight.net ns4.absolight.net),
60
+ },
61
+ })
62
+ pp c.domain_info(:name => "truc-#{$$}.fr")
63
+ pp c.domain_delete("truc-#{$$}.fr")
64
+ pp c.domain_info(:name => "truc-#{$$}.fr")
65
+ pp c.domain_restore(:name => "truc-#{$$}.fr")
66
+ pp c.domain_info(:name => "truc-#{$$}.fr")
67
+
68
+ ensure
69
+ c.logout
70
+ end
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in epp-client.gemspec
4
+ Dir['*.gemspec'].each do |i|
5
+ gemspec :name => i.sub(/\.gemspec$/, '')
6
+ end
@@ -0,0 +1,19 @@
1
+ Copyright (C) 2010 Mathieu Arnold, Absolight
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README ADDED
@@ -0,0 +1,5 @@
1
+ An extensible EPP client library
2
+
3
+ When possible, the objects that are received via EPP are translated to their
4
+ equivalent in ruby, that is, dates in Date object, timestamps in DateTime
5
+ objects.
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env rake
2
+ require 'rake'
3
+ require 'rdoc/task'
4
+ require 'rubygems/package_task'
5
+ require "bundler/gem_helper"
6
+
7
+ MY_GEMS = Dir['*.gemspec'].map {|g| g.sub(/.*-(.*)\.gemspec/, '\1')}
8
+
9
+ MY_GEMS.each do |g|
10
+ namespace g do
11
+ Bundler::GemHelper.new(Dir.pwd, "epp-client-#{g}").install
12
+ end
13
+ end
14
+
15
+ namespace :all do
16
+ task :build => MY_GEMS.map { |f| "#{f}:build" }
17
+ task :install => MY_GEMS.map { |f| "#{f}:install" }
18
+ task :release => MY_GEMS.map { |f| "#{f}:release" }
19
+ end
20
+
21
+ task :build => 'all:build'
22
+ task :install => 'all:install'
23
+ task :release => 'all:release'
24
+
25
+ desc "Generate documentation for the Rails framework"
26
+ Rake::RDocTask.new do |rdoc|
27
+ rdoc.rdoc_dir = 'doc/rdoc'
28
+ rdoc.title = "Documentation"
29
+
30
+ rdoc.options << '--line-numbers' << '--inline-source'
31
+ rdoc.options << '--charset' << 'utf-8'
32
+
33
+ rdoc.rdoc_files.include('README')
34
+ rdoc.rdoc_files.include('ChangeLog')
35
+ rdoc.rdoc_files.include('lib/**/*.rb')
36
+ end
37
+
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/epp-client/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = 'epp-client-afnic'
6
+ gem.version = EPPClient::VERSION
7
+ gem.date = '2010-05-14'
8
+ gem.authors = ['Mathieu Arnold']
9
+ gem.email = ['m@absolight.fr']
10
+ gem.description = 'AFNIC EPP client library.'
11
+ gem.summary = 'AFNIC EPP client library'
12
+ gem.homepage = "https://github.com/Absolight/epp-client"
13
+
14
+ gem.required_ruby_version = '>= 1.8.7'
15
+ gem.required_rubygems_version = ">= 1.3.6"
16
+
17
+ gem.files = [
18
+ 'ChangeLog',
19
+ 'EXAMPLE.AFNIC',
20
+ 'Gemfile',
21
+ 'MIT-LICENSE',
22
+ 'README',
23
+ 'Rakefile',
24
+ 'epp-client-afnic.gemspec',
25
+ 'lib/epp-client/afnic.rb',
26
+ 'vendor/afnic/frnic-1.0.xsd',
27
+ 'vendor/afnic/frnic-1.1.xsd',
28
+ 'vendor/afnic/frnic-1.2.xsd',
29
+ ]
30
+
31
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
32
+ gem.require_paths = ['lib']
33
+
34
+ gem.add_development_dependency "bundler", ">= 1.0.0"
35
+ gem.add_dependency('nokogiri', '~> 1.4')
36
+ gem.add_dependency('builder', '>= 2.1.2')
37
+ gem.add_dependency('epp-client-base', "~> #{EPPClient::VERSION}")
38
+ gem.add_dependency('epp-client-rgp', "~> #{EPPClient::VERSION}")
39
+ gem.add_dependency('epp-client-secdns', "~> #{EPPClient::VERSION}")
40
+ end
@@ -0,0 +1,505 @@
1
+ require 'epp-client/base'
2
+ require 'epp-client/rgp'
3
+ require 'epp-client/secdns'
4
+
5
+ module EPPClient
6
+ class AFNIC < Base
7
+ SCHEMAS_AFNIC = %w[
8
+ frnic-1.2
9
+ ]
10
+
11
+ EPPClient::SCHEMAS_URL.merge!(SCHEMAS_AFNIC.inject({}) do |a,s|
12
+ a[s.sub(/-1\.2$/, '')] = "http://www.afnic.fr/xml/epp/#{s}" if s =~ /-1\.2$/
13
+ a[s] = "http://www.afnic.fr/xml/epp/#{s}"
14
+ a
15
+ end)
16
+
17
+ # Sets the default for AFNIC, that is, server and port, according to
18
+ # AFNIC's documentation.
19
+ # http://www.afnic.fr/doc/interface/epp
20
+ #
21
+ # ==== Optional Attributes
22
+ # [<tt>:test</tt>] sets the server to be the test server.
23
+ def initialize(args)
24
+ if args.delete(:test) == true
25
+ args[:server] ||= 'epp.test.nic.fr'
26
+ else
27
+ args[:server] ||= 'epp.nic.fr'
28
+ end
29
+ @services = EPPClient::SCHEMAS_URL.values_at('domain', 'contact')
30
+ args[:port] ||= 700
31
+ super(args)
32
+ @extensions << EPPClient::SCHEMAS_URL['frnic']
33
+ end
34
+
35
+ # Extends the base domain check so that the specific afnic check
36
+ # informations are processed, the additionnal informations are :
37
+ #
38
+ # [<tt>:reserved</tt>] the domain is a reserved name.
39
+ # [<tt>:rsvReason</tt>] the optional reason why the domain is reserved.
40
+ # [<tt>:forbidden</tt>] the domain is a forbidden name.
41
+ # [<tt>:fbdReason</tt>] the optional reason why the domain is forbidden.
42
+ def domain_check(*domains)
43
+ super # placeholder so that I can add some doc
44
+ end
45
+
46
+ def domain_check_process(xml) # :nodoc:
47
+ ret = super
48
+ xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:chkData/frnic:domain/frnic:cd', EPPClient::SCHEMAS_URL).each do |dom|
49
+ name = dom.xpath('frnic:name', EPPClient::SCHEMAS_URL)
50
+ hash = ret.select {|d| d[:name] == name.text}.first
51
+ hash[:reserved] = name.attr('reserved').value == "1"
52
+ unless (reason = dom.xpath('frnic:rsvReason', EPPClient::SCHEMAS_URL).text).empty?
53
+ hash[:rsvReason] = reason
54
+ end
55
+ hash[:forbidden] = name.attr('forbidden').value == "1"
56
+ unless (reason = dom.xpath('frnic:fbdReason', EPPClient::SCHEMAS_URL).text).empty?
57
+ hash[:fbdReason] = reason
58
+ end
59
+ end
60
+ return ret
61
+ end
62
+
63
+ # Extends the base domain info so that the specific afnic <tt>:status</tt>
64
+ # can be added.
65
+ def domain_info(domain)
66
+ super # placeholder so that I can add some doc
67
+ end
68
+
69
+ def domain_info_process(xml) #:nodoc:
70
+ ret = super
71
+ if (frnic_status = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:infData/frnic:domain/frnic:status', EPPClient::SCHEMAS_URL)).size > 0
72
+ ret[:status] += frnic_status.map {|s| s.attr('s')}
73
+ end
74
+ ret
75
+ end
76
+
77
+ # parse legalEntityInfos content.
78
+ def legalEntityInfos(leI) #:nodoc:
79
+ ret = {}
80
+ ret[:legalStatus] = leI.xpath('frnic:legalStatus', EPPClient::SCHEMAS_URL).attr('s').value
81
+ if (r = leI.xpath("frnic:idStatus", EPPClient::SCHEMAS_URL)).size > 0
82
+ ret[:idStatus] = {:value => r.text}
83
+ ret[:idStatus][:when] = r.attr('when').value if r.attr('when')
84
+ ret[:idStatus][:source] = r.attr('source').value if r.attr('source')
85
+ end
86
+ %w(siren VAT trademark DUNS local).each do |val|
87
+ if (r = leI.xpath("frnic:#{val}", EPPClient::SCHEMAS_URL)).size > 0
88
+ ret[val.to_sym] = r.text
89
+ end
90
+ end
91
+ if (asso = leI.xpath("frnic:asso", EPPClient::SCHEMAS_URL)).size > 0
92
+ ret[:asso] = {}
93
+ if (r = asso.xpath("frnic:waldec", EPPClient::SCHEMAS_URL)).size > 0
94
+ ret[:asso][:waldec] = r.text
95
+ else
96
+ if (decl = asso.xpath('frnic:decl', EPPClient::SCHEMAS_URL)).size > 0
97
+ ret[:asso][:decl] = Date.parse(decl.text)
98
+ end
99
+ publ = asso.xpath('frnic:publ', EPPClient::SCHEMAS_URL)
100
+ ret[:asso][:publ] = {
101
+ :date => Date.parse(publ.text),
102
+ :page => publ.attr('page').value,
103
+ }
104
+ if (announce = publ.attr('announce')) && announce.value != '0'
105
+ ret[:asso][:publ][:announce] = announce.value
106
+ end
107
+ end
108
+ end
109
+ ret
110
+ end
111
+ private :legalEntityInfos
112
+
113
+ # Extends the base contact info so that the specific afnic check
114
+ # informations are processed, the additionnal informations are :
115
+ #
116
+ # either :
117
+ # [<tt>:legalEntityInfos</tt>]
118
+ # indicating that the contact is an organisation with the following
119
+ # informations :
120
+ # [<tt>:legalStatus</tt>]
121
+ # should be either +company+, +association+ or +other+.
122
+ # [<tt>:idStatus</tt>]
123
+ # indicates the identification process status. Has optional
124
+ # <tt>:when</tt> and <tt>:source</tt> attributes.
125
+ # [<tt>:siren</tt>] contains the SIREN number of the organisation.
126
+ # [<tt>:VAT</tt>]
127
+ # is optional and contains the VAT number of the organisation.
128
+ # [<tt>:trademark</tt>]
129
+ # is optional and contains the trademark number of the organisation.
130
+ # [<tt>:DUNS</tt>]
131
+ # is optional and contains the Data Universal Numbering System number of
132
+ # the organisation.
133
+ # [<tt>:local</tt>]
134
+ # is optional and contains an identifier local to the eligible country.
135
+ # [<tt>:asso</tt>]
136
+ # indicates the organisation is an association and contains either a
137
+ # +waldec+ or a +decl+ and a +publ+ :
138
+ # [<tt>:waldec</tt>] contains the waldec id of the association.
139
+ # [<tt>:decl</tt>]
140
+ # optionally indicate the date of the association was declared at the
141
+ # prefecture.
142
+ # [<tt>:publ</tt>]
143
+ # contains informations regarding the publication in the "Journal
144
+ # Officiel" :
145
+ # [<tt>:date</tt>] the date of publication.
146
+ # [<tt>:page</tt>] the page the announce is on.
147
+ # [<tt>:announce</tt>] the announce number on the page (optional).
148
+ # [<tt>:individualInfos</tt>]
149
+ # indicating that the contact is a person with the following
150
+ # informations :
151
+ # [<tt>:idStatus</tt>]
152
+ # indicates the identification process status. Has optional
153
+ # <tt>:when</tt> and <tt>:source</tt> attributes.
154
+ # [<tt>:birthDate</tt>] the date of birth of the contact.
155
+ # [<tt>:birthCity</tt>] the city of birth of the contact.
156
+ # [<tt>:birthPc</tt>] the postal code of the city of birth.
157
+ # [<tt>:birthCc</tt>] the country code of the place of birth.
158
+ #
159
+ # Additionnaly, when the contact is a person, there can be the following
160
+ # informations :
161
+ # [<tt>:firstName</tt>]
162
+ # the first name of the person. (The last name being stored in the +name+
163
+ # field in the +postalInfo+.)
164
+ # [<tt>:list</tt>]
165
+ # with the value of +restrictedPublication+ mean that the element
166
+ # diffusion should be restricted.
167
+ #
168
+ # Optionnaly, there can be :
169
+ # [<tt>:obsoleted</tt>]
170
+ # the contact info is obsolete since/from the optional date <tt>:when</tt>.
171
+ # [<tt>:reachable</tt>]
172
+ # the contact is reachable through the optional <tt>:media</tt> since/from
173
+ # the optional date <tt>:when</tt>. The info having been specified by the
174
+ # <tt>:source</tt>.
175
+ def contact_info(contact)
176
+ super # placeholder so that I can add some doc
177
+ end
178
+
179
+ def contact_info_process(xml) #:nodoc:
180
+ ret = super
181
+ if (contact = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:infData/frnic:contact', EPPClient::SCHEMAS_URL)).size > 0
182
+ if (list = contact.xpath('frnic:list', EPPClient::SCHEMAS_URL)).size > 0
183
+ ret[:list] = list.map {|l| l.text}
184
+ end
185
+ if (firstName = contact.xpath('frnic:firstName', EPPClient::SCHEMAS_URL)).size > 0
186
+ ret[:firstName] = firstName.text
187
+ end
188
+ if (iI = contact.xpath('frnic:individualInfos', EPPClient::SCHEMAS_URL)).size > 0
189
+ ret[:individualInfos] = {}
190
+ ret[:individualInfos][:birthDate] = Date.parse(iI.xpath('frnic:birthDate', EPPClient::SCHEMAS_URL).text)
191
+ if (r = iI.xpath("frnic:idStatus", EPPClient::SCHEMAS_URL)).size > 0
192
+ ret[:individualInfos][:idStatus] = {:value => r.text}
193
+ ret[:individualInfos][:idStatus][:when] = r.attr('when').value if r.attr('when')
194
+ ret[:individualInfos][:idStatus][:source] = r.attr('source').value if r.attr('source')
195
+ end
196
+ %w(birthCity birthPc birthCc).each do |val|
197
+ if (r = iI.xpath("frnic:#{val}", EPPClient::SCHEMAS_URL)).size > 0
198
+ ret[:individualInfos][val.to_sym] = r.text
199
+ end
200
+ end
201
+ end
202
+ if (leI = contact.xpath('frnic:legalEntityInfos', EPPClient::SCHEMAS_URL)).size > 0
203
+ ret[:legalEntityInfos] = legalEntityInfos(leI)
204
+ end
205
+ if (obsoleted = contact.xpath('frnic:obsoleted', EPPClient::SCHEMAS_URL)).size > 0
206
+ if obsoleted.text != '0'
207
+ ret[:obsoleted] = {}
208
+ ret[:obsoleted][:when] = DateTime.parse(v_when.value) if v_when = obsoleted.attr('when')
209
+ end
210
+ end
211
+ if (reachable = contact.xpath('frnic:reachable', EPPClient::SCHEMAS_URL)).size > 0
212
+ if reachable.text != '0'
213
+ ret[:reachable] = {}
214
+ if v_when = reachable.attr('when')
215
+ ret[:reachable][:when] = DateTime.parse(v_when.value)
216
+ end
217
+ if media = reachable.attr('media')
218
+ ret[:reachable][:media] = media.value
219
+ end
220
+ if source = reachable.attr('source')
221
+ ret[:reachable][:source] = source.value
222
+ end
223
+ end
224
+ end
225
+ end
226
+ ret
227
+ end
228
+
229
+ def contact_create_xml(contact) #:nodoc:
230
+ ret = super
231
+
232
+ ext = extension do |xml|
233
+ xml.ext( :xmlns => EPPClient::SCHEMAS_URL['frnic']) do
234
+ xml.create do
235
+ xml.contact do
236
+ if contact.key?(:legalEntityInfos)
237
+ lEI = contact[:legalEntityInfos]
238
+ xml.legalEntityInfos do
239
+ xml.idStatus(lEI[:idStatus]) if lEI.key?(:idStatus)
240
+ xml.legalStatus(:s => lEI[:legalStatus])
241
+ [:siren, :VAT, :trademark, :DUNS, :local].each do |val|
242
+ if lEI.key?(val)
243
+ xml.__send__(val, lEI[val])
244
+ end
245
+ end
246
+ if lEI.key?(:asso)
247
+ asso = lEI[:asso]
248
+ xml.asso do
249
+ if asso.key?(:waldec)
250
+ xml.waldec(asso[:waldec])
251
+ else
252
+ xml.decl(asso[:decl]) if asso.key?(:decl)
253
+ attrs = {:page => asso[:publ][:page]}
254
+ attrs[:announce] = asso[:publ][:announce] if asso[:publ].key?(:announce)
255
+ xml.publ(attrs, asso[:publ][:date])
256
+ end
257
+ end
258
+ end
259
+ end
260
+ else
261
+ if contact.key?(:list)
262
+ xml.list(contact[:list])
263
+ end
264
+ if contact.key?(:individualInfos)
265
+ iI = contact[:individualInfos]
266
+ xml.individualInfos do
267
+ xml.idStatus(iI[:idStatus]) if iI.key?(:idStatus)
268
+ xml.birthDate(iI[:birthDate])
269
+ if iI.key?(:birthCity)
270
+ xml.birthCity(iI[:birthCity])
271
+ end
272
+ if iI.key?(:birthPc)
273
+ xml.birthPc(iI[:birthPc])
274
+ end
275
+ xml.birthCc(iI[:birthCc])
276
+ end
277
+ end
278
+ if contact.key?(:firstName)
279
+ xml.firstName(contact[:firstName])
280
+ end
281
+ end
282
+ if contact.key?(:reachable)
283
+ if Hash === (reachable = contact[:reachable])
284
+ xml.reachable(reachable, 1)
285
+ else
286
+ raise ArgumentError, "reachable has to be a Hash"
287
+ end
288
+ end
289
+ end
290
+ end
291
+ end
292
+ end
293
+
294
+ insert_extension(ret, ext)
295
+ end
296
+
297
+ # Extends the base contact create so that the specific afnic create
298
+ # informations can be sent, the additionnal informations are :
299
+ #
300
+ # either :
301
+ # [<tt>:legalEntityInfos</tt>]
302
+ # indicating that the contact is an organisation with the following
303
+ # informations :
304
+ # [<tt>:idStatus</tt>]
305
+ # indicates the identification process status.
306
+ # [<tt>:legalStatus</tt>]
307
+ # should be either +company+, +association+ or +other+.
308
+ # [<tt>:siren</tt>] contains the SIREN number of the organisation.
309
+ # [<tt>:VAT</tt>]
310
+ # is optional and contains the VAT number of the organisation.
311
+ # [<tt>:trademark</tt>]
312
+ # is optional and contains the trademark number of the organisation.
313
+ # [<tt>:DUNS</tt>]
314
+ # is optional and contains the Data Universal Numbering System number of
315
+ # the organisation.
316
+ # [<tt>:local</tt>]
317
+ # is optional and contains an identifier local to the eligible country.
318
+ # [<tt>:asso</tt>]
319
+ # indicates the organisation is an association and contains either a
320
+ # +waldec+ or a +decl+ and a +publ+ :
321
+ # [<tt>:waldec</tt>] contains the waldec id of the association.
322
+ # [<tt>:decl</tt>]
323
+ # optionally indicate the date of the association was declared at the
324
+ # prefecture.
325
+ # [<tt>:publ</tt>]
326
+ # contains informations regarding the publication in the "Journal
327
+ # Officiel" :
328
+ # [<tt>:date</tt>] the date of publication.
329
+ # [<tt>:page</tt>] the page the announce is on.
330
+ # [<tt>:announce</tt>] the announce number on the page (optional).
331
+ # [<tt>:individualInfos</tt>]
332
+ # indicating that the contact is a person with the following
333
+ # informations :
334
+ # [<tt>:idStatus</tt>]
335
+ # indicates the identification process status.
336
+ # [<tt>:birthDate</tt>] the date of birth of the contact.
337
+ # [<tt>:birthCity</tt>] the city of birth of the contact.
338
+ # [<tt>:birthPc</tt>] the postal code of the city of birth.
339
+ # [<tt>:birthCc</tt>] the country code of the place of birth.
340
+ #
341
+ # Additionnaly, when the contact is a person, there can be the following
342
+ # informations :
343
+ # [<tt>:firstName</tt>]
344
+ # the first name of the person. (The last name being stored in the +name+
345
+ # field in the +postalInfo+.)
346
+ # [<tt>:list</tt>]
347
+ # with the value of +restrictedPublication+ mean that the element
348
+ # diffusion should be restricted.
349
+ #
350
+ # Optionnaly, there can be :
351
+ # [<tt>:reachable</tt>]
352
+ # the contact is reachable through the optional <tt>:media</tt>.
353
+ #
354
+ # The returned information contains new keys :
355
+ # [<tt>:idStatus</tt>]
356
+ # indicates the identification process status. It's only present when the
357
+ # created contact was created with the +:individualInfos+ or
358
+ # +:legalEntityInfos+ extensions.
359
+ # [<tt>:nhStatus</tt>]
360
+ # is a boolean indicating wether the contact is really new, or if there
361
+ # was already a contact with the exact same informations in the database,
362
+ # in which case, it has been returned.
363
+ def contact_create(contact)
364
+ super # placeholder so that I can add some doc
365
+ end
366
+
367
+ def contact_create_process(xml) #:nodoc:
368
+ ret = super
369
+ if (creData = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:creData', EPPClient::SCHEMAS_URL)).size > 0
370
+ ret[:nhStatus] = creData.xpath('frnic:nhStatus', EPPClient::SCHEMAS_URL).attr('new').value == '1'
371
+ ret[:idStatus] = creData.xpath('frnic:idStatus', EPPClient::SCHEMAS_URL).text
372
+ end
373
+ ret
374
+ end
375
+
376
+ # Make sure there's no <tt>:ns</tt>, <tt>:dsData</tt> or <tt>:keyData</tt>
377
+ # records, AFNIC's servers sends quite a strange error when there is.
378
+ def domain_create(args)
379
+ raise ArgumentError, "You can't create a domain with ns records, you must do an update afterwards" if args.key?(:ns)
380
+ raise ArgumentError, "You can't create a domain with ds or key records, you must do an update afterwards" if args.key?(:dsData) || args.key?(:keyData)
381
+ super
382
+ end
383
+
384
+ # Raises an exception, as contacts are deleted with a garbage collector.
385
+ def contact_delete(args)
386
+ raise NotImplementedError, "Contacts are deleted with a garbage collector"
387
+ end
388
+
389
+ def contact_update_xml(args) #:nodoc:
390
+ ret = super
391
+
392
+ if [:add, :rem].any? {|c| args.key?(c) && [:list, :reachable, :idStatus].any? {|k| args[c].key?(k)}}
393
+ ext = extension do |xml|
394
+ xml.ext( :xmlns => EPPClient::SCHEMAS_URL['frnic']) do
395
+ xml.update do
396
+ xml.contact do
397
+ [:add, :rem].each do |c|
398
+ if args.key?(c) && [:list, :reachable, :idStatus].any? {|k| args[c].key?(k)}
399
+ xml.__send__(c) do
400
+ if args[c].key?(:list)
401
+ xml.list(args[c][:list])
402
+ end
403
+ if args[c].key?(:idStatus)
404
+ xml.idStatus(args[c][:idStatus])
405
+ end
406
+ if args[c].key?(:reachable)
407
+ if Hash === (reachable = args[c][:reachable])
408
+ xml.reachable(reachable, 1)
409
+ else
410
+ raise ArgumentError, "reachable has to be a Hash"
411
+ end
412
+ end
413
+ end
414
+ end
415
+ end
416
+ end
417
+ end
418
+ end
419
+ end
420
+
421
+ return insert_extension(ret, ext)
422
+ else
423
+ return ret
424
+ end
425
+ end
426
+
427
+ # Extends the base contact update so that the specific afnic update
428
+ # informations can be sent, the additionnal informations are :
429
+ #
430
+ # [<tt>:add</tt>/<tt>:rem</tt>]
431
+ # adds or removes the following datas :
432
+ # [<tt>:list</tt>]
433
+ # with the value of +restrictedPublication+ mean that the element
434
+ # diffusion should/should not be restricted.
435
+ # [<tt>:idStatus</tt>]
436
+ # indicates the identification process status.
437
+ # [<tt>:reachable</tt>]
438
+ # the contact is reachable through the optional <tt>:media</tt>.
439
+ def contact_update(args)
440
+ super # placeholder so that I can add some doc
441
+ end
442
+
443
+ # Extends the base domain update so that afnic's weirdnesses can be taken
444
+ # into account.
445
+ #
446
+ # AFNIC does not support ns/hostObj, only ns/hostAttr/Host*, so, take care
447
+ # of this here.
448
+ # Also, you can only do one of the following at a time :
449
+ # * update contacts
450
+ # * update name servers
451
+ # * update status & authInfo
452
+ def domain_update(args)
453
+ if args.key?(:chg) && args[:chg].key?(:registrant)
454
+ raise ArgumentError, "You need to do a trade or recover operation to change the registrant"
455
+ end
456
+ has_contacts = args.key?(:add) && args[:add].key?(:contacts) || args.key?(:add) && args[:add].key?(:contacts)
457
+ has_ns = args.key?(:add) && args[:add].key?(:ns) || args.key?(:add) && args[:add].key?(:ns)
458
+ has_other = args.key?(:add) && args[:add].key?(:status) || args.key?(:add) && args[:add].key?(:status) || args.key?(:chg) && args[:chg].key?(:authInfo)
459
+ if [has_contacts, has_ns, has_other].select {|v| v}.size > 1
460
+ raise ArgumentError, "You can't update all that at one time"
461
+ end
462
+ [:add, :rem].each do |ar|
463
+ if args.key?(ar) && args[ar].key?(:ns) && String === args[ar][:ns].first
464
+ args[ar][:ns] = args[ar][:ns].map {|ns| {:hostName => ns}}
465
+ end
466
+ end
467
+ super
468
+ end
469
+
470
+ # Extends the base poll req to be able to parse quallification response
471
+ # extension.
472
+ def poll_req
473
+ super # placeholder so that I can add some doc
474
+ end
475
+
476
+ def poll_req_process(xml) #:nodoc:
477
+ ret = super(xml)
478
+ if (quaData = xml.xpath('epp:extension/frnic:resData/frnic:quaData', EPPClient::SCHEMAS_URL)).size > 0
479
+ if (contact = xml.xpath('frnic:contact', EPPClient::SCHEMAS_URL)).size > 0
480
+ cret = {:id => contact.xpath('frnic:id', EPPClient::SCHEMAS_URL).text}
481
+ qP = contact.xpath('frnic:qualificationProcess', EPPClient::SCHEMAS_URL)
482
+ cret[:qualificationProcess][:s] = qP.attr('s').value
483
+ cret[:qualificationProcess][:lang] = qP.attr('lang').value if qP.attr('lang')
484
+ if (leI = contact.xpath('frnic:legalEntityInfos', EPPClient::SCHEMAS_URL)).size > 0
485
+ ret[:legalEntityInfos] = legalEntityInfos(leI)
486
+ end
487
+ reach = contact.xpath('frnic:reachability', EPPClient::SCHEMAS_URL)
488
+ cret[:reachability] = {:reStatus => reach.xpath('frnic:reStatus', EPPClient::SCHEMAS_URL).text}
489
+ if (voice = reach.xpath('frnic:voice', EPPClient::SCHEMAS_URL)).size > 0
490
+ cret[:reachability][:voice] = voice.text
491
+ end
492
+ if (email = reach.xpath('frnic:email', EPPClient::SCHEMAS_URL)).size > 0
493
+ cret[:reachability][:email] = email.text
494
+ end
495
+ ret[:quaData] = {:contact => cret}
496
+ end
497
+ end
498
+ ret
499
+ end
500
+
501
+ # keep that at the end.
502
+ include EPPClient::RGP
503
+ include EPPClient::SecDNS
504
+ end
505
+ end