/** * xmpputils.h * Yet Another Jabber Component Protocol 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-2006 Null Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef __XMPPUTILS_H #define __XMPPUTILS_H #include #include #ifdef _WINDOWS #ifdef LIBYJINGLE_EXPORTS #define YJINGLE_API __declspec(dllexport) #else #ifndef LIBYJINGLE_STATIC #define YJINGLE_API __declspec(dllimport) #endif #endif #endif /* _WINDOWS */ #ifndef YJINGLE_API #define YJINGLE_API #endif /** * Holds all Telephony Engine related classes. */ namespace TelEngine { class XMPPServerInfo; // Server info class class XMPPNamespace; // XMPP namespaces class XMPPError; // XMPP errors class JabberID; // A Jabber ID (JID) class JIDIdentity; // A JID's identity class JIDFeature; // A JID's feature class JIDFeatureSasl; // A JID's SASL feature class JIDFeatureList; // Feature list class XMPPUtils; // Utilities class XMPPDirVal; // Direction flags /** * This class holds informations about a server * @short Server info class */ class YJINGLE_API XMPPServerInfo : public RefObject { public: /** * Server flags */ enum ServerFlag { NoAutoRestart = 0x0001, // Don't auto restart streams when down KeepRoster = 0x0002, // Tell the presence service to keep the roster for this server TlsRequired = 0x0004, // The server always requires connection encryption OldStyleAuth = 0x0008, // The server doesn't support RFC 3920 TLS/SASL ... AllowPlainAuth = 0x0020, // Allow plain password authentication AllowUnsafeSetup = 0x0040, // Allow user account setup on unenchrypted streams }; /** * Constructor. Construct a full server info object * @param name Server domain name * @param address IP address * @param port IP port * @param password Component only: Password used for authentication * @param identity Component only: The stream identity used when connecting * @param fullidentity Component only: The user identity * @param flags Server flags */ inline XMPPServerInfo(const char* name, const char* address, int port, const char* password, const char* identity, const char* fullidentity, int flags) : m_name(name), m_address(address), m_port(port), m_password(password), m_identity(identity), m_fullIdentity(fullidentity), m_flags(flags) {} /** * Constructor. Construct a partial server info object * @param name Server domain name * @param port IP port */ inline XMPPServerInfo(const char* name, int port) : m_name(name), m_port(port) {} /** * Get the server's address * @return The server's address */ inline const String& address() const { return m_address; } /** * Get the server's domain name * @return The server's domain name */ inline const String& name() const { return m_name; } /** * Get the server's port used to connect to * @return The server's port used to connect to */ inline const int port() const { return m_port; } /** * Get the server's port used to connect to * @return The server's port used to connect to */ inline const String& password() const { return m_password; } /** * Get the server's identity * @return The server's identity */ inline const String& identity() const { return m_identity; } /** * Get the server's full identity * @return The server's full identity */ inline const String& fullIdentity() const { return m_fullIdentity; } /** * Check if a given flag (or mask) is set * @return True if the flag is set */ inline bool flag(int mask) const { return 0 != (m_flags & mask); } /** * Flag names dictionary */ static TokenDict s_flagName[]; private: String m_name; // Domain name String m_address; // IP address int m_port; // Port String m_password; // Authentication data String m_identity; // Identity. Used for Jabber Component protocol String m_fullIdentity; // Full identity for this server int m_flags; // Server flags }; /** * This class holds the XMPP/JabberComponent/Jingle namespace enumerations and the associated strings * @short XMPP namespaces */ class YJINGLE_API XMPPNamespace { public: enum Type { Stream = 1, // http://etherx.jabber.org/streams Client, // jabber:client Server, // jabber:server ComponentAccept, // jabber:component:accept ComponentConnect, // jabber:component:connect StreamError, // urn:ietf:params:xml:ns:xmpp-streams StanzaError, // urn:ietf:params:xml:ns:xmpp-stanzas Register, // http://jabber.org/features/iq-register IqRegister, // jabber:iq:register IqPrivate, // jabber:iq:private IqAuth, // jabber:iq:auth IqAuthFeature, // http://jabber.org/features/iq-auth Starttls, // urn:ietf:params:xml:ns:xmpp-tls Sasl, // urn:ietf:params:xml:ns:xmpp-sasl Session, // urn:ietf:params:xml:ns:xmpp-session Bind, // urn:ietf:params:xml:ns:xmpp-bind Roster, // jabber:iq:roster DynamicRoster, // jabber:iq:roster-dynamic DiscoInfo, // http://jabber.org/protocol/disco#info DiscoItems, // http://jabber.org/protocol/disco#items VCard, // vcard-temp SIProfileFileTransfer, // http://jabber.org/protocol/si/profile/file-transfer ByteStreams, // http://jabber.org/protocol/bytestreams Jingle, // xmlns='urn:xmpp:jingle:0 JingleError, // urn:xmpp:jingle:errors:0 JingleAppsRtp, // urn:xmpp:jingle:apps:rtp:0 JingleAppsRtpInfo, // urn:xmpp:jingle:apps:rtp:info:0 JingleAppsRtpAudio, // urn:xmpp:jingle:apps:rtp:audio JingleAppsFileTransfer, // urn:xmpp:jingle:apps:file-transfer:0 JingleTransportIceUdp, // urn:xmpp:jingle:transports:ice-udp:0 JingleTransportRawUdp, // urn:xmpp:jingle:transports:raw-udp:0 JingleTransportRawUdpInfo, // urn:xmpp:jingle:transports:raw-udp:info:0 JingleTransportByteStreams, // urn:xmpp:jingle:transports:bytestreams:0 JingleTransfer, // urn:xmpp:jingle:transfer:0 Dtmf, // urn:xmpp:jingle:dtmf:0 JingleSession, // http://www.google.com/session JingleAudio, // http://www.google.com/session/phone JingleTransport, // http://www.google.com/transport/p2p JingleRtpInfoOld, // urn:xmpp:jingle:apps:rtp:info DtmfOld, // http://jabber.org/protocol/jingle/info/dtmf Command, // http://jabber.org/protocol/command CapVoiceV1, // http://www.google.com/xmpp/protocol/voice/v1 Count, }; /** * Get the string representation of a namespace value */ inline const char* operator[](Type index) { return lookup(index,s_value); } /** * Check if a text is a known namespace */ static bool isText(Type index, const char* txt); /** * Get the type associated with a given namespace text */ static inline Type type(const char* txt) { int tmp = lookup(txt,s_value,Count); return tmp ? (Type)tmp : Count; } private: static TokenDict s_value[]; // Namespace list }; /** * This class holds the XMPP error type, error enumerations and associated strings * @short XMPP errors. */ class YJINGLE_API XMPPError { public: /** * Error condition enumeration */ enum Type { NoError = 0, // Stream errors BadFormat, // bad-format BadNamespace, // bad-namespace-prefix ConnTimeout, // connection-timeout HostGone, // host-gone HostUnknown, // host-unknown BadAddressing, // improper-addressing Internal, // internal-server-error InvalidFrom, // invalid-from InvalidId, // invalid-id InvalidNamespace, // invalid-namespace InvalidXml, // invalid-xml NotAuth, // not-authorized Policy, // policy-violation RemoteConn, // remote-connection-failed ResConstraint, // resource-constraint RestrictedXml, // restricted-xml SeeOther, // see-other-host Shutdown, // system-shutdown UndefinedCondition, // undefined-condition UnsupportedEnc, // unsupported-encoding UnsupportedStanza, // unsupported-stanza-type UnsupportedVersion, // unsupported-version Xml, // xml-not-well-formed // Auth failures Aborted, // aborted IncorrectEnc, // incorrect-encoding InvalidAuth, // invalid-authzid InvalidMechanism, // invalid-mechanism MechanismTooWeak, // mechanism-too-weak NotAuthorized, // not-authorized TempAuthFailure, // temporary-auth-failure // Stanza errors SBadRequest, // bad-request SConflict, // conflict SFeatureNotImpl, // feature-not-implemented SForbidden, // forbidden SGone, // gone SInternal, // internal-server-error SItemNotFound, // item-not-found SBadJid, // jid-malformed SNotAcceptable, // not-acceptable SNotAllowed, // not-allowed SPayment, // payment-required SUnavailable, // recipient-unavailable SRedirect, // redirect SReg, // registration-required SNoRemote, // remote-server-not-found SRemoteTimeout, // remote-server-timeout SResource, // resource-constraint SServiceUnavailable, // service-unavailable SSubscription, // subscription-required SUndefinedCondition, // undefined-condition SRequest, // unexpected-request // Misc DtmfNoMethod, // unsupported-dtmf-method ItemNotFound, // item-not-found Count, }; /** * Error type enumeration */ enum ErrorType { TypeCancel = 1000, // do not retry (the error is unrecoverable) TypeContinue, // proceed (the condition was only a warning) TypeModify, // retry after changing the data sent TypeAuth, // retry after providing credentials TypeWait, // retry after waiting (the error is temporary) TypeCount, }; /** * Get the text representation of a given error value */ inline const char* operator[](int index) { return lookup(index,s_value); } /** * Check if a given text is a valid error */ static bool isText(int index, const char* txt); /** * Get the type associated with a given error text */ static inline int type(const char* txt) { return lookup(txt,s_value,Count); } private: static TokenDict s_value[]; // Error list }; /** * This class holds a Jabber ID in form "node@domain/resource" or "node@domain" * @short A Jabber ID */ class YJINGLE_API JabberID : public String { public: /** * Constructor */ inline JabberID() {} /** * Constructor. Constructs a JID from a given string * @param jid The JID string */ inline JabberID(const char* jid) { set(jid); } /** * Constructor. Constructs a JID from user, domain, resource * @param node The node * @param domain The domain * @param resource The resource */ JabberID(const char* node, const char* domain, const char* resource = 0) { set(node,domain,resource); } /** * Get the node part of the JID * @return The node part of the JID */ inline const String& node() const { return m_node; } /** * Get the bare JID: "node@domain" * @return The bare JID */ inline const String& bare() const { return m_bare; } /** * Get the domain part of the JID * @return The domain part of the JID */ inline const String& domain() const { return m_domain; } /** * Set the domain part of the JID. * @param d The new domain part of the JID. */ inline void domain(const char* d) { set(m_node.c_str(),d,m_resource.c_str()); } /** * Get the resource part of the JID * @return The resource part of the JID */ inline const String& resource() const { return m_resource; } /** * Check if this is a full JID * @return True if this is a full JID */ inline bool isFull() const { return m_node && m_domain && m_resource; } /** * Try to match another JID to this one. If src has a resource compare it too * (case sensitive). Otherwise compare just the bare JID (case insensitive) * @param src The JID to match * @return True if matched */ inline bool match(const JabberID& src) const { return (src.resource().null() || (resource() == src.resource())) && (bare() &= src.bare()); } /** * Equality operator. Do a case senitive resource comparison and a case insensitive bare jid comparison * @param src The JID to compare with * @return True if equal */ inline bool operator==(const JabberID& src) const { return (resource() == src.resource()) && (bare() &= src.bare()); } /** * Equality operator. Build a temporary JID and compare with it * @param src The string to compare with * @return True if equal */ inline bool operator==(const String& src) const { JabberID tmp(src); return operator==(tmp); } /** * Inequality operator * @param src The JID to compare with * @return True if not equal */ inline bool operator!=(const JabberID& src) const { return !operator==(src); } /** * Inequality operator * @param src The string to compare with * @return True if not equal */ inline bool operator!=(const String& src) const { return !operator==(src); } /** * Set the resource part of the JID * @param res The new resource part of the JID */ inline void resource(const char* res) { set(m_node.c_str(),m_domain.c_str(),res); } /** * Set the data * @param jid The JID string to assign */ void set(const char* jid); /** * Set the data * @param node The node * @param domain The domain * @param resource The resource */ void set(const char* node, const char* domain, const char* resource = 0); /** * Check if the given string contains valid characters * @param value The string to check * @return True if value is valid or 0. False if value is a non empty invalid string */ static bool valid(const String& value); /** * Keep the regexp used to check the validity of a string */ static Regexp s_regExpValid; private: void parse(); // Parse the string. Set the data String m_node; // The node part String m_domain; // The domain part String m_resource; // The resource part String m_bare; // The bare JID: node@domain }; /** * This class holds an identity for a JID * @short A JID identity */ class YJINGLE_API JIDIdentity : public RefObject { public: /** * JID category enumeration */ enum Category { Account, // account Client, // client Component, // component Gateway, // gateway CategoryUnknown }; /** * JID type enumeration */ enum Type { AccountRegistered, // registered ClientPhone, // phone ComponentGeneric, // generic ComponentPresence, // presence GatewayGeneric, // generic TypeUnknown }; /** * Constructor. Build a JID identity * @param c The JID's category * @param t The JID's type * @param name The name of this identity */ inline JIDIdentity(Category c, Type t, const char* name = 0) : m_name(name), m_category(c), m_type(t) {} /** * Destructor */ virtual ~JIDIdentity() {} /** * Build an XML element from this identity * @return A valid XML element */ XMLElement* toXML(); /** * Build this identity from an XML element * @return True on succes */ bool fromXML(const XMLElement* element); /** * Get a string representation of this object * @return This object's name */ virtual const String& toString() const { return m_name; } /** * Get a pointer from this object * @param name The requested pointer's name * @return Requested pointer or 0 */ virtual void* getObject(const String& name) const { if (name == "JIDIdentity") return (void*)this; return RefObject::getObject(name); } /** * Set the name of this identity * @param name New identity name */ inline void setName(const char* name) { if (name) m_name = name; } /** * Lookup for a text associated with a given category * @return The category's name */ static inline const char* categoryText(Category c) { return lookup(c,s_category); } /** * Lookup for a value associated with a given category name * @return The category's value */ static inline Category categoryValue(const char* c) { return (Category)lookup(c,s_category,CategoryUnknown); } /** * Lookup for a text associated with a given category type * @return The category's type name */ static inline const char* typeText(Type t) { return lookup(t,s_type); } /** * Lookup for a value associated with a given category type * @return The category's type value */ static inline Type typeValue(const char* t) { return (Type)lookup(t,s_category,TypeUnknown); } private: static TokenDict s_category[]; static TokenDict s_type[]; String m_name; Category m_category; // Category Type m_type; // Type }; /** * This class holds a JID feature * @short A JID feature */ class YJINGLE_API JIDFeature : public RefObject { public: /** * Constructor * @param feature The feature to add * @param required True if this feature is required */ inline JIDFeature(XMPPNamespace::Type feature, bool required = false) : m_feature(feature), m_required(required) {} /** * Destructor */ virtual ~JIDFeature() {} /** * Check if this feature is a required one * @return True if this feature is a required one */ inline bool required() const { return m_required; } /** * XMPPNamespace::Type conversion operator */ inline operator XMPPNamespace::Type() { return m_feature; } private: XMPPNamespace::Type m_feature; // The feature bool m_required; // Required flag }; /** * This class holds a JID SASL feature (authentication methods) * @short A JID's SASL feature */ class YJINGLE_API JIDFeatureSasl : public JIDFeature { public: /** * Mechanisms used to authenticate a stream */ enum Mechanism { MechNone = 0x00, // No authentication mechanism MechMD5 = 0x01, // MD5 digest MechSHA1 = 0x02, // SHA1 digest MechPlain = 0x04, // Plain text password }; /** * Constructor * @param mech Authentication mechanisms used by the JID * @param required Required flag */ inline JIDFeatureSasl(int mech, bool required = false) : JIDFeature(XMPPNamespace::Sasl,required), m_mechanism(mech) {} /** * Get the authentication mechanisms used by the JID * @return The authentication mechanisms used by the JID */ inline int mechanism() const { return m_mechanism; } /** * Check if a given mechanism is allowed * @return True if the given mechanism is allowed */ inline bool mechanism(Mechanism mech) const { return 0 != (m_mechanism & mech); } /** * XMPPNamespace::Type conversion operator */ inline operator XMPPNamespace::Type() { return JIDFeature::operator XMPPNamespace::Type(); } /** * Authentication mechanism names */ static TokenDict s_authMech[]; private: int m_mechanism; // Authentication mechanisms }; /** * This class holds a list of JID features * @short JID feature list */ class YJINGLE_API JIDFeatureList { public: /** * Add a feature to the list * @param feature The feature to add * @param required True if this feature is required * @return False if the given feature already exists */ inline bool add(XMPPNamespace::Type feature, bool required = false) { if (get(feature)) return false; m_features.append(new JIDFeature(feature,required)); return true; } /** * Add a feature to the list. Destroy the received parameter if already in the list * @param feature The feature to add * @return False if the given feature already exists */ inline bool add(JIDFeature* feature) { if (!feature || get(*feature)) { TelEngine::destruct(feature); return false; } m_features.append(feature); return true; } /** * Remove a feature from the list * @param feature The feature to remove */ inline void remove(XMPPNamespace::Type feature) { m_features.remove(get(feature),true); } /** * Get a feature from the list * @param feature The feature to get * @return Pointer to the feature or 0 if it doesn't exists */ JIDFeature* get(XMPPNamespace::Type feature); /** * Add 'feature' children to the given element * @param element The target XMLElement * @return The given element */ XMLElement* addTo(XMLElement* element); /** * Update the list from 'feature' children of the given element * @param element The source XMLElement * @param reset True to clear the list before updating * @return The given element */ void fromXml(XMLElement* element, bool reset = true); /** * Clear the feature list */ inline void clear() { m_features.clear(); } private: ObjList m_features; // The features }; /** * This class is a general XMPP utilities * @short General XMPP utilities */ class YJINGLE_API XMPPUtils { public: /** * Iq type enumeration */ enum IqType { IqSet, // set IqGet, // get IqResult, // result IqError, // error IqCount, }; /** * Command action enumeration */ enum CommandAction { CommExecute, CommCancel, CommPrev, CommNext, CommComplete, }; /** * Command status enumeration */ enum CommandStatus { CommExecuting, CommCompleted, CommCancelled, }; /** * Create an XML element with an 'xmlns' attribute * @param name Element's name * @param ns 'xmlns' attribute * @param text Optional text for the element * @return A valid XMLElement pointer */ static XMLElement* createElement(const char* name, XMPPNamespace::Type ns, const char* text = 0); /** * Create an XML element with an 'xmlns' attribute * @param type Element's type * @param ns 'xmlns' attribute * @param text Optional text for the element * @return A valid XMLElement pointer */ static XMLElement* createElement(XMLElement::Type type, XMPPNamespace::Type ns, const char* text = 0); /** * Create an 'iq' element * @param type Iq type as enumeration * @param from The 'from' attribute * @param to The 'to' attribute * @param id The 'id' attribute * @return A valid XMLElement pointer */ static XMLElement* createIq(IqType type, const char* from, const char* to, const char* id); /** * Create an 'iq' element with a 'bind' child containing the resources * @param from The 'from' attribute * @param to The 'to' attribute * @param id The 'id' attribute * @param resources The resources to bind (strings) * @return A valid XMLElement pointer */ static XMLElement* createIqBind(const char* from, const char* to, const char* id, const ObjList& resources); /** * Create an 'iq' element with a 'vcard' child * @param get True to set the iq's type to 'get', false to set it to 'set' * @param from The 'from' attribute * @param to The 'to' attribute * @param id The 'id' attribute * @return A valid XMLElement pointer */ static XMLElement* createVCard(bool get, const char* from, const char* to, const char* id); /** * Create a 'command' element * @param action The command action * @param node The command * @param sessionId Optional session ID for the command * @return A valid XMLElement pointer */ static XMLElement* createCommand(CommandAction action, const char* node, const char* sessionId = 0); /** * Create an 'identity' element * @param category The 'category' attribute * @param type The 'type' attribute * @param name The 'name' attribute * @return A valid XMLElement pointer */ static XMLElement* createIdentity(const char* category, const char* type, const char* name); /** * Create an 'iq' of type 'get' element with a 'query' child * @param from The 'from' attribute * @param to The 'to' attribute * @param id The 'id' attribute * @param info True to create a query info request. False to create a query items request * @return A valid XMLElement pointer */ static XMLElement* createIqDisco(const char* from, const char* to, const char* id, bool info = true); /** * Create an 'iq' of type 'result' element with a 'query' child in response to * a disco info request * @param from The 'from' attribute * @param to The 'to' attribute * @param id The 'id' attribute * @param features Features to be added to response * @param identity The identity of the entity sending the response * @return A valid XMLElement pointer */ static XMLElement* createDiscoInfoRes(const char* from, const char* to, const char* id, JIDFeatureList* features, JIDIdentity* identity); /** * Create a 'error' element * @param type Error type * @param error The error * @param text Optional text to add to the error element * @return A valid XMLElement pointer */ static XMLElement* createError(XMPPError::ErrorType type, XMPPError::Type error, const char* text = 0); /** * Create an error from a received element. Consume the received element * Reverse 'to' and 'from' attributes * @param xml Received element * @param type Error type * @param error The error * @param text Optional text to add to the error element * @return A valid XMLElement pointer or 0 if xml is 0 */ static XMLElement* createError(XMLElement* xml, XMPPError::ErrorType type, XMPPError::Type error, const char* text = 0); /** * Create a 'stream:error' element * @param error The XMPP defined condition * @param text Optional text to add to the error * @return A valid XMLElement pointer */ static XMLElement* createStreamError(XMPPError::Type error, const char* text = 0); /** * Build a register query element * @param type Iq type as enumeration * @param from The 'from' attribute * @param to The 'to' attribute * @param id The 'id' attribute * @param child1 Optional child of query element * @param child2 Optional child of query element * @param child3 Optional child of query element * @return Valid XMLElement pointer */ static XMLElement* createRegisterQuery(IqType type, const char* from, const char* to, const char* id, XMLElement* child1 = 0, XMLElement* child2 = 0, XMLElement* child3 = 0); /** * Build an register query element used to create/set username/password * @param from The 'from' attribute * @param to The 'to' attribute * @param id The 'id' attribute * @param username The username * @param password The password * @return Valid XMLElement pointer */ static inline XMLElement* createRegisterQuery(const char* from, const char* to, const char* id, const char* username, const char* password) { return createRegisterQuery(XMPPUtils::IqSet,from,to,id, new XMLElement(XMLElement::Username,0,username), new XMLElement(XMLElement::Password,0,password)); } /** * Check if the given element has an attribute 'xmlns' equal to a given value * @param element Element to check * @param ns Namespace value to check * @return True if the given element has the requested namespace */ static bool hasXmlns(XMLElement& element, XMPPNamespace::Type ns); /** * Decode a received stream error or stanza error * @param element The received element * @param error The error condition * @param text The stanza's error or error text */ static void decodeError(XMLElement* element, String& error, String& text); /** * Encode EPOCH time given in seconds to a date/time profile as defined in * XEP-0082 and XML Schema Part 2: Datatypes Second Edition * @param buf Destination string * @param timeSec The time to encode (in seconds) * @param fractions Optional second fractions */ static void encodeDateTimeSec(String& buf, unsigned int timeSec, unsigned int fractions = 0); /** * Decode a date/time profile as defined in XEP-0082 * and XML Schema Part 2: Datatypes Second Edition to EPOCH time * @param time The date/time string * @param fractions Pointer to integer to be filled with second fractions, if present * @return The decoded time in seconds, -1 on error */ static unsigned int decodeDateTimeSec(const String& time, unsigned int* fractions = 0); /** * Print an XMLElement to a string * @param xmlStr The destination string * @param element The element to print * @param indent The indent. 0 if it is the root element */ static void print(String& xmlStr, XMLElement& element, const char* indent = 0); /** * Split a string at a delimiter character and fills a named list with its parts * Skip empty parts * @param dest The destination NamedList * @param src Pointer to the string * @param sep The delimiter * @param nameFirst True to add the parts as name and index as value. * False to do the other way */ static bool split(NamedList& dest, const char* src, const char sep, bool nameFirst); /** * Decode a comma separated list of flags and put them into an integer mask * @param src Source string * @param dict Dictionary containing flag names and values * @return The mask of found flags */ static int decodeFlags(const String& src, const TokenDict* dict); /** * Encode a mask of flags to a comma separated list of names * @param dest Destination string * @param src Source mask * @param dict Dictionary containing flag names and values */ static void buildFlags(String& dest, int src, const TokenDict* dict); /** * Add child elements from a list to a destination element * @param dest Destination XMLElement * @param list A list containing XML elements * @return True if at least one child was added */ static bool addChidren(XMLElement* dest, ObjList& list); /** * Get the type of an 'iq' stanza as enumeration * @param text The text to check * @return Iq type as enumeration */ static inline IqType iqType(const char* text) { return (IqType)lookup(text,s_iq,IqCount); } /** * Keep the types of 'iq' stanzas */ static TokenDict s_iq[]; /** * Keep the command actions */ static TokenDict s_commandAction[]; /** * Keep the command status */ static TokenDict s_commandStatus[]; }; /** * This class holds a 4-state direction value (such as subscription states) * @short Direction flags */ class YJINGLE_API XMPPDirVal { public: enum Direction { None = 0, To = 1, From = 2, Both = 3, }; /** * Constructor * @param flags Flag(s) to set */ inline XMPPDirVal(int flags = None) : m_value(flags) {} /** * Constructor * @param name The name of the flag used to initialize this object */ inline XMPPDirVal(const char* name) : m_value(lookup(name,None)) {} /** * Replace all flags * @param flag The new value of the flags */ inline void replace(int flag) { m_value = flag; } /** * Replace all flags from a value's name * @param name The name of the flag used to replace this value */ inline void replace(const char* name) { m_value = lookup(name,None); } /** * Set one or more flags * @param flag Flag(s) to set */ inline void set(int flag) { m_value |= flag; } /** * Reset one or more flags * @param flag Flag(s) to reset */ inline void reset(int flag) { m_value &= ~flag; } /** * Check if a given bit mask is set * @param mask Bit mask to check * @return True if the given bit mask is set */ inline bool flag(int mask) const { return (m_value & mask) != 0; } /** * Check if the 'To' flag is set * @return True if the 'To' flag is set */ inline bool to() const { return flag(To); } /** * Check if the 'From' flag is set * @return True if the 'From' flag is set */ inline bool from() const { return flag(From); } /** * Cast operator */ inline operator int() { return m_value; } /** * Get the name of a flag * @param flag The flag * @param defVal Value to return if not found * @return The name of the requested flag */ static inline const char* lookup(int flag, const char* defVal = "") { return TelEngine::lookup(flag,s_names,defVal); } /** * Get the value associated with a flag name * @param name The flag name * @param defVal Value to return if not found * @return The value of the requested flag name */ static inline int lookup(const char* name, int defVal = None) { return TelEngine::lookup(name,s_names,defVal); } /** * Keep the flag names */ static TokenDict s_names[]; private: int m_value; // The value }; }; #endif /* __XMPPUTILS_H */ /* vi: set ts=8 sw=4 sts=4 noet: */