File Coverage

blib/lib/Net/XMPP3/Stanza.pm
Criterion Covered Total %
statement 323 422 76.5
branch 146 228 64.0
condition 48 108 44.4
subroutine 29 36 80.5
pod 0 13 0.0
total 546 807 67.6


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::Stanza;
23              
24             =head1 NAME
25              
26             Net::XMPP3::Stanza - XMPP Stanza Module
27              
28             =head1 SYNOPSIS
29              
30             Net::XMPP3::Stanza is a private package that serves as a basis for all
31             XMPP stanzas generated by Net::XMPP3.
32              
33             =head1 DESCRIPTION
34              
35             This module is not meant to be used directly. You should be using
36             either Net::XMPP3::IQ, Net::XMPP3::Message, Net::XMPP3::Presence, or
37             another package that inherits from Net::XMPP3::Stanza.
38              
39             That said, this is where all of the namespaced methods are documented.
40              
41             The current supported namespaces are:
42              
43             =cut
44              
45             # NS_BEGIN
46              
47             =pod
48              
49             jabber:iq:auth
50             jabber:iq:privacy
51             jabber:iq:register
52             jabber:iq:roster
53             urn:ietf:params:xml:ns:xmpp-bind
54             urn:ietf:params:xml:ns:xmpp-session
55              
56             =cut
57              
58             # NS_END
59              
60             =pod
61              
62             For more information on what these namespaces are for, visit
63             http://www.jabber.org and browse the Jabber Programmers Guide.
64              
65             The following tables can be read as follows:
66              
67             ny:private:ns
68              
69             Name Type Get Set Remove Defined Add
70             ========================== ======= === === ====== ======= ===
71             Foo scalar X X X X
72             Bar child X
73             Bars child X
74             Test master X X
75              
76             Withing the my:private:ns namespace, there exists the functions:
77              
78             GetFoo(), SetFoo(), RemoveFoo(), DefinedFoo()
79              
80             AddBar()
81              
82             GetBars(), DefinedBars()
83              
84             GetTest(), SetMaster()
85              
86             Hopefully it should be obvious how this all works. If not feel free to
87             contact me and I'll work on adding more documentation.
88              
89             =cut
90              
91             # DOC_BEGIN
92             =head1 jabber:iq:auth
93              
94             Name Type Get Set Remove Defined Add
95             ========================== ========= === === ====== ======= ===
96             Digest scalar X X X X
97             Hash scalar X X X X
98             Password scalar X X X X
99             Resource scalar X X X X
100             Sequence scalar X X X X
101             Token scalar X X X X
102             Username scalar X X X X
103             Auth master X X
104              
105             =head1 jabber:iq:privacy
106              
107             Name Type Get Set Remove Defined Add
108             ========================== ========= === === ====== ======= ===
109             Active scalar X X X X
110             Default scalar X X X X
111             List child X
112             Lists child X X X
113             Privacy master X X
114              
115             =head1 jabber:iq:privacy - item objects
116              
117             Name Type Get Set Remove Defined Add
118             ========================== ========= === === ====== ======= ===
119             Action scalar X X X X
120             IQ flag X X X X
121             Message flag X X X X
122             Order scalar X X X X
123             PresenceIn flag X X X X
124             PresenceOut flag X X X X
125             Type scalar X X X X
126             Value scalar X X X X
127             Item master X X
128              
129             =head1 jabber:iq:privacy - list objects
130              
131             Name Type Get Set Remove Defined Add
132             ========================== ========= === === ====== ======= ===
133             Name scalar X X X X
134             Item child X
135             Items child X X X
136             List master X X
137              
138             =head1 jabber:iq:register
139              
140             Name Type Get Set Remove Defined Add
141             ========================== ========= === === ====== ======= ===
142             Address scalar X X X X
143             City scalar X X X X
144             Date scalar X X X X
145             Email scalar X X X X
146             First scalar X X X X
147             Instructions scalar X X X X
148             Key scalar X X X X
149             Last scalar X X X X
150             Misc scalar X X X X
151             Name scalar X X X X
152             Nick scalar X X X X
153             Password scalar X X X X
154             Phone scalar X X X X
155             Registered flag X X X X
156             Remove flag X X X X
157             State scalar X X X X
158             Text scalar X X X X
159             URL scalar X X X X
160             Username scalar X X X X
161             Zip scalar X X X X
162             Register master X X
163              
164             =head1 jabber:iq:roster
165              
166             Name Type Get Set Remove Defined Add
167             ========================== ========= === === ====== ======= ===
168             Item child X
169             Items child X
170             Roster master X X
171              
172             =head1 jabber:iq:roster - item objects
173              
174             Name Type Get Set Remove Defined Add
175             ========================== ========= === === ====== ======= ===
176             Ask scalar X X X X
177             Group array X X X X
178             JID jid X X X X
179             Name scalar X X X X
180             Subscription scalar X X X X
181             Item master X X
182              
183             =head1 urn:ietf:params:xml:ns:xmpp-bind
184              
185             Name Type Get Set Remove Defined Add
186             ========================== ========= === === ====== ======= ===
187             JID jid X X X X
188             Resource scalar X X X X
189             Bind master X X
190              
191             =head1 urn:ietf:params:xml:ns:xmpp-session
192              
193             Name Type Get Set Remove Defined Add
194             ========================== ========= === === ====== ======= ===
195             Session master X X
196              
197              
198             =cut
199              
200             # DOC_END
201              
202             =head1 AUTHOR
203              
204             Ryan Eatmon
205              
206             =head1 COPYRIGHT
207              
208             This module is free software, you can redistribute it and/or modify it
209             under the LGPL.
210              
211             =cut
212              
213 11     11   56 use strict;
  11         19  
  11         383  
214 11     11   57 use Carp;
  11         13  
  11         678  
215 11     11   56 use Net::XMPP3::Namespaces;
  11         20  
  11         483  
216 11     11   50 use vars qw( $AUTOLOAD %FUNCTIONS $DEBUG );
  11         43  
  11         59788  
