1 /**
2  * yatejabber.h
3  * Yet Another Jabber Stack
4  * This file is part of the YATE Project http://YATE.null.ro
5  *
6  * Yet Another Telephony Engine - a fully featured software PBX and IVR
7  * Copyright (C) 2004-2014 Null Team
8  *
9  * This software is distributed under multiple licenses;
10  * see the COPYING file in the main directory for licensing
11  * information for this specific distribution.
12  *
13  * This use of this software may be subject to additional restrictions.
14  * See the LEGAL file in the main directory for details.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef __YATEJABBER_H
22 #define __YATEJABBER_H
23 
24 #include <xmpputils.h>
25 
26 /**
27  * Holds all Telephony Engine related classes.
28  */
29 namespace TelEngine {
30 
31 class SASL;                              // SASL authentication mechanism
32 class JBEvent;                           // A Jabber event
33 class JBStream;                          // A Jabber stream
34 class JBClientStream;                    // A client to server stream
35 class JBServerStream;                    // A server to server stream
36 class JBClusterStream;                   // A cluster stream
37 class JBRemoteDomainDef;                 // Options and connect settings for a remote domain
38 class JBConnect;                         // A socket connector
39 class JBEngine;                          // A Jabber engine
40 class JBServerEngine;                    // A Jabber server engine
41 class JBClientEngine;                    // A Jabber client engine
42 class JBStreamSet;                       // A set of streams to be processed in an uniform way
43 class JBStreamSetProcessor;              // Specialized stream processor
44 class JBStreamSetReceive;                // Specialized stream data receiver
45 class JBStreamSetList;                   // A list of stream sets
46 class JBEntityCaps;                      // Entity capability
47 class JBEntityCapsList;                  // Entity capability list manager
48 
49 
50 /**
51  * Default port for client to server connections
52  */
53 #define XMPP_C2S_PORT 5222
54 
55 /**
56  * Default port for server to server connections
57  */
58 #define XMPP_S2S_PORT 5269
59 
60 /**
61  * Default value for maximum length of an incomplete xml allowed in a stream
62  * parser's buffer
63  */
64 #define XMPP_MAX_INCOMPLETEXML 8192
65 
66 
67 /**
68  * This class handles PLAIN (rfc 4616) and DIGEST (rfc 2831) SASL authentication
69  * @short SASL authentication mechanism
70  */
71 class YJABBER_API SASL : public GenObject
72 {
73     YCLASS(SASL,GenObject)
74 public:
75     /**
76      * Constructor
77      * @param plain True to build a plain password auth object
78      * @param realm Optional server realm
79      */
80     SASL(bool plain, const char* realm = 0);
81 
82     /**
83      * Destructor
84      */
~SASL()85     ~SASL()
86 	{ TelEngine::destruct(m_params); }
87 
88     /**
89      * Set auth params
90      * @param user Optional username
91      * @param pwd Optional password
92      */
93     void setAuthParams(const char* user = 0, const char* pwd = 0);
94 
95     /**
96      * Build a client initial auth or challenge response
97      * @param buf Destination buffer. It will be filled with Base64 encoded result
98      * @param digestUri Digest MD5 URI
99      * @return True on success
100      */
101     bool buildAuthRsp(String& buf, const char* digestUri = 0);
102 
103     /**
104      * Build a server reply to challenge response
105      * @param buf Destination buffer. It will be filled with Base64 encoded result
106      * @param rsp The response
107      */
buildAuthRspReply(String & buf,const String & rsp)108     inline void buildAuthRspReply(String& buf, const String& rsp) {
109 	    if (m_plain)
110 		return;
111 	    String tmp("rspauth=" + rsp);
112 	    Base64 b((void*)tmp.c_str(),tmp.length(),false);
113 	    b.encode(buf);
114 	    b.clear(false);
115 	}
116 
117     /**
118      * Check if a challenge response reply is valid
119      * @param reply The reply to check
120      * @return True if valid
121      */
validAuthReply(const String & reply)122     inline bool validAuthReply(const String& reply) {
123 	    String tmp;
124 	    if (m_params)
125 		buildMD5Digest(tmp,m_params->getValue("password"),false);
126 	    return tmp == reply;
127 	}
128 
129     /**
130      * Build an MD5 challenge from this object.
131      * Generate a new nonce and increase nonce count
132      * @param buf Destination buffer
133      * @return True on success
134      */
135     bool buildMD5Challenge(String& buf);
136 
137     /**
138      * Build a Digest MD5 SASL (RFC 2831) to be sent with authentication responses
139      * @param dest Destination string
140      * @param password The password to use
141      * @param challengeRsp True if building a Digest MD5 challenge response, false if
142      *  building a challenge response reply
143      */
144     inline void buildMD5Digest(String& dest, const char* password,
145 	bool challengeRsp = true) {
146 	    if (m_params)
147 		buildMD5Digest(dest,*m_params,password,challengeRsp);
148 	}
149 
150     /**
151      * Parse plain password auth data
152      * @param buf The buffer to parse
153      * @return True if succesfully parsed
154      */
155     bool parsePlain(const DataBlock& buf);
156 
157     /**
158      * Parse and decode a buffer containing a SASL Digest MD5 challenge.
159      * @param buf Already checked for valid UTF8 characters input string
160      * @return True on success
161      */
162     bool parseMD5Challenge(const String& buf);
163 
164     /**
165      * Parse and decode a buffer containing a SASL Digest MD5 response.
166      * Check realm, nonce and nonce count
167      * @param buf Already checked for valid UTF8 characters input string
168      * @return True on success
169      */
170     bool parseMD5ChallengeRsp(const String& buf);
171 
172     /**
173      * Parse and decode a buffer containing SASL plain authentication data
174      *  as defined in RFC 4616
175      * @param buf Input buffer
176      * @param user Destination buffer for username part
177      * @param pwd Destination buffer for password part
178      * @param authzid Optional destination buffer for authorization identity part
179      * @return True on success
180      */
181     static bool parsePlain(const DataBlock& buf, String& user, String& pwd,
182 	String* authzid = 0);
183 
184     /**
185      * Build a Digest MD5 SASL (RFC 2831) to be sent with authentication responses
186      * @param dest Destination string
187      * @param params List of parameters
188      * @param password The password to use
189      * @param challengeRsp True if building a Digest MD5 challenge response, false if
190      *  building a challenge response reply
191      */
192     static void buildMD5Digest(String& dest, const NamedList& params,
193 	const char* password, bool challengeRsp = true);
194 
195     bool m_plain;
196     NamedList* m_params;
197     String m_realm;
198     String m_nonce;
199     String m_cnonce;
200     unsigned int m_nonceCount;
201 
202 private:
SASL()203     SASL() {}
204 };
205 
206 
207 /**
208  * This class holds a Jabber stream event. Stream events are raised by streams
209  *  and sent by the engine to the proper service
210  * @short A Jabber stream event
211  */
212 class YJABBER_API JBEvent : public RefObject
213 {
214     YCLASS(JBEvent,RefObject)
215     friend class JBStream;
216     friend class JBClientStream;
217     friend class JBServerStream;
218 public:
219     /**
220      * Event type enumeration
221      */
222     enum Type {
223 	// Stream terminated. Try to connect or wait to be destroyed
224 	Terminated,
225 	// Stream is destroying
226 	Destroy,
227 	// Stream start was received: when processing this event, the upper
228 	// layer must call stream's start() method or terminate the stream
229 	Start,
230 	// Incoming stream need auth: when processing this event, the upper
231 	// layer must call stream's authenticated() method
232 	// Component: the event's text contains the handshake data
233 	Auth,
234 	// The event's element is an 'iq' with a child qualified by bind namespace
235 	// This event is generated by an incoming client stream without a bound resource
236 	Bind,
237 	// Stream is running (can send/recv stanzas)
238 	Running,
239 	// The event's element is a 'message'
240 	Message,
241 	// The event's element is a 'presence'
242 	Presence,
243 	// The event's element is an 'iq'
244 	Iq,
245 	// The event's element is a 'db:result' one received by a server-to-server stream
246 	//  containing the dialback key to verify
247 	// The event's text is filled with dialback key to verify
248 	DbResult,
249 	// The event's element is a 'db:verify' one received by a server-to-server stream
250 	DbVerify,
251 	// New user register or user password change succeeded
252 	RegisterOk,
253 	// New user register or user password change failed
254 	// The event's element is the response
255 	RegisterFailed,
256 	// Non stanza element received in Running state
257 	Unknown
258     };
259 
260     /**
261      * Constructor. Constructs an event from a stream
262      * @param type Type of this event
263      * @param stream The stream that generated the event
264      * @param element Element that generated the event
265      * @param from Already parsed source JID
266      * @param to Already parsed destination JID
267      * @param child Optional type depending element's child
268      */
269     inline JBEvent(Type type, JBStream* stream, XmlElement* element,
270 	const JabberID& from, const JabberID& to, XmlElement* child = 0)
m_type(type)271 	: m_type(type), m_stream(0), m_link(true), m_element(element),
272 	m_child(child)
273 	{ init(stream,element,&from,&to); }
274 
275     /**
276      * Constructor. Constructs an event from a stream
277      * @param type Type of this event
278      * @param stream The stream that generated the event
279      * @param element Element that generated the event
280      * @param child Optional type depending element's child
281      */
282     inline JBEvent(Type type, JBStream* stream, XmlElement* element,
283 	XmlElement* child = 0)
m_type(type)284 	: m_type(type), m_stream(0), m_link(true), m_element(element),
285 	m_child(child)
286 	{ init(stream,element); }
287 
288     /**
289      * Destructor. Delete the XML element if valid
290      */
291     virtual ~JBEvent();
292 
293     /**
294      * Get the event type
295      * @return The type of this event as enumeration
296      */
type()297     inline int type() const
298 	{ return m_type; }
299 
300     /**
301      * Get the event name
302      * @return The name of this event
303      */
name()304     inline const char* name() const
305 	{ return lookup(type()); }
306 
307     /**
308      * Get the element's 'type' attribute if any
309      * @return The  element's 'type' attribute
310      */
stanzaType()311     inline const String& stanzaType() const
312 	{ return m_stanzaType; }
313 
314     /**
315      * Get the 'from' attribute of a received stanza
316      * @return The 'from' attribute
317      */
from()318     inline const JabberID& from() const
319 	{ return m_from; }
320 
321     /**
322      * Get the 'to' attribute of a received stanza
323      * @return The 'to' attribute
324      */
to()325     inline const JabberID& to() const
326 	{ return m_to; }
327 
328     /**
329      * Get the sender's id for Write... events or the 'id' attribute if the
330      *  event carries a received stanza
331      * @return The event id
332      */
id()333     inline const String& id() const
334 	{ return m_id; }
335 
336     /**
337      * The stanza's text or termination reason for Terminated/Destroy events
338      * @return The event's text
339      */
text()340     inline const String& text() const
341 	{ return m_text; }
342 
343     /**
344      * Get the stream that generated this event
345      * @return The stream that generated this event
346      */
stream()347     inline JBStream* stream() const
348 	{ return m_stream; }
349 
350     /**
351      * Get a client-to-server stream from the event's stream
352      * @return JBClientStream pointer or 0
353      */
354     JBClientStream* clientStream();
355 
356     /**
357      * Get a server-to-server stream from the event's stream
358      * @return JBServerStream pointer or 0
359      */
360     JBServerStream* serverStream();
361 
362     /**
363      * Get a cluster stream from event's stream
364      * @return JBClusterStream pointer or 0
365      */
366     JBClusterStream* clusterStream();
367 
368     /**
369      * Get the underlying XmlElement
370      * @return XmlElement pointer or 0
371      */
element()372     inline XmlElement* element() const
373 	{ return m_element; }
374 
375     /**
376      * Get the first child of the underlying element if any
377      * @return XmlElement pointer or 0
378      */
child()379     inline XmlElement* child() const
380 	{ return m_child; }
381 
382     /**
383      * Delete the underlying XmlElement(s). Release the ownership.
384      * The caller will own the returned pointer
385      * @param del True to delete all xml elements owned by this event
386      * @return XmlElement pointer if not deleted or 0
387      */
388     XmlElement* releaseXml(bool del = false);
389 
390     /**
391      * Build an 'iq' result stanza from event data
392      * @param addTags True to add the 'from' and 'to' attributes
393      * @param child Optional 'iq' child (will be consumed)
394      * @return True on success
395      */
396     XmlElement* buildIqResult(bool addTags, XmlElement* child = 0);
397 
398     /**
399      * Build and send a stanza 'result' from enclosed 'iq' element
400      * Release the element on success
401      * @param child Optional 'iq' child (will be consumed)
402      * @return True on success
403      */
404     bool sendIqResult(XmlElement* child = 0);
405 
406     /**
407      * Build an 'iq' error stanza from event data
408      * The event's element will be released and added to the error one
409      *  if the id is empty
410      * @param addTags True to add the 'from' and 'to' attributes
411      * @param error Error to be returned to the event's XML sender
412      * @param reason Optional text to be attached to the error
413      * @param type Error type
414      * @return True on success
415      */
416     XmlElement* buildIqError(bool addTags, XMPPError::Type error, const char* reason = 0,
417 	XMPPError::ErrorType type = XMPPError::TypeModify);
418 
419     /**
420      * Build and send a stanza error from enclosed element
421      * Release the element on success
422      * @param error Error to be returned to the event's XML sender
423      * @param reason Optional text to be attached to the error
424      * @param type Error type
425      * @return True on success
426      */
427     bool sendStanzaError(XMPPError::Type error, const char* reason = 0,
428 	XMPPError::ErrorType type = XMPPError::TypeModify);
429 
430     /**
431      * Release the link with the stream to let the stream continue with events
432      * @param release True to release the reference to the stream
433      */
434     void releaseStream(bool release = false);
435 
436     /**
437      * Get the name of an event type
438      * @return The name an event type
439      */
lookup(int type)440     inline static const char* lookup(int type)
441 	{ return TelEngine::lookup(type,s_type); }
442 
443 private:
444     static const TokenDict s_type[];     // Event names
JBEvent()445     JBEvent() {}                         // Don't use it!
446     bool init(JBStream* stream, XmlElement* element,
447 	const JabberID* from = 0, const JabberID* to = 0);
448 
449     Type m_type;                         // Type of this event
450     JBStream* m_stream;                  // The stream that generated this event
451     bool m_link;                         // Stream link state
452     XmlElement* m_element;               // Received XML element, if any
453     XmlElement* m_child;                 // The first child element for 'iq' elements
454     String m_stanzaType;                 // Stanza's 'type' attribute
455     JabberID m_from;                     // Stanza's 'from' attribute
456     JabberID m_to;                       // Stanza's 'to' attribute
457     String m_id;                         // 'id' attribute if the received element has one
458     String m_text;                       // The stanza's text or termination reason for
459                                          //  Terminated/Destroy events
460 };
461 
462 
463 /**
464  * Base class for all Jabber streams. Basic stream data processing: send/receive
465  *  XML elements, keep stream state, generate events
466  * @short A Jabber stream
467  */
468 class YJABBER_API JBStream : public RefObject, public DebugEnabler, public Mutex
469 {
470     friend class JBEngine;
471     friend class JBEvent;
472 public:
473     /**
474      * Stream type enumeration
475      */
476     enum Type {
477 	c2s = 0,                         // Client to server
478 	s2s,                             // Server to server
479 	comp,                            // External component
480 	cluster,                         // Cluster stream
481 	TypeCount                        // Unknown
482     };
483 
484     /**
485      * Stream state enumeration
486      */
487     enum State {
488 	Idle = 0,                        // Stream is waiting to be connected or destroyed
489 	Connecting,                      // Outgoing stream is waiting for the socket to connect
490 	WaitStart,                       // Waiting for remote's stream start
491 	                                 // (outgoing: stream start already sent)
492 	Starting,                        // Incoming stream is processing a stream start element
493 	Features,                        // Outgoing: waiting for stream features
494 	                                 // Incoming: stream features sent
495 	WaitTlsRsp,                      // 'starttls' sent: waiting for response
496 	Securing,                        // Stream is currently negotiating the TLS
497 	Auth,                            // Auth element (db:result for s2s streams) sent
498 	                                 // Incoming comp: handshake received
499 	Challenge,                       // 'challenge' element sent/received
500 	Compressing,                     // Stream is negotiating compression
501 	                                 // outgoing: compress element sent, wait for response
502 	                                 // incoming: waiting for <compressed> element to be sent
503 	Register,                        // A new user is currently registering
504 	// Keep Running state here: we expect all other states
505 	//  (except for Destroy) to have lower values
506 	Running,                         // Established. Allow XML stanzas to pass over the stream
507 	Destroy,                         // Stream is destroying. No more traffic allowed
508     };
509 
510     /**
511      * Stream behaviour options
512      */
513     enum Flags {
514 	NoAutoRestart       = 0x00000001,// Don't restart stream when down
515 	TlsRequired         = 0x00000002,// TLS is mandatory on this stream
516 	AllowPlainAuth      = 0x00000004,// Allow plain password authentication
517 	                                 //  If not allowed and this is the only method
518 	                                 //  offered by server the stream will be terminated
519 	DialbackOnly        = 0x00000008,// Outgoing s2s dialback stream
520 	RegisterUser        = 0x00000010,// Outgoing c2s register new user
521 	Compress            = 0x00000020,// Offer/handle compression
522 	InError             = 0x00000080,// The stream was terminated with error
523 	// Flags to be managed by the upper layer
524 	RosterRequested     = 0x00000100,// c2s: the roster was already requested
525 	AvailableResource   = 0x00000200,// c2s: available presence was sent/received
526 	PositivePriority    = 0x00000400,// c2s: the resource advertised by the client has priority >= 0
527 	// Internal flags (cleared when the stream is re-started)
528 	SetCompressed       = 0x00010000,// Set StreamCompressed flag after succesfully sending
529 	                                 //  the current stream xml buffer
530 	StreamSecured       = 0x00020000,// TLS stage was done (possible without using TLS)
531 	StreamTls           = 0x00040000,// The stream is using TLS
532 	StreamAuthenticated = 0x00080000,// Stream already authenticated
533 	StreamRemoteVer1    = 0x00100000,// Remote party advertised RFC3920 version=1.0
534 	StreamLocalVer1     = 0x00200000,// Advertise RFC3920 version=1.0 on incoming streams
535 	StreamWaitBindRsp   = 0x01000000,// Outgoing c2s waiting for bind response
536 	StreamWaitSessRsp   = 0x02000000,// Outgoing c2s waiting for session response
537 	StreamWaitChallenge = 0x04000000,// Outgoing waiting for auth challenge
538 	StreamWaitChgRsp    = 0x08000000,// Outgoing waiting challenge response confirmation
539 	StreamRfc3920Chg    = 0x10000000,// Outgoing sent empty response to challenge with rspauth (RFC3920)
540 	StreamCompressed    = 0x20000000,// The stream is using compression
541 	StreamCanCompress   = 0x40000000,// Incoming s2s may still be compressed
542 	// Flag masks
543 	StreamFlags         = 0x000000ff,
544 	InternalFlags       = 0xffff0000,
545     };
546 
547     /**
548      * Destructor.
549      * Gracefully close the stream and the socket
550      */
551     virtual ~JBStream();
552 
553     /**
554      * Get the type of this stream. See the protocol enumeration of the engine
555      * @return The type of this stream
556      */
type()557     inline int type() const
558 	{ return m_type; }
559 
560     /**
561      * Retrieve this stream's default namespace
562      * @return The stream default namespace
563      */
xmlns()564     inline int xmlns() const
565 	{ return m_xmlns; }
566 
567     /**
568      * Get the stream state
569      * @return The stream state as enumeration.
570      */
state()571     inline State state() const
572 	{ return m_state; }
573 
574     /**
575      * Get the stream direction
576      * @return True if the stream is an incoming one
577      */
incoming()578     inline bool incoming() const
579 	{ return m_incoming; }
580 
581     /**
582      * Get the stream direction
583      * @return True if the stream is an outgoing one
584      */
outgoing()585     inline bool outgoing() const
586 	{ return !m_incoming; }
587 
588     /**
589      * Get the stream's owner
590      * @return Pointer to the engine owning this stream
591      */
engine()592     inline JBEngine* engine() const
593 	{ return m_engine; }
594 
595     /**
596      * Get the stream's name
597      * @return The stream's name
598      */
name()599     inline const char* name() const
600 	{ return m_name; }
601 
602     /**
603      * Get the stream id
604      * @return The stream id
605      */
id()606     inline const String& id() const
607 	{ return m_id; }
608 
609     /**
610      * Check if the stream id equals a given string.
611      * This method is thread safe
612      * @param str The string to check
613      * @return True if the given string equals this stream's id
614      */
isId(const String & str)615     inline bool isId(const String& str) {
616 	    Lock lock(this);
617 	    return str == m_id;
618 	}
619 
620     /**
621      * Get the JID of the local side of this stream
622      * @return The JID of the local side of this stream
623      */
local()624     inline const JabberID& local() const
625 	{ return m_local; }
626 
627     /**
628      * Get the JID of the local side of this stream.
629      * This method is thread safe
630      * @param jid The JID to be filled with the local side of this stream
631      */
local(JabberID & jid)632     inline void local(JabberID& jid) {
633 	    Lock lock(this);
634 	    jid = m_local;
635 	}
636 
637     /**
638      * Set the local party's JID
639      * @param jid Local party's jid to set
640      */
setLocal(const char * jid)641     inline void setLocal(const char* jid)
642 	{ m_local.set(jid); }
643 
644     /**
645      * Get the JID of the remote side of this stream
646      * @return The JID of the remote side of this stream
647      */
remote()648     inline const JabberID& remote() const
649 	{ return m_remote; }
650 
651     /**
652      * Get the JID of the remote side of this stream.
653      * This method is thread safe
654      * @param jid The JID to be filled with the remote side of this stream
655      */
remote(JabberID & jid)656     inline void remote(JabberID& jid) {
657 	    Lock lock(this);
658 	    jid = m_remote;
659 	}
660 
661     /**
662      * Get the remote party's address
663      * This method is thread safe
664      * @param addr The socket address to be filled with remote party's address
665      * @return True on success
666      */
remoteAddr(SocketAddr & addr)667     inline bool remoteAddr(SocketAddr& addr) {
668 	    Lock lock(this);
669 	    return m_socket && m_socket->getPeerName(addr);
670 	}
671 
672     /**
673      * Get the local address
674      * This method is thread safe
675      * @param addr The socket address to be filled with local address
676      * @return True on success
677      */
localAddr(SocketAddr & addr)678     inline bool localAddr(SocketAddr& addr) {
679 	    Lock lock(this);
680 	    return m_socket && m_socket->getSockName(addr);
681 	}
682 
683     /**
684      * Get the stream flags
685      * @return Stream flags
686      */
flags()687     inline int flags() const
688 	{ return m_flags; }
689 
690     /**
691      * Check if a given option (or option mask) is set
692      * @param mask The flag(s) to check
693      * @return True if set
694      */
flag(int mask)695     inline bool flag(int mask) const
696 	{ return 0 != (m_flags & mask); }
697 
698     /**
699      * Set or reset the TLS required flag
700      * This method is not thread safe
701      * @param set True to set, false to reset the flag
702      */
setTlsRequired(bool set)703     inline void setTlsRequired(bool set) {
704 	    Lock lock(this);
705 	    if (set)
706 		setFlags(TlsRequired);
707 	    else
708 		resetFlags(TlsRequired);
709 	}
710 
711     /**
712      * Check if the stream has valid pending data (received xml elements in queue or
713      *  pending events or pending xml elements that can still be sent).
714      * This method is thread safe
715      * @return True if the stream have pending data, false otherwise
716      */
717     bool haveData();
718 
719     /**
720      * Retrieve connection address(es), port and status
721      * This method is not thread safe
722      * @param addr The remote ip
723      * @param port The remote port
724      * @param localip Local ip to bind
725      * @param stat Current connect status
726      * @param isRedirect Optional pointer to be set to true if returned address is a redirect one
727      * @param srvs List to copy stream SRV records
728      */
729     void connectAddr(String& addr, int& port, String& localip, int& stat,
730 	ObjList& srvs, bool* isRedirect = 0) const;
731 
732     /**
733      * Retrieve server host when connecting.
734      * This method is not thread safe
735      * @return Server host if set, remote jid's domain otherwise
736      */
serverHost()737     inline const String& serverHost() const
738 	{ return m_serverHost ? m_serverHost : m_remote.domain(); }
739 
740     /**
741      * Set/reset RosterRequested flag
742      * This method is thread safe
743      * @param ok True to set, false to reset it
744      */
745     void setRosterRequested(bool ok);
746 
747     /**
748      * Set/reset AvailableResource/PositivePriority flags
749      * This method is thread safe
750      * @param ok True to set, false to reset it
751      * @param positive True if an available resource has positive priority
752      * @return True if changed
753      */
754     bool setAvailableResource(bool ok, bool positive = true);
755 
756     /**
757      * Read data from socket. Send it to the parser.
758      * Terminate the stream on socket or parser error
759      * @param buf Destination buffer
760      * @param len Buffer length (must be greater then 1)
761      * @return True if data was received
762      */
763     bool readSocket(char* buf, unsigned int len);
764 
765     /**
766      * Get a client stream from this one
767      * @return JBClientStream pointer or 0
768      */
clientStream()769     virtual JBClientStream* clientStream()
770 	{ return 0; }
771 
772     /**
773      * Get a server stream from this one
774      * @return JBServerStream pointer or 0
775      */
serverStream()776     virtual JBServerStream* serverStream()
777 	{ return 0; }
778 
779     /**
780      * Get a cluster stream from this one
781      * @return JBClusterStream pointer
782      */
clusterStream()783     virtual JBClusterStream* clusterStream()
784 	{ return 0; }
785 
786     /**
787      * Stream state processor.
788      * This method is thread safe
789      * @param time Current time
790      * @return JBEvent pointer or 0
791      */
792     JBEvent* getEvent(u_int64_t time = Time::msecNow());
793 
794     /**
795      * Send a stanza ('iq', 'message' or 'presence') or dialback elements in Running state.
796      * This method is thread safe
797      * @param xml Element to send (will be consumed and zeroed)
798      * @return True on success
799      */
800     bool sendStanza(XmlElement*& xml);
801 
802     /**
803      * Send stream related XML when negotiating the stream or some other
804      *  stanza in non Running state
805      * All elements will be consumed
806      * This method is thread safe
807      * @param newState The new stream state to set on success
808      * @param first The first element to send
809      * @param second Optional second element to send
810      * @param third Optional third element to send
811      * @return True on success
812      */
813     bool sendStreamXml(State newState, XmlElement* first, XmlElement* second = 0,
814 	XmlElement* third = 0);
815 
816     /**
817      * Start the stream. This method should be called by the upper layer
818      *  when processing an incoming stream Start event
819      * This method is thread safe
820      * @param features Optional features to advertise to the remote party of an
821      *  incoming stream. The caller is responsable of freeing it.
822      *  If processed, list's elements will be moved to stream's features list
823      * @param caps Optional entity capabilities to be added to the stream features.
824      *  Ignored for outgoing streams
825      * @param useVer1 Advertise RFC3920 version. Ignored for outgoing streams
826      */
827     void start(XMPPFeatureList* features = 0, XmlElement* caps = 0, bool useVer1 = true);
828 
829     /**
830      * Auth event result. This method should be called by the
831      *  upper layer when processing an Auth event
832      * This method is thread safe
833      * @param ok True if the remote party was authenticated,
834      *  false if authentication failed
835      * @param rsp Optional success response content. Ignored if not authenticated
836      * @param error Failure reason. Ignored if authenticated
837      * @param username Authenticated user
838      * @param id Non SASL auth response id
839      * @param resource Client resource to set when non SASL authentication is used
840      * @return False if stream state is incorrect
841      */
842     bool authenticated(bool ok, const String& rsp = String::empty(),
843 	XMPPError::Type error = XMPPError::NotAuthorized,
844 	const char* username = 0, const char* id = 0, const char* resource = 0);
845 
846     /**
847      * Terminate the stream. Send stream end tag or error.
848      * Reset the stream. Deref stream if destroying.
849      * This method is thread safe
850      * @param location The terminate request location:
851      *  -1: upper layer, 0: internal, 1: remote
852      * @param destroy True to destroy. False to terminate
853      * @param xml Received XML element. The element will be consumed
854      * @param error Termination reason. Set it to NoError to send stream end tag
855      * @param reason Optional text to be added to the error stanza
856      * @param final True if called from destructor
857      * @param genEvent True to generate terminated event
858      * @param content Optional sent error condition element text
859      */
860     void terminate(int location, bool destroy, XmlElement* xml,
861 	int error = XMPPError::NoError, const char* reason = "",
862 	bool final = false, bool genEvent = true, const char* content = 0);
863 
864     /**
865      * Outgoing stream connect terminated notification.
866      * Send stream start if everithing is ok
867      * @param sock The connected socket, will be consumed and zeroed
868      */
869     virtual void connectTerminated(Socket*& sock);
870 
871     /**
872      * Connecting notification. Start connect timer for synchronous connect
873      * This method is thread safe
874      * @param sync True if the connection is synchronous
875      * @param stat Current status of the connect thread
876      * @param srvs Current list of SRV records in the connect thread
877      * @return True if accepted
878      */
879     virtual bool connecting(bool sync, int stat, ObjList& srvs);
880 
881     /**
882      * Get an object from this stream
883      * @param name The name of the object to get
884      */
885     virtual void* getObject(const String& name) const;
886 
887     /**
888      * Get the name of a stream state
889      * @return The name of the stream state
890      */
stateName()891     inline const char* stateName() const
892 	{ return lookup(state(),s_stateName); }
893 
894     /**
895      * Get the name of a stream type
896      * @return The name of the stream type
897      */
typeName()898     inline const char* typeName() const
899 	{ return lookup(type(),s_typeName); }
900 
901     /**
902      * Build a SHA1 digest from stream id and secret
903      * @param buf Destination buffer
904      * @param secret The secret
905      */
buildSha1Digest(String & buf,const String & secret)906     inline void buildSha1Digest(String& buf, const String& secret) {
907 	    SHA1 sha(id() + secret);
908 	    buf = sha.hexDigest();
909 	    buf.toLower();
910 	}
911 
912     /**
913      * Get the string representation of this stream
914      * @return Stream name
915      */
916     virtual const String& toString() const;
917 
918     /**
919      * Get the stream type associated with a given text
920      * @param text Stream type text to find
921      * @param defVal Value to return if not found
922      * @return The stream type associated with a given text
923      */
924     static inline Type lookupType(const char* text, Type defVal = TypeCount)
925 	{ return (Type)lookup(text,s_typeName,defVal); }
926 
927     /**
928      * SASL authentication data
929      */
930     SASL* m_sasl;
931 
932     /**
933      * Dictionary keeping the stream state names
934      */
935     static const TokenDict s_stateName[];
936 
937     /**
938      * Dictionary keeping the flag names
939      */
940     static const TokenDict s_flagName[];
941 
942     /**
943      * Dictionary keeping the stream type names
944      */
945     static const TokenDict s_typeName[];
946 
947 protected:
948     /**
949      * Constructor. Build an incoming stream from a socket
950      * @param engine Engine owning this stream
951      * @param socket The socket
952      * @param t Stream type as enumeration
953      * @param ssl True if the socket is already using SSL/TLS
954      */
955     JBStream(JBEngine* engine, Socket* socket, Type t, bool ssl = false);
956 
957     /**
958      * Constructor. Build an outgoing stream
959      * @param engine Engine owning this stream
960      * @param t Stream type as enumeration
961      * @param local Local party jabber id
962      * @param remote Remote party jabber id
963      * @param name Optional stream name
964      * @param params Optional stream parameters
965      * @param serverHost Optional server host to use instead of jid domain
966      */
967     JBStream(JBEngine* engine, Type t, const JabberID& local, const JabberID& remote,
968 	const char* name = 0, const NamedList* params = 0, const char* serverHost = 0);
969 
970     /**
971      * Close the stream. Release memory
972      */
973     virtual void destroyed();
974 
975     /**
976      * Check if stream state processor can continue.
977      * This method is called from getEvent() with the stream locked
978      * @param time Current time
979      * @return True to indicate stream availability to process its state,
980      *  false to return the last event, if any
981      */
982     virtual bool canProcess(u_int64_t time);
983 
984     /**
985      * Process stream state. Get XML from parser's queue and process it
986      * This method is called from getEvent() with the stream locked
987      * @param time Current time
988      */
989     virtual void process(u_int64_t time);
990 
991     /**
992      * Process elements in Running state
993      * @param xml Received element (will be consumed)
994      * @param from Already parsed source JID
995      * @param to Already parsed destination JID
996      * @return False if stream termination was initiated
997      */
998     virtual bool processRunning(XmlElement* xml, const JabberID& from,
999 	const JabberID& to);
1000 
1001     /**
1002      * Check stream timeouts.
1003      * This method is called from getEvent() with the stream locked, after
1004      *  the process() method returned without setting the last event
1005      * @param time Current time
1006      */
1007     virtual void checkTimeouts(u_int64_t time);
1008 
1009     /**
1010      * Reset the stream's connection. Build a new XML parser if the socket is valid
1011      * Release the old connection
1012      * @param sock The new socket
1013      */
1014     virtual void resetConnection(Socket* sock = 0);
1015 
1016     /**
1017      * Build a ping iq stanza
1018      * @param stanzaId Stanza id
1019      * @return 0
1020      */
1021     virtual XmlElement* buildPing(const String& stanzaId);
1022 
1023     /**
1024      * Build a stream start XML element
1025      * @return XmlElement pointer
1026      */
1027     virtual XmlElement* buildStreamStart();
1028 
1029     /**
1030      * Process stream start elements while waiting for them
1031      * @param xml Received xml element
1032      * @param from The 'from' attribute
1033      * @param to The 'to' attribute
1034      * @return False if stream termination was initiated
1035      */
1036     virtual bool processStart(const XmlElement* xml, const JabberID& from,
1037 	const JabberID& to);
1038 
1039     /**
1040      * Process elements in Auth state
1041      * @param xml Received element (will be consumed)
1042      * @param from Already parsed source JID
1043      * @param to Already parsed destination JID
1044      * @return False if stream termination was initiated
1045      */
1046     virtual bool processAuth(XmlElement* xml, const JabberID& from,
1047 	const JabberID& to);
1048 
1049     /**
1050      * Process elements in Compressing state
1051      * @param xml Received element (will be consumed)
1052      * @param from Already parsed source JID
1053      * @param to Already parsed destination JID
1054      * @return False if stream termination was initiated
1055      */
1056     virtual bool processCompressing(XmlElement* xml, const JabberID& from,
1057 	const JabberID& to);
1058 
1059     /**
1060      * Process elements in Register state
1061      * @param xml Received element (will be consumed)
1062      * @param from Already parsed source JID
1063      * @param to Already parsed destination JID
1064      * @return False if stream termination was initiated
1065      */
1066     virtual bool processRegister(XmlElement* xml, const JabberID& from,
1067 	const JabberID& to);
1068 
1069     /**
1070      * Check if a received stream start element is correct.
1071      * Check namespaces and set stream version
1072      * Check and set the id for outgoing streams
1073      * Generate an id for incoming streams
1074      * Terminate the stream if this conditions are met
1075      * @param xml Received xml element
1076      * @return False if stream termination was initiated
1077      */
1078     bool processStreamStart(const XmlElement* xml);
1079 
1080     /**
1081      * Handle an already checked (tag and namespace) compress request
1082      * Respond to it. Change stream state on success
1083      * @param xml Received xml element (will be consumed)
1084      * @return False if stream termination was initiated
1085      */
1086     bool handleCompressReq(XmlElement* xml);
1087 
1088     /**
1089      * Check if a received element is a stream error one
1090      * @param xml Received xml element
1091      * @return True if stream termination was initiated (the xml will be consumed)
1092      */
1093     bool streamError(XmlElement* xml);
1094 
1095     /**
1096      * Retrieve and check the 'from' and 'to' JIDs from a receive element
1097      * @param xml Received xml element
1098      * @param from Jabber ID to set from the 'from' attribute
1099      * @param to Jabber ID to set from the 'to' attribute
1100      * @return False if stream termination was initiated (the xml will be consumed)
1101      */
1102     bool getJids(XmlElement* xml, JabberID& from, JabberID& to);
1103 
1104     /**
1105      * Check if a received element is a presence, message or iq qualified by the stream
1106      *  namespace and the stream is not authenticated.
1107      * Validate 'from' for c2s streams
1108      * Validate s2s 'to' domain and 'from' jid
1109      * Fix 'from' or 'to' is needed
1110      * @param xml Received xml element (will be consumed if false is returned)
1111      * @param from The sender of the stanza
1112      * @param to Stanza recipient
1113      * @return False if the element was consumed (error was sent or stream termination was initiated)
1114      */
1115     bool checkStanzaRecv(XmlElement* xml, JabberID& from, JabberID& to);
1116 
1117     /**
1118      * Change stream state. Reset state depending data
1119      * @param newState The new stream state
1120      * @param time Current time
1121      */
1122     void changeState(State newState, u_int64_t time = Time::msecNow());
1123 
1124     /**
1125      * Check if the stream compress flag is set and compression was offered by remote party
1126      * @return Compress request XmlElement pointer or 0
1127      */
1128     XmlElement* checkCompress();
1129 
1130     /**
1131      * Check for pending events. Set the last event
1132      */
1133     void checkPendingEvent();
1134 
1135     /**
1136      * Send pending stream XML or stanzas
1137      * Terminate the stream on error
1138      * @param streamOnly Try to send only existing stream related XML elements
1139      * @return True on success
1140      */
1141     bool sendPending(bool streamOnly = false);
1142 
1143     /**
1144      * Write data to socket. Terminate the stream on socket error
1145      * @param data Buffer to sent
1146      * @param len The number of bytes to send. Filled with actually sent bytes on exit
1147      * @return True on success, false on failure
1148      */
1149     bool writeSocket(const void* data, unsigned int& len);
1150 
1151     /**
1152      * Update stream flags and remote connection data from engine
1153      */
1154     void updateFromRemoteDef();
1155 
1156     /**
1157      * Retrieve the first required feature in the list
1158      * @return XMPPFeature pointer or 0
1159      */
1160     XMPPFeature* firstRequiredFeature();
1161 
1162     /**
1163      * Drop (delete) received XML element
1164      * @param xml The element to delete
1165      * @param reason The reason
1166      * @return True
1167      */
1168     bool dropXml(XmlElement*& xml, const char* reason);
1169 
1170     /**
1171      * Terminate (destroy) the stream. Drop (delete) received XML element
1172      * @param xml The element to delete
1173      * @param error Terminate error
1174      * @param reason Drop reason
1175      * @return False
1176      */
destroyDropXml(XmlElement * & xml,XMPPError::Type error,const char * reason)1177     inline bool destroyDropXml(XmlElement*& xml, XMPPError::Type error, const char* reason) {
1178 	    dropXml(xml,reason);
1179 	    terminate(0,true,0,error);
1180 	    return false;
1181 	}
1182 
1183     /**
1184      * Set stream flag mask
1185      * @param mask The bit mask to set
1186      */
1187     void setFlags(int mask);
1188 
1189     /**
1190      * Reset stream flag mask
1191      * @param mask The bit mask to reset
1192      */
1193     void resetFlags(int mask);
1194 
1195     /**
1196      * Set secured flag. Remove feature from list
1197      */
setSecured()1198     inline void setSecured() {
1199 	    setFlags(StreamSecured);
1200 	    m_features.remove(XMPPNamespace::Tls);
1201 	}
1202 
1203     /**
1204      * Set the idle timer in Running state
1205      * @param msecNow Current time in milliseconds
1206      */
1207     void setIdleTimer(u_int64_t msecNow = Time::msecNow());
1208 
1209     /**
1210      * Reset ping data
1211      */
1212     void resetPing();
1213 
1214     /**
1215      * Set the time of the next ping if there is any timeout and we don't have a ping in progress.
1216      * Set the ping timeout if an element is returned
1217      * @param force True to set it even if already set
1218      * @return XmlElement containing the ping to send, 0 if no ping is going to be sent or 'force' is true
1219      */
1220     XmlElement* setNextPing(bool force);
1221 
1222     /**
1223      * Generate a stanza index from stream id and current stanza index
1224      * Set the ping timeout if an element is returned
1225      * @param buf Destination string
1226      * @param extra Optional extra string
1227      */
1228     inline void generateIdIndex(String& buf, const char* extra = 0)
1229 	{ buf = id() + extra + String(++m_stanzaIndex);	}
1230 
1231     State m_state;                       // Stream state
1232     String m_id;                         // Stream id
1233     JabberID m_local;                    // Local peer's jid
1234     JabberID m_remote;                   // Remote peer's jid
1235     String m_serverHost;                 // Outgoing: optional server host (replaces remote domain when connecting)
1236     int m_flags;                         // Stream flags
1237     XMPPNamespace::Type m_xmlns;         // Stream namespace
1238     XMPPFeatureList m_features;          // Advertised features
1239     JBEvent* m_lastEvent;                // Last event generated by this stream
1240     ObjList m_events;                    // Queued events
1241     ObjList m_pending;                   // Pending outgoing elements
1242     unsigned int m_stanzaIndex;          // Index used to generate IDs for stanzas
1243     // Timers
1244     u_int64_t m_setupTimeout;            // Overall stream setup timeout
1245     u_int64_t m_startTimeout;            // Incoming: wait stream start period
1246     u_int64_t m_pingTimeout;             // Sent ping timeout
1247     u_int64_t m_pingInterval;            // Ping interval
1248     u_int64_t m_nextPing;                // Next ping
1249     u_int64_t m_idleTimeout;             // Stream idle timeout
1250     u_int64_t m_connectTimeout;          // Stream connect timeout
1251     //
1252     unsigned int m_restart;              // Remaining restarts
1253     u_int64_t m_timeToFillRestart;       // The next time to increase the restart counter
1254 
1255     String m_pingId;
1256 
1257 private:
1258     // Forbidden default constructor
JBStream()1259     inline JBStream() {}
1260     // Process incoming elements in Challenge state
1261     // The element will be consumed
1262     // Return false if stream termination was initiated
1263     bool processChallenge(XmlElement* xml, const JabberID& from,
1264 	const JabberID& to);
1265     // Process incoming 'auth' elements qualified by SASL namespace
1266     // The element will be consumed
1267     // Return false if stream termination was initiated
1268     bool processSaslAuth(XmlElement* xml, const JabberID& from,
1269 	const JabberID& to);
1270     // Process received elements in Features state (incoming stream)
1271     // The element will be consumed
1272     // Return false if stream termination was initiated
1273     bool processFeaturesIn(XmlElement* xml, const JabberID& from,
1274 	const JabberID& to);
1275     // Process received elements in Features state (outgoing stream)
1276     // The element will be consumed
1277     // Return false if stream termination was initiated
1278     bool processFeaturesOut(XmlElement* xml, const JabberID& from,
1279 	const JabberID& to);
1280     // Process received elements in WaitTlsRsp state (outgoing stream)
1281     // The element will be consumed
1282     // Return false if stream termination was initiated
1283     bool processWaitTlsRsp(XmlElement* xml, const JabberID& from,
1284 	const JabberID& to);
1285     // Set stream namespace from type
1286     void setXmlns();
1287     // Event termination notification
1288     // @param event The notifier. Ignored if it's not m_lastEvent
1289     void eventTerminated(const JBEvent* event);
1290     // Compress data to be sent (the pending stream xml buffer or pending stanza)
1291     // Return false on failure
1292     bool compress(XmlElementOut* xml = 0);
1293     // Reset connect status data
1294     void resetConnectStatus();
1295     // Postpone stream terminate until all parsed elements are processed
1296     // Terminate now if allowed
1297     // This method is thread safe
1298     void postponeTerminate(int location, bool destroy, int error, const char* reason);
1299     // Handle postponed termination. Return true if found
1300     // This method is not thread safe
1301     bool postponedTerminate();
1302     // Reset redirect data
1303     void setRedirect(const String& addr = String::empty(), int port = 0);
1304     // Reset postponed terminate data
resetPostponedTerminate()1305     inline void resetPostponedTerminate() {
1306 	    m_ppTerminateTimeout = 0;
1307 	    TelEngine::destruct(m_ppTerminate);
1308 	}
1309 
1310     enum {
1311 	SocketCanRead = 0x01,
1312 	SocketReading = 0x02,
1313 	SocketCanWrite = 0x10,
1314 	SocketWriting = 0x20,
1315 	SocketWaitReset = 0x80,
1316     };
socketSetCanRead(bool ok)1317     inline void socketSetCanRead(bool ok) {
1318 	    Lock lock(m_socketMutex);
1319 	    if (ok)
1320 		m_socketFlags |= SocketCanRead;
1321 	    else
1322 		m_socketFlags &= ~SocketCanRead;
1323 	}
socketSetReading(bool ok)1324     inline void socketSetReading(bool ok) {
1325 	    if (ok)
1326 		m_socketFlags |= SocketReading;
1327 	    else
1328 		m_socketFlags &= ~SocketReading;
1329 	}
socketSetCanWrite(bool ok)1330     inline void socketSetCanWrite(bool ok) {
1331 	    Lock lock(m_socketMutex);
1332 	    if (ok)
1333 		m_socketFlags |= SocketCanWrite;
1334 	    else
1335 		m_socketFlags &= ~SocketCanWrite;
1336 	}
socketSetWriting(bool ok)1337     inline void socketSetWriting(bool ok) {
1338 	    if (ok)
1339 		m_socketFlags |= SocketWriting;
1340 	    else
1341 		m_socketFlags &= ~SocketWriting;
1342 	}
socketCanRead()1343     inline bool socketCanRead() const {
1344 	    return m_socket && (m_socketFlags & SocketCanRead) &&
1345 		!socketWaitReset();
1346 	}
socketCanWrite()1347     inline bool socketCanWrite() const {
1348 	    return m_socket && (m_socketFlags & SocketCanWrite) &&
1349 		!socketWaitReset();
1350 	}
socketReading()1351     inline bool socketReading() const
1352 	{ return (m_socketFlags & SocketReading) != 0; }
socketWriting()1353     inline bool socketWriting() const
1354 	{ return (m_socketFlags & SocketWriting) != 0; }
socketWaitReset()1355     inline bool socketWaitReset() const
1356 	{ return 0 != (m_socketFlags & SocketWaitReset); }
1357 
1358     JBEngine* m_engine;                  // The owner of this stream
1359     int m_type;                          // Stream type
1360     bool m_incoming;                     // Stream direction
1361     String m_name;                       // Local (internal) name
1362     JBEvent* m_terminateEvent;           // Pending terminate event
1363     NamedList* m_ppTerminate;            // Postponed terminate parameters
1364     u_int64_t m_ppTerminateTimeout;      // Postponed terminate timeout
1365     // Pending outgoing XML
1366     String m_outStreamXml;
1367     DataBlock m_outStreamXmlCompress;
1368     DataBlock m_outXmlCompress;
1369     // Connection related data
1370     XmlDomParser* m_xmlDom;
1371     Socket* m_socket;
1372     char m_socketFlags;                  // Socket flags: 0: unavailable
1373     Mutex m_socketMutex;                 // Protect the socket and parser
1374     String m_connectAddr;                // Remote ip to connect to
1375     int m_connectPort;                   // Remote port to connect to
1376     String m_localIp;                    // Local ip to bind when connecting
1377     Compressor* m_compress;
1378     int m_connectStatus;                 // Current connect stream status
1379     ObjList m_connectSrvs;               // Current connect stream SRV records
1380     unsigned int m_redirectMax;
1381     unsigned int m_redirectCount;
1382     String m_redirectAddr;
1383     int m_redirectPort;
1384 };
1385 
1386 
1387 /**
1388  * This class holds a client to server stream
1389  * @short A client to server stream
1390  */
1391 class YJABBER_API JBClientStream : public JBStream
1392 {
1393     YCLASS(JBClientStream,JBStream)
1394     friend class JBStream;
1395 public:
1396     /**
1397      * Constructor. Build an incoming stream from a socket
1398      * @param engine Engine owning this stream
1399      * @param socket The socket
1400      * @param ssl True if the socket is already using SSL/TLS
1401      */
1402     JBClientStream(JBEngine* engine, Socket* socket, bool ssl = false);
1403 
1404     /**
1405      * Constructor. Build an outgoing stream
1406      * @param engine Engine owning this stream
1407      * @param jid User jid
1408      * @param account Account (stream) name
1409      * @param params Stream parameters
1410      * @param name Optional stream name
1411      * @param serverHost Optional server host to use instead of jid domain
1412      */
1413     JBClientStream(JBEngine* engine, const JabberID& jid, const String& account,
1414 	const NamedList& params, const char* name = 0, const char* serverHost = 0);
1415 
1416     /**
1417      * Retrieve stream's account
1418      * @return Stream account
1419      */
account()1420     inline const String& account() const
1421 	{ return m_account; }
1422 
1423     /**
1424      * Retrieve stream's user data
1425      * @return GenObject pointer or 0
1426      */
userData()1427     inline GenObject* userData()
1428 	{ return m_userData; }
1429 
1430     /**
1431      * Set stream's user data. Transfer data ownership to the stream
1432      * This method is thread safe
1433      * @param data Data to set
1434      */
userData(GenObject * data)1435     inline void userData(GenObject* data) {
1436 	    Lock lock(this);
1437 	    TelEngine::destruct(m_userData);
1438 	    m_userData = data;
1439 	}
1440 
1441     /**
1442      * Get a client stream from this one
1443      * @return JBClientStream pointer
1444      */
clientStream()1445     virtual JBClientStream* clientStream()
1446 	{ return this; }
1447 
1448     /**
1449      * Build a ping iq stanza
1450      * @param stanzaId Stanza id
1451      * @return Valid XmlElement pointer
1452      */
1453     virtual XmlElement* buildPing(const String& stanzaId);
1454 
1455     /**
1456      * Bind a resource to an incoming stream. This method should be called
1457      * after processing a Bind event
1458      * This method is thread safe
1459      * @param resource Resource to bind. Empty on error
1460      * @param id Received bind request id
1461      * @param error Failure reason. Ignored on success
1462      */
1463     void bind(const String& resource, const char* id,
1464 	XMPPError::Type error = XMPPError::NoError);
1465 
1466     /**
1467      * Request account register or change on outgoing stream.
1468      * This method is thread safe
1469      * @param data True to request registration/change, false to request info
1470      * @param set True to request new user registration, false to remove account from server
1471      * @param newPass New password when requesting account setup on an already
1472      *  authenticated stream
1473      * @return True on success
1474      */
1475     bool requestRegister(bool data, bool set = true,
1476 	const String& newPass = String::empty());
1477 
1478 protected:
1479     /**
1480      * Process elements in Running state
1481      * @param xml Received element (will be consumed)
1482      * @param from Already parsed source JID
1483      * @param to Already parsed destination JID
1484      * @return False if stream termination was initiated
1485      */
1486     virtual bool processRunning(XmlElement* xml, const JabberID& from,
1487 	const JabberID& to);
1488 
1489     /**
1490      * Process stream start elements while waiting for them
1491      * @param xml Received xml element
1492      * @param from The 'from' attribute
1493      * @param to The 'to' attribute
1494      * @return False if stream termination was initiated
1495      */
1496     virtual bool processStart(const XmlElement* xml, const JabberID& from,
1497 	const JabberID& to);
1498 
1499     /**
1500      * Process elements in Auth state
1501      * @param xml Received element (will be consumed)
1502      * @param from Already parsed source JID
1503      * @param to Already parsed destination JID
1504      * @return False if stream termination was initiated
1505      */
1506     virtual bool processAuth(XmlElement* xml, const JabberID& from,
1507 	const JabberID& to);
1508 
1509     /**
1510      * Process elements in Register state
1511      * @param xml Received element (will be consumed)
1512      * @param from Already parsed source JID
1513      * @param to Already parsed destination JID
1514      * @return False if stream termination was initiated
1515      */
1516     virtual bool processRegister(XmlElement* xml, const JabberID& from,
1517 	const JabberID& to);
1518 
1519     /**
1520      * Release memory
1521      */
1522     virtual void destroyed();
1523 
1524     /**
1525      * Start outgoing stream authentication
1526      * @return True on success
1527      */
1528     bool startAuth();
1529 
1530     /**
1531      * Start resource binding on outgoing stream
1532      * @return True on success
1533      */
1534     bool bind();
1535 
1536 private:
isRegisterId(XmlElement & xml)1537     inline bool isRegisterId(XmlElement& xml) {
1538 	    if (!m_registerReq)
1539 		return false;
1540 	    String* id = xml.getAttribute("id");
1541 	    return id && id->length() == 1 && (*id)[0] == m_registerReq;
1542 	}
1543 
1544     String m_account;                    // Stream account
1545     GenObject* m_userData;               // User (upper layer) data
1546     String m_password;                   // The password
1547     String m_newPassword;                // New password
1548     char m_registerReq;                  // Register requested. 1(data) 2(register) 3(remove)
1549 };
1550 
1551 
1552 /**
1553  * This class holds a server to server stream
1554  * @short A server to server stream
1555  */
1556 class YJABBER_API JBServerStream : public JBStream
1557 {
1558     YCLASS(JBServerStream,JBStream)
1559     friend class JBStream;
1560 public:
1561     /**
1562      * Constructor. Build an incoming stream from a socket
1563      * @param engine Engine owning this stream
1564      * @param socket The socket
1565      * @param component True to build an external component stream
1566      */
1567     JBServerStream(JBEngine* engine, Socket* socket, bool component = false);
1568 
1569     /**
1570      * Constructor. Build an outgoing stream
1571      * @param engine Engine owning this stream
1572      * @param local Local party jabber id
1573      * @param remote Remote party jabber id
1574      * @param dbId Optional dialback id (stream id)
1575      * @param dbKey Optional dialback key to verify
1576      * @param dbOnly True if this is a dialback only stream
1577      * @param params Optional stream parameters
1578      */
1579     JBServerStream(JBEngine* engine, const JabberID& local, const JabberID& remote,
1580 	const char* dbId = 0, const char* dbKey = 0, bool dbOnly = false,
1581 	const NamedList* params = 0);
1582 
1583     /**
1584      * Constructor. Build an outgoing component stream
1585      * @param engine Engine owning this stream
1586      * @param local Local party jabber id
1587      * @param remote Remote party jabber id
1588      * @param name Optional stream name
1589      * @param params Optional stream parameters
1590      */
1591     JBServerStream(JBEngine* engine, const JabberID& local, const JabberID& remote,
1592 	const String* name = 0, const NamedList* params = 0);
1593 
1594     /**
1595      * Check if this is an outgoing dialback stream
1596      * @return True if this stream is an outgoing dialback one
1597      */
dialback()1598     inline bool dialback() const
1599 	{ return outgoing() && flag(DialbackOnly); }
1600 
1601     /**
1602      * Retrieve the list of remote domains.
1603      * This method is not thread safe
1604      * @return The list of remote domains
1605      */
remoteDomains()1606     inline const NamedList& remoteDomains() const
1607 	{ return m_remoteDomains; }
1608 
1609     /**
1610      * Check if this stream has an already authenticated remote domain.
1611      * This method is not thread safe
1612      * @param domain Domain to check
1613      * @param auth Check if the domain is authenticated
1614      * @return True if a domain was found
1615      */
1616     inline bool hasRemoteDomain(const String& domain, bool auth = true) {
1617 	    NamedString* tmp = m_remoteDomains.getParam(domain);
1618 	    return tmp && (!auth || tmp->null());
1619 	}
1620 
1621     /**
1622      * Take the dialback key from this stream
1623      * @return NamedString pointer or 0 if there is no dialback key held by this stream
1624      */
takeDb()1625     inline NamedString* takeDb() {
1626 	    Lock lock(this);
1627 	    NamedString* tmp = m_dbKey;
1628 	    m_dbKey = 0;
1629 	    return tmp;
1630 	}
1631 
1632     /**
1633      * Get a server stream from this one
1634      * @return JBServerStream pointer
1635      */
serverStream()1636     virtual JBServerStream* serverStream()
1637 	{ return this; }
1638 
1639     /**
1640      * Send a dialback verify response
1641      * @param from The 'from' attribute
1642      * @param to The 'to' attribute
1643      * @param id The 'id' attribute
1644      * @param rsp The response as enumeration: set it to NoError if valid,
1645      *  NotAuthorized if invalid or any other error to send a db:verify error type
1646      * @return True on success
1647      */
1648     bool sendDbVerify(const char* from, const char* to, const char* id,
1649 	XMPPError::Type rsp = XMPPError::NoError);
1650 
1651     /**
1652      * Send a dialback key response. Update the remote domains list.
1653      * Terminate the stream if there are no more remote domains
1654      * @param from The 'from' attribute
1655      * @param to The 'to' attribute
1656      * @param rsp The response as enumeration: set it to NoError if valid,
1657      *  NotAuthorized if invalid or any other error to send a db:result error type
1658      * @return True on success
1659      */
1660     bool sendDbResult(const JabberID& from, const JabberID& to,
1661 	XMPPError::Type rsp = XMPPError::NoError);
1662 
1663     /**
1664      * Send dialback data (key/verify)
1665      * @return False if stream termination was initiated
1666      */
1667     bool sendDialback();
1668 
1669     /**
1670      * Start a component stream (reply to received stream start).
1671      * Send handshake if outgoing
1672      * @param local Local domain. Ignored if outgoing
1673      * @param remote Remote domain. Ignored if outgoing
1674      * @return True on success
1675      */
1676     bool startComp(const String& local = String::empty(), const String& remote = String::empty());
1677 
1678 protected:
1679     /**
1680      * Release memory
1681      */
1682     virtual void destroyed();
1683 
1684     /**
1685      * Process elements in Running state
1686      * @param xml Received element (will be consumed)
1687      * @param from Already parsed source JID
1688      * @param to Already parsed destination JID
1689      * @return False if stream termination was initiated
1690      */
1691     virtual bool processRunning(XmlElement* xml, const JabberID& from,
1692 	const JabberID& to);
1693 
1694     /**
1695      * Build a stream start XML element
1696      * @return XmlElement pointer
1697      */
1698     virtual XmlElement* buildStreamStart();
1699 
1700     /**
1701      * Process stream start elements while waiting for them
1702      * @param xml Received xml element
1703      * @param from The 'from' attribute
1704      * @param to The 'to' attribute
1705      * @return False if stream termination was initiated
1706      */
1707     virtual bool processStart(const XmlElement* xml, const JabberID& from,
1708 	const JabberID& to);
1709 
1710     /**
1711      * Process elements in Auth state
1712      * @param xml Received element (will be consumed)
1713      * @param from Already parsed source JID
1714      * @param to Already parsed destination JID
1715      * @return False if stream termination was initiated
1716      */
1717     virtual bool processAuth(XmlElement* xml, const JabberID& from,
1718 	const JabberID& to);
1719 
1720     /**
1721      * Process dialback key (db:result) requests
1722      * @param xml Received element (will be consumed)
1723      * @param from Already parsed source JID
1724      * @param to Already parsed destination JID
1725      * @return False if stream termination was initiated
1726      */
1727     bool processDbResult(XmlElement* xml, const JabberID& from, const JabberID& to);
1728 
1729     /**
1730      * Adjust a dialback response to avoid sending XEP 0220 'error' to a party
1731      * not advertising rfc3920 version=1 (might not support it)
1732      * @param rsp The response to adjust
1733      */
adjustDbRsp(XMPPError::Type & rsp)1734     inline void adjustDbRsp(XMPPError::Type& rsp) {
1735 	    Lock lock(this);
1736 	    if (!flag(StreamRemoteVer1) && rsp != XMPPError::NoError)
1737 		rsp = XMPPError::NotAuthorized;
1738 	}
1739 
1740     /**
1741      * Incoming stream remote domains.
1742      * Each element's value will contain the dialback key if not authenticated
1743      */
1744     NamedList m_remoteDomains;
1745 
1746 private:
1747     NamedString* m_dbKey;                // Outgoing: initial dialback key to check
1748     String m_password;                   // Outgoing component: password
1749 };
1750 
1751 
1752 /**
1753  * This class holds a cluster stream
1754  * @short A cluster stream
1755  */
1756 class YJABBER_API JBClusterStream : public JBStream
1757 {
1758     YCLASS(JBClusterStream,JBStream)
1759     friend class JBStream;
1760 public:
1761     /**
1762      * Constructor. Build an incoming stream from a socket
1763      * @param engine Engine owning this stream
1764      * @param socket The socket
1765      */
1766     JBClusterStream(JBEngine* engine, Socket* socket);
1767 
1768     /**
1769      * Constructor. Build an outgoing stream
1770      * @param engine Engine owning this stream
1771      * @param local Local party jabber id
1772      * @param remote Remote party jabber id
1773      * @param params Optional stream parameters
1774      */
1775     JBClusterStream(JBEngine* engine, const JabberID& local, const JabberID& remote,
1776 	const NamedList* params = 0);
1777 
1778     /**
1779      * Get a cluster stream from this one
1780      * @return JBClusterStream pointer
1781      */
clusterStream()1782     virtual JBClusterStream* clusterStream()
1783 	{ return this; }
1784 
1785 protected:
1786     /**
1787      * Build a stream start XML element
1788      * @return XmlElement pointer
1789      */
1790     virtual XmlElement* buildStreamStart();
1791 
1792     /**
1793      * Process stream start elements while waiting for them
1794      * @param xml Received xml element
1795      * @param from The 'from' attribute
1796      * @param to The 'to' attribute
1797      * @return False if stream termination was initiated
1798      */
1799     virtual bool processStart(const XmlElement* xml, const JabberID& from,
1800 	const JabberID& to);
1801 
1802     /**
1803      * Process elements in Running state
1804      * @param xml Received element (will be consumed)
1805      * @param from Already parsed source JID
1806      * @param to Already parsed destination JID
1807      * @return False if stream termination was initiated
1808      */
1809     virtual bool processRunning(XmlElement* xml, const JabberID& from,
1810 	const JabberID& to);
1811 };
1812 
1813 
1814 /**
1815  * This class holds data related to a remote domain.
1816  * The String holds the domain
1817  * @short Options and connect settings for a remote domain
1818  */
1819 class YJABBER_API JBRemoteDomainDef : public String
1820 {
YCLASS(JBRemoteDomainDef,String)1821     YCLASS(JBRemoteDomainDef,String)
1822 public:
1823     /**
1824      * Constructor
1825      * @param domain Domain name
1826      */
1827     inline JBRemoteDomainDef(const char* domain = 0)
1828 	: String(domain), m_port(0), m_flags(0)
1829 	{}
1830 
1831     /**
1832      * Remote address used to connect to
1833      */
1834     String m_address;
1835 
1836     /**
1837      * Remote port used to connect to
1838      */
1839     int m_port;
1840 
1841     /**
1842      * Domain flags
1843      */
1844     int m_flags;
1845 };
1846 
1847 
1848 /**
1849  * This class holds data used to connect an outgoing stream
1850  * A descendant class should implement the thread run method
1851  * @short A socket connector
1852  */
1853 class YJABBER_API JBConnect : public GenObject
1854 {
1855     YCLASS(JBConnect,GenObject)
1856 public:
1857     enum Status {
1858 	Start = 0,
1859 	Address,                         // Use configured address
1860 	Srv,                             // Use SRV records
1861 	Domain                           // Use stream remote domain
1862     };
1863 
1864     /**
1865      * Constructor. Add itself to the stream's engine
1866      * @param stream The stream to connect
1867      */
1868     JBConnect(const JBStream& stream);
1869 
1870     /**
1871      * Destructor. Remove from engine if still there
1872      */
1873     virtual ~JBConnect();
1874 
1875     /**
1876      * Stop the thread. This method should be re-implemented
1877      */
1878     virtual void stopConnect();
1879 
1880     /**
1881      * Retrieve the stream name
1882      * @return Stream name
1883      */
1884     virtual const String& toString() const;
1885 
1886     /**
1887      * Status name dictionary
1888      */
1889     static const TokenDict s_statusName[];
1890 
1891 protected:
1892     /**
1893      * Connect the socket.
1894      * Retrieve ip/port from engine ant use them if valid or try to use SRV records returned by
1895      * the given domain or use the domain's ip address and the default port given by the stream type.
1896      * Notify the stream on termination.
1897      * This method should be called from it's own thread
1898      */
1899     void connect();
1900 
1901 private:
1902     // No default constructor
JBConnect()1903     inline JBConnect()
1904 	{}
1905     // Check if exiting. Release socket if exiting
1906     bool exiting(Socket*& sock);
1907     // Create and try to connect a socket. Return it on success
1908     // Set stop on fatal failure and return 0
1909     Socket* connect(const char* addr, int port, bool& stop);
1910     // Notify termination, remove from engine
1911     void terminated(Socket* sock, bool final);
1912     // Notify connecting to the stream. Return false if stream vanished
1913     bool notifyConnecting(bool sync, bool useCurrentStat = false);
1914     // Delete a socket and zero the pointer
1915     void deleteSocket(Socket*& sock);
1916     // Advance connect status
1917     void advanceStatus();
1918 
1919     int m_status;                        // Current status
1920     String m_domain;                     // Remote domain
1921     String m_address;                    // Remote ip address
1922     int m_port;                          // Port to connect to
1923     JBEngine* m_engine;                  // The engine owning this connector
1924     String m_stream;                     // Stream name
1925     JBStream::Type m_streamType;         // Stream type
1926     String m_localIp;                    // Local ip to bind when connecting
1927     ObjList m_srvs;                      // SRV records list
1928 };
1929 
1930 
1931 /**
1932  * This class holds a Jabber engine
1933  * @short A Jabber engine
1934  */
1935 class YJABBER_API JBEngine : public DebugEnabler, public Mutex, public GenObject
1936 {
1937     YCLASS(JBEngine,GenObject)
1938     friend class JBStream;
1939     friend class JBConnect;
1940     friend class JBStreamSetProcessor;
1941 public:
1942     /**
1943      * Constructor
1944      * @param name Engine name
1945      */
1946     JBEngine(const char* name = "jbengine");
1947 
1948     /**
1949      * Destructor
1950      */
1951     virtual ~JBEngine();
1952 
1953     /**
1954      * Retrieve the stream read buffer length
1955      * @return Stream read buffer length
1956      */
streamReadBuffer()1957     inline unsigned int streamReadBuffer() const
1958 	{ return m_streamReadBuffer; }
1959 
1960     /**
1961      * Check if this engine is exiting
1962      * @return True if this engine is exiting
1963      */
exiting()1964     inline bool exiting() const
1965 	{ return m_exiting; }
1966 
1967     /**
1968      * Set the exiting flag. Terminate all streams
1969      */
setExiting()1970     inline void setExiting() {
1971 	    if (m_exiting)
1972 		return;
1973 	    m_exiting = true;
1974 	    dropAll(JBStream::TypeCount,JabberID::empty(),JabberID::empty(),
1975 		XMPPError::Shutdown);
1976 	}
1977 
1978     /**
1979      * Retrieve maximum redirect counter for outgoing streams
1980      * @return Maximum redirect counter for outgoing streams
1981      */
redirectMax()1982     inline unsigned int redirectMax() const
1983 	{ return m_redirectMax; }
1984 
1985     /**
1986      * Check if TLS is available for outgoing streams
1987      * @return True if TLS is available for outgoing streams
1988      */
hasClientTls()1989     inline bool hasClientTls() const
1990 	{ return m_hasClientTls; }
1991 
1992     /**
1993      * Find a remote domain definition. Return the default settings if not found.
1994      * This method is not thread safe
1995      * @param domain The domain to find
1996      * @return Valid JBRemoteDomainDef pointer
1997      */
remoteDomainDef(const String & domain)1998     inline JBRemoteDomainDef* remoteDomainDef(const String& domain) {
1999 	    ObjList* o = m_remoteDomains.find(domain);
2000 	    return o ? static_cast<JBRemoteDomainDef*>(o->get()) : &m_remoteDomain;
2001 	}
2002 
2003     /**
2004      * Cleanup streams. Stop all threads owned by this engine. Release memory
2005      */
2006     virtual void destruct();
2007 
2008     /**
2009      * Initialize the engine's parameters. Start private streams if requested
2010      * @param params Engine's parameters
2011      */
2012     virtual void initialize(const NamedList& params);
2013 
2014     /**
2015      * Stop connect threads. Drop all streams. Stop all stream sets. Release memory if final
2016      * @param final True if called from destructor
2017      * @param waitTerminate True to wait for all streams to terminate
2018      */
2019     virtual void cleanup(bool final = false, bool waitTerminate = true);
2020 
2021     /**
2022      * Accept an incoming stream connection. Build a stream.
2023      * Don't delete the socket if false is returned
2024      * @param sock Accepted socket
2025      * @param remote Remote ip and port
2026      * @param t Expected stream type
2027      * @param ssl True if the socket is already using SSL/TLS
2028      * @return True on success
2029      */
2030     bool acceptConn(Socket* sock, SocketAddr& remote, JBStream::Type t, bool ssl = false);
2031 
2032     /**
2033      * Find a stream by its name. This method is thread safe
2034      * @param id The internal id of the stream to find
2035      * @param hint Optional stream type hint
2036      * @return Referenced JBStream pointer or 0
2037      */
2038     virtual JBStream* findStream(const String& id,
2039 	JBStream::Type hint = JBStream::TypeCount);
2040 
2041     /**
2042      * Find all c2s streams whose local or remote bare jid matches a given one.
2043      * Ignore destroying streams.
2044      * This method is thread safe
2045      * @param in True for incoming, false for outgoing
2046      * @param jid JID to compare (the local one for outgoing, remote jid for incoming)
2047      * @param flags Optional stream flag to match
2048      * @return List of referenced JBClientStream pointers or 0
2049      */
2050     ObjList* findClientStreams(bool in, const JabberID& jid, int flags = 0xffffffff);
2051 
2052     /**
2053      * Find all c2s streams whose local or remote bare jid matches a given one and
2054      *  their resource is found in the given list.
2055      * Ignore destroying streams.
2056      * This method is thread safe
2057      * @param in True for incoming, false for outgoing
2058      * @param jid JID to compare (the local one for outgoing, remote jid for incoming)
2059      * @param resources The list of resources to match
2060      * @param flags Optional stream flag to match
2061      * @return List of referenced JBClientStream pointers or 0
2062      */
2063     ObjList* findClientStreams(bool in, const JabberID& jid, const ObjList& resources,
2064 	int flags = 0xffffffff);
2065 
2066     /**
2067      * Find a c2s stream by its local or remote jid.
2068      * This method is thread safe
2069      * @param in True for incoming, false for outgoing
2070      * @param jid JID to compare (the local one for outgoing, remote jid for incoming)
2071      * @return Referenced JBClientStream pointer or 0
2072      */
2073     JBClientStream* findClientStream(bool in, const JabberID& jid);
2074 
2075     /**
2076      * Terminate all streams matching type and/or local/remote jid
2077      * @param type Stream type. Match all stream types if unknown
2078      * @param local Optional local jid to match
2079      * @param remote Optional remote jid to match
2080      * @param error Optional error to be sent to the client
2081      * @param reason Optional error text to be sent to the client
2082      * @return The number of stream terminated
2083      */
2084     virtual unsigned int dropAll(JBStream::Type type = JBStream::TypeCount,
2085 	const JabberID& local = JabberID::empty(),
2086 	const JabberID& remote = JabberID::empty(),
2087 	XMPPError::Type error = XMPPError::NoError, const char* reason = 0);
2088 
2089     /**
2090      * Build an internal stream name
2091      * @param name Destination buffer
2092      * @param stream Stream requesting it
2093      */
buildStreamName(String & name,const JBStream * stream)2094     virtual void buildStreamName(String& name, const JBStream* stream)
2095 	{}
2096 
2097     /**
2098      * Check if a domain is serviced by this engine
2099      * @param domain Domain to check
2100      * @return True if the given domain is serviced by this engine
2101      */
hasDomain(const String & domain)2102     virtual bool hasDomain(const String& domain)
2103 	{ return false; }
2104 
2105     /**
2106      * Process an event. The default implementation will return the event
2107      *  to this engine
2108      * @param ev The event to process
2109      */
2110     virtual void processEvent(JBEvent* ev);
2111 
2112     /**
2113      * Return an event to this engine. The default implementation will send an
2114      * error if apropriate and delete the event
2115      * @param ev The event to return
2116      * @param error Optional error to be returned to the event's XML sender
2117      * @param reason Optional text to be attached to the error
2118      */
2119     virtual void returnEvent(JBEvent* ev, XMPPError::Type error = XMPPError::NoError,
2120 	const char* reason = 0);
2121 
2122     /**
2123      * Start stream TLS
2124      * @param stream The stream to enchrypt
2125      */
2126     virtual void encryptStream(JBStream* stream);
2127 
2128     /**
2129      * Connect an outgoing stream
2130      * @param stream The stream to connect
2131      */
2132     virtual void connectStream(JBStream* stream);
2133 
2134     /**
2135      * Start stream compression
2136      * @param stream The stream to compress
2137      * @param formats Supported formats
2138      */
2139     virtual void compressStream(JBStream* stream, const String& formats);
2140 
2141     /**
2142      * Build a dialback key
2143      * @param id The stream id
2144      * @param local Local domain
2145      * @param remote Remote domain
2146      * @param key The dialback key
2147      */
2148     virtual void buildDialbackKey(const String& id, const String& local,
2149 	const String& remote, String& key);
2150 
2151     /**
2152      * Check if an outgoing stream exists with the same id and remote peer
2153      * @param stream The calling stream
2154      * @return True if a duplicate is found
2155      */
2156     bool checkDupId(JBStream* stream);
2157 
2158     /**
2159      * Print XML to output
2160      * @param stream Stream requesting the operation
2161      * @param send True if sending, false if receiving
2162      * @param xml XML to print
2163      */
2164     virtual void printXml(const JBStream* stream, bool send, XmlChild& xml) const;
2165 
2166     /**
2167      * Print an XML fragment to output
2168      * @param stream Stream requesting the operation
2169      * @param send True if sending, false if receiving
2170      * @param frag XML fragment to print
2171      */
2172     virtual void printXml(const JBStream* stream, bool send, XmlFragment& frag) const;
2173 
2174 protected:
2175     /**
2176      * Add a stream to one of the stream lists
2177      * @param stream The stream to add
2178      */
2179     virtual void addStream(JBStream* stream);
2180 
2181     /**
2182      * Remove a stream
2183      * @param stream The stream to remove
2184      * @param delObj True to release the stream, false to remove it from list
2185      *  without releasing it
2186      */
2187     virtual void removeStream(JBStream* stream, bool delObj = true);
2188 
2189     /**
2190      * Stop all stream sets
2191      * @param waitTerminate True to wait for all streams to terminate
2192      */
2193     virtual void stopStreamSets(bool waitTerminate = true)
2194 	{}
2195 
2196     /**
2197      * Retrieve the list of streams of a given type.
2198      * Descendant must implement it
2199      * @param list The destination list to set
2200      * @param type Stream type
2201      */
getStreamList(RefPointer<JBStreamSetList> & list,int type)2202     virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type)
2203 	{}
2204 
2205     /**
2206      * Retrieve all streams
2207      * @param list The destination list to set. The first index will be filled with the
2208      *  c2s streams list, the second index will be set to the s2s stream list
2209      * @param type Optional stream type
2210      */
2211     inline void getStreamLists(RefPointer<JBStreamSetList> list[JBStream::TypeCount],
2212 	int type = JBStream::TypeCount) {
2213 	    if (type == JBStream::c2s || type == JBStream::TypeCount)
2214 		getStreamList(list[JBStream::c2s],JBStream::c2s);
2215 	    if (type == JBStream::s2s || type == JBStream::TypeCount)
2216 		getStreamList(list[JBStream::s2s],JBStream::s2s);
2217 	    if (type == JBStream::comp || type == JBStream::TypeCount)
2218 		getStreamList(list[JBStream::comp],JBStream::comp);
2219 	    if (type == JBStream::cluster || type == JBStream::TypeCount)
2220 		getStreamList(list[JBStream::cluster],JBStream::cluster);
2221 	}
2222 
2223     /**
2224      * Find a stream by its name in a given set list
2225      * @param id The name of the stream to find
2226      * @param list The list to search for a stream
2227      * @return Referenced JBStream pointer or 0
2228      */
2229     JBStream* findStream(const String& id, JBStreamSetList* list);
2230 
2231     bool m_exiting;                      // Engine exiting flag
2232     JBRemoteDomainDef m_remoteDomain;    // Default remote domain definition
2233     ObjList m_remoteDomains;             // Remote domain definitions
2234     unsigned char m_restartMax;          // Maximum value for stream restart counter
2235     unsigned int m_restartUpdInterval;   // Update interval for stream restart counter
2236     unsigned int m_setupTimeout;         // Overall stream setup timeout
2237     unsigned int m_startTimeout;         // Wait stream start period
2238     unsigned int m_connectTimeout;       // Outgoing: socket connect timeout
2239     unsigned int m_srvTimeout;           // SRV query timeout
2240     unsigned int m_pingInterval;         // Stream idle interval (no data received)
2241     unsigned int m_pingTimeout;          // Sent ping timeout
2242     unsigned int m_idleTimeout;          // Stream idle timeout (nothing sent or received)
2243     unsigned int m_pptTimeoutC2s;        // Client streams postpone termination intervals
2244     unsigned int m_pptTimeout;           // Non client streams postpone stream termination intervals
2245     unsigned int m_streamReadBuffer;     // Stream read buffer length
2246     unsigned int m_maxIncompleteXml;     // Maximum length of an incomplete xml
2247     unsigned int m_redirectMax;          // Max redirect counter for outgoing streams
2248     bool m_hasClientTls;                 // True if TLS is available for outgoing streams
2249     int m_printXml;                      // Print XML data to output
2250     bool m_initialized;                  // True if already initialized
2251 
2252 private:
2253     // Add/remove a connect stream thread when started/stopped
2254     void connectStatus(JBConnect* conn, bool started);
2255     // Stop a connect stream
2256     void stopConnect(const String& name);
2257 
2258     ObjList m_connect;                   // Connecting streams
2259 };
2260 
2261 /**
2262  * This class implements a Jabber server engine
2263  * @short A Jabber server engine
2264  */
2265 class YJABBER_API JBServerEngine : public JBEngine
2266 {
2267     YCLASS(JBServerEngine,JBEngine)
2268 public:
2269     /**
2270      * Constructor
2271      * @param name Engine name
2272      */
2273     JBServerEngine(const char* name = "jbserverengine");
2274 
2275     /**
2276      * Destructor
2277      */
2278     ~JBServerEngine();
2279 
2280     /**
2281      * Terminate all streams. Stop all sets processors. Release memory if final
2282      * @param final True if called from destructor
2283      * @param waitTerminate True to wait for all streams to terminate
2284      */
2285     virtual void cleanup(bool final = false, bool waitTerminate = true);
2286 
2287     /**
2288      * Build an internal stream name
2289      * @param name Destination buffer
2290      * @param stream Stream requesting it
2291      */
buildStreamName(String & name,const JBStream * stream)2292     virtual void buildStreamName(String& name, const JBStream* stream)
2293 	{ name << "stream/" << getStreamIndex(); }
2294 
2295     /**
2296      * Find a server to server or component stream by local/remote domain.
2297      * Skip over outgoing dialback only streams
2298      * This method is thread safe
2299      * @param local Local domain
2300      * @param remote Remote domain
2301      * @param out True to find an outgoing stream, false to find an incoming one.
2302      *  Ignored for component streams
2303      * @param auth Check if the remote domain of an incoming s2s stream is authenticated
2304      * @return Referenced JBServerStream pointer or 0
2305      */
2306     JBServerStream* findServerStream(const String& local, const String& remote, bool out,
2307 	bool auth = true);
2308 
2309     /**
2310      * Create an outgoing s2s stream.
2311      * @param local Local party domain
2312      * @param remote Remote party domain
2313      * @param dbId Optional dialback id (stream id)
2314      * @param dbKey Optional dialback key to verify
2315      * @param dbOnly True if this is a dialback only stream
2316      * @param params Optional stream parameters
2317      * @return Referenced JBServerStream pointer or 0 if a stream already exists
2318      */
2319     JBServerStream* createServerStream(const String& local, const String& remote,
2320 	const char* dbId = 0, const char* dbKey = 0, bool dbOnly = false,
2321 	const NamedList* params = 0);
2322 
2323     /**
2324      * Create an outgoing comp stream.
2325      * @param name Stream name
2326      * @param local Local party domain
2327      * @param remote Remote party domain
2328      * @param params Optional stream parameters
2329      * @return Referenced JBServerStream pointer or 0 if a stream already exists
2330      */
2331     JBServerStream* createCompStream(const String& name, const String& local, const String& remote,
2332 	const NamedList* params = 0);
2333 
2334     /**
2335      * Find a cluster stream by remote domain.
2336      * This method is thread safe
2337      * @param remote Remote jid
2338      * @param skip Optional stream to skip
2339      * @return Referenced JBClusterStream pointer or 0
2340      */
2341     JBClusterStream* findClusterStream(const String& remote, JBClusterStream* skip = 0);
2342 
2343     /**
2344      * Create an outgoing cluster stream.
2345      * This method is thread safe
2346      * @param local Local party domain
2347      * @param remote Remote party domain
2348      * @param params Optional stream parameters
2349      * @return Referenced JBClusterStream pointer or 0 if a stream already exists
2350      */
2351     virtual JBClusterStream* createClusterStream(const String& local,
2352 	const String& remote, const NamedList* params = 0);
2353 
2354     /**
2355      * Terminate all incoming c2s streams matching a given JID
2356      * This method is thread safe
2357      * @param jid Client JID
2358      * @param error Optional error to be sent to the client
2359      * @param reason Optional error text to be sent to the client
2360      * @return The number of stream terminated
2361      */
2362     unsigned int terminateClientStreams(const JabberID& jid,
2363 	XMPPError::Type error = XMPPError::NoError, const char* reason = 0);
2364 
2365 protected:
2366     /**
2367      * Add a stream to one of the stream lists
2368      * @param stream The stream to add
2369      */
2370     virtual void addStream(JBStream* stream);
2371 
2372     /**
2373      * Remove a stream
2374      * @param stream The stream to remove
2375      * @param delObj True to release the stream, false to remove it from list
2376      *  without releasing it
2377      */
2378     virtual void removeStream(JBStream* stream, bool delObj = true);
2379 
2380     /**
2381      * Stop all stream sets
2382      * @param waitTerminate True to wait for all streams to terminate
2383      */
2384     virtual void stopStreamSets(bool waitTerminate = true);
2385 
2386     /**
2387      * Retrieve the list of streams of a given type
2388      * @param list The destination list to set
2389      * @param type Stream type
2390      */
2391     virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type);
2392 
2393     /**
2394      * Retrieve the stream lists of a given type
2395      * @param type Stream type
2396      * @param recv Receive stream list to set
2397      * @param process Process stream list to set
2398      */
2399     virtual void getStreamListsType(int type, RefPointer<JBStreamSetList>& recv,
2400 	RefPointer<JBStreamSetList>& process);
2401 
2402     /**
2403      * Increment and return the stream index counter
2404      * @return Current stream index
2405      */
getStreamIndex()2406     inline unsigned int getStreamIndex() {
2407 	    Lock lock(this);
2408 	    return ++m_streamIndex;
2409 	}
2410 
2411     unsigned int m_streamIndex;          // Index used to build stream name
2412     JBStreamSetList* m_c2sReceive;       // c2s streams receive list
2413     JBStreamSetList* m_c2sProcess;       // c2s streams process list
2414     JBStreamSetList* m_s2sReceive;       // s2s streams receive list
2415     JBStreamSetList* m_s2sProcess;       // s2s streams process list
2416     JBStreamSetList* m_compReceive;      // comp streams receive list
2417     JBStreamSetList* m_compProcess;      // comp streams process list
2418     JBStreamSetList* m_clusterReceive;   // cluster streams receive list
2419     JBStreamSetList* m_clusterProcess;   // cluster streams process list
2420 };
2421 
2422 /**
2423  * This class implements a Jabber client engine
2424  * @short A Jabber client engine
2425  */
2426 class YJABBER_API JBClientEngine : public JBEngine
2427 {
2428     YCLASS(JBClientEngine,JBEngine)
2429 public:
2430     /**
2431      * Constructor
2432      * @param name Engine name
2433      */
2434     JBClientEngine(const char* name = "jbclientengine");
2435 
2436     /**
2437      * Destructor
2438      */
2439     ~JBClientEngine();
2440 
2441     /**
2442      * Terminate all streams. Stop all sets processors. Release memory if final
2443      * @param final True if called from destructor
2444      * @param waitTerminate True to wait for all streams to terminate
2445      */
2446     virtual void cleanup(bool final = false, bool waitTerminate = true);
2447 
2448     /**
2449      * Find a stream by account
2450      * @param account Account name
2451      * @return Referenced JBClientStream pointer or 0
2452      */
2453     JBClientStream* findAccount(const String& account);
2454 
2455     /**
2456      * Build an outgoing client stream
2457      * @param account Account name
2458      * @param params Stream parameters
2459      * @param name Optional stream name
2460      * @return Referenced JBClientStream pointer or 0 if a stream already exists
2461      */
2462     JBClientStream* create(const String& account, const NamedList& params,
2463 	const String& name = String::empty());
2464 
2465     /**
2466      * Retrieve the list of streams of a given type
2467      * @param list The destination list to set
2468      * @param type Stream type
2469      */
2470     virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type);
2471 
2472 protected:
2473     /**
2474      * Add a stream to one of the stream lists
2475      * @param stream The stream to add
2476      */
2477     virtual void addStream(JBStream* stream);
2478 
2479     /**
2480      * Remove a stream
2481      * @param stream The stream to remove
2482      * @param delObj True to release the stream, false to remove it from list
2483      *  without releasing it
2484      */
2485     virtual void removeStream(JBStream* stream, bool delObj = true);
2486 
2487     /**
2488      * Stop all stream sets
2489      * @param waitTerminate True to wait for all streams to terminate
2490      */
2491     virtual void stopStreamSets(bool waitTerminate = true);
2492 
2493     JBStreamSetList* m_receive;          // Streams receive list
2494     JBStreamSetList* m_process;          // Streams process list
2495 };
2496 
2497 /**
2498  * This class holds a set of streams to be processed in an uniform way.
2499  * This is a base class for specialized stream list processors.
2500  * Its process() method should be called in its own thread
2501  * @short A set of streams to be processed in an uniform way
2502  */
2503 class YJABBER_API JBStreamSet : public GenObject, public Mutex
2504 {
2505     YCLASS(JBStreamSet,GenObject);
2506     friend class JBStreamSetList;
2507 public:
2508     /**
2509      * Destructor. Delete the owned streams. Remove from owner
2510      */
2511     virtual ~JBStreamSet();
2512 
2513     /**
2514      * Retrieve the list of clients.
2515      * Make sure the set is locked before calling this method
2516      * @return The list of clients
2517      */
clients()2518     inline ObjList& clients()
2519 	{ return m_clients; }
2520 
2521     /**
2522      * Add a stream to the set. The stream's reference counter will be increased.
2523      * This method doesn't check if the stream is already added
2524      * @param client The stream to append
2525      * @return True on success, false if there is no more room in this set
2526      */
2527     virtual bool add(JBStream* client);
2528 
2529     /**
2530      * Remove a stream from set
2531      * @param client The stream to remove
2532      * @param delObj True to release the stream, false to remove it from list
2533      *  without releasing it
2534      * @return True on success, false if not found
2535      */
2536     virtual bool remove(JBStream* client, bool delObj = true);
2537 
2538     /**
2539      * Terminate all streams matching local/remote jid
2540      * @param local Optional local jid to match
2541      * @param remote Optional remote jid to match
2542      * @param error Optional error to be sent to the client
2543      * @param reason Optional error text to be sent to the client
2544      * @return The number of streams terminated
2545      */
2546     unsigned int dropAll(const JabberID& local = JabberID::empty(),
2547 	const JabberID& remote = JabberID::empty(),
2548 	XMPPError::Type error = XMPPError::NoError, const char* reason = 0);
2549 
2550     /**
2551      * Process the list.
2552      * Returns as soon as there are no more streams in the list
2553      */
2554     void run();
2555 
2556     /**
2557      * Start running
2558      * @return True on success
2559      */
2560     virtual bool start();
2561 
2562     /**
2563      * Stop running
2564      */
2565     virtual void stop();
2566 
2567 protected:
2568     /**
2569      * Constructor
2570      * @param owner The list owning this set
2571      */
2572     JBStreamSet(JBStreamSetList* owner);
2573 
2574     /**
2575      * This method is called from run() with the list unlocked and stream's
2576      *  reference counter increased.
2577      * A specialized processor must implement this method
2578      * @param stream The stream to process
2579      * @return True if something was processed
2580      */
2581     virtual bool process(JBStream& stream) = 0;
2582 
2583     bool m_changed;                      // List changed flag
2584     bool m_exiting;                      // The thread is exiting (don't accept clients)
2585     JBStreamSetList* m_owner;            // The list owning this set
2586     ObjList m_clients;                   // The streams list
2587 
2588 private:
JBStreamSet()2589     JBStreamSet() {}                     // Private default constructor (forbidden)
2590 };
2591 
2592 
2593 /**
2594  * This class holds a set specialized in stream processing
2595  * @short Specialized stream processor
2596  */
2597 class YJABBER_API JBStreamSetProcessor : public JBStreamSet
2598 {
2599     YCLASS(JBStreamSetProcessor,JBStreamSet);
2600 protected:
2601     /**
2602      * Constructor
2603      * @param owner The list owning this set
2604      */
JBStreamSetProcessor(JBStreamSetList * owner)2605     inline JBStreamSetProcessor(JBStreamSetList* owner)
2606 	: JBStreamSet(owner)
2607 	{}
2608 
2609     /**
2610      * This method is called from run() with the list unlocked and stream's
2611      *  reference counter increased.
2612      * Calls stream's getEvent(). Pass a generated event to the engine
2613      * Remove the stream from its engine on destroy
2614      * @param stream The stream to process
2615      * @return True if an event was generated by the stream
2616      */
2617     virtual bool process(JBStream& stream);
2618 };
2619 
2620 
2621 /**
2622  * This class holds a set specialized in stream data receiver
2623  * @short Specialized stream data receiver
2624  */
2625 class YJABBER_API JBStreamSetReceive : public JBStreamSet
2626 {
2627     YCLASS(JBStreamSetReceive,JBStreamSet);
2628 protected:
2629     /**
2630      * Constructor. Build the read buffer
2631      * @param owner The list owning this set
2632      */
2633     JBStreamSetReceive(JBStreamSetList* owner);
2634 
2635     /**
2636      * This method is called from run() with the list unlocked and stream's
2637      *  reference counter increased.
2638      * Calls stream's readSocket()
2639      * @param stream The stream to process
2640      * @return True if the stream received any data
2641      */
2642     virtual bool process(JBStream& stream);
2643 
2644 protected:
2645     DataBlock m_buffer;                  // Read buffer
2646 };
2647 
2648 
2649 /**
2650  * This class holds a list of stream sets.
2651  * The purpose is to create a list of threads
2652  * @short A list of stream sets
2653  */
2654 class YJABBER_API JBStreamSetList : public RefObject, public Mutex
2655 {
2656     YCLASS(JBStreamSetList,RefObject);
2657     friend class JBStreamSet;
2658 public:
2659     /**
2660      * Constructor
2661      * @param engine Engine owning this list
2662      * @param max Maximum streams per set (0 for maximum possible)
2663      * @param sleepMs Time to sleep when idle
2664      * @param name List name (for debugging purposes)
2665      */
2666     JBStreamSetList(JBEngine* engine, unsigned int max, unsigned int sleepMs,
2667 	const char* name);
2668 
2669     /**
2670      * Retrieve the stream set list.
2671      * Make sure the list is locked before calling this method
2672      * @return The stream set list
2673      */
sets()2674     inline ObjList& sets()
2675 	{ return m_sets; }
2676 
2677     /**
2678      * Destructor
2679      */
2680     virtual ~JBStreamSetList();
2681 
2682     /**
2683      * Retrieve the maximum number of streams per set
2684      * @return The maximum number of streams per set
2685      */
maxStreams()2686     inline unsigned int maxStreams() const
2687 	{ return m_max; }
2688 
2689     /**
2690      * Retrieve the number of streams in all sets
2691      * @return The number of streams in all sets
2692      */
streamCount()2693     inline unsigned int streamCount() const
2694 	{ return m_streamCount; }
2695 
2696     /**
2697      * Retrieve the engine owning this list
2698      * @return The engine owning this list
2699      */
engine()2700     inline JBEngine* engine() const
2701 	{ return m_engine; }
2702 
2703     /**
2704      * Add a stream to the list. Build a new set if there is no room in existing sets
2705      * @param client The stream to add
2706      * @return True on success
2707      */
2708     bool add(JBStream* client);
2709 
2710     /**
2711      * Remove a stream from list
2712      * @param client The stream to remove
2713      * @param delObj True to release the stream, false to remove it from list
2714      *  without releasing it
2715      */
2716     void remove(JBStream* client, bool delObj = true);
2717 
2718     /**
2719      * Stop one set or all sets
2720      * @param set The set to stop, 0 to stop all
2721      * @param waitTerminate True to wait for all streams to terminate
2722      */
2723     void stop(JBStreamSet* set = 0, bool waitTerminate = true);
2724 
2725     /**
2726      * Get the string representation of this list
2727      * @return The list name
2728      */
2729     virtual const String& toString() const;
2730 
2731 protected:
2732     /**
2733      * Stop all sets. Release memory
2734      */
2735     virtual void destroyed();
2736 
2737     /**
2738      * Remove a set from list without deleting it
2739      * @param set The set to remove
2740      */
2741     void remove(JBStreamSet* set);
2742 
2743     /**
2744      * Build a specialized stream set. Descendants must override this method
2745      * @return JBStreamSet pointer or 0
2746      */
2747     virtual JBStreamSet* build();
2748 
2749     JBEngine* m_engine;                  // The engine owning this list
2750     String m_name;                       // List name
2751     unsigned int m_max;                  // The maximum number of streams per set
2752     unsigned int m_sleepMs;              // Time to sleep if nothig processed
2753     ObjList m_sets;                      // The sets list
2754 
2755 private:
JBStreamSetList()2756     JBStreamSetList() {}                 // Private default constructor (forbidden)
2757 
2758     unsigned int m_streamCount;          // Current number of streams in this list
2759 };
2760 
2761 
2762 /**
2763  * This class holds entity capability data
2764  * Implements XEP 0115 support
2765  * @short Entity capability
2766  */
2767 class YJABBER_API JBEntityCaps : public String
2768 {
2769     YCLASS(JBEntityCaps,String);
2770 public:
2771     /**
2772      * Supported XEP 0115 versions
2773      */
2774     enum {
2775 	Ver1_3 = 1,  // Version lower then 1.4 (m_data is the node version + advertised extensions)
2776 	Ver1_4 = 2,  // Version 1.4 or greater (m_data is the SHA-1 hash of features and identities)
2777     };
2778 
2779     /**
2780      * Constructor
2781      * @param id Object id
2782      * @param version Entity caps version
2783      * @param node Entity node
2784      * @param data Entity data
2785      */
JBEntityCaps(const char * id,char version,const char * node,const char * data)2786     inline JBEntityCaps(const char* id, char version, const char* node, const char* data)
2787 	: String(id),
2788 	m_version(version), m_node(node), m_data(data)
2789 	{}
2790 
2791     /**
2792      * Check if a given feature is found in the list
2793      * @param ns The feature to check
2794      * @return True if the feature was found in the list
2795      */
hasFeature(int ns)2796     inline bool hasFeature(int ns)
2797 	{ return 0 != m_features.get(ns); }
2798 
2799     /**
2800      * Check if an audio capability is present
2801      * @return True if an audio capability is present
2802      */
hasAudio()2803     inline bool hasAudio() {
2804 	    return hasFeature(XMPPNamespace::JingleAppsRtpAudio) ||
2805 		hasFeature(XMPPNamespace::JingleAudio) ||
2806 		hasFeature(XMPPNamespace::JingleVoiceV1);
2807 	}
2808 
2809     /**
2810      * Build an entity caps id
2811      * @param buf Destination buffer
2812      * @param version Entity caps version
2813      * @param node Entity node
2814      * @param data Entity data
2815      * @param ext Optional entity extensions
2816      */
2817     static inline void buildId(String& buf, char version, const char* node,
2818 	const char* data, String* ext = 0)
2819 	{ buf << (int)version << node << data << (ext ? ext->c_str() : ""); }
2820 
2821     char m_version;
2822     String m_node;
2823     String m_data;
2824     XMPPFeatureList m_features;
2825 
2826 private:
JBEntityCaps()2827     JBEntityCaps() {}
2828 };
2829 
2830 
2831 /**
2832  * This class holds data and offer entity capability services.
2833  * Implements XEP 0115 support
2834  * @short Entity capability list manager
2835  */
2836 class YJABBER_API JBEntityCapsList : public ObjList, public Mutex
2837 {
2838     YCLASS(JBEntityCapsList,ObjList);
2839 public:
2840     /**
2841      * Constructor
2842      */
JBEntityCapsList()2843     inline JBEntityCapsList()
2844 	: Mutex(true,"JBEntityCapsList"), m_enable(true), m_reqIndex(0)
2845 	{ m_reqPrefix << "xep0115" << (unsigned int)Time::msecNow() << "_"; }
2846 
2847     /**
2848      * Retrieve an entity caps object. This method is not thread safe
2849      * @param id The id to find
2850      * @return JBEntityCaps pointer or 0
2851      */
findCaps(const String & id)2852     inline JBEntityCaps* findCaps(const String& id) {
2853 	    for (ObjList* o = skipNull(); o; o = o->skipNext())
2854 		if (o->get()->toString() == id)
2855 		    return static_cast<JBEntityCaps*>(o->get());
2856 	    return 0;
2857 	}
2858 
2859     /**
2860      * Expire pending requests.
2861      * This method is thread safe
2862      * @param msecNow Current time
2863      */
2864     void expire(u_int64_t msecNow = Time::msecNow());
2865 
2866     /**
2867      * Process a response.
2868      * This method is thread safe
2869      * @param rsp The element to process
2870      * @param id The element's id
2871      * @param ok True if the response is a result one, false if it's an error
2872      * @return True if the element was processed (handled)
2873      */
2874     bool processRsp(XmlElement* rsp, const String& id, bool ok);
2875 
2876     /**
2877      * Request entity capabilities.
2878      * This method is thread safe
2879      * @param stream The stream to send the request
2880      * @param from The 'from' attribute
2881      * @param to The 'to' attribute
2882      * @param id Entity caps id
2883      * @param version Entity caps version
2884      * @param node Entity node
2885      * @param data Entity caps data
2886      */
2887     void requestCaps(JBStream* stream, const char* from, const char* to, const String& id,
2888 	char version, const char* node, const char* data);
2889 
2890     /**
2891      * Build an XML document from this list.
2892      * This method is thread safe
2893      * @param rootName Document root element name
2894      * @return XmlDocument pointer
2895      */
2896     XmlDocument* toDocument(const char* rootName = "entitycaps");
2897 
2898     /**
2899      * Build this list from an XML document.
2900      * This method is thread safe
2901      * @param doc Document to build from
2902      * @param rootName Document root element name (it will be checked if set)
2903      * @return XmlDocument pointer
2904      */
2905     void fromDocument(XmlDocument& doc, const char* rootName = "entitycaps");
2906 
2907     /**
2908      * Process an element containing an entity capabily child.
2909      * Request capabilities if not found in the list.
2910      * This method is thread safe
2911      * @param capsId String to be filled with entity caps object id
2912      *  (empty if an entity caps child is not found in element )
2913      * @param xml XML element to process
2914      * @param stream The stream used to request capabilities
2915      * @param from The 'from' attribute of the request stanza
2916      * @param to The 'to' attribute of the request stanza
2917      * @return True if processed (already found, added or request sent)
2918      */
2919     virtual bool processCaps(String& capsId, XmlElement* xml, JBStream* stream,
2920 	const char* from, const char* to);
2921 
2922     /**
2923      * Add capabilities to a list.
2924      * This method is thread safe
2925      * @param list Destination list
2926      * @param id Entity caps id
2927      */
addCaps(NamedList & list,const String & id)2928     inline void addCaps(NamedList& list, const String& id) {
2929 	    Lock lock(this);
2930 	    JBEntityCaps* caps = findCaps(id);
2931 	    if (caps)
2932 		addCaps(list,*caps);
2933 	}
2934 
2935     /**
2936      * Add capabilities to a list.
2937      * This method is not thread safe
2938      * @param list Destination list
2939      * @param caps Entity caps to add
2940      */
2941     virtual void addCaps(NamedList& list, JBEntityCaps& caps);
2942 
2943     /**
2944      * Load (reset) this list from an XML document file.
2945      * This method is thread safe
2946      * @param file The file to load
2947      * @param enabler The debug enabler used to output messages
2948      * @return True on success
2949      */
2950     bool loadXmlDoc(const char* file, DebugEnabler* enabler = 0);
2951 
2952     /**
2953      * Save this list to an XML document file.
2954      * This method is thread safe
2955      * @param file The file to save
2956      * @param enabler The debug enabler used to output messages
2957      * @return True on success
2958      */
2959     bool saveXmlDoc(const char* file, DebugEnabler* enabler = 0);
2960 
2961     /**
2962      * Check if an XML element has a 'c' entity capability child and decode it
2963      * @param xml The element to process
2964      * @param version Entity caps version
2965      * @param node Entity node attribute
2966      * @param ver Entity ver attribute
2967      * @param ext Entity ext attribute if version is less the 1.4
2968      * @return True if a child was succesfully decoded
2969      */
2970     static bool decodeCaps(const XmlElement& xml, char& version, String*& node,
2971 	String*& ver, String*& ext);
2972 
2973     /**
2974      * Enabled flag
2975      */
2976     bool m_enable;
2977 
2978 protected:
2979     /**
2980      * Caps list item add notification for descendants.
2981      * This method is called when processing responses with the list locked
2982      * @param caps Changed caps object. 0 if none specified
2983      */
capsAdded(JBEntityCaps * caps)2984     virtual void capsAdded(JBEntityCaps* caps)
2985 	{}
2986 
2987     unsigned int m_reqIndex;             // Disco info request index
2988     String m_reqPrefix;                  // Prefix for disco info stanza id
2989     ObjList m_requests;                  // List of sent disco info requests
2990 };
2991 
2992 }; // namespace TelEngine
2993 
2994 #endif /* __YATEJABBER_H */
2995 
2996 /* vi: set ts=8 sw=4 sts=4 noet: */
2997