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.
- data/ChangeLog +5 -0
- data/EXAMPLE.AFNIC +70 -0
- data/Gemfile +6 -0
- data/MIT-LICENSE +19 -0
- data/README +5 -0
- data/Rakefile +37 -0
- data/epp-client-afnic.gemspec +40 -0
- data/lib/epp-client/afnic.rb +505 -0
- data/vendor/afnic/frnic-1.0.xsd +393 -0
- data/vendor/afnic/frnic-1.1.xsd +406 -0
- data/vendor/afnic/frnic-1.2.xsd +560 -0
- metadata +174 -0
data/ChangeLog
ADDED
data/EXAMPLE.AFNIC
ADDED
@@ -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
data/MIT-LICENSE
ADDED
@@ -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
data/Rakefile
ADDED
@@ -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
|