ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-XMPP2/lib/Net/XMPP2/Connection.pm
Revision: 1.9
Committed: Sat Mar 17 12:27:57 2007 UTC (19 years, 6 months ago) by elmex
Branch: MAIN
Changes since 1.8: +26 -363 lines
Log Message:
some minor cleanups.

File Contents

# User Rev Content
1 elmex 1.1 package Net::XMPP2::Connection;
2     use strict;
3     use AnyEvent;
4     use IO::Socket::INET;
5     use Net::XMPP2::Parser;
6     use Net::XMPP2::Writer;
7     use Net::XMPP2::Util;
8 elmex 1.9 use Net::XMPP2::Event;
9     use Net::XMPP2::SimpleConnection;
10 elmex 1.1 use Net::XMPP2::Namespaces qw/xmpp_ns/;
11     use Net::DNS;
12 elmex 1.2
13 elmex 1.9 our @ISA = qw/Net::XMPP2::SimpleConnection Net::XMPP2::Event/;
14 elmex 1.1
15     =head1 NAME
16    
17     Net::XMPP2::Connection - A XML stream that implements the XMPP RFC 3920.
18    
19     =head1 SYNOPSIS
20    
21     use Net::XMPP2::Connection;
22    
23     my $con =
24     Net::XMPP2::Connection->new (
25     username => "abc",
26     domain => "jabber.org",
27     resource => "Net::XMPP2"
28     );
29    
30     $con->connect or die "Couldn't connect to jabber.org: $!";
31     $con->init;
32     $con->reg_cb (stream_ready => sub { print "XMPP stream ready!\n" });
33    
34     =head1 DESCRIPTION
35    
36     This module represents a XMPP stream as described in RFC 3920. You can issue the basic
37     XMPP XML stanzas with methods like C<send_iq>, C<send_message> and C<send_presence>.
38    
39     And receive events with the C<reg_cb> event framework from the connection.
40    
41     If you need instant messaging stuff please take a look at C<Net::XMPP2::IM::Connection>.
42    
43     =head1 METHODS
44    
45     =head2 new (%args)
46    
47     Following arguments can be passed in C<%args>:
48    
49     =over 4
50    
51     =item language => $tag
52    
53     This should be the language of the human readable contents that
54     will be transmitted over the stream. The default will be 'en'.
55    
56     Please look in RFC 3066 how C<$tag> should look like.
57    
58     =item resource => $resource
59    
60     If this argument is given C<$resource> will be passed as desired
61     resource on resource binding.
62    
63     Note: You have to take care that the stringprep profile for
64     resources can be applied at: C<$resource>. Otherwise the server
65     might signal an error. See L<Net::XMPP2::Util> for utility functions
66     to check this.
67    
68     =item domain => $domain
69    
70     This is the destination host we are going to connect to.
71     As the connection won't be automatically connected use C<connect>
72     to initiate the connect.
73    
74     Note: A SRV RR lookup will be performed to discover the real hostname
75     and port to connect to. See also C<connect>.
76    
77 elmex 1.9 =item override_host => $host
78     =item override_port => $port
79    
80     This will be used as override to connect to.
81    
82 elmex 1.1 =item port => $port
83    
84     This is optional, the default port is 5222.
85    
86     Note: A SRV RR lookup will be performed to discover the real hostname
87     and port to connect to. See also C<connect>.
88    
89     =item username => $username
90    
91     This is your C<$username> (the userpart in the JID);
92    
93     Note: You have to take care that the stringprep profile for
94     nodes can be applied at: C<$username>. Otherwise the server
95     might signal an error. See L<Net::XMPP2::Util> for utility functions
96     to check this.
97    
98     =item password => $password
99    
100     This is the password for the C<username> above.
101    
102 elmex 1.5 =item disable_ssl => $bool
103    
104     If C<$bool> is true no SSL will be used.
105    
106 elmex 1.1 =back
107    
108     =cut
109    
110     sub new {
111     my $this = shift;
112     my $class = ref($this) || $this;
113     my $self = { language => 'en', @_ };
114     bless $self, $class;
115    
116     $self->{parser} = new Net::XMPP2::Parser;
117     $self->{writer} = Net::XMPP2::Writer->new (
118     write_cb => sub { $self->write_data ($_[0]) }
119     );
120    
121     $self->{parser}->set_stanza_cb (sub {
122     $self->handle_stanza (@_);
123     });
124    
125     $self->{iq_id} = 1;
126    
127     $self->{disconnect_cb} = sub {
128     my ($host, $port, $message) = @_;
129 elmex 1.7 delete $self->{authenticated};
130     delete $self->{ssl_enabled};
131 elmex 1.1 $self->event (disconnect => $host, $port, $message);
132     };
133    
134 elmex 1.7 for (qw/username password domain/) {
135     die "No '$_' argument given to new, but '$_' is required\n"
136     unless $self->{$_};
137     }
138    
139 elmex 1.1 return $self;
140     }
141    
142     =head2 connect ($no_srv_rr)
143    
144     Try to connect to the domain and port passed in C<new>.
145    
146     A SRV RR lookup will be performed on the domain to discover
147     the host and port to use. If you don't want this set C<$no_srv_rr>
148     to a true value. C<$no_srv_rr> is false by default.
149    
150     As the SRV RR lookup might return multiple host and you fail to
151     connect to one you might just call this function again to try a
152     different host.
153    
154     If C<connect> was successful and we connected a true value is returned.
155     If the connect was unsuccessful undef is returned and C<$!> will be set
156     to the error that occured while connecting.
157    
158     If you want to know whether further connection attempts might be more
159     successful (as SRV RR lookup may return multiple hosts) call C<may_try_connect>
160     (see also C<may_try_connect>).
161    
162     Note that an internal list will be kept of tried hosts. Use
163     C<reset_connect_tries> to reset the internal list of tried hosts.
164    
165     =cut
166    
167     sub connect {
168     my ($self, $no_srv_rr) = @_;
169    
170     my ($host, $port) = ($self->{domain}, $self->{port} || 5222);
171 elmex 1.9 if ($self->{override_host}) {
172     ($host, $port) = ($self->{override_host}, $self->{override_port} || 5222);
173 elmex 1.1
174 elmex 1.9 } else {
175     unless ($no_srv_rr) {
176     my $res = Net::DNS::Resolver->new;
177     my $p = $res->query ('_xmpp-client._tcp.'.$host, 'SRV');
178     if ($p) {
179     my @srvs = grep { $_->type eq 'SRV' } $p->answer;
180     if (@srvs) {
181     @srvs = sort { $a->priority <=> $b->priority } @srvs;
182     @srvs = sort { $b->weight <=> $a->weight } @srvs; # TODO
183     $port = $srvs[0]->port;
184     $host = $srvs[0]->target;
185     }
186 elmex 1.1 }
187     }
188     }
189    
190     if ($self->SUPER::connect ($host, $port)) {
191     $self->event (connect => $host, $port);
192     return 1;
193     } else {
194     return undef;
195     }
196     }
197    
198     =head2 may_try_connect
199    
200     Returns the number of left alternatives of hosts to connect to for the
201     domain passed to C<new>.
202    
203     An internal list of tried hosts will be managed by C<connect> and those
204     hosts will be ignored by a SRV RR lookup (which will be done if you
205     call this function).
206    
207     Use C<reset_connect_tries> to reset the internal list of tried hosts.
208    
209     =cut
210    
211     sub may_try_connect {
212     # TODO
213     }
214    
215     =head2 reset_connect_tries
216    
217     This function resets the internal list of tried hosts for C<connect>.
218     See also C<connect>.
219    
220     =cut
221    
222     sub reset_connect_tries {
223     # TODO
224     }
225    
226     sub handle_data {
227     my ($self, $buf) = @_;
228     $self->event (debug_recv => $$buf);
229     $self->{parser}->feed (substr $$buf, 0, (length $$buf), '');
230     }
231    
232 elmex 1.5 sub debug_wrote_data {
233     my ($self, $data) = @_;
234     $self->event (debug_send => $data);
235     }
236    
237 elmex 1.1 sub write_data {
238     my ($self, $data) = @_;
239     $self->SUPER::write_data ($data);
240     }
241    
242     sub handle_stanza {
243     my ($self, $p, $node) = @_;
244    
245     if ($node->eq (stream => 'features')) {
246     $self->event (stream_features => $node);
247     $self->handle_stream_features ($node);
248 elmex 1.4 $self->{features} = $node;
249 elmex 1.5
250 elmex 1.2 } elsif ($node->eq (tls => 'proceed')) {
251     $self->enable_ssl;
252     $self->{parser}->init;
253     $self->{writer}->init;
254     $self->{writer}->send_init_stream ($self->{language}, $self->{domain});
255    
256 elmex 1.1 } elsif ($node->eq (sasl => 'challenge')) {
257     $self->handle_sasl_challenge ($node);
258     } elsif ($node->eq (sasl => 'success')) {
259     $self->handle_sasl_success ($node);
260     } elsif ($node->eq (client => 'iq')) {
261     $self->handle_iq ($node);
262 elmex 1.4 } elsif ($node->eq (client => 'message')) {
263 elmex 1.6 $self->event (message_xml => $node);
264 elmex 1.4 } elsif ($node->eq (client => 'presence')) {
265 elmex 1.6 $self->event (presence_xml => $node);
266 elmex 1.1 } elsif ($node->eq (stream => 'error')) {
267     $self->handle_error ($node);
268     } else {
269     warn "Didn't understood stanza: '" . $node->name . "'";
270     }
271     }
272    
273     =head2 init ($domain)
274    
275     Initiate the XML stream.
276    
277     =cut
278    
279     sub init {
280     my ($self) = @_;
281     $self->{writer}->send_init_stream ($self->{language}, $self->{domain});
282     }
283    
284     =head2 send_iq ($type, $create_cb, $result_cb, %attrs)
285    
286     This method sends an IQ XMPP request.
287    
288     Please take a look at the documentation for C<send_iq> in Net::XMPP2::Writer
289     about the meaning of C<$type>, C<$create_cb> and C<%attrs>.
290    
291 elmex 1.4 C<$result_cb> will be called when a result was received. The first argument to
292     C<$result_cb> will be a Net::XMPP2::Node instance containing the IQ result
293     stanza contents.
294 elmex 1.1
295     If the IQ resulted in a stanza error the second argument to C<$result_cb> will
296     be C<undef> (if the error type was not 'continue') and the third argument will
297     be a Net::XMPP2::Node containg the IQ error stanza. And the fourth argument
298     will be a array reference with following contents:
299    
300 elmex 1.4 This method returns the newly generated id for this iq request.
301    
302 elmex 1.1 =over 4
303    
304     =item index 0: error type
305    
306     This will be one of: 'cancel', 'continue', 'modify', 'auth' and 'wait'.
307    
308     =item index 1: error condition element
309    
310     This might be undefined if other XMPP speakers don't play nice i guess.
311    
312     =item index 2: error text
313    
314     This will be the human readable form of the error which is maybe undef if
315     not supplied.
316    
317     =item index 3: error code
318    
319     If the error element had an 'code' attribute it will be put here,
320     the RFC says that this is for backward compatibility :)
321    
322     =back
323    
324     =cut
325    
326     sub send_iq {
327     my ($self, $type, $create_cb, $result_cb, %attrs) = @_;
328     my $id = $self->{iq_id}++;
329     $self->{iqs}->{$id} = $result_cb;
330     $self->{writer}->send_iq ($id, $type, $create_cb, %attrs);
331 elmex 1.4 $id
332     }
333    
334     =head2 reply_iq_result ($req_iq_node, $create_cb, %attrs)
335    
336     This method will generate a result reply to the iq request C<Net::XMPP2::Node>
337     in C<$req_iq_node>.
338    
339     Please take a look at the documentation for C<send_iq> in Net::XMPP2::Writer
340     about the meaning C<$create_cb> and C<%attrs>.
341    
342 elmex 1.6 Use C<$create_cb> to create the XML for the result.
343    
344 elmex 1.4 The type for this iq reply is 'result'.
345    
346     =cut
347    
348     sub reply_iq_result {
349     my ($self, $iqnode, $create_cb, %attrs) = @_;
350     $self->{writer}->send_iq ($iqnode->attr ('id'), 'result', $create_cb, %attrs);
351     }
352    
353     =head2 reply_iq_error ($req_iq_node, $error_type, $error, %attrs)
354    
355     This method will generate an error reply to the iq request C<Net::XMPP2::Node>
356     in C<$req_iq_node>.
357    
358     C<$error_type> is one of 'cancel', 'continue', 'modify', 'auth' and 'wait'.
359     C<$error> is one of the defined error conditions described in
360     L<Net::XMPP2::Writer::write_error_tag>.
361    
362     Please take a look at the documentation for C<send_iq> in Net::XMPP2::Writer
363 elmex 1.6 about the meaning of C<%attrs>.
364 elmex 1.4
365     The type for this iq reply is 'error'.
366    
367     =cut
368    
369     sub reply_iq_error {
370     my ($self, $iqnode, $errtype, $error, %attrs) = @_;
371    
372     $self->{writer}->send_iq (
373     $iqnode->attr ('id'), 'error',
374     sub { $self->{writer}->write_error_tag ($iqnode, $errtype, $error) },
375     %attrs
376     );
377 elmex 1.1 }
378    
379     sub handle_iq {
380     my ($self, $node) = @_;
381    
382 elmex 1.4 my $type = $node->attr ('type');
383    
384     if ($type eq 'result') {
385     if (my $cb = delete $self->{iqs}->{$node->attr ('id')}) {
386 elmex 1.1 $cb->($node);
387     }
388 elmex 1.9
389 elmex 1.4 } elsif ($type eq 'error') {
390     if (my $cb = delete $self->{iqs}->{$node->attr ('id')}) {
391 elmex 1.1
392     my $error = $self->filter_error_stanza ($node);
393     $cb->(($error->[0] eq 'continue' ? $node : undef), $node, $error);
394     }
395 elmex 1.4
396     } else {
397     my $handled = 0;
398 elmex 1.6 $self->event ("iq_${type}_request_xml" => $node, \$handled);
399 elmex 1.4
400     my @from;
401     push @from, (to => $node->attr ('from')) if $node->attr ('from');
402    
403     unless ($handled) {
404 elmex 1.5 $self->reply_iq_error ($node, undef, 'feature-not-implemented', @from);
405 elmex 1.4 }
406 elmex 1.1 }
407     }
408    
409     sub filter_error_stanza {
410     my ($self, $node) = @_;
411 elmex 1.9
412 elmex 1.1 my @error;
413     my ($err) = $node->find_all ([qw/client error/]);
414     $error[0] = $err->attr ('type');
415     $error[3] = $err->attr ('code');
416 elmex 1.9
417 elmex 1.1 if ($err) {
418     if (my ($txt) = $err->find_all ([qw/stanzas text/])) {
419     $error[2] = $txt->text;
420     }
421     for my $er (
422     qw/bad-request conflict feature-not-implemented forbidden
423     gone internal-server-error item-not-found jid-malformed
424     not-acceptable not-allowed not-authorized payment-required
425     recipient-unavailable redirect registration-required
426     remote-server-not-found remote-server-timeout resource-constraint
427     service-unavailable subscription-required undefined-condition
428     unexpected-request/)
429     {
430     if (my ($el) = $err->find_all ([stanzas => $er])) {
431     $error[1] = $el;
432     last;
433     }
434     }
435     } else {
436     warn "no error element found in error stanza!";
437     }
438 elmex 1.9
439 elmex 1.1 return \@error
440     }
441    
442     sub handle_stream_features {
443     my ($self, $node) = @_;
444     my @mechs = $node->find_all ([qw/sasl mechanisms/], [qw/sasl mechanism/]);
445     my @bind = $node->find_all ([qw/bind bind/]);
446 elmex 1.2 my @tls = $node->find_all ([qw/tls starttls/]);
447 elmex 1.1
448 elmex 1.5 if (not ($self->{disable_ssl}) && not ($self->{ssl_enabled}) && @tls) {
449 elmex 1.2 $self->{writer}->send_starttls;
450    
451     } elsif (not ($self->{authenticated}) and @mechs) {
452 elmex 1.1 $self->{writer}->send_sasl_auth (
453     (join ' ', map { $_->text } @mechs),
454     $self->{username}, $self->{domain}, $self->{password}
455     );
456    
457     } elsif (@bind) {
458     $self->do_rebind ($self->{resource});
459     }
460     }
461    
462     sub handle_sasl_challenge {
463     my ($self, $node) = @_;
464     $self->{writer}->send_sasl_response ($node->text);
465     }
466    
467     sub handle_sasl_success {
468     my ($self, $node) = @_;
469     $self->{authenticated} = 1;
470     $self->{parser}->init;
471     $self->{writer}->init;
472     $self->{writer}->send_init_stream ($self->{language}, $self->{domain});
473     }
474    
475     sub handle_error {
476     my ($self, $node) = @_;
477     my @txt = $node->find_all ([qw/stream text/]);
478     my $error;
479     for my $er (
480     qw/bad-format bad-namespace-prefix conflict connection-timeout host-gone
481     host-unknown improper-addressing internal-server-error invalid-from
482     invalid-id invalid-namespace invalid-xml not-authorized policy-violation
483     remote-connection-failed resource-constraint restricted-xml
484     see-other-host system-shutdown undefined-condition unsupported-stanza-type
485     unsupported-version xml-not-well-formed/)
486     {
487     for ($node->nodes) {
488     if ($node->eq (streams => $er)) {
489     $error = $_->name;
490     last
491     }
492     }
493     }
494     unless ($error) {
495     warn "got undefined error stanza, trying to find any undefined error...";
496     for ($node->nodes) {
497     if ($node->eq_ns ('streams')) {
498     $error = $node->name;
499     }
500     }
501     }
502 elmex 1.6 $self->event (stream_error => $error, (@txt ? $txt[0]->text : ''));
503     $self->event (stream_error_xml => $node);
504 elmex 1.1 $self->{writer}->send_end_of_stream;
505     }
506    
507 elmex 1.4 =head2 send_presence ($type, $create_cb, %attrs)
508    
509     This method sends a presence stanza, for the meanings
510     of C<$type>, C<$create_cb> and C<%attrs> please take a look
511     at the documentation for L<Net::XMPP2::Writer::send_presence>.
512    
513     This methods does attach an id attribute to the message stanza and
514     will return the id that was used (so you can react on possible replies).
515    
516     =cut
517    
518     sub send_presence {
519     my ($self, $type, $create_cb, %attrs) = @_;
520     my $id = $self->{iq_id}++;
521     $self->{writer}->send_presence ($id, $type, $create_cb, %attrs);
522     $id
523     }
524    
525     =head2 send_message ($to, $type, $create_cb, %attrs)
526    
527     This method sends a presence stanza, for the meanings
528     of C<$to>, C<$type>, C<$create_cb> and C<%attrs> please take a look
529     at the documentation for L<Net::XMPP2::Writer::send_message>.
530    
531     This methods does attach an id attribute to the message stanza and
532     will return the id that was used (so you can react on possible replies).
533    
534     =cut
535    
536     sub send_message {
537     my ($self, $to, $type, $create_cb, %attrs) = @_;
538     my $id = $self->{iq_id}++;
539     $self->{writer}->send_message ($id, $to, $type, $create_cb, %attrs);
540     $id
541     }
542    
543 elmex 1.1 =head2 do_rebind ($resource)
544    
545     In case you got a C<bind_error> event and want to retry
546     binding you can call this function to set a new C<$resource>
547     and retry binding.
548    
549     If it fails again you can call this again. Becareful not to
550     end up in a loop!
551    
552     If binding was successful the C<stream_ready> event will be generated.
553    
554     =cut
555    
556     sub do_rebind {
557     my ($self, $resource) = @_;
558     $self->{resource} = $resource;
559     $self->send_iq (
560     set =>
561     sub {
562     my ($w) = @_;
563     if ($self->{resource}) {
564     $w->startTag ([xmpp_ns ('bind'), 'bind']);
565     $w->startTag ([xmpp_ns ('bind'), 'resource']);
566     $w->characters ($self->{resource});
567     $w->endTag;
568     $w->endTag;
569     } else {
570     $w->emptyTag ([xmpp_ns ('bind'), 'bind'])
571     }
572     },
573     sub {
574     my ($ret_iq, $err_iq, $err) = @_;
575    
576     if ($err) {
577     my ($res) = $err_iq->find_all ([qw/bind bind/], [qw/bind resource/]);
578     $self->event (bind_error => $err->[0], ($res ? $res : $self->{resource}));
579 elmex 1.6 $self->event (bind_error_xml => $err_iq);
580 elmex 1.1
581     } else {
582     my @jid = $ret_iq->find_all ([qw/bind bind/], [qw/bind jid/]);
583     my $jid = $jid[0]->text;
584     unless ($jid) { die "Got empty JID tag from server!\n" }
585     $self->{jid} = $jid;
586    
587     $self->event (stream_ready => $jid);
588     }
589     }
590     );
591     }
592    
593     =head2 jid
594    
595     After the stream has been bound to a resource the JID can be retrieved via this
596     method.
597    
598     =cut
599    
600     sub jid { $_[0]->{jid} }
601    
602 elmex 1.4 =head2 features
603    
604     Returns the last received <features> tag in form of an L<Net::XMPP2::Node> object.
605    
606     =cut
607    
608     sub features { $_[0]->{features} }
609    
610     #sub enable_extension {
611     # my ($self, @exts) = @_;
612     # for (@exts) {
613     # if (/^xep-(\d+)$/i) {
614     # $self->{ext}->{''.(1*$1)} = 1;
615     # }
616     # }
617     #}
618     #
619     #sub check_extension {
620     # my ($self, $extnum) = @_;
621     # return $self->{ext}->{"$extnum"} || $Net::XMPP2::EXTENSION_ENABLED{"$extnum"};
622     #}
623    
624 elmex 1.1 =head1 EVENTS
625    
626     These events can be registered on with C<reg_cb>:
627    
628     =over 4
629    
630 elmex 1.6 =item stream_features_xml => $node
631 elmex 1.1
632 elmex 1.4 This event is sent when a stream feature (<features>) tag is received. C<$node> is the
633     L<Net::XMPP2::Node> object that represents the <features> tag.
634 elmex 1.1
635     =item stream_ready => $jid
636    
637     This event is sent if the XML stream has been established (and
638     resources have been bound) and is ready for transmitting regular stanzas.
639    
640     C<$jid> is the bound jabber id.
641    
642 elmex 1.6 =item stream_error => $error, $text
643    
644     This event is sent if a XML stream error occured. C<$error>
645     will be the machine readable error string, which is one of:
646    
647     bad-format bad-namespace-prefix conflict connection-timeout host-gone
648     host-unknown improper-addressing internal-server-error invalid-from
649     invalid-id invalid-namespace invalid-xml not-authorized policy-violation
650     remote-connection-failed resource-constraint restricted-xml
651     see-other-host system-shutdown undefined-condition unsupported-stanza-type
652     unsupported-version xml-not-well-formed
653    
654     And C<$text> is an optional human readable text.
655    
656     =item stream_error_xml => $node
657    
658     This is sent when a XML stream error occurs. C<$node>
659     is the XML node of the 'error' stanza and will be a L<Net::XMPP2::Node>
660     object.
661    
662 elmex 1.1 =item bind_error => $error_name, $resource
663    
664     This event is generated when the stream was unable to bind to
665     any or the in C<new> specified resource. C<$error_name>
666     may be 'bad-request', 'not-allowed' or 'conflict'.
667    
668     Node: this is untested, i couldn't get the server to send a bind error
669     to test this.
670    
671 elmex 1.6 =item bind_error_xml => $iq_error_node
672    
673     This event is generated when the stream was unable to bind to
674     any or the in C<new> specified resource. C<$iq_error_node> contains
675     the IQ error L<Net::XMPP2::Node>.
676    
677 elmex 1.1 =item connect => $host, $port
678    
679     This event is generated when a successful connect was performed to
680     the domain passed to C<new>.
681    
682     Note: C<$host> and C<$port> might be different from the domain you passed to
683     C<new> if C<connect> performed a SRV RR lookup.
684    
685     If this connection is lost a C<disconnect> will be generated with the same
686     C<$host> and C<$port>.
687    
688     =item disconnect => $host, $port, $message
689    
690     This event is generated when the connection was lost or another error
691     occured while writing or reading from it.
692    
693     C<$message> is a humand readable error message for the failure.
694     C<$host> and C<$port> were the host and port we were connected to.
695    
696     Note: C<$host> and C<$port> might be different from the domain you passed to
697     C<new> if C<connect> performed a SRV RR lookup.
698    
699 elmex 1.6 =item presence_xml => $node
700 elmex 1.4
701     This event is sent when a presence stanza is received. C<$node> is the
702     L<Net::XMPP2::Node> object that represents the <presence> tag.
703    
704 elmex 1.6 =item message_xml => $node
705 elmex 1.4
706     This event is sent when a message stanza is received. C<$node> is the
707     L<Net::XMPP2::Node> object that represents the <message> tag.
708    
709 elmex 1.6 =item iq_set_request_xml => $node, $handled_ref
710 elmex 1.4
711 elmex 1.6 =item iq_get_request_xml => $node, $handled_ref
712 elmex 1.4
713     These events are sent when an iq request stanza of type 'get' or 'set' is received.
714     C<$type> will either be 'get' or 'set' and C<$node> will be the L<Net::XMPP2::Node>
715     object of the iq tag.
716    
717     If C<$$handled_ref> is true an event handler should not handle this message anymore.
718    
719     If one of the event handlers handled this message the scalar pointed at by
720     the reference in C<$handled_ref> should be set to 1 true value. If C<$$handled_ref>
721     is still false after all event handlers were executed an error iq will be generated.
722    
723 elmex 1.1 =back
724    
725     =head1 AUTHOR
726    
727     Robin Redeker, C<< <elmex at ta-sa.org> >>
728    
729     =head1 COPYRIGHT & LICENSE
730    
731     Copyright 2007 Robin Redeker, all rights reserved.
732    
733     This program is free software; you can redistribute it and/or modify it
734     under the same terms as Perl itself.
735    
736     =cut
737    
738     1; # End of Net::XMPP2