Yate
yatejabber.h
00001 
00024 #ifndef __YATEJABBER_H
00025 #define __YATEJABBER_H
00026 
00027 #include <xmpputils.h>
00028 
00032 namespace TelEngine {
00033 
00034 class SASL;                              // SASL authentication mechanism
00035 class JBEvent;                           // A Jabber event
00036 class JBStream;                          // A Jabber stream
00037 class JBClientStream;                    // A client to server stream
00038 class JBServerStream;                    // A server to server stream
00039 class JBClusterStream;                   // A cluster stream
00040 class JBRemoteDomainDef;                 // Options and connect settings for a remote domain
00041 class JBConnect;                         // A socket connector
00042 class JBEngine;                          // A Jabber engine
00043 class JBServerEngine;                    // A Jabber server engine
00044 class JBClientEngine;                    // A Jabber client engine
00045 class JBStreamSet;                       // A set of streams to be processed in an uniform way
00046 class JBStreamSetProcessor;              // Specialized stream processor
00047 class JBStreamSetReceive;                // Specialized stream data receiver
00048 class JBStreamSetList;                   // A list of stream sets
00049 class JBEntityCaps;                      // Entity capability
00050 class JBEntityCapsList;                  // Entity capability list manager
00051 
00052 
00056 #define XMPP_C2S_PORT 5222
00057 
00061 #define XMPP_S2S_PORT 5269
00062 
00067 #define XMPP_MAX_INCOMPLETEXML 8192
00068 
00069 
00074 class YJABBER_API SASL : public GenObject
00075 {
00076     YCLASS(SASL,GenObject)
00077 public:
00083     SASL(bool plain, const char* realm = 0);
00084 
00088     ~SASL()
00089         { TelEngine::destruct(m_params); }
00090 
00096     void setAuthParams(const char* user = 0, const char* pwd = 0);
00097 
00104     bool buildAuthRsp(String& buf, const char* digestUri = 0);
00105 
00111     inline void buildAuthRspReply(String& buf, const String& rsp) {
00112             if (m_plain)
00113                 return;
00114             String tmp("rspauth=" + rsp);
00115             Base64 b((void*)tmp.c_str(),tmp.length(),false);
00116             b.encode(buf);
00117             b.clear(false);
00118         }
00119 
00125     inline bool validAuthReply(const String& reply) {
00126             String tmp;
00127             if (m_params)
00128                 buildMD5Digest(tmp,m_params->getValue("password"),false);
00129             return tmp == reply;
00130         }
00131 
00138     bool buildMD5Challenge(String& buf);
00139 
00147     inline void buildMD5Digest(String& dest, const char* password,
00148         bool challengeRsp = true) {
00149             if (m_params)
00150                 buildMD5Digest(dest,*m_params,password,challengeRsp);
00151         }
00152 
00158     bool parsePlain(const DataBlock& buf);
00159 
00165     bool parseMD5Challenge(const String& buf);
00166 
00173     bool parseMD5ChallengeRsp(const String& buf);
00174 
00184     static bool parsePlain(const DataBlock& buf, String& user, String& pwd,
00185         String* authzid = 0);
00186 
00195     static void buildMD5Digest(String& dest, const NamedList& params,
00196         const char* password, bool challengeRsp = true);
00197 
00198     bool m_plain;
00199     NamedList* m_params;
00200     String m_realm;
00201     String m_nonce;
00202     String m_cnonce;
00203     unsigned int m_nonceCount;
00204 
00205 private:
00206     SASL() {}
00207 };
00208 
00209 
00215 class YJABBER_API JBEvent : public RefObject
00216 {
00217     YCLASS(JBEvent,RefObject)
00218     friend class JBStream;
00219     friend class JBClientStream;
00220     friend class JBServerStream;
00221 public:
00225     enum Type {
00226         // Stream terminated. Try to connect or wait to be destroyed
00227         Terminated,
00228         // Stream is destroying
00229         Destroy,
00230         // Stream start was received: when processing this event, the upper
00231         // layer must call stream's start() method or terminate the stream
00232         Start,
00233         // Incoming stream need auth: when processing this event, the upper
00234         // layer must call stream's authenticated() method
00235         // Component: the event's text contains the handshake data
00236         Auth,
00237         // The event's element is an 'iq' with a child qualified by bind namespace
00238         // This event is generated by an incoming client stream without a bound resource
00239         Bind,
00240         // Stream is running (can send/recv stanzas)
00241         Running,
00242         // The event's element is a 'message'
00243         Message,
00244         // The event's element is a 'presence'
00245         Presence,
00246         // The event's element is an 'iq'
00247         Iq,
00248         // The event's element is a 'db:result' one received by a server-to-server stream
00249         //  containing the dialback key to verify
00250         // The event's text is filled with dialback key to verify
00251         DbResult,
00252         // The event's element is a 'db:verify' one received by a server-to-server stream
00253         DbVerify,
00254         // New user register or user password change succeeded
00255         RegisterOk,
00256         // New user register or user password change failed
00257         // The event's element is the response
00258         RegisterFailed,
00259         // Non stanza element received in Running state
00260         Unknown
00261     };
00262 
00272     inline JBEvent(Type type, JBStream* stream, XmlElement* element,
00273         const JabberID& from, const JabberID& to, XmlElement* child = 0)
00274         : m_type(type), m_stream(0), m_link(true), m_element(element),
00275         m_child(child)
00276         { init(stream,element,&from,&to); }
00277 
00285     inline JBEvent(Type type, JBStream* stream, XmlElement* element,
00286         XmlElement* child = 0)
00287         : m_type(type), m_stream(0), m_link(true), m_element(element),
00288         m_child(child)
00289         { init(stream,element); }
00290 
00294     virtual ~JBEvent();
00295 
00300     inline int type() const
00301         { return m_type; }
00302 
00307     inline const char* name() const
00308         { return lookup(type()); }
00309 
00314     inline const String& stanzaType() const
00315         { return m_stanzaType; }
00316 
00321     inline const JabberID& from() const
00322         { return m_from; }
00323 
00328     inline const JabberID& to() const
00329         { return m_to; }
00330 
00336     inline const String& id() const
00337         { return m_id; }
00338 
00343     inline const String& text() const
00344         { return m_text; }
00345 
00350     inline JBStream* stream() const
00351         { return m_stream; }
00352 
00357     JBClientStream* clientStream();
00358 
00363     JBServerStream* serverStream();
00364 
00369     JBClusterStream* clusterStream();
00370 
00375     inline XmlElement* element() const
00376         { return m_element; }
00377 
00382     inline XmlElement* child() const
00383         { return m_child; }
00384 
00391     XmlElement* releaseXml(bool del = false);
00392 
00399     XmlElement* buildIqResult(bool addTags, XmlElement* child = 0);
00400 
00407     bool sendIqResult(XmlElement* child = 0);
00408 
00419     XmlElement* buildIqError(bool addTags, XMPPError::Type error, const char* reason = 0,
00420         XMPPError::ErrorType type = XMPPError::TypeModify);
00421 
00430     bool sendStanzaError(XMPPError::Type error, const char* reason = 0,
00431         XMPPError::ErrorType type = XMPPError::TypeModify);
00432 
00437     void releaseStream(bool release = false);
00438 
00443     inline static const char* lookup(int type)
00444         { return TelEngine::lookup(type,s_type); }
00445 
00446 private:
00447     static const TokenDict s_type[];     // Event names
00448     JBEvent() {}                         // Don't use it!
00449     bool init(JBStream* stream, XmlElement* element,
00450         const JabberID* from = 0, const JabberID* to = 0);
00451 
00452     Type m_type;                         // Type of this event
00453     JBStream* m_stream;                  // The stream that generated this event
00454     bool m_link;                         // Stream link state
00455     XmlElement* m_element;               // Received XML element, if any
00456     XmlElement* m_child;                 // The first child element for 'iq' elements
00457     String m_stanzaType;                 // Stanza's 'type' attribute
00458     JabberID m_from;                     // Stanza's 'from' attribute
00459     JabberID m_to;                       // Stanza's 'to' attribute
00460     String m_id;                         // 'id' attribute if the received element has one
00461     String m_text;                       // The stanza's text or termination reason for
00462                                          //  Terminated/Destroy events
00463 };
00464 
00465 
00471 class YJABBER_API JBStream : public RefObject, public DebugEnabler, public Mutex
00472 {
00473     friend class JBEngine;
00474     friend class JBEvent;
00475 public:
00479     enum Type {
00480         c2s = 0,                         // Client to server
00481         s2s,                             // Server to server
00482         comp,                            // External component
00483         cluster,                         // Cluster stream
00484         TypeCount                        // Unknown
00485     };
00486 
00490     enum State {
00491         Idle = 0,                        // Stream is waiting to be connected or destroyed
00492         Connecting,                      // Outgoing stream is waiting for the socket to connect
00493         WaitStart,                       // Waiting for remote's stream start
00494                                          // (outgoing: stream start already sent)
00495         Starting,                        // Incoming stream is processing a stream start element
00496         Features,                        // Outgoing: waiting for stream features
00497                                          // Incoming: stream features sent
00498         WaitTlsRsp,                      // 'starttls' sent: waiting for response
00499         Securing,                        // Stream is currently negotiating the TLS
00500         Auth,                            // Auth element (db:result for s2s streams) sent
00501                                          // Incoming comp: handshake received
00502         Challenge,                       // 'challenge' element sent/received
00503         Compressing,                     // Stream is negotiating compression
00504                                          // outgoing: compress element sent, wait for response
00505                                          // incoming: waiting for <compressed> element to be sent
00506         Register,                        // A new user is currently registering
00507         // Keep Running state here: we expect all other states
00508         //  (except for Destroy) to have lower values
00509         Running,                         // Established. Allow XML stanzas to pass over the stream
00510         Destroy,                         // Stream is destroying. No more traffic allowed
00511     };
00512 
00516     enum Flags {
00517         NoAutoRestart       = 0x00000001,// Don't restart stream when down
00518         TlsRequired         = 0x00000002,// TLS is mandatory on this stream
00519         AllowPlainAuth      = 0x00000004,// Allow plain password authentication
00520                                          //  If not allowed and this is the only method
00521                                          //  offered by server the stream will be terminated
00522         DialbackOnly        = 0x00000008,// Outgoing s2s dialback stream
00523         RegisterUser        = 0x00000010,// Outgoing c2s register new user
00524         Compress            = 0x00000020,// Offer/handle compression
00525         InError             = 0x00000080,// The stream was terminated with error
00526         // Flags to be managed by the upper layer
00527         RosterRequested     = 0x00000100,// c2s: the roster was already requested
00528         AvailableResource   = 0x00000200,// c2s: available presence was sent/received
00529         PositivePriority    = 0x00000400,// c2s: the resource advertised by the client has priority >= 0
00530         // Internal flags (cleared when the stream is re-started)
00531         SetCompressed       = 0x00010000,// Set StreamCompressed flag after succesfully sending
00532                                          //  the current stream xml buffer
00533         StreamSecured       = 0x00020000,// TLS stage was done (possible without using TLS)
00534         StreamTls           = 0x00040000,// The stream is using TLS
00535         StreamAuthenticated = 0x00080000,// Stream already authenticated
00536         StreamRemoteVer1    = 0x00100000,// Remote party advertised RFC3920 version=1.0
00537         StreamLocalVer1     = 0x00200000,// Advertise RFC3920 version=1.0 on incoming streams
00538         StreamWaitBindRsp   = 0x01000000,// Outgoing c2s waiting for bind response
00539         StreamWaitSessRsp   = 0x02000000,// Outgoing c2s waiting for session response
00540         StreamWaitChallenge = 0x04000000,// Outgoing waiting for auth challenge
00541         StreamWaitChgRsp    = 0x08000000,// Outgoing waiting challenge response confirmation
00542         StreamRfc3920Chg    = 0x10000000,// Outgoing sent empty response to challenge with rspauth (RFC3920)
00543         StreamCompressed    = 0x20000000,// The stream is using compression
00544         StreamCanCompress   = 0x40000000,// Incoming s2s may still be compressed
00545         // Flag masks
00546         StreamFlags         = 0x000000ff,
00547         InternalFlags       = 0xffff0000,
00548     };
00549 
00554     virtual ~JBStream();
00555 
00560     inline int type() const
00561         { return m_type; }
00562 
00567     inline int xmlns() const
00568         { return m_xmlns; }
00569 
00574     inline State state() const
00575         { return m_state; }
00576 
00581     inline bool incoming() const
00582         { return m_incoming; }
00583 
00588     inline bool outgoing() const
00589         { return !m_incoming; }
00590 
00595     inline JBEngine* engine() const
00596         { return m_engine; }
00597 
00602     inline const char* name() const
00603         { return m_name; }
00604 
00609     inline const String& id() const
00610         { return m_id; }
00611 
00618     inline bool isId(const String& str) {
00619             Lock lock(this);
00620             return str == m_id;
00621         }
00622 
00627     inline const JabberID& local() const
00628         { return m_local; }
00629 
00635     inline void local(JabberID& jid) {
00636             Lock lock(this);
00637             jid = m_local;
00638         }
00639 
00644     inline void setLocal(const char* jid)
00645         { m_local.set(jid); }
00646 
00651     inline const JabberID& remote() const
00652         { return m_remote; }
00653 
00659     inline void remote(JabberID& jid) {
00660             Lock lock(this);
00661             jid = m_remote;
00662         }
00663 
00670     inline bool remoteAddr(SocketAddr& addr) {
00671             Lock lock(this);
00672             return m_socket && m_socket->getPeerName(addr);
00673         }
00674 
00681     inline bool localAddr(SocketAddr& addr) {
00682             Lock lock(this);
00683             return m_socket && m_socket->getSockName(addr);
00684         }
00685 
00690     inline int flags() const
00691         { return m_flags; }
00692 
00698     inline bool flag(int mask) const
00699         { return 0 != (m_flags & mask); }
00700 
00706     inline void setTlsRequired(bool set) {
00707             Lock lock(this);
00708             if (set)
00709                 setFlags(TlsRequired);
00710             else
00711                 resetFlags(TlsRequired);
00712         }
00713 
00720     bool haveData();
00721 
00731     void connectAddr(String& addr, int& port, String& localip, int& stat,
00732         ObjList& srvs) const;
00733 
00739     inline const String& serverHost() const
00740         { return m_serverHost ? m_serverHost : m_remote.domain(); }
00741 
00747     void setRosterRequested(bool ok);
00748 
00756     bool setAvailableResource(bool ok, bool positive = true);
00757 
00765     bool readSocket(char* buf, unsigned int len);
00766 
00771     virtual JBClientStream* clientStream()
00772         { return 0; }
00773 
00778     virtual JBServerStream* serverStream()
00779         { return 0; }
00780 
00785     virtual JBClusterStream* clusterStream()
00786         { return 0; }
00787 
00794     JBEvent* getEvent(u_int64_t time = Time::msecNow());
00795 
00802     bool sendStanza(XmlElement*& xml);
00803 
00815     bool sendStreamXml(State newState, XmlElement* first, XmlElement* second = 0,
00816         XmlElement* third = 0);
00817 
00829     void start(XMPPFeatureList* features = 0, XmlElement* caps = 0, bool useVer1 = true);
00830 
00844     bool authenticated(bool ok, const String& rsp = String::empty(),
00845         XMPPError::Type error = XMPPError::NotAuthorized,
00846         const char* username = 0, const char* id = 0, const char* resource = 0);
00847 
00860     void terminate(int location, bool destroy, XmlElement* xml,
00861         int error = XMPPError::NoError, const char* reason = "",
00862         bool final = false);
00863 
00869     virtual void connectTerminated(Socket*& sock);
00870 
00879     virtual bool connecting(bool sync, int stat, ObjList& srvs);
00880 
00885     virtual void* getObject(const String& name) const;
00886 
00891     inline const char* stateName() const
00892         { return lookup(state(),s_stateName); }
00893 
00898     inline const char* typeName() const
00899         { return lookup(type(),s_typeName); }
00900 
00906     inline void buildSha1Digest(String& buf, const String& secret) {
00907             SHA1 sha(id() + secret);
00908             buf = sha.hexDigest();
00909             buf.toLower();
00910         }
00911 
00916     virtual const String& toString() const;
00917 
00924     static inline Type lookupType(const char* text, Type defVal = TypeCount)
00925         { return (Type)lookup(text,s_typeName,defVal); }
00926 
00930     SASL* m_sasl;
00931 
00935     static const TokenDict s_stateName[];
00936 
00940     static const TokenDict s_flagName[];
00941 
00945     static const TokenDict s_typeName[];
00946 
00947 protected:
00955     JBStream(JBEngine* engine, Socket* socket, Type t, bool ssl = false);
00956 
00967     JBStream(JBEngine* engine, Type t, const JabberID& local, const JabberID& remote,
00968         const char* name = 0, const NamedList* params = 0, const char* serverHost = 0);
00969 
00973     virtual void destroyed();
00974 
00982     virtual bool canProcess(u_int64_t time);
00983 
00989     virtual void process(u_int64_t time);
00990 
00998     virtual bool processRunning(XmlElement* xml, const JabberID& from,
00999         const JabberID& to);
01000 
01007     virtual void checkTimeouts(u_int64_t time);
01008 
01014     virtual void resetConnection(Socket* sock = 0);
01015 
01020     virtual XmlElement* buildStreamStart();
01021 
01029     virtual bool processStart(const XmlElement* xml, const JabberID& from,
01030         const JabberID& to);
01031 
01039     virtual bool processAuth(XmlElement* xml, const JabberID& from,
01040         const JabberID& to);
01041 
01049     virtual bool processCompressing(XmlElement* xml, const JabberID& from,
01050         const JabberID& to);
01051 
01059     virtual bool processRegister(XmlElement* xml, const JabberID& from,
01060         const JabberID& to);
01061 
01071     bool processStreamStart(const XmlElement* xml);
01072 
01079     bool handleCompressReq(XmlElement* xml);
01080 
01086     bool streamError(XmlElement* xml);
01087 
01095     bool getJids(XmlElement* xml, JabberID& from, JabberID& to);
01096 
01108     bool checkStanzaRecv(XmlElement* xml, JabberID& from, JabberID& to);
01109 
01115     void changeState(State newState, u_int64_t time = Time::msecNow());
01116 
01121     XmlElement* checkCompress();
01122 
01126     void checkPendingEvent();
01127 
01134     bool sendPending(bool streamOnly = false);
01135 
01142     bool writeSocket(const void* data, unsigned int& len);
01143 
01147     void updateFromRemoteDef();
01148 
01153     XMPPFeature* firstRequiredFeature();
01154 
01161     bool dropXml(XmlElement*& xml, const char* reason);
01162 
01170     inline bool destroyDropXml(XmlElement*& xml, XMPPError::Type error, const char* reason) {
01171             dropXml(xml,reason);
01172             terminate(0,true,0,error);
01173             return false;
01174         }
01175 
01180     void setFlags(int mask);
01181 
01186     void resetFlags(int mask);
01187 
01191     inline void setSecured() {
01192             setFlags(StreamSecured);
01193             m_features.remove(XMPPNamespace::Tls);
01194         }
01195 
01200     void setIdleTimer(u_int64_t msecNow = Time::msecNow());
01201 
01202     State m_state;                       // Stream state
01203     String m_id;                         // Stream id
01204     JabberID m_local;                    // Local peer's jid
01205     JabberID m_remote;                   // Remote peer's jid
01206     String m_serverHost;                 // Outgoing: optional server host (replaces remote domain when connecting)
01207     int m_flags;                         // Stream flags
01208     XMPPNamespace::Type m_xmlns;         // Stream namespace
01209     XMPPFeatureList m_features;          // Advertised features
01210     JBEvent* m_lastEvent;                // Last event generated by this stream
01211     ObjList m_events;                    // Queued events
01212     ObjList m_pending;                   // Pending outgoing elements
01213     // Timers
01214     u_int64_t m_setupTimeout;            // Overall stream setup timeout
01215     u_int64_t m_startTimeout;            // Incoming: wait stream start period
01216     u_int64_t m_pingTimeout;             // Sent ping timeout
01217     u_int64_t m_nextPing;                // Next ping
01218     u_int64_t m_idleTimeout;             // Stream idle timeout
01219     u_int64_t m_connectTimeout;          // Stream connect timeout
01220     //
01221     unsigned int m_restart;              // Remaining restarts
01222     u_int64_t m_timeToFillRestart;       // The next time to increase the restart counter
01223 
01224     String m_pingId;
01225 
01226 private:
01227     // Forbidden default constructor
01228     inline JBStream() {}
01229     // Process incoming elements in Challenge state
01230     // The element will be consumed
01231     // Return false if stream termination was initiated
01232     bool processChallenge(XmlElement* xml, const JabberID& from,
01233         const JabberID& to);
01234     // Process incoming 'auth' elements qualified by SASL namespace
01235     // The element will be consumed
01236     // Return false if stream termination was initiated
01237     bool processSaslAuth(XmlElement* xml, const JabberID& from,
01238         const JabberID& to);
01239     // Process received elements in Features state (incoming stream)
01240     // The element will be consumed
01241     // Return false if stream termination was initiated
01242     bool processFeaturesIn(XmlElement* xml, const JabberID& from,
01243         const JabberID& to);
01244     // Process received elements in Features state (outgoing stream)
01245     // The element will be consumed
01246     // Return false if stream termination was initiated
01247     bool processFeaturesOut(XmlElement* xml, const JabberID& from,
01248         const JabberID& to);
01249     // Process received elements in WaitTlsRsp state (outgoing stream)
01250     // The element will be consumed
01251     // Return false if stream termination was initiated
01252     bool processWaitTlsRsp(XmlElement* xml, const JabberID& from,
01253         const JabberID& to);
01254     // Set stream namespace from type
01255     void setXmlns();
01256     // Event termination notification
01257     // @param event The notifier. Ignored if it's not m_lastEvent
01258     void eventTerminated(const JBEvent* event);
01259     // Compress data to be sent (the pending stream xml buffer or pending stanza)
01260     // Return false on failure
01261     bool compress(XmlElementOut* xml = 0);
01262     // Reset connect status data
01263     void resetConnectStatus();
01264     // Postpone stream terminate until all parsed elements are processed
01265     // Terminate now if allowed
01266     // This method is thread safe
01267     void postponeTerminate(int location, bool destroy, int error, const char* reason);
01268     // Handle postponed termination. Return true if found
01269     // This method is not thread safe
01270     bool postponedTerminate();
01271     // Reset postponed terminate data
01272     inline void resetPostponedTerminate() {
01273             m_ppTerminateTimeout = 0;
01274             TelEngine::destruct(m_ppTerminate);
01275         }
01276 
01277     enum {
01278         SocketCanRead = 0x01,
01279         SocketReading = 0x02,
01280         SocketCanWrite = 0x10,
01281         SocketWriting = 0x20,
01282         SocketWaitReset = 0x80,
01283     };
01284     inline void socketSetCanRead(bool ok) {
01285             Lock lock(m_socketMutex);
01286             if (ok)
01287                 m_socketFlags |= SocketCanRead;
01288             else
01289                 m_socketFlags &= ~SocketCanRead;
01290         }
01291     inline void socketSetReading(bool ok) {
01292             if (ok)
01293                 m_socketFlags |= SocketReading;
01294             else
01295                 m_socketFlags &= ~SocketReading;
01296         }
01297     inline void socketSetCanWrite(bool ok) {
01298             Lock lock(m_socketMutex);
01299             if (ok)
01300                 m_socketFlags |= SocketCanWrite;
01301             else
01302                 m_socketFlags &= ~SocketCanWrite;
01303         }
01304     inline void socketSetWriting(bool ok) {
01305             if (ok)
01306                 m_socketFlags |= SocketWriting;
01307             else
01308                 m_socketFlags &= ~SocketWriting;
01309         }
01310     inline bool socketCanRead() const {
01311             return m_socket && (m_socketFlags & SocketCanRead) &&
01312                 !socketWaitReset();
01313         }
01314     inline bool socketCanWrite() const {
01315             return m_socket && (m_socketFlags & SocketCanWrite) &&
01316                 !socketWaitReset();
01317         }
01318     inline bool socketReading() const
01319         { return (m_socketFlags & SocketReading) != 0; }
01320     inline bool socketWriting() const
01321         { return (m_socketFlags & SocketWriting) != 0; }
01322     inline bool socketWaitReset() const
01323         { return 0 != (m_socketFlags & SocketWaitReset); }
01324 
01325     JBEngine* m_engine;                  // The owner of this stream
01326     int m_type;                          // Stream type
01327     bool m_incoming;                     // Stream direction
01328     String m_name;                       // Local (internal) name
01329     JBEvent* m_terminateEvent;           // Pending terminate event
01330     NamedList* m_ppTerminate;            // Postponed terminate parameters
01331     u_int64_t m_ppTerminateTimeout;      // Postponed terminate timeout
01332     // Pending outgoing XML
01333     String m_outStreamXml;
01334     DataBlock m_outStreamXmlCompress;
01335     DataBlock m_outXmlCompress;
01336     // Connection related data
01337     XmlDomParser* m_xmlDom;
01338     Socket* m_socket;
01339     char m_socketFlags;                  // Socket flags: 0: unavailable
01340     Mutex m_socketMutex;                 // Protect the socket and parser
01341     String m_connectAddr;                // Remote ip to connect to
01342     int m_connectPort;                   // Remote port to connect to
01343     String m_localIp;                    // Local ip to bind when connecting
01344     Compressor* m_compress;
01345     int m_connectStatus;                 // Current connect stream status
01346     ObjList m_connectSrvs;               // Current connect stream SRV records
01347 };
01348 
01349 
01354 class YJABBER_API JBClientStream : public JBStream
01355 {
01356     YCLASS(JBClientStream,JBStream)
01357     friend class JBStream;
01358 public:
01365     JBClientStream(JBEngine* engine, Socket* socket, bool ssl = false);
01366 
01376     JBClientStream(JBEngine* engine, const JabberID& jid, const String& account,
01377         const NamedList& params, const char* name = 0, const char* serverHost = 0);
01378 
01383     inline const String& account() const
01384         { return m_account; }
01385 
01390     inline GenObject* userData()
01391         { return m_userData; }
01392 
01398     inline void userData(GenObject* data) {
01399             Lock lock(this);
01400             TelEngine::destruct(m_userData);
01401             m_userData = data;
01402         }
01403 
01408     virtual JBClientStream* clientStream()
01409         { return this; }
01410 
01419     void bind(const String& resource, const char* id,
01420         XMPPError::Type error = XMPPError::NoError);
01421 
01431     bool requestRegister(bool data, bool set = true,
01432         const String& newPass = String::empty());
01433 
01434 protected:
01442     virtual bool processRunning(XmlElement* xml, const JabberID& from,
01443         const JabberID& to);
01444 
01452     virtual bool processStart(const XmlElement* xml, const JabberID& from,
01453         const JabberID& to);
01454 
01462     virtual bool processAuth(XmlElement* xml, const JabberID& from,
01463         const JabberID& to);
01464 
01472     virtual bool processRegister(XmlElement* xml, const JabberID& from,
01473         const JabberID& to);
01474 
01478     virtual void destroyed();
01479 
01484     bool startAuth();
01485 
01490     bool bind();
01491 
01492 private:
01493     inline bool isRegisterId(XmlElement& xml) {
01494             if (!m_registerReq)
01495                 return false;
01496             String* id = xml.getAttribute("id");
01497             return id && id->length() == 1 && (*id)[0] == m_registerReq;
01498         }
01499 
01500     String m_account;                    // Stream account
01501     GenObject* m_userData;               // User (upper layer) data
01502     String m_password;                   // The password
01503     String m_newPassword;                // New password
01504     char m_registerReq;                  // Register requested. 1(data) 2(register) 3(remove)
01505 };
01506 
01507 
01512 class YJABBER_API JBServerStream : public JBStream
01513 {
01514     YCLASS(JBServerStream,JBStream)
01515     friend class JBStream;
01516 public:
01523     JBServerStream(JBEngine* engine, Socket* socket, bool component = false);
01524 
01535     JBServerStream(JBEngine* engine, const JabberID& local, const JabberID& remote,
01536         const char* dbId = 0, const char* dbKey = 0, bool dbOnly = false,
01537         const NamedList* params = 0);
01538 
01547     JBServerStream(JBEngine* engine, const JabberID& local, const JabberID& remote,
01548         const String* name = 0, const NamedList* params = 0);
01549 
01554     inline bool dialback() const
01555         { return outgoing() && flag(DialbackOnly); }
01556 
01562     inline const NamedList& remoteDomains() const
01563         { return m_remoteDomains; }
01564 
01572     inline bool hasRemoteDomain(const String& domain, bool auth = true) {
01573             NamedString* tmp = m_remoteDomains.getParam(domain);
01574             return tmp && (!auth || tmp->null());
01575         }
01576 
01581     inline NamedString* takeDb() {
01582             Lock lock(this);
01583             NamedString* tmp = m_dbKey;
01584             m_dbKey = 0;
01585             return tmp;
01586         }
01587 
01592     virtual JBServerStream* serverStream()
01593         { return this; }
01594 
01604     bool sendDbVerify(const char* from, const char* to, const char* id,
01605         XMPPError::Type rsp = XMPPError::NoError);
01606 
01616     bool sendDbResult(const JabberID& from, const JabberID& to,
01617         XMPPError::Type rsp = XMPPError::NoError);
01618 
01623     bool sendDialback();
01624 
01632     bool startComp(const String& local = String::empty(), const String& remote = String::empty());
01633 
01634 protected:
01638     virtual void destroyed();
01639 
01647     virtual bool processRunning(XmlElement* xml, const JabberID& from,
01648         const JabberID& to);
01649 
01654     virtual XmlElement* buildStreamStart();
01655 
01663     virtual bool processStart(const XmlElement* xml, const JabberID& from,
01664         const JabberID& to);
01665 
01673     virtual bool processAuth(XmlElement* xml, const JabberID& from,
01674         const JabberID& to);
01675 
01683     bool processDbResult(XmlElement* xml, const JabberID& from, const JabberID& to);
01684 
01690     inline void adjustDbRsp(XMPPError::Type& rsp) {
01691             Lock lock(this);
01692             if (!flag(StreamRemoteVer1) && rsp != XMPPError::NoError)
01693                 rsp = XMPPError::NotAuthorized;
01694         }
01695 
01700     NamedList m_remoteDomains;
01701 
01702 private:
01703     NamedString* m_dbKey;                // Outgoing: initial dialback key to check
01704     String m_password;                   // Outgoing component: password
01705 };
01706 
01707 
01712 class YJABBER_API JBClusterStream : public JBStream
01713 {
01714     YCLASS(JBClusterStream,JBStream)
01715     friend class JBStream;
01716 public:
01722     JBClusterStream(JBEngine* engine, Socket* socket);
01723 
01731     JBClusterStream(JBEngine* engine, const JabberID& local, const JabberID& remote,
01732         const NamedList* params = 0);
01733 
01738     virtual JBClusterStream* clusterStream()
01739         { return this; }
01740 
01741 protected:
01746     virtual XmlElement* buildStreamStart();
01747 
01755     virtual bool processStart(const XmlElement* xml, const JabberID& from,
01756         const JabberID& to);
01757 
01765     virtual bool processRunning(XmlElement* xml, const JabberID& from,
01766         const JabberID& to);
01767 };
01768 
01769 
01775 class YJABBER_API JBRemoteDomainDef : public String
01776 {
01777     YCLASS(JBRemoteDomainDef,String)
01778 public:
01783     inline JBRemoteDomainDef(const char* domain = 0)
01784         : String(domain), m_port(0), m_flags(0)
01785         {}
01786 
01790     String m_address;
01791 
01795     int m_port;
01796 
01800     int m_flags;
01801 };
01802 
01803 
01809 class YJABBER_API JBConnect : public GenObject
01810 {
01811     YCLASS(JBConnect,GenObject)
01812 public:
01813     enum Status {
01814         Start = 0,
01815         Address,                         // Use configured address
01816         Srv,                             // Use SRV records
01817         Domain                           // Use stream remote domain
01818     };
01819 
01824     JBConnect(const JBStream& stream);
01825 
01829     virtual ~JBConnect();
01830 
01834     virtual void stopConnect();
01835 
01840     virtual const String& toString() const;
01841 
01845     static const TokenDict s_statusName[];
01846 
01847 protected:
01855     void connect();
01856 
01857 private:
01858     // No default constructor
01859     inline JBConnect()
01860         {}
01861     // Check if exiting. Release socket if exiting
01862     bool exiting(Socket*& sock);
01863     // Create and try to connect a socket. Return it on success
01864     // Set stop on fatal failure and return 0
01865     Socket* connect(const char* addr, int port, bool& stop);
01866     // Notify termination, remove from engine
01867     void terminated(Socket* sock, bool final);
01868     // Notify connecting to the stream. Return false if stream vanished
01869     bool notifyConnecting(bool sync, bool useCurrentStat = false);
01870     // Delete a socket and zero the pointer
01871     void deleteSocket(Socket*& sock);
01872     // Advance connect status
01873     void advanceStatus();
01874 
01875     int m_status;                        // Current status
01876     String m_domain;                     // Remote domain
01877     String m_address;                    // Remote ip address
01878     int m_port;                          // Port to connect to
01879     JBEngine* m_engine;                  // The engine owning this connector
01880     String m_stream;                     // Stream name
01881     JBStream::Type m_streamType;         // Stream type
01882     String m_localIp;                    // Local ip to bind when connecting
01883     ObjList m_srvs;                      // SRV records list
01884 };
01885 
01886 
01891 class YJABBER_API JBEngine : public DebugEnabler, public Mutex, public GenObject
01892 {
01893     YCLASS(JBEngine,GenObject)
01894     friend class JBStream;
01895     friend class JBConnect;
01896     friend class JBStreamSetProcessor;
01897 public:
01902     JBEngine(const char* name = "jbengine");
01903 
01907     virtual ~JBEngine();
01908 
01913     inline unsigned int streamReadBuffer() const
01914         { return m_streamReadBuffer; }
01915 
01920     inline bool exiting() const
01921         { return m_exiting; }
01922 
01926     inline void setExiting() {
01927             if (m_exiting)
01928                 return;
01929             m_exiting = true;
01930             dropAll(JBStream::TypeCount,JabberID::empty(),JabberID::empty(),
01931                 XMPPError::Shutdown);
01932         }
01933 
01938     inline bool hasClientTls() const
01939         { return m_hasClientTls; }
01940 
01947     inline JBRemoteDomainDef* remoteDomainDef(const String& domain) {
01948             ObjList* o = m_remoteDomains.find(domain);
01949             return o ? static_cast<JBRemoteDomainDef*>(o->get()) : &m_remoteDomain;
01950         }
01951 
01955     virtual void destruct();
01956 
01961     virtual void initialize(const NamedList& params);
01962 
01968     virtual void cleanup(bool final = false, bool waitTerminate = true);
01969 
01979     bool acceptConn(Socket* sock, SocketAddr& remote, JBStream::Type t, bool ssl = false);
01980 
01987     virtual JBStream* findStream(const String& id,
01988         JBStream::Type hint = JBStream::TypeCount);
01989 
01999     ObjList* findClientStreams(bool in, const JabberID& jid, int flags = 0xffffffff);
02000 
02012     ObjList* findClientStreams(bool in, const JabberID& jid, const ObjList& resources,
02013         int flags = 0xffffffff);
02014 
02022     JBClientStream* findClientStream(bool in, const JabberID& jid);
02023 
02033     virtual unsigned int dropAll(JBStream::Type type = JBStream::TypeCount,
02034         const JabberID& local = JabberID::empty(),
02035         const JabberID& remote = JabberID::empty(),
02036         XMPPError::Type error = XMPPError::NoError, const char* reason = 0);
02037 
02043     virtual void buildStreamName(String& name, const JBStream* stream)
02044         {}
02045 
02051     virtual bool hasDomain(const String& domain)
02052         { return false; }
02053 
02059     virtual void processEvent(JBEvent* ev);
02060 
02068     virtual void returnEvent(JBEvent* ev, XMPPError::Type error = XMPPError::NoError,
02069         const char* reason = 0);
02070 
02075     virtual void encryptStream(JBStream* stream);
02076 
02081     virtual void connectStream(JBStream* stream);
02082 
02088     virtual void compressStream(JBStream* stream, const String& formats);
02089 
02097     virtual void buildDialbackKey(const String& id, const String& local,
02098         const String& remote, String& key);
02099 
02105     bool checkDupId(JBStream* stream);
02106 
02113     virtual void printXml(const JBStream* stream, bool send, XmlChild& xml) const;
02114 
02121     virtual void printXml(const JBStream* stream, bool send, XmlFragment& frag) const;
02122 
02123 protected:
02128     virtual void addStream(JBStream* stream);
02129 
02136     virtual void removeStream(JBStream* stream, bool delObj = true);
02137 
02142     virtual void stopStreamSets(bool waitTerminate = true)
02143         {}
02144 
02151     virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type)
02152         {}
02153 
02160     inline void getStreamLists(RefPointer<JBStreamSetList> list[JBStream::TypeCount],
02161         int type = JBStream::TypeCount) {
02162             if (type == JBStream::c2s || type == JBStream::TypeCount)
02163                 getStreamList(list[JBStream::c2s],JBStream::c2s);
02164             if (type == JBStream::s2s || type == JBStream::TypeCount)
02165                 getStreamList(list[JBStream::s2s],JBStream::s2s);
02166             if (type == JBStream::comp || type == JBStream::TypeCount)
02167                 getStreamList(list[JBStream::comp],JBStream::comp);
02168             if (type == JBStream::cluster || type == JBStream::TypeCount)
02169                 getStreamList(list[JBStream::cluster],JBStream::cluster);
02170         }
02171 
02178     JBStream* findStream(const String& id, JBStreamSetList* list);
02179 
02180     bool m_exiting;                      // Engine exiting flag
02181     JBRemoteDomainDef m_remoteDomain;    // Default remote domain definition
02182     ObjList m_remoteDomains;             // Remote domain definitions
02183     unsigned char m_restartMax;          // Maximum value for stream restart counter
02184     unsigned int m_restartUpdInterval;   // Update interval for stream restart counter
02185     unsigned int m_setupTimeout;         // Overall stream setup timeout
02186     unsigned int m_startTimeout;         // Wait stream start period
02187     unsigned int m_connectTimeout;       // Outgoing: socket connect timeout
02188     unsigned int m_srvTimeout;           // SRV query timeout
02189     unsigned int m_pingInterval;         // Stream idle interval (no data received)
02190     unsigned int m_pingTimeout;          // Sent ping timeout
02191     unsigned int m_idleTimeout;          // Stream idle timeout (nothing sent or received)
02192     unsigned int m_pptTimeoutC2s;        // Client streams postpone termination intervals
02193     unsigned int m_pptTimeout;           // Non client streams postpone stream termination intervals
02194     unsigned int m_streamReadBuffer;     // Stream read buffer length
02195     unsigned int m_maxIncompleteXml;     // Maximum length of an incomplete xml
02196     bool m_hasClientTls;                 // True if TLS is available for outgoing streams
02197     int m_printXml;                      // Print XML data to output
02198     bool m_initialized;                  // True if already initialized
02199 
02200 private:
02201     // Add/remove a connect stream thread when started/stopped
02202     void connectStatus(JBConnect* conn, bool started);
02203     // Stop a connect stream
02204     void stopConnect(const String& name);
02205 
02206     ObjList m_connect;                   // Connecting streams
02207 };
02208 
02213 class YJABBER_API JBServerEngine : public JBEngine
02214 {
02215     YCLASS(JBServerEngine,JBEngine)
02216 public:
02221     JBServerEngine(const char* name = "jbserverengine");
02222 
02226     ~JBServerEngine();
02227 
02233     virtual void cleanup(bool final = false, bool waitTerminate = true);
02234 
02240     virtual void buildStreamName(String& name, const JBStream* stream)
02241         { name << "stream/" << getStreamIndex(); }
02242 
02254     JBServerStream* findServerStream(const String& local, const String& remote, bool out,
02255         bool auth = true);
02256 
02267     JBServerStream* createServerStream(const String& local, const String& remote,
02268         const char* dbId = 0, const char* dbKey = 0, bool dbOnly = false,
02269         const NamedList* params = 0);
02270 
02279     JBServerStream* createCompStream(const String& name, const String& local, const String& remote,
02280         const NamedList* params = 0);
02281 
02289     JBClusterStream* findClusterStream(const String& remote, JBClusterStream* skip = 0);
02290 
02299     virtual JBClusterStream* createClusterStream(const String& local,
02300         const String& remote, const NamedList* params = 0);
02301 
02310     unsigned int terminateClientStreams(const JabberID& jid,
02311         XMPPError::Type error = XMPPError::NoError, const char* reason = 0);
02312 
02313 protected:
02318     virtual void addStream(JBStream* stream);
02319 
02326     virtual void removeStream(JBStream* stream, bool delObj = true);
02327 
02332     virtual void stopStreamSets(bool waitTerminate = true);
02333 
02339     virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type);
02340 
02347     virtual void getStreamListsType(int type, RefPointer<JBStreamSetList>& recv,
02348         RefPointer<JBStreamSetList>& process);
02349 
02354     inline unsigned int getStreamIndex() {
02355             Lock lock(this);
02356             return ++m_streamIndex;
02357         }
02358 
02359     unsigned int m_streamIndex;          // Index used to build stream name
02360     JBStreamSetList* m_c2sReceive;       // c2s streams receive list
02361     JBStreamSetList* m_c2sProcess;       // c2s streams process list
02362     JBStreamSetList* m_s2sReceive;       // s2s streams receive list
02363     JBStreamSetList* m_s2sProcess;       // s2s streams process list
02364     JBStreamSetList* m_compReceive;      // comp streams receive list
02365     JBStreamSetList* m_compProcess;      // comp streams process list
02366     JBStreamSetList* m_clusterReceive;   // cluster streams receive list
02367     JBStreamSetList* m_clusterProcess;   // cluster streams process list
02368 };
02369 
02374 class YJABBER_API JBClientEngine : public JBEngine
02375 {
02376     YCLASS(JBClientEngine,JBEngine)
02377 public:
02382     JBClientEngine(const char* name = "jbclientengine");
02383 
02387     ~JBClientEngine();
02388 
02394     virtual void cleanup(bool final = false, bool waitTerminate = true);
02395 
02401     JBClientStream* findAccount(const String& account);
02402 
02410     JBClientStream* create(const String& account, const NamedList& params,
02411         const String& name = String::empty());
02412 
02418     virtual void getStreamList(RefPointer<JBStreamSetList>& list, int type);
02419 
02420 protected:
02425     virtual void addStream(JBStream* stream);
02426 
02433     virtual void removeStream(JBStream* stream, bool delObj = true);
02434 
02439     virtual void stopStreamSets(bool waitTerminate = true);
02440 
02441     JBStreamSetList* m_receive;          // Streams receive list
02442     JBStreamSetList* m_process;          // Streams process list
02443 };
02444 
02451 class YJABBER_API JBStreamSet : public GenObject, public Mutex
02452 {
02453     YCLASS(JBStreamSet,GenObject);
02454     friend class JBStreamSetList;
02455 public:
02459     virtual ~JBStreamSet();
02460 
02466     inline ObjList& clients()
02467         { return m_clients; }
02468 
02475     virtual bool add(JBStream* client);
02476 
02484     virtual bool remove(JBStream* client, bool delObj = true);
02485 
02494     unsigned int dropAll(const JabberID& local = JabberID::empty(),
02495         const JabberID& remote = JabberID::empty(),
02496         XMPPError::Type error = XMPPError::NoError, const char* reason = 0);
02497 
02502     void run();
02503 
02508     virtual bool start();
02509 
02513     virtual void stop();
02514 
02515 protected:
02520     JBStreamSet(JBStreamSetList* owner);
02521 
02529     virtual bool process(JBStream& stream) = 0;
02530 
02531     bool m_changed;                      // List changed flag
02532     bool m_exiting;                      // The thread is exiting (don't accept clients)
02533     JBStreamSetList* m_owner;            // The list owning this set
02534     ObjList m_clients;                   // The streams list
02535 
02536 private:
02537     JBStreamSet() {}                     // Private default constructor (forbidden)
02538 };
02539 
02540 
02545 class YJABBER_API JBStreamSetProcessor : public JBStreamSet
02546 {
02547     YCLASS(JBStreamSetProcessor,JBStreamSet);
02548 protected:
02553     inline JBStreamSetProcessor(JBStreamSetList* owner)
02554         : JBStreamSet(owner)
02555         {}
02556 
02565     virtual bool process(JBStream& stream);
02566 };
02567 
02568 
02573 class YJABBER_API JBStreamSetReceive : public JBStreamSet
02574 {
02575     YCLASS(JBStreamSetReceive,JBStreamSet);
02576 protected:
02581     JBStreamSetReceive(JBStreamSetList* owner);
02582 
02590     virtual bool process(JBStream& stream);
02591 
02592 protected:
02593     DataBlock m_buffer;                  // Read buffer
02594 };
02595 
02596 
02602 class YJABBER_API JBStreamSetList : public RefObject, public Mutex
02603 {
02604     YCLASS(JBStreamSetList,RefObject);
02605     friend class JBStreamSet;
02606 public:
02614     JBStreamSetList(JBEngine* engine, unsigned int max, unsigned int sleepMs,
02615         const char* name);
02616 
02622     inline ObjList& sets()
02623         { return m_sets; }
02624 
02628     virtual ~JBStreamSetList();
02629 
02634     inline unsigned int maxStreams() const
02635         { return m_max; }
02636 
02641     inline unsigned int streamCount() const
02642         { return m_streamCount; }
02643 
02648     inline JBEngine* engine() const
02649         { return m_engine; }
02650 
02656     bool add(JBStream* client);
02657 
02664     void remove(JBStream* client, bool delObj = true);
02665 
02671     void stop(JBStreamSet* set = 0, bool waitTerminate = true);
02672 
02677     virtual const String& toString() const;
02678 
02679 protected:
02683     virtual void destroyed();
02684 
02689     void remove(JBStreamSet* set);
02690 
02695     virtual JBStreamSet* build();
02696 
02697     JBEngine* m_engine;                  // The engine owning this list
02698     String m_name;                       // List name
02699     unsigned int m_max;                  // The maximum number of streams per set
02700     unsigned int m_sleepMs;              // Time to sleep if nothig processed
02701     ObjList m_sets;                      // The sets list
02702 
02703 private:
02704     JBStreamSetList() {}                 // Private default constructor (forbidden)
02705 
02706     unsigned int m_streamCount;          // Current number of streams in this list
02707 };
02708 
02709 
02715 class YJABBER_API JBEntityCaps : public String
02716 {
02717     YCLASS(JBEntityCaps,String);
02718 public:
02722     enum {
02723         Ver1_3 = 1,  // Version lower then 1.4 (m_data is the node version + advertised extensions)
02724         Ver1_4 = 2,  // Version 1.4 or greater (m_data is the SHA-1 hash of features and identities)
02725     };
02726 
02734     inline JBEntityCaps(const char* id, char version, const char* node, const char* data)
02735         : String(id),
02736         m_version(version), m_node(node), m_data(data)
02737         {}
02738 
02743     inline bool hasAudio() {
02744             return m_features.get(XMPPNamespace::JingleAppsRtpAudio) ||
02745                 m_features.get(XMPPNamespace::JingleAudio) ||
02746                 m_features.get(XMPPNamespace::JingleVoiceV1);
02747         }
02748 
02757     static inline void buildId(String& buf, char version, const char* node,
02758         const char* data, String* ext = 0)
02759         { buf << (int)version << node << data << (ext ? ext->c_str() : ""); }
02760 
02761     char m_version;
02762     String m_node;
02763     String m_data;
02764     XMPPFeatureList m_features;
02765 
02766 private:
02767     JBEntityCaps() {}
02768 };
02769 
02770 
02776 class YJABBER_API JBEntityCapsList : public ObjList, public Mutex
02777 {
02778     YCLASS(JBEntityCapsList,ObjList);
02779 public:
02783     inline JBEntityCapsList()
02784         : Mutex(true,"JBEntityCapsList"), m_enable(true), m_reqIndex(0)
02785         { m_reqPrefix << "xep0115" << (unsigned int)Time::msecNow() << "_"; }
02786 
02792     inline JBEntityCaps* findCaps(const String& id) {
02793             for (ObjList* o = skipNull(); o; o = o->skipNext())
02794                 if (o->get()->toString() == id)
02795                     return static_cast<JBEntityCaps*>(o->get());
02796             return 0;
02797         }
02798 
02804     void expire(u_int64_t msecNow = Time::msecNow());
02805 
02814     bool processRsp(XmlElement* rsp, const String& id, bool ok);
02815 
02827     void requestCaps(JBStream* stream, const char* from, const char* to, const String& id,
02828         char version, const char* node, const char* data);
02829 
02836     XmlDocument* toDocument(const char* rootName = "entitycaps");
02837 
02845     void fromDocument(XmlDocument& doc, const char* rootName = "entitycaps");
02846 
02859     virtual bool processCaps(String& capsId, XmlElement* xml, JBStream* stream,
02860         const char* from, const char* to);
02861 
02868     inline void addCaps(NamedList& list, const String& id) {
02869             Lock lock(this);
02870             JBEntityCaps* caps = findCaps(id);
02871             if (caps)
02872                 addCaps(list,*caps);
02873         }
02874 
02881     virtual void addCaps(NamedList& list, JBEntityCaps& caps);
02882 
02890     bool loadXmlDoc(const char* file, DebugEnabler* enabler = 0);
02891 
02899     bool saveXmlDoc(const char* file, DebugEnabler* enabler = 0);
02900 
02910     static bool decodeCaps(const XmlElement& xml, char& version, String*& node,
02911         String*& ver, String*& ext);
02912 
02916     bool m_enable;
02917 
02918 protected:
02924     virtual void capsAdded(JBEntityCaps* caps)
02925         {}
02926 
02927     unsigned int m_reqIndex;             // Disco info request index
02928     String m_reqPrefix;                  // Prefix for disco info stanza id
02929     ObjList m_requests;                  // List of sent disco info requests
02930 };
02931 
02932 }; // namespace TelEngine
02933 
02934 #endif /* __YATEJABBER_H */
02935 
02936 /* vi: set ts=8 sw=4 sts=4 noet: */