File Coverage

blib/lib/Jabber/Lite.pm
Criterion Covered Total %
statement 437 2221 19.6
branch 188 1204 15.6
condition 38 367 10.3
subroutine 29 115 25.2
pod 1 1 100.0
total 693 3908 17.7


line stmt bran cond sub pod time code
1             ###################################################################
2             # Jabber::Lite
3             # $Id: Jabber::Lite.pm,v 1.64 2007/01/29 20:44:34 bc Exp bc $
4             # Copyright (C) 2005-2007 Bruce Campbell
5             # ( For my mail sorting, replace the above 'beecee' with the name
6             # of the module, eg 'Jabber::Lite' or 'Jabber-Lite' )
7             #
8             # This is a perl library intended to be a small and light implementation
9             # of Jabber libraries. Nearly a third of this file is documentation of
10             # one sort or another.
11             #
12             # What you should be able to do with this library:
13             # Connect to a Jabber server.
14             # Send and receive packets.
15             # Create new packets.
16             # List attributes on packets.
17             # List tags on packets.
18             #
19             # This library implements a progressive XML parser within itself; it
20             # does not use an seperate parser which your perl installation may not
21             # be able to install.
22             #
23             # This library is fairly dumb. It doesn't understand anything other than
24             # ASCII, and its correctness checks are limited. Unicode is right out.
25             # Basically, this is a Jabber library where the most complicated thing
26             # being dealt with is the base64-encoded stuff in SASL authentication.
27             #
28             ###########################################################################
29             #
30             #
31              
32              
33             =head1 NAME
34              
35             Jabber::Lite - Standalone library for communicating with Jabber servers.
36              
37             =head1 SYNOPSIS
38              
39             use Jabber::Lite;
40              
41             my $jlobj = Jabber::Lite->new();
42              
43             $jlobj->connect( %args );
44             $jlobj->authenticate( %args );
45             my $stillgoing = 1;
46             while( $stillgoing ){
47             my $tval = $jlobj->process();
48             if( $tval == 1 ){
49             my $curobj = $jlobj->get_latest();
50              
51             # Process based on the object.
52              
53             }elsif( $tval < 0 ){
54             $stillgoing = 0;
55             }
56             }
57              
58             =head1 GOALS
59              
60             Jabber::Lite is intended to be a pure perl library for interacting with
61             Jabber servers, and be able to run under any version of perl that has
62             the Sockets library.
63              
64             =head1 DESCRIPTION
65              
66             Jabber::Lite is, as the name implies, a small 'lite' library for dealing
67             with Jabber servers, implemented entirely in perl. Whilst it is small,
68             it does try to be fairly complete for common tasks.
69              
70             Whats in the box? Jabber::Lite is able to connect to a Jabber server,
71             read from the socket, and supply XML objects to the application as
72             the application reads them. Its function calls are mostly compatible
73             with Jabber::NodeFactory and Jabber::Connection.
74             Surprisingly, it can also function as a stand-alone XML parser (which
75             was not the author's original intent, but hey, it works).
76              
77             Whats not in the box? Any requirement for a recent perl version, UTF-8
78             support, as well as a B XML-compliant Parser.
79              
80             Applications using this library will need to be aware that this
81             library uses a combination of 'pull' and 'push' methods of supplying
82             XML objects. Handlers for given object types can be put in place,
83             however if an object is not fully handled by a Handler, the object
84             will 'block' further objects until the Application retrieves it. Read
85             the notes on ->process and ->get_latest() for further details.
86              
87             The inbuilt parser, fully implemented in perl, is more properly termed an
88             XML Recogniser. If you want a fully compliant XML Parser, look elsewhere.
89             This one recognises just enough XML for its purposes ;)
90              
91             =cut
92              
93             # Do proxy thing as per Matt Sergeant's article:
94             # http://www.perl.com/pub/a/2002/08/07/proxyobject.html?page=3
95             # This may reduce some memory usage.
96              
97             package Jabber::Lite;
98              
99 4     4   35076 use strict;
  4         9  
  4         344  
100             our $AUTOLOAD;
101              
102             BEGIN {
103 4     4   393 eval "use Scalar::Util qw(weaken);";
  4     4   24  
  4         5  
  4         483  
104 4 50       24 if ($@) {
105 0         0 $Jabber::Lite::WeakRefs = 0;
106             } else {
107 4         135 $Jabber::Lite::WeakRefs = 1;
108             }
109             }
110              
111             sub new {
112 26     26 1 1704 my $class = shift;
113 4     4   19 no strict 'refs';
  4         6  
  4         521  
114 26         82 my $impl = $class . "::Impl";
115 26         80 my $this = $impl->new(@_);
116 26 50       67 if ($Jabber::Lite::WeakRefs) {
117 26         59 return $this;
118             }
119 0         0 my $self = \$this;
120 0         0 return bless $self, $class;
121             }
122              
123             sub AUTOLOAD {
124 0     0   0 my $method = $AUTOLOAD;
125 0         0 $method =~ s/.*:://; # strip the package name
126 4     4   19 no strict 'refs';
  4         5  
  4         1029  
127 0         0 *{$AUTOLOAD} = sub {
128 0     0   0 my $self = shift;
129 0         0 my $olderror = $@; # store previous exceptions
130 0         0 my $obj = eval { $$self };
  0         0  
131 0 0       0 if ($@) {
132 0 0       0 if ($@ =~ /Not a SCALAR reference/) {
133 0         0 croak("No such method $method in " . ref($self));
134             }
135 0         0 croak $@;
136             }
137 0 0       0 if ($obj) {
138             # make sure $@ propogates if this method call was the
139             # result of losing scope because of a die().
140 0 0       0 if ($method =~ /^(DESTROY|del_parent_link)$/) {
141 0         0 $obj->$method(@_);
142 0 0       0 $@ = $olderror if $olderror;
143 0         0 return;
144             }
145 0         0 return $obj->$method(@_);
146             }
147 0         0 };
148 0         0 goto &$AUTOLOAD;
149             }
150              
151             # sub DESTROY { my $self = shift; warn("Lite::DESTROY $self\n") }
152              
153             # Now for the actual package.
154             package Jabber::Lite::Impl;
155 4     4   23 use constant r_HANDLED => -522201;
  4         6  
  4         411  
156 4     4   24 use Exporter;
  4         6  
  4         8633  
157              
158 4     4   24 use vars qw/@ISA $VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS/;
  4         6  
  4         599  
159             @ISA=qw(Exporter);
160              
161             @EXPORT = qw(r_HANDLED);
162              
163              
164             %EXPORT_TAGS = (
165             'handled' => [qw(r_HANDLED)],
166             );
167              
168             my $con;
169             push @EXPORT_OK, @$con while (undef, $con) = each %EXPORT_TAGS;
170              
171             $VERSION = "0.8";
172              
173 4     4   4455 use IO::Socket::INET;
  4         170464  
  4         40  
174 4     4   6879 use IO::Select;
  4         7219  
  4         142329  
