File Coverage

blib/lib/Net/XMPP3/Protocol.pm
Criterion Covered Total %
statement 54 924 5.8
branch 3 306 0.9
condition 0 54 0.0
subroutine 13 124 10.4
pod 2 104 1.9
total 72 1512 4.7


line stmt bran cond sub pod time code
1             ##############################################################################
2             #
3             # This library is free software; you can redistribute it and/or
4             # modify it under the terms of the GNU Library General Public
5             # License as published by the Free Software Foundation; either
6             # version 2 of the License, or (at your option) any later version.
7             #
8             # This library is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11             # Library General Public License for more details.
12             #
13             # You should have received a copy of the GNU Library General Public
14             # License along with this library; if not, write to the
15             # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16             # Boston, MA 02111-1307, USA.
17             #
18             # Copyright (C) 1998-2004 Jabber Software Foundation http://jabber.org/
19             #
20             ##############################################################################
21              
22             package Net::XMPP3::Protocol;
23              
24             =head1 NAME
25              
26             Net::XMPP3::Protocol - XMPP Protocol Module
27              
28             =head1 SYNOPSIS
29              
30             Net::XMPP3::Protocol is a module that provides a developer easy
31             access to the XMPP Instant Messaging protocol. It provides high
32             level functions to the Net::XMPP3 Client object. These functions are
33             inherited by that modules.
34              
35             =head1 DESCRIPTION
36              
37             Protocol.pm seeks to provide enough high level APIs and automation of
38             the low level APIs that writing a XMPP Client in Perl is trivial. For
39             those that wish to work with the low level you can do that too, but
40             those functions are covered in the documentation for each module.
41              
42             Net::XMPP3::Protocol provides functions to login, send and receive
43             messages, set personal information, create a new user account, manage
44             the roster, and disconnect. You can use all or none of the functions,
45             there is no requirement.
46              
47             For more information on how the details for how Net::XMPP3 is written
48             please see the help for Net::XMPP3 itself.
49              
50             For more information on writing a Client see Net::XMPP3::Client.
51              
52             =head2 Modes
53              
54             Several of the functions take a mode argument that let you specify how
55             the function should behave:
56              
57             block - send the packet with an ID, and then block until an answer
58             comes back. You can optionally specify a timeout so that
59             you do not block forever.
60              
61             nonblock - send the packet with an ID, but then return that id and
62             control to the master program. Net::XMPP3 is still
63             tracking this packet, so you must use the CheckID function
64             to tell when it comes in. (This might not be very
65             useful...)
66              
67             passthru - send the packet with an ID, but do NOT register it with
68             Net::XMPP3, then return the ID. This is useful when
69             combined with the XPath function because you can register
70             a one shot function tied to the id you get back.
71              
72              
73             =head2 Basic Functions
74              
75             use Net::XMPP3 qw( Client );
76             $Con = new Net::XMPP3::Client(); # From
77             $status = $Con->Connect(hostname=>"jabber.org"); # Net::XMPP3::Client
78              
79             $Con->SetCallBacks(send=>\&sendCallBack,
80             receive=>\&receiveCallBack,
81             message=>\&messageCallBack,
82             iq=>\&handleTheIQTag);
83              
84             $Con->SetMessageCallBacks(normal=>\&messageNormalCB,
85             chat=>\&messageChatCB);
86              
87             $Con->SetPresenceCallBacks(available=>\&presenceAvailableCB,
88             unavailable=>\&presenceUnavailableCB);
89              
90             $Con->SetIQCallBacks("custom-namespace"=>
91             {
92             get=>\&iqCustomGetCB,
93             set=>\&iqCustomSetCB,
94             result=>\&iqCustomResultCB,
95             },
96             etc...
97             );
98              
99             $Con->SetXPathCallBacks("/message[@type='chat']"=>&messageChatCB,
100             "/message[@type='chat']"=>&otherMessageChatCB,
101             ...
102             );
103              
104             $Con->RemoveXPathCallBacks("/message[@type='chat']"=>&otherMessageChatCB);
105              
106             $Con->SetDirectXPathCallBacks("/anything"=>&anythingCB,
107             "/anotherthing[@foo='bar']"=>&anotherthingFooBarCB,
108             ...
109             );
110              
111             $Con->RemoveDirectXPathCallBacks("/message[@type='chat']"=>&otherMessageChatCB);
112              
113             $error = $Con->GetErrorCode();
114             $Con->SetErrorCode("Timeout limit reached");
115              
116             $status = $Con->Process();
117             $status = $Con->Process(5);
118              
119             $Con->Send($object);
120             $Con->Send("XML");
121              
122             $Con->Send($object,1);
123             $Con->Send("XML",1);
124              
125             $Con->Disconnect();
126              
127             =head2 ID Functions
128              
129             $id = $Con->SendWithID($sendObj);
130             $id = $Con->SendWithID("XML");
131             $receiveObj = $Con->SendAndReceiveWithID($sendObj);
132             $receiveObj = $Con->SendAndReceiveWithID($sendObj,
133             10);
134             $receiveObj = $Con->SendAndReceiveWithID("XML");
135             $receiveObj = $Con->SendAndReceiveWithID("XML",
136             5);
137             $yesno = $Con->ReceivedID($id);
138             $receiveObj = $Con->GetID($id);
139             $receiveObj = $Con->WaitForID($id);
140             $receiveObj = $Con->WaitForID($id,
141             20);
142              
143             =head2 Namespace Functions
144              
145             $Con->AddNamespace(ns=>"foo:bar",
146             tag=>"myfoo",
147             xpath=>{Foo=>{ path=> "foo/text()" },
148             Bar=>{ path=> "bar/text()" },
149             FooBar=>{ type=> "master" },
150             }
151             );
152              
153             =head2 Message Functions
154              
155             $Con->MessageSend(to=>"bob@jabber.org",
156             subject=>"Lunch",
157             body=>"Let's go grab some...\n",
158             thread=>"ABC123",
159             priority=>10);
160              
161             =head2 Presence Functions
162              
163             $Con->PresenceSend();
164             $Con->PresenceSend(type=>"unavailable");
165             $Con->PresenceSend(show=>"away");
166             $Con->PresenceSend(signature=>...signature...);
167              
168             =head2 Subscription Functions
169              
170             $Con->Subscription(type=>"subscribe",
171             to=>"bob@jabber.org");
172              
173             $Con->Subscription(type=>"unsubscribe",
174             to=>"bob@jabber.org");
175              
176             $Con->Subscription(type=>"subscribed",
177             to=>"bob@jabber.org");
178              
179             $Con->Subscription(type=>"unsubscribed",
180             to=>"bob@jabber.org");
181              
182             =head2 Presence DB Functions
183              
184             $Con->PresenceDB();
185              
186             $Con->PresenceDBParse(Net::XMPP3::Presence);
187              
188             $Con->PresenceDBDelete("bob\@jabber.org");
189             $Con->PresenceDBDelete(Net::XMPP3::JID);
190              
191             $Con->PresenceDBClear();
192              
193             $presence = $Con->PresenceDBQuery("bob\@jabber.org");
194             $presence = $Con->PresenceDBQuery(Net::XMPP3::JID);
195              
196             @resources = $Con->PresenceDBResources("bob\@jabber.org");
197             @resources = $Con->PresenceDBResources(Net::XMPP3::JID);
198              
199             =head2 IQ Functions
200              
201             =head2 Auth Functions
202              
203             @result = $Con->AuthSend();
204             @result = $Con->AuthSend(username=>"bob",
205             password=>"bobrulez",
206             resource=>"Bob");
207              
208             =head2 Register Functions
209              
210             %hash = $Con->RegisterRequest();
211             %hash = $Con->RegisterRequest(to=>"transport.jabber.org");
212             %hash = $Con->RegisterRequest(to=>"transport.jabber.org",
213             timeout=>10);
214              
215             @result = $Con->RegisterSend(to=>"somewhere",
216             username=>"newuser",
217             resource=>"New User",
218             password=>"imanewbie",
219             email=>"newguy@new.com",
220             key=>"some key");
221              
222             =head2 Roster Functions
223              
224             $Roster = $Con->Roster();
225              
226             %roster = $Con->RosterParse($iq);
227             %roster = $Con->RosterGet();
228             $Con->RosterRequest();
229             $Con->RosterAdd(jid=>"bob\@jabber.org",
230             name=>"Bob");
231             $Con->RosterRemove(jid=>"bob@jabber.org");
232              
233             =head2 Roster DB Functions
234              
235             $Con->RosterDB();
236              
237             $Con->RosterDBParse(Net::XMPP3::IQ);
238              
239             $Con->RosterDBAdd("bob\@jabber.org",
240             name=>"Bob",
241             groups=>["foo"]
242             );
243              
244             $Con->RosterDBRemove("bob\@jabber.org");
245             $Con->RosterDBRemove(Net::XMPP3::JID);
246              
247             $Con->RosterDBClear();
248              
249             if ($Con->RosterDBExists("bob\@jabber.org")) { ...
250             if ($Con->RosterDBExists(Net::XMPP3::JID)) { ...
251              
252             @jids = $Con->RosterDBJIDs();
253              
254             if ($Con->RosterDBGroupExists("foo")) { ...
255              
256             @groups = $Con->RosterDBGroups();
257              
258             @jids = $Con->RosterDBGroupJIDs("foo");
259              
260             @jids = $Con->RosterDBNonGroupJIDs();
261              
262             %hash = $Con->RosterDBQuery("bob\@jabber.org");
263             %hash = $Con->RosterDBQuery(Net::XMPP3::JID);
264              
265             $value = $Con->RosterDBQuery("bob\@jabber.org","name");
266             $value = $Con->RosterDBQuery(Net::XMPP3::JID,"groups");
267              
268              
269             =head1 METHODS
270              
271             =head2 Basic Functions
272              
273             GetErrorCode() - returns a string that will hopefully contain some
274             useful information about why a function returned
275             an undef to you.
276              
277             SetErrorCode(string) - set a useful error message before you return
278             an undef to the caller.
279              
280             SetCallBacks(message=>function, - sets the callback functions for
281             presence=>function, the top level tags listed. The
282             iq=>function, available tags to look for are
283             send=>function, , , and
284             receive=>function, . If a packet is received
285             update=>function) with an ID which is found in the
286             registerd ID list (see RegisterID
287             below) then it is not sent to
288             these functions, instead it
289             is inserted into a LIST and can
290             be retrieved by some functions
291             we will mention later.
292              
293             send and receive are used to
294             log what XML is sent and received.
295             update is used as way to update
296             your program while waiting for
297             a packet with an ID to be
298             returned (useful for GUI apps).
299              
300             A major change that came with
301             the last release is that the
302             session id is passed to the
303             callback as the first argument.
304             This was done to facilitate
305             the Server module.
306              
307             The next argument depends on
308             which callback you are talking
309             about. message, presence, and iq
310             all get passed in Net::XMPP3
311             objects that match those types.
312             send and receive get passed in
313             strings. update gets passed
314             nothing, not even the session id.
315              
316             If you set the function to undef,
317             then the callback is removed from
318             the list.
319              
320             SetPresenceCallBacks(type=>function - sets the callback functions for
321             etc...) the specified presence type.
322             The function takes types as the
323             main key, and lets you specify
324             a function for each type of
325             packet you can get.
326             "available"
327             "unavailable"
328             "subscribe"
329             "unsubscribe"
330             "subscribed"
331             "unsubscribed"
332             "probe"
333             "error"
334             When it gets a
335             packet it checks the type=''
336             for a defined callback. If
337             there is one then it calls the
338             function with two arguments:
339             the session ID, and the
340             Net::XMPP3::Presence object.
341              
342             If you set the function to
343             undef, then the callback is
344             removed from the list.
345              
346             NOTE: If you use this, which is a cleaner method,
347             then you must *NOT* specify a callback for
348             presence in the SetCallBacks function.
349              
350             Net::XMPP3 defines a few default
351             callbacks for various types:
352              
353             "subscribe" -
354             replies with subscribed
355              
356             "unsubscribe" -
357             replies with unsubscribed
358              
359             "subscribed" -
360             replies with subscribed
361              
362             "unsubscribed" -
363             replies with unsubscribed
364              
365              
366             SetMessageCallBacks(type=>function, - sets the callback functions for
367             etc...) the specified message type. The
368             function takes types as the
369             main key, and lets you specify
370             a function for each type of
371             packet you can get.
372             "normal"
373             "chat"
374             "groupchat"
375             "headline"
376             "error"
377             When it gets a packet
378             it checks the type='' for a
379             defined callback. If there is
380             one then it calls the function
381             with two arguments:
382             the session ID, and the
383             Net::XMPP3::Message object.
384              
385             If you set the function to
386             undef, then the callback is
387             removed from the list.
388              
389             NOTE: If you use this, which is a cleaner method,
390             then you must *NOT* specify a callback for
391             message in the SetCallBacks function.
392              
393              
394             SetIQCallBacks(namespace=>{ - sets the callback functions for
395             get=>function, the specified namespace. The
396             set=>function, function takes namespaces as the
397             result=>function main key, and lets you specify a
398             }, function for each type of packet
399             etc...) you can get.
400             "get"
401             "set"
402             "result"
403             When it gets an packet it
404             checks the type='' and the
405             xmlns='' for a defined callback.
406             If there is one then it calls
407             the function with two arguments:
408             the session ID, and the
409             Net::XMPP3::xxxx object.
410              
411             If you set the function to undef,
412             then the callback is removed from
413             the list.
414              
415             NOTE: If you use this, which is a cleaner method,
416             then you must *NOT* specify a callback for
417             iq in the SetCallBacks function.
418              
419             SetXPathCallBacks(xpath=>function, - registers a callback function
420             etc...) for each xpath specified. If
421             Net::XMPP3 matches the xpath,
422             then it calls the function with
423             two arguments:
424             the session ID, and the
425             Net::XMPP3::Message object.
426              
427             Xpaths are rooted at each
428             packet:
429             /message[@type="chat"]
430             /iq/*[xmlns="jabber:iq:roster"][1]
431             ...
432              
433             RemoveXPathCallBacks(xpath=>function, - unregisters a callback
434             etc...) function for each xpath
435             specified.
436              
437             SetDirectXPathCallBacks(xpath=>function, - registers a callback function
438             etc...) for each xpath specified. If
439             Net::XMPP3 matches the xpath,
440             then it calls the function with
441             two arguments:
442             the session ID, and the
443             XML::Stream::Node object.
444              
445             Xpaths are rooted at each
446             packet:
447             /anything
448             /anotherthing/foo/[1]
449             ...
450              
451             The big difference between this
452             and regular XPathCallBacks is
453             the fact that this passes in
454             the XML directly and not a
455             Net::XMPP3 based object.
456              
457             RemoveDirectXPathCallBacks(xpath=>function, - unregisters a callback
458             etc...) function for each xpath
459             specified.
460              
461             Process(integer) - takes the timeout period as an argument. If no
462             timeout is listed then the function blocks until
463             a packet is received. Otherwise it waits that
464             number of seconds and then exits so your program
465             can continue doing useful things. NOTE: This is
466             important for GUIs. You need to leave time to
467             process GUI commands even if you are waiting for
468             packets. The following are the possible return
469             values, and what they mean:
470              
471             1 - Status ok, data received.
472             0 - Status ok, no data received.
473             undef - Status not ok, stop processing.
474              
475             IMPORTANT: You need to check the output of every
476             Process. If you get an undef then the connection
477             died and you should behave accordingly.
478              
479             Send(object, - takes either a Net::XMPP3::xxxxx object or
480             ignoreActivity) an XML string as an argument and sends it to
481             Send(string, the server. If you set ignoreActivty to 1,
482             ignoreActivity) then the XML::Stream module will not record
483             this packet as couting towards user activity.
484             =head2 ID Functions
485              
486             SendWithID(object) - takes either a Net::XMPP3::xxxxx object or an
487             SendWithID(string) XML string as an argument, adds the next
488             available ID number and sends that packet to
489             the server. Returns the ID number assigned.
490              
491             SendAndReceiveWithID(object, - uses SendWithID and WaitForID to
492             timeout) provide a complete way to send and
493             SendAndReceiveWithID(string, receive packets with IDs. Can take
494             timeout) either a Net::XMPP3::xxxxx object
495             or an XML string. Returns the
496             proper Net::XMPP3::xxxxx object
497             based on the type of packet
498             received. The timeout is passed
499             on to WaitForID, see that function
500             for how the timeout works.
501              
502             ReceivedID(integer) - returns 1 if a packet has been received with
503             specified ID, 0 otherwise.
504              
505             GetID(integer) - returns the proper Net::XMPP3::xxxxx object based
506             on the type of packet received with the specified
507             ID. If the ID has been received the GetID returns
508             0.
509              
510             WaitForID(integer, - blocks until a packet with the ID is received.
511             timeout) Returns the proper Net::XMPP3::xxxxx object
512             based on the type of packet received. If the
513             timeout limit is reached then if the packet
514             does come in, it will be discarded.
515              
516              
517             NOTE: Only officially support ids, so sending a , or
518             with an id is a risk. The server will ignore the
519             id tag and pass it through, so both clients must support the
520             id tag for these functions to be useful.
521              
522             =head2 Namespace Functions
523              
524             AddNamespace(ns=>string, - This function is very complex.
525             tag=>string, It is a little too complex to
526             xpath=>hash) discuss within the confines of
527             this small paragraph. Please
528             refer to the man page for
529             Net::XMPP3::Namespaces for the
530             full documentation on this
531             subject.
532              
533             =head2 Message Functions
534              
535             MessageSend(hash) - takes the hash and passes it to SetMessage in
536             Net::XMPP3::Message (refer there for valid
537             settings). Then it sends the message to the
538             server.
539              
540             =head2 Presence Functions
541              
542             PresenceSend() - no arguments will send an empty
543             PresenceSend(hash, Presence to the server to tell it
544             signature=>string) that you are available. If you
545             provide a hash, then it will pass
546             that hash to the SetPresence()
547             function as defined in the
548             Net::XMPP3::Presence module.
549             Optionally, you can specify a
550             signature and a jabber:x:signed
551             will be placed in the .
552              
553             =head2 Subscription Functions
554              
555             Subscription(hash) - taks the hash and passes it to SetPresence in
556             Net::XMPP3::Presence (refer there for valid
557             settings). Then it sends the subscription to
558             server.
559              
560             The valid types of subscription are:
561              
562             subscribe - subscribe to JID's presence
563             unsubscribe - unsubscribe from JID's presence
564             subscribed - response to a subscribe
565             unsubscribed - response to an unsubscribe
566              
567             =head2 Presence DB Functions
568              
569             PresenceDB() - Tell the object to initialize the callbacks to
570             automatically populate the Presence DB.
571              
572             PresenceDBParse(Net::XMPP3::Presence) - for every presence that you
573             receive pass the Presence
574             object to the DB so that
575             it can track the resources
576             and priorities for you.
577             Returns either the presence
578             passed in, if it not able
579             to parsed for the DB, or the
580             current presence as found by
581             the PresenceDBQuery
582             function.
583              
584             PresenceDBDelete(string|Net::XMPP3::JID) - delete thes JID entry
585             from the DB.
586              
587             PresenceDBClear() - delete all entries in the database.
588              
589             PresenceDBQuery(string|Net::XMPP3::JID) - returns the NX::Presence
590             that was last received for
591             the highest priority of
592             this JID. You can pass
593             it a string or a NX::JID
594             object.
595              
596             PresenceDBResources(string|Net::XMPP3::JID) - returns an array of
597             resources in order
598             from highest priority
599             to lowest.
600              
601             =head2 IQ Functions
602              
603             =head2 Auth Functions
604              
605             AuthSend(username=>string, - takes all of the information and
606             password=>string, builds a Net::XMPP3::IQ::Auth packet.
607             resource=>string) It then sends that packet to the
608             server with an ID and waits for that
609             ID to return. Then it looks in
610             resulting packet and determines if
611             authentication was successful for not.
612             The array returned from AuthSend looks
613             like this:
614             [ type , message ]
615             If type is "ok" then authentication
616             was successful, otherwise message
617             contains a little more detail about the
618             error.
619              
620             =head2 IQ::Register Functions
621              
622             RegisterRequest(to=>string, - send an request to the specified
623             timeout=>int) server/transport, if not specified it
624             RegisterRequest() sends to the current active server.
625             The function returns a hash that
626             contains the required fields. Here
627             is an example of the hash:
628              
629             $hash{fields} - The raw fields from
630             the iq:register.
631             To be used if there
632             is no x:data in the
633             packet.
634             $hash{instructions} - How to fill out
635             the form.
636             $hash{form} - The new dynamic forms.
637              
638             In $hash{form}, the fields that are
639             present are the required fields the
640             server needs.
641              
642             RegisterSend(hash) - takes the contents of the hash and passes it
643             to the SetRegister function in the module
644             Net::XMPP3::Query jabber:iq:register namespace.
645             This function returns an array that looks like
646             this:
647              
648             [ type , message ]
649              
650             If type is "ok" then registration was
651             successful, otherwise message contains a
652             little more detail about the error.
653              
654             =head2 Roster Functions
655              
656             Roster() - returns a Net::XMPP3::Roster object. This will automatically
657             intercept all of the roster and presence packets sent from
658             the server and give you an accurate Roster. For more
659             information please read the man page for Net::XMPP3::Roster.
660              
661             RosterParse(IQ object) - returns a hash that contains the roster
662             parsed into the following data structure:
663              
664             $roster{'bob@jabber.org'}->{name}
665             - Name you stored in the roster
666              
667             $roster{'bob@jabber.org'}->{subscription}
668             - Subscription status
669             (to, from, both, none)
670              
671             $roster{'bob@jabber.org'}->{ask}
672             - The ask status from this user
673             (subscribe, unsubscribe)
674              
675             $roster{'bob@jabber.org'}->{groups}
676             - Array of groups that
677             bob@jabber.org is in
678              
679             RosterGet() - sends an empty Net::XMPP3::IQ::Roster tag to the
680             server so the server will send the Roster to the
681             client. Returns the above hash from RosterParse.
682              
683             RosterRequest() - sends an empty Net::XMPP3::IQ::Roster tag to the
684             server so the server will send the Roster to the
685             client.
686              
687             RosterAdd(hash) - sends a packet asking that the jid be
688             added to the roster. The hash format
689             is defined in the SetItem function
690             in the Net::XMPP3::Query jabber:iq:roster
691             namespace.
692              
693             RosterRemove(hash) - sends a packet asking that the jid be
694             removed from the roster. The hash
695             format is defined in the SetItem function
696             in the Net::XMPP3::Query jabber:iq:roster
697             namespace.
698              
699             =head2 Roster DB Functions
700              
701             RosterDB() - Tell the object to initialize the callbacks to
702             automatically populate the Roster DB. If you do this,
703             then make sure that you call RosterRequest() instead of
704             RosterGet() so that the callbacks can catch it and
705             parse it.
706              
707             RosterDBParse(IQ object) - If you want to manually control the
708             database, then you can pass in all iq
709             packets with jabber:iq:roster queries to
710             this function.
711              
712             RosterDBAdd(jid,hash) - Add a new JID into the roster DB. The JID
713             is either a string, or a Net::XMPP3::JID
714             object. The hash must be the same format as
715             the has returned by RosterParse above, and
716             is the actual hash, not a reference.
717              
718             RosterDBRemove(jid) - Remove a JID from the roster DB. The JID is
719             either a string, or a Net::XMPP3::JID object.
720              
721             RosterDBClear() - Remove all JIDs from the roster DB.
722              
723             RosterDBExists(jid) - return 1 if the JID exists in the roster DB,
724             undef otherwise. The JID is either a string,
725             or a Net::XMPP3::JID object.
726              
727             RosterDBJIDs() - returns a list of Net::XMPP3::JID objects that
728             represents all of the JIDs in the DB.
729              
730             RosterDBGroups() - returns the complete list of roster groups in the
731             roster.
732              
733             RosterDBGroupExists(group) - return 1 if the group is a group in the
734             roster DB, undef otherwise.
735              
736             RosterDBGroupJIDs(group) - returns a list of Net::XMPP3::JID objects
737             that represents all of the JIDs in the
738             specified roster group.
739              
740             RosterDBNonGroupJIDs() - returns a list of Net::XMPP3::JID objects
741             that represents all of the JIDs not in a
742             roster group.
743              
744             RosterDBQuery(jid) - returns a hash containing the data from the
745             roster DB for the specified JID. The JID is
746             either a string, or a Net::XMPP3::JID object.
747             The hash format the same as in RosterParse
748             above.
749              
750             RosterDBQuery(jid,key) - returns the entry from the above hash for
751             the given key. The available keys are:
752             name, ask, subsrcription and groups
753             The JID is either a string, or a
754             Net::XMPP3::JID object.
755              
756              
757             =head1 AUTHOR
758              
759             Ryan Eatmon
760              
761             =head1 COPYRIGHT
762              
763             This module is free software, you can redistribute it and/or modify it
764             under the LGPL.
765              
766             =cut
767              
768 11     11   8444 use Net::XMPP3::Roster;
  11         35  
  11         390  
769 11     11   7521 use Net::XMPP3::PrivacyLists;
  11         34  
  11         364  
770 11     11   80 use strict;
  11         28  
  11         345  
771 11     11   66 use Carp;
  11         27  
  11         744  
772 11     11   60 use vars qw( %XMLNS %NEWOBJECT $SASL_CALLBACK $TLS_CALLBACK );
  11         43  
  11         169178  
773              
774             ##############################################################################
775             # Define the namespaces in an easy/constant manner.
776             #-----------------------------------------------------------------------------
777             # 1.0
778             #-----------------------------------------------------------------------------
779             $XMLNS{'xmppstreams'} = "urn:ietf:params:xml:ns:xmpp-streams";
780             $XMLNS{'xmpp-bind'} = "urn:ietf:params:xml:ns:xmpp-bind";
781             $XMLNS{'xmpp-sasl'} = "urn:ietf:params:xml:ns:xmpp-sasl";
782             $XMLNS{'xmpp-session'} = "urn:ietf:params:xml:ns:xmpp-session";
783             $XMLNS{'xmpp-tls'} = "urn:ietf:params:xml:ns:xmpp-tls";
784             ##############################################################################
785              
786             ##############################################################################
787             # BuildObject takes a root tag and builds the correct object. NEWOBJECT is
788             # the table that maps tag to package. Override these, or provide new ones.
789             #-----------------------------------------------------------------------------
790             $NEWOBJECT{'iq'} = "Net::XMPP3::IQ";
791             $NEWOBJECT{'message'} = "Net::XMPP3::Message";
792             $NEWOBJECT{'presence'} = "Net::XMPP3::Presence";
793             $NEWOBJECT{'jid'} = "Net::XMPP3::JID";
794             ##############################################################################
795              
796 0     0   0 sub _message { shift; my $o; eval "\$o = new $NEWOBJECT{'message'}(\@_);"; return $o; }
  0         0  
  0         0  
  0         0  
797 0     0   0 sub _presence { shift; my $o; eval "\$o = new $NEWOBJECT{'presence'}(\@_);"; return $o; }
  0         0  
  0         0  
  0         0  
798 0     0   0 sub _iq { shift; my $o; eval "\$o = new $NEWOBJECT{'iq'}(\@_);"; return $o; }
  0         0  
  0         0  
  0         0  
799 0     0   0 sub _jid { shift; my $o; eval "\$o = new $NEWOBJECT{'jid'}(\@_);"; return $o; }
  0         0  
  0         0  
  0         0  
800              
801             ###############################################################################
802             #+-----------------------------------------------------------------------------
803             #|
804             #| Base API
805             #|
806             #+-----------------------------------------------------------------------------
807             ###############################################################################
808              
809             ###############################################################################
810             #
811             # GetErrorCode - if you are returned an undef, you can call this function
812             # and hopefully learn more information about the problem.
813             #
814             ###############################################################################
815             sub GetErrorCode
816             {
817 0     0 0 0 my $self = shift;
818 0 0 0     0 return ((exists($self->{ERRORCODE}) && ($self->{ERRORCODE} ne "")) ?
819             $self->{ERRORCODE} :
820             $!
821             );
822             }
823              
824              
825             ###############################################################################
826             #
827             # SetErrorCode - sets the error code so that the caller can find out more
828             # information about the problem
829             #
830             ###############################################################################
831             sub SetErrorCode
832             {
833 0     0 0 0 my $self = shift;
834 0         0 my ($errorcode) = @_;
835 0         0 $self->{ERRORCODE} = $errorcode;
836             }
837              
838              
839             ###############################################################################
840             #
841             # CallBack - Central callback function. If a packet comes back with an ID
842             # and the tag and ID have been registered then the packet is not
843             # returned as normal, instead it is inserted in the LIST and
844             # stored until the user wants to fetch it. If the tag and ID
845             # are not registered the function checks if a callback exists
846             # for this tag, if it does then that callback is called,
847             # otherwise the function drops the packet since it does not know
848             # how to handle it.
849             #
850             ###############################################################################
851             sub CallBack
852             {
853 0     0 0 0 my $self = shift;
854 0         0 my $sid = shift;
855 0         0 my ($object) = @_;
856              
857 0         0 my $tag;
858             my $id;
859 0         0 my $tree;
860              
861 0 0       0 if (ref($object) !~ /^Net::XMPP3/)
862             {
863 0 0 0     0 if ($self->{DEBUG}->GetLevel() >= 1 || exists($self->{CB}->{receive}))
864             {
865 0         0 my $xml = $object->GetXML();
866 0         0 $self->{DEBUG}->Log1("CallBack: sid($sid) received($xml)");
867 0 0       0 &{$self->{CB}->{receive}}($sid,$xml) if exists($self->{CB}->{receive});
  0         0  
868             }
869              
870 0         0 $tag = $object->get_tag();
871 0         0 $id = "";
872 0 0       0 $id = $object->get_attrib("id")
873             if defined($object->get_attrib("id"));
874 0         0 $tree = $object;
875             }
876             else
877             {
878 0         0 $tag = $object->GetTag();
879 0         0 $id = $object->GetID();
880 0         0 $tree = $object->GetTree();
881             }
882              
883 0         0 $self->{DEBUG}->Log1("CallBack: tag($tag)");
884 0 0       0 $self->{DEBUG}->Log1("CallBack: id($id)") if ($id ne "");
885              
886 0         0 my $pass = 1;
887 0 0 0     0 $pass = 0
      0        
      0        
888             if (!exists($self->{CB}->{$tag}) &&
889             !exists($self->{CB}->{XPath}) &&
890             !exists($self->{CB}->{DirectXPath}) &&
891             !$self->CheckID($tag,$id)
892             );
893              
894 0 0       0 if ($pass)
895             {
896 0         0 $self->{DEBUG}->Log1("CallBack: we either want it or were waiting for it.");
897              
898 0 0       0 if (exists($self->{CB}->{DirectXPath}))
899             {
900 0         0 $self->{DEBUG}->Log1("CallBack: check directxpath");
901              
902 0         0 my $direct_pass = 0;
903              
904 0         0 foreach my $xpath (keys(%{$self->{CB}->{DirectXPath}}))
  0         0  
905             {
906 0         0 $self->{DEBUG}->Log1("CallBack: check directxpath($xpath)");
907 0 0       0 if ($object->XPathCheck($xpath))
908             {
909 0         0 foreach my $func (keys(%{$self->{CB}->{DirectXPath}->{$xpath}}))
  0         0  
910             {
911 0         0 $self->{DEBUG}->Log1("CallBack: goto directxpath($xpath) function($func)");
912 0         0 &{$self->{CB}->{DirectXPath}->{$xpath}->{$func}}($sid,$object);
  0         0  
913 0         0 $direct_pass = 1;
914             }
915             }
916             }
917              
918 0 0       0 return if $direct_pass;
919             }
920              
921 0         0 my $NXObject;
922 0 0       0 if (ref($object) !~ /^Net::XMPP3/)
923             {
924 0         0 $NXObject = $self->BuildObject($tag,$object);
925             }
926             else
927             {
928 0         0 $NXObject = $object;
929             }
930              
931 0 0       0 if ($NXObject == -1)
932             {
933 0         0 $self->{DEBUG}->Log1("CallBack: DANGER!! DANGER!! We didn't build a packet! We're all gonna die!!");
934             }
935             else
936             {
937 0 0       0 if ($self->CheckID($tag,$id))
938             {
939 0         0 $self->{DEBUG}->Log1("CallBack: found registry entry: tag($tag) id($id)");
940 0         0 $self->DeregisterID($tag,$id);
941 0 0       0 if ($self->TimedOutID($id))
942             {
943 0         0 $self->{DEBUG}->Log1("CallBack: dropping packet due to timeout");
944 0         0 $self->CleanID($id);
945             }
946             else
947             {
948 0         0 $self->{DEBUG}->Log1("CallBack: they still want it... we still got it...");
949 0         0 $self->GotID($id,$NXObject);
950             }
951             }
952             else
953             {
954 0         0 $self->{DEBUG}->Log1("CallBack: no registry entry");
955              
956 0 0       0 if (exists($self->{CB}->{XPath}))
957             {
958 0         0 $self->{DEBUG}->Log1("CallBack: check xpath");
959              
960 0         0 foreach my $xpath (keys(%{$self->{CB}->{XPath}}))
  0         0  
961             {
962 0 0       0 if ($NXObject->GetTree()->XPathCheck($xpath))
963             {
964 0         0 foreach my $func (keys(%{$self->{CB}->{XPath}->{$xpath}}))
  0         0  
965             {
966 0         0 $self->{DEBUG}->Log1("CallBack: goto xpath($xpath) function($func)");
967 0         0 &{$self->{CB}->{XPath}->{$xpath}->{$func}}($sid,$NXObject);
  0         0  
968             }
969             }
970             }
971             }
972              
973 0 0       0 if (exists($self->{CB}->{$tag}))
974             {
975 0         0 $self->{DEBUG}->Log1("CallBack: goto user function($self->{CB}->{$tag})");
976 0         0 &{$self->{CB}->{$tag}}($sid,$NXObject);
  0         0  
977             }
978             else
979             {
980 0         0 $self->{DEBUG}->Log1("CallBack: no defined function. Dropping packet.");
981             }
982             }
983             }
984             }
985             else
986             {
987 0         0 $self->{DEBUG}->Log1("CallBack: a packet that no one wants... how sad. =(");
988             }
989             }
990              
991              
992             ###############################################################################
993             #
994             # BuildObject - turn the packet into an object.
995             #
996             ###############################################################################
997             sub BuildObject
998             {
999 0     0 0 0 my $self = shift;
1000 0         0 my ($tag,$tree) = @_;
1001              
1002 0         0 my $obj = -1;
1003              
1004 0 0       0 if (exists($NEWOBJECT{$tag}))
1005             {
1006 0         0 $self->{DEBUG}->Log1("BuildObject: tag($tag) package($NEWOBJECT{$tag})");
1007 0         0 eval "\$obj = new $NEWOBJECT{$tag}(\$tree);";
1008             }
1009              
1010 0         0 return $obj;
1011             }
1012              
1013              
1014             ###############################################################################
1015             #
1016             # SetCallBacks - Takes a hash with top level tags to look for as the keys
1017             # and pointers to functions as the values. The functions
1018             # are called and passed the XML::Parser::Tree objects
1019             # generated by XML::Stream.
1020             #
1021             ###############################################################################
1022             sub SetCallBacks
1023             {
1024 1     1 0 4 my $self = shift;
1025 1         6 while($#_ >= 0)
1026             {
1027 3         8 my $func = pop(@_);
1028 3         6 my $tag = pop(@_);
1029 3         23 $self->{DEBUG}->Log1("SetCallBacks: tag($tag) func($func)");
1030 3 50       9 if (defined($func))
1031             {
1032 3         10 $self->{CB}->{$tag} = $func;
1033             }
1034             else
1035             {
1036 0         0 delete($self->{CB}->{$tag});
1037             }
1038 3 50       15 $self->{STREAM}->SetCallBacks(update=>$func) if ($tag eq "update");
1039             }
1040             }
1041              
1042              
1043             ###############################################################################
1044             #
1045             # SetIQCallBacks - define callbacks for the namespaces inside an iq.
1046             #
1047             ###############################################################################
1048             sub SetIQCallBacks
1049             {
1050 0     0 0 0 my $self = shift;
1051              
1052 0         0 while($#_ >= 0)
1053             {
1054 0         0 my $hash = pop(@_);
1055 0         0 my $namespace = pop(@_);
1056              
1057 0         0 foreach my $type (keys(%{$hash}))
  0         0  
1058             {
1059 0         0 $self->{DEBUG}->Log1("SetIQCallBacks: type($type) func($hash->{$type}) ".
1060             "namespace($namespace)");
1061 0 0       0 if (defined($hash->{$type}))
1062             {
1063 0         0 $self->{CB}->{IQns}->{$namespace}->{$type} = $hash->{$type};
1064             }
1065             else
1066             {
1067 0         0 delete($self->{CB}->{IQns}->{$namespace}->{$type});
1068             }
1069             }
1070             }
1071             }
1072              
1073              
1074             ###############################################################################
1075             #
1076             # SetPresenceCallBacks - define callbacks for the different presence packets.
1077             #
1078             ###############################################################################
1079             sub SetPresenceCallBacks
1080             {
1081 1     1 0 2 my $self = shift;
1082 1         7 my (%types) = @_;
1083              
1084 1         5 foreach my $type (keys(%types))
1085             {
1086 4         653 $self->{DEBUG}->Log1("SetPresenceCallBacks: type($type) func($types{$type})");
1087              
1088 4 50       14 if (defined($types{$type}))
1089             {
1090 4         27 $self->{CB}->{Pres}->{$type} = $types{$type};
1091             }
1092             else
1093             {
1094 0         0 delete($self->{CB}->{Pres}->{$type});
1095             }
1096             }
1097             }
1098              
1099              
1100             ###############################################################################
1101             #
1102             # SetMessageCallBacks - define callbacks for the different message packets.
1103             #
1104             ###############################################################################
1105             sub SetMessageCallBacks
1106             {
1107 0     0 0 0 my $self = shift;
1108 0         0 my (%types) = @_;
1109              
1110 0         0 foreach my $type (keys(%types))
1111             {
1112 0         0 $self->{DEBUG}->Log1("SetMessageCallBacks: type($type) func($types{$type})");
1113              
1114 0 0       0 if (defined($types{$type}))
1115             {
1116 0         0 $self->{CB}->{Mess}->{$type} = $types{$type};
1117             }
1118             else
1119             {
1120 0         0 delete($self->{CB}->{Mess}->{$type});
1121             }
1122             }
1123             }
1124              
1125              
1126             ###############################################################################
1127             #
1128             # SetXPathCallBacks - define callbacks for packets based on XPath.
1129             #
1130             ###############################################################################
1131             sub SetXPathCallBacks
1132             {
1133 2     2 0 4 my $self = shift;
1134 2         8 my (%xpaths) = @_;
1135              
1136 2         7 foreach my $xpath (keys(%xpaths))
1137             {
1138 2         17 $self->{DEBUG}->Log1("SetXPathCallBacks: xpath($xpath) func($xpaths{$xpath})");
1139 2         25 $self->{CB}->{XPath}->{$xpath}->{$xpaths{$xpath}} = $xpaths{$xpath};
1140             }
1141             }
1142              
1143              
1144             ###############################################################################
1145             #
1146             # RemoveXPathCallBacks - remove callbacks for packets based on XPath.
1147             #
1148             ###############################################################################
1149             sub RemoveXPathCallBacks
1150             {
1151 0     0 0 0 my $self = shift;
1152 0         0 my (%xpaths) = @_;
1153              
1154 0         0 foreach my $xpath (keys(%xpaths))
1155             {
1156 0         0 $self->{DEBUG}->Log1("RemoveXPathCallBacks: xpath($xpath) func($xpaths{$xpath})");
1157 0         0 delete($self->{CB}->{XPath}->{$xpath}->{$xpaths{$xpath}});
1158 0         0 delete($self->{CB}->{XPath}->{$xpath})
1159 0 0       0 if (scalar(keys(%{$self->{CB}->{XPath}->{$xpath}})) == 0);
1160 0         0 delete($self->{CB}->{XPath})
1161 0 0       0 if (scalar(keys(%{$self->{CB}->{XPath}})) == 0);
1162             }
1163             }
1164              
1165              
1166             ###############################################################################
1167             #
1168             # SetDirectXPathCallBacks - define callbacks for packets based on XPath.
1169             #
1170             ###############################################################################
1171             sub SetDirectXPathCallBacks
1172             {
1173 2     2 0 5 my $self = shift;
1174 2         6 my (%xpaths) = @_;
1175              
1176 2         9 foreach my $xpath (keys(%xpaths))
1177             {
1178 2         18 $self->{DEBUG}->Log1("SetDirectXPathCallBacks: xpath($xpath) func($xpaths{$xpath})");
1179 2         18 $self->{CB}->{DirectXPath}->{$xpath}->{$xpaths{$xpath}} = $xpaths{$xpath};
1180             }
1181             }
1182              
1183              
1184             ###############################################################################
1185             #
1186             # RemoveDirectXPathCallBacks - remove callbacks for packets based on XPath.
1187             #
1188             ###############################################################################
1189             sub RemoveDirectXPathCallBacks
1190             {
1191 0     0 0 0 my $self = shift;
1192 0         0 my (%xpaths) = @_;
1193              
1194 0         0 foreach my $xpath (keys(%xpaths))
1195             {
1196 0         0 $self->{DEBUG}->Log1("RemoveDirectXPathCallBacks: xpath($xpath) func($xpaths{$xpath})");
1197 0         0 delete($self->{CB}->{DirectXPath}->{$xpath}->{$xpaths{$xpath}});
1198 0         0 delete($self->{CB}->{DirectXPath}->{$xpath})
1199 0 0       0 if (scalar(keys(%{$self->{CB}->{DirectXPath}->{$xpath}})) == 0);
1200 0         0 delete($self->{CB}->{DirectXPath})
1201 0 0       0 if (scalar(keys(%{$self->{CB}->{DirectXPath}})) == 0);
1202             }
1203             }
1204              
1205              
1206             ###############################################################################
1207             #
1208             # Send - Takes either XML or a Net::XMPP3::xxxx object and sends that
1209             # packet to the server.
1210             #
1211             ###############################################################################
1212             sub Send
1213             {
1214 0     0 0 0 my $self = shift;
1215 0         0 my $object = shift;
1216 0         0 my $ignoreActivity = shift;
1217 0 0       0 $ignoreActivity = 0 unless defined($ignoreActivity);
1218              
1219 0 0       0 if (ref($object) eq "")
1220             {
1221 0         0 $self->SendXML($object,$ignoreActivity);
1222             }
1223             else
1224             {
1225 0         0 $self->SendXML($object->GetXML(),$ignoreActivity);
1226             }
1227             }
1228              
1229              
1230             ###############################################################################
1231             #
1232             # SendXML - Sends the XML packet to the server
1233             #
1234             ###############################################################################
1235             sub SendXML
1236             {
1237 0     0 0 0 my $self = shift;
1238 0         0 my $xml = shift;
1239 0         0 my $ignoreActivity = shift;
1240 0 0       0 $ignoreActivity = 0 unless defined($ignoreActivity);
1241              
1242 0         0 $self->{DEBUG}->Log1("SendXML: sent($xml)");
1243 0 0       0 &{$self->{CB}->{send}}($self->GetStreamID(),$xml) if exists($self->{CB}->{send});
  0         0  
1244 0         0 $self->{STREAM}->IgnoreActivity($self->GetStreamID(),$ignoreActivity);
1245 0         0 $self->{STREAM}->Send($self->GetStreamID(),$xml);
1246 0         0 $self->{STREAM}->IgnoreActivity($self->GetStreamID(),0);
1247             }
1248              
1249              
1250             ###############################################################################
1251             #
1252             # SendWithID - Take either XML or a Net::XMPP3::xxxx object and send it
1253             # with the next available ID number. Then return that ID so
1254             # the client can track it.
1255             #
1256             ###############################################################################
1257             sub SendWithID
1258             {
1259 0     0 0 0 my $self = shift;
1260 0         0 my ($object) = @_;
1261              
1262             #--------------------------------------------------------------------------
1263             # Take the current XML stream and insert an id attrib at the top level.
1264             #--------------------------------------------------------------------------
1265 0         0 my $id = $self->UniqueID();
1266              
1267 0         0 $self->{DEBUG}->Log1("SendWithID: id($id)");
1268              
1269 0         0 my $xml;
1270 0 0       0 if (ref($object) eq "")
1271             {
1272 0         0 $self->{DEBUG}->Log1("SendWithID: in($object)");
1273 0         0 $xml = $object;
1274 0         0 $xml =~ s/^(\<[^\>]+)(\>)/$1 id\=\'$id\'$2/;
1275 0         0 my ($tag) = ($xml =~ /^\<(\S+)\s/);
1276 0         0 $self->RegisterID($tag,$id);
1277             }
1278             else
1279             {
1280 0         0 $self->{DEBUG}->Log1("SendWithID: in(",$object->GetXML(),")");
1281 0         0 $object->SetID($id);
1282 0         0 $xml = $object->GetXML();
1283 0         0 $self->RegisterID($object->GetTag(),$id);
1284             }
1285 0         0 $self->{DEBUG}->Log1("SendWithID: out($xml)");
1286              
1287             #--------------------------------------------------------------------------
1288             # Send the new XML string.
1289             #--------------------------------------------------------------------------
1290 0         0 $self->SendXML($xml);
1291              
1292             #--------------------------------------------------------------------------
1293             # Return the ID number we just assigned.
1294             #--------------------------------------------------------------------------
1295 0         0 return $id;
1296             }
1297              
1298              
1299             ###############################################################################
1300             #
1301             # UniqueID - Increment and return a new unique ID.
1302             #
1303             ###############################################################################
1304             sub UniqueID
1305             {
1306 0     0 0 0 my $self = shift;
1307              
1308 0         0 my $id_num = $self->{RCVDB}->{currentID};
1309              
1310 0         0 $self->{RCVDB}->{currentID}++;
1311              
1312 0         0 return "netjabber-$id_num";
1313             }
1314              
1315              
1316             ###############################################################################
1317             #
1318             # SendAndReceiveWithID - Take either XML or a Net::XMPP3::xxxxx object and
1319             # send it with the next ID. Then wait for that ID
1320             # to come back and return the response in a
1321             # Net::XMPP3::xxxx object.
1322             #
1323             ###############################################################################
1324             sub SendAndReceiveWithID
1325             {
1326 0     0 0 0 my $self = shift;
1327 0         0 my ($object,$timeout) = @_;
1328 0 0       0 &{$self->{CB}->{startwait}}() if exists($self->{CB}->{startwait});
  0         0  
1329 0         0 $self->{DEBUG}->Log1("SendAndReceiveWithID: object($object)");
1330 0         0 my $id = $self->SendWithID($object);
1331 0         0 $self->{DEBUG}->Log1("SendAndReceiveWithID: sent with id($id)");
1332 0         0 my $packet = $self->WaitForID($id,$timeout);
1333 0 0       0 &{$self->{CB}->{endwait}}() if exists($self->{CB}->{endwait});
  0         0  
1334 0         0 return $packet;
1335             }
1336              
1337              
1338             ###############################################################################
1339             #
1340             # ReceivedID - returns 1 if a packet with the ID has been received, or 0
1341             # if it has not.
1342             #
1343             ###############################################################################
1344             sub ReceivedID
1345             {
1346 0     0 0 0 my $self = shift;
1347 0         0 my ($id) = @_;
1348              
1349 0         0 $self->{DEBUG}->Log1("ReceivedID: id($id)");
1350 0 0       0 return 1 if exists($self->{RCVDB}->{$id});
1351 0         0 $self->{DEBUG}->Log1("ReceivedID: nope...");
1352 0         0 return 0;
1353             }
1354              
1355              
1356             ###############################################################################
1357             #
1358             # GetID - Return the Net::XMPP3::xxxxx object that is stored in the LIST
1359             # that matches the ID if that ID exists. Otherwise return 0.
1360             #
1361             ###############################################################################
1362             sub GetID
1363             {
1364 0     0 0 0 my $self = shift;
1365 0         0 my ($id) = @_;
1366              
1367 0         0 $self->{DEBUG}->Log1("GetID: id($id)");
1368 0 0       0 return $self->{RCVDB}->{$id} if $self->ReceivedID($id);
1369 0         0 $self->{DEBUG}->Log1("GetID: haven't gotten that id yet...");
1370 0         0 return 0;
1371             }
1372              
1373              
1374             ###############################################################################
1375             #
1376             # CleanID - Delete the list entry for this id since we don't want a leak.
1377             #
1378             ###############################################################################
1379             sub CleanID
1380             {
1381 0     0 0 0 my $self = shift;
1382 0         0 my ($id) = @_;
1383              
1384 0         0 $self->{DEBUG}->Log1("CleanID: id($id)");
1385 0         0 delete($self->{RCVDB}->{$id});
1386             }
1387              
1388              
1389             ###############################################################################
1390             #
1391             # WaitForID - Keep looping and calling Process(1) to poll every second
1392             # until the response from the server occurs.
1393             #
1394             ###############################################################################
1395             sub WaitForID
1396             {
1397 0     0 0 0 my $self = shift;
1398 0         0 my ($id,$timeout) = @_;
1399 0 0       0 $timeout = "300" unless defined($timeout);
1400              
1401 0         0 $self->{DEBUG}->Log1("WaitForID: id($id)");
1402 0         0 my $endTime = time + $timeout;
1403 0   0     0 while(!$self->ReceivedID($id) && ($endTime >= time))
1404             {
1405 0         0 $self->{DEBUG}->Log1("WaitForID: haven't gotten it yet... let's wait for more packets");
1406 0 0       0 return unless (defined($self->Process(1)));
1407 0 0       0 &{$self->{CB}->{update}}() if exists($self->{CB}->{update});
  0         0  
1408             }
1409 0 0       0 if (!$self->ReceivedID($id))
1410             {
1411 0         0 $self->TimeoutID($id);
1412 0         0 $self->{DEBUG}->Log1("WaitForID: timed out...");
1413 0         0 return;
1414             }
1415             else
1416             {
1417 0         0 $self->{DEBUG}->Log1("WaitForID: we got it!");
1418 0         0 my $packet = $self->GetID($id);
1419 0         0 $self->CleanID($id);
1420 0         0 return $packet;
1421             }
1422             }
1423              
1424              
1425             ###############################################################################
1426             #
1427             # GotID - Callback to store the Net::XMPP3::xxxxx object in the LIST at
1428             # the ID index. This is a private helper function.
1429             #
1430             ###############################################################################
1431             sub GotID
1432             {
1433 0     0 0 0 my $self = shift;
1434 0         0 my ($id,$object) = @_;
1435              
1436 0         0 $self->{DEBUG}->Log1("GotID: id($id) xml(",$object->GetXML(),")");
1437 0         0 $self->{RCVDB}->{$id} = $object;
1438             }
1439              
1440              
1441             ###############################################################################
1442             #
1443             # CheckID - Checks the ID registry if this tag and ID have been registered.
1444             # 0 = no, 1 = yes
1445             #
1446             ###############################################################################
1447             sub CheckID
1448             {
1449 0     0 0 0 my $self = shift;
1450 0         0 my ($tag,$id) = @_;
1451 0 0       0 $id = "" unless defined($id);
1452              
1453 0         0 $self->{DEBUG}->Log1("CheckID: tag($tag) id($id)");
1454 0 0       0 return 0 if ($id eq "");
1455 0         0 $self->{DEBUG}->Log1("CheckID: we have that here somewhere...");
1456 0         0 return exists($self->{IDRegistry}->{$tag}->{$id});
1457             }
1458              
1459              
1460             ###############################################################################
1461             #
1462             # TimeoutID - Timeout the tag and ID in the registry so that the CallBack
1463             # can know what to put in the ID list and what to pass on.
1464             #
1465             ###############################################################################
1466             sub TimeoutID
1467             {
1468 0     0 0 0 my $self = shift;
1469 0         0 my ($id) = @_;
1470              
1471 0         0 $self->{DEBUG}->Log1("TimeoutID: id($id)");
1472 0         0 $self->{RCVDB}->{$id} = 0;
1473             }
1474              
1475              
1476             ###############################################################################
1477             #
1478             # TimedOutID - Timeout the tag and ID in the registry so that the CallBack
1479             # can know what to put in the ID list and what to pass on.
1480             #
1481             ###############################################################################
1482             sub TimedOutID
1483             {
1484 0     0 0 0 my $self = shift;
1485 0         0 my ($id) = @_;
1486              
1487 0   0     0 return (exists($self->{RCVDB}->{$id}) && ($self->{RCVDB}->{$id} == 0));
1488             }
1489              
1490              
1491             ###############################################################################
1492             #
1493             # RegisterID - Register the tag and ID in the registry so that the CallBack
1494             # can know what to put in the ID list and what to pass on.
1495             #
1496             ###############################################################################
1497             sub RegisterID
1498             {
1499 0     0 0 0 my $self = shift;
1500 0         0 my ($tag,$id) = @_;
1501              
1502 0         0 $self->{DEBUG}->Log1("RegisterID: tag($tag) id($id)");
1503 0         0 $self->{IDRegistry}->{$tag}->{$id} = 1;
1504             }
1505              
1506              
1507             ###############################################################################
1508             #
1509             # DeregisterID - Delete the tag and ID in the registry so that the CallBack
1510             # can knows that it has been received.
1511             #
1512             ###############################################################################
1513             sub DeregisterID
1514             {
1515 0     0 0 0 my $self = shift;
1516 0         0 my ($tag,$id) = @_;
1517              
1518 0         0 $self->{DEBUG}->Log1("DeregisterID: tag($tag) id($id)");
1519 0         0 delete($self->{IDRegistry}->{$tag}->{$id});
1520             }
1521              
1522              
1523             ###############################################################################
1524             #
1525             # AddNamespace - Add a custom namespace into the mix.
1526             #
1527             ###############################################################################
1528             sub AddNamespace
1529             {
1530 0     0 0 0 my $self = shift;
1531 0         0 &Net::XMPP3::Namespaces::add_ns(@_);
1532             }
1533              
1534              
1535             ###############################################################################
1536             #
1537             # MessageSend - Takes the same hash that Net::XMPP3::Message->SetMessage
1538             # takes and sends the message to the server.
1539             #
1540             ###############################################################################
1541             sub MessageSend
1542             {
1543 0     0 0 0 my $self = shift;
1544              
1545 0         0 my $mess = $self->_message();
1546 0         0 $mess->SetMessage(@_);
1547 0         0 $self->Send($mess);
1548             }
1549              
1550              
1551             ##############################################################################
1552             #
1553             # PresenceDB - initialize the module to use the presence database
1554             #
1555             ##############################################################################
1556             sub PresenceDB
1557             {
1558 0     0 0 0 my $self = shift;
1559              
1560 0     0   0 $self->SetXPathCallBacks('/presence'=>sub{ shift; $self->PresenceDBParse(@_) });
  0         0  
  0         0  
1561             }
1562              
1563              
1564             ###############################################################################
1565             #
1566             # PresenceDBParse - adds the presence information to the Presence DB so
1567             # you can keep track of the current state of the JID and
1568             # all of it's resources.
1569             #
1570             ###############################################################################
1571             sub PresenceDBParse
1572             {
1573 0     0 0 0 my $self = shift;
1574 0         0 my ($presence) = @_;
1575              
1576 0         0 $self->{DEBUG}->Log4("PresenceDBParse: pres(",$presence->GetXML(),")");
1577              
1578 0         0 my $type = $presence->GetType();
1579 0 0       0 $type = "" unless defined($type);
1580 0 0 0     0 return $presence unless (($type eq "") ||
      0        
1581             ($type eq "available") ||
1582             ($type eq "unavailable"));
1583              
1584 0         0 my $fromJID = $presence->GetFrom("jid");
1585 0         0 my $fromID = $fromJID->GetJID();
1586 0 0       0 $fromID = "" unless defined($fromID);
1587 0         0 my $resource = $fromJID->GetResource();
1588 0 0       0 $resource = " " unless ($resource ne "");
1589 0         0 my $priority = $presence->GetPriority();
1590 0 0       0 $priority = 0 unless defined($priority);
1591              
1592 0         0 $self->{DEBUG}->Log1("PresenceDBParse: fromJID(",$fromJID->GetJID("full"),") resource($resource) priority($priority) type($type)");
1593 0         0 $self->{DEBUG}->Log2("PresenceDBParse: xml(",$presence->GetXML(),")");
1594              
1595 0 0       0 if (exists($self->{PRESENCEDB}->{$fromID}))
1596             {
1597 0         0 my $oldPriority = $self->{PRESENCEDB}->{$fromID}->{resources}->{$resource};
1598 0 0       0 $oldPriority = "" unless defined($oldPriority);
1599              
1600 0         0 my $loc = 0;
1601 0         0 foreach my $index (0..$#{$self->{PRESENCEDB}->{$fromID}->{priorities}->{$oldPriority}})
  0         0  
1602             {
1603 0 0       0 $loc = $index
1604             if ($self->{PRESENCEDB}->{$fromID}->{priorities}->{$oldPriority}->[$index]->{resource} eq $resource);
1605             }
1606 0         0 splice(@{$self->{PRESENCEDB}->{$fromID}->{priorities}->{$oldPriority}},$loc,1);
  0         0  
1607 0         0 delete($self->{PRESENCEDB}->{$fromID}->{resources}->{$resource});
1608 0         0 delete($self->{PRESENCEDB}->{$fromID}->{priorities}->{$oldPriority})
1609             if (exists($self->{PRESENCEDB}->{$fromID}->{priorities}->{$oldPriority}) &&
1610 0 0 0     0 ($#{$self->{PRESENCEDB}->{$fromID}->{priorities}->{$oldPriority}} == -1));
1611 0         0 delete($self->{PRESENCEDB}->{$fromID})
1612 0 0       0 if (scalar(keys(%{$self->{PRESENCEDB}->{$fromID}})) == 0);
1613              
1614 0         0 $self->{DEBUG}->Log1("PresenceDBParse: remove ",$fromJID->GetJID("full")," from the DB");
1615             }
1616              
1617 0 0 0     0 if (($type eq "") || ($type eq "available"))
1618             {
1619 0         0 my $loc = -1;
1620 0         0 foreach my $index (0..$#{$self->{PRESENCEDB}->{$fromID}->{priorities}->{$priority}}) {
  0         0  
1621 0 0       0 $loc = $index
1622             if ($self->{PRESENCEDB}->{$fromID}->{priorities}->{$priority}->[$index]->{resource} eq $resource);
1623             }
1624 0 0       0 $loc = $#{$self->{PRESENCEDB}->{$fromID}->{priorities}->{$priority}}+1
  0         0  
1625             if ($loc == -1);
1626 0         0 $self->{PRESENCEDB}->{$fromID}->{resources}->{$resource} = $priority;
1627 0         0 $self->{PRESENCEDB}->{$fromID}->{priorities}->{$priority}->[$loc]->{presence} =
1628             $presence;
1629 0         0 $self->{PRESENCEDB}->{$fromID}->{priorities}->{$priority}->[$loc]->{resource} =
1630             $resource;
1631              
1632 0         0 $self->{DEBUG}->Log1("PresenceDBParse: add ",$fromJID->GetJID("full")," to the DB");
1633             }
1634              
1635 0         0 my $currentPresence = $self->PresenceDBQuery($fromJID);
1636 0 0       0 return (defined($currentPresence) ? $currentPresence : $presence);
1637             }
1638              
1639              
1640             ###############################################################################
1641             #
1642             # PresenceDBDelete - delete the JID from the DB completely.
1643             #
1644             ###############################################################################
1645             sub PresenceDBDelete
1646             {
1647 0     0 0 0 my $self = shift;
1648 0         0 my ($jid) = @_;
1649              
1650 0         0 my $indexJID = $jid;
1651 0 0       0 $indexJID = $jid->GetJID() if $jid->isa("Net::XMPP3::JID");
1652              
1653 0 0       0 return if !exists($self->{PRESENCEDB}->{$indexJID});
1654 0         0 delete($self->{PRESENCEDB}->{$indexJID});
1655 0         0 $self->{DEBUG}->Log1("PresenceDBDelete: delete ",$indexJID," from the DB");
1656             }
1657              
1658              
1659             ###############################################################################
1660             #
1661             # PresenceDBClear - delete all of the JIDs from the DB completely.
1662             #
1663             ###############################################################################
1664             sub PresenceDBClear
1665             {
1666 0     0 0 0 my $self = shift;
1667              
1668 0         0 $self->{DEBUG}->Log1("PresenceDBClear: clearing the database");
1669 0         0 foreach my $indexJID (keys(%{$self->{PRESENCEDB}}))
  0         0  
1670             {
1671 0         0 $self->{DEBUG}->Log3("PresenceDBClear: deleting ",$indexJID," from the DB");
1672 0         0 delete($self->{PRESENCEDB}->{$indexJID});
1673             }
1674 0         0 $self->{DEBUG}->Log3("PresenceDBClear: database is empty");
1675             }
1676              
1677              
1678             ###############################################################################
1679             #
1680             # PresenceDBQuery - retrieve the last Net::XMPP3::Presence received with
1681             # the highest priority.
1682             #
1683             ###############################################################################
1684             sub PresenceDBQuery
1685             {
1686 0     0 0 0 my $self = shift;
1687 0         0 my ($jid) = @_;
1688              
1689 0         0 my $indexJID = $jid;
1690 0 0       0 $indexJID = $jid->GetJID() if $jid->isa("Net::XMPP3::JID");
1691              
1692 0 0       0 return if !exists($self->{PRESENCEDB}->{$indexJID});
1693 0 0       0 return if (scalar(keys(%{$self->{PRESENCEDB}->{$indexJID}->{priorities}})) == 0);
  0         0  
1694              
1695 0         0 my $highPriority =
1696 0         0 (sort {$b cmp $a} keys(%{$self->{PRESENCEDB}->{$indexJID}->{priorities}}))[0];
  0         0  
1697              
1698 0         0 return $self->{PRESENCEDB}->{$indexJID}->{priorities}->{$highPriority}->[0]->{presence};
1699             }
1700              
1701              
1702             ###############################################################################
1703             #
1704             # PresenceDBResources - returns a list of the resources from highest
1705             # priority to lowest.
1706             #
1707             ###############################################################################
1708             sub PresenceDBResources
1709             {
1710 0     0 0 0 my $self = shift;
1711 0         0 my ($jid) = @_;
1712              
1713 0         0 my $indexJID = $jid;
1714 0 0       0 $indexJID = $jid->GetJID() if $jid->isa("Net::XMPP3::JID");
1715              
1716 0         0 my @resources;
1717              
1718 0 0       0 return if !exists($self->{PRESENCEDB}->{$indexJID});
1719              
1720 0         0 foreach my $priority (sort {$b cmp $a} keys(%{$self->{PRESENCEDB}->{$indexJID}->{priorities}}))
  0         0  
  0         0  
1721             {
1722 0         0 foreach my $index (0..$#{$self->{PRESENCEDB}->{$indexJID}->{priorities}->{$priority}})
  0         0  
1723             {
1724 0 0       0 next if ($self->{PRESENCEDB}->{$indexJID}->{priorities}->{$priority}->[$index]->{resource} eq " ");
1725 0         0 push(@resources,$self->{PRESENCEDB}->{$indexJID}->{priorities}->{$priority}->[$index]->{resource});
1726             }
1727             }
1728 0         0 return @resources;
1729             }
1730              
1731              
1732             ###############################################################################
1733             #
1734             # PresenceSend - Sends a presence tag to announce your availability
1735             #
1736             ###############################################################################
1737             sub PresenceSend
1738             {
1739 0     0 0 0 my $self = shift;
1740 0         0 my %args;
1741 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
1742              
1743 0 0       0 $args{ignoreactivity} = 0 unless exists($args{ignoreactivity});
1744 0         0 my $ignoreActivity = delete($args{ignoreactivity});
1745              
1746 0         0 my $presence = $self->_presence();
1747              
1748 0         0 $presence->SetPresence(%args);
1749 0         0 $self->Send($presence,$ignoreActivity);
1750 0         0 return $presence;
1751             }
1752              
1753              
1754             ###############################################################################
1755             #
1756             # PresenceProbe - Sends a presence probe to the server
1757             #
1758             ###############################################################################
1759             sub PresenceProbe
1760             {
1761 0     0 0 0 my $self = shift;
1762 0         0 my %args;
1763 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
1764 0         0 delete($args{type});
1765              
1766 0         0 my $presence = $self->_presence();
1767 0         0 $presence->SetPresence(type=>"probe",
1768             %args);
1769 0         0 $self->Send($presence);
1770             }
1771              
1772              
1773             ###############################################################################
1774             #
1775             # Subscription - Sends a presence tag to perform the subscription on the
1776             # specified JID.
1777             #
1778             ###############################################################################
1779             sub Subscription
1780             {
1781 0     0 1 0 my $self = shift;
1782              
1783 0         0 my $presence = $self->_presence();
1784 0         0 $presence->SetPresence(@_);
1785 0         0 $self->Send($presence);
1786             }
1787              
1788              
1789             ###############################################################################
1790             #
1791             # AuthSend - This is a self contained function to send a login iq tag with
1792             # an id. Then wait for a reply what the same id to come back
1793             # and tell the caller what the result was.
1794             #
1795             ###############################################################################
1796             sub AuthSend
1797             {
1798 0     0 0 0 my $self = shift;
1799 0         0 my %args;
1800 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
1801              
1802 0 0       0 carp("AuthSend requires a username arguement")
1803             unless exists($args{username});
1804 0 0       0 carp("AuthSend requires a password arguement")
1805             unless exists($args{password});
1806              
1807 0 0       0 if($self->{STREAM}->GetStreamFeature($self->GetStreamID(),"xmpp-sasl"))
1808             {
1809 0         0 return $self->AuthSASL(%args);
1810             }
1811              
1812 0         0 return $self->AuthIQAuth(%args);
1813             }
1814              
1815              
1816             ###############################################################################
1817             #
1818             # AuthIQAuth - Try and auth using jabber:iq:auth, the old Jabber way of
1819             # authenticating.
1820             #
1821             ###############################################################################
1822             sub AuthIQAuth
1823             {
1824 0     0 0 0 my $self = shift;
1825 0         0 my %args;
1826 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
1827              
1828 0         0 $self->{DEBUG}->Log1("AuthIQAuth: old school auth");
1829              
1830 0 0       0 carp("AuthIQAuth requires a resource arguement")
1831             unless exists($args{resource});
1832              
1833 0         0 my $authType = "digest";
1834 0         0 my $token;
1835             my $sequence;
1836              
1837             #--------------------------------------------------------------------------
1838             # First let's ask the sever what all is available in terms of auth types.
1839             # If we get an error, then all we can do is digest or plain.
1840             #--------------------------------------------------------------------------
1841 0         0 my $iqAuth = $self->_iq();
1842 0         0 $iqAuth->SetIQ(type=>"get");
1843 0         0 my $iqAuthQuery = $iqAuth->NewChild("jabber:iq:auth");
1844 0         0 $iqAuthQuery->SetUsername($args{username});
1845 0         0 $iqAuth = $self->SendAndReceiveWithID($iqAuth);
1846              
1847 0 0       0 return unless defined($iqAuth);
1848 0 0       0 return ( $iqAuth->GetErrorCode() , $iqAuth->GetError() )
1849             if ($iqAuth->GetType() eq "error");
1850              
1851 0 0       0 if ($iqAuth->GetType() eq "error")
1852             {
1853 0         0 $authType = "digest";
1854             }
1855             else
1856             {
1857 0         0 $iqAuthQuery = $iqAuth->GetChild();
1858 0 0       0 $authType = "plain" if $iqAuthQuery->DefinedPassword();
1859 0 0       0 $authType = "digest" if $iqAuthQuery->DefinedDigest();
1860 0 0 0     0 $authType = "zerok" if ($iqAuthQuery->DefinedSequence() &&
1861             $iqAuthQuery->DefinedToken());
1862 0 0       0 $token = $iqAuthQuery->GetToken() if ($authType eq "zerok");
1863 0 0       0 $sequence = $iqAuthQuery->GetSequence() if ($authType eq "zerok");
1864             }
1865              
1866 0         0 $self->{DEBUG}->Log1("AuthIQAuth: authType($authType)");
1867              
1868 0         0 delete($args{digest});
1869 0         0 delete($args{type});
1870              
1871             #--------------------------------------------------------------------------
1872             # 0k authenticaion (http://core.jabber.org/0k.html)
1873             #
1874             # Tell the server that we want to connect this way, the server sends back
1875             # a token and a sequence number. We take that token + the password and
1876             # SHA1 it. Then we SHA1 it sequence number more times and send that hash.
1877             # The server SHA1s that hash one more time and compares it to the hash it
1878             # stored last time. IF they match, we are in and it stores the hash we sent
1879             # for the next time and decreases the sequence number, else, no go.
1880             #--------------------------------------------------------------------------
1881 0 0       0 if ($authType eq "zerok")
1882             {
1883 0         0 my $hashA = Digest::SHA1::sha1_hex(delete($args{password}));
1884 0         0 $args{hash} = Digest::SHA1::sha1_hex($hashA.$token);
1885              
1886 0         0 for (1..$sequence)
1887             {
1888 0         0 $args{hash} = Digest::SHA1::sha1_hex($args{hash});
1889             }
1890             }
1891              
1892             #--------------------------------------------------------------------------
1893             # If we have access to the SHA-1 digest algorithm then let's use it.
1894             # Remove the password from the hash, create the digest, and put the
1895             # digest in the hash instead.
1896             #
1897             # Note: Concat the Session ID and the password and then digest that
1898             # string to get the server to accept the digest.
1899             #--------------------------------------------------------------------------
1900 0 0       0 if ($authType eq "digest")
1901             {
1902 0         0 my $password = delete($args{password});
1903 0         0 $args{digest} = Digest::SHA1::sha1_hex($self->GetStreamID().$password);
1904             }
1905              
1906             #--------------------------------------------------------------------------
1907             # Create a Net::XMPP3::IQ object to send to the server
1908             #--------------------------------------------------------------------------
1909 0         0 my $iqLogin = $self->_iq();
1910 0         0 $iqLogin->SetIQ(type=>"set");
1911 0         0 my $iqLoginQuery = $iqLogin->NewChild("jabber:iq:auth");
1912 0         0 $iqLoginQuery->SetAuth(%args);
1913              
1914             #--------------------------------------------------------------------------
1915             # Send the IQ with the next available ID and wait for a reply with that
1916             # id to be received. Then grab the IQ reply.
1917             #--------------------------------------------------------------------------
1918 0         0 $iqLogin = $self->SendAndReceiveWithID($iqLogin);
1919              
1920             #--------------------------------------------------------------------------
1921             # From the reply IQ determine if we were successful or not. If yes then
1922             # return "". If no then return error string from the reply.
1923             #--------------------------------------------------------------------------
1924 0 0       0 return unless defined($iqLogin);
1925 0 0       0 return ( $iqLogin->GetErrorCode() , $iqLogin->GetError() )
1926             if ($iqLogin->GetType() eq "error");
1927              
1928 0         0 $self->{DEBUG}->Log1("AuthIQAuth: we authed!");
1929              
1930 0         0 return ("ok","");
1931             }
1932              
1933              
1934             ###############################################################################
1935             #
1936             # AuthSASL - Try and auth using SASL, the XMPP preferred way of authenticating.
1937             #
1938             ###############################################################################
1939             sub AuthSASL
1940             {
1941 0     0 0 0 my $self = shift;
1942 0         0 my %args;
1943 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
1944              
1945 0         0 $self->{DEBUG}->Log1("AuthSASL: shiney new auth");
1946              
1947 0 0       0 carp("AuthSASL requires a username arguement")
1948             unless exists($args{username});
1949 0 0       0 carp("AuthSASL requires a password arguement")
1950             unless exists($args{password});
1951              
1952 0 0       0 $args{resource} = "" unless exists($args{resource});
1953              
1954             #-------------------------------------------------------------------------
1955             # Create the SASLClient on our end
1956             #-------------------------------------------------------------------------
1957 0         0 my $sid = $self->{SESSION}->{id};
1958 0 0       0 my $xhost = defined $args{host}? $args{host} : $self->{SERVER}->{hostname};
1959 0         0 my $status =
1960             SASLClient($self->{STREAM}, $sid,
1961             $args{username},
1962             $args{password},
1963             $xhost
1964             );
1965              
1966 0 0       0 $args{timeout} = "120" unless exists($args{timeout});
1967              
1968             #-------------------------------------------------------------------------
1969             # While we haven't timed out, keep waiting for the SASLClient to finish
1970             #-------------------------------------------------------------------------
1971 0         0 my $endTime = time + $args{timeout};
1972 0   0     0 while(!$self->{STREAM}->SASLClientDone($sid) && ($endTime >= time))
1973             {
1974 0         0 $self->{DEBUG}->Log1("AuthSASL: haven't authed yet... let's wait.");
1975 0 0       0 return unless (defined($self->Process(1)));
1976 0 0       0 &{$self->{CB}->{update}}() if exists($self->{CB}->{update});
  0         0  
1977             }
1978              
1979             #-------------------------------------------------------------------------
1980             # The loop finished... but was it done?
1981             #-------------------------------------------------------------------------
1982 0 0       0 if (!$self->{STREAM}->SASLClientDone($sid))
1983             {
1984 0         0 $self->{DEBUG}->Log1("AuthSASL: timed out...");
1985 0         0 return( "system","SASL timed out authenticating");
1986             }
1987              
1988             #-------------------------------------------------------------------------
1989             # Ok, it was done... but did we auth?
1990             #-------------------------------------------------------------------------
1991 0 0       0 if (!$self->{STREAM}->SASLClientAuthed($sid))
1992             {
1993 0         0 $self->{DEBUG}->Log1("AuthSASL: Authentication failed.");
1994 0         0 return ( "error", $self->{STREAM}->SASLClientError($sid));
1995             }
1996              
1997             #-------------------------------------------------------------------------
1998             # Phew... Restart the per XMPP
1999             #-------------------------------------------------------------------------
2000 0         0 $self->{DEBUG}->Log1("AuthSASL: We authed!");
2001 0         0 $self->{SESSION} = $self->{STREAM}->OpenStream($sid);
2002 0         0 $sid = $self->{SESSION}->{id};
2003              
2004 0         0 $self->{DEBUG}->Log1("AuthSASL: We got a new session. sid($sid)");
2005              
2006             #-------------------------------------------------------------------------
2007             # Look in the new set of s and see if xmpp-bind was
2008             # offered.
2009             #-------------------------------------------------------------------------
2010 0         0 my $bind = $self->{STREAM}->GetStreamFeature($sid,"xmpp-bind");
2011 0 0       0 if ($bind)
2012             {
2013 0         0 $self->{DEBUG}->Log1("AuthSASL: Binding to resource");
2014 0         0 $self->BindResource($args{resource});
2015             }
2016              
2017             #-------------------------------------------------------------------------
2018             # Look in the new set of s and see if xmpp-session was
2019             # offered.
2020             #-------------------------------------------------------------------------
2021 0         0 my $session = $self->{STREAM}->GetStreamFeature($sid,"xmpp-session");
2022 0 0       0 if ($session)
2023             {
2024 0         0 $self->{DEBUG}->Log1("AuthSASL: Starting session");
2025 0         0 $self->StartSession();
2026             }
2027              
2028 0         0 return ("ok","");
2029             }
2030              
2031              
2032             ##############################################################################
2033             #
2034             # BindResource - bind to a resource
2035             #
2036             ##############################################################################
2037             sub BindResource
2038             {
2039 0     0 0 0 my $self = shift;
2040 0         0 my $resource = shift;
2041              
2042 0         0 $self->{DEBUG}->Log2("BindResource: Binding to resource");
2043 0         0 my $iq = $self->_iq();
2044              
2045 0         0 $iq->SetIQ(type=>"set");
2046 0         0 my $bind = $iq->NewChild(&ConstXMLNS("xmpp-bind"));
2047              
2048 0 0 0     0 if (defined($resource) && ($resource ne ""))
2049             {
2050 0         0 $self->{DEBUG}->Log2("BindResource: resource($resource)");
2051 0         0 $bind->SetBind(resource=>$resource);
2052             }
2053              
2054 0         0 my $result = $self->SendAndReceiveWithID($iq);
2055             }
2056              
2057              
2058             ##############################################################################
2059             #
2060             # StartSession - Initialize a session
2061             #
2062             ##############################################################################
2063             sub StartSession
2064             {
2065 0     0 0 0 my $self = shift;
2066              
2067 0         0 my $iq = $self->_iq();
2068              
2069 0         0 $iq->SetIQ(type=>"set");
2070 0         0 my $session = $iq->NewChild(&ConstXMLNS("xmpp-session"));
2071              
2072 0         0 my $result = $self->SendAndReceiveWithID($iq);
2073             }
2074              
2075              
2076             ##############################################################################
2077             #
2078             # PrivacyLists - Initialize a Net::XMPP3::PrivacyLists object and return it.
2079             #
2080             ##############################################################################
2081             sub PrivacyLists
2082             {
2083 0     0 0 0 my $self = shift;
2084              
2085 0         0 return new Net::XMPP3::PrivacyLists(connection=>$self);
2086             }
2087              
2088              
2089             ##############################################################################
2090             #
2091             # PrivacyListsGet - Sends an empty IQ to the server to request that the user's
2092             # Privacy Lists be sent to them. Returns the iq packet
2093             # of the result.
2094             #
2095             ##############################################################################
2096             sub PrivacyListsGet
2097             {
2098 0     0 0 0 my $self = shift;
2099 0         0 my %args;
2100 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
2101              
2102 0         0 my $iq = $self->_iq();
2103 0         0 $iq->SetIQ(type=>"get");
2104 0         0 my $query = $iq->NewChild("jabber:iq:privacy");
2105              
2106 0 0       0 if (exists($args{list}))
2107             {
2108 0         0 $query->AddList(name=>$args{list});
2109             }
2110              
2111 0         0 $iq = $self->SendAndReceiveWithID($iq);
2112 0 0       0 return unless defined($iq);
2113              
2114 0         0 return $iq;
2115             }
2116              
2117              
2118             ##############################################################################
2119             #
2120             # PrivacyListsRequest - Sends an empty IQ to the server to request that the
2121             # user's privacy lists be sent to them, and return to
2122             # let the user's program handle parsing the return packet.
2123             #
2124             ##############################################################################
2125             sub PrivacyListsRequest
2126             {
2127 0     0 0 0 my $self = shift;
2128 0         0 my %args;
2129 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
2130              
2131 0         0 my $iq = $self->_iq();
2132 0         0 $iq->SetIQ(type=>"get");
2133 0         0 my $query = $iq->NewChild("jabber:iq:privacy");
2134              
2135 0 0       0 if (exists($args{list}))
2136             {
2137 0         0 $query->AddList(name=>$args{list});
2138             }
2139              
2140 0         0 $self->Send($iq);
2141             }
2142              
2143              
2144             ##############################################################################
2145             #
2146             # PrivacyListsSet - Sends an empty IQ to the server to request that the
2147             # user's privacy lists be sent to them, and return to
2148             # let the user's program handle parsing the return packet.
2149             #
2150             ##############################################################################
2151             sub PrivacyListsSet
2152             {
2153 0     0 0 0 my $self = shift;
2154 0         0 my %args;
2155 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
2156              
2157 0         0 my $iq = $self->_iq();
2158 0         0 $iq->SetIQ(type=>"set");
2159 0         0 my $query = $iq->NewChild("jabber:iq:privacy");
2160              
2161             #XXX error check that there is a list
2162 0         0 my $list = $query->AddList(name=>$args{list});
2163              
2164 0         0 foreach my $item (@{$args{items}})
  0         0  
2165             {
2166 0         0 $list->AddItem(%{$item});
  0         0  
2167             }
2168              
2169 0         0 $iq = $self->SendAndReceiveWithID($iq);
2170 0 0       0 return unless defined($iq);
2171              
2172 0 0       0 return if $iq->DefinedError();
2173              
2174 0         0 return 1;
2175             }
2176              
2177              
2178             ###############################################################################
2179             #
2180             # RegisterRequest - This is a self contained function to send an iq tag
2181             # an id that requests the target address to send back
2182             # the required fields. It waits for a reply what the
2183             # same id to come back and tell the caller what the
2184             # fields are.
2185             #
2186             ###############################################################################
2187             sub RegisterRequest
2188             {
2189 0     0 0 0 my $self = shift;
2190 0         0 my %args;
2191 0         0 $args{mode} = "block";
2192 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
2193              
2194 0 0       0 my $timeout = exists($args{timeout}) ? delete($args{timeout}) : undef;
2195              
2196             #--------------------------------------------------------------------------
2197             # Create a Net::XMPP3::IQ object to send to the server
2198             #--------------------------------------------------------------------------
2199 0         0 my $iq = $self->_iq();
2200 0 0       0 $iq->SetIQ(to=>delete($args{to})) if exists($args{to});
2201 0         0 $iq->SetIQ(type=>"get");
2202 0         0 my $query = $iq->NewChild("jabber:iq:register");
2203              
2204             #--------------------------------------------------------------------------
2205             # Send the IQ with the next available ID and wait for a reply with that
2206             # id to be received. Then grab the IQ reply.
2207             #--------------------------------------------------------------------------
2208 0 0       0 if ($args{mode} eq "passthru")
2209             {
2210 0         0 my $id = $self->UniqueID();
2211 0         0 $iq->SetIQ(id=>$id);
2212 0         0 $self->Send($iq);
2213 0         0 return $id;
2214             }
2215              
2216 0 0       0 return $self->SendWithID($iq) if ($args{mode} eq "nonblock");
2217              
2218 0         0 $iq = $self->SendAndReceiveWithID($iq,$timeout);
2219              
2220             #--------------------------------------------------------------------------
2221             # Check if there was an error.
2222             #--------------------------------------------------------------------------
2223 0 0       0 return unless defined($iq);
2224 0 0       0 if ($iq->GetType() eq "error")
2225             {
2226 0         0 $self->SetErrorCode($iq->GetErrorCode().": ".$iq->GetError());
2227 0         0 return;
2228             }
2229              
2230 0         0 my %register;
2231             #--------------------------------------------------------------------------
2232             # From the reply IQ determine what fields are required and send a hash
2233             # back with the fields and any values that are already defined (like key)
2234             #--------------------------------------------------------------------------
2235 0         0 $query = $iq->GetChild();
2236 0         0 $register{fields} = { $query->GetRegister() };
2237              
2238 0         0 return %register;
2239             }
2240              
2241              
2242             ###############################################################################
2243             #
2244             # RegisterSend - This is a self contained function to send a registration
2245             # iq tag with an id. Then wait for a reply what the same
2246             # id to come back and tell the caller what the result was.
2247             #
2248             ###############################################################################
2249             sub RegisterSend
2250             {
2251 0     0 0 0 my $self = shift;
2252 0         0 my %args;
2253 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
2254              
2255             #--------------------------------------------------------------------------
2256             # Create a Net::XMPP3::IQ object to send to the server
2257             #--------------------------------------------------------------------------
2258 0         0 my $iq = $self->_iq();
2259 0 0       0 $iq->SetIQ(to=>delete($args{to})) if exists($args{to});
2260 0         0 $iq->SetIQ(type=>"set");
2261 0         0 my $iqRegister = $iq->NewChild("jabber:iq:register");
2262 0         0 $iqRegister->SetRegister(%args);
2263              
2264             #--------------------------------------------------------------------------
2265             # Send the IQ with the next available ID and wait for a reply with that
2266             # id to be received. Then grab the IQ reply.
2267             #--------------------------------------------------------------------------
2268 0         0 $iq = $self->SendAndReceiveWithID($iq);
2269              
2270             #--------------------------------------------------------------------------
2271             # From the reply IQ determine if we were successful or not. If yes then
2272             # return "". If no then return error string from the reply.
2273             #--------------------------------------------------------------------------
2274 0 0       0 return unless defined($iq);
2275 0 0       0 return ( $iq->GetErrorCode() , $iq->GetError() )
2276             if ($iq->GetType() eq "error");
2277 0         0 return ("ok","");
2278             }
2279              
2280              
2281             ##############################################################################
2282             #
2283             # RosterAdd - Takes the Jabber ID of the user to add to their Roster and
2284             # sends the IQ packet to the server.
2285             #
2286             ##############################################################################
2287             sub RosterAdd
2288             {
2289 0     0 0 0 my $self = shift;
2290 0         0 my %args;
2291 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
2292              
2293 0         0 my $iq = $self->_iq();
2294 0         0 $iq->SetIQ(type=>"set");
2295 0         0 my $roster = $iq->NewChild("jabber:iq:roster");
2296 0         0 my $item = $roster->AddItem();
2297 0         0 $item->SetItem(%args);
2298              
2299 0         0 $self->{DEBUG}->Log1("RosterAdd: xml(",$iq->GetXML(),")");
2300 0         0 $self->Send($iq);
2301             }
2302              
2303              
2304             ##############################################################################
2305             #
2306             # RosterAdd - Takes the Jabber ID of the user to remove from their Roster
2307             # and sends the IQ packet to the server.
2308             #
2309             ##############################################################################
2310             sub RosterRemove
2311             {
2312 0     0 0 0 my $self = shift;
2313 0         0 my %args;
2314 0         0 while($#_ >= 0) { $args{ lc pop(@_) } = pop(@_); }
  0         0  
2315 0         0 delete($args{subscription});
2316              
2317 0         0 my $iq = $self->_iq();
2318 0         0 $iq->SetIQ(type=>"set");
2319 0         0 my $roster = $iq->NewChild("jabber:iq:roster");
2320 0         0 my $item = $roster->AddItem();
2321 0         0 $item->SetItem(%args,
2322             subscription=>"remove");
2323 0         0 $self->Send($iq);
2324             }
2325              
2326              
2327             ##############################################################################
2328             #
2329             # RosterParse - Returns a hash of roster items.
2330             #
2331             ##############################################################################
2332             sub RosterParse
2333             {
2334 0     0 0 0 my $self = shift;
2335 0         0 my($iq) = @_;
2336              
2337 0         0 my %roster;
2338 0         0 my $query = $iq->GetChild("jabber:iq:roster");
2339              
2340 0 0       0 if (defined($query)) #$query->GetXMLNS() eq "jabber:iq:roster")
2341             {
2342 0         0 my @items = $query->GetItems();
2343              
2344 0         0 foreach my $item (@items)
2345             {
2346 0         0 my $jid = $item->GetJID();
2347 0         0 $roster{$jid}->{name} = $item->GetName();
2348 0         0 $roster{$jid}->{subscription} = $item->GetSubscription();
2349 0         0 $roster{$jid}->{ask} = $item->GetAsk();
2350 0         0 $roster{$jid}->{groups} = [ $item->GetGroup() ];
2351             }
2352             }
2353              
2354 0         0 return %roster;
2355             }
2356              
2357              
2358             ##############################################################################
2359             #
2360             # RosterGet - Sends an empty IQ to the server to request that the user's
2361             # Roster be sent to them. Returns a hash of roster items.
2362             #
2363             ##############################################################################
2364             sub RosterGet
2365             {
2366 0     0 0 0 my $self = shift;
2367              
2368 0         0 my $iq = $self->_iq();
2369 0         0 $iq->SetIQ(type=>"get");
2370 0         0 my $query = $iq->NewChild("jabber:iq:roster");
2371              
2372 0         0 $iq = $self->SendAndReceiveWithID($iq);
2373              
2374 0 0       0 return unless defined($iq);
2375              
2376 0         0 return $self->RosterParse($iq);
2377             }
2378              
2379              
2380             ##############################################################################
2381             #
2382             # RosterRequest - Sends an empty IQ to the server to request that the user's
2383             # Roster be sent to them, and return to let the user's program
2384             # handle parsing the return packet.
2385             #
2386             ##############################################################################
2387             sub RosterRequest
2388             {
2389 0     0 0 0 my $self = shift;
2390              
2391 0         0 my $iq = $self->_iq();
2392 0         0 $iq->SetIQ(type=>"get");
2393 0         0 my $query = $iq->NewChild("jabber:iq:roster");
2394              
2395 0         0 $self->Send($iq);
2396             }
2397              
2398              
2399             ##############################################################################
2400             #
2401             # Roster - Initialize a Net::XMPP3::Roster object and return it.
2402             #
2403             ##############################################################################
2404             sub Roster
2405             {
2406 0     0 1 0 my $self = shift;
2407              
2408 0         0 return new Net::XMPP3::Roster(connection=>$self);
2409             }
2410              
2411              
2412             ##############################################################################
2413             #
2414             # RosterDB - initialize the module to use the roster database
2415             #
2416             ##############################################################################
2417             sub RosterDB
2418             {
2419 0     0 0 0 my $self = shift;
2420              
2421 0     0   0 $self->SetXPathCallBacks('/iq[@type="result" or @type="set"]/query[@xmlns="jabber:iq:roster"]'=>sub{ shift; $self->RosterDBParse(@_) });
  0         0  
  0         0  
2422             }
2423              
2424              
2425             ##############################################################################
2426             #
2427             # RosterDBAdd - adds the entry to the Roster DB.
2428             #
2429             ##############################################################################
2430             sub RosterDBAdd
2431             {
2432 0     0 0 0 my $self = shift;
2433 0         0 my ($jid,%item) = @_;
2434              
2435 0         0 $self->{ROSTERDB}->{JIDS}->{$jid} = \%item;
2436              
2437 0         0 foreach my $group (@{$item{groups}})
  0         0  
2438             {
2439 0         0 $self->{ROSTERDB}->{GROUPS}->{$group}->{$jid} = 1;
2440             }
2441             }
2442              
2443              
2444             ###############################################################################
2445             #
2446             # RosterDBClear - delete all of the JIDs from the DB completely.
2447             #
2448             ###############################################################################
2449             sub RosterDBClear
2450             {
2451 0     0 0 0 my $self = shift;
2452              
2453 0         0 $self->{DEBUG}->Log1("RosterDBClear: clearing the database");
2454 0         0 foreach my $jid ($self->RosterDBJIDs())
2455             {
2456 0         0 $self->{DEBUG}->Log3("RosterDBClear: deleting ",$jid->GetJID()," from the DB");
2457 0         0 $self->RosterDBRemove($jid);
2458             }
2459 0         0 $self->{DEBUG}->Log3("RosterDBClear: database is empty");
2460             }
2461              
2462              
2463             ##############################################################################
2464             #
2465             # RosterDBExists - allows you to query if the JID exists in the Roster DB.
2466             #
2467             ##############################################################################
2468             sub RosterDBExists
2469             {
2470 0     0 0 0 my $self = shift;
2471 0         0 my ($jid) = @_;
2472              
2473 0 0       0 if ($jid->isa("Net::XMPP3::JID"))
2474             {
2475 0         0 $jid = $jid->GetJID();
2476             }
2477              
2478 0 0       0 return unless exists($self->{ROSTERDB});
2479 0 0       0 return unless exists($self->{ROSTERDB}->{JIDS});
2480 0 0       0 return unless exists($self->{ROSTERDB}->{JIDS}->{$jid});
2481 0         0 return 1;
2482             }
2483              
2484              
2485             ##############################################################################
2486             #
2487             # RosterDBGroupExists - allows you to query if the group exists in the Roster
2488             # DB.
2489             #
2490             ##############################################################################
2491             sub RosterDBGroupExists
2492             {
2493 0     0 0 0 my $self = shift;
2494 0         0 my ($group) = @_;
2495              
2496 0 0       0 return unless exists($self->{ROSTERDB});
2497 0 0       0 return unless exists($self->{ROSTERDB}->{GROUPS});
2498 0 0       0 return unless exists($self->{ROSTERDB}->{GROUPS}->{$group});
2499 0         0 return 1;
2500             }
2501              
2502              
2503             ##############################################################################
2504             #
2505             # RosterDBGroupJIDs - returns a list of the current groups in your roster.
2506             #
2507             ##############################################################################
2508             sub RosterDBGroupJIDs
2509             {
2510 0     0 0 0 my $self = shift;
2511 0         0 my $group = shift;
2512              
2513 0 0       0 return unless $self->RosterDBGroupExists($group);
2514 0         0 my @jids;
2515 0         0 foreach my $jid (keys(%{$self->{ROSTERDB}->{GROUPS}->{$group}}))
  0         0  
2516             {
2517 0         0 push(@jids,$self->_jid($jid));
2518             }
2519 0         0 return @jids;
2520             }
2521              
2522              
2523             ##############################################################################
2524             #
2525             # RosterDBGroups - returns a list of the current groups in your roster.
2526             #
2527             ##############################################################################
2528             sub RosterDBGroups
2529             {
2530 0     0 0 0 my $self = shift;
2531              
2532 0 0       0 return () unless exists($self->{ROSTERDB}->{GROUPS});
2533 0 0       0 return () if (scalar(keys(%{$self->{ROSTERDB}->{GROUPS}})) == 0);
  0         0  
2534 0         0 return keys(%{$self->{ROSTERDB}->{GROUPS}});
  0         0  
2535             }
2536              
2537              
2538             ##############################################################################
2539             #
2540             # RosterDBJIDs - returns a list of all of the JIDs in your roster.
2541             #
2542             ##############################################################################
2543             sub RosterDBJIDs
2544             {
2545 0     0 0 0 my $self = shift;
2546 0         0 my $group = shift;
2547              
2548 0         0 my @jids;
2549              
2550 0 0       0 return () unless exists($self->{ROSTERDB});
2551 0 0       0 return () unless exists($self->{ROSTERDB}->{JIDS});
2552 0         0 foreach my $jid (keys(%{$self->{ROSTERDB}->{JIDS}}))
  0         0  
2553             {
2554 0         0 push(@jids,$self->_jid($jid));
2555             }
2556 0         0 return @jids;
2557             }
2558              
2559              
2560             ##############################################################################
2561             #
2562             # RosterDBNonGroupJIDs - returns a list of the JIDs not in a group.
2563             #
2564             ##############################################################################
2565             sub RosterDBNonGroupJIDs
2566             {
2567 0     0 0 0 my $self = shift;
2568 0         0 my $group = shift;
2569              
2570 0         0 my @jids;
2571              
2572 0 0       0 return () unless exists($self->{ROSTERDB});
2573 0 0       0 return () unless exists($self->{ROSTERDB}->{JIDS});
2574 0         0 foreach my $jid (keys(%{$self->{ROSTERDB}->{JIDS}}))
  0         0  
2575             {
2576 0         0 next if (exists($self->{ROSTERDB}->{JIDS}->{$jid}->{groups}) &&
2577 0 0 0     0 ($#{$self->{ROSTERDB}->{JIDS}->{$jid}->{groups}} > -1));
2578              
2579 0         0 push(@jids,$self->_jid($jid));
2580             }
2581 0         0 return @jids;
2582             }
2583              
2584              
2585             ##############################################################################
2586             #
2587             # RosterDBParse - takes an iq packet that containsa roster, parses it, and puts
2588             # the roster into the Roster DB.
2589             #
2590             ##############################################################################
2591             sub RosterDBParse
2592             {
2593 0     0 0 0 my $self = shift;
2594 0         0 my ($iq) = @_;
2595              
2596             #print "RosterDBParse: iq(",$iq->GetXML(),")\n";
2597              
2598 0         0 my $type = $iq->GetType();
2599 0 0 0     0 return unless (($type eq "set") || ($type eq "result"));
2600              
2601 0         0 my %newroster = $self->RosterParse($iq);
2602              
2603 0         0 $self->RosterDBProcessParsed(%newroster);
2604             }
2605              
2606              
2607             ##############################################################################
2608             #
2609             # RosterDBProcessParsed - takes a parsed roster and puts it into the Roster DB.
2610             #
2611             ##############################################################################
2612             sub RosterDBProcessParsed
2613             {
2614 0     0 0 0 my $self = shift;
2615 0         0 my (%roster) = @_;
2616              
2617 0         0 foreach my $jid (keys(%roster))
2618             {
2619 0         0 $self->RosterDBRemove($jid);
2620              
2621 0 0       0 if ($roster{$jid}->{subscription} ne "remove")
2622             {
2623 0         0 $self->RosterDBAdd($jid, %{$roster{$jid}} );
  0         0  
2624             }
2625             }
2626             }
2627              
2628              
2629             ##############################################################################
2630             #
2631             # RosterDBQuery - allows you to get one of the pieces of info from the
2632             # Roster DB.
2633             #
2634             ##############################################################################
2635             sub RosterDBQuery
2636             {
2637 0     0 0 0 my $self = shift;
2638 0         0 my $jid = shift;
2639 0         0 my $key = shift;
2640              
2641 0 0       0 if ($jid->isa("Net::XMPP3::JID"))
2642             {
2643 0         0 $jid = $jid->GetJID();
2644             }
2645              
2646 0 0       0 return unless $self->RosterDBExists($jid);
2647 0 0       0 if (defined($key))
2648             {
2649 0 0       0 return unless exists($self->{ROSTERDB}->{JIDS}->{$jid}->{$key});
2650 0         0 return $self->{ROSTERDB}->{JIDS}->{$jid}->{$key};
2651             }
2652 0         0 return %{$self->{ROSTERDB}->{JIDS}->{$jid}};
  0         0  
2653             }
2654              
2655              
2656             ##############################################################################
2657             #
2658             # RosterDBRemove - removes the JID from the Roster DB.
2659             #
2660             ##############################################################################
2661             sub RosterDBRemove
2662             {
2663 0     0 0 0 my $self = shift;
2664 0         0 my ($jid) = @_;
2665              
2666 0 0       0 if ($self->RosterDBExists($jid))
2667             {
2668 0 0       0 if (defined($self->RosterDBQuery($jid,"groups")))
2669             {
2670 0         0 foreach my $group (@{$self->RosterDBQuery($jid,"groups")})
  0         0  
2671             {
2672 0         0 delete($self->{ROSTERDB}->{GROUPS}->{$group}->{$jid});
2673 0         0 delete($self->{ROSTERDB}->{GROUPS}->{$group})
2674 0 0       0 if (scalar(keys(%{$self->{ROSTERDB}->{GROUPS}->{$group}})) == 0);
2675 0         0 delete($self->{ROSTERDB}->{GROUPS})
2676 0 0       0 if (scalar(keys(%{$self->{ROSTERDB}->{GROUPS}})) == 0);
2677             }
2678             }
2679              
2680 0         0 delete($self->{ROSTERDB}->{JIDS}->{$jid});
2681             }
2682             }
2683              
2684              
2685              
2686              
2687             ##############################################################################
2688             #+----------------------------------------------------------------------------
2689             #|
2690             #| TLS Functions
2691             #|
2692             #+----------------------------------------------------------------------------
2693             ##############################################################################
2694              
2695             ##############################################################################
2696             #
2697             # TLSInit - Initialize the connection for TLS.
2698             #
2699             ##############################################################################
2700             sub TLSInit
2701             {
2702 1     1 0 2 my $self = shift;
2703              
2704 1     0   6 $TLS_CALLBACK = sub{ $self->ProcessTLSStanza( @_ ) };
  0         0  
2705 1         7 $self->SetDirectXPathCallBacks('/[@xmlns="'.&ConstXMLNS("xmpp-tls").'"]'=>$TLS_CALLBACK);
2706             }
2707              
2708              
2709             ##############################################################################
2710             #
2711             # ProcessTLSStanza - process a TLS based packet.
2712             #
2713             ##############################################################################
2714             sub ProcessTLSStanza
2715             {
2716 0     0 0 0 my $self = shift;
2717 0         0 my $sid = shift;
2718 0         0 my $node = shift;
2719              
2720 0         0 my $tag = &XML::Stream::XPath($node,"name()");
2721              
2722 0 0       0 if ($tag eq "failure")
2723             {
2724 0         0 $self->TLSClientFailure($node);
2725             }
2726              
2727 0 0       0 if ($tag eq "proceed")
2728             {
2729 0         0 $self->TLSClientProceed($node);
2730             }
2731             }
2732              
2733              
2734             ##############################################################################
2735             #
2736             # TLSStart - client function to have the socket start TLS.
2737             #
2738             ##############################################################################
2739             sub TLSStart
2740             {
2741 0     0 0 0 my $self = shift;
2742 0         0 my $timeout = shift;
2743 0 0       0 $timeout = 120 unless defined($timeout);
2744 0 0       0 $timeout = 120 if ($timeout eq "");
2745              
2746 0         0 $self->TLSSendStartTLS();
2747              
2748 0         0 my $endTime = time + $timeout;
2749 0   0     0 while(!$self->TLSClientDone() && ($endTime >= time))
2750             {
2751 0         0 $self->Process();
2752             }
2753              
2754 0 0       0 if (!$self->TLSClientSecure())
2755             {
2756 0         0 return;
2757             }
2758              
2759 0         0 $self->RestartStream($timeout);
2760             }
2761              
2762              
2763             ##############################################################################
2764             #
2765             # TLSClientProceed - handle a packet.
2766             #
2767             ##############################################################################
2768             sub TLSClientProceed
2769             {
2770 0     0 0 0 my $self = shift;
2771 0         0 my $node = shift;
2772              
2773 0         0 my ($status,$message) = $self->{STREAM}->StartTLS($self->GetStreamID());
2774              
2775 0 0       0 if ($status)
2776             {
2777 0         0 $self->{TLS}->{done} = 1;
2778 0         0 $self->{TLS}->{secure} = 1;
2779             }
2780             else
2781             {
2782 0         0 $self->{TLS}->{done} = 1;
2783 0         0 $self->{TLS}->{error} = $message;
2784             }
2785              
2786 0         0 $self->RemoveDirectXPathCallBacks('/[@xmlns="'.&ConstXMLNS("xmpp-tls").'"]'=>$TLS_CALLBACK);
2787             }
2788              
2789              
2790             ##############################################################################
2791             #
2792             # TLSClientSecure - return 1 if the socket is secure, 0 otherwise.
2793             #
2794             ##############################################################################
2795             sub TLSClientSecure
2796             {
2797 0     0 0 0 my $self = shift;
2798              
2799 0         0 return $self->{TLS}->{secure};
2800             }
2801              
2802              
2803             ##############################################################################
2804             #
2805             # TLSClientDone - return 1 if the TLS process is done
2806             #
2807             ##############################################################################
2808             sub TLSClientDone
2809             {
2810 0     0 0 0 my $self = shift;
2811              
2812 0         0 return $self->{TLS}->{done};
2813             }
2814              
2815              
2816             ##############################################################################
2817             #
2818             # TLSClientError - return the TLS error if any
2819             #
2820             ##############################################################################
2821             sub TLSClientError
2822             {
2823 0     0 0 0 my $self = shift;
2824              
2825 0         0 return $self->{TLS}->{error};
2826             }
2827              
2828              
2829             ##############################################################################
2830             #
2831             # TLSClientFailure - handle a
2832             #
2833             ##############################################################################
2834             sub TLSClientFailure
2835             {
2836 0     0 0 0 my $self = shift;
2837 0         0 my $node = shift;
2838              
2839 0         0 my $type = &XML::Stream::XPath($node,"*/name()");
2840              
2841 0         0 $self->{TLS}->{error} = $type;
2842 0         0 $self->{TLS}->{done} = 1;
2843             }
2844              
2845              
2846             ##############################################################################
2847             #
2848             # TLSSendFailure - Send a in the TLS namespace
2849             #
2850             ##############################################################################
2851             sub TLSSendFailure
2852             {
2853 0     0 0 0 my $self = shift;
2854 0         0 my $type = shift;
2855              
2856 0         0 $self->Send("<${type}/>");
2857             }
2858              
2859              
2860             ##############################################################################
2861             #
2862             # TLSSendStartTLS - send a in the TLS namespace.
2863             #
2864             ##############################################################################
2865             sub TLSSendStartTLS
2866             {
2867 0     0 0 0 my $self = shift;
2868              
2869 0         0 $self->Send("");
2870             }
2871              
2872              
2873              
2874              
2875             ##############################################################################
2876             #+----------------------------------------------------------------------------
2877             #|
2878             #| SASL Functions
2879             #|
2880             #+----------------------------------------------------------------------------
2881             ##############################################################################
2882              
2883             ##############################################################################
2884             #
2885             # SASLInit - Initialize the connection for SASL.
2886             #
2887             ##############################################################################
2888             sub SASLInit
2889             {
2890 1     1 0 4 my $self = shift;
2891              
2892 1     0   14 $SASL_CALLBACK = sub{ $self->ProcessSASLStanza( @_ ) };
  0         0  
2893 1         4 $self->SetDirectXPathCallBacks('/[@xmlns="'.&ConstXMLNS("xmpp-sasl").'"]'=> $SASL_CALLBACK);
2894             }
2895              
2896              
2897             ##############################################################################
2898             #
2899             # ProcessSASLStanza - process a SASL based packet.
2900             #
2901             ##############################################################################
2902             sub ProcessSASLStanza
2903             {
2904 0     0 0 0 my $self = shift;
2905 0         0 my $sid = shift;
2906 0         0 my $node = shift;
2907              
2908 0         0 my $tag = &XML::Stream::XPath($node,"name()");
2909              
2910 0 0       0 if ($tag eq "challenge")
2911             {
2912 0         0 $self->SASLAnswerChallenge($node);
2913             }
2914              
2915 0 0       0 if ($tag eq "failure")
2916             {
2917 0         0 $self->SASLClientFailure($node);
2918             }
2919              
2920 0 0       0 if ($tag eq "success")
2921             {
2922 0         0 $self->SASLClientSuccess($node);
2923             }
2924             }
2925              
2926              
2927             ##############################################################################
2928             #
2929             # SASLAnswerChallenge - when we get a we need to do the grunt
2930             # work to return a .
2931             #
2932             ##############################################################################
2933             sub SASLAnswerChallenge
2934             {
2935 0     0 0 0 my $self = shift;
2936 0         0 my $node = shift;
2937              
2938 0         0 my $challenge64 = &XML::Stream::XPath($node,"text()");
2939 0         0 my $challenge = MIME::Base64::decode_base64($challenge64);
2940              
2941 0         0 my $response = $self->SASLGetClient()->client_step($challenge);
2942              
2943 0         0 my $response64 = MIME::Base64::encode_base64($response,"");
2944 0         0 $self->SASLSendResponse($response64);
2945             }
2946              
2947              
2948             ###############################################################################
2949             #
2950             # SASLClient - This is a helper function to perform all of the required steps
2951             # for doing SASL with the server.
2952             #
2953             ###############################################################################
2954             sub SASLClient
2955             {
2956 0     0 0 0 my $self = shift;
2957 0         0 my $sid = shift;
2958 0         0 my $username = shift;
2959 0         0 my $password = shift;
2960 0         0 my $host = shift;
2961              
2962 0         0 my $mechanisms = $self->GetStreamFeature($sid,"xmpp-sasl");
2963              
2964 0 0       0 return unless defined($mechanisms);
2965              
2966 0         0 my $sasl = new Authen::SASL(mechanism=>join(" ",@{$mechanisms}),
  0         0  
2967             callback=>{ authname => $username."@".$self->{SIDS}->{$sid}->{hostname},
2968             user => $username,
2969             pass => $password
2970             }
2971             );
2972              
2973 0         0 $self->{SIDS}->{$sid}->{sasl}->{client} = $sasl->client_new('xmpp', $host);
2974 0         0 $self->{SIDS}->{$sid}->{sasl}->{username} = $username;
2975 0         0 $self->{SIDS}->{$sid}->{sasl}->{password} = $password;
2976 0         0 $self->{SIDS}->{$sid}->{sasl}->{authed} = 0;
2977 0         0 $self->{SIDS}->{$sid}->{sasl}->{done} = 0;
2978            
2979 0         0 $self->SASLAuth($sid);
2980             }
2981              
2982              
2983             ##############################################################################
2984             #
2985             # SASLClientAuthed - return 1 if we authed via SASL, 0 otherwise
2986             #
2987             ##############################################################################
2988             sub SASLClientAuthed
2989             {
2990 0     0 0 0 my $self = shift;
2991              
2992 0         0 return $self->{SASL}->{authed};
2993             }
2994              
2995              
2996             ##############################################################################
2997             #
2998             # SASLClientDone - return 1 if the SASL process is finished
2999             #
3000             ##############################################################################
3001             sub SASLClientDone
3002             {
3003 0     0 0 0 my $self = shift;
3004              
3005 0         0 return $self->{SASL}->{done};
3006             }
3007              
3008              
3009             ##############################################################################
3010             #
3011             # SASLClientError - return the error if any
3012             #
3013             ##############################################################################
3014             sub SASLClientError
3015             {
3016 0     0 0 0 my $self = shift;
3017              
3018 0         0 return $self->{SASL}->{error};
3019             }
3020              
3021              
3022             ##############################################################################
3023             #
3024             # SASLClientFailure - handle a received
3025             #
3026             ##############################################################################
3027             sub SASLClientFailure
3028             {
3029 0     0 0 0 my $self = shift;
3030 0         0 my $node = shift;
3031              
3032 0         0 my $type = &XML::Stream::XPath($node,"*/name()");
3033              
3034 0         0 $self->{SASL}->{error} = $type;
3035 0         0 $self->{SASL}->{done} = 1;
3036             }
3037              
3038              
3039             ##############################################################################
3040             #
3041             # SASLClientSuccess - handle a received
3042             #
3043             ##############################################################################
3044             sub SASLClientSuccess
3045             {
3046 0     0 0 0 my $self = shift;
3047 0         0 my $node = shift;
3048              
3049 0         0 $self->{SASL}->{authed} = 1;
3050 0         0 $self->{SASL}->{done} = 1;
3051              
3052 0         0 $self->RemoveDirectXPathCallBacks('/[@xmlns="'.&ConstXMLNS("xmpp-sasl").'"]'=>$SASL_CALLBACK);
3053             }
3054              
3055              
3056             ###############################################################################
3057             #
3058             # SASLGetClient - This is a helper function to return the SASL client object.
3059             #
3060             ###############################################################################
3061             sub SASLGetClient
3062             {
3063 0     0 0 0 my $self = shift;
3064              
3065 0         0 return $self->{SASL}->{client};
3066             }
3067              
3068              
3069             ##############################################################################
3070             #
3071             # SASLSendAuth - send an in the SASL namespace
3072             #
3073             ##############################################################################
3074             sub SASLSendAuth
3075             {
3076 0     0 0 0 my $self = shift;
3077              
3078 0         0 $self->Send("");
3079             }
3080              
3081              
3082             ##############################################################################
3083             #
3084             # SASLSendChallenge - Send a in the SASL namespace
3085             #
3086             ##############################################################################
3087             sub SASLSendChallenge
3088             {
3089 0     0 0 0 my $self = shift;
3090 0         0 my $challenge = shift;
3091              
3092 0         0 $self->Send("${challenge}");
3093             }
3094              
3095              
3096             ##############################################################################
3097             #
3098             # SASLSendFailure - Send a tag in the SASL namespace
3099             #
3100             ##############################################################################
3101             sub SASLSendFailure
3102             {
3103 0     0 0 0 my $self = shift;
3104 0         0 my $type = shift;
3105              
3106 0         0 $self->Send("<${type}/>");
3107             }
3108              
3109              
3110             ##############################################################################
3111             #
3112             # SASLSendResponse - Send a tag in the SASL namespace
3113             #
3114             ##############################################################################
3115             sub SASLSendResponse
3116             {
3117 0     0 0 0 my $self = shift;
3118 0         0 my $response = shift;
3119              
3120 0         0 $self->Send("${response}");
3121             }
3122              
3123              
3124              
3125              
3126             ##############################################################################
3127             #+----------------------------------------------------------------------------
3128             #|
3129             #| Default CallBacks
3130             #|
3131             #+----------------------------------------------------------------------------
3132             ##############################################################################
3133              
3134              
3135             ##############################################################################
3136             #
3137             # xmppCallbackInit - initialize the default callbacks
3138             #
3139             ##############################################################################
3140             sub xmppCallbackInit
3141             {
3142 1     1 0 2 my $self = shift;
3143              
3144 1         113 $self->{DEBUG}->Log1("xmppCallbackInit: start");
3145              
3146 0     0   0 $self->SetCallBacks(iq=>sub{ $self->callbackIQ(@_) },
3147 0     0   0 presence=>sub{ $self->callbackPresence(@_) },
3148 0     0   0 message=>sub{ $self->callbackMessage(@_) },
3149 1         30 );
3150              
3151 0     0   0 $self->SetPresenceCallBacks(subscribe=>sub{ $self->callbackPresenceSubscribe(@_) },
3152 0     0   0 unsubscribe=>sub{ $self->callbackPresenceUnsubscribe(@_) },
3153 0     0   0 subscribed=>sub{ $self->callbackPresenceSubscribed(@_) },
3154 0     0   0 unsubscribed=>sub{ $self->callbackPresenceUnsubscribed(@_) },
3155 1         21 );
3156              
3157 1         13 $self->TLSInit();
3158 1         12 $self->SASLInit();
3159              
3160 1         7 $self->{DEBUG}->Log1("xmppCallbackInit: stop");
3161             }
3162              
3163              
3164             ##############################################################################
3165             #
3166             # callbackMessage - default callback for packets.
3167             #
3168             ##############################################################################
3169             sub callbackMessage
3170             {
3171 0     0 0 0 my $self = shift;
3172 0         0 my $sid = shift;
3173 0         0 my $message = shift;
3174              
3175 0         0 my $type = "normal";
3176 0 0       0 $type = $message->GetType() if $message->DefinedType();
3177              
3178 0         0 $self->{DEBUG}->Log1("callbackMessage: type($type) sid($sid) ");
3179              
3180 0 0       0 if (exists($self->{CB}->{Mess}->{$type})
3181             #&& (ref($self->{CB}->{Mess}->{$type}) =~ /CODE/)
3182             )
3183             {
3184 0         0 &{$self->{CB}->{Mess}->{$type}}($sid,$message);
  0         0  
3185             }
3186             else
3187             {
3188 0         0 $self->{DEBUG}->Log1("callbackMessage: type($type) not code (ref($self->{CB}->{Mess}->{$type})) ");
3189             }
3190             }
3191              
3192              
3193             ##############################################################################
3194             #
3195             # callbackPresence - default callback for packets.
3196             #
3197             ##############################################################################
3198             sub callbackPresence
3199             {
3200 0     0 0 0 my $self = shift;
3201 0         0 my $sid = shift;
3202 0         0 my $presence = shift;
3203              
3204 0         0 my $type = "available";
3205 0 0       0 $type = $presence->GetType() if $presence->DefinedType();
3206              
3207 0         0 $self->{DEBUG}->Log1("callbackPresence: type($type) sid($sid) ");
3208              
3209 0 0       0 if (exists($self->{CB}->{Pres}->{$type})
3210             # && (ref($self->{CB}->{Pres}->{$type}) =~ /CODE/)
3211             )
3212             {
3213 0         0 &{$self->{CB}->{Pres}->{$type}}($sid,$presence);
  0         0  
3214             }
3215             }
3216              
3217              
3218             ##############################################################################
3219             #
3220             # callbackIQ - default callback for packets.
3221             #
3222             ##############################################################################
3223             sub callbackIQ
3224             {
3225 0     0 0 0 my $self = shift;
3226 0         0 my $sid = shift;
3227 0         0 my $iq = shift;
3228              
3229 0         0 $self->{DEBUG}->Log1("callbackIQ: sid($sid) iq($iq)");
3230              
3231 0 0       0 return unless $iq->DefinedChild();
3232 0         0 my $query = $iq->GetChild();
3233 0 0       0 return unless defined($query);
3234              
3235 0         0 my $type = $iq->GetType();
3236 0         0 my $ns = $query->GetXMLNS();
3237              
3238 0         0 $self->{DEBUG}->Log1("callbackIQ: type($type) ns($ns)");
3239              
3240 0 0 0     0 if (exists($self->{CB}->{IQns}->{$ns})
    0          
3241             && (ref($self->{CB}->{IQns}->{$ns}) != 'HASH' )
3242             )
3243             {
3244 0         0 $self->{DEBUG}->Log1("callbackIQ: goto user function( $self->{CB}->{IQns}->{$ns} )");
3245 0         0 &{$self->{CB}->{IQns}->{$ns}}($sid,$iq);
  0         0  
3246              
3247             }
3248             elsif (exists($self->{CB}->{IQns}->{$ns}->{$type})
3249             # && (ref($self->{CB}->{IQns}->{$ns}->{$type}) =~ /CODE/)
3250             )
3251             {
3252 0         0 $self->{DEBUG}->Log1("callbackIQ: goto user function( $self->{CB}->{IQns}->{$ns}->{$type} )");
3253 0         0 &{$self->{CB}->{IQns}->{$ns}->{$type}}($sid,$iq);
  0         0  
3254             }
3255             }
3256              
3257              
3258             ##############################################################################
3259             #
3260             # callbackPresenceSubscribe - default callback for subscribe packets.
3261             #
3262             ##############################################################################
3263             sub callbackPresenceSubscribe
3264             {
3265 0     0 0 0 my $self = shift;
3266 0         0 my $sid = shift;
3267 0         0 my $presence = shift;
3268              
3269 0         0 my $reply = $presence->Reply(type=>"subscribed");
3270 0         0 $self->Send($reply,1);
3271 0         0 $reply->SetType("subscribe");
3272 0         0 $self->Send($reply,1);
3273             }
3274              
3275              
3276             ##############################################################################
3277             #
3278             # callbackPresenceUnsubscribe - default callback for unsubscribe packets.
3279             #
3280             ##############################################################################
3281             sub callbackPresenceUnsubscribe
3282             {
3283 0     0 0 0 my $self = shift;
3284 0         0 my $sid = shift;
3285 0         0 my $presence = shift;
3286              
3287 0         0 my $reply = $presence->Reply(type=>"unsubscribed");
3288 0         0 $self->Send($reply,1);
3289             }
3290              
3291              
3292             ##############################################################################
3293             #
3294             # callbackPresenceSubscribed - default callback for subscribed packets.
3295             #
3296             ##############################################################################
3297             sub callbackPresenceSubscribed
3298             {
3299 0     0 0 0 my $self = shift;
3300 0         0 my $sid = shift;
3301 0         0 my $presence = shift;
3302              
3303 0         0 my $reply = $presence->Reply(type=>"subscribed");
3304 0         0 $self->Send($reply,1);
3305             }
3306              
3307              
3308             ##############################################################################
3309             #
3310             # callbackPresenceUnsubscribed - default callback for unsubscribed packets.
3311             #
3312             ##############################################################################
3313             sub callbackPresenceUnsubscribed
3314             {
3315 0     0 0 0 my $self = shift;
3316 0         0 my $sid = shift;
3317 0         0 my $presence = shift;
3318              
3319 0         0 my $reply = $presence->Reply(type=>"unsubscribed");
3320 0         0 $self->Send($reply,1);
3321             }
3322              
3323              
3324              
3325             ##############################################################################
3326             #+----------------------------------------------------------------------------
3327             #|
3328             #| Stream functions
3329             #|
3330             #+----------------------------------------------------------------------------
3331             ##############################################################################
3332             sub GetStreamID
3333             {
3334 0     0 0 0 my $self = shift;
3335              
3336 0         0 return $self->{SESSION}->{id};
3337             }
3338              
3339              
3340             sub GetStreamFeature
3341             {
3342 0     0 0 0 my $self = shift;
3343 0         0 my $feature = shift;
3344              
3345 0         0 return $self->{STREAM}->GetStreamFeature($self->GetStreamID(),$feature);
3346             }
3347              
3348              
3349             sub RestartStream
3350             {
3351 0     0 0 0 my $self = shift;
3352 0         0 my $timeout = shift;
3353              
3354 0         0 $self->{SESSION} =
3355             $self->{STREAM}->OpenStream($self->GetStreamID(),$timeout);
3356 0         0 return $self->GetStreamID();
3357             }
3358              
3359              
3360             ##############################################################################
3361             #
3362             # ConstXMLNS - Return the namespace from the constant string.
3363             #
3364             ##############################################################################
3365             sub ConstXMLNS
3366             {
3367 2     2 0 5 my $const = shift;
3368              
3369 2         22 return $XMLNS{$const};
3370             }
3371              
3372             1;