#!/usr/bin/perl-w
#
# geospider.pl
#
# Pajk lokalizujcy -- przez API Google wysya do Google zapytanie,
# pobierana nazwy serwerw dla zwrconych adresw URL, odszukuje adresy
# tych serwerw i dopasowuje te adresy do zapisw z bazy danych 
# IP-to-Country udostpnia je przez Directi:
# ip-to-country.directi.com. Wicej danych o tym oprogramowaniu
# pod adresem http://www.artymiak.com/software lub jacek@artymiak.com
# 
# Kod ten jest oprogramowaniem darmowym; mona go rozpowszechnia i/lub
# modyfikowa na takich zasadach, jak samego Perla.
#

use strict; 
use Getopt::Std;
use Net::Google;
use constant GOOGLEKEY => 'tutaj Twj klucz API Google';
use Socket;

my $help = <<"EOH";
----------------------------------------------------------------------------
Pajk analizujcy dane pod ktem pooenia geograficznego
----------------------------------------------------------------------------
Options:

  -h    pokazuje t pomoc
  -q    zapytanie w utf8, np. 'Spidering Hacks'
  -l    kody krajw, np. 'en fr jp'
  -d    domeny, np. '.com'
  -s    ktry wynik ma by pokazywany jako pierwszy (liczenie zaczyna si od 0)
  -n    ile wynikw naley zwrci, np. 700
----------------------------------------------------------------------------
EOH

# definiujemy argumenty, na danie pokazujemy pomoc; pomoc 
# pokazujemy te przy braku zapytania.
my %args; getopts("hq:l:d:s:n:", \%args);
die $help if exists $args{h};
die $help unless $args{'q'};

# utworzenie obiektu Google.
my $google = Net::Google->new(key=>GOOGLEKEY);
my $search = $google->search(  );

# jzyk; domylnie angielski.
$search->lr(qw($args{l}) || "en");

# od ktrego wyniku szukania zacz; domylnie od 0.
$search->starts_at($args{'s'} || 0);

# ile wynikw zwrci; domylnie 10.
$search->starts_at($args{'n'} || 10);

# kodowanie wejciowe i wyjciowe.
$search->ie(qw(utf8)); $search->oe(qw(utf8));

my $querystr; # ostateczna posta acucha z opisem szukania.
if ($args{d}) { $querystr = "$args{q} .site:$args{d}"; }
else { $querystr = $args{'q'} } # szukanie konkretnej domeny.

# adujemy nasz list porwnawcz z
# http://ip-to-country.directi.com/
my $file = "ip-to-country.csv";
print STDERR "Prba otwarcia $file... \n";
open (FILE, "<$file") or die "[error] Bd otwarcia $file: $!\n";

# teraz wszystko adujemy do pamici.
print STDERR "Otwarto baz danych, adowanie... \n";
my (%ip_from, %ip_to, %code2, %code3, %country);
my $counter=0; while (<FILE>) {
    chomp; my $line = $_; $line =~ s/"//g; # odrzucenie cudzysoww.
    my ($ip_from, $ip_to, $code2, $code3, $country) = split(/,/, $line);

    # usunicie kocowych zer.
    $ip_from =~ s/^0{0,10}//g; 
    $ip_to =~ s/^0{0,10}//g;

    # i przypisanie naszych wartoci staych.
    $ip_from{$counter} = $ip_from;
    $ip_to{$counter}   = $ip_to;
    $code2{$counter}   = $code2;
    $code3{$counter}   = $code3;
    $country{$counter} = $country;
    $counter++; # do nastpnego wiersza.
}

$search->query(qq($querystr));
print STDERR "Zapytanie do Google $querystr... \n";
print STDERR "Przetwarzanie wynikw z Google... \n";

# dla kadego wyniku z Google pokamy
# znalezione dane o pooeniu geograficznym.
foreach my $result (@{$search->response(  )}) {
    print "-" x 80 . "\n";
    print " Czas szukania: " . $result->searchTime(  ) . "s\n";
    print "     Zapytanie: $querystr\n";
    print "        Jzyki: " . ( $args{l} || "en" ) . "\n";
    print "        Domena: " . ( $args{d} || "" ) . "\n";
    print "    Zaczto od: " . ( $args{'s'} || 0 ) . "\n";
    print "      Zwrcono: " . ( $args{n} || 10 ) . "\n";
    print "-" x 80 . "\n";

    map {
        print "url: " . $_->URL(  ) . "\n";
        my @addresses = get_host($_->URL(  ));
        if (scalar @addresses != 0) {
            match_ip(get_host($_->URL(  )));
        } else {
            print "adres: nieznany\n";
            print "kraj: nieznany\n";
            print "code3: nieznany\n";
            print "code2: nieznany\n";
        } print "-" x 50 . "\n";
    } @{$result->resultElements(  )};
}

# pobranie adresw IP dla pasujcych serwerw.
sub get_host {
    my ($url) = @_;

    # obcicie URL do samej nazwy serwera.
    my $name = substr($url, 7); $name =~ m/\//g;
    $name = substr($name, 0, pos($name) - 1);
    print "serwer: $name\n";

    # i pobranie odpowiednich IP.
    my @addresses = gethostbyname($name);
    if (scalar @addresses != 0) {
        @addresses = map { inet_ntoa($_) } @addresses[4 .. $#addresses];
    } else { return undef; }
    return "@addresses";
}

# sprawdzenie IP w pamici, w licie Directi.
sub match_ip {
    my (@addresses) = split(/ /, "@_");
    foreach my $address (@addresses) {
        print "adres: $address\n";
        my @classes = split(/\./, $address);
        my $p; foreach my $class (@classes) {
            $p .= pack("C", int($class));
        } $p  = unpack("N", $p);
        my $counter = 0;
        foreach (keys %ip_to) {
            if ($p <= int($ip_to{$counter})) {
                print "kraj: " . $country{$counter} . "\n";
                print "code3: "   . $code3{$counter}   . "\n";
                print "code2: "   . $code2{$counter}   . "\n";
                last;
            } else { ++$counter; }
        } 
    }
}

