diff --git a/CHANGELOG.md b/CHANGELOG.md index a1f879e36..aca68d5a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,9 +7,11 @@ * NEW: Added full whois.audns.net.au parser. -* NEW: Added full whois.cctld.by server (GH-154). +* NEW: Added full whois.cctld.by parser (GH-154). -* NEW: Added full whois.domainregistry.ie server. +* NEW: Added full whois.domainregistry.ie parser. + +* NEW: Added full whois.cira.ca parser. * CHANGED: Moved scanners from Whois::Record::Parser::Scanners to Whois::Record::Scanners. diff --git a/lib/whois/record/parser/base_afilias.rb b/lib/whois/record/parser/base_afilias.rb index 43a1bcf9c..e2f3d5ede 100644 --- a/lib/whois/record/parser/base_afilias.rb +++ b/lib/whois/record/parser/base_afilias.rb @@ -24,7 +24,7 @@ class BaseAfilias < Base property_supported :disclaimer do - node("property:disclaimer") + node("field:disclaimer") end diff --git a/lib/whois/record/parser/whois.cira.ca.rb b/lib/whois/record/parser/whois.cira.ca.rb index 512d4f7d3..210a01ee5 100644 --- a/lib/whois/record/parser/whois.cira.ca.rb +++ b/lib/whois/record/parser/whois.cira.ca.rb @@ -8,28 +8,42 @@ require 'whois/record/parser/base' +require 'whois/record/scanners/whois.cira.ca.rb' module Whois class Record class Parser - # - # = whois.cira.ca parser - # # Parser for the whois.cira.ca server. + # + # @see Whois::Record::Parser::Example + # The Example parser for the list of all available methods. # - # NOTE: This parser is just a stub and provides only a few basic methods - # to check for domain availability and get domain status. - # Please consider to contribute implementing missing methods. - # See WhoisNicIt parser for an explanation of all available methods - # and examples. - # + # @since RELEASE class WhoisCiraCa < Base + include Scanners::Ast + + property_supported :disclaimer do + node("field:disclaimer") + end + + + property_supported :domain do + node("Domain name") + end + + property_not_supported :domain_id + + + property_not_supported :referral_whois + + property_not_supported :referral_url + property_supported :status do if content_for_scanner =~ /Domain status:\s+(.+?)\n/ - case $1.downcase + case node("Domain status", &:downcase) when "registered" :registered when "redemption" @@ -60,30 +74,46 @@ class WhoisCiraCa < Base property_supported :created_on do - if content_for_scanner =~ /Creation date:\s+(.+?)\n/ - Time.parse($1) - end + node("Creation date") { |str| Time.parse(str) } end property_supported :updated_on do - if content_for_scanner =~ /Updated date:\s+(.+?)\n/ - Time.parse($1) - end + node("Updated date") { |str| Time.parse(str) } end property_supported :expires_on do - if content_for_scanner =~ /Expiry date:\s+(.+?)\n/ - Time.parse($1) - end + node("Expiry date") { |str| Time.parse(str) } end property_supported :registrar do - if content_for_scanner =~ /^Registrar:\n(.+\n?)^\n/m - match = $1 - id = match =~ /Number:\s+(.+)$/ ? $1.strip : nil - name = match =~ /Name:\s+(.+)$/ ? $1.strip : nil - Whois::Record::Registrar.new(:id => id, :name => name, :organization => name) + node("Registrar") do |hash| + Record::Registrar.new( + :id => hash["Number"], + :name => hash["Name"], + :organization => hash["Name"] + ) + end + end + + + property_supported :registrant_contacts do + build_contact("Registrant", Whois::Record::Contact::TYPE_REGISTRANT) + end + + property_supported :admin_contacts do + build_contact("Administrative contact", Whois::Record::Contact::TYPE_ADMIN) + end + + property_supported :technical_contacts do + build_contact("Technical contact", Whois::Record::Contact::TYPE_TECHNICAL) + end + + + property_supported :nameservers do + Array.wrap(node("nserver")).map do |line| + name, ipv4 = line.split(/\s+/) + Record::Nameserver.new(:name => name, :ipv4 => ipv4) end end @@ -97,11 +127,9 @@ class WhoisCiraCa < Base # ns2.google.com 216.239.34.10 # property_supported :nameservers do - if content_for_scanner =~ /Name servers:\n((?:\s+([^\s]+)\s+([^\s]+)\n)+)/ - $1.split("\n").map do |line| - name, ipv4 = line.strip.split(/\s+/) - Record::Nameserver.new(:name => name, :ipv4 => ipv4) - end + Array.wrap(node("field:nameservers")).map do |line| + name, ipv4 = line.strip.split(/\s+/) + Record::Nameserver.new(:name => name, :ipv4 => ipv4) end end @@ -135,6 +163,38 @@ def invalid? end end + + # Initializes a new {Scanners::WhoisCiraCa} instance + # passing the {#content_for_scanner} + # and calls +parse+ on it. + # + # @return [Hash] + def parse + Scanners::WhoisCiraCa.new(content_for_scanner).parse + end + + + private + + def build_contact(element, type) + node(element) do |hash| + Record::Contact.new( + :type => type, + :id => nil, + :name => hash["Name"], + :organization => nil, + :address => hash["Postal address"], + :city => nil, + :zip => nil, + :state => nil, + :country => nil, + :phone => hash["Phone"], + :fax => hash["Fax"], + :email => hash["Email"] + ) + end + end + end end diff --git a/lib/whois/record/scanners/afilias.rb b/lib/whois/record/scanners/afilias.rb index 9ec7cde39..f2dd6c05a 100644 --- a/lib/whois/record/scanners/afilias.rb +++ b/lib/whois/record/scanners/afilias.rb @@ -50,7 +50,7 @@ class Afilias < Base tokenizer :scan_disclaimer do if @input.pos == 0 && @input.match?(/^(.+\n){3,}\n/) - @ast["property:disclaimer"] = _scan_lines_to_array(/^(.+)\n/).join(" ") + @ast["field:disclaimer"] = _scan_lines_to_array(/^(.+)\n/).join(" ") end end end diff --git a/lib/whois/record/scanners/base.rb b/lib/whois/record/scanners/base.rb index 4d8bca2ca..a5b8e63d1 100644 --- a/lib/whois/record/scanners/base.rb +++ b/lib/whois/record/scanners/base.rb @@ -53,7 +53,7 @@ def parse if @ast[key].nil? @ast[key] = value else - @ast[key] = [@ast[key]] unless @ast[key].is_a?(Array) + @ast[key] = Array.wrap(@ast[key]) @ast[key] << value end end @@ -64,6 +64,7 @@ def parse def _scan_lines_to_array(pattern) lines = [] while @input.scan(pattern) + @input[1].strip lines << @input[1].strip end lines diff --git a/lib/whois/record/scanners/whois.cira.ca.rb b/lib/whois/record/scanners/whois.cira.ca.rb new file mode 100644 index 000000000..5cbe909e1 --- /dev/null +++ b/lib/whois/record/scanners/whois.cira.ca.rb @@ -0,0 +1,86 @@ +#-- +# Ruby Whois +# +# An intelligent pure Ruby WHOIS client and parser. +# +# Copyright (c) 2009-2012 Simone Carletti +#++ + + +require 'whois/record/scanners/base' + + +module Whois + class Record + module Scanners + + # Scanner for the whois.cira.ca record. + # + # @since RELEASE + class WhoisCiraCa < Base + + self.tokenizers += [ + :skip_empty_line, + :scan_disclaimer, + :skip_comment, + :scan_header, + :scan_keyvalue, + :scan_nameserver, + ] + + + + tokenizer :scan_disclaimer do + if @input.match?(/^% Use of CIRA/) + @ast["field:disclaimer"] = _scan_lines_to_array(/^%(.*)\n/).join("\n") + end + end + + tokenizer :scan_header do + if @input.scan(/^(.+?):\n/) + @tmp["group"] = @input[1] + end + end + + tokenizer :scan_keyvalue do + if @input.scan(/^(.+?):(.*?)\n/) + start = @input[1] + key, value = start.strip, @input[2].strip + + # This is a nested key + target = if start[0] == " " + error!("Expected group.") if @tmp["group"].nil? + @ast[@tmp["group"]] ||= {} + else + @tmp.delete("group") + @ast + end + + more = _scan_lines_to_array(/^\s{#{start.size}}(.+)\n/) + value = more.unshift(value).join("\n") unless more.empty? + + if target[key].nil? + target[key] = value + else + target[key] = Array.wrap(target[key]) + target[key] << value + end + end + end + + tokenizer :scan_nameserver do + if @input.scan(/^\s+(.+?)\n/) && @tmp["group"] == "Name servers" + @ast["field:nameservers"] ||= [] + @ast["field:nameservers"] << @input[1].strip + end + end + + tokenizer :skip_comment do + @input.skip(/^%.*\n/) + end + + end + + end + end +end diff --git a/lib/whois/record/scanners/whois.domainregistry.ie.rb b/lib/whois/record/scanners/whois.domainregistry.ie.rb index 8dd936409..a0adbf923 100644 --- a/lib/whois/record/scanners/whois.domainregistry.ie.rb +++ b/lib/whois/record/scanners/whois.domainregistry.ie.rb @@ -19,7 +19,7 @@ class WhoisDomainregistryIe < Base self.tokenizers += [ :skip_empty_line, - :scan_copyright, + :scan_disclaimer, :scan_contact, :scan_keyvalue, :scan_available, @@ -31,7 +31,7 @@ class WhoisDomainregistryIe < Base end end - tokenizer :scan_copyright do + tokenizer :scan_disclaimer do if @input.match?(/^% Rights restricted by copyright/) @ast["field:disclaimer"] = _scan_lines_to_array(/^%(.+)\n/).join("\n") end diff --git a/lib/whois/record/scanners/whois.rnids.rs.rb b/lib/whois/record/scanners/whois.rnids.rs.rb index 2e966dc17..c03b24edb 100644 --- a/lib/whois/record/scanners/whois.rnids.rs.rb +++ b/lib/whois/record/scanners/whois.rnids.rs.rb @@ -53,7 +53,6 @@ class WhoisRnidsRs < Base tokenizer :scan_group_keyvalue do if @input.scan(/(.+?):(.*?)\n/) key, value = @input[1].strip, @input[2].strip - target = @tmp["group"] ? (@ast[@tmp["group"]] ||= {}) : @ast if target[key].nil? diff --git a/spec/fixtures/responses/whois.cira.ca/status_available.expected b/spec/fixtures/responses/whois.cira.ca/status_available.expected index 47a4d45da..b2dbb6641 100644 --- a/spec/fixtures/responses/whois.cira.ca/status_available.expected +++ b/spec/fixtures/responses/whois.cira.ca/status_available.expected @@ -1,3 +1,21 @@ +#disclaimer + should: %s == "Use of CIRA's WHOIS service is governed by the Terms of Use in its Legal\nNotice, available at http://www.cira.ca/legal-notice/?lang=en\n\n(c) 2010 Canadian Internet Registration Authority, (http://www.cira.ca/)" + + +#domain + should: %s == "u34jedzcq.ca" + +#domain_id + should: %s raise_error(Whois::PropertyNotSupported) + + +#referral_whois + should: %s raise_error(Whois::PropertyNotSupported) + +#referral_url + should: %s raise_error(Whois::PropertyNotSupported) + + #status should: %s == :available @@ -21,6 +39,18 @@ #registrar should: %s == nil +#registrant_contacts + should: %s CLASS(array) + should: %s == [] + +#admin_contacts + should: %s CLASS(array) + should: %s == [] + +#technical_contacts + should: %s CLASS(array) + should: %s == [] + #nameservers should: %s CLASS(array) diff --git a/spec/fixtures/responses/whois.cira.ca/status_registered.expected b/spec/fixtures/responses/whois.cira.ca/status_registered.expected index e9147a595..fd90b8daf 100644 --- a/spec/fixtures/responses/whois.cira.ca/status_registered.expected +++ b/spec/fixtures/responses/whois.cira.ca/status_registered.expected @@ -1,3 +1,21 @@ +#disclaimer + should: %s == "Use of CIRA's WHOIS service is governed by the Terms of Use in its Legal\nNotice, available at http://www.cira.ca/legal-notice/?lang=en\n\n(c) 2010 Canadian Internet Registration Authority, (http://www.cira.ca/)" + + +#domain + should: %s == "google.ca" + +#domain_id + should: %s raise_error(Whois::PropertyNotSupported) + + +#referral_whois + should: %s raise_error(Whois::PropertyNotSupported) + +#referral_url + should: %s raise_error(Whois::PropertyNotSupported) + + #status should: %s == :registered @@ -28,6 +46,57 @@ should: %s.organization == "Webnames.ca Inc." should: %s.url == nil +#registrant_contacts + should: %s CLASS(array) + should: %s SIZE(1) + should: %s[0] CLASS(contact) + should: %s[0].type == Whois::Record::Contact::TYPE_REGISTRANT + should: %s[0].id == nil + should: %s[0].name == "Google Inc." + should: %s[0].organization == nil + should: %s[0].address == nil + should: %s[0].city == nil + should: %s[0].zip == nil + should: %s[0].state == nil + should: %s[0].country_code == nil + should: %s[0].phone == nil + should: %s[0].fax == nil + should: %s[0].email == nil + +#admin_contacts + should: %s CLASS(array) + should: %s SIZE(1) + should: %s[0] CLASS(contact) + should: %s[0].type == Whois::Record::Contact::TYPE_ADMIN + should: %s[0].id == nil + should: %s[0].name == "Christina Chiou" + should: %s[0].organization == nil + should: %s[0].address == "130 King St. W., Suite 1800,\nToronto ON M5X1E3 Canada" + should: %s[0].city == nil + should: %s[0].zip == nil + should: %s[0].state == nil + should: %s[0].country_code == nil + should: %s[0].phone == "+1.4168653361x" + should: %s[0].fax == "+1.4169456616" + should: %s[0].email == "dns-admin@google.com" + +#technical_contacts + should: %s CLASS(array) + should: %s SIZE(1) + should: %s[0] CLASS(contact) + should: %s[0].type == Whois::Record::Contact::TYPE_TECHNICAL + should: %s[0].id == nil + should: %s[0].name == "Matt Serlin" + should: %s[0].organization == nil + should: %s[0].address == "Domain Provisioning,10400 Overland Rd. PMB 155\nBoise ID 83709 United States" + should: %s[0].city == nil + should: %s[0].zip == nil + should: %s[0].state == nil + should: %s[0].country_code == nil + should: %s[0].phone == "+1.2083895740x" + should: %s[0].fax == "+1.2083895771" + should: %s[0].email == "ccops@markmonitor.com" + #nameservers should: %s CLASS(array) diff --git a/spec/whois/record/parser/responses/whois.cira.ca/status_available_spec.rb b/spec/whois/record/parser/responses/whois.cira.ca/status_available_spec.rb index 872e17b05..06ab3588b 100644 --- a/spec/whois/record/parser/responses/whois.cira.ca/status_available_spec.rb +++ b/spec/whois/record/parser/responses/whois.cira.ca/status_available_spec.rb @@ -21,6 +21,31 @@ @parser = klass.new(part) end + describe "#disclaimer" do + it do + @parser.disclaimer.should == "Use of CIRA's WHOIS service is governed by the Terms of Use in its Legal\nNotice, available at http://www.cira.ca/legal-notice/?lang=en\n\n(c) 2010 Canadian Internet Registration Authority, (http://www.cira.ca/)" + end + end + describe "#domain" do + it do + @parser.domain.should == "u34jedzcq.ca" + end + end + describe "#domain_id" do + it do + lambda { @parser.domain_id }.should raise_error(Whois::PropertyNotSupported) + end + end + describe "#referral_whois" do + it do + lambda { @parser.referral_whois }.should raise_error(Whois::PropertyNotSupported) + end + end + describe "#referral_url" do + it do + lambda { @parser.referral_url }.should raise_error(Whois::PropertyNotSupported) + end + end describe "#status" do it do @parser.status.should == :available @@ -56,6 +81,24 @@ @parser.registrar.should == nil end end + describe "#registrant_contacts" do + it do + @parser.registrant_contacts.should be_a(Array) + @parser.registrant_contacts.should == [] + end + end + describe "#admin_contacts" do + it do + @parser.admin_contacts.should be_a(Array) + @parser.admin_contacts.should == [] + end + end + describe "#technical_contacts" do + it do + @parser.technical_contacts.should be_a(Array) + @parser.technical_contacts.should == [] + end + end describe "#nameservers" do it do @parser.nameservers.should be_a(Array) diff --git a/spec/whois/record/parser/responses/whois.cira.ca/status_registered_spec.rb b/spec/whois/record/parser/responses/whois.cira.ca/status_registered_spec.rb index 9b948eca1..fdb4f3d7b 100644 --- a/spec/whois/record/parser/responses/whois.cira.ca/status_registered_spec.rb +++ b/spec/whois/record/parser/responses/whois.cira.ca/status_registered_spec.rb @@ -21,6 +21,31 @@ @parser = klass.new(part) end + describe "#disclaimer" do + it do + @parser.disclaimer.should == "Use of CIRA's WHOIS service is governed by the Terms of Use in its Legal\nNotice, available at http://www.cira.ca/legal-notice/?lang=en\n\n(c) 2010 Canadian Internet Registration Authority, (http://www.cira.ca/)" + end + end + describe "#domain" do + it do + @parser.domain.should == "google.ca" + end + end + describe "#domain_id" do + it do + lambda { @parser.domain_id }.should raise_error(Whois::PropertyNotSupported) + end + end + describe "#referral_whois" do + it do + lambda { @parser.referral_whois }.should raise_error(Whois::PropertyNotSupported) + end + end + describe "#referral_url" do + it do + lambda { @parser.referral_url }.should raise_error(Whois::PropertyNotSupported) + end + end describe "#status" do it do @parser.status.should == :registered @@ -63,6 +88,63 @@ @parser.registrar.url.should == nil end end + describe "#registrant_contacts" do + it do + @parser.registrant_contacts.should be_a(Array) + @parser.registrant_contacts.should have(1).items + @parser.registrant_contacts[0].should be_a(Whois::Record::Contact) + @parser.registrant_contacts[0].type.should == Whois::Record::Contact::TYPE_REGISTRANT + @parser.registrant_contacts[0].id.should == nil + @parser.registrant_contacts[0].name.should == "Google Inc." + @parser.registrant_contacts[0].organization.should == nil + @parser.registrant_contacts[0].address.should == nil + @parser.registrant_contacts[0].city.should == nil + @parser.registrant_contacts[0].zip.should == nil + @parser.registrant_contacts[0].state.should == nil + @parser.registrant_contacts[0].country_code.should == nil + @parser.registrant_contacts[0].phone.should == nil + @parser.registrant_contacts[0].fax.should == nil + @parser.registrant_contacts[0].email.should == nil + end + end + describe "#admin_contacts" do + it do + @parser.admin_contacts.should be_a(Array) + @parser.admin_contacts.should have(1).items + @parser.admin_contacts[0].should be_a(Whois::Record::Contact) + @parser.admin_contacts[0].type.should == Whois::Record::Contact::TYPE_ADMIN + @parser.admin_contacts[0].id.should == nil + @parser.admin_contacts[0].name.should == "Christina Chiou" + @parser.admin_contacts[0].organization.should == nil + @parser.admin_contacts[0].address.should == "130 King St. W., Suite 1800,\nToronto ON M5X1E3 Canada" + @parser.admin_contacts[0].city.should == nil + @parser.admin_contacts[0].zip.should == nil + @parser.admin_contacts[0].state.should == nil + @parser.admin_contacts[0].country_code.should == nil + @parser.admin_contacts[0].phone.should == "+1.4168653361x" + @parser.admin_contacts[0].fax.should == "+1.4169456616" + @parser.admin_contacts[0].email.should == "dns-admin@google.com" + end + end + describe "#technical_contacts" do + it do + @parser.technical_contacts.should be_a(Array) + @parser.technical_contacts.should have(1).items + @parser.technical_contacts[0].should be_a(Whois::Record::Contact) + @parser.technical_contacts[0].type.should == Whois::Record::Contact::TYPE_TECHNICAL + @parser.technical_contacts[0].id.should == nil + @parser.technical_contacts[0].name.should == "Matt Serlin" + @parser.technical_contacts[0].organization.should == nil + @parser.technical_contacts[0].address.should == "Domain Provisioning,10400 Overland Rd. PMB 155\nBoise ID 83709 United States" + @parser.technical_contacts[0].city.should == nil + @parser.technical_contacts[0].zip.should == nil + @parser.technical_contacts[0].state.should == nil + @parser.technical_contacts[0].country_code.should == nil + @parser.technical_contacts[0].phone.should == "+1.2083895740x" + @parser.technical_contacts[0].fax.should == "+1.2083895771" + @parser.technical_contacts[0].email.should == "ccops@markmonitor.com" + end + end describe "#nameservers" do it do @parser.nameservers.should be_a(Array)