Growl用WebAPI提供サーバ

前のエントリで書いたGrowl用Web APIを単独で動くサーバにし、アイコンにも対応しました。
バックグラウンドで動かしておいて、

http://localhost:23080/title=たいとる&msg=ほげほげ&icon=http://url/〜.jpg

というURLにアクセスすると、Growlでメッセージが通知されます。デフォルトではlocalhostのみからアクセス可能です。しかもアイコン付き。一応MD5ハッシュファイル名でキャッシュします*1。前のエントリに書いたtwicli GrowlプラグインもURLを書き換えればそのまま使えます。
ソースは以下から。

#!/usr/bin/perl
use strict;
use HTTP::Daemon;
use HTTP::Status;
use Digest::MD5 'md5_base64';
use Mac::Growl ':all';
use LWP::Simple;
use Cwd 'abs_path';

my $icon_cache_dir = $ENV{'HOME'}.'/tmp/icons';
$icon_cache_dir = abs_path($icon_cache_dir);

$SIG{PIPE} = 'IGNORE';
my $d = HTTP::Daemon->new(LocalAddr => '127.0.0.1', LocalPort => 23080) or die $!;
while (my $c = $d->accept) {
    while (my $r = $c->get_request) {
        if ($r->method eq 'GET') {
            my $name = "Message via Web API";
            my %p = ();
            my $q = $r->url->query;
            $c->force_last_request();
            foreach (split /&/, $q) {
                my ($key, $val) = split /=/;
                $val =~ tr/+/ /;
                $val =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
                $p{$key} = $val;
            }
            my $icon = get_icon_path($p{'icon'});
            RegisterNotifications("Growl Web API", [$name], [$name]);
            PostNotification("Growl Web API", $name, $p{'title'}, $p{'msg'}, 0, 0, $icon);

            my $h = HTTP::Headers->new('Content-Type' => 'text/javascript');
            my $res = HTTP::Response->new(200, 'OK', $h, '"OK"'.$/);
            $c->send_response($res);
        } else {
            $c->send_error(RC_FORBIDDEN)
        }
    }
    $c->close;
    undef($c);
}

sub get_icon_path {
    my $icon = $_[0];
    if ($icon) {
        my $hash = md5_base64($icon);
        $hash =~ tr!+/!_-!;
        my $ext = $icon;
        $ext =~ s/^.*\.//;
        my $ret = "$icon_cache_dir/$hash.$ext";
        unless (-f $ret) {
            my $result = getstore $icon, $ret;
            print "Download $icon as $ret : $result\n";
            return '' if (is_error($result));
        }
        return $ret;
    }
    return '';
}

*1:ハッシュ衝突なんてしないよねJK(ぉ