175              
176             sub DESTROY {
177 26     26   3909 my $self = shift;
178             # warn("Impl::DESTROY $self\n");
179              
180             # Remove references to this instance. If it is being called
181             # manually, may trigger garbage collection of other objects.
182 26         69 $self->hidetree();
183              
184             }
185              
186             =head1 METHODS
187              
188             The methods within have been organised into several categories, listed here
189             for your searching pleasure:
190              
191             =over
192              
193             =item Initialisation
194              
195             =item Resolving
196              
197             =item Connecting
198              
199             =item Authenticating
200              
201             =item Dealing with
202              
203             =item Handling Packets
204              
205             =item So Long, and Thanks for all the
206              
207             =item These are a few of my incidental things
208              
209             =item Object common
210              
211             =item Object detailed and other stuff.
212              
213             =back
214              
215              
216             =cut
217              
218             =head1 METHODS - Initialisation
219              
220             =cut
221              
222             =head2 new
223              
224             Returns a new instance of the object. Takes a hash of arguments which
225             are passed straight to ->init();
226              
227             =cut
228              
229             sub new {
230              
231 26     26   47 my ($class, %args) = @_;
232 26         40 my $self = {};
233              
234 26         58 bless $self, $class ;
235              
236 26         68 $self->init( %args );
237              
238 26         177 return( $self);
239              
240             }
241              
242             =head2 init
243              
244             (Re-)initialises data stored on the object, removing most references.
245             Used by ->new() to ensure that there is no 'bad' stuff around. Takes a
246             hash of values including:
247              
248             =over
249              
250             =item readsize
251              
252             The number of bytes to request (but not expect) from the socket at any one
253             time. Defaults to 1500 to ensure that an ethernet packet will be read in
254             one call. Do not set this excessively high. Likewise, setting it too low
255             will result in excessive polls.
256              
257             =item disconnectonmax
258              
259             A boolean indicating whether to disconnect on exceeding maxobjectsize bytes,
260             maxnamesize or maxobjectdepth in a single object. The default, 0, will
261             continue to read and parse the object, but will not save more of the object's
262             data or attributes into memory.
263              
264             =item maxobjectsize
265              
266             The maximum number of bytes allowed in a single object. There is no default.
267             This is intended as protection against an excessively large packet.
268              
269             =item maxobjectdepth
270              
271             The maximum number of subtags allowed in a single object. There is no
272             default.
273              
274             =item maxnamesize
275              
276             The maximum length of a single tag name, eg, the 'foo' in ''. There
277             is no default. Note that this is applied against every tag, not just the
278             parent tag. This is intended as protecting against a really long
279             , which may still consume
280             memory if the maxobject size is exceeded and disconnectonmax is left at 0.
281              
282             =item debug
283              
284             A debug qualifier. If set to '1', will show all debug messages. If set to
285             a comma-seperated string, will show all debug messages generated by those
286             subroutines.
287              
288             =back
289              
290             The various 'max' settings are enforced by ->do_read. Calling ->parse_more
291             directly will not incur the dubious protections afforded by this.
292              
293             =cut
294              
295             sub init {
296              
297 26     26   32 my $self = shift;
298 26         83 my %args = ( readsize => 1500,
299             disconnectonmax => 0,
300             @_ );
301              
302             # First clear the object.
303 26         35 foreach my $kkey ( keys %{$self} ){
  26         101  
304 0         0 delete( $self->{"$kkey"} );
305             }
306              
307             # Then apply any arguments.
308 26         144 my %validargs = ( "readsize", "1",
309             "debug", "1",
310             "disconnectonmax", "1",
311             "maxobjectsize", "1",
312             "maxnamesize", "1",
313             "maxobjectdepth", "1",
314             );
315              
316             # Run through the possible known args, overwriting any that
317             # already exist.
318 26         56 foreach my $kkey( keys %args ){
319 52 50       124 next unless( defined( $validargs{"$kkey"} ) );
320 52         134 $self->{"_$kkey"} = $args{"$kkey"};
321             }
322              
323             # Clear the handlers.
324 26         43 %{$self->{'handlers'}} = ();
  26         124  
325              
326             }
327              
328             =head1 METHODS - Resolving
329              
330             Before connecting, you may need to resolve something in order to find
331             out where to point the connection methods to. Heres some methods
332             for resolving.
333              
334             =head2 resolve
335              
336             Deals with the intricacies of figuring out what you need to connect to.
337             Understands SRV records, and how things can resolve differently depending
338             on whether you want a server or client connection. Takes a hash of 'Domain',
339             a 'Timeout' value (in seconds) and a 'Type' of 'client' or 'server'.
340             Returns a boolean success value of 1 (success) or 0 (failure).
341              
342             Note that no DNSSEC or TSIG verification is done.
343              
344             =cut
345              
346             sub resolve {
347 0     0   0 my $self = shift;
348 0         0 my %args = ( Domain => undef,
349             Type => 'client',
350             Protocol => 'tcp',
351             Timeout => 90,
352             @_,
353             );
354              
355             # We just dump it all to bgresolve.
356 0         0 $self->bgresolve( %args );
357              
358             # Loop until we do not have '-1' as the result. bgresolve takes
359             # care of any timeouts.
360 0         0 my $curresult = $self->bgresolved;
361 0         0 while( $curresult == -1 ){
362 0         0 $curresult = $self->bgresolved;
363              
364 0         0 select( undef, undef, undef, 0.1 );
365             }
366              
367 0         0 return( $curresult );
368             }
369            
370              
371             =head2 resolved
372              
373             Returns a list of what the last ->resolve request actually resolved to.
374             This is an ordered-by-priority, randomised-by-weight @list of
375             'IP.address,port'. If there is no ',port', then no port information
376             was present in the DNS, and the application's own idea of default
377             port should be used.
378              
379             The ordering is done according to the method set out in
380             RFC2782(DNS SRV Records). Of particular note is page 3, where a
381             randomisation function is applied to the ordering of SRV RRs with
382             equal priority. Thus, each time this function is called, it may
383             return a different ordering of IPs.
384              
385             =cut
386              
387             sub resolved {
388 50     50   8166 my $self = shift;
389              
390             # Do the ordering of hosts in this function.
391             # The results have been stored in a hash:
392             # $self->{'_resolved'}{'hostname'}
393             # Each of these contains another hash, of @'srv' and $'address',
394             # amongst others.
395 50         73 my @list = ();
396              
397             # Run through the hosts, and see if any have 'srv' records. There
398             # should only be one, and it holds indirections to other hosts.
399 50         52 my $srvrec = undef;
400 50         69 foreach my $host( keys %{$self->{'_resolved'}} ){
  50         200  
401 500 100       12763 next unless( defined( $self->{'_resolved'}{$host}{'srv'} ) );
402 50         62 $srvrec = $host;
403             }
404              
405 50 50       151 if( ! defined( $srvrec ) ){
406 0         0 foreach my $host( keys %{$self->{'_resolved'}} ){
  0         0  
407 0 0       0 next unless( defined( $self->{'_resolved'}{$host}{'address'} ) );
408 0 0       0 next if( $self->{'_resolved'}{$host}{'address'} =~ /^\s*$/ );
409 0         0 push @list, $self->{'_resolved'}{$host}{'address'};
410             }
411             }else{
412             # Run through the srv listing in order.
413 50         77 my %uhosts = ();
414 50         61 foreach my $prio ( sort { $a <=> $b } keys %{$self->{'_resolved'}{$srvrec}{'srv'}} ){
  50         150  
  50         294  
415             # Collect all of the weights.
416 100         204 my %weights = ();
417 100         118 my $wghtcnt = scalar @{$self->{'_resolved'}{$srvrec}{'srv'}{$prio}};
  100         211  
418 100         112 my $wghthigh = 0;
419 100         91 foreach my $wghtrec( @{$self->{'_resolved'}{$srvrec}{'srv'}{$prio}} ){
  100         191  
420 450 50       2374 next unless( $wghtrec =~ /^\s*(\d+)\s+(\d+)\s+(\S+)\s*$/ );
421 450         647 my $wghtnum = $1;
422 450         565 my $port = $2;
423 450         535 my $host = $3;
424 450 100       10290 if( $wghtnum > $wghthigh ){
425 50         92 $wghthigh = $wghtnum;
426             }
427             }
428              
429             # Run through again, now that we know the highest
430             # weight.
431 100         138 my $posmax = 0;
432 100         145 foreach my $wghtrec( @{$self->{'_resolved'}{$srvrec}{'srv'}{$prio}} ){
  100         308  
433 450 50       2464 next unless( $wghtrec =~ /^\s*(\d+)\s+(\d+)\s+(\S+)\s*$/ );
434 450         589 my $wghtnum = $1;
435 450         535 my $port = $2;
436 450         739 my $host = $3;
437              
438             # Work out a position for this weight, between
439             # 0 and $wghtcnt (inclusive).
440 450         926 my $wghtpos = abs( int( rand( $wghtcnt + 1 ) + ( $wghthigh - $wghtnum ) ) );
441 450         714 my $trycnt = 0;
442 450   66     1298 while( defined( $weights{"$wghtpos"} ) && $trycnt < $wghtcnt ){
443 144         227 $wghtpos = abs( int( rand( $wghtcnt + 1 ) + ( $wghthigh - $wghtnum ) ) );
444 144         570 $trycnt++;
445             }
446              
447             # Did the loop exit due to success, or because
448             # of too many iterations?
449 450 50       816 if( defined( $weights{"$wghtpos"} ) ){
450             # Count up until we find one.
451 0         0 $wghtpos = 0;
452 0         0 while( defined( $weights{"$wghtpos"} ) ){
453 0         0 $wghtpos++;
454             }
455             }
456              
457             # Save the port and host.
458 450         2460 $weights{"$wghtpos"} = "$port $host";
459              
460 450 100       1005 if( $wghtpos > $posmax ){
461 159         6947 $posmax = $wghtpos;
462             }
463             # print "Found SRV $srvrec and priority $prio and weight $wghtnum and pos $wghtpos and port $port and host $host\n";
464             }
465              
466             # Now output the hosts seen in the semi-random
467             # order chosen.
468 100         325 foreach my $weightkey ( sort { $b <= $a } keys %weights ){
  692         789  
469 450 50       870 next unless( defined( $weights{"$weightkey"} ) );
470 450 50       2036 next unless( $weights{"$weightkey"} =~ /^\s*(\d+)\s+(\S+)\s*$/ );
471 450         611 my $port = $1;
472 450         543 my $host = $2;
473 450 50       1519 next unless( defined( $self->{'_resolved'}{$host}{'address'} ) );
474 450 50       2114 next if( $self->{'_resolved'}{$host}{'address'} =~ /^\s*$/ );
475             # addresses can be multiple!
476 450         647 foreach my $address( @{$self->{'_resolved'}{$host}{'address'}} ){
  450         9592  
477             # Only output a given IP and port combination once.
478 500 50       2125 next if( defined( $uhosts{$port . $address} ) );
479 500         797 push @list, $address . "," . $port;
480 500         2210 $uhosts{$port . $address}++;
481             }
482             }
483             }
484             }
485 50         328 return( @list );
486             }
487              
488             =head2 bgresolve
489              
490             As per ->resolve, but submit in the background. This returns 1 if the query
491             could be submitted, and 0 if not.
492             ( Actually, ->resolve is simply a wrapper around ->bgresolve and ->bgresolved )
493              
494             =cut
495              
496             sub bgresolve {
497 0     0   0 my $self = shift;
498 0         0 my %args = ( Domain => undef,
499             Type => 'client',
500             Protocol => 'tcp',
501             Timeout => 90,
502             @_,
503             );
504              
505 0         0 my $retval = 0;
506              
507             # Wipe out previous resolution records.
508 0         0 delete( $self->{'_resolved'} );
509 0         0 delete( $self->{'_queries'} );
510              
511 0 0       0 if( ! defined( $args{"Timeout"} ) ){
    0          
    0          
512 0         0 $args{"Timeout"} = 90;
513             }elsif( $args{"Timeout"} !~ /^\s*\d+\s*$/ ){
514 0         0 $args{"Timeout"} = 90;
515             }elsif( $args{"Timeout"} < 11 ){
516             # Try to stop the application from shooting off its own foot.
517 0         0 $args{"Timeout"} = 11;
518             }
519              
520             # If we have all of a domain, a type and a protocol, then we can
521             # make a query.
522 0 0 0     0 if( defined( $args{"Domain"} ) && defined( $args{"Type"} ) && defined( $args{"Protocol"} ) && $self->_got_Net_DNS() ){
      0        
      0        
523             # Set up the initial query.
524 0         0 my $res = Net::DNS::Resolver->new();
525 0         0 $res->retry(2);
526 0         0 $res->retrans(5);
527 0         0 $res->tcp_timeout( $args{"Timeout"} - 1 );
528              
529             # udp_timeout is effectively the #retries * #retransmissions,
530             # which we've set to 2 * 5 == 10.
531              
532             # No spaces in $qname.
533 0         0 $args{"Type"} =~ s/\s*//g;
534 0         0 $args{"Protocol"} =~ s/\s*//g;
535 0         0 $args{"Domain"} =~ s/\s*//g;
536 0         0 my $qname = "_xmpp-" . $args{"Type"} . "._" . $args{"Protocol"} . "." . $args{"Domain"};
537              
538             # Make sure the query makes sense.
539 0 0       0 if( $qname =~ /^_xmpp-(server|client)\._([^\.]+)\.(\S+)$/i ){
540              
541             # Send it.
542 0         0 my $sock = $res->bgsend( $qname, "SRV", "IN" );
543              
544             # Store it.
545 0         0 my $sname = $args{"Domain"} . ";1";
546 0         0 $self->{'_queries'}{";;base"} = $args{"Domain"};
547 0         0 $self->{'_queries'}{";;q1"} = $sname;
548 0         0 $self->{'_queries'}{";;start"} = time;
549 0         0 $self->{'_queries'}{";;end"} = $self->{'_queries'}{";;start"} + $args{"Timeout"};
550 0         0 $self->{'_queries'}{";;res"} = $res;
551 0         0 $self->{'_queries'}{"$sname"}{"start"} = $self->{'_queries'}{";;start"};
552 0         0 $self->{'_queries'}{"$sname"}{"sock"} = $sock;
553 0         0 $self->{'_queries'}{"$sname"}{"qname"} = $qname;
554 0         0 $self->{'_queries'}{"$sname"}{"qtype"} = "SRV";
555              
556             # Increment the return value.
557 0         0 $retval++;
558             }
559              
560              
561             # If the query was for a 'server' type, send off a second
562             # query for '_jabber._tcp.HOST' in case the first query
563             # fails. This should cut down on the wait time. This code
564             # should be removed when that portion of XMPP-CORE gets
565             # relegated to 'do not use'.
566 0         0 $qname = "_jabber._" . $args{"Protocol"} . "." . $args{"Domain"};
567 0 0 0     0 if( $qname =~ /^_jabber\._([^\.]+)\.(\S+)$/i && $args{"Type"} =~ /^server$/i ){
568             # Send it.
569 0         0 my $sock = $res->bgsend( $qname, "SRV", "IN" );
570              
571             # Store it.
572 0         0 my $sname = $args{"Domain"} . ";2";
573 0         0 $self->{'_queries'}{";;res"} = $res;
574 0         0 $self->{'_queries'}{";;q2"} = $sname;
575 0         0 $self->{'_queries'}{"$sname"}{"start"} = $self->{'_queries'}{";;start"};
576 0         0 $self->{'_queries'}{"$sname"}{"sock"} = $sock;
577 0         0 $self->{'_queries'}{"$sname"}{"qname"} = $qname;
578 0         0 $self->{'_queries'}{"$sname"}{"qtype"} = "SRV";
579              
580             # Increment the return value.
581 0         0 $retval++;
582             }
583              
584             }
585              
586             # Return true or false.
587 0 0       0 if( $retval > 0 ){
588 0         0 return( 1 );
589             }else{
590 0         0 return( 0 );
591             }
592             }
593              
594              
595             =head2 bgresolved
596              
597             Checks to see whether the last ->bgresolve request completed. Only one
598             request in the background can be ongoing at a time. Returns -1 if the
599             resolution is still pending, 0 if the resolution failed, and 1 if the
600             resolution was successful. ->resolved can then be called to retrieve
601             the list.
602              
603             =cut
604              
605             sub bgresolved {
606 0     0   0 my $self = shift;
607              
608 0         0 my $retval = -1;
609              
610             # The resolving chain goes something like:
611             # Look up the SRV records for '_xmpp-TYPE._PROTOCOL.HOST' .
612             # If successful:
613             # look up in turn the A or AAAA records for the
614             # hostnames mentioned in the SRV records.
615             # If unsuccessful and TYPE is 'server':
616             # look up the SRV records for '_jabber._PROTOCOL.HOST'
617             # If successful:
618             # look up in turn the A or AAAA records for
619             # the hostnames mentioned in the SRV records
620             # If unsuccessful so far in looking up SRV records:
621             # look up the A or AAAA records for the 'HOST'
622             #
623             # If unsuccessful in resolving hostnames supplied by SRV records:
624             # treat resolution as unsuccessful.
625              
626             # _xmpp-client._tcp.example.com.
627             # _xmpp-server._tcp.example.com.
628             # jabberserverhostname. 86400 A jabberserverip
629             # _xmpp-server._tcp.jabberserverhostname. 86400 IN SRV 5 0 5269 jabberserverhostname.
630             # _xmpp-client._tcp.jabberserverhostname. 86400 IN SRV 5 0 5222 jabberserverhostname.
631             # _jabber._tcp.jabberserverhostname. 86400 IN SRV 5 0 5269 jabberserverhostname.
632             #
633             # SRV lookups (RFC2781) say:
634             # Do a lookup for QNAME=_service._protocol.target, QCLASS=IN,
635             # QTYPE=SRV.
636             #
637             # If the reply is NOERROR, ANCOUNT>0 and there is at least one
638             # SRV RR which specifies the requested Service and Protocol in
639             # the reply:
640             #
641             # If there is precisely one SRV RR, and its Target is "."
642             # (the root domain), abort.
643              
644              
645             # Does 'abort' in the above mean 'do not continue with SRV processing,
646             # but attempt to resolve the HOST via A or AAAA queries',
647             # 'do not continue with processing this QNAME', or 'do not continue
648             # with resolving the original HOST' ? For example, what happens if
649             # _xmpp-server._tcp.HOST fails in this way, but _jabber._tcp.HOST has
650             # usable information in it?
651              
652             # See what the basename is. Then see if basename;1 has completed.
653 0         0 my $bname = $self->{'_queries'}{';;base'};
654 0         0 my $res = $self->{'_queries'}{';;res'};
655 0         0 my $q1 = $self->{'_queries'}{';;q1'};
656 0         0 my $q2 = $self->{'_queries'}{';;q2'};
657 0         0 my $srvcompleted = 0;
658 0         0 my $srvabort = 0;
659              
660 0 0 0     0 if( defined( $bname ) && defined( $res ) && defined( $q1 ) ){
      0        
661             # There is a query. See if we have exceeded our timeout
662             # value.
663 0         0 my $q1pkt = undef;
664 0         0 my $q2pkt = undef;
665 0         0 my $colsrv = 0;
666 0 0 0     0 if( $self->{'_queries'}{';;end'} < time ){
    0 0        
    0 0        
667 0         0 $retval = 0;
668             }elsif( ! defined( $self->{'_queries'}{$q1}{'completed'} ) && defined( $self->{'_queries'}{$q1}{'start'} ) ){
669             # See if the first query has completed.
670 0         0 my $q1sock = $self->{'_queries'}{$q1}{'sock'};
671 0 0       0 if( $res->bgisready( $q1sock ) ){
672             # It is. Read in the value.
673 0         0 $q1pkt = $res->bgread( $q1sock );
674 0         0 $q1sock = undef;
675 0         0 delete( $self->{'_queries'}{$q1}{'sock'} );
676 0         0 $self->{'_queries'}{$q1}{'completed'} = time;
677 0         0 $colsrv++;
678             }
679             }elsif( defined( $q2 ) && ! defined( $self->{'_queries'}{$q2}{'completed'} ) && defined( $self->{'_queries'}{$q2}{'start'} ) ){
680             # There is a second query, which must be collected
681             # to avoid memory leakage.
682 0         0 my $q2sock = $self->{'_queries'}{$q2}{'sock'};
683 0 0       0 if( $res->bgisready( $q2sock ) ){
684 0         0 $q2pkt = $res->bgread( $q2sock );
685 0         0 $q2sock = undef;
686 0         0 delete( $self->{'_queries'}{$q2}{'sock'} );
687 0         0 $self->{'_queries'}{$q2}{'completed'} = time;
688 0         0 $colsrv++;
689             }
690             }
691              
692             # If the first one was completed, then set a flag for later.
693 0 0 0     0 if( defined( $self->{'_queries'}{$q1}{'completed'} ) && defined( $self->{'_queries'}{$q1}{'start'} ) ){
694 0         0 $srvcompleted++;
695             }
696              
697             # If we collected a SRV result this time, then the return
698             # value is -1, as we're about to send off another few
699             # queries.
700 0 0       0 if( $colsrv ){
701 0         0 $retval = -1;
702              
703             # If we collected the q2 result, check whether the
704             # q1 result was successful. If it was, throw out the
705             # q2 result, as its just extra.
706 0         0 my $wrkpkt = $q1pkt;
707 0 0 0     0 if( defined( $q2pkt ) && defined( $self->{'_queries'}{$q1}{';;success'} ) ){
    0          
708 0         0 $q2pkt = undef;
709             }elsif( defined( $q2pkt ) ){
710 0         0 $wrkpkt = $q2pkt;
711             }
712              
713             # Did we actually get a packet? It could be undef
714             # if q2pkt was something, but q1 was successful.
715 0 0       0 if( defined( $wrkpkt ) ){
716             # Take it apart.
717 0         0 my @answers = $wrkpkt->answer;
718              
719             # Count how many there are.
720 0         0 my $ancount = scalar @answers;
721              
722 0         0 foreach my $answer( @answers ){
723 0 0       0 next unless( $answer->type eq 'SRV' );
724 0         0 my $prio = $answer->priority;
725 0         0 my $wght = $answer->weight;
726 0         0 my $port = $answer->port;
727 0         0 my $target = $answer->target;
728              
729             # If there is just one answer, and
730             # the target is '.', then mark this
731             # one as failed and continue.
732 0 0 0     0 if( $ancount == 1 && $target eq '.' ){
    0 0        
      0        
      0        
733             # Was this q1?
734 0 0       0 if( defined( $q1pkt ) ){
735 0         0 $self->{'_queries'}{$q1}{'fail'}++;
736             }else{
737 0         0 $self->{'_queries'}{$q2}{'fail'}++;
738             }
739             }elsif( $prio =~ /^\s*\d+\s*$/ && $wght =~ /^\s*\d+\s*$/ && $port =~ /^\s*\d+\s*$/ && $target =~ /^\S{2,}$/ ){
740 0         0 my $qname = $self->{'_queries'}{$q1}{'qname'};
741 0 0       0 if( defined( $q1pkt ) ){
742             # Success.
743 0         0 $self->{'_queries'}{$q1}{'success'}++;
744             }else{
745             # Success.
746 0         0 $self->{'_queries'}{$q1}{'success'}++;
747 0         0 $qname = $self->{'_queries'}{$q2}{'qname'};
748             }
749              
750             # Add the result to the
751             # '_resolved' hash as
752             # appropriate.
753 0         0 push @{$self->{'_resolved'}{$qname}{'srv'}{$prio}}, $answer->weight . " " . $port . " " . $target;
  0         0  
754              
755             # Start queries for 'A' and
756             # 'AAAA'. Should these go
757             # into the _queries or
758             # _resolved hash ? _queries,
759             # as that gets cleaned out
760             # and the keys time gets shorter
761 0         0 my $sname = $target . ";1";
762 0 0       0 if( ! defined( $self->{'_queries'}{$sname} ) ){
763 0         0 my $sock = $res->bgsend( $target, "IN", "AAAA" );
764 0         0 $self->{'_queries'}{"$sname"}{"start"} = time;
765 0         0 $self->{'_queries'}{"$sname"}{"sock"} = $sock;
766 0         0 $self->{'_queries'}{"$sname"}{"qname"} = $target;
767 0         0 $self->{'_queries'}{"$sname"}{"qtype"} = "AAAA";
768             }
769 0         0 $sname = $target . ";2";
770 0 0       0 if( ! defined( $self->{'_queries'}{$sname} ) ){
771 0         0 my $sock = $res->bgsend( $target, "IN", "A" );
772 0         0 $self->{'_queries'}{"$sname"}{"start"} = time;
773 0         0 $self->{'_queries'}{"$sname"}{"sock"} = $sock;
774 0         0 $self->{'_queries'}{"$sname"}{"qname"} = $target;
775 0         0 $self->{'_queries'}{"$sname"}{"qtype"} = "A";
776             }
777             }
778             }
779             }
780             }else{ # colsrv.
781 0         0 $retval = -1;
782             # Run through the normal queries that we've got,
783             # and see if any came back.
784 0         0 my %todel = ();
785 0         0 my $foundcount = 0;
786 0         0 foreach my $sname ( keys %{$self->{'_queries'}} ){
  0         0  
787 0 0       0 next unless( $sname =~ /\;\d+$/ );
788 0 0       0 next unless( defined( $self->{'_queries'}{$sname}{'qtype'} ) );
789 0 0       0 next unless( $self->{'_queries'}{$sname}{'qtype'} =~ /^(A|AAAA)$/ );
790 0         0 $foundcount++;
791 0         0 my $sock = $self->{'_queries'}{"$sname"}{"sock"};
792 0         0 my $dpkt = undef;
793 0 0       0 if( defined( $sock ) ){
794 0 0       0 if( $res->bgisready( $sock ) ){
795 0         0 $dpkt = $res->bgread( $sock );
796             }
797             }
798             # Store the socket again.
799 0         0 $self->{'_queries'}{"$sname"}{"sock"} = $sock;
800              
801             # Run through the packet.
802 0 0       0 if( defined( $dpkt ) ){
803 0         0 $todel{"$sname"}++;
804 0         0 my @answers = $dpkt->answers;
805 0         0 foreach my $answer( @answers ){
806 0 0       0 next unless( defined( $answer ) );
807 0 0       0 next unless( $answer->type =~ /^(a|aaaa)$/i );
808 0         0 push @{$self->{'_resolved'}{$self->{'_queries'}{"$sname"}{"qname"}}{'address'}}, $answer->address;
  0         0  
809             }
810             }
811             }
812              
813             # Run through the queries that have been collected.
814 0         0 foreach my $delkey( keys %todel ){
815 0         0 delete( $self->{'_queries'}{$delkey} );
816             }
817              
818 0 0 0     0 if( $foundcount == 0 && $srvcompleted == 1 ){
819 0         0 $retval = 1;
820             }
821             }
822             }
823              
824             #
825             # Else, for all such RR's, build a list of (Priority, Weight,
826             # Target) tuples
827             #
828             # Sort the list by priority (lowest number first)
829             #
830             # Create a new empty list
831             #
832             # For each distinct priority level
833             # While there are still elements left at this priority
834             # level
835             # Select an element as specified above, in the
836             # description of Weight in "The format of the SRV
837             # RR" Section, and move it to the tail of the new
838             # list
839             #
840             # For each element in the new list
841             #
842             # query the DNS for address records for the Target or
843             # use any such records found in the Additional Data
844             # section of the earlier SRV response.
845             #
846             # for each address record found, try to connect to the
847             # (protocol, address, service).
848             #
849             # else
850             #
851             # Do a lookup for QNAME=target, QCLASS=IN, QTYPE=A
852             #
853             # for each address record found, try to connect to the
854             # (protocol, address, service)
855             #
856              
857             }
858            
859              
860             =head1 METHODS - Connecting
861              
862             Before jabbering at other entities, you need to connect to a remote host.
863              
864             =head2 connect
865              
866             Connect to a Jabber server. Only one connection at a time is supported
867             on any given object. Returns 0 if unsuccessful, 1 if successful.
868              
869             Takes a hash of values as follows:
870              
871             =over 4
872              
873             =item Host
874              
875             The Host (name or IP address) to connect to. Default is no host, and
876             thus no connection. Note that if a name of the Host is used, then
877             gethostbyname will be implicitly used by IO::Socket::INET, blocking the
878             application whilst doing so. Calling applications may wish to avail
879             themselves of the ->resolve methods listed earlier to avoid this.
880              
881             =item Port
882              
883             The port to connect to on the remote host. Defaults to 5222.
884              
885             =item Domain
886              
887             The domain to request on the remote Host. Defaults to the value of
888             the Host option. The meaning of this depends on the connection type
889             (StreamXMLNS). If connecting as a client, refers to the domain that the
890             Username and Password credentials belong to. If connecting as a
891             component, refers to the domain that this connection wants to bind as.
892              
893             =item UseSSL
894              
895             Initiate a SSL/TLS connection immediately on connecting, for example, if
896             you are connecting to a server which offers SSL on an alternative port.
897             Defaults to 0. This is used internally to redo the connection.
898              
899             =item UseTLS
900              
901             Negotiate a TLS connection if is listed as one of the connection
902             features, and IO::Socket::SSL is available. Defaults to 1, as everyone likes
903             encryption.
904              
905             =item MustEncrypt
906              
907             The connection must be encrypted before considering the connection to be
908             opened. This defaults to 0. If this is set to 1, and IO::Socket::SSL is not
909             available, the connection will fail.
910              
911             =item JustConnect
912              
913             This simply opens a connection and returns without having sent any packets,
914             except for any required to initiate SSL if requested. The calling program
915             is responsible for sending any initial packets down the link, and
916             responding to any packets received. Defaults to 0.
917              
918             =item JustConnectAndStream
919              
920             This simply opens a connection and sends the initial '' tag,
921             then returns. The default is 0. It is used internally for a number of
922             things, each time a new '' tag needs to be sent, which is
923             surprisingly often (once when connect, once after TLS is negotiated, and
924             once after SASL has been negotiated).
925              
926             =item AllowRedirect
927              
928             This checks to see if the server domain returned to us is the same as the
929             Domain that was requested. The default, 1, allows this check to be skipped.
930              
931             =item StreamXMLNS
932              
933             The type of connection that we're telling the server this is. Defaults
934             to 'jabber:client'. For component connections, use 'jabber:component:accept',
935             and for servers, use 'jabber:server'. Or use the C method
936             documented towards the end (use 'client' or 'component').
937              
938             =item StreamXMLLANG
939              
940             The default language used over the connection, as per xml:lang. Defaults
941             to undef (not sent).
942              
943             =item StreamId
944              
945             A client-initiated Identifier. RFC3920 4.4 says that the stream id
946             SHOULD only be used from the receiving entity to the intiating entity.
947             However, some applications may think otherwise. Defaults to undef (not sent).
948              
949             =item Timeout
950              
951             The number of seconds to hang around whilst waiting for a connection to
952             succeed. Defaults to 30. Note that the time taken for connect may be
953             more than this, as the same value is used in the connection, SSL
954             negotiation and waiting for the remote server to respond phases.
955              
956             Note that during the SSL negotiation, the application will block, due to
957             the perl SSL libraries not obviously supporting a backgroundable method.
958              
959             =item Version
960              
961             The version to declare to the remote Jabber server. The default, '1.0',
962             attempts to steer the conversation along the lines of RFC3920, xmpp-core.
963              
964             =item SSL*
965              
966             Any option beginning with 'SSL' will be passed to IO::Socket::SSL as-is,
967             which may be useful if you are expecting to exchange certificate
968             information. No values are set up by default.
969              
970             =item OwnSocket
971              
972             A boolean which indicates that a socket has previously been created by
973             methods unknown to this library, and stored via ->socket(). Thus,
974             ->connect doesn't actually have to do a TCP connection, and can just
975             continue on with the connection methods.
976              
977             =back
978              
979             Note for people with their own connection requirements: The ->connect
980             method is comparitively simple (ha!); just initiating a TCP connection and
981             setting up handlers to negotiate TLS. Those wishing to set up their
982             own connection handlers are welcome to do so, but search this library's
983             code for the string 'grok incomplete' before doing so.
984              
985             =cut
986              
987             sub connect {
988 0     0   0 my $self = shift;
989              
990 0         0 $self->debug( "connect: Starting up\n" );
991 0         0 my %args = ( Host => undef,
992             Port => 5222,
993             Domain => undef,
994             UseSSL => 0, # Initiate SSL right away.
995             UseTLS => 1, # If found a tag,
996             # take them up on it.
997             MustEncrypt => 0, # Connection must be encrypted
998             # before proceeding
999             JustConnect => 0, # Just connect, ok.
1000             JustConnectAndStream => 0, # Just connect and send the
1001             # opening tag.
1002             AllowRedirect => 1, # The domain that the server
1003             # returns must be the same
1004             # as the domain we supplied.
1005             StreamXMLNS => $self->ConstXMLNS( "client" ),
1006             StreamXMLLANG => undef, # Default language.
1007             StreamId => undef, # Client-side Id. Optional.
1008             Timeout => 30, # Various timeouts
1009             Version => "1.0", # What version do we support?
1010             OwnSocket => 0, # We have our own socket.
1011             _redo => 0, # Used internally to renegotiate
1012             # due to SSL/TLS starting up.
1013             _connectbg => 0, # Used internally as handover
1014             # from bgconnect.
1015             @_,
1016             );
1017              
1018              
1019             # Only one connection at a time.
1020 0         0 my $cango = 0;
1021 0 0       0 if( ! $args{"_redo"} ){
    0          
1022              
1023 0 0       0 if( ! $self->{"OwnSocket"} ){
1024 0 0       0 if( defined( $self->socket ) ){
1025 0         0 $self->disconnect();
1026             }
1027             }
1028            
1029 0         0 $self->{'_is_connected'} = undef;
1030 0         0 $self->{'_is_eof'} = undef;
1031              
1032             # Do you grok incomplete tags? A stream to a Jabber server
1033             # is completely within a '' tag, just a very
1034             # big one. The problem is that this parser will only return
1035             # a complete tag, meaning that ordinarily, it would not
1036             # indicate that it had completed an object until the
1037             # server disconnected us, supplying the closing
1038             # '' text. By setting a tag name within
1039             # the '_expect-incomplete' hash, the parser will consider
1040             # the tag to be complete as soon as it sees a '>' character,
1041             # and will assume it was '/>' instead. This makes logging on
1042             # work much better.
1043 0         0 $self->{'_expect-incomplete'}{"stream:stream"} = 1;
1044 0         0 $self->debug( "connect: setting up incomplete as " . $self->{'_expect-incomplete'} . " X\n" );
1045              
1046             # Attempt to connect to the host.
1047             # Background connecting can be done via the tricks
1048             # shown in Cache::Memcached library, which supports
1049             # background connections.
1050              
1051             # Alternatively, we can forgo supplying the PeerAddr and
1052             # PeerPort when creating the socket, and continually
1053             # invoke the socket's ->connect method until it returns
1054             # something other than EINPROGRESS. Thus, we get
1055             # TCP connections in the background. Yay!
1056 0         0 my $socket = undef;
1057 0 0       0 if( $args{"OwnSocket"} ){
1058 0         0 $socket = $self->socket();
1059             }else{
1060 0         0 $socket = new IO::Socket::INET ( PeerAddr => $args{"Host"},
1061             PeerPort => $args{"Port"},
1062             Proto => "tcp",
1063             MultiHomed => 1,
1064             Timeout => $args{"Timeout"},
1065             Blocking => 0,
1066             );
1067             }
1068              
1069             # Were we able to connect; ie, do we have a socket?
1070 0 0       0 if( defined( $socket ) ){
1071 0         0 $cango = 1;
1072              
1073 0         0 $self->{'_is_connected'} = 1;
1074 0         0 $self->{'_is_encrypted'} = undef;
1075 0         0 $self->{'_is_authenticated'} = undef;
1076 0         0 $self->{'_ask_encrypted'} = undef;
1077              
1078             # Save it. Also sets up the IO::Select construct.
1079 0         0 $self->socket( $socket );
1080             }
1081              
1082             }elsif( defined( $self->socket() ) ){
1083 0         0 $cango = 1;
1084             }
1085              
1086 0 0       0 if( $cango ){
1087             # Start up SSL or TLS as required.
1088             # Has SSL been requested?
1089 0 0 0     0 if( ( $args{"UseSSL"} || $args{"MustEncrypt"} ) && ! $self->_check_val( '_is_encrypted') ){
      0        
1090             # Start SSL.
1091 0         0 my $gotssl = $self->_got_IO_Socket_SSL();
1092              
1093 0 0       0 if( $gotssl ){
1094             # We have to hand over the socket to the
1095             # IO::Socket::SSL library for conversion.
1096 0         0 $gotssl = 0;
1097 0         0 my %SSLHash = ();
1098 0         0 foreach my $kkey( keys %args ){
1099 0 0       0 next unless( $kkey =~ /^SSL/ );
1100 0         0 $SSLHash{"$kkey"} = $args{"$kkey"};
1101             }
1102              
1103 0         0 $self->debug( "connect: Starting up SSL\n" );
1104 0         0 my $newsock = IO::Socket::SSL->start_SSL( $self->socket,
1105             %SSLHash,
1106             );
1107 0 0       0 if( defined( $newsock ) ){
1108 0         0 $self->socket( $newsock );
1109 0         0 $gotssl = 1;
1110 0         0 $self->{'_is_encrypted'} = 1;
1111 0         0 $self->debug( "connect: Successfully started SSL\n" ) ;
1112             }else{
1113 0         0 $self->debug( "connect: Could not start SSL\n" );
1114             }
1115             }
1116              
1117             # If we could not open the ssl libraries or negotiate
1118             # an SSL connection, see if we consider this a failure.
1119 0 0 0     0 if( ! $gotssl && $args{"MustEncrypt"} ){
1120 0         0 $cango = 0;
1121              
1122             # Disconnect.
1123             # print STDERR "NO SSL AND MUST ENCRYPT!\n";
1124 0         0 $self->abort();
1125             }
1126             }
1127             }
1128              
1129             # Were we asked just to connect?
1130 0 0       0 if( $args{"JustConnect"} ){
1131 0         0 return( $cango );
1132             }
1133              
1134             # print STDERR "CONNECT1 HAS $cango\n";
1135              
1136             # Can we still go?
1137 0 0       0 if( $cango ){
1138             # Output the initial tags.
1139             # RFC3920 11.4 says that implementations SHOULD supply
1140             # the opening text declaration (xml version/encoding)
1141 0         0 my $xmlobj = $self->newNode( "?xml" );
1142 0         0 $xmlobj->attr( "version", "1.0" );
1143 0         0 $self->send( $xmlobj );
1144              
1145 0 0       0 if( ! defined( $args{"Domain"} ) ){
1146 0         0 $args{"Domain"} = $args{"Host"};
1147             }
1148              
1149 0         0 my $streamobj = $self->newNode( "stream:stream", $args{"StreamXMLNS"} );
1150 0         0 $streamobj->attr( "xmlns:stream", $self->ConstXMLNS( "stream" ) );
1151 0         0 $streamobj->attr( "to", $args{"Domain"} );
1152 0         0 $streamobj->attr( "version", $args{"Version"} );
1153              
1154 0 0       0 if( defined( $args{"StreamXMLLANG"} ) ){
1155 0         0 $streamobj->attr( "xml:lang", $args{"StreamXMLLANG"} );
1156             }
1157 0 0       0 if( defined( $args{"StreamId"} ) ){
1158 0         0 $streamobj->attr( "id:lang", $args{"StreamId"} );
1159             }
1160              
1161             # We must send this object without a closing '/'.
1162 0         0 $cango = $self->send( $streamobj->toStr( GenClose => 0 ) );
1163             }
1164              
1165             # print STDERR "CONNECT2 HAS $cango\n";
1166              
1167             # Were we asked just to connect and send the initial stream headers?
1168 0 0       0 if( $args{"JustConnectAndStream"} ){
1169 0         0 return( $cango );
1170             }
1171              
1172             # We possibly have output the stream header. Now, we have to wait
1173             # for a response. Were we able to write?
1174 0         0 my $robj = undef;
1175 0 0       0 if( $cango ){
1176             # Set up the initial handlers. This makes the whole connection
1177             # process read much better
1178 0     0   0 $self->register_handler( '?xml', sub { $self->_connect_handler(@_) }, "connect" );
  0         0  
1179 0     0   0 $self->register_handler( 'stream:stream', sub { $self->_connect_handler( @_ ) }, "connect" );
  0         0  
1180 0     0   0 $self->register_handler( 'stream:error', sub { $self->_connect_handler( @_ ) }, "connect" );
  0         0  
1181 0     0   0 $self->register_handler( 'stream:features', sub { $self->_connect_handler( @_ ) }, "connect" );
  0         0  
1182 0     0   0 $self->register_handler( 'proceed', sub { $self->_connect_starttls( @_ ) }, "connect" );
  0         0  
1183 0     0   0 $self->register_handler( 'failure', sub { $self->_connect_starttls( @_ ) }, "connect" );
  0         0  
1184              
1185             # Save the original args.
1186 0         0 %{$self->{'_connectargs'}} = %args;
  0         0  
1187              
1188             # Set some variables.
1189 0         0 $self->{'_is_connected'} = 1;
1190 0         0 $self->{'_is_authenticated'} = undef;
1191 0         0 $self->{'_connect_jid'} = undef;
1192 0         0 $self->{'confirmedns'} = undef;
1193 0         0 $self->{'streamid'} = undef;
1194 0         0 $self->{'streamversion'} = undef;
1195 0         0 $self->{'streamxmlns'} = undef;
1196 0         0 $self->{'streamxml:lang'} = undef;
1197 0         0 $self->{'streamstream:xmlns'} = undef;
1198 0         0 $self->{'stream:error'} = undef;
1199 0         0 $self->{'stream:features'} = undef;
1200              
1201 0         0 %{$self->{'authmechs'}} = ();
  0         0  
1202              
1203             # Wait until the connection checker finishes.
1204 0 0       0 if( ! $args{"_connectbg"} ){
1205 0         0 my $endtime = time + $args{"Timeout"};
1206 0         0 my $stillgoing = 1;
1207 0         0 while( $stillgoing ){
1208 0 0       0 $stillgoing = 0 if( time > $endtime );
1209 0         0 $self->debug( "connect: invoking bgconnected\n" );
1210 0         0 my $tval = $self->bgconnected( RunProcess => 1 );
1211 0 0       0 if( $tval >= 0 ){
1212 0         0 $cango = $tval;
1213 0         0 $stillgoing = 0;
1214             }else{
1215 0         0 select( undef, undef, undef, 0.01 );
1216             }
1217             }
1218             }
1219             }
1220             # print STDERR "CONNECT3 HAS $cango\n";
1221              
1222 0 0       0 if( ! $cango ){
1223             # print STDERR "CONNECT HAS NO CANGO!\n";
1224 0         0 $self->abort();
1225             }
1226              
1227 0         0 $self->debug( "connect: returning $cango\n" );
1228 0         0 return( $cango );
1229             }
1230              
1231             =head2 bgconnect
1232              
1233             The ->bgconnect method is just the same as the ->connect method, except it
1234             returns straight away. Use the ->bgconnected method to test for an answer
1235             to that 4am question, am I connected or not?
1236              
1237             Returns 1 if the TCP connection could be started, and 0 if not. If this
1238             method returns 0, you probably have bigger problems.
1239              
1240             Note: The ->bgconnect method just calls ->connect with the background
1241             flag set.
1242              
1243             =cut
1244              
1245             sub bgconnect {
1246 0     0   0 my $self = shift;
1247 0         0 return( $self->connect( @_, "_connectbg" => 1 ) );
1248             }
1249              
1250             =head2 bgconnected
1251              
1252             This tests to see whether the current connection has succeeded. It
1253             returns -1 if not yet, 0 if failed (and socket has been closed) and
1254             1 if successful. It takes a hash of:
1255              
1256             RunProcess - Invoke ->process internally
1257             ProcessTime - time to pass to ->process (default 0 )
1258              
1259             If RunProcess is not specified, you will have to invoke ->process()
1260             seperately.
1261              
1262             =cut
1263              
1264             sub bgconnected {
1265 0     0   0 my $self = shift;
1266 0         0 my %args = ( RunProcess => 0,
1267             ProcessTime => 0,
1268             @_,
1269             );
1270              
1271 0         0 my $retval = -1;
1272              
1273 0 0       0 if( $args{"RunProcess"} ){
1274 0         0 $self->debug( "bgconnected: invoking process\n" );
1275 0         0 my $tval = $self->process( $args{"ProcessTime"} );
1276 0         0 $self->debug( "bgconnected: invoked process - $tval\n" );
1277 0 0       0 if( $tval == 1 ){
1278 0         0 my $objthrowaway = $self->get_latest();
1279 0         0 $objthrowaway->hidetree;
1280             }
1281             }
1282              
1283 0         0 $self->debug( "bgconnected: invoked\n" );
1284              
1285             # Test a few variables.
1286 0 0       0 if( $self->is_eof() ){
    0          
1287 0         0 $self->debug( "bgconnected: found eof\n" );
1288             # print STDERR ( "bgconnected: found eof\n" );
1289 0         0 $retval = 0;
1290             }elsif( $self->is_connected() > 0 ){
1291 0         0 $retval = 1;
1292             # If we wanted encryption, did we get encryption?
1293 0 0 0     0 if( $self->{'_connectargs'}{"MustEncrypt"} && ! $self->is_encrypted() ){
    0 0        
1294 0         0 $self->debug( "wanted encryption but no encryption\n");
1295 0         0 $retval = -1;
1296              
1297             # Have we asked for encryption to be started?
1298             }elsif( $self->_check_val( '_ask_encrypted' ) && ! $self->is_encrypted() ){
1299 0         0 $self->debug( " asked for encryption but no encryption\n" );
1300 0         0 $retval = -1;
1301             }
1302              
1303             # If we have got a reply host?
1304 0 0 0     0 if( $retval == 1 && $self->_check_val( "confirmedns" ) ){
1305 0 0       0 if( ! $self->{'_connectargs'}{"AllowRedirect"} ){
1306 0 0       0 if( lc( $self->{'confirmedns'} ) ne lc( $self->{'_connectargs'}{"Domain"} ) ){
1307 0         0 $self->debug( " domain mismatch\n" );
1308             # print STDERR ( "bgconnected: domain mismatch\n" );
1309 0         0 $retval = 0;
1310             }
1311             }
1312             }else{
1313 0         0 $self->debug( " retval is not 1 and we do not have a confirmedns yet\n");
1314 0         0 $retval = -1;
1315             }
1316              
1317             # All servers MUST provide a stream id value.
1318 0 0 0     0 if( $retval == 1 && ! $self->_check_val( 'streamid' ) ){
1319 0         0 $self->debug( " no streamid yet");
1320 0         0 $retval = -1;
1321             }
1322              
1323             # All 1.x servers MUST provide the stream:features tag.
1324 0 0 0     0 if( $retval == 1 && $self->_check_val( 'streamversion' ) ){
1325 0 0 0     0 if( $self->{'streamversion'} >= 1.0 && ! $self->_check_val( 'stream:features' ) ){
1326 0         0 $self->debug( " streamversion >= 1.0 but no stream:features yet");
1327 0         0 $retval = -1;
1328             }
1329             }
1330              
1331             # When using encryption or compression, it is possible that
1332             # the encryption engine has not completely sent out the last
1333             # packet that we sent. Lets kick it.
1334 0 0       0 if( $retval == -1 ){
1335 0 0       0 if( ! defined( $self->{'_connecting_prod'} ) ){
    0          
1336 0         0 $self->{'_connecting_prod'} = time;
1337             }elsif( $self->{'_connecting_prod'} < ( time - 5 ) ){
1338 0         0 $self->debug( "prodding the connection" );
1339 0         0 $self->send( "\n" );
1340 0         0 $self->{'_connecting_prod'} = time;
1341             }
1342             }
1343             }else{
1344 0         0 $self->debug( " default set to 0\n");
1345             # print STDERR ( "bgconnected: default set to 0\n");
1346 0         0 $retval = 0;
1347             }
1348              
1349 0         0 $self->debug( " returning $retval\n");
1350 0         0 return( $retval );
1351             }
1352              
1353             =head1 METHODS - Authenticating
1354              
1355             It helps if the remote server knows who you are.
1356              
1357             =head2 authenticate
1358              
1359             Attempt to authenticate to the Jabber server over a connected socket.
1360             It takes a hash of:
1361              
1362             =over 4
1363              
1364             =item Username
1365              
1366             The username to authenticate as.
1367              
1368             =item Password
1369              
1370             The password to use.
1371              
1372             =item Resource
1373              
1374             Specify a resource method to use. If a Resource is not specified, a
1375             default value of 'Jabber::Lite' is used. Note that the Resource
1376             accepted by the server may be different; use ->connect_jid() to find
1377             out what the server considers the Resource to be.
1378              
1379             =item Domain
1380              
1381             The domain to use if the authentication method requires it. Defaults
1382             to the value specified for ->connect().
1383              
1384             =item ComponentSecret
1385              
1386             The secret to use if authenticating as a component, or if the chosen
1387             authentication method requires just a password, not a username.
1388              
1389             =item Method
1390              
1391             The preferred authentication method to use. Either 'sasl' or
1392             'jabber:iq:auth'. The default is 'jabber:iq:auth' (JEP-0078), unless
1393             the server has supplied a list of authentication mechanisms as per
1394             xmpp-core (RFC3920), in which case 'sasl' is used.
1395              
1396             =item Mechanism
1397              
1398             A preferred mechanism to use for authentication. The library will try
1399             to use any available mechanisms that are considered more secure than
1400             the one supplied, but should not try mechanisms that are considered
1401             less secure. The mechanisms available, in order of highest security
1402             to lowest, are:
1403              
1404             =over 4
1405              
1406             =item anonymous
1407              
1408             =item digest-md5
1409              
1410             =item plain
1411              
1412             =back
1413              
1414             =item DoBind
1415              
1416             A boolean indicating whether to bind the nominated resource if so
1417             requested by the remote server. The default, 1, is for applications
1418             that do not wish to deal with this step, or for people for whom
1419             urn:ietf:params:xml:ns:xmpp-bind is at a significant altitude.
1420             If you know what you are doing, set this to 0, and be sure to read
1421             the ->bind() method. Note that if the server requires binding, and
1422             this is not done, the server will most probably return a ''
1423             stanza back and disconnect (so says RFC3920 section 7).
1424              
1425             =item DoSession
1426              
1427             A boolean indicating whether to initiate a session if so requested
1428             by the remote server. The default, 1, is for applications that
1429             do not wish to deal with this step, or for people for whom
1430             urn:ietf:params:xml:ns:xmpp-session is at a significant altitude.
1431             If you know what you are doing, set this to 0, and be sure to read
1432             the ->session() method. Note that if the server requires sessions, and
1433             this is not done, the server will most probably return a ''
1434             stanza back and disconnect (so says RFC3921 section 3).
1435              
1436             =item RandomResource
1437              
1438             A boolean indicating whether a random Resource identifier can be used
1439             in the case of conflicts. Defaults to 0.
1440              
1441             =back
1442              
1443             It returns 1 on success, and 0 on failure.
1444              
1445             =cut
1446              
1447             sub authenticate {
1448 0     0   0 my $self = shift;
1449 0         0 my %args = ( Username => undef,
1450             Password => undef,
1451             Resource => undef,
1452             ComponentSecret => undef,
1453             Domain => $self->{'_connectargs'}{'Domain'},
1454             Method => undef,
1455             Mechanism => undef,
1456             Timeout => 30,
1457             Idval => rand(65535) . $$ . rand(65536),
1458             DoBind => 1,
1459             DoSession => 1,
1460             AllowRandom => 0,
1461             _authbg => 0,
1462             @_,
1463             );
1464              
1465 0         0 my $retval = 0;
1466              
1467 0 0       0 if( ! defined( $args{"Resource"} ) ){
1468             # set a default value.
1469 0         0 $args{"Resource"} = "Jabber::Lite";
1470             }
1471              
1472             # See if we should add jabber:iq:auth method, in addition to
1473             # what the server supplied.
1474 0 0       0 if( defined( $args{"Method"} ) ){
1475 0 0       0 if( $args{"Method"} eq "jabber:iq:auth" ){
1476 0         0 $self->{'authmechs'}{"jabber:iq:auth"} = "1";
1477             }
1478             }
1479              
1480             # This sets up a number of handlers to perform the authentication.
1481             # Set up the initial behaviour.
1482 0         0 $self->{'_ask_handshake'} = undef;
1483 0         0 $self->{'_got_handshake'} = undef;
1484 0         0 $self->{'_ask_iq_auth'} = undef;
1485 0         0 $self->{'_got_iq_auth'} = undef;
1486 0         0 $self->{'_started_auth'} = undef;
1487 0         0 $self->{'_done_auth_sasl'} = undef;
1488 0         0 $self->{'_auth_failed'} = undef;
1489 0         0 $self->{'_auth_finished'} = undef;
1490 0         0 $self->{'saslclient'} = undef;
1491              
1492             # Store the orginal arguments. bgconnected wipes these when
1493             # it returns success or failure to avoid leakage.
1494 0         0 %{$self->{'_authenticateargs'}} = %args;
  0         0  
1495              
1496             # Prime listauths to send the initial packet asking for authentication
1497             # methods, if jabber:iq:auth is one of the options, and we haven't
1498             # been explicitly constrained to use sasl. Yes, this does mean that
1499             # we might send an unneeded packet, but we don't care.
1500 0         0 my $doask = 1;
1501 0 0       0 if( defined( $args{"Method"} ) ){
1502 0 0       0 if( $args{"Method"} eq "sasl" ){
1503 0         0 $doask = 0;
1504             }
1505             }
1506              
1507             # Do not ask the question if we're authenticating as a
1508             # component.
1509 0 0 0     0 if( defined( $args{"ComponentSecret"} ) && $self->_check_val( 'streamxmlns' ) ){
1510             # Make sure the server is expecting a component connection.
1511 0 0       0 if( $self->{'streamxmlns'} eq $self->ConstXMLNS( 'component' ) ){
1512 0         0 $doask = 0;
1513             # Request component authorisation.
1514 0         0 $self->{'_ask_handshake'} = time;
1515             }
1516             }
1517              
1518             # Ask away.
1519 0 0       0 if( $doask ){
1520             # print STDERR "AUTHENTICATE IS ASKING FOR AUTHS\n";
1521 0         0 $self->listauths( Want => 'dontcare', Username => $args{"Username"}, JustAsk => 1 );
1522              
1523             # If we did ask, set up a handler for the response.
1524 0 0       0 if( $self->_check_val( '_ask_iq_auth' ) ){
1525 0         0 $self->debug( "Asked for auths, setting up handler" );
1526             # print STDERR ( "Asked for auths, setting up handler" );
1527 0     0   0 $self->register_handler( "iq", sub { $self->_listauths_handler( @_ ) }, "authenticate" );
  0         0  
1528             }
1529             }
1530              
1531             # Exit if we've been told to. Client will invoke bgauthenticated
1532             # themselves.
1533 0 0       0 if( $self->{'_authbg'} ){
1534 0         0 $self->debug( "client to execute bgauthenticated\n");
1535 0         0 return( -1 );
1536             }
1537              
1538             # Wait for bgauthenticate to do its work.
1539 0         0 my $stillgoing = 1;
1540 0         0 my $endtime = time + $args{"Timeout"};
1541 0         0 while( $stillgoing ){
1542 0 0       0 $stillgoing = 0 if( time > $endtime );
1543              
1544 0         0 $self->debug( "looping on bgauthenticated\n");
1545 0         0 my $tval = $self->bgauthenticated( RunProcess => 1 );
1546              
1547 0 0       0 if( $tval == 0 ){
    0          
1548 0         0 $stillgoing = 0;
1549             # print STDERR "BGAUTHENTICATED RETURNED 0!\n";
1550 0         0 $retval = 0;
1551             }elsif( $tval == 1 ){
1552 0         0 $stillgoing = 0;
1553 0         0 $retval = 1;
1554 0         0 $self->{'_is_authenticated'}++;
1555             }else{
1556 0         0 select( undef, undef, undef, 0.01 );
1557             }
1558             }
1559              
1560 0         0 return( $retval );
1561             }
1562            
1563              
1564             =head2 bgauthenticate
1565              
1566             This accepts the same arguments as ->authenticate(), but returns after
1567             sending the initial packets required to start the authentication
1568             steps.
1569              
1570             Note: This method will block on older servers where ->listauths() has to
1571             ask for a packet.
1572              
1573             =cut
1574              
1575             sub bgauthenticate {
1576 0     0   0 my $self = shift;
1577 0         0 return( $self->authenticate( @_, "_authbg" => 1 ) );
1578             }
1579              
1580             =head2 bgauthenticated
1581              
1582             This tests to see whether the current authentication steps have succeeded.
1583             It returns -1 if not yet, 0 if failed and 1 if successful. It takes a
1584             hash of:
1585              
1586             RunProcess - Invoke ->process internally
1587             ProcessTime - time to pass to ->process (default 0 )
1588              
1589             If RunProcess is not specified, you will have to invoke ->process()
1590             seperately.
1591              
1592             =cut
1593              
1594             sub bgauthenticated {
1595 0     0   0 my $self = shift;
1596 0         0 my %args = ( RunProcess => 0,
1597             ProcessTime => 0,
1598             @_,
1599             );
1600              
1601 0         0 my $retval = 1;
1602              
1603 0         0 my $authas = "client";
1604              
1605 0 0       0 if( $args{"RunProcess"} ){
1606 0         0 $self->debug( "invoking process\n");
1607 0         0 my $tval = $self->process( $args{"ProcessTime"} );
1608 0         0 $self->debug( "invoked process - $tval\n");
1609 0 0       0 if( $tval == 1 ){
    0          
1610 0         0 my $objthrowaway = $self->get_latest();
1611 0         0 $objthrowaway->hidetree;
1612             }elsif( $tval < 0 ){
1613             # print STDERR "BGAUTHENTICATED GOT $tval FROM process\n";
1614 0         0 $retval = 0;
1615             }
1616             }
1617              
1618             # Start considering the options. Client authentication.
1619 0         0 my %availableauths = ();
1620 0 0       0 if( $self->_check_val( '_ask_iq_auth' ) ){
1621 0 0       0 if( ! $self->_check_val( '_got_iq_auth' ) ){
1622 0         0 $retval = -1;
1623             }
1624             }
1625              
1626             # Component checking.
1627 0 0 0     0 if( $retval && $self->_check_val( '_ask_handshake' ) ){
1628 0         0 $authas = "component";
1629 0 0       0 if( ! $self->_check_val( '_started_auth' ) ){
1630 0         0 $self->{'_started_auth'} = time;
1631              
1632             # This is JEP 114 stuff.
1633 0         0 my $handshake = $self->newNode( 'handshake' );
1634 0         0 my $gotdsha1 = $self->_got_Digest_SHA1();
1635 0 0       0 if( $gotdsha1 ){
1636 0         0 $handshake->data( lc( Digest::SHA1::sha1_hex( $self->{'streamid'} . $self->{'_authenticateargs'}{'ComponentSecret'} ) ) );
1637             }
1638 0         0 $self->send( $handshake );
1639 0     0   0 $self->register_handler( "handshake", sub { $self->_bgauthenticated_handler( @_ ) }, "authenticate" );
  0         0  
1640             }
1641              
1642 0 0       0 if( $self->_check_val( '_got_handshake' ) ){
    0          
1643             # XXXX - This is possibly incorrect.
1644             # print STDERR "bgauthenticated: _got_handshake set, setting _auth_finished and retval to 1\n";
1645 0         0 $self->{'_auth_finished'} = 1;
1646 0         0 $retval = 1;
1647             }elsif( $self->_check_val( 'stream:error' ) ){
1648 0         0 $self->{'_auth_finished'} = 0;
1649             # If the wrong secret was supplied, then we disconnect.
1650 0         0 $self->debug( "GOT stream:error" );
1651 0         0 $retval = 0;
1652             }else{
1653 0         0 $retval = -1;
1654             }
1655             }
1656              
1657 0 0 0     0 if( $retval == 1 && ! $self->_check_val( '_started_auth' ) ){
    0 0        
    0 0        
    0 0        
      0        
      0        
      0        
      0        
      0        
      0        
1658 0         0 %availableauths = $self->listauths( Want => 'hash' );
1659              
1660 0         0 my $chosenauth = undef;
1661 0         0 my %rauths = ();
1662 0         0 my $somesasl = 0;
1663              
1664             # Strain out the auths that are not suitable.
1665 0         0 foreach my $kkey( keys %availableauths ){
1666 0         0 my $tkey = lc( $kkey );
1667 0         0 $self->debug( " Found auth $kkey\n");
1668             # print STDERR ( " Found auth $kkey\n");
1669              
1670 0         0 my $jiqauth = 0;
1671              
1672 0 0       0 if( defined( $self->{'_authenticateargs'}{"Method"} ) ){
1673 0         0 my $mtest = lc( $self->{'_authenticateargs'}{"Method"} );
1674 0 0       0 next unless( $kkey =~ /^$mtest\-/ );
1675              
1676 0 0       0 $jiqauth = 1 if( $kkey eq "jabber:iq:auth" );
1677             }
1678              
1679 0 0       0 if( defined( $self->{'_authenticateargs'}{"Mechanism"} ) ){
1680 0         0 my $mtest = lc( $self->{'_authenticateargs'}{"Mechanism"} );
1681              
1682             # Remap the name if preferring jabber:iq:auth
1683             # TODO 0.9 - Check this logic.
1684             # if( $jiqauth ){
1685             # $mtest = "token" if( $mtest eq "anonymous" );
1686             # $mtest = "digest" if( $mtest eq "digest-md5" );
1687             # $mtest = "password" if( $mtest eq "plain" );
1688             #
1689             # }
1690 0 0       0 next unless( $kkey =~ /^[^\-\]\-$mtest$/ );
1691             }
1692              
1693             # Bypass the 'sequence' tag; we catch the 'token' tag
1694             # instead.
1695 0 0       0 next if( $tkey =~ /^jabber:iq:auth\-sequence$/i );
1696              
1697             # Get a score for the auth.
1698 0         0 $rauths{lc($tkey)}++;
1699              
1700             # print STDERR " Using $tkey?\n";
1701              
1702 0 0       0 if( $tkey =~ /^sasl\-/ ){
1703 0         0 $somesasl++;
1704             }
1705             }
1706              
1707             # Prepare possible packets to send.
1708 0         0 my $saslxmlns = $self->ConstXMLNS( "xmpp-sasl" );
1709 0         0 my $saslpkt = $self->newNode( "auth", $saslxmlns );
1710              
1711 0         0 my $idval = rand(65535) . $$ . rand(65536);
1712 0         0 my $iqpkt = $self->newNode( "iq" );
1713 0         0 $iqpkt->attr( 'type', 'set' );
1714 0         0 $iqpkt->attr( 'to', $self->{'_authenticateargs'}{"Domain"} );
1715 0         0 $iqpkt->attr( 'id', $idval );
1716 0         0 my $querytag = $iqpkt->insertTag( 'query', "jabber:iq:auth" );
1717 0         0 my $utag = $querytag->insertTag( 'username' );
1718 0         0 $utag->data( $self->{'_authenticateargs'}{"Username"} );
1719 0         0 my $rtag = $querytag->insertTag( 'resource' );
1720 0         0 $rtag->data( $self->{'_authenticateargs'}{"Resource"} );
1721              
1722             # See what libraries have been installed. Try to load
1723             # both Digest::SHA1 and Authen::SASL. If we can't load
1724             # Authen::SASL, then we fall back on Digest::SHA1, then
1725             # to plain, if we haven't eliminated it by a supplied
1726             # Method or Mechanism, and the server has provided
1727             # the 'plain' mechanism. Phew.
1728 0         0 my $gotdsha1 = $self->_got_Digest_SHA1();
1729 0         0 my $gotasasl = $self->_got_Authen_SASL();
1730 0         0 my $gotmba64 = $self->_got_MIME_Base64();
1731              
1732             # Run through the auths known or approved.
1733 0         0 my $sendsasl = 0;
1734 0         0 my $sasl = undef;
1735 0         0 my $sendiq = 0;
1736 0         0 my $usedauth = undef;
1737              
1738             # We let Authen::SASL do the work.
1739 0 0 0     0 if( $somesasl && $gotasasl && $gotmba64 ){
    0 0        
    0 0        
    0 0        
      0        
1740 0         0 my @mechs = ();
1741 0         0 foreach my $kkey( keys %rauths ){
1742 0 0       0 next unless( $kkey =~ /^sasl\-(\S+)$/i );
1743 0         0 push @mechs, uc( $1 );
1744             }
1745              
1746             # Set up the Authen::SASL handle. Copied from
1747             # XML::Stream
1748 0         0 $sasl = Authen::SASL->new( mechanism => join( " ", @mechs ),
1749             callback => {
1750             authname => $self->{'_authenticateargs'}{"Username"} . "@" . $self->{'_authenticateargs'}{"Domain"},
1751             user => $self->{'_authenticateargs'}{"Username"},
1752             pass => $self->{'_authenticateargs'}{"Password"},
1753             },
1754             );
1755 0         0 $self->{'_saslclient'} = $sasl->client_new();
1756              
1757 0         0 my $first_step = $self->{'_saslclient'}->client_start();
1758 0         0 my $first_step64 = MIME::Base64::encode_base64( $first_step, "" );
1759 0         0 $saslpkt->attr( 'mechanism', $self->{'_saslclient'}->mechanism() );
1760 0         0 $saslpkt->data( $first_step64 );
1761              
1762 0         0 $sendsasl++;
1763              
1764             }elsif( defined( $rauths{"jabber:iq:auth-token"} ) && $gotdsha1 && 1 == 2 ){
1765             # zero knowledge. We snarf the original values.
1766             # Copied from Jabber::Connection. This code does not
1767             # work against my server, so is disabled.
1768 0         0 $sendiq++;
1769 0         0 $usedauth = "jabber:iq:auth-zerok";
1770 0         0 my $htag = $querytag->insertTag( 'hash' );
1771 0         0 my $hval = DIGEST::SHA1::sha1_hex( $self->{'Password'} );
1772 0         0 my $seq = $availableauths{"jabber:iq:auth-sequence"};
1773 0         0 my $token = $availableauths{"jabber:iq:auth-token"};
1774 0         0 $self->debug( " Got seq of $seq and $token X\n");
1775 0         0 $hval = Digest::SHA1::sha1_hex( $hval . $token );
1776             # Aie! Keep hashing until sequence decremented to 0??
1777 0         0 $hval = Digest::SHA1::sha1_hex( $hval ) while( $seq-- );
1778 0         0 $htag->data( $hval );
1779              
1780             }elsif( defined( $rauths{"jabber:iq:auth-digest"} ) && $gotdsha1 ){
1781             # digest
1782 0         0 $sendiq++;
1783 0         0 $usedauth = "jabber:iq:auth-digest";
1784 0         0 my $dtag = $querytag->insertTag( 'digest' );
1785 0         0 $dtag->data( Digest::SHA1::sha1_hex( $self->{'streamid'} . $self->{'_authenticateargs'}{"Password"} ) );
1786             }elsif( defined( $rauths{"jabber:iq:auth-password"} ) ){
1787             # plain password.
1788 0         0 $sendiq++;
1789 0         0 $usedauth = "jabber:iq:auth-plain";
1790 0         0 my $ptag = $querytag->insertTag( 'password' );
1791 0         0 $ptag->data( $self->{'_authenticateargs'}{"Password"} );
1792             }
1793              
1794 0 0       0 if( $sendsasl ){
    0          
1795 0 0       0 $self->debug( "bgauthenticate: Sending sasl packet: " . $saslpkt->toStr . "\n" ) if( $self->_check_val( '_debug' ) );
1796 0         0 $self->send( $saslpkt );
1797 0         0 $self->{'_started_auth'} = "sasl";
1798 0         0 $retval = -1;
1799 0     0   0 $self->register_handler( "failure", sub { $self->_bgauthenticated_handler( @_ ) }, "authenticate" );
  0         0  
1800 0     0   0 $self->register_handler( "success", sub { $self->_bgauthenticated_handler( @_ ) }, "authenticate" );
  0         0  
1801 0     0   0 $self->register_handler( "challenge", sub { $self->_bgauthenticated_handler( @_ ) }, "authenticate" );
  0         0  
1802              
1803             }elsif( $sendiq ){
1804 0 0       0 $self->debug( "bgauthenticate: Sending iq packet: " . $iqpkt->toStr . "\n" ) if( $self->_check_val( '_debug' ) );
1805             # print STDERR "Sending " . $iqpkt->toStr . "\n";
1806 0         0 $self->send( $iqpkt );
1807 0         0 $self->{'_started_auth'} = "iq-auth";
1808              
1809             # Say that we attempted authentication.
1810 0         0 $self->{'_sent_iq_auth'} = $idval;
1811 0         0 $retval = -1;
1812              
1813             # Set up a handler for this.
1814 0     0   0 $self->register_handler( "iq", sub { $self->_bgauthenticated_handler( @_ ) }, "authenticate" );
  0         0  
1815             }else{
1816             # We haven't been able to choose an authentication method.
1817 0         0 $self->debug( "INDECISIVE RE AUTH METHODS" );
1818 0         0 $retval = 0;
1819             }
1820              
1821             }elsif( $retval == 1 && $self->_check_val( '_started_auth' ) && $self->_check_val( "_sent_iq_auth" ) && $authas eq "client" ){
1822             # See if the value is set.
1823              
1824 0 0 0     0 if( $retval == 1 && $self->_check_val( '_auth_finished' ) ){
1825 0         0 $retval = $self->{'_auth_finished'};
1826              
1827             }
1828              
1829             }elsif( $retval == 1 && $self->_check_val( '_started_auth' ) && $authas eq "client" && ! $self->_check_val( '_auth_failed' ) ){
1830              
1831             # Check to see if we are waiting on the server to
1832             # reissue the tag.
1833 0 0       0 if( $self->_check_val( '_need_auth_stream' ) ){
1834 0 0       0 if( $self->bgconnected != 1 ){
1835 0         0 $self->debug( "Waiting on auth stream" );
1836 0         0 $retval = -1;
1837             }
1838             }
1839              
1840             # Now, check to see if we need to set up resource binding.
1841             # if( $retval == 1 && ! $self->_check_val( '_need_auth_bind' ) && ! $self->_check_val( '_auth_finished' ) ){
1842 0 0 0     0 if( $retval == 1 && ! $self->_check_val( '_need_auth_bind' ) ){
    0 0        
      0        
1843             # Do we need to do the binding?
1844 0 0       0 if( $self->{'_authenticateargs'}{"DoBind"} ){
1845 0         0 $retval = $self->bind( Process => "if-required", Resource => $self->{'_authenticateargs'}{"Resource"}, AllowRandom => $self->{'_authenticateargs'}{"RandomResource"}, _bindbg => 1 );
1846             }else{
1847 0         0 $self->{'_done_auth_bind'} = 1;
1848             }
1849 0         0 $self->debug("Waiting on bind result" );
1850 0         0 $retval = -1;
1851             }elsif( $retval == 1 && $self->_check_val( '_need_auth_bind' ) && ! $self->_check_val( '_done_auth_bind' ) ){
1852             # Have we got the results from the bind back?
1853 0         0 $retval = -1;
1854 0         0 $self->debug( " checking result of bgbinded\n");
1855 0 0       0 if( $self->bgbinded() == 1 ){
1856 0         0 $retval = 1;
1857             }
1858             }
1859              
1860             # How about sessions?
1861 0         0 $self->debug( "About to check on session? retval is $retval, _need_auth_session is " . $self->_check_val( '_need_auth_session' ) . ", _auth_finished is " . $self->_check_val( '_auth_finished' ) . " E " );
1862             # if( $retval == 1 && ! $self->_check_val( '_need_auth_session' ) && ! $self->_check_val( '_auth_finished' ) ){
1863 0 0 0     0 if( $retval == 1 && ! $self->_check_val( '_need_auth_session' ) ){
    0 0        
1864             # Do we need to do the binding?
1865 0         0 $self->debug( " need session?" );
1866 0 0       0 if( $self->{'_authenticateargs'}{"DoSession"} ){
1867 0         0 $retval = $self->session( Process => "if-required", _sessionbg => 1 );
1868             }else{
1869 0         0 $self->{'_done_auth_session'} = 1;
1870             }
1871 0         0 $self->debug("Waiting on session result" );
1872 0         0 $retval = -1;
1873             # }elsif( $retval == 1 && $self->_check_val( '_need_auth_session' ) && ! $self->_check_val( '_auth_finished' ) ){
1874             }elsif( $retval == 1 && $self->_check_val( '_need_auth_session' ) ){
1875             # Have we got the results from the bind back?
1876 0         0 $retval = -1;
1877 0         0 $self->debug( " checking result of bgsessioned\n");
1878 0 0       0 if( $self->bgsessioned() == 1 ){
1879 0         0 $retval = 1;
1880             }
1881             }
1882              
1883 0 0 0     0 if( $retval == 1 && $self->_check_val( '_auth_finished' ) ){
    0          
1884 0         0 $retval = $self->{'_auth_finished'};
1885              
1886             # Make sure we record that we were authenticated.
1887 0 0       0 if( $retval > 0 ){
1888 0         0 $self->{'_is_authenticated'} = 1;
1889             }
1890              
1891             }elsif( ! $self->_check_val( '_auth_finished' ) ){
1892             # print STDERR "BGAUTHENTICATED IS UNKNOWN\n";
1893 0         0 $self->debug( "unknown condition - retval is 1 but _auth_finished is not set" );
1894 0         0 $retval = -1;
1895             }
1896             }elsif( $retval == 1 && $self->_check_val( '_started_auth' ) && $authas eq "client" && $self->_check_val( '_auth_failed' ) ){
1897 0         0 $retval = 0;
1898 0         0 $self->{'_is_authenticated'} = undef;
1899             }
1900              
1901 0 0       0 if( $retval >= 0 ){
1902             # Success or failure.
1903              
1904             # Set the connect jid if required.
1905 0 0 0     0 if( $retval > 0 && ! defined( $self->{'_connect_jid'} ) ){
1906             # Save the connect_jid.
1907 0         0 $self->{'_connect_jid'} = $self->{'_authenticateargs'}{'Username'} . "@" . $self->{'_authenticateargs'}{"Domain"};
1908 0 0       0 if( defined( $self->{'_authenticateargs'}{"Resource"} ) ){
1909 0         0 $self->{'_connect_jid'} .= "/" . $self->{'_authenticateargs'}{"Resource"};
1910             }
1911             }
1912              
1913             # Delete the authenticate args
1914 0         0 delete( $self->{'_authenticateargs'} );
1915             }
1916              
1917 0         0 $self->debug( "Returning with $retval" );
1918 0         0 return( $retval );
1919             }
1920              
1921             sub _bgauthenticated_handler {
1922 0     0   0 my $self = shift;
1923 0         0 my $node = shift;
1924 0         0 my $persisdata = shift;
1925              
1926 0         0 my $retval = undef;
1927              
1928 0         0 $self->debug( "invoked\n" );
1929 0         0 my $sendtype = $self->{'_started_auth'};
1930              
1931 0 0 0     0 if( defined( $node ) && defined( $sendtype ) ){
1932 0         0 my $saslxmlns = $self->ConstXMLNS( 'xmpp-sasl' );
1933              
1934 0 0 0     0 if( $node->name eq 'handshake' ){
    0          
    0          
1935             # Handshake is empty if all good.
1936 0 0       0 if( $self->_check_val( '_ask_handshake' ) ){
1937 0         0 $self->{'_got_handshake'} = time;
1938 0         0 $retval = r_HANDLED;
1939             }
1940 0 0       0 $self->debug( "got " . $node->toStr . " X \n" ) if( $self->_check_val( '_debug' ) );
1941             }elsif( $sendtype eq "iq-auth" && $node->name eq 'iq' ){
1942 0         0 my $idval = $self->{'_sent_iq_auth'};
1943 0         0 $self->debug( "got back iq result - want $idval" );
1944             # print STDERR ( "got back iq result (" . $node->attr('id') . ") - want $idval " . $node->toStr . "\n" );
1945 0 0       0 if( defined( $idval ) ){
1946 0 0       0 if( $node->attr('id') eq $idval ){
1947 0         0 $retval = r_HANDLED;
1948 0 0       0 if( $node->attr('type') eq 'result' ){
1949             # XXXX - check for error here??
1950 0         0 $self->debug( "got back iq result - auth successful?" );
1951 0         0 $self->{'_auth_finished'} = 1;
1952 0         0 $self->{'_connect_jid'} = $self->{'_authenticateargs'}{'Username'} . "@" . $self->{'_authenticateargs'}{"Domain"};
1953 0 0       0 if( defined( $self->{'_authenticateargs'}{"Resource"} ) ){
1954 0         0 $self->{'_connect_jid'} .= "/" . $self->{'_authenticateargs'}{"Resource"};
1955             }
1956             }else{
1957             # Not successful.
1958 0         0 $self->debug( "got back iq something, auth not successful." );
1959 0         0 $self->{'_auth_finished'} = 0;
1960 0         0 $self->{'_auth_failed'} = 1;
1961             }
1962             }
1963             }
1964              
1965             # No? Maybe its the next step in the sasl
1966             # authentication.
1967             }elsif( $sendtype eq "sasl" ){
1968 0 0 0     0 if( ( $node->name eq 'failure' || $node->name eq 'abort' ) && $node->xmlns() eq $saslxmlns ){
    0 0        
    0 0        
      0        
1969             # Failed to authenticate. Return 0 to
1970             # the caller; note that the connection
1971             # is still in place (RFC3920 6.2).
1972             # 'abort' is slightly odd here, in that
1973             # we are the initiating entity, but
1974             # just in case we're talking to some
1975             # braindead server...
1976 0         0 $self->{'_auth_finished'} = 0;
1977 0         0 $self->{'_done_auth_sasl'} = 1;
1978 0         0 $self->{'_auth_failed'} = 1;
1979 0         0 $retval = r_HANDLED;
1980             }elsif( $node->name eq 'success' && $node->xmlns() eq $saslxmlns ){
1981             # We've succeeded.
1982 0         0 $self->{'_auth_finished'} = 1;
1983 0         0 $self->{'_done_auth_sasl'} = 1;
1984 0         0 $self->{'_auth_failed'} = undef;
1985 0         0 $retval = r_HANDLED;
1986              
1987             # We need to resend the initial
1988             # '' header (RFC3920 6.2) again.
1989             # If we've done SSL, that means that we'll have
1990             # done 3 so far. We re-use bgconnected to test
1991             # for the appearance of the
1992             # tag again; Remember that those connect
1993             # handlers are still set up.
1994 0         0 $self->{'stream:features'} = undef;
1995              
1996             # Implementation bug: Missing the domain
1997             # ('to') from the tag after
1998             # successful SASL authentication results in
1999             # jabberd2's c2s component dying.
2000 0         0 $self->connect( '_redo' => 1, JustConnectAndStream => 1, Domain => $self->{'_authenticateargs'}{"Domain"} );
2001 0         0 $self->{'_need_auth_stream'} = 1;
2002              
2003             }elsif( $node->name eq 'challenge' && $node->xmlns() eq $saslxmlns ){
2004 0         0 $retval = r_HANDLED;
2005 0         0 my $ctext64 = $node->data();
2006 0         0 my $ctext = MIME::Base64::decode_base64( $ctext64 );
2007 0         0 my $rtext = "";
2008             # XML::Stream notes that a challenge
2009             # containing 'rspauth=' is essentially
2010             # a no-op; we've successfully authed.
2011             # Authen::SASL whinges about it though.
2012 0 0       0 if( $ctext !~ /rspauth\=/ ){
2013 0         0 $rtext = $self->{'_saslclient'}->client_step( $ctext );
2014             }
2015 0         0 my $rtext64 = MIME::Base64::encode_base64( $rtext , "" );
2016 0         0 my $saslpkt = $self->newNode( 'response', $saslxmlns );
2017 0         0 $saslpkt->data( $rtext64 );
2018 0         0 $self->send( $saslpkt );
2019             }
2020             }
2021             }
2022              
2023 0         0 return( $retval );
2024             }
2025              
2026             =head2 auth
2027              
2028             This is the Jabber::Connection compatibility call. It takes 1 or 3 arguments,
2029             being either the shared password (for use when connecting as a component),
2030             or the username, password and resource. It returns 1 if successful, 0
2031             if unsuccessful.
2032              
2033             =cut
2034              
2035             sub auth {
2036 0     0   0 my $self = shift;
2037 0         0 my $username = shift;
2038 0         0 my $password = shift;
2039 0         0 my $resource = shift;
2040              
2041 0         0 my $retval = 0;
2042              
2043 0 0       0 if( ! defined( $password ) ){
2044 0         0 $retval = $self->authenticate( ComponentSecret => $username );
2045             }else{
2046 0         0 $retval = $self->authenticate( Username => $username,
2047             Password => $password,
2048             Resource => $resource,
2049             );
2050             }
2051              
2052 0         0 return( $retval );
2053             }
2054              
2055             =head2 AuthSend
2056              
2057             This is the Net::XMPP::Protocol/Net::Jabber::Component compatibility call.
2058             It takes a hash of 'username', 'password' and 'resource', or "secret" and
2059             returns a @list of two values, being a success ('ok')/failure string, and
2060             a message. Note that apart from 'ok', the success/failure string may not
2061             be the same as returned by the Net::XMPP libraries.
2062              
2063             =cut
2064              
2065             sub AuthSend {
2066 0     0   0 my $self = shift;
2067 0         0 my %args = ( username => undef,
2068             password => undef,
2069             resource => undef,
2070             secret => undef,
2071             @_,
2072             );
2073              
2074 0         0 my $retval = "not ok";
2075 0         0 my $retmsg = "Reason unknown";
2076              
2077 0         0 my $tval = $self->authenticate( Username => $args{"username"},
2078             Password => $args{"password"},
2079             Resource => $args{"resource"},
2080             ComponenetSecret => $args{"secret"},
2081             );
2082              
2083 0 0       0 if( $tval == 1 ){
    0          
2084 0         0 $retval = "ok";
2085 0         0 $retmsg = "authentication successful, happy jabbering";
2086             }elsif( $tval == 0 ){
2087 0         0 $retval = "not ok";
2088 0         0 $retmsg = "authenticate returned 0";
2089             }
2090              
2091 0         0 return( $retval, $retmsg );
2092             }
2093              
2094             =head1 METHODS - Dealing with
2095              
2096             Some incidental things.
2097              
2098             =head2 stream_features
2099              
2100             This method returns the latest tag received from the
2101             server, or undef. It is used internally by the ->bind and ->session methods.
2102              
2103             Note that during the ->connect() and ->authenticate() phases, certain of
2104             these features may get 'used', and thus not returned by the server the
2105             next time it issues a tag.
2106              
2107             =cut
2108              
2109             sub stream_features {
2110 0     0   0 my $self = shift;
2111              
2112 0         0 return( $self->{'stream:features'} );
2113             }
2114              
2115             =head2 listauths
2116              
2117             This method lists the authentication methods available either to the library
2118             or provided by this Jabber server by way of . An optional
2119             hash may be provided, where 'Ask' triggers the asking of the server for
2120             authentication information according to the 'jabber:iq:auth' namespace
2121             (JEP-0078), with the optional 'Username' being supplied as required.
2122              
2123             The return value is either an @array or %hash of possible authentication
2124             methods and mechanisms depending on the 'Want' option ('array' or 'hash'),
2125             arranged as per 'method-mechanism', eg 'sasl-digest-md5' or
2126             'jabber:iq:auth-plain'.
2127              
2128             This method should be called after ->connect(), obviously.
2129              
2130             Note: If Ask (or JustAsk) is specified, this method will call ->process,
2131             until it gets the reply it is expecting. If other packets are expected
2132             during this time, use ->register_handler to set up callbacks for them,
2133             making sure that any packets in the
2134             'jabber:iq:auth' namespace ( subtag) are not swallowed.
2135              
2136             =cut
2137              
2138             # This method gets called by ->authenticate, and is mainly useful
2139             # for finding out jabber:iq:auth methods.
2140             sub listauths {
2141 0     0   0 my $self = shift;
2142 0         0 my %args = ( Username => undef,
2143             Domain => $self->{'_connectargs'}{'Domain'},
2144             Ask => 0, # Whether to ask the server.
2145             JustAsk => 0, # Used by ->authenticate.
2146             Want => 'hash', # The return type.
2147             Timeout => 30, # How long to wait for
2148             # a valid answer.
2149             _internalvar => 0, # Preparation to doing
2150             # a handler-based method.
2151             HaveAsked => 0, # This is not used yet.
2152             Idval => rand(65535) . $$ . rand(65536),
2153             @_,
2154             );
2155              
2156 0         0 my @retarr = ();
2157 0         0 my %rethash = ();
2158 0         0 my %retint = ();
2159              
2160             # Run through the listings that we have cached. If we have
2161             # a Username, and 'jabber:iq:auth' is in the listing, set up
2162             # a handler and send off a question.
2163 0         0 my $stillgoing = 1;
2164 0         0 my $havesent = $args{"HaveAsked"};
2165 0         0 my $gotans = 0;
2166              
2167             # Work out a random identifier if required.
2168 0         0 my $idval = $args{"Idval"};
2169 0         0 my $endtime = time + $args{"Timeout"};
2170 0         0 my $deliqauth = 0;
2171 0   0     0 while( $stillgoing && time < $endtime ){
2172 0         0 $stillgoing = 0;
2173 0         0 foreach my $thisauth ( keys %{$self->{'authmechs'}} ){
  0         0  
2174 0         0 $self->debug( " Found auth $thisauth\n" );
2175 0 0       0 if( $thisauth eq 'jabber:iq:auth' ){
2176 0 0 0     0 if( ( $args{"Ask"} || $args{"JustAsk"} ) && ! $havesent ){
    0 0        
      0        
      0        
2177             # Send off the query.
2178 0         0 my $sendpkt = $self->newNode( "iq" );
2179 0         0 $sendpkt->attr( 'type', 'get' );
2180 0         0 $sendpkt->attr( 'id', $idval );
2181 0         0 $sendpkt->attr( 'to', $args{"Domain"} );
2182 0         0 my $querytag = $sendpkt->insertTag( 'query', 'jabber:iq:auth' );
2183 0 0       0 if( defined( $args{"Username"} ) ){
2184 0         0 my $utag = $querytag->insertTag( 'username' );
2185 0         0 $utag->data( $args{"Username"} );
2186             }
2187 0         0 $self->{'_ask_iq_auth'} = $idval;
2188 0         0 $self->debug( "Asking about authentication methods" );
2189 0         0 $havesent = $self->send( $sendpkt );
2190 0 0       0 $stillgoing = 1 if( ! $self->{"JustAsk"} );
2191 0         0 $self->{'_authask'} = $idval;
2192             }elsif( $args{"Ask"} && $havesent && ! $gotans ){
2193 0         0 $stillgoing = 1;
2194              
2195             # Invoke ->process to see if we got
2196             # something.
2197              
2198             # XXXX This is the only place we
2199             # collect an object directly during the
2200             # authentication process, and thats
2201             # only if 'JustAsk' is not specified.
2202 0         0 $self->debug( "looping for result\n");
2203 0         0 my $tval = $self->process( 1 );
2204 0         0 my $tobj = undef;
2205 0         0 my $querytag = undef;
2206 0 0       0 if( $tval == 1 ){
2207 0         0 $tobj = $self->get_latest();
2208             }
2209              
2210             # We hand the processing off to the
2211             # normal handler function for this
2212             # packet type manually. This is only
2213             # relevant if 'Ask' is specified.
2214 0 0       0 if( defined( $tobj ) ){
2215 0         0 my $tval = $self->_listauths_handler( $tobj, undef );
2216 0 0       0 if( defined( $tval ) ){
2217 0 0       0 if( $tval eq r_HANDLED ){
2218 0         0 $gotans++;
2219 0         0 $deliqauth++;
2220             }
2221             }
2222 0         0 $tobj->hidetree;
2223             }
2224             }
2225             }else{
2226 0         0 $rethash{"$thisauth"} = $self->{"authmechs"}{"$thisauth"};
2227             }
2228             }
2229             }
2230              
2231             # Delete the 'jabber:iq:auth' string from the available authentication
2232             # mechanisms, to avoid retriggering the same query/response pattern
2233             # if this is used later. Would probably screw something up then.
2234 0 0       0 if( $deliqauth ){
2235 0         0 delete( $self->{'authmechs'}{'jabber:iq:auth'} );
2236             }
2237              
2238             # Find out if an @array is wanted in response.
2239 0 0       0 if( $args{"Want"} eq "array" ){
    0          
2240 0         0 foreach my $thisauth( keys %rethash ){
2241 0         0 $self->debug( " Array? Sending back $thisauth as " . $rethash{"$thisauth"} . " X \n" );
2242 0         0 push @retarr, $thisauth;
2243             }
2244 0         0 return( @retarr );
2245             }elsif( $args{"Want"} eq "hash" ){
2246 0         0 foreach my $thisauth( keys %rethash ){
2247 0         0 $self->debug( " Hash? Sending back $thisauth as " . $rethash{"$thisauth"} . " X \n" );
2248             }
2249 0         0 return( %rethash );
2250             }
2251             }
2252              
2253             sub _listauths_handler {
2254 0     0   0 my $self = shift;
2255 0         0 my $node = shift;
2256 0         0 my $persisdata = shift;
2257 0         0 my $retval = undef;
2258 0         0 my $gotans = 0;
2259              
2260 0         0 $self->debug( "invoked\n" );
2261 0         0 my $idval = $self->{'_ask_iq_auth'};
2262 0 0 0     0 if( defined( $node ) && defined( $idval ) ){
2263 0         0 my $querytag = undef;
2264 0 0 0     0 if( $node->name() eq 'iq' && $node->attr('id') eq $idval ){
2265 0 0       0 if( $node->attr( 'type' ) eq 'result' ){
    0          
2266             # Get the query tag.
2267 0         0 $querytag = $node->getTag( 'query', 'jabber:iq:auth' );
2268 0         0 $gotans++;
2269             }elsif( $node->attr( 'type' ) eq 'error' ){
2270             # Don't we need to set something for negative?
2271 0         0 $self->{'_got_iq_auth'} = time;
2272 0         0 $retval = r_HANDLED;
2273             }
2274             }
2275              
2276             # Run through the list that we
2277             # received in response.
2278 0 0       0 if( defined( $querytag ) ){
2279 0         0 $retval = r_HANDLED;
2280 0         0 foreach my $cnode( $querytag->getChildren() ){
2281 0         0 $self->debug( "Received back " . $cnode->name . "\n" );
2282 0 0       0 next if( lc($cnode->name) =~ /^(username|resource)$/i );
2283 0         0 $self->{"authmechs"}{"jabber:iq:auth-" . lc( $cnode->name() )}++;
2284             # Special case.
2285 0 0       0 if( lc($cnode->name) =~ /^(token|sequence)$/i ){
2286 0         0 $self->{"authmechs"}{"jabber:iq:auth-" . lc( $cnode->name() )} = $cnode->data();
2287             }
2288             # $deliqauth++;
2289 0         0 $self->{'_got_iq_auth'} = time;
2290             }
2291             }
2292             }
2293 0         0 return( $retval );
2294             }
2295              
2296             =head2 session
2297              
2298             Starts a session with the remote server, if required by the
2299             packet. Called internally by ->authenticate() if DoSession is set as the
2300             default '1'. Takes an optional hash of:
2301              
2302             =over 4
2303              
2304             =item Process
2305              
2306             A string of either 'if-required' or 'always', indicating whether to always
2307             do so, or just if required to do so.
2308              
2309             =back
2310              
2311             Returns 1 if successful, 0 otherwise.
2312              
2313             =cut
2314              
2315             sub session {
2316 0     0   0 my $self = shift;
2317 0         0 my %args = ( Process => "if-required",
2318             Timeout => 60,
2319             _sessionbg => 0,
2320             @_,
2321             );
2322              
2323 0         0 my $retval = 0;
2324              
2325             # See if we have to do this.
2326 0         0 my $doso = 0;
2327 0 0       0 if( $args{"Process"} eq "if-required" ){
    0          
2328 0         0 my $stag = $self->stream_features();
2329 0 0       0 if( defined( $stag ) ){
2330 0         0 my $btag = $stag->getTag( "session", $self->ConstXMLNS( "xmpp-session" ) );
2331 0 0       0 if( defined( $btag ) ){
2332             # We got the tag. We must do this.
2333 0         0 $doso = 1;
2334             }
2335             }
2336             }elsif( $args{"Process"} eq "always" ){
2337             # We don't care.
2338 0         0 $doso = 1;
2339             }
2340              
2341             # Do we get to go?
2342 0         0 my $stillgoing = 0;
2343 0 0       0 if( $doso ){
2344              
2345             # Send the initial packet.
2346 0         0 my $idval = rand(65535 . time );
2347 0         0 my $iqpkt = $self->newNode( 'iq' );
2348 0         0 $iqpkt->attr( 'id', $idval );
2349 0         0 $iqpkt->attr( 'type', 'set' );
2350 0         0 $iqpkt->attr( 'to', $self->{'_authenticateargs'}{"Domain"} );
2351 0         0 my $bindtag = $iqpkt->insertTag( 'session', $self->ConstXMLNS( 'xmpp-session' ) );
2352              
2353 0         0 $self->{'_need_auth_session'} = $idval;
2354 0         0 $self->{'_done_auth_session'} = undef;
2355 0         0 $stillgoing = $self->send( $iqpkt );
2356 0     0   0 $self->register_handler( 'iq', sub { $self->_session_handler(@_) }, "authenticate" );
  0         0  
2357 0         0 %{$self->{'_sessionargs'}} = %args;
  0         0  
2358             }
2359              
2360 0 0 0     0 if( $doso && $stillgoing ){
2361 0 0       0 if( ! $args{"_sessionbg"} ){
2362 0         0 my $endtime = time + $args{"Timeout"};
2363              
2364 0         0 while( $stillgoing ){
2365 0 0       0 $stillgoing = 0 if( time > $endtime );
2366 0         0 my $tval = $self->bgsessioned( RunProcess => 1 );
2367 0 0       0 if( $tval >= 0 ){
2368 0         0 $stillgoing = 0;
2369 0         0 $retval = $tval;
2370             }
2371             }
2372             }else{
2373 0         0 $retval = -1;
2374             }
2375             }
2376              
2377 0         0 return( $retval );
2378             }
2379              
2380             =head2 bgsessioned
2381              
2382             Checks to see if the session establishment has completed,
2383             returning -1 on still going, 0 on refused and 1 on success.
2384              
2385             =cut
2386              
2387             sub bgsessioned {
2388 0     0   0 my $self = shift;
2389 0         0 my %args = ( RunProcess => 0,
2390             ProcessTime => 0,
2391             @_,
2392             );
2393              
2394 0         0 my $retval = -1;
2395              
2396 0 0       0 if( $args{"RunProcess"} ){
2397 0         0 $self->debug( " invoking process\n" );
2398 0         0 my $tval = $self->process( $args{"ProcessTime"} );
2399 0         0 $self->debug( " invoked process - $tval\n" );
2400 0 0       0 if( $tval == 1 ){
2401 0         0 my $objthrowaway = $self->get_latest();
2402 0         0 $objthrowaway->hidetree;
2403             }
2404             }
2405              
2406 0 0       0 if( $self->_check_val( '_done_auth_session' ) ){
2407 0         0 $retval = $self->{'_done_auth_session'};
2408             }
2409 0         0 return( $retval );
2410             }
2411              
2412             sub _session_handler {
2413 0     0   0 my $self = shift;
2414 0         0 my $node = shift;
2415 0         0 my $persisdata = shift;
2416              
2417 0         0 $self->debug( "invoked\n" );
2418 0         0 my $retval = undef;
2419 0         0 my $idval = $self->{'_need_auth_session'};
2420              
2421 0 0 0     0 if( defined( $node ) && defined( $idval ) ){
2422 0 0       0 if( $node->name() eq 'iq' ){
2423 0 0       0 if( $node->attr( 'id' ) eq $idval ){
2424 0         0 $retval = r_HANDLED;
2425 0         0 $self->{'_done_auth_session'} = 1;
2426              
2427             # XXXX This needs fixing up.
2428 0 0       0 if( $node->attr( 'type' ) eq 'result' ){
    0          
2429             # Search for the session and jid tag.
2430 0         0 my $btag = $node->getTag( "session", $self->ConstXMLNS( "xmpp-session" ) );
2431 0 0       0 if( defined( $btag ) ){
2432             # Finished.
2433             }
2434             }elsif( $node->attr( 'type' ) eq 'error' ){
2435             # What error?
2436 0         0 my $etag = $node->getTag( "error" );
2437 0 0       0 if( defined( $etag ) ){
2438 0         0 my $notallowed = $etag->getTag( 'not-allowed' );
2439 0         0 my $conflict = $etag->getTag( 'conflict' );
2440 0         0 my $badreq = $etag->getTag( 'bad-request' );
2441 0 0 0     0 if( ( $etag->type eq 'modify' && defined( $badreq ) ) || ( $etag->type eq 'cancel' && defined( $conflict ) ) ){
    0 0        
      0        
2442             }elsif( $etag->type eq 'cancel' ){
2443             # Foo.
2444             }
2445             }
2446             }
2447             }
2448             }
2449             }
2450              
2451             # Mild cleanup.
2452 0 0       0 if( $retval == 1 ){
2453 0         0 delete( $self->{'_sessionargs'} );
2454             }
2455              
2456 0         0 return( $retval );
2457             }
2458              
2459             =head2 bind
2460              
2461             Binds a Resource value to the connection, if required by the
2462             packet. Called internally by ->authenticate() if DoBind is set as the
2463             default '1'. Takes an optional hash of:
2464              
2465             =over 4
2466              
2467             =item Process
2468              
2469             A string of either 'if-required' or 'always', indicating whether to always
2470             do so, or just if required to do so.
2471              
2472             =item Resource
2473              
2474             A Resource string to use.
2475              
2476             =item AllowRandom
2477              
2478             Start using a random resource if the requested Resource was rejected by
2479             the server.
2480              
2481             =back
2482              
2483             Returns 1 if successful, 0 otherwise. If successful, will update the
2484             value used by ->connect_jid().
2485              
2486             =cut
2487              
2488             sub bind {
2489 0     0   0 my $self = shift;
2490 0         0 my %args = ( Process => "if-required",
2491             Resource => undef,
2492             AllowRandom => 0,
2493             Timeout => 60,
2494             _bindbg => 0,
2495             @_,
2496             );
2497              
2498 0         0 my $retval = 0;
2499              
2500             # See if we have to do this.
2501 0         0 my $doso = 0;
2502 0 0       0 if( $args{"Process"} eq "if-required" ){
    0          
2503 0         0 my $stag = $self->stream_features();
2504 0 0       0 if( defined( $stag ) ){
2505             #
2506 0         0 my $btag = $stag->getTag( "bind", $self->ConstXMLNS( "xmpp-bind" ) );
2507 0 0       0 if( defined( $btag ) ){
2508             # We got the tag. We must do this.
2509 0         0 $doso = 1;
2510             }else{
2511 0         0 $self->debug( "No bind tag - ?" . $stag->toStr . " $stag" );
2512             }
2513             }else{
2514 0         0 $self->debug( "No stream:features?" );
2515             }
2516             }elsif( $args{"Process"} eq "always" ){
2517             # We don't care.
2518 0         0 $doso = 1;
2519             }
2520              
2521             # Do we get to go?
2522 0         0 my $stillgoing = 0;
2523 0 0       0 if( $doso ){
2524              
2525 0         0 $self->debug( "Performing bind based on " . $args{"Process"} );
2526              
2527             # Send the initial packet.
2528 0         0 my $idval = rand(65535 . time );
2529 0         0 my $iqpkt = $self->newNode( 'iq' );
2530 0         0 $iqpkt->attr( 'id', $idval );
2531 0         0 $iqpkt->attr( 'type', 'set' );
2532 0         0 $iqpkt->attr( 'to', $self->{'_authenticateargs'}{"Domain"} );
2533 0         0 my $bindtag = $iqpkt->insertTag( 'bind', $self->ConstXMLNS( 'xmpp-bind' ) );
2534 0 0       0 if( defined( $args{"Resource"} ) ){
2535 0         0 my $rtag = $bindtag->insertTag( 'resource' );
2536 0         0 $rtag->data( $args{"Resource"} );
2537             }
2538              
2539 0         0 $self->{'_need_auth_bind'} = $idval;
2540 0         0 $self->{'_done_auth_bind'} = undef;
2541 0         0 $stillgoing = $self->send( $iqpkt );
2542 0     0   0 $self->register_handler( 'iq', sub { $self->_bind_handler(@_) }, "authenticate" );
  0         0  
2543 0         0 %{$self->{'_bindargs'}} = %args;
  0         0  
2544             }else{
2545 0         0 $self->debug( "Not performing bind based on " . $args{"Process"} );
2546             }
2547              
2548 0 0 0     0 if( $doso && $stillgoing ){
2549 0 0       0 if( ! $args{"_bindbg"} ){
2550 0         0 my $endtime = time + $args{"Timeout"};
2551              
2552 0         0 while( $stillgoing ){
2553 0 0       0 $stillgoing = 0 if( time > $endtime );
2554 0         0 my $tval = $self->bgbinded( RunProcess => 1 );
2555 0 0       0 if( $tval >= 0 ){
2556 0         0 $stillgoing = 0;
2557 0         0 $retval = $tval;
2558             }
2559             }
2560             }else{
2561 0         0 $retval = -1;
2562             }
2563             }
2564              
2565 0         0 return( $retval );
2566             }
2567              
2568             =head2 bgbind
2569              
2570             Background version of bind. Takes the same arguments as the ->bind() call.
2571              
2572             =cut
2573              
2574             sub bgbind {
2575 0     0   0 my $self = shift;
2576 0         0 return( $self->bind( @_, _bindbg => 1 ) );
2577             }
2578              
2579             =head2 bgbinded
2580              
2581             Technically this should be 'bgbound', but for consistency with other 'bg'
2582             methods, its named this way. Checks to see if the binding has completed,
2583             returning -1 on still going, 0 on refused and 1 on success.
2584              
2585             =cut
2586              
2587             sub bgbinded {
2588 0     0   0 my $self = shift;
2589 0         0 my %args = ( RunProcess => 0,
2590             ProcessTime => 0,
2591             @_,
2592             );
2593              
2594 0         0 my $retval = -1;
2595              
2596 0 0       0 if( $args{"RunProcess"} ){
2597 0         0 $self->debug( " invoking process\n" );
2598 0         0 my $tval = $self->process( $args{"ProcessTime"} );
2599 0         0 $self->debug( " invoked process - $tval\n" );
2600 0 0       0 if( $tval == 1 ){
2601 0         0 my $objthrowaway = $self->get_latest();
2602 0         0 $objthrowaway->hidetree;
2603             }
2604             }
2605              
2606 0 0       0 if( $self->_check_val( '_done_auth_bind' ) ){
2607 0         0 $retval = $self->{'_done_auth_bind'};
2608             }
2609 0         0 return( $retval );
2610             }
2611              
2612             sub bgbound {
2613 0     0   0 my $self = shift;
2614 0         0 return( $self->bgbinded( @_ ) );
2615             }
2616              
2617             sub _bind_handler {
2618 0     0   0 my $self = shift;
2619 0         0 my $node = shift;
2620 0         0 my $persisdata = shift;
2621              
2622 0         0 $self->debug( "invoked\n" );
2623 0         0 my $retval = undef;
2624 0         0 my $idval = $self->{'_need_auth_bind'};
2625              
2626 0 0 0     0 if( defined( $node ) && defined( $idval ) ){
2627 0 0       0 if( $node->name() eq 'iq' ){
2628 0 0       0 if( $node->attr( 'id' ) eq $idval ){
2629 0         0 $retval = r_HANDLED;
2630 0 0       0 if( $node->attr( 'type' ) eq 'result' ){
    0          
2631             # Search for the bind and jid tag.
2632 0         0 my $btag = $node->getTag( "bind", $self->ConstXMLNS( "xmpp-bind" ) );
2633 0         0 $self->{'_done_auth_bind'} = 1;
2634 0 0       0 if( defined( $btag ) ){
2635 0         0 my $jtag = $btag->getTag( 'jid' );
2636 0 0       0 if( defined( $jtag ) ){
2637 0         0 $self->{'_connect_jid'} = $jtag->data();
2638             }
2639             }
2640             }elsif( $node->attr( 'type' ) eq 'error' ){
2641             # What error?
2642 0         0 my $etag = $node->getTag( "error" );
2643 0 0       0 if( defined( $etag ) ){
2644 0         0 my $notallowed = $etag->getTag( 'not-allowed' );
2645 0         0 my $conflict = $etag->getTag( 'conflict' );
2646 0         0 my $badreq = $etag->getTag( 'bad-request' );
2647 0 0 0     0 if( ( $etag->type eq 'modify' && defined( $badreq ) ) || ( $etag->type eq 'cancel' && defined( $conflict ) ) ){
    0 0        
      0        
2648             # Ok, we send in another
2649             # one if possible.
2650 0         0 $idval = rand(65535 . time );
2651 0         0 $self->{'_need_auth_bind'} = $idval;
2652 0         0 my $iqpkt = $self->newNode( 'iq' );
2653 0         0 $iqpkt->attr( 'id', $idval );
2654 0         0 $iqpkt->attr( 'type', 'set' );
2655 0         0 $iqpkt->attr( 'to', $self->{'_authenticateargs'}{"Domain"} );
2656 0         0 my $bindtag = $iqpkt->insertTag( 'bind', $self->ConstXMLNS( 'xmpp-bind' ) );
2657              
2658             # If Random is set, we
2659             # use a random number,
2660             # otherwise we trust
2661             # to the server.
2662 0 0       0 if( $self->{'_bindargs'}{"AllowRandom"} ){
2663 0         0 my $rtag = $bindtag->insertTag( 'resource' );
2664 0         0 $rtag->data( int( rand( 65535 ) ) );
2665             }
2666 0         0 $self->send( $iqpkt );
2667             }elsif( $etag->type eq 'cancel' ){
2668             # Remaining type is 'not-allowed'.
2669 0         0 $self->{'_done_auth_bind'} = 1;
2670             }
2671             }
2672             }
2673             }
2674             }
2675             }
2676              
2677             # Mild cleanup.
2678 0 0       0 if( defined( $retval ) ){
2679 0 0       0 if( $retval == r_HANDLED ){
2680 0         0 delete( $self->{'_bindargs'} );
2681             }
2682             }
2683              
2684 0         0 return( $retval );
2685             }
2686              
2687              
2688             =head1 METHODS - Handling Packets
2689              
2690             =head2 clear_handlers
2691              
2692             This clears any handlers that have been put on the object. Some
2693             applications may wish to do this after the standard ->connect
2694             and ->authenticate methods have returned successfully, as these
2695             use handlers to do their jobs.
2696              
2697             Alternatively, specifying a 'Class' of 'connect' and 'authenticate'
2698             will remove just the handlers created by ->connect and ->authenticate
2699             respectively.
2700              
2701             WARNING: The standard ->connect and ->authenticate (and/or their
2702             bg varients) require their configured handlers to be in place. Do
2703             not execute ->clear_handlers between ->connect and ->authenticate,
2704             lest your application suddenly fail to work.
2705              
2706             This takes a hash of optional arguments, being 'Type' and 'Class'.
2707             The 'Type' is the same as the Type supplied to 'register_handler', and
2708             if supplied, will delete all callbacks of that Type. The 'Class' is
2709             the same as the optional Class supplied to 'register_handler', and if
2710             supplied, will delete all callbacks of that class.
2711              
2712             =cut
2713              
2714             sub clear_handlers {
2715 0     0   0 my $self = shift;
2716 0         0 my %args = ( Type => undef,
2717             Class => undef,
2718             @_,
2719             );
2720              
2721             # Delete a specific class and type.
2722 0 0 0     0 if( defined( $args{"Class"} ) && defined( $args{"Type"} ) ){
    0 0        
    0 0        
2723 0 0       0 if( defined( $self->{'handlers'}{$args{"Type"}}{$args{"Class"}} ) ){
2724 0         0 delete( $self->{'handlers'}{$args{"Type"}}{$args{"Class"}} );
2725             }
2726              
2727             # Delete a specific type.
2728             }elsif( defined( $args{"Type"} ) && ! defined( $args{"Class"} ) ){
2729 0         0 delete( $self->{'handlers'}{$args{"Type"}} );
2730              
2731             # Delete a specific class.
2732             }elsif( defined( $args{"Class"} ) && ! defined( $args{"Type"} ) ){
2733             # Delete all handlers of this class from all object
2734             # types.
2735 0         0 foreach my $type( keys %{$self->{'handlers'}} ){
  0         0  
2736 0 0       0 next unless( defined( $type ) );
2737 0 0       0 next if( $type =~ /^\s*$/ );
2738 0 0       0 next unless( defined( $self->{'handlers'}{$type}{$args{"Class"}} ) );
2739 0         0 delete( $self->{'handlers'}{$type}{$args{"Class"}} );
2740             }
2741              
2742             # No arguments, delete all.
2743             }else{
2744 0         0 delete( $self->{'handlers'} );
2745             }
2746 0         0 return( 1 );
2747             }
2748              
2749             =head2 register_handler
2750              
2751             Record a packet type and a subroutine to be invoked when the matching
2752             packet type is received. Multiple handlers for the same packet type
2753             can be registered. Each of these handlers is called in succession with
2754             the received packet until one returns the constant C .
2755              
2756             Each handler is invoked with two arguments; the object representing
2757             the current packet, and a value received from calls to previous handlers.
2758             so-called 'parcel' or 'persistent' data. The return value is either
2759             the C constant or parcel/persistent data to be handed to the
2760             next handler.
2761              
2762             Note: See notes regarding handlers under ->process.
2763              
2764             Note: The ->connect and ->authenticate methods use handlers to function.
2765              
2766             Note: A third argument can be supplied to indicate the 'class' of this handler,
2767             for usage with ->clear_handlers. If not supplied, defaults to 'user'.
2768              
2769             =cut
2770              
2771             sub register_handler {
2772 0     0   0 my $self = shift;
2773              
2774 0         0 my $ptype = shift;
2775 0         0 my $process = shift;
2776 0         0 my $class = shift;
2777              
2778 0 0       0 if( ! defined( $class ) ){
2779 0         0 $class = "user";
2780             }
2781              
2782 0         0 my $retval = 0;
2783 0 0 0     0 if( defined( $ptype ) && defined( $process ) ){
2784 0         0 $retval++;
2785 0         0 push @{$self->{'handlers'}{$ptype}{$class}}, $process;
  0         0  
2786 0         0 $self->debug( "$ptype is $process in class $class" );
2787             }
2788              
2789 0         0 return( $retval );
2790             }
2791              
2792             =head2 register_interval
2793              
2794             Records a time interval and a subroutine to be invoked when the appropriate
2795             time period has elapsed. Takes a hash of:
2796              
2797             =over 4
2798              
2799             =item Interval
2800              
2801             The frequency which this subroutine should be executed, in seconds.
2802              
2803             =item Sub
2804              
2805             A reference to the actual subroutine. Since I keep forgetting how to
2806             do so myself, if you want to call an object-based method with your
2807             working object, you do so via 'Sub => sub { $objname->some_method(@_) }'
2808              
2809             =item Argument
2810              
2811             If supplied, will be supplied as the second argument.
2812              
2813             =item Once
2814              
2815             A boolean as to whether this routine should be executed just once
2816             (after Interval seconds). Defaults to 0.
2817              
2818             =item Now
2819              
2820             A boolean as to whether this routine's first execution should be the
2821             next time ->process() is invoked, or after Interval seconds have
2822             elapsed. Defaults to 0.
2823              
2824             =back
2825              
2826             The subroutine is invoked with a single argument of the current connection
2827             object (in case you want to send something), and the value of the 'Argument'
2828             hash if supplied.
2829              
2830             Note: These are executed as a side-effect of running ->process(). If you
2831             do not regularly invoke ->process() (or via ->start()), these timeouts will
2832             not be invoked. Executing ->process() from within the handler may cause
2833             odd things to happen.
2834              
2835             =cut
2836              
2837             sub register_interval {
2838 0     0   0 my $self = shift;
2839              
2840 0         0 my %args = ( Interval => -1,
2841             Sub => undef,
2842             Argument => undef,
2843             Once => 0,
2844             Now => 0,
2845             @_,
2846             );
2847              
2848 0         0 my $retval = 0;
2849              
2850 0 0 0     0 if( $args{"Interval"} != -1 && defined( $args{"Sub"} ) ){
2851 0         0 $self->debug( "Adding " . $args{"Sub"} . " with interval of " . $args{"Interval"} );
2852             # Set things up. Get a unique value.
2853 0         0 my $tlook = rand( 65535 );
2854 0         0 while( defined( $self->{'timebeats'}{"$tlook"} ) ){
2855 0         0 $tlook = rand( 65535 );
2856             }
2857              
2858             # Save stuff.
2859 0         0 $self->{'timebeats'}{"$tlook"}{"interval"} = $args{"Interval"};
2860 0         0 $self->{'timebeats'}{"$tlook"}{"sub"} = $args{"Sub"};
2861 0         0 $self->{'timebeats'}{"$tlook"}{"once"} = $args{"Once"};
2862 0         0 $self->{'timebeats'}{"$tlook"}{"arg"} = $args{"Argument"};
2863              
2864 0         0 my $initialinterval = $args{"Interval"};
2865              
2866 0 0       0 if( $args{"Now"} ){
2867 0         0 $initialinterval = 0;
2868             }
2869              
2870 0         0 $retval = $self->_beat_addnext( Key => $tlook, Interval => $initialinterval, Once => $self->{'timebeats'}{"$tlook"}{"once"} );
2871             }
2872              
2873 0         0 return( $retval );
2874             }
2875              
2876             =head2 register_beat
2877              
2878             This is the Jabber::Connection compatibility call, and takes two arguments,
2879             a time interval and a subroutine. Invokes ->register_interval .
2880              
2881             =cut
2882              
2883             sub register_beat {
2884 0     0   0 my $self = shift;
2885              
2886 0         0 my $argint = shift;
2887 0         0 my $argsub = shift;
2888              
2889 0         0 return( $self->register_interval( Interval => $argint, Sub => $argsub ) );
2890             }
2891              
2892             =head2 process
2893              
2894             For most applications, this is the function to use. It checks to see if
2895             anything is available to be read on the socket, reads it in, and returns
2896             a success (or otherwise) value. It takes an optional timeout argument,
2897             for how long the ->can_read() call can hang around for (default 0).
2898              
2899             The values returned, which MUST be checked on each call, are:
2900              
2901             -2: Invalid XML was read.
2902              
2903             -1: EOF was reached.
2904              
2905             0: No action. Data may or may not have been read.
2906              
2907             1: A complete object has been read, and is available for
2908             retrieval via get_latest().
2909              
2910             2: A complete object was read, but was eaten
2911             by a defined handler.
2912              
2913             Note that after a complete object has been read, any further calls to
2914             ->process() will not create additional objects until the current complete
2915             object has been retrieved via ->get_latest(). This does not apply if the
2916             object was eaten/accepted by a defined handler.
2917              
2918             Note: ->process() is a wrapper around ->can_read() and ->do_read(), but
2919             it executes handlers as well. ->process will return after every packet
2920             read (imho, a better behaviour than simply reading from the socket until
2921             the remote end stops sending us data).
2922              
2923             =cut
2924              
2925             sub process {
2926 0     0   0 my $self = shift;
2927              
2928 0         0 my $arg = shift;
2929              
2930 0         0 my $dval = $self->_check_val( '_debug' );
2931 0 0       0 if( $dval ){
2932 0         0 $dval = $self->{'_debug'};
2933             }
2934 0 0       0 if( ! defined( $arg ) ){
2935 0         0 $arg = 0;
2936             }else{
2937 0 0       0 $self->debug( " Got arg of $arg\n" ) if( $dval );
2938             }
2939              
2940 0         0 my $retval = 0;
2941              
2942             # See if we can process anything.
2943 0 0       0 if( $self->can_read( $arg ) ){
    0          
    0          
2944 0 0       0 $self->debug( " can_read yes, invoking do_read()\n" ) if( $dval );
2945 0         0 $retval = $self->do_read();
2946 0 0       0 if( $retval == -1 ){
2947             # print STDERR "RETVAL -1 THANKS TO DO_READ\n";
2948             }
2949             }elsif( defined( $self->{'_pending'} ) ){
2950             # Yes, we go process something if there is still pending text.
2951 0 0       0 $self->debug( " can_read no, pending yes, invoking do_read()\n" ) if( $dval );
2952 0         0 $retval = $self->do_read( PendingOnly => 1 );
2953 0 0       0 if( $retval == -1 ){
2954             # print STDERR "RETVAL -1 THANKS TO DO_READ PENDING\n";
2955             }
2956             }elsif( $self->is_eof() ){
2957 0 0       0 $self->debug( " can_read no, pending no, eof yes\n" ) if( $dval );
2958 0         0 $retval = -1;
2959             # print STDERR "SET RETVAL TO -1 AS IS_EOF\n";
2960             }else{
2961 0 0       0 $self->debug( " can_read no, pending no, eof no\n" ) if( $dval );
2962             # Is there currently an object?
2963 0 0       0 if( defined( $self->{'_curobj'} ) ){
2964 0 0       0 if( $self->{'_curobj'}->is_complete() ){
2965 0         0 $self->{'_is_complete'} = 1;
2966 0         0 $retval = 1;
2967             }
2968             }
2969             }
2970              
2971 0 0       0 $self->debug( " retval is $retval\n" ) if( $dval );
2972             # Process the handlers defined. We make two passes; one for the
2973             # current packet, and one for the timeouts.
2974 0 0 0     0 if( $retval == 1 && defined( $self->{'handlers'} ) ){
2975             #
2976 0         0 my $tobj = $self->get_latest;
2977 0         0 my $curname = $tobj->name();
2978 0 0       0 $self->debug( " considering handler for $tobj ($curname)\n" ) if( $dval );
2979              
2980 0         0 my $stillgoing = 1;
2981 0 0       0 if( defined( $self->{'handlers'}{$curname} ) ){
2982             # Run through it.
2983             # Run through the various classes.
2984             # The connect and authenticate handlers must be
2985             # run first, as any client code might incorrectly
2986             # say that they've handled it.
2987 0         0 my %uclass = ();
2988 0         0 foreach my $thisclass( "connect", "authenticate", keys %{$self->{'handlers'}{$curname}} ){
  0         0  
2989 0 0       0 next unless( $stillgoing );
2990 0 0       0 next unless( defined( $thisclass ) );
2991 0 0       0 next if( $thisclass =~ /^\s*$/ );
2992 0 0       0 next if( defined( $uclass{"$thisclass"} ) );
2993 0 0       0 $self->debug( "Checking handlers for $curname of class $thisclass" ) if( $dval );
2994 0         0 $uclass{"$thisclass"}++;
2995 0 0       0 next unless( exists( $self->{'handlers'}{$curname}{$thisclass} ) );
2996 0 0       0 $self->debug("Handler for $curname and $thisclass" ) if( $dval );
2997 0         0 my $persisdata = undef;
2998 0         0 my $loop = 0;
2999 0         0 my $maxhandlers = scalar( @{$self->{'handlers'}{$curname}{$thisclass}} );
  0         0  
3000 0   0     0 while( $loop < $maxhandlers && $stillgoing ){
3001 0         0 eval {
3002 0 0       0 $self->debug( "handing $tobj and " . ( defined( $persisdata ) ? $persisdata : "undef" ) . " to $curname handler $loop\n" ) if( $dval );
    0          
3003 0         0 $persisdata = ${$self->{'handlers'}{$curname}{$thisclass}}[$loop]->( $tobj, $persisdata );
  0         0  
3004             };
3005              
3006 0 0       0 if( defined( $persisdata ) ){
3007 0 0       0 if( $persisdata eq r_HANDLED ){
3008 0         0 $stillgoing=0;
3009             }
3010             }
3011              
3012 0 0       0 $self->debug( " Got $loop and $maxhandlers - $stillgoing\n" ) if( $dval );
3013 0         0 $loop++;
3014             }
3015             }
3016             }
3017              
3018             # If we're still here, the packet wasn't handled.
3019             # Put it back in the object.
3020 0 0       0 if( $stillgoing ){
3021 0         0 $self->copy_latest( $tobj );
3022 0         0 $retval = 1;
3023             }else{
3024 0         0 $tobj->hidetree;
3025 0         0 $retval = 2;
3026             }
3027 0 0       0 $self->debug( " Back to here\n" ) if( $dval );
3028             }
3029              
3030             # Lets process the timeouts. These do not affect the
3031             # return value. We only run one timeout at a time.
3032 0 0       0 if( defined( $self->{'heartbeats'} ) ){
3033 0 0       0 if( defined( ${$self->{'heartbeats'}}[0] ) ){
  0         0  
3034             # XXXX - bug in inserting things into heartbeats?
3035             # print STDERR "check heartbeats - " . time . " " . ${$self->{'heartbeats'}}[0] . "\n";
3036 0 0       0 if( time > ${$self->{'heartbeats'}}[0] ){
  0         0  
3037 0 0       0 $self->debug( "Found heartbeats - " . time . " " . ${$self->{'heartbeats'}}[0] ) if( $dval );
  0         0  
3038             # print STDERR "Found heartbeats - " . time . " " . ${$self->{'heartbeats'}}[0] . "\n";
3039 0         0 my $plook = ${$self->{'heartbeats'}}[0];
  0         0  
3040 0         0 splice( @{$self->{'heartbeats'}}, 0, 1 );
  0         0  
3041 0         0 my $tlook = $self->{'timepend'}{"$plook"};
3042 0         0 delete( $self->{'timepend'}{"$plook"} );
3043              
3044             # Re-add this one as appropriate.
3045 0 0       0 if( defined( $self->{'timebeats'}{"$tlook"} ) ){
3046 0         0 $self->_beat_addnext( Key => $tlook, Interval => $self->{'timebeats'}{"$tlook"}{"interval"}, Once => $self->{'timebeats'}{"$tlook"}{"once"}, Argument => $self->{'timebeats'}{"$tlook"}{"arg"} );
3047              
3048             # Execute this one.
3049 0         0 eval {
3050 0 0       0 $self->debug( "Executing sub" ) if( $dval );
3051 0         0 $self->{'timebeats'}{"$tlook"}{"sub"}->( $self, $self->{'timebeats'}{"$tlook"}{"arg"} );
3052 0 0       0 $self->debug( "Finished Executing sub" ) if( $dval );
3053             };
3054             }
3055             }
3056             }
3057             }
3058              
3059 0 0       0 $self->debug( "returning $retval\n" ) if( $dval );
3060 0 0       0 if( $retval == -1 ){
3061             # Abort as theres nothing more to be read.
3062             # print STDERR "ABORTING AS RETVAL IS -1\n";
3063 0         0 $self->abort();
3064             }
3065 0         0 return( $retval );
3066             }
3067              
3068             =head2 send
3069              
3070             Sends either text or an object down the connected socket. Returns
3071             a count of the number of bytes read. Will return '-1' if an error
3072             occured and the text was not sent.
3073              
3074             Note that if you send non-XML data (gibberish or incomplete), thats
3075             your problem, not mine.
3076              
3077             =cut
3078              
3079             sub send {
3080              
3081 0     0   0 my $self = shift;
3082 0         0 my $arg = shift;
3083 0         0 my $retval = 0;
3084             # print "$self: send: $arg\n";
3085 0 0       0 if( defined( $self->socket() ) ){
3086              
3087             # Can the socket be written to?
3088 0         0 $retval = -1;
3089 0         0 my $nwritable = $self->can_write();
3090              
3091             # Is the socket still connected? can_write() does not
3092             # detect this condition.
3093 0         0 my $amconnected = 0;
3094 0 0       0 if( defined( $self->socket->connected ) ){
3095 0         0 $amconnected = 1;
3096             }
3097              
3098             # IO::Socket::SSL does not have send; I missed this when
3099             # changed from syswrite.
3100 0         0 my $usesend = 1;
3101              
3102 0 0       0 if( ! defined( $self->{'_checked_send_ability'} ) ){
3103 0         0 my $tsock = $self->socket();
3104 0         0 my $tref = ref( $tsock );
3105 0 0       0 if( $tref =~ /SSL/ ){
3106             # Does it have send?
3107 0 0 0     0 if( $amconnected && $nwritable ){
3108 0         0 eval {
3109 0         0 $self->socket->send( " " );
3110             };
3111 0 0       0 if( $@ ){
3112             # We got an error.
3113 0         0 $usesend = 0;
3114             }
3115 0         0 $self->{'_checked_send_ability'} = $usesend;
3116             }
3117             }
3118             }else{
3119 0         0 $usesend = $self->{'_checked_send_ability'};
3120             }
3121              
3122              
3123             # Deal with either the public or hidden class.
3124 0         0 my $tref = ref( $arg );
3125 0 0 0     0 if ( ( $tref eq 'Jabber::Lite' || $tref eq 'Jabber::Lite::Impl' ) && $nwritable && $amconnected ) {
    0 0        
      0        
      0        
3126             # print "OBJECT is " . $arg->toStr . "\n";
3127             # print "WRI";
3128 0 0       0 if( $usesend ){
3129 0         0 $retval = $self->socket->send( $arg->toStr );
3130             }else{
3131 0         0 $retval = $self->socket->syswrite( $arg->toStr );
3132             }
3133 0         0 $self->debug( "Sent off $arg" );
3134             # print "TE $retval - $@\n";
3135             }elsif( $nwritable && $amconnected ) {
3136             # print "object is " . $arg . "\n";
3137             # print "wri";
3138 0 0       0 if( $usesend ){
3139 0         0 $retval = $self->socket->send( $arg );
3140             }else{
3141 0         0 $retval = $self->socket->syswrite( $arg );
3142             }
3143             # print "te (" . $arg . ") $retval - $@\n";
3144 0         0 $self->debug( "Sent off $arg" );
3145             }else{
3146 0         0 $self->debug( "socket is not writable or is disconnected." );
3147 0         0 $self->abort();
3148             }
3149 0         0 $self->{'_lastsendtime'} = time;
3150 0         0 eval {
3151 0         0 $self->socket->autoflush(1);
3152             };
3153             }
3154 0         0 return( $retval );
3155             }
3156              
3157              
3158             =head1 METHODS - So Long, and Thanks for all the
3159              
3160             =head2 disconnect
3161              
3162             Disconnect from the Jabber server by sending the closing tags and then
3163             closing the connection. Note that no closing '' tag is sent,
3164             but the closing tag is sent.
3165              
3166             =cut
3167              
3168             sub disconnect {
3169 0     0   0 my $self = shift;
3170 0         0 my $retval = 0;
3171 0 0       0 if( defined( $self->socket() ) ){
3172             # Send the closing tags.
3173             # We don't bother with preparing an object here.
3174 0         0 $self->send( "\n" );
3175              
3176             # Invoke abort();
3177             # print STDERR "ABORTING VIA DISCONNECT!\n";
3178 0         0 $retval = $self->abort();
3179             }
3180 0         0 return( $retval );
3181             }
3182              
3183              
3184             =head2 abort
3185              
3186             Close the connection abruptly. If the connection is not to a Jabber server,
3187             use abort() instead of disconnect().
3188              
3189             =cut
3190              
3191             sub abort {
3192 0     0   0 my $self = shift;
3193 0         0 my $retval = 0;
3194 0         0 $self->debug( "aborting!\n" );
3195             # print STDERR "ABORTING!\n";
3196 0 0       0 if( defined( $self->socket() ) ){
3197 0 0       0 if( defined( $self->{'_select'} ) ){
3198 0         0 $self->{'_select'}->remove( $self->socket() );
3199             }
3200              
3201 0         0 my $tref = ref( $self->socket );
3202 0 0       0 if( $tref ){
3203 0 0       0 if( $tref =~ /SSL/ ){
3204             # IO::Socket::SSL says that it has the
3205             # possibility of blocking unless the
3206             # SSL_no_shutdown argument is specified.
3207             # Some servers may not like this behaviour.
3208 0         0 $self->socket->close( SSL_no_shutdown => 1 );
3209             }else{
3210 0         0 close( $self->socket() );
3211             }
3212 0         0 delete( $self->{'_checked_send_ability'} );
3213             }else{
3214 0         0 close( $self->socket() );
3215 0         0 delete( $self->{'_checked_send_ability'} );
3216             }
3217 0         0 $self->{'_socket'} = undef;
3218 0         0 $retval++;
3219             }
3220              
3221 0         0 foreach my $todel( '_is_connected', '_is_encrypted', '_is_authenticated', '_connect_jid', '_is_eof', '_select', '_socket', '_pending' ){
3222 0         0 $self->{$todel} = undef;
3223 0         0 delete( $self->{$todel} );
3224             }
3225 0         0 return( $retval );
3226             }
3227              
3228             =head1 METHODS - These are a few of my incidental things
3229              
3230             =head2 socket
3231              
3232             Returns (or sets) the socket that this object is using. This is provided
3233             to support a parent program designed around its own IO::Select() loop.
3234             A previously opened socket/filehandle can be supplied as the argument.
3235              
3236             Note: The library uses sysread() and send/syswrite() as required. Passing
3237             in filehandles that do not support these functions is probably a bad
3238             idea.
3239              
3240             Note: There is some juggling of sockets within the ->connect method
3241             when SSL starts up. Whilst a select() on the original, or parent socket
3242             will probably still work, it would probably be safer to not include
3243             the socket returned by ->socket() in any select() until the ->connect()
3244             and ->authenticate methods have returned.
3245              
3246             =cut
3247              
3248             sub socket {
3249 0     0   0 my $self = shift;
3250 0         0 my $arg = shift;
3251             # print STDERR "SOCKET HAS $arg\n";
3252 0 0       0 if( defined( $arg ) ){
3253 0         0 $self->{'_socket'} = $arg;
3254 0         0 delete( $self->{'_checked_send_ability'} );
3255              
3256             # Set up an IO::Select object.
3257 0         0 $self->{'_select'} = new IO::Select;
3258 0         0 $self->{'_select'}->add( $arg );
3259              
3260             # Assume that this is not at EOF initially.
3261 0         0 $self->{'_is_eof'} = undef;
3262             }
3263              
3264 0 0       0 if( defined( $self->{'_socket'} ) ){
3265 0         0 return( $self->{'_socket'} );
3266             }else{
3267 0         0 return( undef );
3268             }
3269             }
3270              
3271             =head2 can_read
3272              
3273             Checks to see whether there is anything further on the socket. Returns
3274             1 if there is data to be read, 0 otherwise.
3275              
3276             =cut
3277              
3278             sub can_read {
3279 0     0   0 my $self = shift;
3280 0         0 my $arg = shift;
3281 0 0       0 if( ! defined( $arg ) ){
3282 0         0 $arg = 0;
3283             }
3284 0         0 my $retval = 0;
3285 0 0       0 if( defined( $self->{'_select'} ) ){
3286 0         0 $self->debug( " invoking io:select\n" );
3287 0         0 my @readhans = $self->{'_select'}->can_read($arg);
3288 0 0       0 if( scalar @readhans > 0 ){
3289 0         0 $retval = 1;
3290             }
3291 0         0 $self->debug( " invoked io:select returning $retval\n" );
3292             }
3293 0         0 return( $retval );
3294             }
3295              
3296             =head2 can_write
3297              
3298             Checks to see whether the socket can be written to. Returns
3299             1 if so, 0 otherwise.
3300              
3301             =cut
3302              
3303             sub can_write {
3304 0     0   0 my $self = shift;
3305 0         0 my $arg = shift;
3306 0 0       0 if( ! defined( $arg ) ){
3307 0         0 $arg = 0;
3308             }
3309 0         0 my $retval = 0;
3310 0 0       0 if( defined( $self->{'_select'} ) ){
3311 0         0 $self->debug( " invoking io:select\n" );
3312 0         0 my @readhans = $self->{'_select'}->can_write($arg);
3313 0 0       0 if( scalar @readhans > 0 ){
3314 0         0 $retval = 1;
3315             }
3316 0         0 $self->debug( " invoked io:select returning $retval\n" );
3317             }
3318 0         0 return( $retval );
3319             }
3320              
3321             =head2 do_read
3322              
3323             Reads in the latest text from the socket, and submits it to
3324             be added to the current XML object. Returns:
3325              
3326             =over 4
3327              
3328             =item -2 if the parsing indicated invalid XML,
3329              
3330             =item -1 if the socket reached EOF,
3331              
3332             =item 0 if the socket was ok and data was read happily.
3333              
3334             =item 1 if there is a complete object (use ->get_latest() )
3335              
3336             =back
3337              
3338             Applications MUST check the return value on each call. Takes a hash
3339             of optional arguments, the most important being:
3340              
3341             PendingOnly (default 0) - Only process the pending data, do not
3342             attempt to read from the socket.
3343              
3344             ->do_read also checks the maxobjectsize, maxobjectdepth and maxnamesize.
3345              
3346             ->do_read also checks the likely size of the object as it is being read. If
3347             it is larger than the maxobjectsize value passed to ->new/->init, the
3348             appropriate behaviour will be taken. Note that if the behaviour chosen
3349             is to continue parsing but not save (the default), then an attack consisting
3350             of repeated ad nauseum will still eventually exhaust memory.
3351              
3352             This is because to properly parse the object, the parser must know at which
3353             point the object is at, meaning that the name of each must be stored.
3354              
3355             =cut
3356              
3357             sub do_read {
3358 0     0   0 my $self = shift;
3359 0         0 my %args = ( PendingOnly => 0,
3360             @_,
3361             );
3362 0         0 my $socket = $self->socket();
3363 0         0 my $retval = -1;
3364              
3365 0         0 my $save_to_memory = 1;
3366              
3367 0 0 0     0 if( defined( $socket ) && ! $self->is_eof() && ! $args{"PendingOnly"} ){
      0        
3368 0         0 $retval = 0;
3369 0         0 my $buf = "";
3370 0         0 my $tval = sysread( $socket, $buf, $self->{'_readsize'} );
3371              
3372             # Some slight parsing to preload the is_eof function.
3373 0         0 $self->{'_justreadcount'} = 0;
3374 0 0       0 if( ! defined( $tval ) ){
    0          
    0          
3375             # An error occurred. We assume that
3376             # this is eof.
3377 0         0 $self->{'_is_eof'} = 1;
3378             # print STDERR "SYSREAD RETURNED UNDEF\n";
3379 0         0 $retval = -1;
3380             }elsif( $tval == 0 ){
3381             # This is EOF.
3382 0         0 $self->{'_is_eof'} = 1;
3383             # print STDERR "SYSREAD RETURNED 0\n";
3384 0         0 $retval = -1;
3385             }elsif( $tval > 0 ){
3386             # We did get some bytes. First add it
3387             # to the pending buffer.
3388 0         0 $self->debug( "Read in $buf" );
3389 0         0 $self->{'_pending'} .= $buf;
3390              
3391             # We just read something. Not EOF.
3392 0         0 $self->{'_is_eof'} = undef;
3393              
3394             # How many bytes did we just read?
3395 0         0 $self->{'_justreadcount'} = $tval;
3396              
3397             # Running total.
3398 0         0 $self->{'_totalreadcount'} += $tval;
3399              
3400             # Update the time of last read. Useful for
3401             # the calling program.
3402 0         0 $self->{'_lastreadtime'} = time;
3403              
3404             # Increment the count of bytes read since the
3405             # last time an object was cleared. This is not
3406             # quite the same as the number of bytes in an
3407             # object.
3408 0         0 $self->{'_curobjbytes'} += $tval;
3409              
3410             # Have we exceeded the allowable count of bytes read?
3411 0 0       0 if( defined( $self->{'_maxobjectsize'} ) ){
3412 0 0       0 if( $self->{'_curobjbytes'} > $self->{'_maxobjectsize'} ){
3413             # We must do the appropriate action.
3414             # disconnect
3415 0 0       0 if( $self->{'_disconnectonmax'} ){
3416             # Bye bye.
3417 0         0 $self->debug( "Exceeded maxobjectsize (" . $self->{'_maxobjectsize'} . ") with " . $self->{'_curobjbytes'} . ", disconnecting\n" );
3418             # print STDERR "ABORTING VIA EXCESS MEMORY\n";
3419 0         0 $self->abort();
3420             }else{
3421 0         0 $save_to_memory=0;
3422             }
3423             }
3424             }
3425             }
3426             }
3427              
3428             # If there is data in the pending variable, we have
3429             # to deal with it. This includes things that we just read.
3430              
3431 0 0       0 if( defined( $self->{'_pending'} ) ){
3432             # $self->debug( "Current pending is " . $self->{'_pending'} . "\n" );
3433              
3434             # Then see if we have to create an object.
3435 0 0       0 if( ! defined( $self->{'_curobj'} ) ){
    0          
3436              
3437             # See if we have enough data to
3438             # create an object.
3439 0         0 my ( $tobj, $tval, $rtext ) = $self->create_and_parse( $self->{'_pending'} );
3440 0 0       0 if( defined( $tobj ) ){
3441 0         0 $self->{'_curobj'} = $tobj;
3442              
3443             # Record when the object started being received.
3444             # Useful for the calling program.
3445 0         0 $self->{'_lastobjectstart'} = time;
3446 0 0       0 if( length( $rtext ) > 0 ){
3447 0         0 $self->{'_pending'} = $rtext;
3448             }else{
3449 0         0 delete( $self->{'_pending'} );
3450             }
3451              
3452             # Check for completeness.
3453 0 0       0 if( $self->{'_curobj'}->is_complete() ){
3454 0         0 $self->{'_is_complete'} = 1;
3455 0         0 $retval = 1;
3456             }
3457             }else{
3458             # No object was created. Thus, we are between
3459             # objects, and what was read is solely
3460             # whitespace. We've possibly also read a '<'
3461             # character at the end. So, we delete any
3462             # whitespace, decrement the curobjbytes count
3463             # by that amount, and save the pending again.
3464             # create_and_parse will swallow whitespace
3465             # as well.
3466 0 0       0 if( $self->{'_pending'} =~ /^(\s*)(<)?$/sm ){
3467 0         0 $self->{'_curobjbytes'} -= length( $1 );
3468 0   0     0 $self->{'_pending'} = $2 || undef;
3469             }else{
3470             # Caution, possible memory leakage
3471             # issue here. It shouldn't be anything
3472             # but whitespace.
3473 0         0 $self->{'_pending'} = $rtext;
3474 0 0       0 if( $tval == -2 ){
3475 0         0 $self->debug( "tval is -2 ?" );
3476 0         0 $retval = $tval;
3477             }
3478             }
3479             }
3480              
3481             # Return XML parse errors to the caller.
3482 0 0       0 if( $tval == -2 ){
3483 0         0 $retval = -2;
3484             }
3485              
3486             # See if we have an object that is not marked
3487             # as being complete. If we have an object that
3488             # is marked as being complete, we leave the text
3489             # that we read in the _pending variable.
3490             }elsif( ! defined( $self->{'_is_complete'} ) ){
3491 0         0 my( $tval, $rtext ) = $self->{'_curobj'}->parse_more( $self->{'_pending'} );
3492 0 0       0 if( length( $rtext ) > 0 ){
3493 0         0 $self->{'_pending'} = $rtext;
3494             }else{
3495             # We have to delete it as we
3496             # use its 'defined' value to
3497             # determine whether we enter
3498             # this function when no data
3499             # was read. Nice bricktext.
3500 0         0 delete( $self->{'_pending'} );
3501             }
3502              
3503             # Check for completeness.
3504 0 0       0 if( $self->{'_curobj'}->is_complete() ){
3505 0         0 $self->{'_is_complete'} = 1;
3506 0         0 $retval = 1;
3507              
3508             # Record when the last object was received.
3509             # Useful for the calling program.
3510 0         0 $self->{'_lastobjecttime'} = time;
3511             }
3512              
3513             # Detect XML parse errors.
3514 0 0       0 if( $tval == -2 ){
3515 0         0 $retval = -2;
3516             }
3517             }
3518             }
3519              
3520             # Return what we have.
3521 0         0 return( $retval );
3522             }
3523              
3524             =head2 is_eof
3525              
3526             Sees whether the socket is still around, based on the last
3527             call to ->do_read(). Returns 1 if the socket is at EOF, 0
3528             if the socket not at EOF.
3529              
3530             =cut
3531              
3532             sub is_eof {
3533 0     0   0 my $self = shift;
3534 0         0 return( $self->_check_val( '_is_eof' ) );
3535             }
3536              
3537             =head2 is_authenticated
3538              
3539             Returns 1 or 0 whether this connection has been authenticated yet.
3540              
3541             =cut
3542              
3543             sub is_authenticated {
3544 0     0   0 my $self = shift;
3545 0         0 return( $self->_check_val( '_is_authenticated' ) );
3546             }
3547              
3548             =head2 is_connected
3549              
3550             Returns 1 or 0 whether this connection is currently connected.
3551              
3552             =cut
3553              
3554             sub is_connected {
3555 0     0   0 my $self = shift;
3556 0         0 my $retval = $self->_check_val( '_is_connected' );
3557 0         0 $self->debug( "Returning $retval" );
3558             # print "is_connected $self: Returning $retval X\n";
3559 0         0 return( $retval );
3560             }
3561              
3562             =head2 is_encrypted
3563              
3564             Returns 1 or 0 whether this connection is currently encrypted.
3565              
3566             =cut
3567              
3568             sub is_encrypted {
3569 0     0   0 my $self = shift;
3570 0         0 return( $self->_check_val( '_is_encrypted' ) );
3571             }
3572              
3573             =head2 connect_jid
3574              
3575             Returns the JID currently associated with this connection, or undef.
3576              
3577             =cut
3578              
3579             sub connect_jid {
3580 0     0   0 my $self = shift;
3581 0         0 return( $self->{'_connect_jid'} );
3582             }
3583              
3584             # Helper function, not documented.
3585             # Checks to see whether the nominated value has been defined.
3586             sub _check_val {
3587 66     66   68 my $self = shift;
3588 66         87 my $arg = shift;
3589 66 50       145 if( defined( $self->{"$arg"} ) ){
3590 0         0 return( 1 );
3591             }else{
3592 66         118 return( 0 );
3593             }
3594             }
3595              
3596              
3597             # Helper function, not documented.
3598             # Alters the pending time tables.
3599             sub _beat_addnext {
3600 0     0   0 my $self = shift;
3601 0         0 my %args = ( Key => undef,
3602             Interval => undef,
3603             Once => 0,
3604             FirstOnce => 0,
3605             @_,
3606             );
3607              
3608 0         0 my $retval = 0;
3609 0 0 0     0 if( defined( $args{"Key"} ) && defined( $args{"Interval"} ) ){
3610             # See if this is a once one?
3611 0 0 0     0 if( ! $args{"Once"} || ( $args{"Once"} && $args{"FirstOnce"} ) ){
      0        
3612             # Lets see now. Work out the next time it
3613             # should be triggered.
3614 0         0 my $nexttime = time + $args{"Interval"};
3615              
3616             # Find out where it should be inserted.
3617 0         0 my $stillgoing = 1;
3618 0         0 my $loopinsert = 0;
3619 0   0     0 while( $stillgoing && defined( ${$self->{'heartbeats'}}[$loopinsert] ) ){
  0         0  
3620 0 0       0 if( $nexttime < ${$self->{'heartbeats'}}[$loopinsert] ){
  0         0  
3621 0         0 $stillgoing = 0;
3622             }else{
3623 0         0 $loopinsert++;
3624             }
3625             }
3626              
3627             # We have a place to insert it. See whether this would
3628             # conflict with an existing value.
3629 0         0 my $orignext = $nexttime;
3630 0         0 while( defined( $self->{'timepend'}{"$nexttime"} ) ){
3631 0         0 $nexttime = $orignext + rand(1);
3632             }
3633              
3634             # Insert it into the quick check. The loop we've just
3635             # done insures that its before any value that is 'just'
3636             # higher than the number we've done. Thus, the
3637             # ones with short intervals only have to go through
3638             # a small number of checks, whilst the ones with
3639             # longer intervals go through a longer number of
3640             # checks, but we only have to take that hit when on
3641             # those intervals.
3642 0         0 splice( @{$self->{'heartbeats'}}, $loopinsert, 0, $nexttime );
  0         0  
3643              
3644             # Insert it into the main list. As we're checking
3645             # the timeout to execute via a changing numeric check,
3646             # we have this indirection to lookup the actual
3647             # subroutine (and the next interval)
3648 0         0 $self->{'timepend'}{"$nexttime"} = $args{"Key"};
3649              
3650 0         0 $retval++;
3651             }
3652             }
3653 0         0 return( $retval );
3654             }
3655              
3656             =head2 _connect_starttls handler
3657              
3658             This is a helper function (for ->connect) for the starting up of TLS/SSL
3659             via the tag.
3660              
3661             =cut
3662              
3663             sub _connect_starttls {
3664 0     0   0 my $self = shift;
3665              
3666 0         0 my $node = shift;
3667 0         0 my $persisdata = shift;
3668 0         0 my $tlsxmlns = $self->ConstXMLNS( 'xmpp-tls' );
3669              
3670 0         0 my $retval = undef;
3671              
3672 0 0       0 if( defined( $node ) ){
3673 0 0 0     0 if( $node->name() eq "proceed" && $node->xmlns() eq $tlsxmlns ){
    0 0        
3674             # Re-invoke ->connect to get SSL running. We need
3675             # to slurp the original SSL* args out though.
3676 0         0 my %SSLHash = ();
3677 0         0 foreach my $kkey( keys %{$self->{'_connectargs'}} ){
  0         0  
3678 0 0       0 next unless( $kkey =~ /^(SSL|Version|Domain)/ );
3679 0         0 $SSLHash{"$kkey"} = $self->{'_connectargs'}{"$kkey"};
3680             }
3681 0         0 $self->connect( '_redo' => 1, JustConnectAndStream => 1, UseSSL => 1, MustEncrypt => 1, %SSLHash );
3682 0         0 $retval = r_HANDLED;
3683             }elsif( $node->name() eq "failure" && $node->xmlns() eq $tlsxmlns ){
3684             # We have sent a '', but the other side has
3685             # sent us a '' tag. RFC3920 5.2 #5 states
3686             # that the receiving entity (thats us) MUST terminate
3687             # both the XML stream and the underlying TCP connection.
3688 0         0 $self->disconnect();
3689 0         0 $retval = r_HANDLED;
3690              
3691             }
3692             }
3693              
3694 0         0 return( $retval );
3695             }
3696              
3697             =head2 _connect_handler handler
3698              
3699             This is a helper function (for ->connect) for the handling of some initial
3700             tags.
3701              
3702             =cut
3703              
3704             sub _connect_handler {
3705 0     0   0 my $self = shift;
3706 0         0 my $node = shift;
3707 0         0 my $persisdata = shift;
3708              
3709 0         0 my $retval = undef;
3710 0         0 my $cango = 1;
3711              
3712 0         0 $self->debug( "invoked\n" );
3713              
3714 0 0       0 if( defined( $node ) ){
3715 0         0 my $nodename = lc( $node->name() );
3716 0 0       0 $self->debug( " Got $node($nodename) and " . ( defined( $persisdata ) ? $persisdata : "undef" ) . " X\n" );
3717              
3718 0 0       0 if( $nodename eq '?xml' ){
    0          
    0          
    0          
3719             # RFC3920 11.4 says that applications MUST deal with
3720             # the opening text declaration. We don't unfortunately,
3721             # and we don't pass it back to the caller. This is
3722             # something for 0.9 .
3723 0         0 $retval = r_HANDLED;
3724 0         0 $self->xml_version( value => $node->attr( "version" ) );
3725 0         0 $self->xml_encoding( value => $node->attr( "encoding" ) );
3726             }elsif( $nodename eq 'stream:stream' ){
3727 0         0 $retval = r_HANDLED;
3728              
3729 0 0       0 if( defined( $node->attr( 'from' ) ) ){
3730 0         0 $self->{'confirmedns'} = $node->attr( 'from' );
3731             # See if we allow such redirection.
3732             # if( ! $args{"AllowRedirect"} ){
3733 0 0       0 if( ! $self->{'_connectargs'}{"AllowRedirect"} ){
3734 0 0       0 if( lc( $self->{'confirmedns'} ) ne lc( $self->{'_connectargs'}{"Domain"} ) ){
3735 0         0 $cango = 0;
3736             }
3737             }
3738             }
3739 0 0       0 if( defined( $node->attr( 'id' ) ) ){
3740 0         0 $self->{'streamid'} = $node->attr( 'id' );
3741             }
3742              
3743             # RFC3920 - 4.4.1 item 4. Version defaults to 0.0
3744 0 0       0 if( defined( $node->attr( 'version' ) ) ){
3745 0         0 $self->{'streamversion'} = $node->attr( 'version' );
3746             }else{
3747 0         0 $self->{'streamversion'} = "0.0";
3748 0         0 $self->{'authmechs'}{"jabber:iq:auth"} = "1";
3749             }
3750 0 0       0 if( defined( $node->xmlns() ) ){
3751 0         0 $self->{'streamxmlns'} = $node->xmlns();
3752             }
3753 0 0       0 if( defined( $node->attr( 'stream:xmlns' ) ) ){
3754 0         0 $self->{'streamstream:xmlns'} = $node->attr( 'stream:xmlns' );
3755             }
3756 0 0       0 if( defined( $node->attr( 'xml:lang' ) ) ){
3757 0         0 $self->{'streamxml:lang'} = $node->attr( 'xml:lang' );
3758             }
3759             }elsif( $nodename eq 'stream:error' ){
3760 0         0 $retval = r_HANDLED;
3761             # Create a new node, as the previous one gets bits of it
3762             # automagically destroyed at the end.
3763 0         0 $self->{'stream:error'} = $self->newNodeFromStr( $node->toStr );
3764 0         0 $self->disconnect();
3765             }elsif( $nodename eq 'stream:features' ){
3766 0         0 $retval = r_HANDLED;
3767              
3768             # Create a new node, as the previous one gets bits of it
3769             # automagically destroyed at the end.
3770 0         0 $self->{'stream:features'} = $self->newNodeFromStr( $node->toStr );
3771              
3772             # Run through the list, and initiate tls if required.
3773 0         0 my $tlsxmlns = $self->ConstXMLNS( "xmpp-tls" );
3774 0         0 my $ssltag = $node->getTag( "starttls", $tlsxmlns );
3775 0 0 0     0 if( defined( $ssltag ) && $self->{'_connectargs'}{"UseTLS"} && ! $self->is_encrypted() ){
      0        
3776 0         0 $self->debug( " Got ssltag\n" );
3777             # We can issue a tag, then wait for
3778             # a or tag. If it is
3779             # a , we reinvoke ourselves with
3780             # UseSSL, MustEncrypt and _redo set, and
3781             # return with that.
3782              
3783             # Flip into single character mode, so we
3784             # don't swallow any initial SSL characters.
3785             # my $oldreadsize = $self->{'_readsize'};
3786             # $self->{'_readsize'} = 1;
3787              
3788 0         0 my $sendsslproceed = $self->newNode( "starttls", $tlsxmlns );
3789 0         0 $self->send( $sendsslproceed );
3790 0         0 $self->{'_ask_encrypted'} = 1;
3791 0         0 $self->{'stream:features'} = undef;
3792             }else{
3793             # Run through the list of what we have. We're
3794             # after the auth mechanisms, and possibly the
3795             # auth tag.
3796 0         0 foreach my $snode( $node->getChildren() ){
3797 0 0       0 if( lc($snode->name()) eq "auth" ){
    0          
3798 0 0       0 if( lc( $snode->xmlns ) eq $self->ConstXMLNS( "iq-auth" ) ){
3799 0         0 $self->{'authmechs'}{"jabber:iq:auth"} = "1";
3800             }
3801             }elsif( $snode->name() eq "mechanisms" ){
3802 0         0 foreach my $cnode( $snode->getChildren() ){
3803 0 0       0 next unless( $cnode->name() eq "mechanism" );
3804 0         0 $self->{'authmechs'}{'sasl-' . lc($cnode->data())} = "1";
3805             }
3806             }
3807             }
3808             }
3809             }
3810             }
3811              
3812 0         0 $self->debug( " returning $retval X\n" );
3813 0         0 return( $retval );
3814             }
3815              
3816             =head2 xml_version
3817              
3818             This returns the version supplied by the last tag received.
3819              
3820             =cut
3821              
3822             sub xml_version {
3823 0     0   0 my $self = shift;
3824 0         0 my %args = ( @_ );
3825 0 0       0 if( exists( $args{"value"} ) ){
3826 0         0 $self->{'_xml_version'} = $args{"value"};
3827             }
3828 0         0 return( $self->{'_xml_version'} );
3829             }
3830              
3831             =head2 xml_encoding
3832              
3833             This returns the encoding supplied by the last tag received.
3834              
3835             =cut
3836              
3837             sub xml_encoding {
3838 0     0   0 my $self = shift;
3839 0         0 my %args = ( @_ );
3840 0 0       0 if( exists( $args{"value"} ) ){
3841 0         0 $self->{'_xml_encoding'} = $args{"value"};
3842             }
3843 0         0 return( $self->{'_xml_encoding'} );
3844             }
3845              
3846             ############################################################################
3847             # Functions for the object as XML document holder. OO style, so we
3848             # continually create sub-objects as required.
3849              
3850             =head1 METHODS - Object common
3851              
3852             These are for the library as XML parser, creating new objects, reading
3853             attributes etc.
3854              
3855             =head2 get_latest
3856              
3857             Returns the latest complete object or undef. This function is only
3858             valid on the parent connection object.
3859              
3860             WARNING: This is a destructive process; a second call will return undef
3861             until another object has been read.
3862              
3863             =cut
3864              
3865             sub get_latest {
3866 0     0   0 my $self = shift;
3867              
3868 0         0 my $retval = undef;
3869 0 0       0 if( defined( $self->{'_curobj'} ) ){
    0          
3870 0 0       0 if( $self->{'_curobj'}->is_complete() ){
3871 0         0 $retval = $self->{'_curobj'};
3872 0         0 $self->{'_curobj'} = undef;
3873 0         0 $self->{'_curobjbytes'} = 0;
3874 0         0 $self->{'_is_complete'} = undef;
3875             }else{
3876 0         0 $self->{'_is_complete'} = undef;
3877             }
3878             }elsif( defined( $self->{'_is_complete'} ) ){
3879             # Cope with stray things.
3880 0         0 $self->{'_is_complete'} = undef;
3881             }
3882              
3883 0         0 $self->debug( "returning $retval\n" );
3884 0         0 return( $retval );
3885             }
3886              
3887             =head2 copy_latest
3888              
3889             This returns a copy of the latest object, whether or not it is
3890             actually complete. An optional argument may be supplied, which
3891             will be used to replace the current object.
3892              
3893             WARNING: This may return objects which are incomplete, and may not
3894             make too much sense. Supplying an argument which is not of this
3895             class may produce odd results.
3896              
3897             =cut
3898              
3899             sub copy_latest {
3900 0     0   0 my $self = shift;
3901              
3902 0         0 my $retval = undef;
3903 0         0 my $arg = shift;
3904 0 0       0 if( defined( $arg ) ){
3905 0         0 $self->debug( " putting back $arg\n" );
3906 0         0 $self->{'_curobj'} = $arg;
3907             }
3908 0 0       0 if( defined( $self->{'_curobj'} ) ){
3909 0         0 $retval = $self->{'_curobj'};
3910             }
3911              
3912 0         0 return( $retval );
3913             }
3914              
3915             =head2 clear_latest
3916              
3917             This clears the latest object.
3918              
3919             =cut
3920              
3921             sub clear_latest {
3922 0     0   0 my $self = shift;
3923              
3924 0         0 $self->{'_curobj'} = undef;
3925             }
3926              
3927             =head2 newNode
3928              
3929             Creates a new Node or tag, and returns the object thus created. Takes
3930             two arguments, being a required name for the object, and an optional
3931             xmlns value. Returns undef if a name was not supplied.
3932              
3933             A previously created object can be supplied instead.
3934              
3935             =cut
3936              
3937             sub newNode {
3938 14     14   17 my $self = shift;
3939 14         25 my $arg = shift;
3940              
3941 14         14 my $retobj = undef;
3942              
3943 14 50       42 if( defined( $arg ) ){
3944              
3945             # First argument could be a reference, hopefully
3946             # to one of us.
3947 14         18 my $tref = ref( $arg );
3948 14 50       24 if( $tref ){
3949 0         0 $retobj = $arg;
3950             }else{
3951 14         32 $retobj = Jabber::Lite->new();
3952 14         35 $retobj->name( $arg );
3953             }
3954              
3955 14         25 my $xmlns = shift;
3956              
3957 14 50       28 if( defined( $xmlns ) ){
3958 0         0 $retobj->xmlns( $xmlns );
3959             }
3960              
3961             # If we have debug set, set it on the child.
3962 14         29 $retobj->{'_debug'} = $self->{'_debug'};
3963              
3964             }
3965              
3966             # my @calledwith = caller(1);
3967             # my $lineno = $calledwith[2];
3968             # my $fname = $calledwith[1];
3969             # print STDERR "$self: newNode called from line $lineno $fname, returning $retobj\n";
3970              
3971 14         23 return( $retobj );
3972             }
3973              
3974             =head2 newNodeFromStr
3975              
3976             Creates a new Node or tag from a supplied string, and returns the object
3977             thus created. Takes a single argument, being the string for the object.
3978             Returns undef if a string was not supplied.
3979              
3980             Note: If there was more than one object in the string, the remaining
3981             string is tossed away; you only get one object back.
3982              
3983             =cut
3984              
3985             sub newNodeFromStr {
3986 0     0   0 my $self = shift;
3987 0         0 my $str = shift;
3988              
3989 0         0 my ($retobj, $success, $rtext ) = $self->create_and_parse( $str );
3990              
3991 0 0       0 if( $success == 1 ){
3992 0         0 return( $retobj );
3993             }else{
3994 0         0 return( undef );
3995             }
3996             }
3997              
3998             =head2 insertTag
3999              
4000             Inserts a tag into the current object. Takes the same arguments as
4001             ->newNode, and returns the object created.
4002              
4003             =cut
4004              
4005             sub insertTag {
4006 0     0   0 my $self = shift;
4007              
4008 0         0 my $retobj = $self->newNode( @_ );
4009             # print STDERR "insertTag called on $self, going to return $retobj\n";
4010              
4011 0 0       0 if( defined( $retobj ) ){
4012 0         0 my $nextnum = 0;
4013 0 0       0 if( defined( $self->{'_curobjs'} ) ){
4014 0         0 $nextnum = scalar @{$self->{'_curobjs'}};
  0         0  
4015             }
4016 0 0       0 if( ! defined( $nextnum ) ){
    0          
4017 0         0 $nextnum = 0;
4018             }elsif( $nextnum =~ /\D/ ){
4019 0         0 $nextnum = 0;
4020             }
4021              
4022             # Set the parent. This is enclosed in an eval
4023             # in case it is a different reference type.
4024 0         0 eval {
4025             # print STDERR "Setting parent on $retobj to be $self\n";
4026 0         0 $retobj->parent( $self );
4027             };
4028              
4029             # Store it.
4030 0         0 ${$self->{'_curobjs'}}[$nextnum] = $retobj;
  0         0  
4031              
4032             }
4033              
4034 0         0 return( $retobj );
4035             }
4036              
4037              
4038             =head2 name
4039              
4040             Returns, or sets, the name of the object. Takes an optional argument for
4041             the new name.
4042              
4043             Note: No checking or escaping is done on the supplied name.
4044              
4045             =cut
4046              
4047             sub name {
4048 36     36   41 my $self = shift;
4049 36         42 my $arg = shift;
4050 36 100       64 if( defined( $arg ) ){
4051 14         26 $self->{'_name'} = $arg;
4052 14         38 $self->debug( "Setting my name to $arg X" );
4053             }
4054              
4055 36         83 return( $self->{'_name'} );
4056             }
4057              
4058             =head2 is_complete
4059              
4060             Return 1 or 0 whether the current object is complete.
4061              
4062             =cut
4063              
4064             sub is_complete {
4065 6     6   9 my $self = shift;
4066 6 50       24 if( defined( $self->{'_is_complete'} ) ){
4067 0         0 $self->debug( " 1\n" );
4068 0         0 return( 1 );
4069             }else{
4070 6         11 $self->debug( " 0\n" );
4071 6         30 return( 0 );
4072             }
4073             }
4074              
4075             =head2 getChildren
4076              
4077             Return an @array of subobjects.
4078              
4079             =cut
4080              
4081             sub getChildren {
4082 0     0   0 my $self = shift;
4083 0         0 return( @{$self->{'_curobjs'}} );
  0         0  
4084             }
4085              
4086             =head2 getTag
4087              
4088             Return a specific child tag if it exists. Takes the name of the tag,
4089             and optionally the xmlns value of the tag (first found wins in the case
4090             of duplicates).
4091              
4092             =cut
4093              
4094             sub getTag {
4095 0     0   0 my $self = shift;
4096              
4097 0         0 my $wantname = shift;
4098 0         0 my $wantxmlns = shift;
4099              
4100 0         0 my $retobj = undef;
4101 0 0 0     0 if( defined( $self->{'_curobjs'} ) && defined( $wantname ) ){
4102 0         0 my $maxobjs = scalar( @{$self->{'_curobjs'}} );
  0         0  
4103 0         0 my $loop = 0;
4104 0   0     0 while( $loop < $maxobjs && ! defined( $retobj ) ){
4105 0 0       0 if( defined( ${$self->{'_curobjs'}}[$loop] ) ){
  0         0  
4106 0 0       0 if( ${$self->{'_curobjs'}}[$loop]->name() eq $wantname ){
  0         0  
4107 0         0 $self->debug( " $loop matches $wantname X\n" );
4108 0 0       0 if( defined( $wantxmlns ) ){
4109 0 0       0 if( ${$self->{'_curobjs'}}[$loop]->xmlns() eq $wantxmlns ){
  0         0  
4110 0         0 $self->debug( " $loop matches $wantxmlns X\n" );
4111 0         0 $retobj = ${$self->{'_curobjs'}}[$loop];
  0         0  
4112             }
4113             }else{
4114 0         0 $retobj = ${$self->{'_curobjs'}}[$loop];
  0         0  
4115             }
4116             }
4117             }
4118 0         0 $loop++;
4119             }
4120             }
4121            
4122              
4123 0         0 return( $retobj );
4124             }
4125              
4126             =head2 listAttrs
4127              
4128             Return an @array of attributes on the current object.
4129              
4130             =cut
4131              
4132             sub listAttrs {
4133 0     0   0 my $self = shift;
4134              
4135 0         0 my @retarray = ();
4136              
4137 0         0 foreach my $attribname( keys %{$self->{'_attribs'}} ){
  0         0  
4138 0 0       0 next unless( defined( $attribname ) );
4139 0 0       0 next if( $attribname =~ /^\s*$/s );
4140 0         0 push @retarray, $attribname;
4141             }
4142 0         0 return( @retarray );
4143              
4144             }
4145              
4146             =head2 attr
4147              
4148             Return or set the contents of an attribute. Takes an attribute name
4149             as the first argument, and the optional attribute contents (replacing
4150             anything there) as the second argument.
4151              
4152             =cut
4153              
4154             sub attr {
4155 0     0   0 my $self = shift;
4156              
4157 0         0 my $attribname = shift;
4158 0         0 my $attribvalue = shift;
4159              
4160 0 0 0     0 if( defined( $attribvalue ) && defined( $attribname ) ){
    0          
4161 0         0 $self->debug( " Storing in $attribname - $attribvalue X\n" );
4162 0         0 $self->{'_attribs'}{"$attribname"} = $attribvalue;
4163             }elsif( defined( $attribname ) ){
4164 0 0       0 if( defined( $self->{'_attribs'}{"$attribname"} ) ){
4165 0         0 $attribvalue = $self->{'_attribs'}{"$attribname"};
4166             }else{
4167 0         0 $attribvalue = undef;
4168             }
4169             }else{
4170 0         0 $attribvalue = undef;
4171             }
4172              
4173 0         0 return( $attribvalue );
4174             }
4175              
4176             =head2 xmlns
4177              
4178             Sets or returns the value of the xmlns attribute.
4179              
4180             =cut
4181              
4182             sub xmlns {
4183 0     0   0 my $self = shift;
4184 0         0 return( $self->attr( 'xmlns', @_ ) );
4185             }
4186              
4187             =head2 data
4188              
4189             Returns or sets the data associated with this object. Take an optional
4190             argument supplying the data to replace any existing data. Performs
4191             encoding/decoding of common XML escapes.
4192              
4193             =cut
4194              
4195             sub data {
4196 0     0   0 my $self = shift;
4197              
4198 0         0 my $dstr = shift;
4199              
4200 0 0       0 if( defined( $dstr ) ){
4201             # Do some encoding on the string.
4202 0         0 $self->{'_data'} = $self->encode( $dstr );
4203              
4204             }
4205              
4206             # Need to do some decoding stuff.
4207 0         0 return( $self->decode( $self->{'_data'} ) );
4208             }
4209              
4210             =head2 rawdata
4211              
4212             The same as ->data(), but without the encodings/decodings used. Make sure
4213             anything that you add doesn't include valid XML tag characters, or something
4214             else will break.
4215              
4216             =cut
4217              
4218             sub rawdata {
4219 0     0   0 my $self = shift;
4220              
4221 0         0 my $dstr = shift;
4222              
4223 0 0       0 if( defined( $dstr ) ){
4224 0         0 $self->{'_data'} = $dstr;
4225             }
4226              
4227 0         0 return( $self->{'_data'} );
4228             }
4229              
4230             =head2 parent
4231              
4232             Returns the parent object of the current object, or undef.
4233              
4234             =cut
4235              
4236             sub parent {
4237 33     33   35 my $self = shift;
4238              
4239 33 100       102 if( @_ ){
4240 4 50       8 if( $Jabber::Lite::WeakRefs ){
4241 4         13 Scalar::Util::weaken($self->{'_parent'} = shift);
4242             # warn( "$self: Set SUW parent to " . $self->{'_parent'} . "\n" );
4243             }else{
4244             # warn( "$self: Set parent to " . $self->{'_parent'} . "\n" );
4245 0         0 $self->{'_parent'} = shift;
4246             }
4247             }else{
4248             # warn( "$self: Unset parent on " . $self->name . "\n" );
4249             }
4250              
4251 33         95 return( $self->{'_parent'} );
4252             }
4253              
4254             # Hidden method to remove it; the name is MaGiC in AUTOLOAD.
4255             sub del_parent_link {
4256 4     4   4 my $self = shift;
4257 4         7 $self->{'_parent'} = undef;
4258             }
4259              
4260             =head2 hide
4261              
4262             Remove references to the current object from the parent object, effectively
4263             deleting it. Returns 1 if successful, 0 if no valid parent. If there are
4264             any child-objects, removes references to this object from them.
4265              
4266             =cut
4267              
4268             sub hide {
4269 26     26   26 my $self = shift;
4270              
4271 26         31 my $retval = 0;
4272 26 50       50 if( defined( $self->parent() ) ){
4273 0         0 $retval = $self->parent->hidechild( $self );
4274             }
4275              
4276 26 100       101 if( defined( $self->{'_curobjs'} ) ){
4277 4         5 my $numchild = scalar @{$self->{'_curobjs'}};
  4         6  
4278 4 50       12 if( defined( $numchild ) ){
4279 4         18 while( $numchild > 0 ){
4280 0         0 $numchild--;
4281             # warn( "$self: Invoking parent dereference on $numchild\n" );
4282             # This duplicates hide() and hidechild(), but
4283             # we don't want to jump through too many
4284             # hoops right now.
4285 0         0 ${$self->{'_curobjs'}}[$numchild]->del_parent_link( undef );
  0         0  
4286 0         0 ${$self->{'_curobjs'}}[$numchild] = undef;
  0         0  
4287 0         0 delete( ${$self->{'_curobjs'}}[$numchild] );
  0         0  
4288             }
4289             }
4290             }
4291              
4292 26         355 return( $retval );
4293             }
4294              
4295             =head2 hidechild
4296              
4297             Remove references to a child object. Takes an argument of a child object
4298             to delete. Returns 1 if successful, 0 if not.
4299              
4300             =cut
4301              
4302             sub hidechild {
4303 0     0   0 my $self = shift;
4304 0         0 my $arg = shift;
4305 0         0 my $match = $arg;
4306              
4307 0         0 my $retval = 0;
4308              
4309             # Run through all of the objects to find a match.
4310 0         0 my %todel = ();
4311 0 0 0     0 if( defined( $match ) && defined( $self->{'_curobjs'} ) ){
4312 0         0 my $loop = 0;
4313 0         0 my $maxval = scalar( @{$self->{'_curobjs'}} );
  0         0  
4314 0         0 while( $loop < $maxval ){
4315 0 0       0 if( defined( ${$self->{'_curobjs'}}[$loop] ) ){
  0         0  
4316 0 0       0 if( ${$self->{'_curobjs'}}[$loop] == $match ){
  0         0  
4317 0         0 $todel{"$loop"}++;
4318             }
4319             }else{
4320 0         0 $todel{"$loop"}++;
4321             }
4322 0         0 $loop++;
4323             }
4324             }
4325              
4326             # Work through the list, descending (as splice changes the
4327             # list offsets).
4328 0         0 foreach my $offset( sort { $b <=> $a } keys %todel ){
  0         0  
4329 0 0       0 next unless( defined( $offset ) );
4330 0 0       0 next if( $offset =~ /\D/ );
4331              
4332 0         0 splice( @{$self->{'_curobjs'}}, $offset, 1 );
  0         0  
4333 0         0 $retval++;
4334             }
4335              
4336             # Finally, check whether it is '_curobj' .
4337 0 0 0     0 if( defined( $self->{'_curobj'} ) && defined( $match ) ){
4338 0 0       0 if( $self->{'_curobj'} == $match ){
4339 0         0 $self->{'_curobj'} = undef;
4340 0         0 $retval++;
4341             }
4342             }
4343              
4344 0         0 return( $retval );
4345             }
4346              
4347             =head2 hidetree
4348              
4349             This routine removes references to this object, and to objects below it.
4350             In certain versions of perl, this may assist with cleanup.
4351              
4352             =cut
4353              
4354             # ->hidetree is in two parts. This is the first part, which invokes the
4355             # recursive routine and then removes the reference to ourselves from our
4356             # parent.
4357             sub hidetree {
4358 26     26   27 my $self = shift;
4359              
4360 26         53 $self->hidetree_recurse();
4361 26         57 return( $self->hide() );
4362             }
4363              
4364             # This is the second part. It avoids the recursing routine on each
4365             # child object from querying the current object again to remove
4366             # itself, as is done by ->hide.
4367             sub hidetree_recurse {
4368 30     30   36 my $self = shift;
4369              
4370             # Go through our children objects and invoke this routine.
4371 30 100       90 if( defined( $self->{'_curobjs'} ) ){
4372 4         5 my $loop = scalar( @{$self->{'_curobjs'}} );
  4         9  
4373 4         11 while( $loop > 0 ){
4374 4         5 $loop--;
4375 4 50       4 if( defined( ${$self->{'_curobjs'}}[$loop] ) ){
  4         12  
4376             # Recurse.
4377 4         5 ${$self->{'_curobjs'}}[$loop]->hidetree_recurse();
  4         13  
4378             # Delete the reference to us.
4379 4         6 ${$self->{'_curobjs'}}[$loop]->del_parent_link();
  4         13  
4380             }
4381 4         6 delete( ${$self->{'_curobjs'}}[$loop] );
  4         13  
4382             }
4383             }
4384              
4385             }
4386              
4387             =head2 toStr
4388              
4389             Returns the object in a single string. Takes an optional hash consisting
4390             of 'FH', being a filehandle reference to send output to instead (useful if
4391             you aren't wanting to copy the object into a local variable), and
4392             'GenClose', which defaults to 1 and ensures that the first tag has the
4393             proper '/' character when closing the tag.
4394              
4395             If set to '0', '' will be output instead of '', a highly
4396             important distinction when first connecting to Jabber servers (remember that
4397             a Jabber connection is really one long '' tag ).
4398              
4399             =cut
4400              
4401             # Note - since this is a recursive call, there are probably too many
4402             # tests to see whether we have a filehandle. A slight performance
4403             # increase could probably be gained by duplicating the code in
4404             # a seperate function, but that means that two locations for output
4405             # need to be maintained.
4406              
4407             sub toStr {
4408 0     0   0 my $self = shift;
4409 0         0 my %args = ( FH => undef,
4410             GenClose => 1,
4411             @_, );
4412 0         0 my $fh = $args{"FH"};
4413 0         0 my $doend = 0;
4414              
4415 0         0 my $dval = $self->_check_val( '_debug' );
4416 0 0       0 if( $dval ){
4417 0         0 $dval = $self->{'_debug'};
4418             }
4419              
4420 0 0       0 if( ! $args{"GenClose"} ){
4421 0         0 $doend = 1;
4422             }
4423              
4424             # Return a string representation of this object.
4425 0         0 my $retstr = "";
4426 0         0 my $usefh = 0;
4427 0         0 my $mustend = 0;
4428 0 0       0 if( defined( $fh ) ){
4429 0         0 $usefh = 1;
4430             }
4431              
4432             # $self->debug( "toStr starting\n") if( $dval );
4433 0 0       0 if( ! $usefh ){
4434 0         0 $retstr = "<" . $self->name();
4435             }else{
4436 0         0 print $fh "<" . $self->name();
4437             }
4438              
4439             # See if this is actually processing instructions etc.
4440 0 0       0 if( $self->name() =~ /^\[CDATA\[/ ){
    0          
    0          
4441 0 0       0 if( ! $usefh ){
4442 0         0 $retstr .= $self->{'_cdata'} . "]]";
4443             }else{
4444 0         0 print $fh $self->{'_cdata'} . "]]";
4445             }
4446 0         0 $doend = 1;
4447             }elsif( $self->name() =~ /^\!/ ){
4448 0         0 $mustend = 1;
4449              
4450             # doctype stuff is special. When we see the
4451             # pattern '\[\s*\]' within, that means that we
4452             # insert, at that point, the 'next' subtag object,
4453             # and so forth. Annoying stuff.
4454 0         0 my $tstr = "";
4455 0         0 my $tloop = -1;
4456 0         0 my $tstrlength = -1;
4457 0         0 my $stillgoing = 0;
4458 0 0       0 if( defined( $self->{'_doctype'} ) ){
4459 0         0 $tstrlength = length( $self->{'_doctype'} );
4460 0         0 $stillgoing = 1;
4461             }
4462              
4463 0         0 my $nexttag = 0;
4464 0         0 my $foundopen = -5;
4465 0   0     0 while( $tloop < $tstrlength && $stillgoing ){
4466 0         0 $tloop++;
4467 0         0 my $thischar = substr( $self->{'_doctype'}, $tloop, 1 );
4468 0 0 0     0 if( $thischar eq '[' ){
    0 0        
    0          
    0          
4469 0         0 $tstr .= $thischar;
4470 0         0 $foundopen = $tloop;
4471             # Find the next subtag offset.
4472 0 0       0 if( defined( $self->{'_curobjs'} ) ){
4473 0 0       0 if( defined( ${$self->{'_curobjs'}}[$nexttag] ) ){
  0         0  
4474 0         0 $tstr .= ${$self->{'_curobjs'}}[$nexttag]->toStr();
  0         0  
4475 0         0 $nexttag++;
4476             }
4477             }
4478             }elsif( $foundopen >= 0 && $thischar !~ /^(\s*|\])$/ ){
4479 0         0 $tstr .= "]";
4480 0         0 $foundopen = -5;
4481 0         0 $tstr .= $thischar;
4482             }elsif( $foundopen >= 0 && $thischar eq ']' ){
4483 0         0 $foundopen = -5;
4484 0         0 $tstr .= $thischar;
4485             }elsif( $foundopen < 0 ){
4486 0         0 $tstr .= $thischar;
4487             }
4488             }
4489              
4490 0 0       0 if( ! $usefh ){
4491 0         0 $retstr .= $tstr;
4492             }else{
4493 0         0 print $fh $tstr;
4494             }
4495 0         0 $doend = 1;
4496             }elsif( $self->name() =~ /^\?/ ){
4497 0 0       0 if( defined( $self->{'_processinginstructions'} ) ){
4498 0 0       0 if( ! $usefh ){
4499 0         0 $retstr .= " " . $self->{'_processinginstructions'};
4500             }else{
4501 0         0 print $fh " " . $self->{'_processinginstructions'};
4502             }
4503             }
4504 0         0 $mustend = 1;
4505 0         0 $doend = 1;
4506             }
4507              
4508 0 0       0 if( defined( $self->{'_attribs'} ) ){
4509 0 0       0 if( ! $usefh ){
4510 0         0 foreach my $attribname ( $self->listAttrs ){
4511 0         0 my $attribvalue = $self->attr( $attribname );
4512              
4513             # $retstr .= " " . $attribname . "=\"" . $attribvalue . "\"";
4514 0         0 $retstr .= " " . $attribname . "=\'" . $attribvalue . "\'";
4515             }
4516             }else{
4517 0         0 foreach my $attribname ( $self->listAttrs ){
4518 0         0 my $attribvalue = $self->attr( $attribname );
4519              
4520 0         0 print $fh " " . $attribname . "=\"" . $attribvalue . "\"";
4521             }
4522             }
4523             }
4524              
4525 0 0       0 $self->debug( "toStr now have $retstr\n" ) if( $dval );
4526              
4527 0         0 my $gotmore = 0;
4528 0 0       0 if( defined( $self->{'_data'} ) ){
    0          
4529 0 0       0 $self->debug( "toStr has _data\n") if( $dval );
4530 0         0 $gotmore++;
4531             }elsif( defined( $self->{'_curobjs'} ) ){
4532 0 0       0 $self->debug( "toStr has _cur_objs\n" ) if( $dval );
4533 0 0       0 if( ( scalar @{$self->{'_curobjs'}} ) > 0 ){
  0         0  
4534 0         0 $gotmore++;
4535             }
4536             }
4537 0 0       0 $self->debug( "toStr G $gotmore M $mustend D $doend\n") if( $dval );
4538              
4539             # Close off the start tag.
4540 0 0 0     0 if( ! $gotmore || $mustend ){
4541             # Complete end of tag.
4542 0 0       0 if( $self->name() =~ /^\?/ ){
4543 0 0       0 if( ! $usefh ){
4544 0         0 $retstr .= '?';
4545             }else{
4546 0         0 print $fh '?';
4547             }
4548             }
4549 0 0       0 if( $doend ){
4550 0 0       0 if( ! $usefh ){
4551 0         0 $retstr .= '>';
4552             }else{
4553 0         0 print $fh '>';
4554             }
4555             }else{
4556 0 0       0 if( ! $usefh ){
4557 0         0 $retstr .= '/>';
4558             }else{
4559 0         0 print $fh '/>';
4560             }
4561             }
4562             }else{
4563             # There are more tags to insert.
4564 0 0       0 if( ! $usefh ){
4565 0         0 $retstr .= ">";
4566             }else{
4567 0         0 print $fh ">";
4568             }
4569              
4570             # Start running through the list of stuff. Subtags first.
4571 0 0       0 if( defined( $self->{'_curobjs'} ) ){
4572 0         0 my $numobjs = scalar @{$self->{'_curobjs'}};
  0         0  
4573              
4574 0         0 my $loop = 0;
4575 0 0       0 if( ! $usefh ){
4576 0         0 while( $loop < $numobjs ){
4577 0         0 $retstr .= ${$self->{'_curobjs'}}[$loop]->toStr();
  0         0  
4578 0         0 $loop++;
4579             }
4580             }else{
4581 0         0 while( $loop < $numobjs ){
4582 0         0 ${$self->{'_curobjs'}}[$loop]->toStr( FH => $fh );
  0         0  
4583 0         0 $loop++;
4584             }
4585             }
4586             }
4587              
4588             # Now for the data. No encoding on the output.
4589 0 0       0 if( defined( $self->{'_data'} ) ){
4590 0 0       0 if( ! $usefh ){
4591 0         0 $retstr .= $self->rawdata();
4592             }else{
4593 0         0 print $fh $self->rawdata();
4594             }
4595             }
4596              
4597             # Now finish off.
4598 0 0       0 if( $doend ){
4599 0 0       0 if( ! $usefh ){
4600 0         0 $retstr .= ">";
4601             }else{
4602 0         0 print $fh ">";
4603             }
4604             }else{
4605 0 0       0 if( ! $usefh ){
4606 0         0 $retstr .= 'name() . ">";
4607             }else{
4608 0         0 print $fh 'name() . ">";
4609             }
4610             }
4611             }
4612              
4613 0 0       0 $self->debug( "toStr ending with $retstr\n" ) if( $dval );
4614             # print STDERR "$self returning X $retstr X\n";
4615 0         0 chomp( $retstr );
4616              
4617             # Clean up the return.
4618 0         0 $retstr =~ s/^\s*
4619 0         0 $retstr =~ s/>\s*$/>/gs;
4620 0         0 return( $retstr );
4621             }
4622              
4623             =head2 GetXML
4624              
4625             This is the Net::XMPP::Stanza compatibility call, and simply invokes
4626             ->toStr. Note for Ryan: where is ->GetXML actually documented?
4627              
4628             =cut
4629              
4630             sub GetXML {
4631 0     0   0 my $self = shift;
4632 0         0 return( $self->toStr( @_ ) );
4633             }
4634              
4635             =head1 METHODS - Object detailed and other stuff.
4636              
4637             =head2 create_and_parse
4638              
4639             Creates and returns a new instance of an object. Invoked by ->do_read() and
4640             ->parse_more(). Takes as an optional argument some text to parse.
4641              
4642             Returns the new object (or undef), a success value, and any unprocessed text.
4643             Success values can be one of:
4644              
4645             -2 Invalid XML
4646             0 No errors
4647             1 Complete object
4648              
4649             =cut
4650              
4651             sub create_and_parse {
4652 14     14   84 my $self = shift;
4653              
4654 14         21 my $str = shift;
4655              
4656 14         51 $self->debug( " Invoked with $str X\n" );
4657              
4658 14         19 my $retobj = undef;
4659 14         16 my $retstr = "";
4660 14         16 my $retval = 0;
4661              
4662             # We expect to find '' or '' or ''
4663             # or ''
4664              
4665             # See if there is a complete word.
4666 14 50       28 if( defined( $str ) ){
4667 14         16 my $tagstr = "";
4668 14         15 my $isend = 0;
4669 14         16 my $curstatus = "unknown";
4670 14         14 my $gotlength = 0;
4671 14         13 my $gotfull = 0;
4672             # Match '' or ''.
4673             # All parsing is done by parse_more.
4674 14 50       78 if( $str =~ /^(\s*<(\S+.*))$/s ){
4675 14         26 $gotlength = length( $1 );
4676 14         26 $tagstr = $2;
4677 14         18 $curstatus = "name";
4678             }
4679              
4680             # Prepare the string to return.
4681 14 50       26 if( $gotlength > 0 ){
    0          
4682              
4683             # Return the string minus the stuff we just read.
4684 14         25 $retstr = substr( $str, $gotlength );
4685              
4686             # Process the tag string. We just look for
4687             # the first bit of text giving the name, then
4688             # we pass the rest of the processing to
4689             # parse_more.
4690              
4691             # Create the object. Use a null string at first.
4692 14         35 $retobj = $self->newNode( "" );
4693              
4694             # Set the status indicator on this object
4695             # for later usage.
4696 14         23 $retobj->{'_cur_status'} = $curstatus;
4697              
4698             # Copy the list of tags we expect to be incomplete.
4699 14 50       48 if( defined( $self->{'_expect-incomplete'} ) ){
4700 0         0 $retobj->{'_expect-incomplete'} = $self->{'_expect-incomplete'};
4701             }
4702            
4703 14         23 my $tval = 0;
4704 14         16 my $rtext = "";
4705              
4706             # Pass it off to parse_more.
4707 14         51 ( $tval, $rtext ) = $retobj->parse_more( $tagstr );
4708             # $self->debug( "parse_more returned $tval, $rtext X" );
4709              
4710             # There shouldn't be anything left in
4711             # rtext. What do we do if there is?
4712             # Add it to the text to be returned,
4713             # and processed later.
4714 14 100       45 if( length( $rtext ) > 0 ){
4715 6         9 $retstr = $rtext;
4716             }else{
4717 8         11 $retstr = "";
4718             }
4719              
4720             # Return what this one received.
4721 14         25 $retval = $tval;
4722              
4723             }elsif( $str =~ /^\s*$/sm ){
4724             # Swallow whitespace.
4725 0         0 $retstr = "";
4726             }else{
4727             # XML Parse error; there are characters and they
4728             # are not whitespace or object start. Bad.
4729 0         0 $retstr = $str;
4730 0         0 $retval = -2;
4731             }
4732             }
4733              
4734 14         59 $self->debug( " Returning $retobj, $retval, $retstr\n" );
4735             # Return the object and the string to return.
4736 14         55 return( $retobj, $retval, $retstr );
4737             }
4738              
4739             =head2 parse_more
4740              
4741             Parses some text and adds it to an existing object. Creates further
4742             sub-objects as appropriate. Returns a success value, and any unprocessed
4743             text. Success values can be one of:
4744              
4745             -2 if a parsing error was found.
4746             0 if no obvious bugs were found.
4747             1 if a complete object was found.
4748              
4749             The parser, such as it is, will sometimes return text to be prepended with
4750             any new text. If the calling application does not keep track of the
4751             returned text and supply it the next time, the parser's behaviour is
4752             undefined. Most applications will be invoking ->parse_more() via
4753             ->do_read or ->process(), so this situation will not come up.
4754              
4755             This needs
4756              
4757             An optional second argument can be supplied which, if 1, will inhibit the
4758             saving of most text to memory. This is used by do_read to indicate that an
4759             excessively-large object is being read.
4760              
4761             =cut
4762              
4763             sub parse_more {
4764 18     18   35 my $self = shift;
4765              
4766 18         20 my $str = shift;
4767              
4768 18         38 my $dval = $self->_check_val( '_debug' );
4769 18 50       37 if( $dval ){
4770 0         0 $dval = $self->{'_debug'};
4771             }
4772 18 50       39 if( defined( $self->name() ) ){
4773 18 50       52 $self->debug( " " . $self->name() . " Invoked with $str\n" ) if( $dval );
4774             }else{
4775 0 0       0 $self->debug( " (no name) Invoked with $str\n" ) if( $dval );
4776             }
4777              
4778 18         21 my $retval = 0;
4779 18         20 my $retstr = "";
4780              
4781             # Make sure that we have something to work on.
4782 18 50       63 if( ! defined( $str ) ){
    50          
4783 0         0 return( $retval, $retstr );
4784             }elsif( $str =~ /^$/ ){
4785 0         0 return( $retval, $retstr );
4786             }
4787              
4788             # What is our current status?
4789 18         22 my $curstatus = "subtag";
4790 18 50       38 if( defined( $self->{'_cur_status'} ) ){
4791 18         29 $curstatus = $self->{'_cur_status'};
4792             }
4793              
4794             # Keep looping until we run out of text.
4795 18         20 my $pmloop = 5;
4796              
4797 18   100     87 while( $pmloop > 0 && length( $str ) > 0 ){
4798 36         38 $pmloop--;
4799              
4800 36 50       64 $self->debug( " $pmloop status of $curstatus\n" ) if( $dval );
4801              
4802             # First possible - adding to the name. The text received
4803             # is a continuation of the name.
4804 36 100       63 if( $curstatus eq "name" ){
4805 16 100       75 if( $str =~ /^(\S+)(\s+.*)?$/s ){
    50          
4806 15         34 my $namefurther = $1;
4807 15         23 $str = $2;
4808              
4809             # Deal with 'dfgdg>', which could be
4810             # read as a continuation of the name.
4811 15 100       72 if( $namefurther =~ /^([^\/]*\/>)(.*)$/s ){
    100          
4812 1         2 $namefurther = $1;
4813              
4814             # This juggling is to avoid a warning.
4815 1         2 my $r2 = $2;
4816 1         2 my $ostr = $str;
4817 1         2 $str = "";
4818 1 50       4 if( defined( $r2 ) ){
4819 1         2 $str = $r2;
4820             }
4821 1 50       6 if( defined( $ostr ) ){
4822 1         2 $str .= $ostr;
4823             }
4824             }elsif( $namefurther =~ /^([^>]*>)(.*)$/s ){
4825 11         23 $namefurther = $1;
4826              
4827             # This juggling is to avoid a warning.
4828 11         14 my $r2 = $2;
4829 11         15 my $ostr = $str;
4830 11         13 $str = "";
4831 11 50       24 if( defined( $r2 ) ){
4832 11         14 $str = $r2;
4833             }
4834 11 100       23 if( defined( $ostr ) ){
4835 8         12 $str .= $ostr;
4836             }
4837             }
4838            
4839             # Add it to the current name.
4840 15         28 $self->{'_name'} .= $namefurther;
4841              
4842             # See if we've incorporated a possible end tag into
4843             # this. We do the test on the completed name instead
4844             # of the string received in case we received the
4845             # '/' during the previous call.
4846             # We send it back if we did.
4847 15 50 33     140 if( $self->{'_name'} =~ /^\!\-\-(.*)$/s ){
    50          
    50          
    100          
    50          
    100          
    50          
    0          
4848             # Start processing a comment.
4849 0         0 $curstatus = "comment";
4850 0         0 $self->{'_name'} = '!--';
4851 0         0 $str = $1 . $str;
4852              
4853             }elsif( $self->{'_name'} =~ /^(\!\[CDATA\[)(.*)$/ ){
4854 0         0 $curstatus = "cdata";
4855 0         0 $self->{'_name'} = $1;
4856 0         0 $str = $2 . $str;
4857              
4858             }elsif( $self->{'_name'} =~ /\/$/s ){
4859             # Possible start of '/>' . Send it back.
4860             # If its actually 'sdlfk//sdf', it'll be
4861             # properly parsed next time.
4862 0         0 chop( $self->{'_name'} );
4863 0         0 $str = '/' . $str;
4864 0         0 $curstatus = "name";
4865              
4866             }elsif( $self->{'_name'} =~ /\/>$/s ){
4867             # Definitely bad. Chop off the last
4868             # two characters.
4869 2         6 chop( $self->{'_name'} );
4870 2         5 chop( $self->{'_name'} );
4871              
4872             # Then mark ourselves as being complete.
4873 2         5 $self->{'_is_complete'} = 1;
4874 2         4 $retval = 1;
4875 2         3 $curstatus = "complete";
4876              
4877             }elsif( $self->{'_name'} =~ /\?>$/s && $self->{'_name'} =~ /^\?/ ){
4878             # This is 'processing instructions'.
4879 0         0 chop( $self->{'_name'} );
4880 0         0 chop( $self->{'_name'} );
4881 0         0 $curstatus = "complete";
4882              
4883             }elsif( $self->{'_name'} =~ />$/s ){
4884             # name is 'sdfj>'. Means that we've reached
4885             # the end of the tag name, but not the end
4886             # of the tag. Remove the '>', and indicate
4887             # what we've got.
4888 10         21 chop( $self->{'_name'} );
4889 10         10 $curstatus = "subtag";
4890              
4891 10 50       25 if( $self->{'_name'} =~ /^\!/ ){
4892 0         0 $curstatus = "complete";
4893             }
4894              
4895             # This point is good for checking
4896             # whether this name matches the
4897             # one specified as 'expect-incomplete'.
4898 10 50       21 if( defined( $self->{'_expect-incomplete'} ) ){
4899 0 0       0 if( defined( $self->{'_expect-incomplete'}{$self->{'_name'}} ) ){
4900 0         0 $curstatus = "complete";
4901             }
4902             }
4903              
4904             }elsif( defined( $str ) ){
4905             # We've got a space. The name has been
4906             # completed.
4907 3         4 $curstatus = "attribs";
4908              
4909             # See if this is special stuff.
4910 3 50       19 if( $self->{'_name'} =~ /^\!/ ){
    100          
    50          
4911 0         0 $curstatus = "doctype";
4912             }elsif( $self->{'_name'} =~ /^\?/s ){
4913 1         2 $curstatus = "processinginstructions";
4914             }elsif( $self->{'_name'} =~ /^(\!\[CDATA\[)(.*)$/ ){
4915 0         0 $curstatus = "cdata";
4916 0         0 $self->{'_name'} = $1;
4917 0         0 $str = $2 . $str;
4918             }
4919              
4920             }elsif( ! defined( $str ) ){
4921 0         0 $str = "";
4922             }
4923              
4924 15 50       36 $self->debug( " ($curstatus) Remaining is $str X\n" ) if( $dval );
4925              
4926              
4927             # A space, indicating the end of the name tag, and onto the
4928             # attributes.
4929             }elsif( $str =~ /^\s+(\S+.*)$/s ){
4930 1         3 $str = $1;
4931 1         3 $curstatus = "attribs";
4932             }
4933              
4934             # Check for comments. Second check in case we missed
4935             # something.
4936 16 100       37 if( $curstatus eq "attribs" ){
4937 3 50       47 if( $self->{'_name'} =~ /^\!\-\-(.*)$/s ){
    50          
    50          
    50          
4938             # Start processing a comment.
4939 0         0 $curstatus = "comment";
4940 0         0 $str = $1 . $str;
4941             }elsif( $self->{'_name'} =~ /^\!/ ){
4942 0         0 $curstatus = "doctype";
4943             }elsif( $self->{'_name'} =~ /^\?/s ){
4944 0         0 $curstatus = "processinginstructions";
4945             }elsif( $self->{'_name'} =~ /^(\!\[CDATA\[)(.*)$/ ){
4946 0         0 $curstatus = "cdata";
4947 0         0 $self->{'_name'} = $1;
4948 0         0 $str = $2 . $str;
4949             }
4950             }
4951              
4952             # Finally, check for a valid name.
4953 16 50       31 if( $curstatus ne "name" ){
4954 16 100       76 if( $self->{'_name'} !~ /^[A-Za-z][A-Za-z0-9\-\_\:\.]*$/ ){
4955 6 100       22 if( $self->{'_name'} !~ /^(\?|\!)(\S+)/ ){
4956             # Invalid XML!
4957 5         6 $retval = -2;
4958 5         7 $retstr = $str;
4959 5         14 return( $retval, $retstr );
4960             }
4961             }
4962             }
4963             }
4964              
4965             # The string is (or is now) text that is stuff with the doctype
4966             # declaration.
4967 31 100       87 if( $curstatus =~ /^(doctype|processinginstructions|cdata)/ ){
4968 1         3 my $strlength = ( length( $str ) - 1 );
4969              
4970 1         2 my $loop = -1;
4971 1         3 my $stillgoing = 1;
4972 1         1 my $prevquery = -5;
4973              
4974 1   66     9 while( $loop < $strlength && $stillgoing ){
4975 17         19 $loop++;
4976 17         33 my $thischar = substr( $str, $loop, 1 );
4977 17 50       48 if( $curstatus eq "doctype" ){
    50          
    0          
4978 0 0       0 if( $thischar eq '[' ){
    0          
4979 0         0 $curstatus = "subtag";
4980 0         0 $stillgoing = 0;
4981 0         0 $self->{'_doctype'} .= $thischar;
4982 0         0 next;
4983             }elsif( $thischar eq '>' ){
4984 0         0 $curstatus = "complete";
4985 0         0 $stillgoing = 0;
4986 0         0 next;
4987             }else{
4988 0         0 $self->{'_doctype'} .= $thischar;
4989 0         0 next;
4990             }
4991             }elsif( $curstatus eq "processinginstructions" ){
4992 17 100       34 if( $thischar eq '>' ){
    50          
4993 2         5 $self->{'_processinginstructions'} .= $thischar;
4994             # See if this is the end pattern?
4995 2 50       7 if( $self->{'_processinginstructions'} =~ /\?>$/s ){
4996 0         0 $self->{'_processinginstructions'} =~ s/\?>$//sg;
4997             # chomp( $self->{'_processinginstructions'} );
4998 0 0       0 $self->debug( " PI is " . $self->{'_processinginstructions'} . " X " . $str . " X\n" ) if( $dval );
4999             # $loop++;
5000 0         0 $curstatus = "complete";
5001 0         0 $stillgoing = 0;
5002             }
5003 2         9 next;
5004             }elsif( $thischar eq '?' ){
5005 0         0 $prevquery = '?';
5006 0         0 $self->{'_processinginstructions'} .= $thischar;
5007             }else{
5008 15         74 $self->{'_processinginstructions'} .= $thischar;
5009             }
5010             }elsif( $curstatus eq "cdata" ){
5011 0 0       0 if( $thischar eq '>' ){
5012 0         0 $self->{'_cdata'} .= $thischar;
5013             # See if this is the end pattern?
5014 0 0       0 if( $self->{'_cdata'} =~ /\]\]>$/s ){
5015 0         0 chomp( $self->{'_processinginstructions'} );
5016 0         0 chomp( $self->{'_processinginstructions'} );
5017 0         0 chomp( $self->{'_processinginstructions'} );
5018 0         0 $curstatus = "complete";
5019 0         0 $stillgoing = 0;
5020             }
5021             }else{
5022 0         0 $self->{'_cdata'} .= $thischar;
5023             }
5024             }
5025             }
5026              
5027             # Supply the remaining text to return.
5028 1 50       4 if( $loop < $strlength ){
5029             # Remember that $loop is the character that we
5030             # have read, and $strlength has been decremented
5031             # already. So adding 1 to $loop is ok.
5032 0         0 $str = substr( $str, ( $loop + 1 ) );
5033             }else{
5034 1         2 $str = "";
5035             }
5036             }
5037              
5038             # The string is (or is now) text that is possibly attribute text.
5039             # It gets split up based on spaces.
5040 31 100       64 if( $curstatus =~ /^attrib/ ){
5041              
5042             # The attribute text looks like 'dsfkl="dfg dg" dlgkj="dg"',
5043             # with a possible end character as well. At first glance,
5044             # we can split between seperate attribute name=value pairs
5045             # by using whitespace, however whitespace within the
5046             # attribute value is possibly significant. We _must_ keep
5047             # it in place. The next method of doing this is character
5048             # by character, which is a royal pain in the ass to do.
5049             # Since we don't know how big the string is, using
5050             # split( // ) simply duplicates the string. Ugg.
5051             # So we continually use substr to peek at each character
5052             # in turn.
5053 4         7 my $strlength = ( length( $str ) - 1 );
5054              
5055 4         4 my $loop = -1;
5056              
5057 4         10 my $stillgoing = 1;
5058 4         10 my $prevforslash = -5; # Need for a numeric comparison.
5059 4         6 my $prevbacslash = -5; # Need for a numeric comparison.
5060 4         3 my $whitestart = -5; # Need for a numeric comparison.
5061 4         11 my $prevquery = -5; # Need for a numeric comparison.
5062              
5063 4   100     21 while( $loop < $strlength && $stillgoing ){
5064 18         17 $loop++;
5065              
5066             # What are we currently doing? Adding to a current
5067             # attribute or just waiting for a new attribute?
5068             # $curstatus is one of:
5069             # attribs - toss out whitespace, wait for
5070             # next attribute or end marker.
5071             # attrib-n - Finishing up a name, stored in
5072             # '_cur_attrib_name'. Look for '='.
5073             # attrib-s-fooble - Looking for a seperator
5074             # character to save in
5075             # '_cur_attrib_end'
5076             # attrib-v-fooble - Adding data to an attribute,
5077             # saving everything except for
5078             # the value in '_cur_attrib_end'
5079             #
5080 18         26 my $thischar = substr( $str, $loop, 1 );
5081              
5082 18 100       56 if( $curstatus eq "attribs" ){
    100          
    100          
    50          
5083             # Is this whitespace?
5084 10 100 66     61 if( $thischar =~ /^\s*$/s ){
    100          
    50          
    100          
    100          
5085             # Yup. Ignore it.
5086 4 100       7 if( $whitestart < 0 ){
5087 3         4 $whitestart = $loop;
5088             }
5089 4         15 next;
5090             }elsif( $thischar eq '/' ){
5091             # Possible start of end. We ignore
5092             # it as it cannot be the start of
5093             # an attribute name.
5094 1         1 $prevforslash = $loop;
5095 1         8 $whitestart = -5;
5096 1         4 next;
5097             }elsif( $thischar eq '?' && $self->{'_name'} =~ /^\?/ ){
5098             # Possible start of end when dealing
5099             # with 'processinginstructions'.
5100 0         0 $prevquery = $loop;
5101 0         0 $whitestart = -5;
5102 0         0 next;
5103             }elsif( $thischar eq '>' ){
5104              
5105             # End of the tag name. See if this
5106             # is the actual end, or start of
5107             # subtags, based on the value of
5108             # $prevforslash.
5109 1         2 $stillgoing = 0;
5110              
5111             # Is '/ >' the same as '/>' ? Have
5112             # kept $whitestart updated in case
5113             # it is.
5114 1 50 33     34 if( $prevforslash == ( $loop - 1 ) ){
    50 33        
    50          
    50          
5115 0         0 $curstatus = "complete";
5116             }elsif( $prevquery == ( $loop - 1 ) && $self->{'_name'} =~ /^\?(.*)$/s ){
5117             # processing instructions. This
5118             # gets treated as a tag on its
5119             # own.
5120 0         0 $curstatus = "complete";
5121             }elsif( $prevquery != ( $loop - 1 ) && $self->{'_name'} =~ /^\?(.*)$/s ){
5122             # Current tag is the
5123             # processing instructions,
5124             # which can only be
5125             # closed by the '?>'
5126             # construct. So, we
5127             # ignore this.
5128 0         0 $stillgoing = 1;
5129             }elsif( $self->{'_name'} =~ /^\!(\S+)$/s ){
5130 0         0 $curstatus = "complete";
5131             }else{
5132 1         2 $curstatus = "subtag";
5133             }
5134 1         6 next;
5135              
5136             # First character of an attribute name can
5137             # be a letter, underscore or colon.
5138             }elsif( $thischar =~ /^[A-Za-z\_\:]$/s ){
5139             # Start of an attribute name.
5140 2         4 $curstatus = "attrib-n";
5141 2         6 $self->{'_cur_attrib_name'} = $thischar;
5142 2         8 next;
5143             }else{
5144             # Invalid character. Do we complain
5145             # about this, or do we silently drop
5146             # it?
5147 2         3 $whitestart = -5;
5148              
5149             # We complain.
5150 2         3 $retval = -2;
5151 2         6 $stillgoing = 0;
5152 2         9 next;
5153             }
5154              
5155             # attrib-n - Finishing up a name, stored
5156             # in '_cur_attrib_name'. Look for '='.
5157             }elsif( $curstatus eq "attrib-n" ){
5158             # We add to the name, finishing when either
5159             # whitespace (value is stored as 'undef'),
5160             # or '=' is found.
5161 4 100       22 if( $thischar eq '=' ){
    50          
5162 1         2 $curstatus = "attrib-s-" . $self->{'_cur_attrib_name'};
5163 1         4 $self->{'_attribs'}{$self->{'_cur_attrib_name'}} = undef;
5164 1         2 $self->{'_cur_attrib_name'} = undef;
5165 1         4 next;
5166             }elsif( $thischar =~ /^\s+$/s ){
5167 0         0 $curstatus = "attribs";
5168 0         0 $self->{'_attribs'}{$self->{'_cur_attrib_name'}} = undef;
5169 0         0 $self->{'_cur_attrib_name'} = undef;
5170 0         0 next;
5171             }else{
5172 3         6 $self->{'_cur_attrib_name'} .= $thischar;
5173 3         10 next;
5174             }
5175              
5176             # attrib-s-fooble - Looking for a
5177             # seperator character
5178             # to save in
5179             # '_cur_attrib_end'
5180             }elsif( $curstatus =~ /^attrib-s-(\S+)$/ ){
5181 1         2 my $tname = $1;
5182 1 50       6 if( $thischar =~ /^(\"|\')$/s ){
    0          
5183 1         3 $self->{'_cur_attrib_end'} = $thischar;
5184 1         6 $curstatus = "attrib-v-" . $tname;
5185             }elsif( $thischar =~ /^\s+$/s ){
5186 0         0 next;
5187             }
5188            
5189             # attrib-v-fooble - Adding data to an
5190             # attribute, saving
5191             # everything except
5192             # for the value in
5193             # '_cur_attrib_end'
5194             }elsif( $curstatus =~ /^attrib-v-(\S+)$/s ){
5195 3         4 my $tname = $1;
5196              
5197 3 100       19 if( $thischar eq $self->{'_cur_attrib_end'} ){
    50          
    50          
5198             # Code for escaping the quote. This
5199             # isn't valid XML though, so it is
5200             # commented out.
5201             # if( $prevbacslash == ( $loop - 1 ) ){
5202             # $self->{'_attribs'}{$tname} .= $thischar;
5203             # }else{
5204 1         1 $curstatus = "attribs";
5205              
5206             # XXXX - Attribute Value
5207             # Normalisation - 3.3.3
5208 1         5 next;
5209             # }
5210             }elsif( $thischar eq "\\" ){
5211             # We store this just in case.
5212 0         0 $prevbacslash = $loop;
5213 0         0 $self->{'_attribs'}{$tname} .= $thischar;
5214 0         0 next;
5215             }elsif( $thischar eq '<' ){
5216             # 3.1 - Attribute Values
5217             # MUST NOT contain a '<'
5218             # character.
5219 0         0 $retval = -2;
5220 0         0 $retstr = $str;
5221 0         0 return( $retval, $retstr );
5222 0         0 next;
5223             }else{
5224 2         8 $prevbacslash = -5;
5225 2         3 $self->{'_attribs'}{$tname} .= $thischar;
5226 2         10 next;
5227             }
5228             }
5229             }
5230            
5231             # Now, we retrieve the text to be returned. This is based on
5232             # the $loop value, to retrieve the text further passed that.
5233              
5234 4 50       10 $self->debug( "End of loop: $curstatus $loop, $strlength, $str X\n" ) if( $dval );
5235 4 100       10 if( $loop < $strlength ){
    50          
5236             # Remember that $loop is the character that we
5237             # have read, and $strlength has been decremented
5238             # already. So adding 1 to $loop is ok.
5239 3         7 $str = substr( $str, ( $loop + 1 ) );
5240             }elsif( $prevforslash == $loop ){
5241 0         0 $str = '/';
5242             }else{
5243 1         2 $str = "";
5244             }
5245              
5246 4 50       9 $self->debug( " seeing whether curstatus ($curstatus) is subtag and name (" . $self->name() . ") is in incomplete\n" ) if( $dval );
5247 4 100       15 if( $curstatus eq 'subtag' ){
5248             # This point is good for checking
5249             # whether this name matches the
5250             # one specified as 'expect-incomplete'.
5251 1 50       4 if( defined( $self->{'_expect-incomplete'} ) ){
5252 0 0       0 $self->debug( " curstatus is subtag, and incomplete is " . $self->{'_expect-incomplete'} . "\n" ) if( $dval );
5253 0 0       0 $self->debug( " incomplete hash exists\n" ) if( $dval );
5254 0 0       0 if( defined( $self->{'_expect-incomplete'}{$self->{'_name'}} ) ){
5255 0 0       0 $self->debug( " incomplete matches\n" ) if( $dval );
5256 0         0 $curstatus = "complete";
5257             }
5258             }else{
5259 1 50       4 $self->debug( " curstatus is subtag, and incomplete is undef" ) if( $dval );
5260             }
5261             }
5262              
5263             }
5264              
5265             # The processing of the subtag setting. This reads as being
5266             # 'subtag' if we're about to enter the first subtag, and
5267             # 'subtag-num-foo' if we're in a particular subtag. Subtags
5268             # are stored in @{$self->{'_curobjs'}{'foo'}}, and numbered
5269             # offsets. Each subtag is essentially another copy of this,
5270             # with its own data.
5271 31         34 my $canparse = 1;
5272 31         41 my $numloops = 5;
5273 31   100     231 while( $curstatus =~ /^subtag/s && $canparse && $retval != -2 && $numloops > 0 ){
      100        
      66        
5274 11         14 $numloops--;
5275              
5276             # No sense parsing the unparsable.
5277 11 100       37 if( length( $str ) < 1 ){
5278 1         1 $canparse = 0;
5279 1         7 next;
5280             }
5281              
5282             # Subtag or end tag.
5283 10         13 my $istag = 1;
5284 10 100       48 if( $curstatus eq 'subtag' ){
5285             # Everything we read in here until the next
5286             # '<' character is treated as data on this
5287             # object.
5288 8         12 my $strlength = length( $str ) - 1;
5289 8         9 my $loop = -1;
5290 8         9 my $stillgoing = 1;
5291              
5292 8         8 my $tagstarts = -5;
5293 8   66     38 while( $loop < $strlength && $stillgoing ){
5294             # Only thing significant at this point
5295             # is the '<' character.
5296 26         23 $loop++;
5297 26         40 my $thischar = substr( $str, $loop, 1 );
5298             # XXXX should also check for '&' escapes
5299             # This may mean pushing them back.
5300 26 100       52 if( $thischar eq '&' ){
    100          
5301             # We must have a full escape,
5302             # which means terminated by a
5303             # ';' character.
5304 3         7 my $rstr = substr( $str, $loop );
5305 3 50       14 if( $rstr =~ /^\&(\#[0-9]+|\#x[A-Fa-f0-9]+|[A-Fa-z][A-Fa-f0-9\-\_\:\.]*|[a-z]+);(.*)$/s ){
    0          
5306 3         6 my $entlookup = $1;
5307             # my $remaining = $2;
5308 3         8 my $rtext = $self->expandEntity( $entlookup );
5309 3 50       13 if( ! defined( $rtext ) ){
5310             # Invalid XML.
5311 0         0 $retval = -2;
5312 0         0 $retstr = $rstr;
5313 0         0 return( $retval, $retstr );
5314             }else{
5315 3         6 $self->{'_data'} .= $rtext;
5316             }
5317             # Continue processing where we left off.
5318 3         13 $loop += length( '&' . $entlookup . ';' );
5319              
5320             }elsif( $rstr =~ /^\&[^;]*\s+/ ){
5321             # Invalid XML
5322 0         0 $retval = -2;
5323 0         0 $retstr = $rstr;
5324 0         0 return( $retval, $retstr );
5325             }else{
5326             # Insufficient data
5327             # Push it back.
5328 0 0       0 $self->debug( "pushing back on $thischar as $rstr is not a complete html escape." ) if( $dval );
5329 0         0 $stillgoing = 0;
5330             }
5331            
5332             }elsif( $thischar ne '<' ){
5333 15         52 $self->{'_data'} .= $thischar;
5334             }else{
5335             # End of processing for now.
5336 8         42 $stillgoing = 0;
5337             }
5338             }
5339              
5340             # The loop has ended. Sort out the remaining
5341             # string. We want the last character we looked at,
5342             # as it is significant.
5343 8 50 33     32 if( $loop <= $strlength && $stillgoing == 0 ){
5344 8         14 $str = substr( $str, $loop );
5345             }else{
5346 0         0 $str = "";
5347             }
5348              
5349             # We're expecting '
5350 8         8 $strlength = length( $str );
5351 8 50       18 if( $strlength < 2 ){
5352             # Insufficient data. We must know whether
5353             # the next two characters are '
5354             # Punt till next time.
5355 0         0 $istag = 0;
5356 0         0 $canparse = 0;
5357             }else{
5358             # Sufficient data to be sure.
5359 8 100       21 if( $str =~ /^<\//s ){
5360 4         5 $curstatus = "endname";
5361 4         7 $str = substr( $str, 2 );
5362 4         11 $self->{'_cur_endname'} = "";
5363             }else{
5364 4         5 $curstatus = "subtag";
5365 4         8 $istag = 1;
5366             }
5367             }
5368             }
5369              
5370             # Once again with feeling.
5371 10 100 66     35 if( $curstatus eq 'subtag' && $istag ){
5372              
5373             # We're creating a new object.
5374 4         19 my ( $tobj, $tval, $rtext ) = $self->create_and_parse( $str );
5375 4 50       14 if( defined( $tobj ) ){
5376              
5377             # Keep the remaining portion.
5378 4         6 $str = $rtext;
5379              
5380             # Whats the next scalar value of this one?
5381 4         5 my $nextnum = 0;
5382 4 50       10 if( defined( $self->{'_curobjs'} ) ){
5383 0         0 $nextnum = scalar @{$self->{'_curobjs'}};
  0         0  
5384             }
5385              
5386             # Set the parent.
5387 4         9 $tobj->parent( $self );
5388              
5389             # Store it.
5390 4         5 ${$self->{'_curobjs'}}[$nextnum] = $tobj;
  4         13  
5391              
5392             # Store the status.
5393 4         9 $curstatus = "subtag-" . $nextnum;
5394              
5395 4 50       8 $self->debug( "setting7 status to $curstatus - nextnum is $nextnum X\n" ) if( $dval );
5396              
5397             # If this one was considered to be complete,
5398             # change back to waiting for the next one.
5399            
5400             # Check for completeness.
5401 4 50       36 if( $tobj->is_complete() ){
5402 0         0 $curstatus = "subtag";
5403 0         0 $retval = 0;
5404 0 0       0 if( ! defined( $self->{'_name'} ) ){
    0          
    0          
5405             # print STDERR "I have no name and I must scream\n";
5406 0 0       0 $self->debug( "I have no name? This is odd." ) if( $dval );
5407             }elsif( $self->{'_name'} =~ /^\?/ ){
5408 0         0 $curstatus = "processinginstructions";
5409             }elsif( $self->{'_name'} =~ /^\!/ ){
5410 0         0 $curstatus = "doctype";
5411             }
5412 0 0       0 $self->debug( " found complete, back to $curstatus - returning $rtext X\n" ) if( $dval );
5413             }
5414             }
5415              
5416             # Did we get something invalid?
5417 4 100       12 if( $tval == -2 ){
5418 3         4 $retval = -2;
5419             }
5420              
5421             # Try removing the reference here.
5422 4         9 $tobj = undef;
5423             }
5424              
5425             # Add the remaining text to the given subtag.
5426 10 100       39 if( $curstatus =~ /^subtag\-(\d+)$/s ){
5427 6         13 my $offnum = $1;
5428 6         9 my $strlength = length( $str );
5429              
5430 6 100 66     47 if( $retval != -2 && defined( ${$self->{'_curobjs'}}[$offnum] ) && $strlength > 0 ){
  3   100     31  
5431 2         3 my( $tval, $rtext ) = ${$self->{'_curobjs'}}[$offnum]->parse_more( $str );
  2         6  
5432 2         5 $str = $rtext;
5433 2 50       6 if( $tval == -2 ){
5434 2         12 $retval = -2;
5435 2         3 $canparse = 0;
5436             }
5437              
5438             # Was this one complete?
5439 2 50       3 if( ${$self->{'_curobjs'}}[$offnum]->is_complete() ){
  2 50       6  
5440             # It was. Go back to looking for
5441             # additional stuff to add to this
5442             # object.
5443 0         0 $curstatus = "subtag";
5444 0 0       0 $self->debug( " setting8 status to $curstatus - offnum is $offnum X\n" ) if( $dval );
5445             # Are we actually elsewhere?
5446 0 0       0 if( $self->{'_name'} =~ /^\?/ ){
    0          
5447 0         0 $curstatus = "processinginstructions";
5448             }elsif( $self->{'_name'} =~ /^\!/ ){
5449 0         0 $curstatus = "doctype";
5450             }
5451             }elsif( length( $str ) < 2 ){
5452 0         0 $canparse = 0;
5453             }
5454             }
5455             }
5456             }
5457              
5458             # Finally, see if we're closing an end tag.
5459 31 100       96 if( $curstatus eq 'endname' ){
5460             # The name that we're closing is in '_cur_endname', and
5461             # must match name(), eventually. We loop through
5462             # the string looking for '>'.
5463 4         5 my $strlength = length( $str ) - 1;
5464 4         21 my $loop = -1;
5465 4         5 my $stillgoing = 1;
5466 4   100     22 while( $loop < $strlength && $stillgoing ){
5467 16         13 $loop++;
5468 16         30 my $thischar = substr( $str, $loop, 1 );
5469 16 100       39 if( $thischar eq '>' ){
    50          
5470             # Does it match?
5471 4 50       11 if( $self->{'_cur_endname'} eq $self->name() ){
5472 4         5 $curstatus = "complete";
5473 4         4 $retval = 1;
5474             }else{
5475             # Does not match. Invalid XML.
5476 0         0 $retval = -2;
5477             }
5478 4         13 $stillgoing = 0;
5479            
5480             }elsif( $thischar =~ /^\s+$/s ){
5481 0         0 $retval = -2;
5482 0         0 $stillgoing = 0;
5483             }else{
5484 12         50 $self->{'_cur_endname'} .= $thischar;
5485             }
5486             }
5487              
5488             # Get the remaining text.
5489 4         6 $str = substr( $str, $loop + 1 );
5490             }
5491              
5492              
5493             # Digest comments.
5494 31 50       53 if( $curstatus eq 'comment' ){
5495 0 0       0 $self->debug( " - comment with $str X\n" ) if( $dval );
5496             # Throw out stuff except for '-->'. Push back any '-'
5497             # characters, but no more than two.
5498 0 0       0 if( $str =~ /(\-\-)([^>]+.*)$/s ){
    0          
    0          
5499 0 0       0 $self->debug( "doubledash found with no >\n" ) if( $dval );
5500             # '--' must not appear within a comment
5501             # except when closing a comment.
5502             # section 2.5.
5503 0         0 $retval = -2;
5504 0         0 $retstr = $2;
5505 0         0 return( $retval, $retstr );
5506             }elsif( $str =~ /^([^>]+)>(.*)$/s ){
5507 0 0       0 $self->debug( "closing > found\n" ) if( $dval );
5508 0         0 my $doq = $1;
5509 0         0 $str = $2;
5510 0 0       0 if( $doq =~ /\-\-$/ ){
5511 0         0 $curstatus = "complete";
5512 0         0 $retval = 1;
5513             }
5514             }elsif( $str =~ /^(.*)(\-{1,2})$/s ){
5515 0         0 $str = $2;
5516             }else{
5517 0         0 $str = "";
5518             }
5519             }
5520              
5521             # Digest processing instructions
5522 31 100       48 if( $curstatus eq 'processinginstructions' ){
5523             # Throw out stuff except for '?>'. Push back any '?'
5524             # characters, but no more than one.
5525 1 50       6 if( $str =~ /^([^>]+)>(.*)$/s ){
    50          
5526 0         0 my $doq = $1;
5527 0         0 $str = $2;
5528 0 0       0 if( $doq =~ /\?$/ ){
5529 0         0 $curstatus = "complete";
5530             }
5531             }elsif( $str =~ /^(.*)(\?)$/s ){
5532             # Push back '?' characters.
5533 0         0 $str = $2;
5534             }else{
5535 1         3 $str = "";
5536             }
5537             }
5538              
5539 31 100       46 if( $curstatus eq 'complete' ){
5540              
5541             # Do check on the data stuff.
5542 5         11 $self->{'_is_complete'} = 1;
5543 5         5 $pmloop = 0;
5544              
5545             # Do the doctype parsing. This isn't as robust
5546             # as it could be.
5547 5 50       21 if( $self->{'_name'} =~ /^!ENTITY$/ ){
5548 0 0       0 if( $self->{'_doctype'} =~ /^\s*(\S+)\s+(\S+.*)\s*$/ ){
5549 0         0 my $ename = $1;
5550 0         0 my $evalue = $2;
5551 0 0       0 if( $evalue =~ /^\"/ ){
    0          
5552 0         0 $evalue =~ s/^\"//g;
5553 0         0 $evalue =~ s/\"$//g;
5554             }elsif( $evalue =~ /^\'/ ){
5555 0         0 $evalue =~ s/^\'//g;
5556 0         0 $evalue =~ s/\'$//g;
5557             }
5558 0         0 $self->{'_entities'}{"$ename"} = $evalue;
5559             }
5560             }
5561             }else{
5562 26         122 $self->{'_is_complete'} = undef;
5563             }
5564             }
5565              
5566             # Record our current status.
5567 13         22 $self->{'_cur_status'} = $curstatus;
5568              
5569             # Patch up.
5570 13 100 66     39 if( $curstatus eq "complete" && $retval >= 0 ){
5571 5         7 $self->{'_is_complete'} = 1;
5572 5         5 $retval = 1;
5573             }
5574              
5575 13 50       24 $self->debug( " Returning ($curstatus) $retval and $str\n" ) if( $dval );
5576             # print STDERR "$self: Returning ($curstatus) $retval and $str\n" ;
5577 13         44 return( $retval, $str );
5578             }
5579              
5580             =head2 _curstatus
5581              
5582             Returns the current status of the parser on the current object.
5583             Used by the ->connect method, but may be useful in debugging the
5584             parser.
5585              
5586             =cut
5587              
5588             sub _curstatus {
5589              
5590 0     0   0 my $self = shift;
5591              
5592 0         0 my $retval = "";
5593 0 0       0 if( defined( $self->{'_cur_status'} ) ){
    0          
5594 0         0 $retval = $self->{'_cur_status'};
5595             }elsif( defined( $self->{'_curobj'} ) ){
5596 0         0 $retval = $self->{'_curobj'}->_curstatus();
5597             }
5598 0         0 return( $retval );
5599             }
5600              
5601             =head2 encode
5602              
5603             When passed a string, returns the string with appropriate XML escapes
5604             put in place, eg '&' to '&', '<' to '<' etc.
5605              
5606             =cut
5607              
5608             # encode and decode copied from Jabber::NodeFactory;
5609             sub encode {
5610 0     0   0 my $self = shift;
5611              
5612 0         0 my $data = shift;
5613              
5614 0         0 $data =~ s/&/&/g;
5615 0         0 $data =~ s/
5616 0         0 $data =~ s/>/>/g;
5617 0         0 $data =~ s/'/'/g;
5618 0         0 $data =~ s/"/"/g;
5619              
5620 0         0 return $data;
5621              
5622             }
5623              
5624             =head2 decode
5625              
5626             When passed a string, returns the string with the XML escapes reversed,
5627             eg '&' to '&' and so forth.
5628              
5629             =cut
5630              
5631             sub decode {
5632 0     0   0 my $self = shift;
5633              
5634 0         0 my $data = shift;
5635              
5636 0         0 $data =~ s/&/&/g;
5637 0         0 $data =~ s/</
5638 0         0 $data =~ s/>/>/g;
5639 0         0 $data =~ s/'/'/g;
5640 0         0 $data =~ s/"/"/g;
5641              
5642 0         0 return $data;
5643              
5644             }
5645              
5646             =head2 expandEntity
5647              
5648             When passed an '&' escape string, will return the text that it expands
5649             to, based on both a set of predefined escapes, and any escapes that may
5650             have been _previously_ defined within the document. Will return undef
5651             if it cannot expand the string.
5652              
5653             This function is non-intuitive, as it will replace 'amp' with 'amp', but
5654             'pre-defined-escape' with 'text that was declared in the
5655             declaration for pre-defined-escape'. Its prime usage is in the storage
5656             of hopefully-compliant-XML data into the object, and is used as part
5657             of the data verification routines.
5658              
5659             =cut
5660              
5661             sub expandEntity {
5662 3     3   2 my $self = shift;
5663              
5664 3         4 my $retval = undef;
5665              
5666             # XXXX - This ties into the doctype declarations, which are all
5667             # stored right at the parent object (no sense copying them). So
5668             # we go all the way back up to the parent to expand the string, even
5669             # if it is simply 'amp'.
5670 3 50       5 if( defined( $self->parent ) ){
5671 0         0 return( $self->parent->expandEntity( @_ ) );
5672             }else{
5673 3         4 my $arg = shift;
5674              
5675             # 4.6 of XML-core
5676 3         14 my %predefents = ( "lt", "lt",
5677             "gt", "gt",
5678             "amp", "amp",
5679             "apos", "apos",
5680             "quot", "quot",
5681             );
5682              
5683 3 50       7 if( defined( $predefents{"$arg"} ) ){
    0          
    0          
    0          
5684 3         7 $retval = $predefents{"$arg"};
5685              
5686             # WARNING - This does not properly handle Unicode.
5687             }elsif( $arg =~ /^#(\d+)$/ ){
5688             # Numeric reference. Grumble.
5689 0         0 $retval = chr( $1 );
5690             }elsif( $arg =~ /^#x([A-Fa-f0-9])+$/ ){
5691             # Hexadecimal reference.
5692 0         0 $retval = chr( 0x . $arg );
5693              
5694             # Maybe its something that has been defined?
5695             }elsif( defined( $self->{'_entities'}{"$arg"} ) ){
5696 0         0 $retval = $self->{'_entities'}{"$arg"};
5697             }
5698             }
5699              
5700 3         5 return( $retval );
5701             }
5702              
5703             =head2 ConstXMLNS
5704              
5705             This helper function keeps several xmlns strings in one place, to make for
5706             easier (sic) upgrading. It takes one argument, and returns the result of
5707             that argument's lookup.
5708              
5709             =cut
5710              
5711             sub ConstXMLNS {
5712 0     0   0 my $self = shift;
5713              
5714 0         0 my $arg = shift;
5715              
5716             # Copied from XML::Stream
5717 0         0 my %xmlnses = ( 'client', "jabber:client",
5718             'component', "jabber:component:accept",
5719             'server', "jabber:server",
5720             'iq-auth', "http://jabber.org/features/iq-auth",
5721             'stream', "http://etherx.jabber.org/streams",
5722             'xmppstreams', "urn:ietf:params:xml:ns:xmpp-streams",
5723             'xmpp-bind', "urn:ietf:params:xml:ns:xmpp-bind",
5724             'xmpp-sasl', "urn:ietf:params:xml:ns:xmpp-sasl",
5725             'xmpp-session', "urn:ietf:params:xml:ns:xmpp-session",
5726             'xmpp-tls', "urn:ietf:params:xml:ns:xmpp-tls",
5727             );
5728              
5729 0         0 return( $xmlnses{"$arg"} );
5730             }
5731              
5732             =head2 _got_Net_DNS
5733              
5734             Helper function to load Net::DNS into the current namespace.
5735              
5736             =cut
5737              
5738             sub _got_Net_DNS {
5739 0     0   0 my $self = shift;
5740              
5741 0         0 my $retval = 0;
5742              
5743 0         0 eval {
5744 0         0 require Net::DNS;
5745 0         0 $retval++;
5746             };
5747              
5748 0         0 $self->debug( " returning $retval\n" );
5749 0         0 return( $retval );
5750             }
5751              
5752             =head2 _got_Digest_SHA1
5753              
5754             Helper function to load Digest::SHA1 into the current namespace.
5755              
5756             =cut
5757              
5758             sub _got_Digest_SHA1 {
5759 0     0   0 my $self = shift;
5760              
5761 0         0 my $retval = 0;
5762              
5763 0         0 eval {
5764             # Eric Hacker found a problem where these 'use' lines within
5765             # the 'eval' were being acted on on the program load; not
5766             # execution.
5767             # use Digest::SHA1 qw(sha1_hex);
5768 0         0 require Digest::SHA1;
5769 0         0 $retval++;
5770             };
5771              
5772 0         0 $self->debug( " returning $retval\n" );
5773 0         0 return( $retval );
5774             }
5775              
5776             =head2 _got_Digest_MD5
5777              
5778             Helper function to load Digest::MD5 into the current namespace.
5779              
5780             =cut
5781              
5782             sub _got_Digest_MD5 {
5783 0     0   0 my $self = shift;
5784              
5785 0         0 my $retval = 0;
5786              
5787 0         0 eval {
5788 0         0 require Digest::MD5;
5789 0         0 $retval++;
5790             };
5791              
5792 0         0 $self->debug( " returning $retval\n" );
5793 0         0 return( $retval );
5794             }
5795              
5796             =head2 _got_Authen_SASL
5797              
5798             Helper function to load Authen::SASL into the current namespace.
5799              
5800             =cut
5801              
5802             sub _got_Authen_SASL {
5803 0     0   0 my $self = shift;
5804              
5805 0         0 my $retval = 0;
5806              
5807 0         0 eval {
5808 0         0 require Authen::SASL;
5809 0         0 $retval++;
5810             };
5811              
5812 0         0 $self->debug( " returning $retval\n" );
5813 0         0 return( $retval );
5814             }
5815              
5816             =head2 _got_MIME_Base64
5817              
5818             Helper function to load MIME::Base64 into the current namespace.
5819              
5820             =cut
5821              
5822             sub _got_MIME_Base64 {
5823 0     0   0 my $self = shift;
5824              
5825 0         0 my $retval = 0;
5826              
5827 0         0 eval {
5828 0         0 require MIME::Base64;
5829 0         0 $retval++;
5830             };
5831              
5832 0         0 $self->debug( " returning $retval\n" );
5833 0         0 return( $retval );
5834             }
5835              
5836             =head2 _got_IO_Socket_SSL
5837              
5838             Helper function to load IO::Socket::SSL into the current namespace.
5839              
5840             =cut
5841              
5842             sub _got_IO_Socket_SSL {
5843 0     0   0 my $self = shift;
5844              
5845 0         0 my $retval = 0;
5846              
5847 0         0 eval {
5848 0         0 require IO::Socket::SSL;
5849 0         0 $retval++;
5850             };
5851              
5852 0         0 $self->debug( " returning $retval\n" );
5853 0         0 return( $retval );
5854             }
5855              
5856             =head2 debug
5857              
5858             Debug is vor finding de bugs!
5859              
5860             Prints the supplied string, along with some other useful information, to
5861             STDERR, if the initial object was created with the debug flag.
5862              
5863             =cut
5864              
5865             sub debug {
5866 48     48   59 my $self = shift;
5867 48         55 my $arg = shift;
5868              
5869 48         61 chomp( $arg );
5870              
5871             # This check is repeated in some functions, to avoid the
5872             # overhead of invoking ->debug as they are called very frequently.
5873 48         81 my $dval = $self->_check_val( '_debug' );
5874 48 50       82 if( $dval ){
5875 0         0 $dval = $self->{'_debug'};
5876              
5877             # Do this before invoking caller(); saves oodles of time.
5878 0 0       0 if( $dval eq "0" ){
5879 0         0 return( 0 );
5880             }
5881             }else{
5882 48         61 return( 0 );
5883             }
5884              
5885 0         0 my @calledwith = caller(1);
5886 0         0 my $callingname = $calledwith[3];
5887 0         0 my $callingpkg = $calledwith[0];
5888 0         0 my $lineno = $calledwith[2];
5889 0         0 my $selfref = ref( $self );
5890 0 0       0 if( $selfref eq $callingpkg ){
5891 0         0 $callingname =~ s/^$callingpkg\:\://g;
5892             }else{
5893 0         0 $callingname =~ s/^.*://g;
5894             }
5895              
5896 0         0 my $cango = 0;
5897 0 0       0 if( $dval eq "1" ){
    0          
5898 0         0 $cango++;
5899             }elsif( $dval =~ /(^|,)$callingname(,|$)/ ){
5900 0         0 $cango++;
5901             }
5902 0 0       0 print STDERR "DEBUG: $lineno " . time . " $dval:" . $self . "->$callingname: " . $arg . "\n" if( $cango );
5903 0         0 return( $cango );
5904             }
5905              
5906             =head2 version
5907              
5908             Returns the major version of the library.
5909              
5910             =cut
5911              
5912             sub version {
5913 1     1   34 return( $VERSION );
5914             }
5915              
5916             =head1 HISTORY
5917              
5918             September 2005: During implementation of a Jabber-based project,
5919             the author encountered a machine which for political reasons, could not
5920             be upgraded to a version of perl which supported a current version of
5921             various Jabber libraries. After getting irritated with having to build
5922             a completely new standalone perl environment, together with the ~10 meg,
5923             no 11, no 12, no 15 (etc), footprint of libraries required to support
5924             XML::Parser, the desire for a lightweight Jabber library was born.
5925              
5926             December 2005: The author, merrily tossing large chunks of data through
5927             his Jabber servers, discovered that XML::Parser does not deal with
5928             large data sizes in a graceful fashion.
5929              
5930             January 2006: The author completed a version which would, at least, not
5931             barf on most things.
5932              
5933             January through September 2006: Being busy with other things, the author
5934             periodically ran screaming from memory leakage problems similar to
5935             XML::Parser.. Finally, a casual mention in one of the oddest places
5936             lead the author to a good explanation of how Perl does not deal with
5937             circular dependencies.
5938              
5939             =head1 PREREQUISITES / DEPENDENCIES
5940              
5941             IO::Socket::INET, IO::Select . Thats it. Although, if you want encryption
5942             on your connection, SASL support or reasonable garbage collection in various
5943             versions of perl, there are soft dependencies on:
5944              
5945             =over 4
5946              
5947             =item IO::Socket::SSL
5948              
5949             Library for handling SSL/TLS encryption.
5950              
5951             =item MIME::Base64
5952              
5953             This is used for some authentication methods.
5954              
5955             =item Authen::SASL
5956              
5957             SASL magic. Hooray.
5958              
5959             =item Digest::SHA1
5960              
5961             This is used for some authentication methods.
5962              
5963             =item Scalar::Util
5964              
5965             Helps with memory management, saving this library from being caught in
5966             the hell of circular dependencies, which in turn avoids circular
5967             dependencies from making the use of this library hell on memory, which if I
5968             remember avoids the circular dependency hell.
5969              
5970             =back
5971              
5972             =head1 BUGS
5973              
5974             Perl's garbage collection is at times rather dubious. A prime example
5975             is when you have double-linked lists, otherwise known as circular
5976             references. Since both objects refer to each other (in recording
5977             parent <-> child relationships), perl does not clean them up until the
5978             end of the program. Whilst this library does do some tricks to get around
5979             this in newer versions of perl, involving proxy objects and
5980             'weaken' from Scalar::Util , this library may leak memory in older versions
5981             of perl. Invoking ->hidetree on a retrieved object before it falls out
5982             of scope is recommended (the library does this on some internal objects,
5983             perhaps obsessively). Note that you may need to create a copy of a
5984             object via newNodeFromStr/toStr due to this.
5985              
5986             =head1 AUTHOR
5987              
5988             Bruce Campbell, Zerlargal VOF, 2005-7 . See http://cpan.zerlargal.org/Jabber::Lite
5989              
5990             =head1 COPYRIGHT
5991              
5992             Copyright (c) 2005-7 Bruce Campbell. All rights reserved.
5993             This program is free software; you can redistribute it and/or
5994             modify it under the same terms as Perl itself.
5995              
5996             =head1 BLATANT COPYING
5997              
5998             I am primarily a Sysadmin, and like Perl programmers, Sysadmins are lazy
5999             by nature. So, bits of this library were copied from other, existing
6000             libraries as follows:
6001              
6002             encode(), decode() and some function names: Jabber::NodeFactory.
6003             ConstXMLNS(), SASL handling: XML::Stream
6004              
6005             =cut
6006              
6007              
6008             1;