File Coverage

blib/lib/Net/XMPP3/Namespaces.pm
Criterion Covered Total %
statement 9 9 100.0
branch 6 6 100.0
condition n/a
subroutine 2 2 100.0
pod 1 1 100.0
total 18 18 100.0


line stmt bran cond sub pod time code
1             ##############################################################################
2             #
3             # This library is free software; you can redistribute it and/or
4             # modify it under the terms of the GNU Library General Public
5             # License as published by the Free Software Foundation; either
6             # version 2 of the License, or (at your option) any later version.
7             #
8             # This library is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11             # Library General Public License for more details.
12             #
13             # You should have received a copy of the GNU Library General Public
14             # License along with this library; if not, write to the
15             # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16             # Boston, MA 02111-1307, USA.
17             #
18             # Copyright (C) 1998-2004 Jabber Software Foundation http://jabber.org/
19             #
20             ##############################################################################
21              
22             package Net::XMPP3::Namespaces;
23              
24             =head1 NAME
25              
26             Net::XMPP3::Namespaces - In depth discussion on how namespaces are handled
27              
28             =head1 SYNOPSIS
29              
30             Net::XMPP3::Namespaces provides an depth look at how Net::XMPP3 handles
31             namespacs, and how to add your own custom ones. It also serves as the
32             storage bin for all of the Namespace information Net::XMPP3 requires.
33              
34             =head1 DESCRIPTION
35              
36             XMPP as a protocol is very well defined. There are three main top
37             level packets (message, iq, and presence). There is also a way to
38             extend the protocol in a very clear and strucutred way, via namespaces.
39              
40             Two major ways that namespaces are used in Jabber is for making the
41             a generic wrapper, and as a way for adding data to any packet via
42             a child tag . We will use to represent the packet, but in
43             reality it could be any child tag: , , , etc.
44              
45             The Info/Query packet uses namespaces to determine the type of
46             information to access. Usually there is a tag in the
47             that represents the namespace, but in fact it can be any tag. The
48             definition of the Query portion, is the first tag that has a namespace.
49              
50            
51              
52             or
53              
54            
55              
56             After that Query stanza can be any number of other stanzas ( tags)
57             you want to include. The Query packet is represented and available by
58             calling GetQuery() or GetChild(), and the other namespaces are
59             available by calling GetChild().
60              
61             The X tag is just a way to piggy back data on other packets. Like
62             embedding the timestamp for a message using jabber:x:delay, or signing
63             you presence for encryption using jabber:x:signed.
64              
65             To this end, Net::XMPP3 has sought to find a way to easily, and clearly
66             define the functions needed to access the XML for a namespace. We will
67             go over the full docs, and then show two examples of real namespaces so
68             that you can see what we are talking about.
69              
70             =head2 Overview
71              
72             To avoid a lot of nasty modules populating memory that are not used,
73             and to avoid having to change 15 modules when a minor change is
74             introduced, the Net::XMPP3 modules have taken AUTOLOADing to the
75             extreme. Namespaces.pm is nothing but a set of function calls that
76             generates a big hash of hashes. The hash is accessed by the Stanza.pm
77             AUTOLOAD function to do something. (This will make sense, I promise.)
78              
79             Before going on, I highly suggest you read a Perl book on AUTOLOAD and
80             how it works. From this point on I will assume that you understand it.
81              
82             When you create a Net::XMPP3::IQ object and add a Query to it (NewChild)
83             several things are happening in the background. The argument to
84             NewChild is the namespace you want to add. (custom-namespace)
85              
86             Now that you have a Query object to work with you will call the GetXXX
87             functions, and SetXXX functions to set the data. There are no defined
88             GetXXX and SetXXXX functions. You cannot look in the Namespaces.pm
89             file and find them. Instead you will find something like this:
90              
91             &add_ns(ns => "mynamespace",
92             tag => "mytag",
93             xpath => {
94             JID => { type=>'jid', path => '@jid' },
95             Username => { path => 'username/text()' },
96             Test => { type => 'master' }
97             }
98             );
99              
100             When the GetUsername() function is called, the AUTOLOAD function looks
101             in the Namespaces.pm hash for a "Username" key. Based on the "type" of
102             the field (scalar being the default) it will use the "path" as an XPath
103             to retrieve the data and call the XPathGet() method in Stanza.pm.
104              
105             Confused yet?
106              
107             =head2 Net::XMPP3 private namespaces
108              
109             Now this is where this starts to get a little sticky. When you see a
110             namespace with __netxmpp__, or __netjabber__ from Net::Jabber, at the
111             beginning it is usually something custom to Net::XMPP3 and NOT part of
112             the actual XMPP protocol.
113              
114             There are some places where the structure of the XML allows for
115             multiple children with the same name. The main places you will see
116             this behavior is where you have multiple tags with the same name and
117             those have children under them (jabber:iq:roster).
118              
119             In jabber:iq:roster, the tag can be repeated multiple times,
120             and is sort of like a mini-namespace in itself. To that end, we treat
121             it like a seperate namespace and defined a __netxmpp__:iq:roster:item
122             namespace to hold it. What happens is this, in my code I define that
123             the s tag is "item" and anything with that tag name is to create
124             a new Net::XMPP3::Stanza object with the namespace
125             __netxmpp__:iq:roster:item which then becomes a child of the
126             jabber:iq:roster Stanza object. Also, when you want to add a new item
127             to a jabber:iq:roster project you call NewQuery with the private
128             namespace.
129              
130             I know this sounds complicated. And if after reading this entire
131             document it is still complicated, email me, ask questions, and I will
132             monitor it and adjust these docs to answer the questions that people
133             ask.
134              
135             =head2 add_ns()
136              
137             To repeat, here is an example call to add_ns():
138              
139             &add_ns(ns => "mynamespace",
140             tag => "mytag",
141             xpath => {
142             JID => { type=>'jid', path => '@jid' },
143             Username => { path => 'username/text()' },
144             Test => { type => 'master' }
145             }
146             );
147              
148             ns - This is the new namespace that you are trying to add.
149              
150             tag - This is the root tag to use for objects based on this namespace.
151              
152             xpath - The hash reference passed in the add_ns call to each name of
153             entry tells Net::XMPP3 how to handle subsequent GetXXXX(), SetXXXX(),
154             DefinedXXXX(), RemoveXXXX(), AddXXXX() calls. The basic options you
155             can pass in are:
156              
157             type - This tells Stanza how to handle the call. The possible
158             values are:
159              
160             array - The value to set and returned is an an array
161             reference. For example, in jabber:iq:roster.
162              
163             child - This tells Stanza that it needs to look for the
164             __netxmpp__ style namesapced children. AddXXX() adds
165             a new child, and GetXXX() will return a new Stanza
166             object representing the packet.
167              
168             flag - This is for child elements that are tags by themselves:
169             . Since the presence of the tag is what is
170             important, and there is no cdata to store, we just call
171             it a flag.
172              
173             jid - The value is a Jabber ID. GetXXX() will return a
174             Net::XMPP3::JID object unless you pass it "jid", then it
175             returns a string.
176              
177             master - The GetXXX() and SetXXX() calls return and take a
178             hash representing all of the GetXXX() and SetXXX()
179             calls. For example:
180              
181             SetTest(foo=>"bar",
182             bar=>"baz");
183              
184             Translates into:
185              
186             SetFoo("bar");
187             SetBar("baz");
188              
189             GetTest() would return a hash containing what the
190             packet contains:
191              
192             { foo=>"bar", bar=>"baz" }
193              
194             raw - This will stick whatever raw XML you specify directly
195             into the Stanza at the point where the path specifies.
196              
197             scalar - This will set and get a scalar value. This is the
198             main workhorse as attributes and CDATA is represented
199             by a scalar. This is the default setting if you do
200             not provide one.
201              
202             special - The special type is unique in that instead of a
203             string "special", you actually give it an array:
204              
205             [ "special" , ]
206              
207             This allows Net::XMPP3 to be able to handle the
208             SetXXXX() call in a special manner according to your
209             choosing. Right now this is mainly used by
210             jabber:iq:time to automatically set the time info in
211             the correct format, and jabber:iq:version to set the
212             machine OS and add the Net::Jabber version to the
213             return packet. You will likely NOT need to use
214             this, but I wanted to mention it.
215              
216             timestamp - If you call SetXXX() but do not pass it anything,
217             or pass it "", then Net::XMPP3 will place a
218             timestamp in the xpath location.
219              
220             path - This is the XPath path to where the bit data lives. The
221             difference. Now, this is not full XPath due to the nature
222             of how it gets used. Instead of providing a rooted path
223             all the way to the top, it's a relative path ignoring what
224             the parent is. For example, if the "tag" you specified was
225             "foo", and the path is "bar/text()", then the XPath will be
226             rooted in the XML of the packet. It will set and get
227             the CDATA from:
228              
229             xxxxx
230              
231             For a flag and a child type, just specify the child element.
232             Take a look at the code in this file for more help on what
233             this means. Also, read up on XPath if you don't already know
234             what it is.
235              
236             child - This is a hash reference that tells Net::XMPP3 how to handle
237             adding and getting child objects. The keys for the hash are
238             as follows:
239              
240             ns - the real or custom (__netxmpp__) namesapce to use for
241             this child packet.
242              
243             skip_xmlns => 1 - this tells Net::XMPP3 not to add an
244             xmlns='' into the XML for the child
245             object.
246              
247             specify_name => 1 - allows you to call NewChild("ns","tag")
248             and specify the tag to use for the child
249             object. This, IMHO, is BAD XML
250             practice. You should always know what
251             the tag of the child is and use an
252             attribute or CDATA to change the type
253             of the stanza. You do not want to use
254             this.
255              
256             tag - If you use specify_name, then this is the default tag
257             to use. You do not want to use this.
258              
259             calls - Array reference telling Net::XMPP3 what functions to create
260             for this name. For most of the types above you will get
261             Get, Set, Defined, and Remove. For child types you need to
262             decide how you API will look and specify them yourself:
263              
264             ["Get","Defined"]
265             ["Add"]
266             ["Get","Add","Defined"]
267              
268             It all depends on how you want your API to look.
269              
270             Once more... The following:
271              
272             &add_ns(ns => "mynamespace",
273             tag => "mytag",
274             xpath => {
275             JID => { type=>'jid', path => '@jid' },
276             Username => { path => 'username/text()' },
277             Test => { type => 'master' }
278             }
279             );
280              
281             generates the following API calls:
282              
283             GetJID()
284             SetJID()
285             DefinedJID()
286             RemoveJID()
287             GetUsername()
288             SetUsername()
289             DefinedUsername()
290             RemoveUsername()
291             GetTest()
292             SetTest()
293              
294             =head2 Wrap Up
295              
296             Well. I hope that I have not scared you off from writing a custom
297             namespace for you application and use Net::XMPP3. Look in the
298             Net::XMPP3::Protocol manpage for an example on using the add_ns()
299             function to register your custom namespace so that Net::XMPP3 can
300             properly handle it.
301              
302             =head1 AUTHOR
303              
304             Ryan Eatmon
305              
306             =head1 COPYRIGHT
307              
308             This module is free software, you can redistribute it and/or modify it
309             under the LGPL.
310              
311             =cut
312              
313 11     11   55 use vars qw ( %NS %SKIPNS );
  11         20  
  11         8238  
