# Source: libs/yjabber/yatejingle.h |
Annotated List
Files
Globals
Hierarchy
Index

    /**
     * yatejingle.h
     * Yet Another Jingle Stack
     * This file is part of the YATE Project http://YATE.null.ro
     *
     * Yet Another Telephony Engine - a fully featured software PBX and IVR
     * Copyright (C) 2004-2014 Null Team
     *
     * This software is distributed under multiple licenses;
     * see the COPYING file in the main directory for licensing
     * information for this specific distribution.
     *
     * This use of this software may be subject to additional restrictions.
     * See the LEGAL file in the main directory for details.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     */

    #ifndef __YATEJINGLE_H
    #define __YATEJINGLE_H

    #include
    #include

    /**
     * Holds all Telephony Engine related classes.
     */
    namespace TelEngine {

    class JGRtpMedia;                        // A Jingle RTP data payload
    class JGCrypto;                          // Content crypto data
    class JGRtpMediaList;                    // A list of Jingle RTP data payloads
    class JGRtpCandidate;                    // A RTP transport candidate
    class JGRtpCandidates;                   // A list of RTP transport candidates
    class JGSessionContent;                  // A Jingle session content
    class JGStreamHost;                      // A Jingle file transfer stream host
    class JGSession;                         // A basic Jingle session
    class JGSession0;                        // A session implementing the old jingle protocol
    class JGSession1;                        // The version 1 of a jingle session
    class JGEvent;                           // An event generated by a Jingle session
    class JGEngine;                          // The Jingle engine
    class JGSentStanza;                      // Sent stanza timeout info

    /**
     * This class holds a Jingle data payload description
     * @short A Jingle data payload
     */
    class YJABBER_API JGRtpMedia : public GenObject
    {
    public:
        /**
         * Constructor. Fill this object from the given attributes
         * @param id The 'id' attribute
         * @param name The 'name' attribute
         * @param clockrate The 'clockrate' attribute
         * @param synonym Application synonym for this payload
         * @param channels Optional 'channels' attribute (the number of channels)
         * @param pTime Optional "ptime" attribute (packet time)
         * @param maxPTime Optional "maxptime" attribute (maximum packet time)
         * @param bitRate Optional "bitrate" attribute
         */
        inline JGRtpMedia(const char* id, const char* name, const char* clockrate,
    	const char* synonym, const char* channels = 0,
    	const char* pTime = 0, const char* maxPTime = 0, const char* bitRate = 0)
    	: m_params("")
    	{ set(id,name,clockrate,synonym,channels,pTime,maxPTime,bitRate); }

        /**
         * Constructor. Fill this object from an XML element
         * @param xml The element to fill from
         */
        inline JGRtpMedia(XmlElement* xml)
    	: m_params("")
    	{ fromXml(xml); }

        /**
         * Copy constructor
         */
        inline JGRtpMedia(const JGRtpMedia& src)
    	: m_params("") {
    	    set(src.m_id,src.m_name,src.m_clockrate,src.m_synonym,src.m_channels,
    		src.m_pTime,src.m_maxPTime,src.m_bitRate);
    	    m_params = src.m_params;
    	}

        /**
         * Set the data
         * @param id The 'id' attribute
         * @param name The 'name' attribute
         * @param clockrate The 'clockrate' attribute
         * @param synonym Application synonym for this payload
         * @param channels Optional 'channels' attribute (the number of channels)
         * @param pTime Optional "ptime" attribute (packet time)
         * @param maxPTime Optional "maxptime" attribute (maximum packet time)
         * @param bitRate Optional "bitrate" attribute
         */
        inline void set(const char* id, const char* name, const char* clockrate,
    	const char* synonym = 0, const char* channels = 0,
    	const char* pTime = 0, const char* maxPTime = 0, const char* bitRate = 0) {
    	    m_id = id;
    	    m_name = name;
    	    m_clockrate = clockrate;
    	    m_synonym = synonym;
    	    m_channels = channels;
    	    m_pTime = pTime;
    	    m_maxPTime = maxPTime;
    	    m_bitRate = bitRate;
    	    m_params.clearParams();
    	}

        /**
         * Get the string repreasentation (id) of this payload
         * @return The string repreasentation (id) of this payload
         */
        virtual const String& toString() const
    	{ return m_id; }

        /**
         * Create a 'payload-type' element from this object
         * @return Valid XmlElement pointer
         */
        XmlElement* toXml() const;

        /**
         * Fill this object from a given element
         * @param xml The element
         */
        void fromXml(XmlElement* xml);

        /**
         * The numeric id of this payload
         */
        String m_id;

        /**
         * The Jingle name of this payload
         */
        String m_name;

        /**
         * The clockrate of this payload
         */
        String m_clockrate;

        /**
         * A synonym of this payload's name
         */
        String m_synonym;

        /**
         * The number of channels
         */
        String m_channels;

        /**
         * Packet time
         */
        String m_pTime;

        /**
         * Maximum packet time
         */
        String m_maxPTime;

        /**
         * Data bit rate
         */
        String m_bitRate;

        /**
         * List of optional parameters
         */
        NamedList m_params;
    };

    /**
     * This class holds a content description's crypto data.
     * The tag is kept in the String component
     * @short Content crypto data
     */
    class YJABBER_API JGCrypto : public String
    {
    public:
        /**
         * Constructor
         * @param tag The tag parameter
         * @param suite The crypto-suite paramter
         * @param key The key-params parameter
         * @param session The session-param parameter
         */
        inline JGCrypto(const char* tag = "1", const char* suite = 0,
    	const char* key = 0, const char* session = 0)
    	: String(tag),
    	m_suite(suite), m_keyParams(key), m_sessionParams(session)
    	{}

        /**
         * Constructor. Build this element from a received element
         * @param xml The received xml element
         */
        inline JGCrypto(const XmlElement* xml)
    	{ fromXml(xml); }

        /**
         * Create a 'crypto' element from this object
         * @return Valid XmlElement pointer
         */
        XmlElement* toXml() const;

        /**
         * Build this element from a received element
         * @param xml The received xml element
         */
        void fromXml(const XmlElement* xml);

        /**
         * Build an 'encryption' element from a list of crypto objects
         * @param list The list of crypto objects
         * @param required True if encryption is required
         * @return XmlElement pointer or 0 if the list is empty
         */
        static XmlElement* buildEncryption(const ObjList& list, bool required);

        /**
         * Decode an 'encryption' element. Clear the list before starting
         * @param xml The element to decode
         * @param list The list to be filled with crypto objects
         * @param required Variable to be filled with the value of the 'required' attribute
         */
        static void decodeEncryption(const XmlElement* xml, ObjList& list, bool& required);

        String m_suite;
        String m_keyParams;
        String m_sessionParams;
    };

    /**
     * Hold a list of RTP data payloads
     * @short A List of Jingle RTP data payloads
     */
    class YJABBER_API JGRtpMediaList : public ObjList
    {
    public:
        /**
         * Media type enumeration
         */
        enum Media {
    	MediaMissing = -1,
    	MediaUnknown = 0,
    	Audio        = 1,
        };

        /**
         * Constructor
         * @param m Media type as enumeration
         * @param cryptoRequired True to require media encryption
         */
        inline JGRtpMediaList(Media m = MediaMissing, bool cryptoRequired = false)
    	: m_media(m), m_bandwidth(0), m_cryptoRequired(cryptoRequired), m_ready(false),
    	m_telEvent(101), m_telEventName("telephone-event")
    	{}

        /**
         * Destructor
         */
        inline ~JGRtpMediaList()
    	{ TelEngine::destruct(m_bandwidth); }

        /**
         * Get the media type of the payloads owned by this list
         * @return Media type as enumeration
         */
        inline Media media() const
    	{ return m_media; }

        /**
         * Append a new data payload
         * @param id The 'id' attribute
         * @param name The 'name' attribute
         * @param clockrate The 'clockrate' attribute
         * @param synonym Optional application synonym for the payload
         * @param channels Optional 'channels' attribute (the number of channels)
         * @param pTime Optional "ptime" attribute (packet time)
         * @param maxPTime Optional "maxptime" attribute (maximum packet time)
         * @param bitRate Optional "bitrate" attribute
         */
        inline void add(const char* id, const char* name, const char* clockrate,
    	const char* synonym = 0, const char* channels = 0,
    	const char* pTime = 0, const char* maxPTime = 0, const char* bitRate = 0)
    	{ append(new JGRtpMedia(id,name,clockrate,synonym,channels,pTime,maxPTime,bitRate)); }

        /**
         * Reset the list and data
         */
        void reset();

        /**
         * Set media type and payloads from another list
         * @param src Media list to copy into this one
         * @param only Optional list of synonyms to set if found in src.
         *  Copy the whole list if this parameter is empty
         */
        void setMedia(const JGRtpMediaList& src, const String& only = String::empty());

        /**
         * Filter media list preserving only some formats
         * @param only List of synonyms to preserve, do not filter media if this parameter is empty
         */
        void filterMedia(const String& only);

        /**
         * Find a data payload by its id
         * @param id Identifier of media to find
         * @return JGRtpMedia pointer or 0 if not found
         */
        JGRtpMedia* findMedia(const String& id);

        /**
         * Find a data payload by its synonym
         * @param value The value to compare with
         * @return JGRtpMedia pointer or 0 if not found
         */
        JGRtpMedia* findSynonym(const String& value) const;

        /**
         * Create a 'description' element and add payload children to it
         * @return Valid XmlElement pointer
         */
        XmlElement* toXml() const;

        /**
         * Fill this list from an XML element's children. Clear before attempting to fill
         * @param xml The source XML element
         */
        void fromXml(XmlElement* xml);

        /**
         * Create a list from data payloads
         * @param dest Destination string
         * @param synonym True to create from synonyms, false to create from names
         * @param sep List item separator
         * @return False if the list is empty
         */
        bool createList(String& dest, bool synonym, const char* sep = ",");

        /**
         * Build and add telephone-event media child to a parent xml element.
         * Add a second telephone event media child if set
         * @param xml Parent element
         * @param name Optional event name. Defaults to set event name
         */
        void addTelEvent(XmlElement* xml, const char* name = 0) const;

        /**
         * The list of media type names
         */
        static const TokenDict s_media[];

        /**
         * The media type
         */
        Media m_media;

        /**
         * Synchronization source
         */
        String m_ssrc;

        /**
         * Optional SDP media bandwith. The name of the string keeps the type ('bwtype')
         * and its value keeps the actual bandwith
         */
        NamedString* m_bandwidth;

        /**
         * Crypto (SRTP) params
         */
        bool m_cryptoRequired;
        ObjList m_cryptoLocal;
        ObjList m_cryptoRemote;

        /**
         * Flag indicating wether media was negotiated
         */
        bool m_ready;

        /**
         * Telephone event payload id
         */
        int m_telEvent;

        /**
         * Telephone event payload name
         */
        String m_telEventName;

        /**
         * Second telephone event payload name
         */
        String m_telEventName2;
    };

    /**
     * This class holds a RTP transport candidate
     * @short A RTP transport candidate
     */
    class YJABBER_API JGRtpCandidate : public String
    {
    public:
        /**
         * Constructor
         */
        inline JGRtpCandidate(const char* id, const char* component = "1",
    	unsigned int generation = 0, unsigned int net = 0, int prio = 0)
    	: String(id),
    	m_port(0), m_component(component), m_generation(generation),
    	m_network(net), m_priority(prio), m_protocol("udp"), m_type("host")
    	{}

        /**
         * Constructor. Build a candidate from received data
         * @param xml Received xml element
         * @param container The transport container
         */
        inline JGRtpCandidate(XmlElement* xml, const JGRtpCandidates& container)
    	{ fromXml(xml,container); }

        /**
         * Create a 'candidate' element from this object using local address/port
         * @param container The transport container
         * @return Valid XmlElement pointer if type is a known one
         */
        virtual XmlElement* toXml(const JGRtpCandidates& container) const;

        /**
         * Fill this object from a candidate element using remote address/port
         * @param xml Received xml element
         * @param container The transport container
         */
        void fromXml(XmlElement* xml, const JGRtpCandidates& container);

        String m_address;
        String m_port;
        String m_component;                  // Candidate component
        String m_generation;                 // Candidate generation
        String m_network;                    // NIC card (diagnostic only)
        String m_priority;                   // Candidate priority
        String m_protocol;                   // The only allowable value is "udp"
        String m_type;                       // A Candidate Type as defined in ICE-CORE
    };

    /**
     * This class holds a RTP transport candidate
     * @short A RTP transport candidate
     */
    class YJABBER_API JGRtpCandidateP2P : public JGRtpCandidate
    {
        YCLASS(JGRtpCandidateP2P,JGRtpCandidate)
    public:
        /**
         * Constructor
         */
        inline JGRtpCandidateP2P()
    	: JGRtpCandidate("")
    	{}

        /**
         * Constructor. Build a candidate from received data
         * @param xml Received xml element
         * @param container The transport container
         */
        inline JGRtpCandidateP2P(XmlElement* xml, const JGRtpCandidates& container)
    	: JGRtpCandidate("")
    	{ fromXml(xml,container); }

        /**
         * Create a 'candidate' element from this object using local address/port
         * @param container The transport container
         * @return Valid XmlElement pointer if type is a known one
         */
        virtual XmlElement* toXml(const JGRtpCandidates& container) const;

        /**
         * Fill this object from a candidate element using remote address/port
         * @param xml Received xml element
         * @param container The transport container
         */
        void fromXml(XmlElement* xml, const JGRtpCandidates& container);

        String m_username;
        String m_password;
    };

    /**
     * This class holds a list of jingle RTP transport candidates
     * @short A list of RTP transport candidates
     */
    class YJABBER_API JGRtpCandidates : public ObjList
    {
    public:
        /**
         * Enumeration of transport types
         */
        enum Type {
    	Unknown   = -1,
    	RtpIceUdp = 1,
    	RtpRawUdp,
    	RtpP2P,
    	RtpGoogleRawUdp,
        };

        /**
         * Constructor. Fill this object from an XML element
         * @param t The transport type
         */
        inline JGRtpCandidates(Type t = Unknown)
    	: m_type(t)
    	{}

        /**
         * Get the name of this list's type
         * @return The name of this list's type
         */
        inline const char* typeName() const
    	{ return typeName(m_type); }

        /**
         * Fill password and ufrag data
         */
        inline void generateIceAuth() {
    	    generateIceToken(m_password,true);
    	    generateIceToken(m_ufrag,false);
    	}

        /**
         * Fill password and ufrag data using old transport restrictions (16 bytes length)
         */
        inline void generateOldIceAuth() {
    	    generateOldIceToken(m_password);
    	    generateOldIceToken(m_ufrag);
    	}

        /**
         * Find a candidate by its component value
         * @param component The value to search
         * @return JGRtpCandidate pointer or 0
         */
        JGRtpCandidate* findByComponent(unsigned int component);

        /**
         * Create a 'transport' element from this object. Add candidates
         * @param addCandidates True to add the candidate children
         * @param addAuth RtpIceUdp only: add auth data
         * @return Valid XmlElement pointer
         */
        XmlElement* toXml(bool addCandidates, bool addAuth) const;

        /**
         * Fill this object from a given element
         * @param element The element
         */
        void fromXml(XmlElement* element);

        /**
         * Generate a random password or username to be used with ICE-UDP transport
         * @param dest Destination string
         * @param pwd True to generate a password, false to generate an username (ufrag)
         * @param max Maximum number of characters. The maxmimum value is 256.
         *  The minimum value is 22 for password and 4 for username
         */
        static void generateIceToken(String& dest, bool pwd, unsigned int max = 0);

        /**
         * Generate a random password or username to be used with old ICE-UDP transport
         * @param dest Destination string
         */
        static void generateOldIceToken(String& dest);

        /**
         * Get the name associated with a list's type
         * @param t The desired type
         * @param defVal Default value to return
         * @return The name associated with a list's type
         */
        static inline const char* typeName(int t, const char* defVal = "unknown")
    	{ return TelEngine::lookup(t,s_type,defVal); }

        /**
         * The list of type names
         */
        static const TokenDict s_type[];

        Type m_type;
        String m_password;
        String m_ufrag;
    };

    /**
     * This class holds a Jingle content negotiated during a session
     * It can be built from a received xml element and
     *  it can build an xml element from itself
     * @short A Jingle session content
     */
    class YJABBER_API JGSessionContent : public RefObject
    {
    public:
        /**
         * Enumeration of content type
         */
        enum Type {
    	Unknown             = -1,        // Unknown
    	UnknownFileTransfer = -2,        // Unknown (unsupported) file transfer content
    	RtpIceUdp           = 1,         // Audio: RTP ICE-UDP transport
    	RtpRawUdp,                       // Audio: RTP RAW-UDP transport
    	RtpP2P,                          //
    	RtpGoogleRawUdp,                 //
    	FileBSBOffer,                    // File offer: byte stream (SOCKS) transport
    	FileBSBRequest,                  // File request: byte stream (SOCKS) transport
        };

        /**
         * Enumeration values for the 'senders' attribute (required)
         */
        enum Senders {
    	SendUnknown    = 0,
    	SendBoth       = 1,
    	SendInitiator  = 2,
    	SendResponder  = 3
        };

        /**
         * Enumeration values for the 'creator' attribute (required)
         */
        enum Creator {
    	CreatorUnknown   = 0,
    	CreatorInitiator = 1,
    	CreatorResponder = 2
        };

        /**
         * Constructor
         * @param t Content type as enumeration
         * @param name Content name
         * @param senders Content senders as enumeration
         * @param creator Content creator as enumeration
         * @param disposition Optional content disposition (defauls to 'session' if empty)
         */
        JGSessionContent(Type t, const char* name, Senders senders,
    	Creator creator, const char* disposition = 0);

        /**
         * Get the content type
         * @return Content type as enumeration
         */
        inline Type type() const
    	{ return m_type; }

        /**
         * Get the senders
         * @return Senders as enumeration
         */
        inline Senders senders() const
    	{ return m_senders; }

        /**
         * Get the content creator
         * @return Content creator as enumeration
         */
        inline Creator creator() const
    	{ return m_creator; }

        /**
         * Check if this content is a valid audio one: it's media list type is Audio
         *  and the payload list is not empty
         * @return True if this content can be used for audio purposes
         */
        inline bool isValidAudio() const
    	{ return (m_rtpMedia.media() == JGRtpMediaList::Audio) && (0 != m_rtpMedia.skipNull()); }

        /**
         * Get the name of this content
         */
        virtual const String& toString() const
    	{ return m_name; }

        /**
         * Check if the content disposition is session
         * XEP-0166: true if disposition is missing
         * @return True if this content should be processed at session level
         */
        inline bool isSession() const
    	{ return !m_disposition || m_disposition == "session"; }

        /**
         * Check if the content disposition is early media
         * @return True if this content is an early media one
         */
        inline bool isEarlyMedia() const
    	{ return m_disposition == "early-session"; }

        /**
         * Set this content's disposition to early media
         */
        inline void setEarlyMedia()
    	{ m_disposition = "early-session"; }

        /**
         * Build a 'content' XML element from this object
         * @param minimum Minimum data (only creator and name)
         * @param addDesc True to add the description child
         * @param addTrans True to add the transport child
         * @param addCandidates True to add the transport candidate children
         * @param addAuth RtpIceUdp only: add auth data
         * @return Valid XmlElement pointer
         */
        XmlElement* toXml(bool minimum, bool addDesc,
    	bool addTrans, bool addCandidates, bool addAuth) const;

        /**
         * Decode 'content' element attributes
         * @param xml The XML element
         * @param err The error on failure
         * @param error Error text to be sent on failure
         * @return Valid JGSessionContent pointer on success
         */
        static JGSessionContent* fromXml(XmlElement* xml, XMPPError::Type& err,
    	String& error);

        /**
         * The list containing the text values for Senders enumeration
         */
        static const TokenDict s_senders[];

        /**
         * The list containing the text values for Creator enumeration
         */
        static const TokenDict s_creator[];

        /**
         * The RTP media description if used
         */
        JGRtpMediaList m_rtpMedia;

        /**
         * The RTP local candidates
         */
        JGRtpCandidates m_rtpLocalCandidates;

        /**
         * The RTP remote candidates
         */
        JGRtpCandidates m_rtpRemoteCandidates;

        /**
         * File info (for file transfer)
         */
        NamedList m_fileTransfer;

    private:
        Type m_type;
        String m_name;
        Senders m_senders;
        Creator m_creator;
        String m_disposition;
    };

    /**
     * This class holds a file transfer stream host definition
     * @short A Jingle file transfer stream host
     */
    class JGStreamHost : public String
    {
    public:
        /**
         * Constructor
         * @param local Local stream host
         * @param jid Stream host jid (id)
         * @param addr Stream host address
         * @param port Stream host port
         * @param zeroConf Optional zero conf definition (override address/port)
         */
        JGStreamHost(bool local, const char* jid, const char* addr, int port, const char* zeroConf = 0)
    	: String(jid),
    	m_local(local), m_address(addr), m_port(port), m_zeroConf(zeroConf)
    	{}

        /**
         * Copy constructor
         * @param src Source stream host to copy from
         */
        inline JGStreamHost(const JGStreamHost& src)
    	: String(src),
    	m_local(src.m_local), m_address(src.m_address), m_port(src.m_port),
    	m_zeroConf(src.m_zeroConf)
    	{}

        /**
         * Build an XML element from this stream host
         * @return Valid XmlElement pointer
         */
        XmlElement* toXml();

        /**
         * Build a stream host from an XML element
         * @param xml The element to build from
         * @return Valid JGStreamHost pointer or 0 on error
         */
        static JGStreamHost* fromXml(XmlElement* xml);

        /**
         * Build a query XML element carrying a list of stream hosts
         * @param hosts List of JGStreamHost objects
         * @param sid The query element's sid attribute
         * @param mode The query element's mode attribute
         * @return Valid XmlElement pointer
         */
        static XmlElement* buildHosts(const ObjList& hosts, const char* sid,
    	const char* mode = "tcp");

        /**
         * Build a query XML element with a streamhost-used child
         * @param jid The jid of the stream host used
         * @return Valid XmlElement pointer
         */
        static XmlElement* buildRsp(const char* jid);

        bool m_local;
        String m_address;
        int m_port;
        String m_zeroConf;
    };

    /**
     * This class is a base class for all specific jingle sessions
     * @short A basic Jingle session
     */
    class YJABBER_API JGSession : public RefObject, public Mutex
    {
        friend class JGEvent;
        friend class JGEngine;
    public:
        /**
         * Jingle session version
         */
        enum Version {
    	Version0 = 0,
    	Version1 = 1,
    	VersionUnknown
        };

        /**
         * Jingle defined reasons and errors
         */
        enum Reason {
    	ReasonUnknown = 0,
    	// Session termination reason
    	ReasonOk,                        // success
    	ReasonBusy,                      // busy
    	ReasonDecline,                   // decline
    	ReasonCancel,                    // cancel
    	ReasonExpired,                   // expired
    	ReasonConn,                      // connectivity-error
    	ReasonFailApp,                   // failed-application
    	ReasonFailTransport,             // failed-transport
    	ReasonGone,                      // gone
    	ReasonParams,                    // incompatible-parameters
    	ReasonMedia,                     // media-error
    	ReasonTransport,                 // unsupported-transports
    	ReasonApp,                       // unsupported-applications
    	ReasonSecurity,                  // security-error
    	ReasonTimeout,                   // timeout
    	ReasonGeneral,                   // general-error
    	ReasonAltSess,                   // alternative-session
    	// Session transfer (XEP 0251)
    	Transferred,                     // transferred
    	// RTP session errors (XEP 0167)
    	CryptoRequired,                  // crypto-required
    	InvalidCrypto,                   // invalid-crypto
        };

        /**
         * RTP session info (XEP 0167)
         */
        enum RtpInfo {
    	RtpActive,                       // active
    	RtpHold,                         // hold
    	RtpMute,                         // mute
    	RtpRinging,                      // ringing
        };

        /**
         * Session state enumeration
         */
        enum State {
    	Idle    = 0,                     // Outgoing stream is waiting for
    	Pending = 1,                     // Session is pending, session-initiate sent/received
    	Active  = 2,                     // Session is active, session-accept sent/received
    	Ending  = 3,                     // Session terminated: Wait for write result
    	Destroy = 4,                     // The session will be destroyed
        };

        /**
         * Jingle action enumeration
         */
        enum Action {
    	ActAccept,                       // session-accept
    	ActInitiate,                     // session-initiate
    	ActTerminate,                    // session-terminate
    	ActReject,                       // reject
    	ActInfo,                         // session-info
    	ActTransportInfo,                // transport-info
    	ActTransportAccept,              // transport-accept
    	ActTransportReject,              // transport-reject
    	ActTransportReplace,             // transport-replace
    	ActCandidates,                   // candidates
    	ActContentAccept,                // content-accept
    	ActContentAdd,                   // content-add
    	ActContentModify,                // content-modify
    	ActContentReject,                // content-reject
    	ActContentRemove,                // content-remove
    	ActContentInfo,                  // content-info
    	ActDescriptionInfo,              // description-info
    	ActTransfer,                     // session-info: Transfer
    	ActRinging,                      // session-info: Ringing
    	ActTrying,                       // session-info: Trying
    	ActReceived,                     // session-info: Received
    	ActHold,                         // session-info: Hold
    	ActActive,                       // session-info: Active
    	ActMute,                         // session-info: Mute
    	ActDtmf,                         // session-info: Dtmf
    	ActStreamHost,
    	ActCount,
        };

        /**
         * Session flags
         */
        enum SessionFlag {
    	FlagNoPing = 0x0001,             // Don't send ping
    	FlagRingNsRtp = 0x0002,          // Send ringing using rtp namespace instead of rtp info namespace
    	FlagNoOkInitiate = 0x0004,       // Don't raise a ResultOk when initiate stanza is confirmed
        };

        /**
         * Destructor
         */
        virtual ~JGSession();

        /**
         * Get the session version
         * @return The session version
         */
        inline Version version() const
    	{ return m_version; }

        /**
         * Retrieve the engine owning this session
         * @return The engine owning this session
         */
        inline JGEngine* engine() const
    	{ return m_engine; }

        /**
         * Get the session direction
         * @return True if it is an outgoing session
         */
        inline bool outgoing() const
    	{ return m_outgoing; }

        /**
         * Get the session id
         * @return The session id
         */
        inline const String& sid() const
    	{ return m_sid; }

        /**
         * Get the local peer's JID
         * @return The local peer's JID
         */
        inline const JabberID& local() const
    	{ return m_local; }

        /**
         * Get the remote peer's JID
         * @return The remote peer's JID
         */
        inline const JabberID& remote() const
    	{ return m_remote; }

        /**
         * Get the session state.
         * @return The session state as enumeration.
         */
        inline State state() const
    	{ return m_state; }

        /**
         * Retrieve session flags
         * @param mask Mask to retrieve
         * @return Session flags
         */
        inline int flag(int mask) const
    	{ return m_flags & mask; }

        /**
         * Replace session flags
         * @param value The new session flags
         */
        inline void setFlags(int value)
    	{ m_flags = value; }

        /**
         * Get the arbitrary user data of this session
         * @return The arbitrary user data of this session
         */
        inline void* userData()
    	{ return m_private; }

        /**
         * Set the arbitrary user data of this session
         * @param userdata The new arbitrary user data's value
         */
        inline void userData(void* userdata)
    	{ m_private = userdata; }

        /**
         * Retrieve the client account used by this session
         * @return The client account used by this session
         */
        inline const String& line() const
    	{ return m_line; }

        /**
         * Set the client account used by this session
         * @param acc The client account used by this session
         */
        inline void line(const String& acc)
    	{ m_line = acc; }

        /**
         * Get an action (jingle element type) from a jingle element
         * @param xml Element to check
         * @return The found action, ActCount if not found or unknown
         */
        Action getAction(XmlElement* xml);

        /**
         * Ask this session to accept an incoming xml 'iq' element
         * @param type Iq type as enumeration
         * @param from The sender
         * @param to The recipient
         * @param id The session id of this is a request (set/get) or the stanza id
         * @param xml The received element
         * @return True if accepted (the element was enqueued), false if not
         */
        bool acceptIq(XMPPUtils::IqType type, const JabberID& from, const JabberID& to,
    	const String& id, XmlElement* xml);

        /**
         * Confirm (send result) a received element
         * @param xml The element to confirm
         * @return False if send failed or element is 0
         */
        bool confirmResult(XmlElement* xml);

        /**
         * Confirm (send error) a received element
         * @param xml The element to confirm (will be consumed and zeroed)
         * @param error The error condition
         * @param text Optional text to add to the error element
         * @param type Error type
         * @return False if send failed or element is 0
         */
        bool confirmError(XmlElement*& xml, XMPPError::Type error,
    	const char* text = 0, XMPPError::ErrorType type = XMPPError::TypeModify);

        /**
         * Accept a Pending incoming session.
         * This method is thread safe
         * @param contents The list of accepted contents
         * @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
         * @return False if send failed
         */
        virtual bool accept(const ObjList& contents, String* stanzaId = 0)
    	{ return false; }

        /**
         * Close a Pending or Active session
         * This method is thread safe
         * @param reason Optional termination reason
         * @return False if send failed
         */
        virtual bool hangup(XmlElement* reason = 0);

        /**
         * Create a RTP info child to be added to a session-info element
         * @param info The informational tag as enumeration
         * @return Valid XmlElement pointer or 0 if not supported
         */
        virtual XmlElement* createRtpInfoXml(RtpInfo info)
    	{ return 0; }

        /**
         * Create a termination reason element
         * @param reason The reason code
         * @param text Optional reason text child
         * @param child Optional additional reason child
         * @return Valid XmlElement pointer or 0 if not supported
         */
        virtual XmlElement* createReason(int reason, const char* text = 0,
    	XmlElement* child = 0)
    	{ return 0; }

        /**
         * Create a transfer reason element
         * @param reason The reason code
         * @return Valid XmlElement pointer or 0 if not supported
         */
        virtual XmlElement* createTransferReason(int reason)
    	{ return 0; }

        /**
         * Create a RTP session reason element
         * @param reason The reason code
         * @return Valid XmlElement pointer or 0 if not supported
         */
        virtual XmlElement* createRtpSessionReason(int reason)
    	{ return 0; }

        /**
         * Send a stanza with session content(s)
         * This method is thread safe
         * @param action Must be a transport- or content- action
         * @param contents Non empty list with content(s) to send
         * @param stanzaId Optional string to be filled with sent
         *  stanza id (used to track the response)
         * @return False if send failed
         */
        virtual bool sendContent(Action action, const ObjList& contents, String* stanzaId = 0)
    	{ return false; }

        /**
         * Send a stanza with a session content
         * This method is thread safe
         * @param action Must be a transport- or content- action
         * @param content The content to send
         * @param stanzaId Optional string to be filled with sent
         *  stanza id (used to track the response)
         * @return False if send failed
         */
        inline bool sendContent(Action action, const JGSessionContent* content,
    	String* stanzaId = 0) {
    	    if (!content)
    		return false;
    	    ObjList tmp;
    	    tmp.append(content)->setDelete(false);
    	    return sendContent(action,tmp,stanzaId);
    	}

        /**
         * Send a stanza with stream hosts
         * This method is thread safe
         * @param hosts The list of hosts to send
         * @param stanzaId Optional string to be filled with sent
         *  stanza id (used to track the response)
         * @return False if send failed
         */
        virtual bool sendStreamHosts(const ObjList& hosts, String* stanzaId = 0)
    	{ return false; }

        /**
         * Send a stanza with a stream host used. If the jid is empty, send an
         *  item-not-found error response
         * This method is thread safe
         * @param jid The stream host to send
         * @param stanzaId The id of the stanza to confirm
         * @return False if send failed
         */
        virtual bool sendStreamHostUsed(const char* jid, const char* stanzaId)
    	{ return false; }

        /**
         * Build SOCKS SHA1 dst.addr used by file transfer
         * @param buf Destination string
         */
        void buildSocksDstAddr(String& buf);

        /**
         * Send a session info element to the remote peer.
         * This method is thread safe
         * @param xml The XmlElement carried by the session info element
         * @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
         * @param extra Optional extra child for jingle element
         * @return False on failure
         */
        bool sendInfo(XmlElement* xml, String* stanzaId = 0, XmlElement* extra = 0);

        /**
         * Send a dtmf string to remote peer. If the string's length is greater then 1, each
         *  character is added as a 'dtmf' child of the jingle element
         * @param dtmf The dtmf string
         * @param msDuration The tone duration in miliseconds. Ignored if 0
         * @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
         * @return False if send failed
         */
        bool sendDtmf(const char* dtmf, unsigned int msDuration = 0, String* stanzaId = 0);

        /**
         * Check if the remote party supports a given feature
         * @param feature The requested feature
         * @return True if the remote party supports the given feature
         */
        bool hasFeature(XMPPNamespace::Type feature);

        /**
         * Build a transfer element
         * @param transferTo The JID to transfer to
         * @param transferFrom The transferror's JID
         * @param sid Optional session id used for attended transfer (empty for unattended transfer)
         * @return Valid XmlElement pointer
         */
        static XmlElement* buildTransfer(const String& transferTo, const String& transferFrom,
    	const String& sid = String::empty());

         /**
         * Get the session version associated with a text
         * @param value The version text
         * @param def Default value to return if not found
         * @return Session Version value
         */
        static inline Version lookupVersion(const char* value, Version def = VersionUnknown)
    	{ return (Version)lookup(value,s_versions,def); }

         /**
         * Get the session version name
         * @param value The version value
         * @param def Default value to return if not found
         * @return Session version name or the default value if not found
         */
        static inline const char* lookupVersion(int value, const char* def = "unknown")
    	{ return lookup(value,s_versions,def); }

         /**
         * Get the termination code associated with a text
         * @param value The termination text
         * @param def Default value to return if not found
         * @return Termination code
         */
        static inline int lookupReason(const char* value, int def = ReasonOk)
    	{ return lookup(value,s_reasons,def); }

        /**
         * Get the termination code associated with a text
         * @param value The termination code
         * @param def Default value to return if not found
         * @return Termination text
         */
        static inline const char* lookupReason(int value, const char* def = 0)
    	{ return lookup(value,s_reasons,def); }

        /**
         * Get the name of a session state
         * @param state The state to find
         * @return The name of a session state
         */
        static const char* lookupState(int state)
    	{ return lookup(state,s_states); }

        /**
         * Get the name of an action
         * @param act The action to find
         * @param ver Session version to use
         * @return The name of an action
         */
        static const char* lookupAction(int act, Version ver);

        /**
         * Get the action associated with a given string
         * @param str The action name
         * @param ver Session version to use
         * @return The name of an action
         */
        static Action lookupAction(const char* str, Version ver);

        /**
         * Session version names
         */
        static const TokenDict s_versions[];

        /**
         * Termination reasons and errors
         */
        static const TokenDict s_reasons[];

        /**
         * RTP session info (XEP 0167)
         */
        static const TokenDict s_rtpInfo[];

        /**
         * Session state names
         */
        static const TokenDict s_states[];

        /**
         * Action names for version Version0
         */
        static const TokenDict s_actions0[];

        /**
         * Action names for version Version1
         */
        static const TokenDict s_actions1[];

        /**
         * Session flag names
         */
        static const TokenDict s_flagName[];

    protected:
        /**
         * Constructor. Create an outgoing session
         * @param ver The session version
         * @param engine The engine owning this session
         * @param caller The caller's full JID
         * @param called The called party's full JID
         */
        JGSession(Version ver, JGEngine* engine,
    	const JabberID& caller, const JabberID& called);

        /**
         * Constructor. Create an incoming session.
         * @param ver The session version
         * @param engine The engine owning this session
         * @param caller The caller's full JID
         * @param called The called party's full JID
         * @param xml A valid Jabber Jingle xml with action session initiate
         * @param id Session id
         */
        JGSession(Version ver, JGEngine* engine, const JabberID& caller,
    	const JabberID& called, XmlElement* xml, const String& id);

        /**
         * Build and send the initial message on an outgoing session
         * @param contents The session contents to be sent with session initiate element
         * @param extra Optional extra child to be added to the session initiate element
         * @param subject Optional session subject
         * @return True on success
         */
        virtual bool initiate(const ObjList& contents, XmlElement* extra,
    	const char* subject = 0) = 0;

        /**
         * Get a Jingle event from the queue.
         * This method is thread safe
         * @param time Current time in miliseconds
         * @return JGEvent pointer or 0
         */
        virtual JGEvent* getEvent(u_int64_t time);

        /**
         * Release this session and its memory
         */
        virtual void destroyed();

        /**
         * Send a stanza to the remote peer
         * @param stanza The stanza to send
         * @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
         * @param confirmation True if the stanza needs confirmation (add 'id' attribute)
         * @param ping True if the stanza is a ping one
         * @param toutMs Optional stanza timeout interval in milliseconds
         * @return True on success
         */
        bool sendStanza(XmlElement* stanza, String* stanzaId = 0, bool confirmation = true,
    	bool ping = false, unsigned int toutMs = 0);

        /**
         * Send a ping (empty session info) stanza to the remote peer if it's time to do it
         * @param msecNow The current time
         * @return True if a ping was succesfully sent
         */
        bool sendPing(u_int64_t msecNow);

        /**
         * Decode a jingle element
         * @param xml The element to decode
         * @param child The element's first child
         * @return JGEvent pointer or 0
         */
        virtual JGEvent* decodeJingle(XmlElement*& xml, XmlElement* child) = 0;

        /**
         * Create an 'iq' of type 'set' with a 'jingle' child
         * @param action The action of the Jingle stanza
         * @param element1 Optional child element
         * @param element2 Optional child element
         * @param element3 Optional child element
         * @return Valid XmlElement pointer
         */
        virtual XmlElement* createJingle(Action action, XmlElement* element1 = 0,
    	XmlElement* element2 = 0, XmlElement* element3 = 0) = 0;

        /**
         * Create a dtmf XML element
         * @param dtmf The dtmf string
         * @param msDuration The tone duration in miliseconds. Ignored if 0
         * @return Valid XmlElement pointer or 0
         */
        virtual XmlElement* createDtmf(const char* dtmf, unsigned int msDuration = 0) = 0;

        /**
         * Method called in getEvent() to process a last event decoded from a
         *  received jingle element
         * @param ev The event to process (will be consumed and zeroed)
         * @return JGEvent pointer or 0
         */
        virtual JGEvent* processJingleSetEvent(JGEvent*& ev);

        /**
         * Method called in getEvent() to process a jabber event carrying a response
         * @param result True if the element is a result, false if it's an error response
         * @param xml Xml element to process
         * @return JGEvent pointer or 0
         */
        virtual JGEvent* processJabberIqResponse(bool result, XmlElement*& xml);

        /**
         * Decode a file transfer element
         * @param set True if the xml is an iq 'set', false if type is 'get'
         * @param xml The element to decode
         * @param child The element's first child
         * @return JGEvent pointer or 0
         */
        virtual JGEvent* processFileTransfer(bool set, XmlElement*& xml, XmlElement* child);

        /**
         * Terminate notification from an event. Reset the last generated event
         * @param event Terminated (processed) event
         */
        void eventTerminated(JGEvent* event);

        /**
         * Changed session state
         * @param newState Session new state
         */
        void changeState(State newState);

        Version m_version;                   // Session version
        State m_state;                       // Session state
        int m_flags;                         // Session flags
        u_int64_t m_timeToPing;              // Time to send ping (empty session-info)
        JGEngine* m_engine;                  // The engine that owns this session
        bool m_outgoing;                     // Session direction
        String m_sid;                        // Session id
        JabberID m_local;                    // Local peer's JID
        JabberID m_remote;                   // Remote peer's JID
        XmlFragment m_queue;                 // Incoming, unprocessed, xml elements
        JGEvent* m_lastEvent;                // Last generated event
        bool m_recvTerminate;                // Flag indicating whether session-terminate was received
        void* m_private;                     // Arbitrary user data
        String m_localSid;                   // Local session id (used to generate element's id)
        u_int32_t m_stanzaId;                // Sent stanza id counter
        ObjList m_sentStanza;                // Sent stanzas' id
        String m_line;                       // Session account

    private:
        JGSession() {}                       // Don't use it
    };

    /**
     * A session implementing the old jingle protocol
     * @short The version 0 of a jingle session
     */
    class YJABBER_API JGSession0 : public JGSession
    {
        friend class JGEvent;
        friend class JGEngine;
    public:
        /**
         * Destructor
         */
        virtual ~JGSession0();

        /**
         * Accept a Pending incoming session.
         * This method is thread safe
         * @param contents The list of accepted contents
         * @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
         * @return False if send failed
         */
        virtual bool accept(const ObjList& contents, String* stanzaId = 0);

    protected:
        /**
         * Constructor. Create an outgoing session
         * @param engine The engine owning this session
         * @param caller The caller's full JID
         * @param called The called party's full JID
         */
        JGSession0(JGEngine* engine, const JabberID& caller, const JabberID& called);

        /**
         * Constructor. Create an incoming session.
         * @param engine The engine owning this session
         * @param caller The caller's full JID
         * @param called The called party's full JID
         * @param xml A valid Jabber Jingle xml with action session initiate
         * @param id Session id
         */
        JGSession0(JGEngine* engine, const JabberID& caller, const JabberID& called,
    	XmlElement* xml, const String& id);

        /**
         * Build and send the initial message on an outgoing session
         * @param contents The session contents to be sent with session initiate element
         * @param extra Optional extra child to be added to the session initiate element
         * @param subject Optional session subject
         * @return True on success
         */
        virtual bool initiate(const ObjList& contents, XmlElement* extra,
    	const char* subject = 0);

        /**
         * Send a stanza with session content(s)
         * This method is thread safe
         * @param action Must be a transport- action
         * @param contents Non empty list with content(s) to send
         * @param stanzaId Optional string to be filled with sent
         *  stanza id (used to track the response)
         * @return False if send failed
         */
        virtual bool sendContent(Action action, const ObjList& contents, String* stanzaId = 0);

        /**
         * Decode a jingle element
         * @param xml The element to decode
         * @param child The element's first child
         * @return JGEvent pointer or 0
         */
        virtual JGEvent* decodeJingle(XmlElement*& xml, XmlElement* child);

        /**
         * Create an 'iq' of type 'set' with a 'jingle' child
         * @param action The action of the Jingle stanza
         * @param element1 Optional child element
         * @param element2 Optional child element
         * @param element3 Optional child element
         * @return Valid XmlElement pointer
         */
        virtual XmlElement* createJingle(Action action, XmlElement* element1 = 0,
    	XmlElement* element2 = 0, XmlElement* element3 = 0);

        /**
         * Create a dtmf XML element
         * @param dtmf The dtmf string
         * @param msDuration The tone duration in miliseconds. Ignored if 0
         * @return Valid XmlElement pointer or 0
         */
        virtual XmlElement* createDtmf(const char* dtmf, unsigned int msDuration = 0);

    protected:
        String m_sessContentName;            // Content name advertised to upper layer
        Action m_candidatesAction;           // Use candidates/transport-info for candidates
    };

    /**
     * A session implementing the Jingle protocol including session transfer and file transfer
     * @short The version 1 of a jingle session
     */
    class YJABBER_API JGSession1 : public JGSession
    {
        friend class JGEvent;
        friend class JGEngine;
    public:
        /**
         * Destructor
         */
        virtual ~JGSession1();

        /**
         * Accept a Pending incoming session.
         * This method is thread safe
         * @param contents The list of accepted contents
         * @param stanzaId Optional string to be filled with sent stanza id (used to track the response)
         * @return False if send failed
         */
        virtual bool accept(const ObjList& contents, String* stanzaId = 0);

        /**
         * Create a RTP info child to be added to a session-info element
         * @param info The informational tag as enumeration
         * @return Valid XmlElement pointer or 0 if not supported
         */
        virtual XmlElement* createRtpInfoXml(RtpInfo info);

        /**
         * Create a termination reason element
         * @param reason The reason code
         * @param text Optional reason text child
         * @param child Optional additional reason child
         * @return Valid XmlElement pointer or 0 if not supported
         */
        virtual XmlElement* createReason(int reason, const char* text = 0,
    	XmlElement* child = 0);

        /**
         * Create a transfer reason element
         * @param reason The reason code
         * @return Valid XmlElement pointer or 0 if not supported
         */
        virtual XmlElement* createTransferReason(int reason);

        /**
         * Create a RTP session reason element
         * @param reason The reason code
         * @return Valid XmlElement pointer or 0 if not supported
         */
        virtual XmlElement* createRtpSessionReason(int reason);

        /**
         * Send a stanza with session content(s)
         * This method is thread safe
         * @param action Must be a transport- or content- action
         * @param contents Non empty list with content(s) to send
         * @param stanzaId Optional string to be filled with sent
         *  stanza id (used to track the response)
         * @return False if send failed
         */
        virtual bool sendContent(Action action, const ObjList& contents, String* stanzaId = 0);

        /**
         * Send a stanza with stream hosts
         * This method is thread safe
         * @param hosts The list of hosts to send
         * @param stanzaId Optional string to be filled with sent
         *  stanza id (used to track the response)
         * @return False if send failed
         */
        virtual bool sendStreamHosts(const ObjList& hosts, String* stanzaId = 0);

        /**
         * Send a stanza with a stream host used. If the jid is empty, send an
         *  item-not-found error response
         * This method is thread safe
         * @param jid The stream host to send
         * @param stanzaId The id of the stanza to confirm
         * @return False if send failed
         */
        virtual bool sendStreamHostUsed(const char* jid, const char* stanzaId);

    protected:
        /**
         * Constructor. Create an outgoing session
         * @param engine The engine owning this session
         * @param caller The caller's full JID
         * @param called The called party's full JID
         */
        JGSession1(JGEngine* engine, const JabberID& caller, const JabberID& called);

        /**
         * Constructor. Create an incoming session.
         * @param engine The engine owning this session
         * @param caller The caller's full JID
         * @param called The called party's full JID
         * @param xml A valid Jabber Jingle xml with action session initiate
         * @param id Session id
         */
        JGSession1(JGEngine* engine, const JabberID& caller, const JabberID& called,
    	XmlElement* xml, const String& id);

        /**
         * Build and send the initial message on an outgoing session
         * @param contents The session contents to be sent with session initiate element
         * @param extra Optional extra child to be added to the session initiate element
         * @param subject Optional session subject
         * @return True on success
         */
        virtual bool initiate(const ObjList& contents, XmlElement* extra,
    	const char* subject = 0);

        /**
         * Decode a jingle element
         * @param xml The element to decode
         * @param child The element's first child
         * @return JGEvent pointer or 0
         */
        virtual JGEvent* decodeJingle(XmlElement*& xml, XmlElement* child);

        /**
         * Create an 'iq' of type 'set' with a 'jingle' child
         * @param action The action of the Jingle stanza
         * @param element1 Optional child element
         * @param element2 Optional child element
         * @param element3 Optional child element
         * @return Valid XmlElement pointer
         */
        virtual XmlElement* createJingle(Action action, XmlElement* element1 = 0,
    	XmlElement* element2 = 0, XmlElement* element3 = 0);

        /**
         * Create a dtmf XML element
         * @param dtmf The dtmf string
         * @param msDuration The tone duration in miliseconds. Ignored if 0
         * @return Valid XmlElement pointer or 0
         */
        virtual XmlElement* createDtmf(const char* dtmf, unsigned int msDuration = 0);

        /**
         * Decode a file transfer element
         * @param set True if the xml is an iq 'set', false if type is 'get'
         * @param xml The element to decode
         * @param child The element's first child
         * @return JGEvent pointer or 0
         */
        virtual JGEvent* processFileTransfer(bool set, XmlElement*& xml, XmlElement* child);

    };

    /**
     * This class holds an event generated by a Jingle session
     * @short A Jingle event
     */
    class YJABBER_API JGEvent
    {
        friend class JGSession;
        friend class JGSession0;
        friend class JGSession1;
    public:
        /**
         * Jingle events enumeration
         */
        enum Type {
    	Jingle,                          //
    	ResultOk,                        // Response for a sent stanza (iq with type=result)
    	ResultError,                     // Response for a sent stanza (iq with type=error)
    	ResultTimeout,                   // Response for a sent stanza (stanza timeout)
    	// Final
    	Terminated,                      // m_element is the element that caused the termination
    	                                 //  m_reason contains the reason
    	Destroy,                         // The engine sould delete the event (causing session destruction)
        };

        /**
         * Destructor. Deref the session. Delete the XML element
         */
        virtual ~JGEvent();

        /**
         * Get the type of this event
         * @return The type of this event as enumeration
         */
        inline Type type() const
    	{ return m_type; }

        /**
         * Get the name of this
         * @return The name of this event
         */
        inline const char* name()
    	{ return lookupType(m_type); }

        /**
         * Get the session that generated this event
         * @return The session that generated this event
         */
        inline JGSession* session() const
    	{ return m_session; }

        /**
         * Get the XML element that generated this event
         * @return The XML element that generated this event
         */
        inline XmlElement* element() const
    	{ return m_element; }

        /**
         * Get the Jingle child of the XML element carried by the event
         * Don't delete it after use: it is owned by the event
         * @return The Jingle child of the XML element carried by the event
         */
        inline XmlElement* jingle() const
    	{ return m_jingle; }

        /**
         * Get the jingle action as enumeration
         * @return The jingle action as enumeration
         */
        inline JGSession::Action action() const
    	{ return m_action; }

        /**
         * Get the name of an action
         * @return The name of an action
         */
        inline const char* actionName() const
    	{ return m_session ? JGSession::lookupAction(m_action,m_session->version()) : ""; }

        /**
         * Get the id
         * @return The id
         */
        inline const String& id() const
    	{ return m_id; }

        /**
         * Get the reason
         * @return The reason
         */
        inline const String& reason() const
    	{ return m_reason; }

        /**
         * Get the text
         * @return The text
         */
        inline const String& text() const
    	{ return m_text; }

        /**
         * Get the XML element that generated this event and set it to 0
         * @return The XML element that generated this event
         */
        inline XmlElement* releaseXml() {
    	    XmlElement* tmp = m_element;
    	    m_jingle = m_element = 0;
    	    return tmp;
    	 }

        /**
         * Check if this event is a final one (Terminated or Destroy)
         * @return True if it is
         */
        inline bool final() const
    	{ return m_type == Terminated || m_type == Destroy; }

        /**
         * Confirm the element carryied by this event. See JGSession::confirm() for details
         * @param error The error condition
         * @param text Optional text to add to the error element
         * @param type Error type
         * @return False if send failed or element is 0
         */
        inline bool confirmElement(XMPPError::Type error = XMPPError::NoError,
    	const char* text = 0, XMPPError::ErrorType type = XMPPError::TypeModify) {
    	    if (m_session && element() && !m_confirmed) {
    		m_confirmed = true;
    		if (error == XMPPError::NoError)
    		    return m_session->confirmResult(element());
    		XmlElement* err = releaseXml();
    		return m_session->confirmError(err,error,text,type);
    	    }
    	    return false;
    	}

        /**
         * Set the confirmed flag. Use it for action with delayed response
         */
        inline void setConfirmed()
    	{ m_confirmed = true; }

        /**
         * Set the jingle action as enumeration. Set confirmation flag if
         *  the element don't require it
         * @param act The jingle action as enumeration
         */
        void setAction(JGSession::Action act);

        /**
         * Get the name of an event type
         * @return The name of an event type
         */
        static inline const char* lookupType(int type)
    	{ return lookup(type,s_typeName); }

        /**
         * Dictionary with event type names
         */
        static const TokenDict s_typeName[];

        /**
         * The list of session contents if used
         */
        ObjList m_contents;

        /**
         * The list of stream hosts if used
         */
        ObjList m_streamHosts;

    protected:
        /**
         * Constructor. Set the id parameter if the element is valid
         * @param type Event type
         * @param session The session that generated this event
         * @param element Optional XML element that generated this event
         * @param reason Optional reason data
         * @param text Optional text data
         */
        inline JGEvent(Type type, JGSession* session, XmlElement* element = 0,
    	const char* reason = 0, const char* text = 0)
    	: m_type(type), m_confirmed(true), m_session(0), m_element(element),
    	m_jingle(0), m_action(JGSession::ActCount), m_reason(reason), m_text(text)
    	{ init(session); }

        /**
         * Constructor. Create a Jingle event. Set the id parameter if the element is valid
         * @param act The jingle action
         * @param session The session that generated this event
         * @param element XML element that generated this event
         * @param reason Optional reason data
         * @param text Optional text data
         */
        inline JGEvent(JGSession::Action act, JGSession* session, XmlElement* element,
    	const char* reason = 0, const char* text = 0)
    	: m_type(Jingle), m_confirmed(false), m_session(0), m_element(element), m_jingle(0),
    	m_action(act), m_reason(reason), m_text(text) {
    	    init(session);
    	    setAction(act);
    	}

    private:
        JGEvent() {}                         // Don't use it
        void init(JGSession* session);

        Type m_type;                         // The type of this event
        bool m_confirmed;                    // Flag indicating that element was confirmed
        JGSession* m_session;                // Jingle session that generated this event
        XmlElement* m_element;               // XML element that generated this event
        XmlElement* m_jingle;                // The session child, if present
        // Event specific
        JGSession::Action m_action;          // The action if type is Jingle
        String m_id;                         // The element's id attribute
        String m_reason;                     // The reason if type is Error or Terminated
        String m_text;                       // Dtmf text
    };

    /**
     * This class holds a Jingle service for the Jabber engine. Handle jingle stanzas,
     *  stanza write fail events and stream termination events
     * @short A Jingle engine
     */
    class YJABBER_API JGEngine : public DebugEnabler, public Mutex
    {
        friend class JGSession;
    public:
        /**
         * Constructor
         * @param name Debug name
         */
        JGEngine(const char* name = "jgengine");

        /**
         * Destructor. Terminates all active sessions
         */
        virtual ~JGEngine();

        /**
         * Retrieve the default session flags value
         * @return The default session flags value
         */
        inline int sessionFlags() const
    	{ return m_sessionFlags; }

        /**
         * Get the timeout interval of a sent stanza
         * @return The timeout interval of a sent stanza
         */
        inline u_int64_t stanzaTimeout() const
    	{ return m_stanzaTimeout; }

        /**
         * Get the timeout interval of a sent stream host stanza
         * @return The timeout interval of a sent stream host stanza
         */
        inline u_int64_t streamHostTimeout() const
    	{ return m_streamHostTimeout; }

        /**
         * Get the ping interval used by jingle sessions
         * @return The interval to ping the remote party of a jingle session
         */
        inline u_int64_t pingInterval() const
    	{ return m_pingInterval; }

        /**
         * Initialize this service
         * @param params Service's parameters
         */
        virtual void initialize(const NamedList& params);

        /**
         * Send a session's stanza.
         * This method should be re-implemented
         * @param session The session requesting the operation
         * @param stanza The stanza to send. Will be consumed and zeroed
         * @return True on success
         */
        virtual bool sendStanza(JGSession* session, XmlElement*& stanza);

        /**
         * Send a chat message on behalf of a session
         * @param session The session requesting the operation
         * @param body Message body
         * @return True on success
         */
        virtual bool sendMessage(JGSession* session, const char* body);

        /**
         * Call getEvent() for each session list until an event is generated or the end is reached
         * This method is thread safe
         * @param time Current time in miliseconds
         * @return The first generated event
         */
        JGEvent* getEvent(u_int64_t time);

        /**
         * Make an outgoing call.
         * 'media' and 'transport' will be invalid on exit. Don't delete them
         * @param ver The session version to use
         * @param caller The caller
         * @param called The called
         * @param contents The list of session content(s)
         * @param extra Optional extra child for session initiate element
         * @param msg Optional message to send before call
         * @param subject Optional session subject
         * @param line Optional session account
         * @param flags Optional session flags to set
         * @return Valid JGSession pointer (referenced) on success
         */
        JGSession* call(JGSession::Version ver, const JabberID& caller, const JabberID& called,
    	const ObjList& contents, XmlElement* extra = 0, const char* msg = 0,
    	const char* subject = 0, const char* line = 0, int* flags = 0);

        /**
         * Ask this engine to accept an incoming xml 'iq' element
         * @param type Iq type as enumeration
         * @param from The sender
         * @param to The recipient
         * @param id Element id attribute
         * @param xml The received element
         * @param line Account receiving the stanza (may be empty)
         * @param error XMPPError result. This value should be check if false is returned.
         *  Any value different from NoError indicate an invalid element
         * @param text Error text
         * @return True if accepted (don't use the given pointer if accepted)
         */
        bool acceptIq(XMPPUtils::IqType type, const JabberID& from, const JabberID& to,
    	const String& id, XmlElement* xml, const char* line,
    	XMPPError::Type& error, String& text);

        /**
         * Default event processor. Delete event.
         * @param event The event to process
         */
        void defProcessEvent(JGEvent* event);

        /**
         * Process events from the sessions. Default action: Delete event.
         * Descendants must override this method to process generated events
         * @param event The event to process
         */
        virtual void processEvent(JGEvent* event);

        /**
         * Decode a comma separated list of flags
         * @param list The list of flags
         * @param dict Dictionary to use
         * @return Found flags
         */
        static int decodeFlags(const String& list, const TokenDict* dict);

        /**
         * Encode (append) flags to a comma separated list
         * @param buf Destination buffer
         * @param flags Flags to encode
         * @param dict Dictionary to use
         */
        static void encodeFlags(String& buf, int flags, const TokenDict* dict);

    private:
        // Create a local session id
        void createSessionId(String& id);

        ObjList m_sessions;                  // List of sessions
        u_int32_t m_sessionId;               // Session id counter
        u_int64_t m_stanzaTimeout;           // The timeout of a sent stanza
        u_int64_t m_streamHostTimeout;       // The timeout of a sent stream host stanza
        u_int64_t m_pingInterval;            // Interval to send ping (empty session-info)
        int m_sessionFlags;                  // Default session flags
    };

    /**
     * This class holds sent stanzas info used for timeout checking
     * @short Send stanza timeout info
     */
    class YJABBER_API JGSentStanza : public String
    {
    public:
        /**
         * Constructor
         * @param id The sent stanza's id
         * @param time The sent time
         * @param notif True to notify stanza timeout or response
         * @param ping True if the sent stanza is a ping one
         * @param action Optional sent stanza action
         */
        JGSentStanza(const char* id, u_int64_t time, bool notif = false, bool ping = false,
    	JGSession::Action action = JGSession::ActCount)
    	: String(id), m_time(time), m_notify(notif), m_ping(ping), m_action(action)
    	{}

        /**
         * Retrieve stanza timeout
         * @return Stanza timeout
         */
        inline u_int64_t timeout() const
    	{ return m_time; }

        /**
         * Check if this element timed out
         * @return True if timeout
         */
        inline bool timeout(u_int64_t time) const
    	{ return time > m_time; }

        /**
         * Check if timeout should be notified to sender
         * @return True to notify
         */
        inline bool notify() const
    	{ return m_notify; }

        /**
         * Check if the stanza is a ping one
         * @return True if the stanza is a ping one
         */
        inline bool ping() const
    	{ return m_ping; }

        /**
         * Get the jingle action as enumeration
         * @return The jingle action as enumeration
         */
        inline JGSession::Action action() const
    	{ return m_action; }

    private:
        u_int64_t m_time;                    // Timeout
        bool m_notify;                       // Notify timeout to sender
        bool m_ping;                         // Sent stanza is a ping one
        JGSession::Action m_action;          // Sent stanza action
    };

    };

    #endif /* __YATEJINGLE_H */

    /* vi: set ts=8 sw=4 sts=4 noet: */

Generated by: paulc on bussard on Mon Feb 10 13:15:47 2014, using kdoc 2.0a54.