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 => $passwordpackage 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なんで一発送ってハイさようならでもいい気がする(プロセス常駐させなくていいし)んだけどどうすかねぇ。