module Rubber
  module Dns

    class Dyndns < Base

      def initialize(env)
        super(env, 'dyndns')
        @user, @pass = provider_env.user, provider_env.password
        @update_url = provider_env.update_url || 'https://members.dyndns.org/nic/update?hostname=%host%&myip=%ip%'
        @update_url = @update_url.gsub(/%([^%]+)%/, '#{\1}')
      end

      def nameserver
        "ns1.mydyndns.org"
      end

      def up_to_date(host, ip)
        # This queries dns server directly instead of using hosts file
        current_ip = nil
        Resolv::DNS.open(:nameserver => [nameserver], :search => [], :ndots => 1) do |dns|
          current_ip = dns.getaddress("#{host}.#{provider_env.domain}").to_s rescue nil
        end
        return ip == current_ip
      end
      
      def find_host_records(opts={})
        opts = setup_opts(opts, [:host, :domain])
        hostname = "#{opts[:host]}.#{opts[:domain]}"
        begin
          Resolv::DNS.open(:nameserver => [nameserver], :search => [], :ndots => 1) do |dns|
            r = dns.getresource(hostname, Resolv::DNS::Resource::IN::A)
            result = [{:host =>host, :data => r.address}]
          end
        rescue
          raise "Domain needs to exist in dyndns as an A record before record can be updated"
        end
        return true
      end

      def create_host_record(opts={})
        puts "WARNING: No create record available for dyndns, you need to do so manually"
      end

      def destroy_host_record(opts={})
        puts "WARNING: No destroy record available for dyndns, you need to do so manually"
      end

      def update_host_record(old_opts={}, new_opts={})
        old_opts = setup_opts(opts, [:host, :domain])
        new_opts = setup_opts(opts, [:data])
        
        host = hostname(old_opts[:host])
        ip = new_opts[:data]
        update_url = eval('%Q{' + @update_url + '}')

        # This header is required by dyndns.org
        headers = {
         "User-Agent" => "Capistrano - Rubber - 0.1"
        }

        uri = URI.parse(update_url)
        http = Net::HTTP.new(uri.host, uri.port)
        # switch on SSL
        http.use_ssl = true if uri.scheme == "https"
        # suppress verification warning
        http.verify_mode = OpenSSL::SSL::VERIFY_NONE
        req = Net::HTTP::Get.new(update_url.gsub(/.*:\/\/[^\/]*/, ''), headers)
        # authentication details
        req.basic_auth @user, @pass
        resp = http.request(req)
        # print out the response for the update
        puts "DynDNS Update result: #{resp.body}"
      end

    end

  end
end