ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Net-XMPP2/lib/Net/XMPP2/Ext/Disco.pm
Revision: 1.9
Committed: Wed Jul 25 13:53:33 2007 UTC (19 years, 2 months ago) by elmex
Branch: MAIN
Changes since 1.8: +26 -16 lines
Log Message:
implemented OOB and fixed bugs in Disco and further developed in band registration.

File Contents

# User Rev Content
1 elmex 1.3 package Net::XMPP2::Ext::Disco;
2 elmex 1.1 use Net::XMPP2::Namespaces qw/xmpp_ns/;
3 elmex 1.9 use Net::XMPP2::Util qw/simxml/;
4 elmex 1.3 use Net::XMPP2::Ext::Disco::Items;
5     use Net::XMPP2::Ext::Disco::Info;
6 elmex 1.6 use Net::XMPP2::Ext;
7    
8     our @ISA = qw/Net::XMPP2::Ext/;
9 elmex 1.1
10     =head1 NAME
11    
12 elmex 1.5 Net::XMPP2::Ext::Disco - Service discovery manager class for XEP-0030
13 elmex 1.1
14     =head1 SYNOPSIS
15    
16 elmex 1.3 use Net::XMPP2::Ext::Disco;
17 elmex 1.1
18     my $con = Net::XMPP2::IM::Connection->new (...);
19 elmex 1.7 $con->add_extension (my $disco = Net::XMPP2::Ext::Disco->new);
20 elmex 1.1 $disco->request_items ('romeo@montague.net',
21 elmex 1.8 sub {
22     my ($disco, $items, $error) = @_;
23 elmex 1.1 if ($error) { print "ERROR".$error->string."\n" }
24     else {
25 elmex 1.8 ... do something with the $items ...
26 elmex 1.1 }
27     }
28     );
29    
30     =head1 DESCRIPTION
31    
32     This module represents a service discovery manager class.
33     You make instances of this class and get a handle to send
34     discovery requests like described in XEP-0030.
35    
36     It also allows you to setup a disco-info/items tree
37     that others can walk and also lets you publish disco information.
38    
39 elmex 1.6 This class is derived from L<Net::XMPP2::Ext> and can be added as extension to
40     objects that implement the L<Net::XMPP2::Extendable> interface or derive from
41     it.
42    
43 elmex 1.1 =head1 METHODS
44    
45 elmex 1.4 =over 4
46    
47     =item B<new (%args)>
48 elmex 1.1
49 elmex 1.6 Creates a new disco handle.
50 elmex 1.1
51     =cut
52    
53     sub new {
54     my $this = shift;
55     my $class = ref($this) || $this;
56     my $self = bless { @_ }, $class;
57     $self->init;
58     $self
59     }
60    
61     sub init {
62     my ($self) = @_;
63    
64     $self->set_identity (client => console => 'Net::XMPP2');
65 elmex 1.9 $self->enable_feature (xmpp_ns ('disco_info'));
66     $self->enable_feature (xmpp_ns ('disco_items'));
67 elmex 1.1
68 elmex 1.6 $self->reg_cb (
69     iq_get_request_xml => sub {
70 elmex 1.9 my ($self, $con, $node) = @_;
71 elmex 1.1
72 elmex 1.6 if ($self->handle_disco_query ($con, $node)) {
73 elmex 1.9 return 1;
74 elmex 1.6 }
75 elmex 1.1
76 elmex 1.9 ()
77 elmex 1.6 }
78     );
79 elmex 1.1 }
80    
81 elmex 1.4 =item B<set_identity ($category, $type, $name)>
82 elmex 1.1
83     This sets the identity of the top info node.
84     The default is: C<$category = "client">, C<$type = "console">
85     and C<$name = "Net::XMPP2">.
86    
87     C<$name> is optional and can be undef.
88    
89     For a list of valid identites look at:
90    
91     http://www.xmpp.org/registrar/disco-categories.html
92    
93     Valid identity types for C<$category = "client"> may be:
94    
95     bot
96     console
97     handheld
98     pc
99     phone
100     web
101    
102     =cut
103    
104     sub set_identity {
105     my ($self, $category, $type, $name) = @_;
106     $self->{iden}->{cat} = $category;
107     $self->{iden}->{type} = $type;
108     $self->{iden}->{name} = $name;
109     }
110    
111    
112 elmex 1.4 =item B<enable_feature ($uri)>
113 elmex 1.1
114     This method enables the feature C<$uri>, where C<$uri>
115     should be one of the values from the B<Name> column on:
116    
117     http://www.xmpp.org/registrar/disco-features.html
118    
119     These features are enabled by default:
120    
121     http://jabber.org/protocol/disco#info
122     http://jabber.org/protocol/disco#items
123    
124     =cut
125    
126     sub enable_feature {
127     my ($self, $feature) = @_;
128     $self->{feat}->{$feature} = 1
129     }
130    
131 elmex 1.4 =item B<disable_feature ($uri)>
132 elmex 1.1
133     This method enables the feature C<$uri>, where C<$uri>
134     should be one of the values from the B<Name> column on:
135    
136     http://www.xmpp.org/registrar/disco-features.html
137    
138     These features are enabled by default:
139    
140     http://jabber.org/protocol/disco#info
141     http://jabber.org/protocol/disco#items
142    
143     =cut
144    
145     sub disable_feature {
146     my ($self, $feature) = @_;
147     delete $self->{feat}->{$feature}
148     }
149    
150     sub write_feature {
151     my ($self, $w, $var) = @_;
152    
153     $w->emptyTag ([xmpp_ns ('disco_info'), 'feature'], var => $var);
154     }
155    
156     sub write_identity {
157     my ($self, $w, $cat, $type, $name) = @_;
158    
159     $w->emptyTag ([xmpp_ns ('disco_info'), 'identity'],
160     category => $cat,
161     type => $type,
162     (defined $name ? (name => $name) : ())
163     );
164     }
165    
166     sub handle_disco_query {
167 elmex 1.6 my ($self, $con, $node) = @_;
168 elmex 1.1
169 elmex 1.9 if (my ($q) = $node->find_all ([qw/disco_info query/])) {
170 elmex 1.6 $con->reply_iq_result (
171 elmex 1.1 $node, sub {
172     my ($w) = @_;
173    
174 elmex 1.9 if ($q->attr ('node')) {
175     simxml ($w, defns => 'disco_info', node => {
176     ns => 'disco_info', name => 'query',
177     attrs => [ node => $q->attr ('node') ]
178     });
179 elmex 1.1
180     } else {
181     $w->addPrefix (xmpp_ns ('disco_info'), '');
182     $w->startTag ([xmpp_ns ('disco_info'), 'query']);
183     $self->write_identity ($w,
184     $self->{iden}->{cat},
185     $self->{iden}->{type},
186     $self->{iden}->{name},
187     );
188 elmex 1.9 for (sort grep { $self->{feat}->{$_} } keys %{$self->{feat}}) {
189     $self->write_feature ($w, $_);
190     }
191 elmex 1.1 $w->endTag;
192     }
193 elmex 1.6 },
194     to => $node->attr ('from')
195 elmex 1.1 );
196    
197     return 1
198    
199 elmex 1.9 } elsif (my ($q) = $node->find_all ([qw/disco_items query/])) {
200 elmex 1.6 $con->reply_iq_result (
201 elmex 1.1 $node, sub {
202     my ($w) = @_;
203    
204 elmex 1.9 if ($q->attr ('node')) {
205     simxml ($w, defns => 'disco_items', node => {
206     ns => 'disco_items',
207     name => 'query',
208     attrs => [ node => $q->attr ('node') ]
209     });
210 elmex 1.1
211     } else {
212 elmex 1.9 simxml ($w, defns => 'disco_items', node => {
213     ns => 'disco_items',
214     name => 'query'
215     });
216 elmex 1.1 }
217 elmex 1.6 },
218     to => $node->attr ('from')
219 elmex 1.1 );
220    
221     return 1
222     }
223    
224     0
225     }
226    
227     sub DESTROY {
228     my ($self) = @_;
229     $self->{connection}->unreg_cb ($self->{cb_id})
230     }
231    
232 elmex 1.2
233 elmex 1.6 =item B<request_items ($con, $dest, $node, $cb)>
234 elmex 1.2
235     This method does send a items request to the JID entity C<$from>.
236     C<$node> is the optional node to send the request to, which can be
237     undef.
238 elmex 1.6 C<$con> must be an instance of L<Net::XMPP2::Connection> or a subclass of it.
239 elmex 1.2 The callback C<$cb> will be called when the request returns with 3 arguments:
240 elmex 1.3 the disco handle, an L<Net::XMPP2::Ext::Disco::Items> object (or undef)
241 elmex 1.2 and an L<Net::XMPP2::Error::IQ> object when an error occured and no items
242     were received.
243    
244 elmex 1.6 $disco->request_items ($con, 'a@b.com', undef, sub {
245 elmex 1.2 my ($disco, $items, $error) = @_;
246     die $error->string if $error;
247    
248     # do something with the items here ;_)
249     });
250    
251     =cut
252    
253     sub request_items {
254 elmex 1.6 my ($self, $con, $dest, $node, $cb) = @_;
255 elmex 1.2
256 elmex 1.6 $con->send_iq (
257 elmex 1.2 get => sub {
258     my ($w) = @_;
259     $w->addPrefix (xmpp_ns ('disco_items'), '');
260     $w->emptyTag ([xmpp_ns ('disco_items'), 'query'],
261     (defined $node ? (node => $node) : ())
262     );
263     },
264     sub {
265     my ($xmlnode, $error) = @_;
266     my $items;
267    
268     if ($xmlnode) {
269     my (@query) = $xmlnode->find_all ([qw/disco_items query/]);
270 elmex 1.3 $items = Net::XMPP2::Ext::Disco::Items->new (
271 elmex 1.2 jid => $dest,
272     node => $node,
273     xmlnode => $query[0]
274     )
275     }
276    
277     $cb->($self, $items, $error)
278     },
279     to => $dest
280     );
281     }
282    
283 elmex 1.6 =item B<request_info ($con, $dest, $node, $cb)>
284 elmex 1.2
285     This method does send a info request to the JID entity C<$from>.
286     C<$node> is the optional node to send the request to, which can be
287     undef.
288 elmex 1.6 C<$con> must be an instance of L<Net::XMPP2::Connection> or a subclass of it.
289 elmex 1.2 The callback C<$cb> will be called when the request returns with 3 arguments:
290 elmex 1.3 the disco handle, an L<Net::XMPP2::Ext::Disco::Info> object (or undef)
291 elmex 1.2 and an L<Net::XMPP2::Error::IQ> object when an error occured and no items
292     were received.
293    
294     $disco->request_info ('a@b.com', undef, sub {
295     my ($disco, $info, $error) = @_;
296     die $error->string if $error;
297    
298     # do something with info here ;_)
299     });
300    
301     =cut
302    
303     sub request_info {
304 elmex 1.6 my ($self, $con, $dest, $node, $cb) = @_;
305 elmex 1.2
306 elmex 1.6 $con->send_iq (
307 elmex 1.2 get => sub {
308     my ($w) = @_;
309     $w->addPrefix (xmpp_ns ('disco_info'), '');
310     $w->emptyTag ([xmpp_ns ('disco_info'), 'query'],
311     (defined $node ? (node => $node) : ())
312     );
313     },
314     sub {
315     my ($xmlnode, $error) = @_;
316     my $info;
317    
318     if ($xmlnode) {
319     my (@query) = $xmlnode->find_all ([qw/disco_info query/]);
320 elmex 1.3 $info = Net::XMPP2::Ext::Disco::Info->new (
321 elmex 1.2 jid => $dest,
322     node => $node,
323     xmlnode => $query[0]
324     )
325     }
326    
327     $cb->($self, $info, $error)
328     },
329     to => $dest
330     );
331     }
332    
333 elmex 1.4 =back
334    
335 elmex 1.1 =head1 AUTHOR
336    
337 elmex 1.4 Robin Redeker, C<< <elmex at ta-sa.org> >>, JID: C<< <elmex at jabber.org> >>
338 elmex 1.1
339     =head1 COPYRIGHT & LICENSE
340    
341     Copyright 2007 Robin Redeker, all rights reserved.
342    
343     This program is free software; you can redistribute it and/or modify it
344     under the same terms as Perl itself.
345    
346     =cut
347    
348     1;