Net::DRI
========

A Perl library to access Domain Name Registries/Registrars
Copyright (c) 2005 Patrick Mevzek <netdri@dotandco.com>

DRI stands for Domain Registry Interface and aims to be,
for domain name registries/registrars/resellers
what Perl DBI is for databases.

Net::DRI offers a uniform API to access services.
It can be used by registrars to access registries.
It can be used by clients to access registrars and/or resellers.

It is an OO framework that can be easily extended to
handle various protocols (RRP, EPP, custom protocols) and
various transports methods (TCP, TLS, SOAP, email, etc...).

Specific policies for each registry are handled in a Net::DRI::DRD
subclass, DRD standing for Domain Registry Driver with registry
being used broadly to describe a service offering domain names
and related things, which can be provided by a true domain name
registry, a registrar or a reseller at any level in the chain.

Net::DRI standardizes as much as possible on EPP which is the current
standard for domain name activities, for example for status codes.

Currently Net::DRI ships with
- a full RRP implementation (RFC 2832 & 3632)
- a TCP/TLS transport
- a SOAP transport (HTTP/HTTPS)
- a Web scraping ``transport''
- a Net::DRI::DRD::VNDS covering Verisign Naming & Directory Services for
  .COM & .NET
- a Net::DRI::DRD::AFNIC covering AFNIC registry for .FR
     (only domain_check through web services)
- a Net::DRI::DRD::Gandi covering Gandi registrar for .COM/.NET/.ORG/.BIZ/
   .INFO/.NAME/.BE
     (only domain_update for nameservers through web site)

Work is underway to provide a full EPP implementation for various registries,
as well as an email transport.

If you are a registry/registrar/reseller, we would welcome
the opportunity to be able to test Net::DRI against your system. Please
drop a note to the authors of Net::DRI and do not hesitate to provide
this framework to your clients (see license file).


Perl modules needed
-------------------

Carp (Perl internal)
DateTime
DateTime::Duration
DateTime::Format::Strptime
DateTime::TimeZone
Class::Accessor
Class::Accessor::Chained

Time::HiRes

IO::Socket::INET
IO::Socket::SSL (>=0.90)
SOAP::Lite
WWW::Mechanize

Install
-------

Use the standard procedure:
perl Makefile.PL ; make ; make tests ; make install
Or just copy the content of the lib/ directory somewhere in your path.
You can use tests available in t/ to make sure everything is well.
(all tests are done locally and do not require a network connection)

How to use
----------

You can find examples in the eg subdirectory:
vnds_rrp.pl : as registrar, to connect to Verisign systems using RRP
afnic_ws.pl : as AFNIC member, to use AFNIC web services
gandi_web.pl : as Gandi client, to change nameservers for your domain, 
               through the web interface

All errors trigger an exception using die and a specific class
(Net::DRI::Exception). Thus all calls to Net::DRI methods should be
put in an eval() to easily trap exceptions. Please see Net::DRI::Exception
for details about information available when an exception is raised.

Net::DRI uses an internal cache (in the future many different backends will
be available for this service), and you can provide the global time to live of objects
in it when you create the Net::DRI object. A negative ttl means no cache at all.
It is recommended not to completely disable the cache, and to have a ttl of at
least of few seconds : it will cut down the use of checks and related verifications
done at registry, especially for complex operations.

Typical use of this library would go along those lines:
- $dri=Net::DRI->new(...) to create the global object. Save the output,
  everything will be done with methods applied on this object
- $dri->add_registry(...) to add a new registry driver
  you can attach as many registry drivers as you need to a single dri object
  this would enable you to easily operate on multiple registries at the same time
  Use $dri->target('registry name') to set the current registry, the one which
  will receive all future calls.
  The target method returns the $dri object, thus can be chained with other calls.
  Besides the registry name you can also pass a domain name or a TLD, and the library
  will try to find the correct registry. This will work only if you have no overlap between
  your TLDs among various registries
