package Xchat::XPI::Net;

use strict;
use warnings;

use IO::Socket::INET;

use Net::DNS;

use Xchat qw<:all>;

our $VERSION = '0.03';

my $res;

BEGIN {
 $res = Net::DNS::Resolver->new;

 my $timeout = 5;
 $res->tcp_timeout($timeout);
 $res->udp_timeout($timeout);

 my $nameservers = '';
 $res->nameservers( [ split ' ', $nameservers ] ) if $nameservers;
}

sub resolve {
 my ($host, $callback, $args) = @_;
 return unless $host and $callback;

 my $sock = $res->bgsend($host);
 return unless $sock;
 $sock->autoflush(1);

 return Xchat::hook_fd($sock, \&_dns_recv, {
  flags => FD_READ,
  data  => [ $callback, $args ],
 });
}

sub _dns_recv {
 my $fh = $_[0];
 my ($callback, $args) = @{$_[2]};

 my $p = $res->bgread($fh);
 $fh->shutdown(2);
 close $fh;
 undef $fh;

 $callback->($p, $args);

 return REMOVE;
}

my %whois_servers = (
 domain => {
  default => 'whois.internic.net',
     arpa => 'whois.arin.net',
#      mil => 'whois.nic.mil',
 },
 ipv4 => { default => 'whois.ripe.net'  },
 ipv6 => { default => 'whois.6bone.net' },
);

sub whois {
 my ($host, $callback, $args) = @_;
 return unless $host and $callback;

 my $server;
 if ($host =~ /^\s*\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(\/\d{1,2})?$/) {
  $server = $whois_servers{ipv4}{default};
 } elsif ($host =~ /^\s*[\d:]*(\/\d{1,2})?\s*$/) {
  $server = $whois_servers{ipv6}{default};
 } elsif ($host =~ /([^\.]+)\.+([a-z]+)\.*$/) {
  $host   = $1 . '.' . $2;
  $server = $whois_servers{domain}{$2};
  $server = $whois_servers{domain}{default} unless $server;
 }
 return unless $server;

 my $hook;

# resolve($server, \&_whois_send, [ \$hook, $host, $callback, $args ] );
# return \$hook;
#}
#
#sub _whois_send {
# my $p = $_[0];
# my @a = grep { $_->type eq 'A' && $_->address } $p->answer;
# return unless @a;
# my ($hookref, $host, $callback, $args) = @{$_[1]};
# my $server = $a[rand(@a)]->address;

 my $sock = IO::Socket::INET->new(
  PeerAddr => $server,
  PeerPort => 43,
  Proto    => 'tcp',
 );
 return unless $sock;
 $sock->autoflush(1);

 print $sock "$host\x0D\x0A";
 $sock->shutdown(1); # stop writing

 return Xchat::hook_fd($sock, \&_whois_recv, {
  flags => FD_READ,
  data  => [ $callback, $args ],
 });
}

sub _whois_recv {
 my $fh = $_[0];
 my ($callback, $args) = @{$_[2]};

 my $raw = do { local $/; <$fh>; };
 $fh->shutdown(2);
 close $fh;
 undef $fh;

 $callback->($raw, $args);

 return REMOVE;
}

use base qw<Exporter>;

our @EXPORT         = ();
our %EXPORT_TAGS    = ('funcs' => [ qw<resolve whois> ]);
our @EXPORT_OK      = map { @$_ } values %EXPORT_TAGS;
$EXPORT_TAGS{'all'} = [ @EXPORT_OK ];

1;
