use strict;
use v5.10;
+has app => ( is => 'ro' );
has controller => ( is => 'ro' );
-has jid => ( is => 'ro' );
-has password => ( is => 'rw' );
has xmpp => ( is => 'ro' );
+has jid => ( is => 'ro' );
+has password => ( is => 'ro' );
+has active => ( is => 'ro' );
sub attach {
my ($self, %params) = @_;
- if ($self->xmpp && $self->xmpp->is_connected) {
- # If we're reattaching, check that the new password matches the original
- if ($params{password} ne $self->password) {
- return;
- }
- say "Attaching to existing XMPP connection for ", $self->jid;
- } else {
- # Otherwise, attempt a new connection with the given password
- say "Creating new XMPP connection for ", $self->jid;
- $self->{password} = $params{password};
- $self->{xmpp} = AnyEvent::XMPP::IM::Connection->new(
- jid => $self->jid,
- password => $self->password,
- );
- $self->xmpp->connect;
- }
-
if ($self->controller) {
$self->controller->finish(1000 => "Reconnected");
}
$self->{controller} = $params{controller};
- $self->set_up_events;
+ $self->attach_controller_events;
}
-sub set_up_events {
+sub attach_controller_events {
my ($self) = @_;
$self->controller->tx->on(json => sub {
my ($tx, $msg) = @_;
given ($msg->{type}) {
- when ('message') {
- $self->xmpp->send_message($msg->to, 'chat', undef, {
- body => $msg->{body}
- });
+ when ('login') {
+ my $password = $msg->{password};
+
+ if (!defined $password) {
+ $self->controller->finish(1015 => "Login must have password\n");
+ delete $self->{controller};
+ return;
+ }
+
+ if ($self->xmpp && $self->xmpp->is_connected) {
+ # If we're reattaching, check that the new password matches the original
+ if ($password ne $self->password) {
+ $self->ws_send('logged-out', reason => 'unauthorized');
+ return;
+ }
+ $self->{active} = 1;
+ $self->ws_send('logged-in');
+ $self->app->log->debug("reattaching " . $self->jid);
+ } else {
+ # Otherwise, attempt a new connection with the given password
+ $self->app->log->debug("Creating new XMPP connection for " . $self->jid);
+ $self->{password} = $password;
+ $self->{xmpp} = AnyEvent::XMPP::IM::Connection->new(
+ jid => $self->jid,
+ password => $password,
+ );
+ $self->attach_xmpp_events;
+ $self->xmpp->connect;
+ }
}
when ('logout') {
+ $self->active || return;
+ $self->guard_connected || return;
$self->xmpp->disconnect;
delete $self->{xmpp};
- $self->ws_send('logged-out');
- say "Logged out of ", $self->jid;
+ $self->ws_send('logged-out', reason => 'user requested');
+ $self->app->log->debug($self->jid . " logged out");
+ }
+ when ('message') {
+ $self->active || return;
+ $self->guard_connected || return;
+ AnyEvent::XMPP::IM::Message->new(
+ from => $self->jid,
+ to => $msg->{to},
+ body => $msg->{body},
+ )->send($self->xmpp);
+ }
+ when ('get-roster') {
+ $self->active || return;
+ $self->guard_connected || return;
+ $self->ws_send_roster;
+ }
+ when (undef) {
+ $self->app->log->debug("Empty message?");
}
default {
- say "Unknown message type $msg->{type}";
+ $self->app->log->debug("Unknown message type $msg->{type}");
}
}
});
$self->controller->tx->on(finish => sub {
delete $self->{controller};
- say $self->jid, " detached";
+ $self->{active} = undef;
+ $self->app->log->debug($self->jid . " detached");
});
+}
+
+sub attach_xmpp_events {
+ my ($self) = @_;
$self->xmpp->reg_cb(
session_ready => sub {
$self->ws_send('logged-in');
- say "Session ready for ", $self->xmpp->jid;
+ $self->{active} = 1;
+ $self->app->log->debug("Session ready for " . $self->xmpp->jid);
},
session_error => sub {
my ($err) = @_;
- $self->ws_send('logged-out');
- say "Session error: ", $err->string;
+ $self->ws_send('logged-out', reason => 'error', error => $err->string);
+ $self->{active} = undef;
+ $self->app->log->error("Session error: " . $err->string);
+ },
+ sasl_error => sub {
+ my ($connection, $err) = @_;
+ $self->{active} = undef;
+ $self->app->log->error($err->string);
+ if ($err->string =~ /not-authorized/) {
+ $self->ws_send('logged-out', reason => 'unauthorized');
+ }
+ },
+ roster_update => sub {
+ my ($connection, $roster, $contacts) = @_;
},
presence_update => sub {
my ($connection, $roster, $contact, $old_presence, $new_presence) = @_;
- say $contact->jid, ": ", pretty_presence($old_presence),
- " => ", pretty_presence($new_presence);
$self->ws_send('presence',
- jid => $contact->jid,
+ jid => $new_presence->jid,
status => pretty_presence($new_presence),
+ priority => $new_presence->priority,
);
},
message => sub {
my ($connection, $msg) = @_;
- say "Message from ", $msg->from, ": ", $msg->body;
AnyEvent::XMPP::IM::Message->new(
from => $self->jid,
}
}
+sub ws_send_roster {
+ my ($self) = @_;
+
+ my @raw_contacts = map {
+ {
+ jid => $_->jid,
+ name => $_->name,
+ groups => [$_->groups],
+ presence => pretty_presence($_->get_priority_presence),
+ subscription => $_->subscription,
+ }
+ } $self->xmpp->get_roster->get_contacts;
+ $self->ws_send('roster', contacts => \@raw_contacts);
+}
+
+sub guard_connected {
+ my ($self) = @_;
+ if (!$self->xmpp || !$self->xmpp->is_connected) {
+ $self->ws_send('error', message => 'not connected');
+ return;
+ }
+ return 1;
+}
+
1;