- $dri->new_profile('profilename','transport class',[transport params],'protocol class',[protocol params])
 (or new_current_profile with same parameters as in new_profile and it will also
   set the default profile to the one being created)
  Each registry driver is used through a specific profile. Each driver can have at the same time
  as many profiles as needed.
  A profile is:
  - a name
  - a transport, with specific parameters
  - a protocol, with specific parameters

  This enables you to be connected to the same registries with different credentials at the same
  time, or through different transports, if the registry provides for example access by email
  and by TCP at the same time.

  You switch profile using the $dri->target('registry name','profile name') call.

  Optionnally, you can use an auto target function:
  by providing details about which profile to use for each given action,
  Net::DRI can switch to the profile needed automatically, thus you will not need
  anymore to call target() by yourself.
  To do that, you will need to provide information by calling:
  $dri->set_auto_target('profile','type','action')
  Profile is the profile name to use when doing
  action 'action' (check, info, create, etc...) on object type 'type' (domain, host, contact).
  The profile must exist before calling set_auto_target()
  A default profile can be specified when type and/or action is undef.

- after registries and profiles have been created (others can be added at any time),
 you can apply many methods (see below) to the $dri object
 You can change the current registry and/or current profile at any time using $dri->target(...,...)

 You get back for most of the calls an object representing the status.
 It is an instance of Net::DRI::Protocol::ResultStatus, please see its documentation.

 You can also always use:
 result_is_success() result_code() result_native_code() result_message() methods
 to get back the same information (if not given by the methods or if you want to discard output)

 Information that has been sent by registry will be available through $dri->get_info(...)
 with a specific key. The key to use depends on the operation, but should be registry-independent.
 get_info() get back information related to the latest operation.
 If you use target() and later get_info() you will get information related to the latest operation
 for the registry/profile specified in the target() call.

 See below the list of methods you can call, and information available after each in get_info()

- when you are finished, call $dri->end() to deallocate ressources and close any open connections.


Available API
-------------

* root_servers()

 gives list of root servers or domain name of root servers (in scalar context)
 for the current registry
 
* is_thick()

 gives 1 if the current registry stores contacts (thick registry)
 
* periods()

 gives the list of all registration periods allowed by the current registry.
 Periods are given as DateTime::Duration objects.

* is_my_tld()

 with a domain name as argument, returns 1 if the current registry handles this
 domain name (TLD of domain name is handled by registry)

* verify_name_domain() verify_name_host()

 gives 0 if the given argument is a correct name for a domain name or an hostname
 at the current registry.

* verify_duration_create() verify_duration_renew() verify_duration_transfer()

 called internally at various stages in Net::DRI to verify that we can add/renew/transfer
 a domain name

* domain_create_only()

 Create a domain at the current registry and current profile.
 A domain name and an hash ref should be provided.
 The hash ref can have a ``duration'' key with its value being a DateTime::Duration object,
 and a ``ns'' key with its value being a Net::DRI::Data::Hosts object.
 If nameservers are given, they must already exist at registry.

 You may use get_info with the following keys to get more information:
 - exDate : for the current expiration date (a DateTime object)
 - status : for the current status of domain name

* domain_create()

 Same thing as before but
 1) we separate nameservers : those being inside domain name being created, those being outside
 2) we test outside nameservers for existence at registry, and if it fails, we try to create them
 3) we create domain
 4) we create nameservers that are inside domain
 5) we update domain to add nameservers created at step 4.
 6) if a status key exists in hash ref given, we try to change status of newly created domain name

 (For thick registries, we would also test contacts, and add them if necessary)

 In scalar context we get back the last status (which can be the one at any step, if it does not succeed)
 of the list of all status for each step in array context.

* domain_delete_only()

 Delete a domain at the current registry and current profile.
 A domain name should be provided.

* domain_delete()

 Same as previous method except:
 1) we find the current list of nameservers for this domain
 2) we remove all nameservers from this domain
 3) we delete the domain name
 (which can fail if some nameservers use the domain name in their FQDN,
 we should try to rename them first, it is planned for later)

 See domain_create() for information on what we get back.
 
* domain_info()

 Ask for all information on a given domain name at the current registry and current profile.

 You may use get_info with the following keys to get more information:
 - ns : a Net::DRI::Data::Hosts object representing the nameservers of the domain
 - status : a Net::DRI::Protocol::StatusList object representing the current status list of the domain queried
 - exDate, crDate, upDate, trDate : DateTime objects representing the expiration, creation, last update, and
                          transfer date for the domain queried
 - clID, crID, upID : (strings) local registry ID of the current sponsoring registrar, the registrar having created,
                       and the registrar (or registry) having last modified the domain queried

* domain_check()

 Check if a domain name exists or not at the current registry and current profile.
 
 $dri->get_info('exist') returns 0 or 1

