summaryrefslogtreecommitdiff
path: root/EZLocate.pm
diff options
context:
space:
mode:
Diffstat (limited to 'EZLocate.pm')
-rw-r--r--EZLocate.pm186
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