DOWNLOAD the AddressBookExtreme.air application
In order to read the Address Book into Apollo on the Mac, I read the files in the directory:
~/Library/Caches/com.apple.AddressBook/MetaData
Each file in here is an XML document that represents either a group of contacts or an individual contact.
I build all the addresses into an XML string and tie each address element to the unique ID from the address book and then I pass the XML string to an application server.
I then employ the Weather Channel SOAP API to find the real-time weather observations for each unique location in my address book.
When I click on a phone number, it calls up an AppleScript that dials the phone number in Skype. In order for this to work, Skype must already be open. I think this is due to a bug in the Skype API on Mac OS X.
My AppleScript to launch Skype is simply:
tell application "Skype"
send command "CALL <phone-number>" script name "AddressBookFun"
end tell
Because you can't launch AppleScript from ActionScript 3 in Flex now, I had to resort to other methods. I run Apache on my Mac and I call up a perl script on localhost which executes the AppleScript for me.
Below is a sample of the Perl code format to accomplish this:
#!/usr/local/bin/perl
use strict;
use Mac::AppleScript qw(RunAppleScript);
my $application = "tell application \"Skype\"
send command \"CALL <phone-number>\" script name \"AddressBookFun\"
end tell";
RunAppleScript(qq($appleScript));
Calling up iChat from AppleScript looks like this:
tell application "iChat"
send "<message>"
to account id "AIM:<IM Handle>"
end tell
The AppleScript for this looks like:
set theAccount to "Name of your mail account"
set theSubject to "The subject of the mail"
set theAddress to "<to-address>"
set bccAddress to "<bcc-address>"
tell application "Mail"
activate
set newMessage to make new outgoing message
tell newMessage
make new to recipient at end of to recipients with properties {address:theAddress}
make new bcc recipient at end of bcc recipients with properties {address:bccAddress}
set visible to true
end tell
end tell
The AppleScript for this looks like:
tell application "Address Book" to set theID to id of person "<first-name last-name>"
open location "addressbook://" & theID
To call up a search from Blogger, I set the following URL to an HTMLComponent's location property:
myHTMLComponent.location = "http://search.blogger.com/?q="+thisSearchString+"&hl=en&ie=UTF-8&ui=blg&filter=1&safe=active&sa=N&start=0";
To call up a search from Google, I set the following URL to an HTMLComponent's location property:
myHTMLComponent.location = "http://www.google.com/search?hl=en&q="+thisSearchString+"&btnG=Google+Search";
To call up a search from Google Maps, I set the following URL to an HTMLComponent's location property:
var fa:String = street+","+city+","+state+" "+country
myHTMLComponent.location = "http://maps.google.com/maps?f=q&hl=en&q="+fa+"&ie=UTF8&z=15&om=1&iwloc=addr";
Here I send the name of the cities both where the primary card holder in the Address Book is and the contact's city to the Yahoo airport lookup tool.
This returns the airport codes, and then I pass that to a flight search tool and load that to the HTML Component.
Mapping all the contacts at one time was probably the most challenging part of this as I wanted to do all this on the client-side but had to resort to some server-side processing.
Since there is no way to pass data at present from an ActionScript function to Javascript contained within the HTMLComponent, what I am doing is wrapping all the addresses from my Address Book into an XML document and passing that to the server.
I am writing that out to the server as a text file in /tmp with a unique ID number. I then return that unique ID number to Apollo. Then, I redirect the HTML component to a script server-side and pass the unique ID number of the text file.
Then I read that text file, parse its XML, and here is where the fun begins.
I then use the Geo::Coder::Yahoo perl module from CPAN to translate all addresses in my address book into latitudes and longitudes. Below is a sample of what that code looks like:
use Geo::Coder::Yahoo;
my $address = "$street, $city, $state $zip, $country";
my $geoCoder = Geo::Coder::Yahoo->new(appid=>$appId);
my $location;
eval { $location = $geoCoder->geocode(location => $address); };
if($location) {
my @arr = @{$location};
my %thisHash = %{$arr[0]};
my $lat = $thisHash{latitude};
my $lon = $thisHash{longitude};
my $address = "$street
$city, $state $zip
$country";
}
Once I have read all of my latitudes and longitudes into an array of hashes, I then deploy the Google Maps API.
Here is the simple Mod_Perl and Javascript code I am using for the Google Maps API:
my @contacts = @{$_[0]};
my $mapKey = "ABQIAAAAldee76B96MQErFK6djnPvxSwlxfzWfAKt7R5-U7h2cZGvbCUrRS91tQBNedb7_I2TV9-uyW1fPO1Kg";
my $htmlObject = "<html>
<head>
<title>AddressBook</title>
<script src=\"http://maps.google.com/maps?file=api&v=2&key=$mapKey\" type=\"text/javascript\"></script>
<script type=\"text/javascript\">
//<![CDATA[
function load() {
if (GBrowserIsCompatible()) {
icon = new GIcon();
icon.image = \"http://enrich.ucompass.com/Components/MyVacation/mapIcon.gif\";
icon.iconSize = new GSize(16, 16);
icon.iconAnchor = new GPoint(8, 8);
icon.infoWindowAnchor = new GPoint(5, 1);
map = new GMap2(document.getElementById(\"mapUse\"));
map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.setCenter(new GLatLng(42.29356419217007, -51.328125), 2);\n";
foreach my $this (@contacts) {
my %thisHash = %{$this};
my $lat = $thisHash{lat};
my $lon = $thisHash{lon};
my $name = $thisHash{name};
my $address = $thisHash{address};
$htmlObject.="addMapPoint($lat,$lon,'$name','$address');\n";
}
$htmlObject.="
}
}
function addMapPoint(lat,lon,name,address) {
lat = Number(lat);
lon = Number(lon);
var myPoint = new GLatLng(lat,lon);
var pointMarker = new GMarker(myPoint, icon);
map.addOverlay(pointMarker);
GEvent.addListener(pointMarker, \"click\", function() {
addressClick(pointMarker,name,address);
});
return pointMarker;
}
function addressClick(pointMarker,name,address) {
myInfo = pointMarker.openInfoWindowHtml('<div style=\"font-family: Arial, Helvetica;font-size: 10px;\"><span style=\"font-size: 12px; font-style: bold;\"><u>'+name+'</u></span><br/>'+address+'</div>');
}
//]]>
</script>
</head>
<body onload=\"load()\" onunload=\"GUnload()\">
<div id=\"map\"><div id=\"mapUse\" style=\"width: 646px; height: 344px;\"></div>
</body>
</html>";