Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

rjbs (4671)

rjbs
  (email not shown publicly)
http://rjbs.manxome.org/
AOL IM: RicardoJBSignes (Add Buddy, Send Message)
Yahoo! ID: RicardoSignes (Add User, Send Message)

I'm a Perl coder living in Bethlehem, PA and working Philadelphia. I'm a philosopher and theologan by training, but I was shocked to learn upon my graduation that these skills don't have many associated careers. Now I write code.

Journal of rjbs (4671)

Monday November 19, 2007
10:04 PM

aol service assistant, slightly better than nothing

[ #34935 ]

For a long time, my parents have been held hostage by AOL. AOL, for ages, made it nearly impossible to use any tool other than their mega-integrated awful front end to The Internet. Even once they set up IMAP, you were stuck with their Favorites and Address Book. This was a big deal for my dad, who has a gigantic contact list. I've been heckling him to use Apple's Address Book for ages, but he couldn't get out.

Recently, AOL published the AOL Service Assistant, which lets you set up your Mac to work with your AOL settings. Most of this is trivial, but it exports your AOL Favorites (read: bookmarks) and your Address Book. This was great news, and I put it to use when setting up a new Mac for my mom a few weeks ago.

The big snag was that it exports contacts in a completely asinine way. As far as I can tell, AOL's contact list has no concept of "person" or "group." It just associates a name with a list of one or more email addresses. When you export your contact list to Address Book, each entry becomes a group, and each address in it becomes a person. That means that if you had "grandma@example.com" as the address for your "Nanny Smith" entry, you will now have a group called "Nanny Smith" with one person. That person will have no name, just an email address.

This is totally insane.

Mac::Glue made fixing this a whole lot less hateful than it might have otherwise been. Here's the script I used:

#!/usr/bin/perl
use strict;
use warnings;

use Mac::Glue ':glue';

my $addr = Mac::Glue->new('Address Book');

my @groups = $addr->prop('groups')->get;

my %emails_for;
my %groups_for;

for my $group (@groups) {
  my $name = $group->prop('name')->get;
  my @people = $group->prop('people')->get;

  if (@people == 1) {
    # a one-address group is probably a person
    my $person = $people[0];
    my ($email) = map { $_->prop('value')->get } $person->prop('email')->get;
    push @{ $emails_for{ $name } ||= [] }, $email;
  } else {
    # ...but a multipe-address group is probably a group for real real
    my @emails =
      map { $_->prop('value')->get }
      map { $_->prop('email')->get }
      @people;

    for my $email (@emails) {
      push @{ $groups_for{ $email } ||= [] }, $name;
    }
  }
}

my %local_part;
for my $email (keys %groups_for) {
  print "$email\n";
  my ($local_part) = split /\@/, $email;

  unless (grep { $_ eq $email } map { @$_ } values %emails_for) {
    my $i = ++ $local_part{ $local_part };
    $emails_for{"$local_part $i"} = [ $email ];
  }
}

# Okay, we've learned all we can, let's obliterate all the bogus cards.
$_->delete for $addr->prop('people')->get;

for my $name (keys %emails_for) {
  my @emails = @{ $emails_for{ $name } };

  my ($first, $last);
  ($first, $last) = split / /, $name, 2;

  # Set up the address book card
  my $person = $addr->make(
    new => 'person',
    with_properties => {
      'first name' => $first,
      'last name'  => $last,
    },
  );

  # Add the person's email addresses
  for my $email (@emails) {
    $addr->make(
      new => 'email',
      at  => location(end => $person->prop('emails')),
      with_properties => {
        label => 'Home',
        value => $email,
      }
    );
  }

  # Put each individual back into the groups in which they originally appeared.
  my %group;
  $seen{ $_ }++ for map { @{ $groups_for{ $_ } || [] } } @emails;

  for (keys %group) {
    next unless my $group = $addr->obj(group => whose(name => equals => $_));

    $person->add(to => $group);
  }
}

Basically, it converts any group with only one address into a person. For any group that had more than one address, if it can find a "person" for that address (in other words, that address appeared in another group with no other addresses) then the group remains a group, now with that person (and probably others) in it. It's not perfect, but it got my mom's 200+ member contact list into a state where hand-correcting it was not a huge problem.

I'd like to think that AOL will fix this in a future release, but I doubt it. I think that it's not just awful programming, it's a mismatch between the data structures of AOL's and Apple's address books.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Not only is it a data mismatch, I don't think there are any programmers left to fix the problem if even someone wanted to. This last layoff caught a lot of people in product development. Tools like this will go unmaintained while the remaining programmers try and keep the core properties and code online.
  • Granted I only worked on the edge of the address book (integrating the ab into a wap email client) but I find it had to imagine that is the best they can do. 7 years ago they had a http protocol that would allow you to export the ab using a couple of dozen lines of perl.