Notify::XMPP 0.03
- - 最新版はこのへんにあるす。
変更点
- コネクション張るのを1回だけにした。(0.02までは、entryごとに接続/切断を繰り返してたのでした)
- Google Talkに接続できるようにした。ただし、XML::Streamをちと変更する必要あり(後述)
- pod書いた。
Google Talkのアカウントで接続するときはXML::Streamをちと変更する必要があります。
その理由はこうです。
Google Talkの認証はSASLのPLAINで行われます。(starttlsが必須なためか、CRAM-MD5とかは対応してない)
んで、PLAINの認証は、
[authorize-id] NUL authenticate-id NUL password
をbase64したものをサーバに送ります。
authorize-idは、「username@servername」の形式で、Google Talkの場合は「hirose31@gmail.com」になってないと認証が失敗します。
でですね、Google Talkに繋げる場合は、サーバ名はtalk.google.comで、gmail.comじゃないんです。なので、XML::Streamが作るauthorize-idは「hirose31@talk.google.com」となり、(ユーザ名とパスワードが正しくても)認証に失敗しちゃうんです。
ほんでどうしたかというと、Net::XMPP::COnnection::Connectでcomponentname => 'gmail.com'を指定すると、それがXML::Streamでは$self->{SIDS}->{$sid}->{to}で取り出せるので、{to}がある場合はそれをauthorize-idのservernameんところに使うようにしたわけです。
ちなみに仕様上authorize-idは省略可能で、省略した場合でもGoogle Talkの認証は通るんですが、XML::Streamでそれを省略させるオプションがないんす。
ただですね、これは繋げるアカウントのお話で、jabber.orgとGoogle Talkは相互接続しているので、jabber.orgのアカウントで接続してもGoogle Talkな人にメッセージは送れます。なので、XML::Streamいじらなくても、Google TalkにNotifyすることはできます。
--- Stream.pm.orig 2004-08-25 23:23:32.000000000 +0900 +++ Stream.pm 2006-08-17 19:00:07.000000000 +0900 @@ -2113,7 +2113,7 @@ my $sasl = new Authen::SASL(mechanism=>join(" ",@{$mechanisms}), callback=>{ - authname => $username."@".$self->{SIDS}->{$sid}->{hostname}, + authname => $username."@".($self->{SIDS}->{$sid}->{to} or $self->{SIDS}->{$sid}->{hostname}), user => $username, pass => $password
package Plagger::Plugin::Notify::XMPP; our $VERSION = '0.03'; use strict; use warnings; use base qw( Plagger::Plugin ); use Encode; use Net::XMPP; sub register { my ($self, $context) = @_; $context->register_hook( $self, 'plugin.init' => \&initialize, 'publish.entry' => \¬ify, 'publish.finalize' => \&finalize, ); } sub initialize { my ($self, $context, $args) = @_; $context->log(debug => ">>initialize"); my $connectattempts = 3; my $connectsleep = 1; $self->{connected} = 0; $self->{client} = Net::XMPP::Client->new(debuglevel=>0); my $jid = $self->conf->{jid} || do { $context->log(error => "missing: jid"); return; }; unless (index($jid, '@') >= 1) { $context->log(error => "missing: jid"); return; } my ($username, $componentname) = split /@/, $jid; my $password = $self->conf->{password} || do { $context->log(error => "missing: password"); return; }; my $hostname = $self->conf->{server_host} || $componentname; my $port = $self->conf->{server_port} || '5222'; my $tls = $self->conf->{tls} || 0; unless ($self->conf->{to}) { $context->log(warn => "missing: to"); return; } $context->log(debug => "hostname=$hostname port=$port tls=$tls componentname=$componentname"); my ($status, $error); while (--$connectattempts >= 0) { $status = $self->{client}->Connect( hostname => $hostname, port => $port, tls => $tls, componentname => $componentname, ); last if defined $status; $context->log(warn => "retry[$connectattempts]"); sleep $connectsleep; } unless (defined $status) { $context->log(error => "connection failure"); return; } ($status,$error) = $self->{client}->AuthSend( username => $username, password => $password, resource => 'Plagger', ); unless ($status and $status eq 'ok') { $context->log(error => "authentication failure"); return; } $self->{connected} = 1; } sub notify { my ($self, $context, $args) = @_; return unless $self->{connected}; $context->log(debug => ">>notify"); my $body = $self->templatize('xmpp_notify.tt', $args); utf8::decode($body) if utf8::is_utf8($body); foreach my $a_to (@{$self->conf->{to}}) { $context->log(info => "Notifying <" . $args->{entry}->title . "> to $a_to"); $self->{client}->MessageSend( to => $a_to, body => $body, ); } } sub finalize { my ($self, $context, $args) = @_; return unless $self->{connected}; $context->log(debug => ">>finalize"); $self->{client}->Disconnect(); } 1; __END__ =head1 NAME Plagger::Plugin::Notify::XMPP - Notify feed updates to XMPP client =head1 SYNOPSIS jabber.org - module: Notify::XMPP config: jid: foo@jabber.org password: plahplahplah to: - bar@jabber.org - baz@gmail.com - qux@jabber.jp Google Talk - module: Notify::XMPP config: jid: foo@gmail.com password: plahplahplah server_host: talk.google.com tls: 1 to: - bar@jabber.org - baz@gmail.com - qux@jabber.jp =head1 DESCRIPTION This plugin allows you to notify feed updates to XMPP clients (jabber, Google Talk) using Net::XMPP. =head1 AUTHOR HIROSE Masaaki (hirose31) =head1 SEE ALSO L<Plagger>, L<Net::XMPP> =cut # for Emacsen # Local Variables: # mode: cperl # cperl-indent-level: 4 # cperl-indent-parens-as-block: t # indent-tabs-mode: nil # coding: euc-jp # End: # vi: set ts=4 sw=4 sts=0 :
テンプレートは0.02んときid:hirose31:20060815:1155646327と同じのでOK。
POE::Component::Jabberとか使えば、Notify::IRCみたいに常駐できるかも。ただ、IMなんで一発送ってハイさようならでもいい気がする(プロセス常駐させなくていいし)んだけどどうすかねぇ。