314              
315             $SKIPNS{'__netxmpp__'} = 1;
316              
317             #------------------------------------------------------------------------------
318             # __netxmpp__:child:test
319             #------------------------------------------------------------------------------
320             {
321             &add_ns(ns => "__netxmpptest__:child:test",
322             tag => "test",
323             xpath => {
324             Bar => { path => 'bar/text()' },
325             Foo => { path => '@foo' },
326             Test => { type => 'master' }
327             }
328             );
329             }
330              
331             #------------------------------------------------------------------------------
332             # __netxmpp__:child:test:two
333             #------------------------------------------------------------------------------
334             {
335             &add_ns(ns => "__netxmpptest__:child:test:two",
336             tag => "test",
337             xpath => {
338             Bob => { path => 'owner/@bob' },
339             Joe => { path => 'joe/text()' },
340             Test => { type => 'master' }
341             }
342             );
343             }
344              
345             #-----------------------------------------------------------------------------
346             # urn:ietf:params:xml:ns:xmpp-bind
347             #-----------------------------------------------------------------------------
348             {
349             &add_ns(ns => "urn:ietf:params:xml:ns:xmpp-bind",
350             tag => "bind",
351             xpath => {
352             JID => { type => 'jid',
353             path => 'jid/text()',
354             },
355             Resource => { path => 'resource/text()' },
356             Bind => { type => 'master' },
357             },
358             docs => {
359             module => 'Net::XMPP3',
360             },
361             );
362             }
363              
364             #-----------------------------------------------------------------------------
365             # urn:ietf:params:xml:ns:xmpp-session
366             #-----------------------------------------------------------------------------
367             {
368             &add_ns(ns => "urn:ietf:params:xml:ns:xmpp-session",
369             tag => "session",
370             xpath => { Session => { type => 'master' } },
371             docs => {
372             module => 'Net::XMPP3',
373             },
374             );
375             }
376              
377             #-----------------------------------------------------------------------------
378             # jabber:iq:auth
379             #-----------------------------------------------------------------------------
380             {
381             &add_ns(ns => "jabber:iq:auth",
382             tag => "query",
383             xpath => {
384             Digest => { path => 'digest/text()' },
385             Hash => { path => 'hash/text()' },
386             Password => { path => 'password/text()' },
387             Resource => { path => 'resource/text()' },
388             Sequence => { path => 'sequence/text()' },
389             Token => { path => 'token/text()' },
390             Username => { path => 'username/text()' },
391             Auth => { type => 'master' },
392             },
393             docs => {
394             module => 'Net::XMPP3',
395             },
396             );
397             }
398              
399             #-----------------------------------------------------------------------------
400             # jabber:iq:privacy
401             #-----------------------------------------------------------------------------
402             {
403             &add_ns(ns => "jabber:iq:privacy",
404             tag => "query",
405             xpath => {
406             Active => { path => 'active/@name' },
407             Default => { path => 'default/@name' },
408             List => {
409             type => 'child',
410             path => 'list',
411             child => { ns => '__netxmpp__:iq:privacy:list', },
412             calls => [ 'Add' ],
413             },
414             Lists => {
415             type => 'child',
416             path => 'list',
417             child => { ns => '__netxmpp__:iq:privacy:list', },
418             },
419             Privacy => { type => 'master' },
420             },
421             docs => {
422             module => 'Net::XMPP3',
423             },
424             );
425             }
426              
427             #-----------------------------------------------------------------------------
428             # __netxmpp__:iq:privacy:list
429             #-----------------------------------------------------------------------------
430             {
431             &add_ns(ns => '__netxmpp__:iq:privacy:list',
432             xpath => {
433             Name => { path => '@name' },
434             Item => {
435             type => 'child',
436             path => 'item',
437             child => { ns => '__netxmpp__:iq:privacy:list:item', },
438             calls => [ 'Add' ],
439             },
440             Items => {
441             type => 'child',
442             path => 'item',
443             child => { ns => '__netxmpp__:iq:privacy:item', },
444             },
445             List => { type => 'master' },
446             },
447             docs => {
448             module => 'Net::XMPP3',
449             name => 'jabber:iq:privacy - list objects',
450             },
451             );
452             }
453              
454             #-----------------------------------------------------------------------------
455             # __netxmpp__:iq:privacy:list:item
456             #-----------------------------------------------------------------------------
457             {
458             &add_ns(ns => '__netxmpp__:iq:privacy:list:item',
459             xpath => {
460             Action => { path => '@action' },
461             IQ => {
462             type => 'flag',
463             path => 'iq',
464             },
465             Message => {
466             type => 'flag',
467             path => 'message',
468             },
469             Order => { path => '@order' },
470             PresenceIn => {
471             type => 'flag',
472             path => 'presence-in',
473             },
474             PresenceOut => {
475             type => 'flag',
476             path => 'presence-out',
477             },
478             Type => { path => '@type' },
479             Value => { path => '@value' },
480             Item => { type => 'master' },
481             },
482             docs => {
483             module => 'Net::XMPP3',
484             name => 'jabber:iq:privacy - item objects',
485             },
486             );
487             }
488              
489             #-----------------------------------------------------------------------------
490             # jabber:iq:register
491             #-----------------------------------------------------------------------------
492             {
493             &add_ns(ns => "jabber:iq:register",
494             tag => "query",
495             xpath => {
496             Address => { path => 'address/text()' },
497             City => { path => 'city/text()' },
498             Date => { path => 'date/text()' },
499             Email => { path => 'email/text()' },
500             First => { path => 'first/text()' },
501             Instructions => { path => 'instructions/text()' },
502             Key => { path => 'key/text()' },
503             Last => { path => 'last/text()' },
504             Misc => { path => 'misc/text()' },
505             Name => { path => 'name/text()' },
506             Nick => { path => 'nick/text()' },
507             Password => { path => 'password/text()' },
508             Phone => { path => 'phone/text()' },
509             Registered => {
510             type => 'flag',
511             path => 'registered',
512             },
513             Remove => {
514             type => 'flag',
515             path => 'remove',
516             },
517             State => { path => 'state/text()' },
518             Text => { path => 'text/text()' },
519             URL => { path => 'url/text()' },
520             Username => { path => 'username/text()' },
521             Zip => { path => 'zip/text()' },
522             Register => { type => 'master' },
523             },
524             docs => {
525             module => 'Net::XMPP3',
526             },
527             );
528             }
529              
530             #-----------------------------------------------------------------------------
531             # jabber:iq:roster
532             #-----------------------------------------------------------------------------
533             {
534             &add_ns(ns => 'jabber:iq:roster',
535             tag => "query",
536             xpath => {
537             Item => {
538             type => 'child',
539             path => 'item',
540             child => { ns => '__netxmpp__:iq:roster:item', },
541             calls => [ 'Add' ],
542             },
543             Items => {
544             type => 'child',
545             path => 'item',
546             child => { ns => '__netxmpp__:iq:roster:item', },
547             calls => [ 'Get' ],
548             },
549             Roster => { type => 'master' },
550             },
551             docs => {
552             module => 'Net::XMPP3',
553             },
554             );
555             }
556              
557             #-----------------------------------------------------------------------------
558             # __netxmpp__:iq:roster:item
559             #-----------------------------------------------------------------------------
560             {
561             &add_ns(ns => "__netxmpp__:iq:roster:item",
562             xpath => {
563             Ask => { path => '@ask' },
564             Group => {
565             type => 'array',
566             path => 'group/text()',
567             },
568             JID => {
569             type => 'jid',
570             path => '@jid',
571             },
572             Name => { path => '@name' },
573             Subscription => { path => '@subscription' },
574             Item => { type => 'master' },
575             },
576             docs => {
577             module => 'Net::XMPP3',
578             name => 'jabber:iq:roster - item objects',
579             },
580             );
581             }
582              
583              
584              
585             sub add_ns
586             {
587 121     121 1 318 my (%args) = @_;
588              
589             # XXX error check...
590              
591 121 100       466 $NS{$args{ns}}->{tag} = $args{tag} if exists($args{tag});
592 121         281 $NS{$args{ns}}->{xpath} = $args{xpath};
593 121 100       286 if (exists($args{docs}))
594             {
595 99         228 $NS{$args{ns}}->{docs} = $args{docs};
596 99 100       446 $NS{$args{ns}}->{docs}->{name} = $args{ns}
597             unless exists($args{docs}->{name});
598             }
599             }
600              
601              
602             1;