217              
218             $DEBUG = new Net::XMPP3::Debug(usedefault=>1,
219             header=>"XMPP");
220              
221             # XXX need to look at evals and $@
222              
223             sub new
224             {
225 15     15 0 704 my $proto = shift;
226 15   33     92 my $class = ref($proto) || $proto;
227 15         39 my $self = { };
228              
229 15         48 bless($self, $proto);
230              
231 15         77 $self->{DEBUGHEADER} = "Stanza";
232 15         35 $self->{TAG} = "__netxmpp__:unknown:tag";
233              
234 15         109 $self->{FUNCS} = \%FUNCTIONS;
235              
236 15         66 my $result = $self->_init(@_);
237              
238 15 50       61 return $result if defined($result);
239              
240 15         44 return $self;
241             }
242              
243              
244             sub _init
245             {
246 26     26   54 my $self = shift;
247              
248 26         85 $self->{CHILDREN} = [];
249              
250 26 100       132 if ("@_" ne (""))
251             {
252 15 50       177 if ($_[0]->isa("Net::XMPP3::Stanza"))
    100          
253             {
254 0         0 return $_[0];
255             }
256             elsif (ref($_[0]) eq "")
257             {
258 3         7 $self->{TAG} = shift;
259 3         34 $self->{TREE} = new XML::Stream::Node($self->{TAG});
260             }
261             else
262             {
263 12         38 $self->{TREE} = shift;
264 12         48 $self->{TAG} = $self->{TREE}->get_tag();
265 12         114 $self->_parse_xmlns();
266 12         359 $self->_parse_tree();
267             }
268             }
269             else
270             {
271 11         303 $self->{TREE} = new XML::Stream::Node($self->{TAG});
272             }
273              
274 26         413 return;
275             }
276              
277              
278             $FUNCTIONS{XMLNS}->{path} = '@xmlns';
279              
280             $FUNCTIONS{Child}->{type} = 'child';
281             $FUNCTIONS{Child}->{path} = '*[@xmlns]';
282             $FUNCTIONS{Child}->{child} = {};
283              
284             ##############################################################################
285             #
286             # debug - prints out the XML::Parser Tree in a readable format for debugging
287             #
288             ##############################################################################
289             sub debug
290             {
291 0     0 0 0 my $self = shift;
292              
293 0         0 print "debug ",$self,":\n";
294 0         0 &Net::XMPP3::printData("debug: \$self->{CHILDREN}->",$self->{CHILDREN});
295             }
296              
297              
298             ##############################################################################
299             #+----------------------------------------------------------------------------
300             #|
301             #| Public Methods
302             #|
303             #+----------------------------------------------------------------------------
304             ##############################################################################
305              
306             ##############################################################################
307             #
308             # GetXML - Returns a string that represents the packet.
309             #
310             ##############################################################################
311             sub GetXML
312             {
313 24     24 0 5229 my $self = shift;
314 24         114 return $self->GetTree()->GetXML();
315             }
316              
317              
318             ##############################################################################
319             #
320             # GetTag - Returns the root tag of the object.
321             #
322             ##############################################################################
323             sub GetTag
324             {
325 0     0 0 0 my $self = shift;
326              
327 0         0 return $self->{TAG};
328             }
329              
330              
331             ##############################################################################
332             #
333             # GetTree - Returns an XML::Stream::Node that contains the full tree including
334             # Query, and X children.
335             #
336             ##############################################################################
337             sub GetTree
338             {
339 49     49 0 75 my $self = shift;
340 49         76 my $keepXMLNS = shift;
341 49 100       130 $keepXMLNS = 0 unless defined($keepXMLNS);
342              
343 49         193 my $node = $self->{TREE}->copy();
344              
345 49 50 33     6328 $node->remove_attrib("xmlns")
346             if (exists($self->{SKIPXMLNS}) && ($keepXMLNS == 0));
347              
348 49         72 foreach my $child (@{$self->{CHILDREN}})
  49         131  
349             {
350 10         58 my $child_tree = $child->GetTree($keepXMLNS);
351 10         45 $node->add_child($child_tree);
352             }
353              
354 49         169 my $remove_ns = 0;
355 49 100 100     139 if (defined($node->get_attrib("xmlns")) && ($keepXMLNS == 0))
356             {
357 19 100       222 $remove_ns = 1
358             if ($self->_check_skip_xmlns($node->get_attrib("xmlns")));
359             }
360              
361 49 100       579 $node->remove_attrib("xmlns") if ($remove_ns == 1);
362              
363 6         25 $node->add_raw_xml(@{$self->{RAWXML}})
  7         50  
364 49 100 100     239 if (exists($self->{RAWXML}) && ($#{$self->{RAWXML}} > -1));
365              
366 49         199 return $node;
367             }
368              
369              
370             ##############################################################################
371             #
372             # NewChild - calls AddChild to create a new Net::XMPP3::Stanza object, sets the
373             # xmlns and returns a pointer to the new object.
374             #
375             ##############################################################################
376             sub NewChild
377             {
378 9     9 0 3017 my $self = shift;
379 9         20 my $xmlns = shift;
380 9         16 my $tag = shift;
381              
382 9 50       45 return unless exists($Net::XMPP3::Namespaces::NS{$xmlns});
383              
384 9 50       28 if (!defined($tag))
385             {
386 9         14 $tag = "x";
387 9 50       48 $tag = $Net::XMPP3::Namespaces::NS{$xmlns}->{tag}
388             if exists($Net::XMPP3::Namespaces::NS{$xmlns});
389             }
390              
391 9         48 my $node = new XML::Stream::Node($tag);
392 9         210 $node->put_attrib(xmlns=>$xmlns);
393              
394 9         135 return $self->AddChild($node);
395             }
396              
397              
398             ##############################################################################
399             #
400             # AddChild - creates a new Net::XMPP3::packet object, pushes it on the child
401             # list, and returns a pointer to the new object. This is a
402             # private helper function.
403             #
404             ##############################################################################
405             sub AddChild
406             {
407 12     12 0 26 my $self = shift;
408 12         19 my $node = shift;
409 12         67 my $packet = $self->_new_packet($node);
410 12         22 push(@{$self->{CHILDREN}},$packet);
  12         52  
411 12         39 return $packet;
412             }
413              
414              
415             ##############################################################################
416             #
417             # RemoveChild - removes all xtags that have the specified namespace.
418             #
419             ##############################################################################
420             sub RemoveChild
421             {
422 1     1 0 637 my $self = shift;
423 1         2 my $xmlns = shift;
424              
425 1         3 foreach my $index (reverse(0..$#{$self->{CHILDREN}}))
  1         5  
426             {
427 1 50 33     15 splice(@{$self->{CHILDREN}},$index,1)
  1   33     8  
428             if (!defined($xmlns) ||
429             ($xmlns eq "") ||
430             ($self->{CHILDREN}->[$index]->GetXMLNS() eq $xmlns));
431             }
432             }
433              
434              
435             ##############################################################################
436             #
437             # NewFirstChild - calls AddFirstChild to create a new Net::XMPP3::Stanza
438             # object, sets the xmlns and returns a pointer to the new
439             # object.
440             #
441             ##############################################################################
442             sub NewFirstChild
443             {
444 0     0 0 0 my $self = shift;
445 0         0 my $xmlns = shift;
446 0         0 my $tag = shift;
447              
448 0 0       0 return unless exists($Net::XMPP3::Namespaces::NS{$xmlns});
449              
450 0 0       0 if (!defined($tag))
451             {
452 0         0 $tag = "x";
453 0 0       0 $tag = $Net::XMPP3::Namespaces::NS{$xmlns}->{tag}
454             if exists($Net::XMPP3::Namespaces::NS{$xmlns});
455             }
456              
457 0         0 my $node = new XML::Stream::Node($tag);
458 0         0 $node->put_attrib(xmlns=>$xmlns);
459              
460 0         0 return $self->AddFirstChild($node);
461             }
462              
463              
464             ##############################################################################
465             #
466             # AddFirstChild - creates a new Net::XMPP3::packet object, puts it on the child
467             # list in the front, and returns a pointer to the new object.
468             # This is a private helper function.
469             #
470             ##############################################################################
471             sub AddFirstChild
472             {
473 0     0 0 0 my $self = shift;
474 0         0 my $node = shift;
475 0         0 my $packet = $self->_new_packet($node);
476 0         0 unshift(@{$self->{CHILDREN}},$packet);
  0         0  
477 0         0 return $packet;
478             }
479              
480              
481             ##############################################################################
482             #
483             # RemoveFirstChild - removes all xtags that have the specified namespace.
484             #
485             ##############################################################################
486             sub RemoveFirstChild
487             {
488 0     0 0 0 my $self = shift;
489              
490 0         0 shift(@{$self->{CHILDREN}});
  0         0  
491             }
492              
493              
494             ##############################################################################
495             #
496             # InsertRawXML - puts the specified string onto the list for raw XML to be
497             # included in the packet.
498             #
499             ##############################################################################
500             sub InsertRawXML
501             {
502 5     5 0 7311 my $self = shift;
503 5         15 my(@rawxml) = @_;
504 5 100       16 if (!exists($self->{RAWXML}))
505             {
506 3         9 $self->{RAWXML} = [];
507             }
508 5         9 push(@{$self->{RAWXML}},@rawxml);
  5         18  
509             }
510              
511              
512             ##############################################################################
513             #
514             # ClearRawXML - removes all raw XML from the packet.
515             #
516             ##############################################################################
517             sub ClearRawXML
518             {
519 1     1 0 610 my $self = shift;
520 1         4 $self->{RAWXML} = [];
521             }
522              
523              
524              
525              
526             ##############################################################################
527             #+----------------------------------------------------------------------------
528             #|
529             #| AutoLoad methods
530             #|
531             #+----------------------------------------------------------------------------
532             ##############################################################################
533              
534             ##############################################################################
535             #
536             # AutoLoad - This function is a central location for handling all of the
537             # AUTOLOADS for all of the sub modules.
538             #
539             ##############################################################################
540             sub AUTOLOAD
541             {
542 591     591   161185 my $self = shift;
543 591 50       1810 return if ($AUTOLOAD =~ /::DESTROY$/);
544 591         2764 my ($package) = ($AUTOLOAD =~ /^(.*)::/);
545 591         2301 $AUTOLOAD =~ s/^.*:://;
546 591         2777 my ($call,$var) = ($AUTOLOAD =~ /^(Add|Get|Set|Remove|Defined)(.*)$/);
547 591 50       1822 $call = "" unless defined($call);
548 591 50       1217 $var = "" unless defined($var);
549              
550             #$self->_debug("AUTOLOAD: self($self) AUTOLOAD($AUTOLOAD) package($package)");
551             #$self->_debug("AUTOLOAD: tag($self->{TAG}) call($call) var($var) args(",join(",",@_),")");
552              
553             #-------------------------------------------------------------------------
554             # Pick off calls for top level tags , , and
555             #-------------------------------------------------------------------------
556 591         3102 my @xmlns = $self->{TREE}->XPath('@xmlns');
557 591         253403 my $XPathArgs = $self->_xpath_AUTOLOAD($package,$call,$var,$xmlns[0]);
558 591 50       1682 return $self->_xpath($call,@{$XPathArgs},@_) if defined($XPathArgs);
  591         2368  
559              
560             #-------------------------------------------------------------------------
561             # We don't know what this function is... Hand it off to Missing Persons...
562             #-------------------------------------------------------------------------
563 0         0 $self->_missing_function($AUTOLOAD);
564             }
565              
566              
567             ##############################################################################
568             #
569             # _xpath_AUTOLOAD - This function is a helper function for the main AutoLoad
570             # function to help cut down on repeating code.
571             #
572             ##############################################################################
573             sub _xpath_AUTOLOAD
574             {
575 591     591   855 my $self = shift;
576 591         3078 my $package = shift;
577 591         949 my $call = shift;
578 591         768 my $var = shift;
579 591         988 my $xmlns = shift;
580              
581 591         3092 $self->_debug("_xpath_AUTOLOAD: self($self) package($package) call($call) var($var)");
582 591 100       2018 $self->_debug("_xpath_AUTOLOAD: xmlns($xmlns)") if defined($xmlns);
583              
584             #-------------------------------------------------------------------------
585             # First thing, figure out which group of functions we are going to be
586             # working with. FUNCTIONS, or NS{$xmlns}->{xpath}...
587             #-------------------------------------------------------------------------
588 591         1624 my $funcs = $self->_xpath_funcs($package,$call,$var,$xmlns);
589 591 50       2901 return unless defined($funcs);
590              
591 591         653 my @setFuncs = grep { $_ ne $var } keys(%{$funcs});
  5538         10967  
  591         2096  
592              
593             #$self->_debug("_xpath_AUTOLOAD: setFuncs(",join(",",@setFuncs),")");
594              
595              
596 591 100       2272 my $type = (exists($funcs->{$var}->{type}) ?
597             $funcs->{$var}->{type} :
598             "scalar"
599             );
600              
601 591 100       1767 my $path = (exists($funcs->{$var}->{path}) ?
602             $funcs->{$var}->{path} :
603             ""
604             );
605              
606 591 50       1547 $path = "*" if ($type eq "raw");
607              
608 591         891 my $child = "";
609              
610             #-------------------------------------------------------------------------
611             # When this is a master function... change the above variables...
612             #-------------------------------------------------------------------------
613 591 100 33     3831 if(($type eq "master") ||
    100 66        
614             ((ref($type) eq "ARRAY") && ($type->[0] eq "master")))
615             {
616 13 50       45 if ($call eq "Get")
617             {
618 0         0 my @newSetFuncs;
619 0         0 foreach my $func (@setFuncs)
620             {
621 0 0       0 my $funcType = ( exists($funcs->{$func}->{type}) ?
622             $funcs->{$func}->{type} :
623             undef
624             );
625              
626 0 0 0     0 push(@newSetFuncs,$func)
      0        
      0        
      0        
      0        
      0        
627             if (!defined($funcType) || ($funcType eq "scalar") ||
628             ($funcType eq "jid") || ($funcType eq "array") ||
629             ($funcType eq "flag") || ($funcType eq "timestamp") ||
630             (ref($funcType) eq "ARRAY"));
631             }
632              
633 0         0 $child = \@newSetFuncs;
634             }
635             else
636             {
637 13         27 $child = \@setFuncs;
638             }
639             }
640             #-------------------------------------------------------------------------
641             # When this is a child based function... change the above variables...
642             #-------------------------------------------------------------------------
643             elsif (exists($funcs->{$var}->{child}))
644             {
645 33         77 $child = $funcs->{$var}->{child};
646              
647             #$self->_debug("_xpath_AUTOLOAD: child($child)");
648              
649 33 100       100 if (exists($child->{ns}))
650             {
651 4         7 my $addXMLNS = $child->{ns};
652              
653 4         13 my $addFuncs = $Net::XMPP3::Namespaces::NS{$addXMLNS}->{xpath};
654 24 100       101 my @calls =
655             grep
656             {
657 4         16 exists($addFuncs->{$_}->{type}) &&
658             ($addFuncs->{$_}->{type} eq "master")
659             }
660 4         6 keys(%{$addFuncs});
661              
662 4 50       11 if ($#calls > 0)
663             {
664 0         0 print STDERR "Warning: I cannot serve two masters.\n";
665             }
666 4         13 $child->{master} = $calls[0];
667             }
668             }
669              
670             #-------------------------------------------------------------------------
671             # Return the arguments for the xpath function
672             #-------------------------------------------------------------------------
673             #$self->_debug("_xpath_AUTOLOAD: return($type,$path,$child);");
674 591         2532 return [$type,$path,$child];
675             }
676              
677              
678             ##############################################################################
679             #
680             # _xpath_funcs - Return the list of functions either from the FUNCTIONS hash
681             # or from Net::XMPP3::Namespaces::NS.
682             #
683             ##############################################################################
684             sub _xpath_funcs
685             {
686 591     591   786 my $self = shift;
687 591         912 my $package = shift;
688 591         902 my $call = shift;
689 591         739 my $var = shift;
690 591         675 my $xmlns = shift;
691              
692 591         679 my $funcs;
693              
694 591         935 my $coreFuncs = $self->{FUNCS};
695             #eval "\$coreFuncs = \\%".$package."::FUNCTIONS";
696 591 50       1151 $coreFuncs = {} unless defined($coreFuncs);
697              
698 591         914 my $nsFuncs = {};
699 591 100 66     2293 $nsFuncs = $Net::XMPP3::Namespaces::NS{$xmlns}->{xpath}
700             if (defined($xmlns) && exists($Net::XMPP3::Namespaces::NS{$xmlns}));
701              
702 591         1042 foreach my $set ($coreFuncs,$nsFuncs)
703             {
704 1182 100       4460 if (exists($set->{$var}))
705             {
706 591 100       1799 my $type = (exists($set->{$var}->{type}) ?
707             $set->{$var}->{type} :
708             "scalar"
709             );
710              
711 591         1515 my @calls = ('Get','Set','Defined','Remove');
712 591 100       1254 @calls = ('Get','Set') if ($type eq "master");
713 591 100       1211 @calls = ('Get','Defined','Remove') if ($type eq "child");
714 591 100       1434 @calls = @{$set->{$var}->{calls}}
  4         16  
715             if exists($set->{$var}->{calls});
716              
717 591         7392 foreach my $callName (@calls)
718             {
719 1234 100       2635 if ($callName eq $call)
720             {
721 591         733 $funcs = $set;
722 591         1881 last;
723             }
724             }
725             }
726             }
727              
728             #-------------------------------------------------------------------------
729             # If we didn't find any functions to return, Return failure.
730             #-------------------------------------------------------------------------
731 591 50       1303 if (!defined($funcs))
732             {
733             #$self->_debug("_xpath_AUTOLOAD: no funcs found");
734 0         0 return;
735             }
736              
737 591         1549 return $funcs;
738             }
739              
740              
741             ##############################################################################
742             #
743             # _xpath - given a type it calls the appropriate _xpath_* function below
744             #
745             ##############################################################################
746             sub _xpath
747             {
748 591     591   1124 my $self = shift;
749 591         830 my $call = shift;
750              
751             #$self->_debug("_xpath: call($call) args(",join(",",@_),")");
752              
753 591 100       1785 if ($call eq "Get") { return $self->_xpath_get(@_) ; }
  210 100       821  
    100          
    100          
    50          
754 121         513 elsif ($call eq "Set") { return $self->_xpath_set(@_); }
755 233         938 elsif ($call eq "Defined") { return $self->_xpath_defined(@_); }
756 3         14 elsif ($call eq "Add") { return $self->_xpath_add(@_); }
757 24         97 elsif ($call eq "Remove") { return $self->_xpath_remove(@_); }
758             }
759              
760              
761             ##############################################################################
762             #
763             # _xpath_get - returns the value stored in the node
764             #
765             ##############################################################################
766             sub _xpath_get
767             {
768 210     210   281 my $self = shift;
769 210         265 my $type = shift;
770 210         256 my $xpath = shift;
771 210         280 my $childtype = shift;
772 210         313 my ($arg0) = shift;
773              
774             #$self->_debug("_xpath_get: self($self) type($type) xpath($xpath) childtype($childtype)");
775             #$self->{TREE}->debug();
776              
777 210         249 my $subType;
778 210         519 ($type,$subType) = $self->_xpath_resolve_types($type);
779              
780              
781             #-------------------------------------------------------------------------
782             # type == master
783             #-------------------------------------------------------------------------
784 210 50       550 if ($type eq "master")
785             {
786 0         0 my %fields;
787              
788 0         0 foreach my $func (sort {$a cmp $b} @{$childtype})
  0         0  
  0         0  
789             {
790 0         0 my $defined;
791 0         0 eval "\$defined = \$self->Defined$func();";
792 0 0       0 if ($defined)
793             {
794 0         0 my @values;
795 0         0 eval "\@values = \$self->Get$func();";
796              
797 0 0       0 if ($#values > 0)
798             {
799 0         0 $fields{lc($func)} = \@values;
800             }
801             else
802             {
803 0         0 $fields{lc($func)} = $values[0];
804             }
805             }
806             }
807              
808 0         0 return %fields;
809             }
810              
811             #-------------------------------------------------------------------------
812             # type == node
813             #-------------------------------------------------------------------------
814             # XXX Remove this if there are no problems
815             #if ($type eq "node")
816             #{
817             #$self->_debug("_xpath_get: node: xmlns($arg0)") if defined($arg0);
818              
819             #my @results;
820             #foreach my $child (@{$self->{CHILDREN}})
821             #{
822             #$self->_debug("_xpath_get: node: child($child)");
823             #$self->_debug("_xpath_get: node: childXML(",$child->GetXML(),")");
824              
825             #push(@results,$child)
826             # if (!defined($arg0) ||
827             # ($arg0 eq "") ||
828             # ($child->GetTree(1)->get_attrib("xmlns") eq $arg0));
829             #}
830              
831             #return $results[$childtype->{child_index}] if exists($childtype->{child_index});
832             #return @results if (wantarray);
833             #return $results[0];
834             #}
835              
836             #-------------------------------------------------------------------------
837             # The rest actually call the XPath, so call it.
838             #-------------------------------------------------------------------------
839 210         778 my @nodes = $self->{TREE}->XPath($xpath);
840              
841             #-------------------------------------------------------------------------
842             # type == scalar or timestamp
843             #-------------------------------------------------------------------------
844 210 100 66     115843 if (($type eq "scalar") || ($type eq "timestamp"))
845             {
846 133 100       368 return "" if ($#nodes == -1);
847 131         1512 return $nodes[0];
848             }
849              
850             #-------------------------------------------------------------------------
851             # type == jid
852             #-------------------------------------------------------------------------
853 77 100       219 if ($type eq "jid")
854             {
855 60 50       164 return if ($#nodes == -1);
856 60 100 66     332 return $self->_new_jid($nodes[0])
857             if (defined($arg0) && ($arg0 eq "jid"));
858 36         394 return $nodes[0];
859             }
860              
861             #-------------------------------------------------------------------------
862             # type == flag
863             #-------------------------------------------------------------------------
864 17 50       56 if ($type eq "flag")
865             {
866 0         0 return $#nodes > -1;
867             }
868              
869             #-------------------------------------------------------------------------
870             # type == array
871             #-------------------------------------------------------------------------
872 17 100       50 if ($type eq "array")
873             {
874 3 100       16 return @nodes if (wantarray);
875 1         10 return $nodes[0];
876             }
877              
878             #-------------------------------------------------------------------------
879             # type == raw
880             #-------------------------------------------------------------------------
881 14 50       40 if ($type eq "raw")
882             {
883 0         0 my $rawXML = "";
884              
885 0 0       0 return join("",@{$self->{RAWXML}}) if ($#{$self->{RAWXML}} > -1);
  0         0  
  0         0  
886              
887 0         0 foreach my $node (@nodes)
888             {
889 0         0 $rawXML .= $node->GetXML();
890             }
891              
892 0         0 return $rawXML;
893             }
894              
895             #-------------------------------------------------------------------------
896             # type == child
897             #-------------------------------------------------------------------------
898 14 50 33     76 if (($type eq "child") || ($type eq "children") || ($type eq "node"))
      33        
899             {
900 14         27 my $xmlns = $arg0;
901 14 100       38 $xmlns = $childtype->{ns} if exists($childtype->{ns});
902              
903             #$self->_debug("_xpath_get: children: xmlns($xmlns)");
904              
905 14         17 my @results;
906 14         24 foreach my $child (@{$self->{CHILDREN}})
  14         39  
907             {
908 26 100 66     253 push(@results, $child)
      100        
909             if (!defined($xmlns) ||
910             ($xmlns eq "") ||
911             ($child->GetTree(1)->get_attrib("xmlns") eq $xmlns));
912             }
913              
914 14         97 foreach my $node (@nodes)
915             {
916 0 0       0 $node->put_attrib(xmlns=>$xmlns)
917             unless defined($node->get_attrib("xmlns"));
918 0         0 my $result = $self->AddChild($node);
919 0         0 $self->{TREE}->remove_child($node);
920 0 0 0     0 push(@results,$result)
      0        
921             if (!defined($xmlns) ||
922             ($xmlns eq "") ||
923             ($node->get_attrib("xmlns") eq $xmlns));
924             }
925              
926             #$self->_debug("_xpath_get: children: ",join(",",@results));
927 14 100       57 return $results[$childtype->{child_index}] if exists($childtype->{child_index});
928 13 50       107 return @results if (wantarray);
929 0         0 return $results[0];
930             }
931             }
932              
933              
934             ##############################################################################
935             #
936             # _xpath_set - makes the XML tree such that the value was set.
937             #
938             ##############################################################################
939             sub _xpath_set
940             {
941 121     121   302 my $self = shift;
942 121         156 my $type = shift;
943 121         246 my $xpath = shift;
944 121         269 my $childtype = shift;
945              
946             #$self->_debug("_xpath_set: self($self) type($type) xpath($xpath) childtype($childtype)");
947              
948 121         141 my $subType;
949 121         285 ($type,$subType) = $self->_xpath_resolve_types($type);
950              
951 121         379 my $node = $self->{TREE};
952              
953             #$self->_debug("_xpath_set: node($node)");
954              
955             #-------------------------------------------------------------------------
956             # When the type is master, the rest of the args are in hash form
957             #-------------------------------------------------------------------------
958 121 100       340 if ($type eq "master")
959             {
960             #$self->_debug("_xpath_set: master: funcs(",join(",",@{$childtype}),")");
961 13         26 my %args;
962 13         47 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  45         192  
963             #$self->_debug("_xpath_set: args(",%args,")");
964 13         28 foreach my $func (sort {$a cmp $b} @{$childtype})
  258         325  
  13         77  
965             {
966             #$self->_debug("_xpath_set: func($func)");
967 115 100       1426 if (exists($args{lc($func)}))
    50          
968             {
969             #$self->_debug("_xpath_set: \$self->Set$func(\$args{lc(\$func)});");
970 45         3587 eval "\$self->Set$func(\$args{lc(\$func)});";
971             }
972             elsif ($subType eq "all")
973             {
974             #$self->_debug("_xpath_set: \$self->Set$func();");
975 0         0 eval "\$self->Set$func();";
976             }
977             }
978 13         182 return;
979             }
980              
981             #-------------------------------------------------------------------------
982             # When the type is not master, there can be only one argument.
983             #-------------------------------------------------------------------------
984 108         147 my $value = shift;
985              
986 108 50       240 if ($type eq "raw")
987             {
988 0         0 $self->ClearRawXML();
989 0         0 $self->InsertRawXML($value);
990 0         0 return;
991             }
992              
993             #-------------------------------------------------------------------------
994             # Hook to support special cases. You can register the specials with
995             # the module and they will ba called based on match.
996             #-------------------------------------------------------------------------
997 108 50 33     701 if (($subType ne "") && exists($self->{CUSTOMSET}->{$subType}))
998             {
999             #$self->_debug("_xpath_set: custom: subType($subType)");
1000             #$self->_debug("_xpath_set: custom: value($value)") if defined($value);
1001 0         0 $value = &{$self->{CUSTOMSET}->{$subType}}($self,$value);
  0         0  
1002             }
1003              
1004 108 50       245 if ($type eq "timestamp")
1005             {
1006 0 0       0 $value = "" unless defined($value);
1007 0 0       0 if ($value eq "") {
1008 0         0 $value = &Net::XMPP3::GetTimeStamp("utc","","stamp");
1009             }
1010             }
1011              
1012             #$self->_debug("_xpath_set: value($value)") unless !defined($value);
1013              
1014             #-------------------------------------------------------------------------
1015             # Now that we have resolved the value, we put it into an array so that we
1016             # can support array refs by referring to the values as an array.
1017             #-------------------------------------------------------------------------
1018 108         134 my @values;
1019 108         170 push(@values,$value);
1020 108 100       419 if ($type eq "array")
1021             {
1022 2 100       10 if (ref($value) eq "ARRAY")
1023             {
1024 1         2 @values = @{$value};
  1         4  
1025             }
1026             }
1027              
1028             #$self->_debug("_xpath_set: values(",join(",",@values),")") unless !defined($value);
1029              
1030             #-------------------------------------------------------------------------
1031             # And now, for each value...
1032             #-------------------------------------------------------------------------
1033 108         192 foreach my $val (@values)
1034             {
1035             #$self->_debug("_xpath_set: val($val)") unless !defined($val);
1036             #$self->_debug("_xpath_set: type($type)");
1037              
1038 109 50 33     381 next unless (defined($val) || ($type eq "flag"));
1039              
1040 109 50 33     493 if ((ref($val) ne "") && ($val->isa("Net::XMPP3::JID")))
1041             {
1042 0         0 $val = $val->GetJID("full");
1043             }
1044              
1045 109         148 my $path = $xpath;
1046              
1047             #$self->_debug("_xpath_set: val($val)") unless !defined($val);
1048             #$self->_debug("_xpath_set: path($path)");
1049              
1050 109         148 my $childPath = "";
1051 109   66     680 while(($path !~ /^\/?\@/) && ($path !~ /^\/?text\(\)/))
1052             {
1053             #$self->_debug("_xpath_set: Multi-level!!!!");
1054 45         179 my ($child) = ($path =~ /^\/?([^\/]+)/);
1055 45         154 $path =~ s/^\/?[^\/]+//;
1056             #$self->_debug("_xpath_set: path($path)");
1057             #$self->_debug("_xpath_set: childPath($childPath)");
1058              
1059 45 50 66     168 if (($type eq "scalar") || ($type eq "jid") || ($type eq "timestamp"))
      66        
1060             {
1061 42         59 my $tmpPath = $child;
1062 42 50       103 $tmpPath = "$childPath/$child" if ($childPath ne "");
1063              
1064 42         172 my @nodes = $self->{TREE}->XPath("$tmpPath");
1065             #$self->_debug("_xpath_set: \$#nodes($#nodes)");
1066 42 100       20435 if ($#nodes == -1)
1067             {
1068 36 50       79 if ($childPath eq "")
1069             {
1070 36         133 $node = $self->{TREE}->add_child($child);
1071             }
1072             else
1073             {
1074 0         0 my $tree = $self->{TREE}->XPath("$childPath");
1075 0         0 $node = $tree->add_child($child);
1076             }
1077             }
1078             else
1079             {
1080 6         16 $node = $nodes[0];
1081             }
1082             }
1083              
1084 45 100       1000 if ($type eq "array")
1085             {
1086 3         15 $node = $self->{TREE}->add_child($child);
1087             }
1088              
1089 45 50       189 if ($type eq "flag")
1090             {
1091 0         0 $node = $self->{TREE}->add_child($child);
1092 0         0 return;
1093             }
1094              
1095 45 50       115 $childPath .= "/" unless ($childPath eq "");
1096 45         287 $childPath .= $child;
1097             }
1098              
1099 109         401 my ($piece) = ($path =~ /^\/?([^\/]+)/);
1100              
1101             #$self->_debug("_xpath_set: piece($piece)");
1102              
1103 109 100       417 if ($piece =~ /^\@(.+)$/)
    50          
1104             {
1105 70         256 $node->put_attrib($1=>$val);
1106             }
1107             elsif ($piece eq "text()")
1108             {
1109 39         145 $node->remove_cdata();
1110 39         428 $node->add_cdata($val);
1111             }
1112             }
1113             }
1114              
1115              
1116             ##############################################################################
1117             #
1118             # _xpath_defined - returns true if there is data for the requested item, false
1119             # otherwise.
1120             #
1121             ##############################################################################
1122             sub _xpath_defined
1123             {
1124 233     233   9531 my $self = shift;
1125 233         349 my $type = shift;
1126 233         277 my $xpath = shift;
1127 233         287 my $childtype = shift;
1128 233         303 my $ns = shift;
1129              
1130 233         1103 $self->_debug("_xpath_defined: self($self) type($type) xpath($xpath) childtype($childtype)");
1131 233 100       600 $self->_debug("_xpath_defined: ns($ns)") if defined($ns);
1132 233         908 $self->_debug("_xpath_defined: xml(",$self->{TREE}->GetXML(),")");
1133              
1134 233         413 my $subType;
1135 233         658 ($type,$subType) = $self->_xpath_resolve_types($type);
1136 233         1291 $self->_debug("_xpath_defined: type($type) subType($subType) ");
1137              
1138 233 50       637 if ($type eq "raw")
1139             {
1140 0 0       0 if ($#{$self->{RAWXML}} > -1)
  0         0  
1141             {
1142 0         0 return 1;
1143             }
1144             }
1145              
1146 233         999 my @nodes = $self->{TREE}->XPath($xpath);
1147             # If the $ns is defined, then the presence of nodes does not mean
1148             # we're defined, we have to check them.
1149 233   66     156463 my $defined = ( @nodes > 0 && !defined($ns) );
1150              
1151 233         876 $self->_debug("_xpath_defined: nodes(",join(",",@nodes),")");
1152              
1153 233 50 66     1495 if (!@nodes && (($type eq "child") || ($type eq "children") || ($type eq "node")))
      66        
1154             {
1155 16 50 33     115 if ((ref($childtype) eq "HASH") && exists($childtype->{ns}))
1156             {
1157 0         0 $ns = $childtype->{ns};
1158             }
1159             }
1160              
1161 233 100       570 $self->_debug("_xpath_defined: ns(".$ns.") defined(".$defined.")") if defined($ns);
1162              
1163 233         336 foreach my $packet (@{$self->{CHILDREN}})
  233         621  
1164             {
1165 36         205 $self->_debug("_xpath_defined: packet->GetXMLNS ",$packet->GetXMLNS());
1166 36 100 100     325 if (defined($ns) && ($packet->GetXMLNS() eq $ns))
    100 100        
1167             {
1168 7         17 $defined = 1;
1169 7         14 last;
1170             }
1171             # if we have children, and that's all we're looking for, then by golly
1172             # we're done.
1173             elsif ( !defined($ns) && $type =~ /child/ )
1174             {
1175 4         10 $defined = 1;
1176 4         8 last;
1177             }
1178             }
1179 233         1038 $self->_debug("_xpath_defined: defined($defined)");
1180              
1181 233         2550 return $defined;
1182             }
1183              
1184              
1185             ##############################################################################
1186             #
1187             # _xpath_add - returns the value stored in the node
1188             #
1189             ##############################################################################
1190             sub _xpath_add
1191             {
1192 3     3   8 my $self = shift;
1193 3         4 my $type = shift;
1194 3         39 my $xpath = shift;
1195 3         6 my $childtype = shift;
1196              
1197 3         6 my $xmlns = $childtype->{ns};
1198 3         5 my $master = $childtype->{master};
1199              
1200             #$self->_debug("_xpath_add: self($self) type($type) xpath($xpath) childtype($childtype)");
1201             #$self->_debug("_xpath_add: xmlns($xmlns) master($master)");
1202              
1203 3         5 my $tag = $xpath;
1204 3 50       15 if (exists($childtype->{specify_name}))
1205             {
1206 0 0 0     0 if (($#_ > -1) && (($#_/2) =~ /^\d+$/))
1207             {
1208 0         0 $tag = shift;
1209             }
1210             else
1211             {
1212 0         0 $tag = $childtype->{tag};
1213             }
1214             }
1215              
1216 3         27 my $node = new XML::Stream::Node($tag);
1217 3         69 $node->put_attrib(xmlns=>$xmlns);
1218              
1219 3         40 my $obj = $self->AddChild($node);
1220 3 50       329 eval "\$obj->Set${master}(\@_);" if defined($master);
1221              
1222 3 50       22 $obj->_skip_xmlns() if exists($childtype->{skip_xmlns});
1223              
1224 3         20 return $obj;
1225             }
1226              
1227              
1228             ##############################################################################
1229             #
1230             # _xpath_remove - remove the specified thing from the data (I know it's vague.)
1231             #
1232             ##############################################################################
1233             sub _xpath_remove
1234             {
1235 24     24   38 my $self = shift;
1236 24         43 my $type = shift;
1237 24         32 my $xpath = shift;
1238 24         29 my $childtype = shift;
1239              
1240             #$self->_debug("_xpath_remove: self($self) type($type) xpath($xpath) childtype($childtype)");
1241              
1242 24         33 my $subType;
1243 24         64 ($type,$subType) = $self->_xpath_resolve_types($type);
1244              
1245 24         49 my $nodePath = $xpath;
1246 24         103 $nodePath =~ s/\/?\@\S+$//;
1247 24         65 $nodePath =~ s/\/text\(\)$//;
1248              
1249             #$self->_debug("_xpath_remove: xpath($xpath) nodePath($nodePath)");
1250              
1251 24         41 my @nodes;
1252 24 100       127 @nodes = $self->{TREE}->XPath($nodePath) if ($nodePath ne "");
1253              
1254             #$self->_debug("_xpath_remove: nodes($#nodes)");
1255              
1256 24 100       6621 if ($xpath =~ /\@(\S+)/)
1257             {
1258 15         41 my $attrib = $1;
1259             #$self->_debug("_xpath_remove: attrib($attrib)");
1260              
1261 15 100       35 if ($nodePath eq "")
1262             {
1263 12         64 $self->{TREE}->remove_attrib($attrib);
1264             }
1265             else
1266             {
1267 3         9 foreach my $node (@nodes)
1268             {
1269 3         14 $node->remove_attrib($attrib);
1270             }
1271             }
1272 15         241 return;
1273             }
1274              
1275 9         28 foreach my $node (@nodes)
1276             {
1277             #$self->_debug("_xpath_remove: node GetXML(".$node->GetXML().")");
1278 9         46 $self->{TREE}->remove_child($node);
1279             }
1280              
1281 9 50       357 if ($type eq "child")
1282             {
1283 0         0 my @keep;
1284 0         0 foreach my $child (@{$self->{CHILDREN}})
  0         0  
1285             {
1286             #$self->_debug("_xpath_remove: check(".$child->GetXML().")");
1287 0 0       0 next if ($child->GetXMLNS() eq $childtype->{ns});
1288             #$self->_debug("_xpath_remove: keep(".$child->GetXML().")");
1289 0         0 push(@keep,$child);
1290             }
1291 0         0 $self->{CHILDREN} = \@keep;
1292             }
1293             }
1294              
1295              
1296             ##############################################################################
1297             #
1298             # _xpath_resolve_types - Resolve the type and subType into the correct values.
1299             #
1300             ##############################################################################
1301             sub _xpath_resolve_types
1302             {
1303 588     588   1035 my $self = shift;
1304 588         992 my $type = shift;
1305              
1306 588         716 my $subType = "";
1307 588 50       1283 if (ref($type) eq "ARRAY")
1308             {
1309 0 0       0 if ($type->[0] eq "special")
    0          
1310             {
1311 0         0 $subType = $type->[1];
1312 0         0 $type = "scalar";
1313             }
1314             elsif ($type->[0] eq "master")
1315             {
1316 0         0 $subType = $type->[1];
1317 0         0 $type = "master";
1318             }
1319             }
1320              
1321             #$self->_debug("_xpath_resolve_types: type($type) subtype($subType)");
1322              
1323 588         1627 return ($type,$subType);
1324             }
1325              
1326              
1327             ##############################################################################
1328             #
1329             # _parse_xmlns - anything that uses the namespace method must first kow what
1330             # the xmlns of this thing is... So here's a function to do
1331             # just that.
1332             #
1333             ##############################################################################
1334             sub _parse_xmlns
1335             {
1336 12     12   95 my $self = shift;
1337              
1338 12 50       50 $self->SetXMLNS($self->{TREE}->get_attrib("xmlns"))
1339             if defined($self->{TREE}->get_attrib("xmlns"));
1340             }
1341              
1342              
1343             ##############################################################################
1344             #
1345             # _parse_tree - run through the XML::Stream::Node and pull any child nodes
1346             # out that we recognize and create objects for them.
1347             #
1348             ##############################################################################
1349             sub _parse_tree
1350             {
1351 12     12   19 my $self = shift;
1352              
1353 12         48 my @xTrees = $self->{TREE}->XPath('*[@xmlns]');
1354              
1355 12 50       7008 if ($#xTrees > -1)
1356             {
1357 0         0 foreach my $xTree (@xTrees)
1358             {
1359 0 0       0 if( exists($Net::XMPP3::Namespaces::NS{$xTrees[0]->get_attrib("xmlns")}))
1360             {
1361 0         0 $self->AddChild($xTree);
1362 0         0 $self->{TREE}->remove_child($xTree);
1363             }
1364             }
1365             }
1366             }
1367              
1368              
1369              
1370              
1371             ##############################################################################
1372             #+----------------------------------------------------------------------------
1373             #|
1374             #| Private Methods
1375             #|
1376             #+----------------------------------------------------------------------------
1377             ##############################################################################
1378              
1379             sub _check_skip_xmlns
1380             {
1381 19     19   216 my $self = shift;
1382 19         28 my $xmlns = shift;
1383              
1384 19         60 foreach my $skipns (keys(%Net::XMPP3::Namespaces::SKIPNS))
1385             {
1386 19 100       278 return 1 if ($xmlns =~ /^$skipns/);
1387             }
1388              
1389 10         37 return 0;
1390             }
1391              
1392              
1393             ##############################################################################
1394             #
1395             # _debug - helper function for printing debug messages using Net::XMPP3::Debug
1396             #
1397             ##############################################################################
1398             sub _debug
1399             {
1400 1994     1994   65902 my $self = shift;
1401 1994         20943 return $DEBUG->Log99($self->{DEBUGHEADER},": ",@_);
1402             }
1403              
1404              
1405             ##############################################################################
1406             #
1407             # _missing_function - send an error if the function is missing.
1408             #
1409             ##############################################################################
1410             sub _missing_function
1411             {
1412 0     0   0 my ($parent,$function) = @_;
1413 0         0 croak("Undefined function $function in package ".ref($parent));
1414             }
1415              
1416              
1417             ##############################################################################
1418             #
1419             # _new_jid - create a new JID object.
1420             #
1421             ##############################################################################
1422             sub _new_jid
1423             {
1424 24     24   50 my $self = shift;
1425 24         181 return new Net::XMPP3::JID(@_);
1426             }
1427              
1428              
1429             ##############################################################################
1430             #
1431             # _new_packet - create a new Stanza object.
1432             #
1433             ##############################################################################
1434             sub _new_packet
1435             {
1436 12     12   21 my $self = shift;
1437 12         98 return new Net::XMPP3::Stanza(@_);
1438             }
1439              
1440              
1441             ##############################################################################
1442             #
1443             # _skip_xmlns - in the GetTree function, cause the xmlns attribute to be
1444             # removed for a node that has this set.
1445             #
1446             ##############################################################################
1447             sub _skip_xmlns
1448             {
1449 0     0     my $self = shift;
1450              
1451 0           $self->{SKIPXMLNS} = 1;
1452             }
1453              
1454              
1455             1;