diff options
author | Mark Wells <mark@freeside.biz> | 2012-11-02 14:28:31 -0700 |
---|---|---|
committer | Mark Wells <mark@freeside.biz> | 2012-11-02 14:28:31 -0700 |
commit | 7be09bed7f9acdf8a20362c49831dfb39fc4e7a4 (patch) | |
tree | 51ed1f3337fd567897a12553fe6a6ae2ced3ce7c /EZLocate.pm |
initial commit
Diffstat (limited to 'EZLocate.pm')
-rw-r--r-- | EZLocate.pm | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/EZLocate.pm b/EZLocate.pm new file mode 100644 index 0000000..3215dc3 --- /dev/null +++ b/EZLocate.pm @@ -0,0 +1,186 @@ +package Geo::EZLocate; + +use 5.006; +use strict; +use warnings; + +use Geo::EZLocate::Interfaces::Authentication::Authentication; +use Geo::EZLocate::Interfaces::Geocoding::Geocoding; + +=head1 NAME + +Geo::EZLocate - TomTom EZLocate geocoding service interface + +=head1 VERSION + +Version 0.01 + +=cut + +our $VERSION = '0.01'; + +our $timeout = 10; # in minutes + +=head1 SYNOPSIS + + use Geo::EZLocate; + + my $geo = Geo::EZLocate->new(); + my $result = $geo->login('myusername', 'mypassword'); + $ + ... + +=head1 METHODS + +=head2 login USERNAME PASSWORD + +Authenticates and caches a login token. Returns the result code, which +is zero on success and nonzero on failure. + +=cut + +# shorthand class names + +my $Interfaces = 'Geo::EZLocate::Interfaces'; +my $Auth = $Interfaces.'::Authentication::Authentication'; +my $EZClient = $Interfaces.'::EZClient::EZClient'; +my $Geocoding = $Interfaces.'::Geocoding::Geocoding'; + +sub new { + my $class = shift; + # mimic the official API + my $username = shift; + my $password = shift; + return bless { username => $username, password => $password, @_ }, + 'Geo::EZLocate'; +} + +sub login { + my $self = shift; + + if ( $self->{identity} and (time - $self->{authtime}) < $timeout ) { + return; # no need to reauth + } + + my ($username, $password) = @_; + if ( $username ) { + $self->{username} = $username; + $self->{password} = $password; + } + + # preprocess key + my $key = 0; + for (split(//, $self->{password})) { + $key = ($key << 4) + ord($_); + my $bits = $key & 0xf0000000; + $bits >>= 24; + $key = ($key ^ $bits); + } + $key = $key & 0x3fffffff; + + my $client = $self->{'auth'} ||= $Auth->new; + my $r_requestChallenge = $client->requestChallenge({ + userName => $self->{username}, + minutesValid => $timeout, + }); + my $eid = $r_requestChallenge->get_encryptedID; + + # XOR $eid with key, multiply it by the magic number, XOR it back + my $ans = $eid ^ $key; + $ans = ($ans * 39371) % 0x3fffffff; + $ans = $ans ^ $key; + + my $r_answerChallenge = $client->answerChallenge({ + originalChallenge => $eid, + encryptedResponse => $ans, + }); + + my $id = $r_answerChallenge->get_credential; + if ( $id ) { + $self->{identity} = $id; + $self->{authtime} = time; + } + return $r_answerChallenge->get_resultCode; +} + +=head2 findAddress ADDRESS, CITY, STATE, ZIP, [OPTION => VALUE] ... + +Validate the specified address. The only OPTION that matters currently +is 'country', which can be set to "CA" to search for addresses in Canada. + +=cut + +sub findAddress { + my $self = shift; + my %params; + # again, imitate the positional parameters in the official SDK + $params{Addr} = shift; + $params{City} = shift; + $params{State} = shift; + $params{ZIP} = shift; + my %opt = @_; + + my $client = $self->{geocoding} ||= $Geocoding->new; + $self->login(); + die "authentication failed" unless $self->{identity}; + + my $service = 'USA_Geo_004'; + if ( lc($opt{'country'} || '') eq 'ca' ) { + $service = 'CAN_Geo_001'; + } + my $input = { + nv => [ map { +{ name => $_, value => $params{$_} } } keys %params ] + }; + my $r_findAddress = $client->findAddress({ + 'service' => $service, + 'identity' => $self->{identity}, + 'input' => $input, + }); + + my $nvs = $r_findAddress->get_result->get_mAttributes->get_nv; + + my $match = {}; + foreach my $nv (@$nvs) { + $match->{$nv->get_name} = '' . $nv->get_value; #force stringification + } + + $match; +} + +=head1 AUTHOR + +Mark Wells, C<< <mark at freeside.biz> >> + +=head1 BUGS + +Much of the API is unsupported. The Geo::EZLocate::Interfaces::* +packages have autogenerated wrappers for all of the API methods, and +they work, but I haven't documented or tested most of them. + +This module shouldn't even be necessary, but the EZLocate SDK has a +restrictive license which makes it impractical for open-source +development. This is a shame, because their geocoding service is +very good. + +=head1 SUPPORT + +You can find documentation for this module with the perldoc command. + + perldoc Geo::EZLocate + +This library is not supported by TomTom. + +=head1 LICENSE AND COPYRIGHT + +Copyright 2012 Mark Wells. + +This program is free software; you can redistribute it and/or modify it +under the terms of either: the GNU General Public License as published +by the Free Software Foundation; or the Artistic License. + +See http://dev.perl.org/licenses/ for more information. + + +=cut + +1; # End of Geo::EZLocate |