* domain_exist()

 Same as previous, but we get back 0 or 1 if the domain does not exist/exist or undef if we do not know.

* domain_update()

 Update the domain name given as argument at the current registry and current profile.
 Most of the time you should use the following more specific methods.
 
* domain_update_ns()

 Update nameservers of the domain name given as argument at the current registry and current profile.
 Most of the time you should use the following more specific methods.
 
* domain_update_ns_add()

 For the given domain name as first argument,
 add the nameservers given as second argument (being a Net::DRI::Data::Hosts object).
 
* domain_update_ns_del()

 Same as previous to delete nameservers
 
* domain_update_ns_set()

 Same as previous to set the current list of nameservers, irrespective to what they are now.
 
* domain_update_status()

 Update statuses of the domain name given as argument at the current registry and current profile.
 Most of the time you should use the following more specific methods.
 
* domain_update_status_add()

 For the given domain name as first argument,
 add the statuses given as second argument (being a Net::DRI::Protocol::StatusList or subclass object).

 To create the second argument, the following must be done:
 - $p=$dri->protocol(); to retrieve the protocol handler for the current registry and current profile.
 - then $p->create_status($rh) to create the Net::DRI::Protocol::StatusList
 with $rh being an hash ref with keys being the name of operation you do not want, and values being 0
 You can forbid : renew, update, transfer, publish, delete 
 The choices really available depend on the registry.

* domain_update_status_del()

 Same as previous to delete statuses.
 
* domain_update_status_set()

 Same as previous to set the current list of status, irrespective to what they are now.
 
* domain_renew()

 Renew the domain name provided as first argument,
 with optionnally the duration as second argument, and current expiration as third.

 You may use get_info() to retrieve the same information as after domain_create_only()

* domain_transfer()

 Various operations related to transfers of domain names.
 Most of the time you should use the following more specific methods.

* domain_transfer_start()

 Start the transfer of the given domain name as first argument.
 
* domain_transfer_stop()

 Stop the transfer of the given domain name as first argument (used by the registrar having started the transfer).

* domain_transfer_query()

 Query the state of the ongoing transfer for the given domain name as first argument.

* domain_transfer_accept()

 Accept the transfer of the given domain name as first argument (used by the registrar currently sponsoring the domain name).

* domain_transfer_refuse()

 Refuse the transfer of the given domain name as first argument (used by the registrar currently sponsoring the domain name).
 
* domain_can()

 For the domain name given as first argument, and for the operation given as second
 (being either 'renew','update','delete' or 'tranfer'), returns 1 if we can
 do the requested operation at the current registry and current profile.
 We check the domain name status, and if who sponsors currently the domain name.

* domain_status_allows()

 Check if the current status of the domain name given as first argument allows
 for a specific operation.
 Most of the time you should use the following more specific methods.

* domain_status_allows_delete()

 Returns 1 if we can delete the domain name given as first argument at the current registry and current profile.
 Else, 0.
 
* domain_status_allows_update()

 Same for update.

* domain_status_allows_renew()

 Same for renew.
 
* domain_status_allows_transfer()

 Same for transfer.
 
* domain_current_status()

 Returns the status of the domain name given as first argument at the current registry and current profile.
 (status is a Net::DRI::Data::StatusList or subclass object)
 
* domain_is_mine()

 Returns 1 if we are the current sponsor of the domain name given as first argument 
 at the current registry and current profile.
 Else, 0.

* host_create()

 Create a new nameserver. The first and only argument should be a Net::DRI::Data::Host object.

* host_delete()

 Delete a nameserver. The first and only argument should be a Net::DRI::Data::Host object or a string.
 
* host_info()

 Retrieve information about a namserver. The first and only argument should be a Net::DRI::Data::Host object or a string.

 You may use get_info with the following keys to get more information:
 - self : a Net::DRI::Data::Host for the nameserver itself (name + IP addresses)
 - exDate, crDate, upDate, trDate, clID, crID, upID : see domain_info()

* host_check()
* host_exist()
* host_update()
* host_update_ip()
* host_update_ip_add()
* host_update_status_del()
* host_update_status_set()
* host_update_name_set()
* host_current_status()
* host_is_mine()

See corresponding domain_* methods.



Please note that another API is available, through the use of Net::DRI::RegistryObject
It is still under consideration, and will be explained later if kept.


