GMailのアドレス帳(Contacts)にPerlでアクセスする
とあるCGIを作っている最中に、メールアドレスをGMailのアドレス帳(Contactsというらしい)に同期したくなった。何かいい方法はないかな、と思い、例によってCPANをあさってみた。
すると、WWW::Google::ContactsというCPANモジュールがあった。
http://search.cpan.org/~fayland/WWW-Google-Contacts-0.05/lib/WWW/Google/Contacts.pm
今回少しいじったので、使い方をメモっておく。
まずは、アドレス帳の中身を読む方法。なお、GMail側から取得できるデータ構造の詳細は割愛します。知りたい場合は、サンプルコードのData::Dumperの使い方を参考に中身をダンプしてみてください。
#!/usr/bin/perl use strict; use warnings; use utf8; use WWW::Google::Contacts; use Data::Dumper; # インスタンス作成 my $gcontacts = WWW::Google::Contacts->new(); # 何をするにもまずはログインしなくては。 $gcontacts->login('ログイン名','パスワード') or die $@; # アドレス帳のリストを取得 my @contacts = $gcontacts->get_contacts(); # アドレス帳で名前が載っている人だけメールアドレスを表示する foreach my $contact (@contacts){ # アドレス帳に載っている人の名前を取得 my $name = $$contact{'name'}->{'gd:fullName'}; # 名前が明示的につけられているか? if( defined($name)){ print "Name : " , $name,"\n"; } else{ print "Name : No Name\n"; next; } # 該当する名前に紐づいているメールアドレスを全て表示 my @mailaddresses = map {$_->{address}} @{$contact->{email}}; foreach my $mailaddr (@mailaddresses) { print $mailaddr,"\n"; } } # グループを取得 my @groups = $gcontacts->get_groups(); # グループに関するデータ構造とデータをダンプ。 foreach my $group (@groups){ my $dump = Dumper($group); $dump =~ s/\\x{([0-9a-z]+)}/chr(hex($1))/ge; print $dump; }
ついで、アドレス帳に新たなエントリを載せる方法。
#!/usr/bin/perl use strict; use warnings; use utf8; use WWW::Google::Contacts; use Encode; my $gcontacts = WWW::Google::Contacts->new(); # 何はともあれ、まずログイン $gcontacts->login('ログイン名','パスワード') or die $@; # 注意。文字コードはUTF-8にした上でUTF-8フラグを落とすこと。 # 具体的には設定したい文字に対して以下のようにEncode::encode() # を呼ぶ。さもないと、はまります。 # 詳細は以下「ハマった箇所」に記載。 my $notes = ''; # displaynameもfullnameも区別していないみたいだ....? # もし違うのであれば、ご一報を。 my $displayname = Encode::encode('utf8','サンプルさん'); my $fullname = Encode::encode('utf8','サンプルさん'); # アドレス帳に追加!なお、givenname,familynameは日本ではあまり意味をもたない。 my $ret = $gcontacts->create_contact( { givenName => $fullname, familyName => $fullname, fullName => $fullname, Notes => $notes, primaryMail => 'メールアドレス', displayName => $displayname, }); # 非ゼロの戻り値で追加成功。 if($ret){ print "created!\n"; } else{ print "not created\n"; }
あとは、ハマった箇所について。
コメントにもあるように、encode()を呼んでUTF8フラグを落としてバイトストリームとして扱う必要がある。なぜか。
実はこれをしないと、create_contact()呼び出しにより例外が発生する。
例外発生時のメッセージ$@を表示すると、
HTTP::Message content must be bytes at /usr/share/perl5/HTTP/Request/Common.pm line 91
となっている。ソースコードを早速あさると、該当個所は
$req->content($content);
で$reqは
my $req = HTTP::Request->new(POST => $url);
ならば、ということでHTTP::Requestのcontent()メソッドの仕様をCPANのドキュメント(http://search.cpan.org/~gaas/libwww-perl-5.836/lib/HTTP/Request.pm)で調べると
Note that the content should be a string of bytes. Strings in perl can contain characters outside the range of a byte. The Encode module can be used to turn such strings into a string of bytes
となっており、コンテンツがバイトストリームでなければいけないとわかる。
よって、Encode::encocde()が必要なのである。
なお、update系のI/Fもありますが、それはまたの機会にさせてください。