#!/usr/bin/perl

use Net::ParseWhois;
use Data::Dumper;

my $debug = "";
my $maxage = 2; # days

my $basepath = "/home/client/public_html/parsewhois";
my $cacheUrlBase = "/parsewhois/whois";
my $log = "$basepath/log.txt";

my $domain = 'PublicDomainRegistry.com';

if( $temp = $ENV{'QUERY_STRING'} ) {
  @pairs=split(/&/, $temp );
  foreach $item( @pairs ) {
     ($key,$content)=split ( /=/, $item, 2 );
     $content=~tr/+/ /;
     $content=~ s/%(..)/pack("c",hex($1))/ge;
     $fields{$key}=$content;
  }
  $domain = $fields{ 'domain' };
  $debug = $fields{ 'debug' } if $fields{ 'debug' };
}

if( $debug gt "" ) {
  use CGI::Carp qw( fatalsToBrowser );
  print qq(Content-type: text/plain\n\n);
} else {
  print qq(Content-type: text/xml\n\n);
  print qq(<?xml version="1.0" encoding="us-ascii"?>\n);
}

my $whois = Net::ParseWhois::Domain->new($domain);
unless ($whois->ok) {
#  warn "error: " . $whois->{'error'} . "\n" if $whois->{'error'};
#  die "No match for $domain\n";
}

printStartNode( "Domain_Name_Whois_Record", "" );
if( $whois->{'whois_referral'} gt "" ) {
  printNode( "  Found_In_Whois", "Yes" );

  if( ($whois->{'UNKNOWN_REGISTRAR'}) && $whois->{'UNKNOWN_REGISTRAR'} eq "1" ) {
    printNode( "  Whois_Parser_Exists", "No" );
    appendLog( "Missing parser for <a href='http://www.$domain/'>$domain</a> <a href='$cacheUrlBase/$domain.txt'>view cache</a> (<a href='/cgi-bin/$0?domain=$domain'>Retry $0 " . $whois->{'whois_referral'} . "</a>)" );
    saveWhois( $domain, $whois->{'RAW_WHOIS_TEXT'} );
  } else {
    printNode( "  Whois_Parser_Exists", "Yes" );
  }

  if( length($whois->domain) > 4 ) {
    printNode( "  Parsing_Was_Successful", "Yes" );
  } else {
    printNode( "  Parsing_Was_Successful", "No" );
    appendLog( "Parser failed for <a href='http://www.$domain/'>$domain</a> <a href='$cacheUrlBase/$domain.txt'>view cache</a> (<a href='/cgi-bin/$0?domain=$domain'>Retry $0 " . $whois->{'whois_referral'} . "</a>)" );
    saveWhois( $domain, $whois->{'RAW_WHOIS_TEXT'} );
  }

  printNode( "  Whois_Referral", $whois->{'whois_referral'} );
  printNode( "  Domain_Name", lc($whois->domain) );
  printNode( "  Date_Time_Created", $whois->record_created );
  printNode( "  Date_Time_Updated", $whois->record_updated );
  printNode( "  Date_Time_Expires", $whois->record_expires );
  printStartNode( "  Registrant", "" );
  printNode( "    Name", $whois->name );

  #my @addresses = split( "\n", $whois->address );
  #parseAddresses(\@addresses);

  printNode( "    Address", $whois->address );
  printNode( "    Country", $whois->country );

  printNode( "    Raw_Text", $whois->name . "\n" . $whois->address . "\n" . $whois->country . "\n" );
  printEndNode( "  Registrant" );
  if( my $c = $whois->contacts ) {
    for my $t (sort keys %$c) {
      $t =~ s|n/a|unknown|;
      printStartNode( "  $t", "" );
      parseAddresses( \@{$$c{$t}} );
      printStartNode( "    Raw_Text", "" );
      print qq(<![CDATA[);
      print map { "$_\n" } @{$$c{$t}};
      print qq(]]>);
      printEndNode( "    Raw_Text" );
      printEndNode( "  $t" );
    }
  }

  printStartNode( "  Raw_Text", "" );
  print qq(<![CDATA[\n);
  print $whois->{'RAW_WHOIS_TEXT'};
  print qq(\n]]>\n);
  printEndNode( "  Raw_Text" );

  if( $debug gt "" ) {
    printStartNode( "  Data_Dump", "" );
    print qq(<![CDATA[\n);
    print Dumper($whois);
    print qq(\n]]>\n);
    printEndNode( "  Data_Dump" );
  }
} else {
  printNode( "  Found_In_Whois", "No" );
  #my $dump = Dumper( $whois );
  #print qq(<!--$dump-->);
}

printEndNode( "Domain_Name_Whois_Record" );

exit;

#################################################

sub saveWhois {
  my $domain = shift;
  my $data = shift;

  my $file = "$basepath/whois/$domain.txt";

  if( !(-e $file) || ( -M( $file ) > $maxage ) ) {
    if( open( WHOIS, "> $file" ) ) {
      print WHOIS $data;
      close( WHOIS );
    }
  }

}

sub appendLog {
  my $message = shift;
  $tms = getTimestamp();
  appendFile("$tms $message\n", "$log");
}

sub appendFile {
  my $data = shift;
  my $file = shift;

  if( !(-e $file."shtml") ) {
    if( open( HTMLFILE, "> $basepath/index.shtml" ) ) {
      print HTMLFILE "<html><body><pre><!--#include virtual='/parsewhois/log.txt' --></pre></body></html>";
      close HTMLFILE;
    }
  }

  if( !(-e $file) ) {
    open( FILE, "> $file" );
  } else {
    open( FILE, ">> $file" );
  }
  print FILE $data;
  close( FILE );
}

