AnyEvent-XMPP
view release on metacpan or search on metacpan
lib/AnyEvent/XMPP/Connection.pm view on Meta::CPAN
Returns true if the connection is still connected and stanzas can be
sent.
=cut
sub is_connected {
my ($self) = @_;
$self->{authenticated}
}
=item B<set_default_iq_timeout ($seconds)>
This sets the default timeout for IQ requests. If the timeout runs out
the request will be aborted and the callback called with a L<AnyEvent::XMPP::Error::IQ> object
where the C<condition> method returns a special value (see also C<condition> method of L<AnyEvent::XMPP::Error::IQ>).
The default timeout for IQ is 60 seconds.
=cut
sub set_default_iq_timeout {
my ($self, $sec) = @_;
$self->{default_iq_timeout} = $sec;
}
=item B<send_iq ($type, $create_cb, $result_cb, %attrs)>
This method sends an IQ XMPP B<request>.
If you want to B<respond> to a IQ request you received via the C<iq_set_request_xml>,
and C<iq_get_request_xml> events you have to use the C<reply_iq_result> or
C<reply_iq_error> methods documented below.
Please take a look at the documentation for C<send_iq> in AnyEvent::XMPP::Writer
about the meaning of C<$type>, C<$create_cb> and C<%attrs> (with the exception
of the 'timeout' key of C<%attrs>, see below).
C<$result_cb> will be called when a result was received or the timeout reached.
The first argument to C<$result_cb> will be a AnyEvent::XMPP::Node instance
containing the IQ result stanza contents.
If the IQ resulted in a stanza error the second argument to C<$result_cb> will
be C<undef> (if the error type was not 'continue') and the third argument will
be a L<AnyEvent::XMPP::Error::IQ> object.
The timeout can be set by C<set_default_iq_timeout> or passed separately
in the C<%attrs> array as the value for the key C<timeout> (timeout in seconds btw.).
This method returns the newly generated id for this iq request.
=cut
sub send_iq {
my ($self, $type, $create_cb, $result_cb, %attrs) = @_;
my $id = $self->{iq_id}++;
$self->{iqs}->{$id} = $result_cb;
my $timeout = delete $attrs{timeout} || $self->{default_iq_timeout};
if ($timeout) {
$self->{iq_timers}->{$id} =
AnyEvent->timer (after => $timeout, cb => sub {
delete $self->{iq_timers}->{$id};
my $cb = delete $self->{iqs}->{$id};
$cb->(undef, AnyEvent::XMPP::Error::IQ->new)
});
}
$self->{writer}->send_iq ($id, $type, $create_cb, %attrs);
$id
}
=item B<next_iq_id>
This method returns the next IQ id that will be used.
=cut
sub next_iq_id {
$_[0]->{iq_id};
}
=item B<reply_iq_result ($req_iq_node, $create_cb, %attrs)>
This method will generate a result reply to the iq request C<AnyEvent::XMPP::Node>
in C<$req_iq_node>.
Please take a look at the documentation for C<send_iq> in L<AnyEvent::XMPP::Writer>
about the meaning C<$create_cb> and C<%attrs>.
Use C<$create_cb> to create the XML for the result.
The type for this iq reply is 'result'.
The C<to> attribute of the reply stanza will be set to the C<from>
attribute of the C<$req_iq_node>. If C<$req_iq_node> had no C<from>
node it won't be set. If you want to overwrite the C<to> field just
pass it via C<%attrs>.
=cut
sub reply_iq_result {
my ($self, $iqnode, $create_cb, %attrs) = @_;
return $self->_reply_iq(
$iqnode,
'result',
$create_cb,
%attrs
);
}
=item B<reply_iq_error ($req_iq_node, $error_type, $error, %attrs)>
This method will generate an error reply to the iq request C<AnyEvent::XMPP::Node>
in C<$req_iq_node>.
C<$error_type> is one of 'cancel', 'continue', 'modify', 'auth' and 'wait'.
C<$error> is one of the defined error conditions described in
C<write_error_tag> method of L<AnyEvent::XMPP::Writer>.
Please take a look at the documentation for C<send_iq> in AnyEvent::XMPP::Writer
about the meaning of C<%attrs>.
The type for this iq reply is 'error'.
The C<to> attribute of the reply stanza will be set to the C<from>
attribute of the C<$req_iq_node>. If C<$req_iq_node> had no C<from>
node it won't be set. If you want to overwrite the C<to> field just
pass it via C<%attrs>.
=cut
sub reply_iq_error {
my ($self, $iqnode, $errtype, $error, %attrs) = @_;
return $self->_reply_iq(
$iqnode,
'error',
sub { $self->{writer}->write_error_tag ($iqnode, $errtype, $error) },
%attrs
);
}
sub _reply_iq {
my ($self, $iqnode, $type, $create_cb, %attrs) = @_;
return $self->{writer}->send_iq (
$iqnode->attr ('id'), $type, $create_cb,
(defined $iqnode->attr ('from') ? (to => $iqnode->attr ('from')) : ()),
(defined $iqnode->attr ('to') ? (from => $iqnode->attr ('to')) : ()),
%attrs
);
}
sub handle_iq {
my ($self, $node) = @_;
my $type = $node->attr ('type');
my $id = $node->attr ('id');
delete $self->{iq_timers}->{$id} if defined $id;
if ($type eq 'result') {
if (my $cb = delete $self->{iqs}->{$id}) {
eval {
$cb->($node);
};
if ($@) { $self->event (iq_result_cb_exception => $@) }
}
} elsif ($type eq 'error') {
if (my $cb = delete $self->{iqs}->{$id}) {
my $error = AnyEvent::XMPP::Error::IQ->new (node => $node);
eval {
$cb->(($error->type eq 'continue' ? $node : undef), $error);
};
if ($@) { $self->event (iq_result_cb_exception => $@) }
}
} else {
my $handled = 0;
$self->event ("iq_${type}_request_xml" => $node, \$handled);
$handled or $self->reply_iq_error ($node, undef, 'service-unavailable');
}
}
sub send_sasl_auth {
my ($self, @mechs) = @_;
for (qw/username password domain/) {
die "No '$_' argument given to new, but '$_' is required\n"
unless defined $self->{$_};
}
$self->{writer}->send_sasl_auth (
[map { $_->text } @mechs],
$self->{username},
($self->{use_host_as_sasl_hostname}
? $self->{host}
: $self->{domain}),
$self->{password}
);
}
sub handle_stream_features {
my ($self, $node) = @_;
my @bind = $node->find_all ([qw/bind bind/]);
my @tls = $node->find_all ([qw/tls starttls/]);
# and yet another weird thingie: in XEP-0077 it's said that
# the register feature MAY be advertised by the server. That means:
# it MAY not be advertised even if it is available... so we don't
# care about it...
# my @reg = $node->find_all ([qw/register register/]);
if (not ($self->{disable_ssl}) && not ($self->{ssl_enabled}) && @tls) {
$self->{writer}->send_starttls;
} elsif (not $self->{authenticated}) {
lib/AnyEvent/XMPP/Connection.pm view on Meta::CPAN
binding you can call this function to set a new C<$resource>
and retry binding.
If it fails again you can call this again. Becareful not to
end up in a loop!
If binding was successful the C<stream_ready> event will be generated.
=cut
sub do_rebind {
my ($self, $resource) = @_;
$self->{resource} = $resource;
$self->send_iq (
set =>
sub {
my ($w) = @_;
if ($self->{resource}) {
simxml ($w,
defns => 'bind',
node => {
name => 'bind',
childs => [ { name => 'resource', childs => [ $self->{resource} ] } ]
}
)
} else {
simxml ($w, defns => 'bind', node => { name => 'bind' })
}
},
sub {
my ($ret_iq, $error) = @_;
if ($error) {
# TODO: make bind error into a seperate error class?
if ($error->xml_node ()) {
my ($res) = $error->xml_node ()->find_all ([qw/bind bind/], [qw/bind resource/]);
$self->event (bind_error => $error, ($res ? $res : $self->{resource}));
} else {
$self->event (bind_error => $error);
}
} else {
my @jid = $ret_iq->find_all ([qw/bind bind/], [qw/bind jid/]);
my $jid = $jid[0]->text;
unless ($jid) { die "Got empty JID tag from server!\n" }
$self->{jid} = $jid;
$self->event (stream_ready => $jid);
}
}
);
}
sub _start_whitespace_ping {
my ($self) = @_;
return unless $self->{whitespace_ping_interval} > 0;
$self->{_ws_ping} =
AnyEvent->timer (after => $self->{whitespace_ping_interval}, cb => sub {
$self->{writer}->send_whitespace_ping;
$self->_start_whitespace_ping;
});
}
sub _stop_whitespace_ping {
delete $_[0]->{_ws_ping};
}
=item B<jid>
After the stream has been bound to a resource the JID can be retrieved via this
method.
=cut
sub jid { $_[0]->{jid} }
=item B<features>
Returns the last received <features> tag in form of an L<AnyEvent::XMPP::Node> object.
=cut
sub features { $_[0]->{features} }
=item B<stream_id>
This is the ID of this stream that was given us by the server.
=cut
sub stream_id { $_[0]->{stream_id} }
=back
=head1 EVENTS
The L<AnyEvent::XMPP::Connection> class is derived from the L<Object::Event> class,
and thus inherits the event callback registering system from it. Consult the
documentation of L<Object::Event> about more details.
NODE: Every callback gets as it's first argument the L<AnyEvent::XMPP::Connection>
object. The further callback arguments are described in the following listing of
events.
These events can be registered on with C<reg_cb>:
=over 4
=item stream_features => $node
This event is sent when a stream feature (<features>) tag is received. C<$node> is the
L<AnyEvent::XMPP::Node> object that represents the <features> tag.
=item stream_pre_authentication
This event is emitted after TLS/SSL was initiated (if enabled) and before any
authentication happened.
( run in 0.988 second using v1.01-cache-2.11-cpan-39bf76dae61 )