sub getTimestamp {

   ( $sec, $min, $hour, $mday, $mon, $year ) = localtime(time);
   return sprintf( "%04d-%02d-%02d %02d:%02d:%02d",
      $year + 1900, $mon + 1, $mday, $hour, $min, $sec );

}

sub parseAddresses {

  my $array = shift;
  my @addresses = @$array;
  my $bAddress_Line_1 = 0;
  my $bCity = 0;
  my $bState = 0;
  my $bZip = 0;
  my $bCountry = 0;
  my $bTelephone_Number = 0;
  my $line_no = 0;
  my $bName = 0;
  my $bEmail = 0;


  foreach my $address ( @addresses ) {
    # print "$address//\n";
    # look for city state zip

    $line_no++;

    if( $bName == 0 && $bEmail == 0 && $address =~ /(.*?)\s+([A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,}))/ ) {
      printNode( "    Name", "$1" );
      printNode( "    Email_Address", $2 );
      $bName = 1;
      $bEmail = 1;
    } elsif( $bName == 0 && $bEmail == 0 && $address =~ /(\w+), (\w+)\s+([A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,}))/ ) {
      printNode( "    Name", "$1, $2" );
      printNode( "    Email_Address", $3 );
      $bName = 1;
      $bEmail = 1;
    } elsif( $bName == 0 && $bEmail == 0 && $address =~ /(\w+)\s(\w+)\s+([A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,}))/ ) {
      printNode( "    Name", "$1, $2" );
      printNode( "    Email_Address", $3 );
      $bName = 1;
      $bEmail = 1;
    } elsif( $bEmail == 0 && $address =~ /([A-Za-z0-9](([_\.\-]?[a-zA-Z0-9]+)*)@([A-Za-z0-9]+)(([\.\-]?[a-zA-Z0-9]+)*)\.([A-Za-z]{2,}))/ ) {
      printNode( "    Email_Address", $1 );
      $bEmail = 1;
    } elsif( $bCity == 0 && $bState == 0 && $bZip == 0 && $address =~ /(\w+), (\w+)\s+(\d+)/ ) {
      printNode( "    City", $1 );
      printNode( "    State_Province", $2 );
      printNode( "    Postal_Code", $3 );
      $bCity = 1;
      $bState =1;
      $bZip = 1;
    } elsif( $bName == 0 && $line_no < 3 && $address =~ /(\w+),\s(\w+)/ ) {
      printNode( "    Name", "$2, $1" );
      $bName = 1;
#    } elsif( $address =~ /(\w+)\s(\w+)/ ) {
#      printNode( "    Name", "$1, $2" );
    }
    if( $bAddress_Line_1 == 1 && $bZip == 0 && $address =~ /\b(\d\d\d\d\d)\b/ ) {
      printNode( "    Postal_Code", $1 );
      $bZip = 1;
    } elsif( $bZip == 0 && $address =~ /\b(\d\d\d\d\d\-\d\d\d\d)\b/ ) {
      printNode( "    Postal_Code", $1 );
      $bZip = 1;
    }
    if( $bTelephone_Number == 0 && ( $address =~ /(\(\d\d\d\)\s\d\d\d\-\d\d\d\d)/ ||
        $address =~ /(\d\d\d\-\d\d\d\-\d\d\d\d)/ ||
        $address =~ /(\d\d\d\d\d\d\d\d\d\d)/ ) ) {
      printNode( "    Telephone_Number", $1 );
      $bTelephone_Number = 1;
    }
    if( $address =~ /Fax:?-?\s+\+?1?\.?(.*)/ ) {
      my $fax = $1;
      $fax =~ s/^--\s+//;
      printNode( "    Fax_Telephone_Number", $fax );
    }
    if( $bCountry == 0 && ( $address =~ /(United States)/i || $address =~ /\b(US)\b/ ) ) {
      printNode( "    Country", $1 );
      $bCountry = 1;
    }
    if( $bAddress_Line_1 == 0 && ( $address =~ /(\d+\s.*?)$/ || $address =~ /(PO BOX\s\d+)/i ) ) {
      printNode( "    Address_Line_1", $1 );
      $bAddress_Line_1 = 1;
    }
  }


}

sub printStartNode {
  my $node = shift;

  my $space = "";
  if( $node =~ s/^(\s+)// ) {
    $space = $1;
  }

  if( $node =~ /ADMIN/i ) {
    $node = "Administrative_Contact";
  }
  if( $node =~ /BILLING/i ) {
    $node = "Billing_Contact";
  }
  if( $node =~ /TECH/i ) {
    $node = "Technical_Contact";
  }
  my $attr = shift;
  $node = $node . " " . $attr if $attr;
  print qq($space<$node>\n);
}

sub printEndNode {
  my $node = shift;

  my $space = "";
  if( $node =~ s/^(\s+)// ) {
    $space = $1;
  }

  if( $node =~ /ADMIN/i ) {
    $node = "Administrative_Contact";
  }
  if( $node =~ /BILLING/i ) {
    $node = "Billing_Contact";
  }
  if( $node =~ /TECH/i ) {
    $node = "Technical_Contact";
  }
  print qq($space</$node>\n);
}

sub printNode {
  my $node = shift;
  my $value = shift;
  $value =~ s|n/a||;
  my $space = "";
  if( $node =~ s/^(\s+)// ) {
    $space = $1;
  }

  print qq($space<$node><![CDATA[$value]]></$node>\n);
}
