Changed jabber library layout. Specialized services can be attached to the engine to process specific stream events.

git-svn-id: http://voip.null.ro/svn/yate@1721 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2008-02-12 13:54:29 +00:00
parent 372ba06925
commit f2553f398d
11 changed files with 6017 additions and 5398 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -28,117 +28,81 @@ using namespace TelEngine;
/**
* JGEngine
*/
JGEngine::JGEngine(JBEngine* jb, const NamedList& params)
: JBClient(jb),
Mutex(true),
m_sessionIdMutex(true),
m_sessionId(1)
JGEngine::JGEngine(JBEngine* engine, const NamedList* params, int prio)
: JBService(engine,"jgengine",params,prio),
m_sessionIdMutex(true),
m_sessionId(1),
m_stanzaTimeout(10000),
m_useSidAttr(false)
{
debugName("jgengine");
initialize(params);
XDebug(this,DebugAll,"JGEngine. [%p]",this);
}
JGEngine::~JGEngine()
{
XDebug(this,DebugAll,"~JGEngine. [%p]",this);
cancelThreads();
}
// Create private stream(s) to get events from sessions
void JGEngine::initialize(const NamedList& params)
{
debugLevel(params.getIntValue("debug_level",debugLevel()));
int timeout = params.getIntValue("stanza_timeout",10);
if (timeout < 10)
timeout = 10;
m_stanzaTimeout = timeout * 1000;
m_useSidAttr = params.getBoolValue("session_sid",false);
if (debugAt(DebugInfo)) {
String s;
s << " stanza_timeout=" << (unsigned int)m_stanzaTimeout;
s << " session_sid=" << m_useSidAttr;
Debug(this,DebugInfo,"Jabber Jingle service initialized:%s [%p]",
s.c_str(),this);
}
if (!m_initialized) {
m_initialized = true;
int c = params.getIntValue("private_process_threads",1);
for (int i = 0; i < c; i++)
JBThread::start(JBThread::Jingle,this,this,2,Thread::Normal);
}
}
// Make an outgoing call
JGSession* JGEngine::call(const String& localJID, const String& remoteJID,
XMLElement* media, XMLElement* transport, const char* message)
{
DDebug(this,DebugAll,"call. New outgoing call from '%s' to '%s'.",
DDebug(this,DebugAll,"New outgoing call from '%s' to '%s'",
localJID.c_str(),remoteJID.c_str());
JBComponentStream* stream = m_engine->getStream();
// Get a stream from the engine
JBStream* stream = 0;
if (engine()->protocol() == JBEngine::Component)
stream = engine()->getStream();
else {
// Client: the stream must be already created
JabberID jid(localJID);
stream = engine()->getStream(&jid,false);
}
// Create outgoing session
if (stream) {
// Create outgoing session
JGSession* session = new JGSession(this,stream,localJID,remoteJID);
JGSession* session = new JGSession(this,stream,localJID,remoteJID,
media,transport,m_useSidAttr,message);
if (session->state() != JGSession::Destroy) {
if (message)
session->sendMessage(message);
session->initiate(media,transport);
m_sessions.append(session);
return (session && session->ref() ? session : 0);
}
session->deref();
TelEngine::destruct(session);
}
DDebug(this,DebugCall,"call. Outgoing call to '%s' failed. No stream.",remoteJID.c_str());
Debug(this,DebugNote,"Outgoing call from '%s' to '%s' failed: %s",
localJID.c_str(),remoteJID.c_str(),
stream?"can't create stream":"failed to send data");
return 0;
}
bool JGEngine::receive()
{
Lock lock(this);
JBEvent* event = m_engine->getEvent(Time::msecNow());
if (!event)
return false;
bool checkSession = true;
// Check for new incoming session
if (event->type() == JBEvent::IqJingleSet && event->child()) {
const char* type = event->child()->getAttribute("type");
JGSession::Action action = JGSession::action(type);
if (action == JGSession::ActInitiate) {
m_sessions.append(new JGSession(this,event));
return true;
}
}
// Check if it's a message from a user with resource
else if (event->type() == JBEvent::Message) {
JabberID from(event->from());
checkSession = !from.resource().null();
}
// Add event to the appropriate session
if (checkSession) {
ObjList* obj = m_sessions.skipNull();
for (; obj; obj = obj->skipNext()) {
JGSession* session = static_cast<JGSession*>(obj->get());
if (session->receive(event))
return true;
}
}
// Return unhandled event to the jabber engine
m_engine->returnEvent(event);
return false;
}
void JGEngine::runReceive()
{
while(1) {
if (!receive())
Thread::msleep(2,true);
}
}
bool JGEngine::process()
{
bool ok = false;
for (;;) {
JGEvent* event = getEvent(Time::msecNow());
if (!event)
break;
ok = true;
if (event->type() == JGEvent::Destroy) {
DDebug(this,DebugAll,"Deleting internal event(%p) 'Destroy'.",event);
delete event;
continue;
}
processEvent(event);
}
return ok;
}
void JGEngine::runProcess()
{
while(1) {
if (!process())
Thread::msleep(2,true);
}
}
// Get events from sessions
JGEvent* JGEngine::getEvent(u_int64_t time)
{
JGEvent* event = 0;
@ -155,22 +119,135 @@ JGEvent* JGEngine::getEvent(u_int64_t time)
continue;
unlock();
if (0 != (event = s->getEvent(time)))
return event;
if (event->type() == JGEvent::Destroy) {
DDebug(this,DebugAll,"Deleting internal event (%p,Destroy)",event);
delete event;
}
else
return event;
lock();
}
unlock();
return 0;
}
// Default event processor
void JGEngine::defProcessEvent(JGEvent* event)
{
if (!event)
return;
DDebug(this,DebugAll,"JGEngine::defprocessEvent. Deleting event(%p). Type %u.",
DDebug(this,DebugAll,"JGEngine::defprocessEvent. Deleting event (%p,%u)",
event,event->type());
delete event;
}
// Accept an event from the Jabber engine
bool JGEngine::accept(JBEvent* event, bool& processed, bool& insert)
{
if (!(event && event->stream()))
return false;
XMLElement* child = event->child();
XMPPError::Type error = XMPPError::NoError;
const char* errorText = 0;
Lock lock(this);
switch (event->type()) {
case JBEvent::IqJingleGet:
// Jingle stanzas should never have type='get'
Debug(this,DebugNote,"Received iq jingle stanza with type='get'");
return false;
case JBEvent::IqJingleSet:
case JBEvent::IqJingleRes:
case JBEvent::IqJingleErr:
if (child) {
// Jingle clients may send the session id as 'id' or 'sid'
bool useSid = false;
String sid = child->getAttribute("id");
if (!sid) {
sid = child->getAttribute("sid");
useSid = false;
}
if (!sid) {
error = XMPPError::SBadRequest;
errorText = "Missing or empty session id";
break;
}
// Check for a destination by SID
for (ObjList* o = m_sessions.skipNull(); o; o = o->skipNext()) {
JGSession* session = static_cast<JGSession*>(o->get());
if (sid == session->sid()) {
session->enqueue(event);
processed = true;
return true;
}
}
// Check if this an incoming session request
if (event->type() == JBEvent::IqJingleSet) {
const char* type = event->child()->getAttribute("type");
int action = lookup(type,JGSession::s_actions,JGSession::ActCount);
if (action == JGSession::ActInitiate) {
if (!event->stream()->ref()) {
error = XMPPError::SInternal;
break;
}
DDebug(this,DebugAll,"New incoming call from '%s' to '%s'",
event->from().c_str(),event->to().c_str());
m_sessions.append(new JGSession(this,event,sid,useSid));
processed = true;
return true;
}
}
error = XMPPError::SRequest;
errorText = "Unknown session";
}
else
error = XMPPError::SBadRequest;
break;
case JBEvent::IqResult:
case JBEvent::WriteFail:
// Sessions always set the id of sent stanzas to their local id
for (ObjList* o = m_sessions.skipNull(); o; o = o->skipNext()) {
JGSession* session = static_cast<JGSession*>(o->get());
if (event->id().startsWith(session->m_localSid)) {
session->enqueue(event);
processed = true;
return true;
}
}
break;
case JBEvent::Terminated:
case JBEvent::Destroy:
for (ObjList* o = m_sessions.skipNull(); o; o = o->skipNext()) {
JGSession* session = static_cast<JGSession*>(o->get());
if (event->stream() == session->stream())
session->enqueue(new JBEvent((JBEvent::Type)event->type(),
event->stream(),0));
}
break;
default:
return false;
}
if (error == XMPPError::NoError)
return false;
// Send error
XMLElement* iq = XMPPUtils::createIq(XMPPUtils::IqError,
event->to(),event->from(),event->id());
iq->addChild(event->releaseXML());
iq->addChild(XMPPUtils::createError(XMPPError::TypeModify,error,errorText));
event->stream()->sendStanza(iq);
TelEngine::destruct(event);
processed = true;
return true;
}
// Process generated events
void JGEngine::processEvent(JGEvent* event)
{
Debug(this,DebugStub,"JGEngine::processEvent. Calling default processor");
defProcessEvent(event);
}
// Create a local session id
void JGEngine::createSessionId(String& id)
{
Lock lock(m_sessionIdMutex);
@ -179,56 +256,28 @@ void JGEngine::createSessionId(String& id)
m_sessionId++;
}
void JGEngine::processEvent(JGEvent* event)
{
DDebug(this,DebugAll,"JGEngine::processEvent. Call default.");
defProcessEvent(event);
}
void JGEngine::removeSession(JGSession* session)
{
if (!session)
return;
Lock lock(this);
m_sessions.remove(session,false);
}
/**
* JGEvent
*/
JGEvent::JGEvent(Type type, JGSession* session, XMLElement* element)
: m_type(type),
m_session(0),
m_element(element),
m_action(JGSession::ActCount)
{
XDebug(DebugAll,"JGEvent::JGEvent [%p].",this);
if (session && session->ref())
m_session = session;
}
JGEvent::~JGEvent()
{
if (m_session) {
m_session->eventTerminated(this);
m_session->deref();
TelEngine::destruct(m_session);
}
if (m_element)
delete m_element;
XDebug(DebugAll,"JGEvent::~JGEvent [%p].",this);
XDebug(DebugAll,"JGEvent::~JGEvent [%p]",this);
}
bool JGEvent::final()
void JGEvent::init(JGSession* session)
{
// Check: Terminated, Destroy
switch (type()) {
case Terminated:
case Destroy:
return true;
default: ;
}
return false;
XDebug(DebugAll,"JGEvent::JGEvent [%p]",this);
if (session && session->ref())
m_session = session;
if (m_element)
m_id = m_element->getAttribute("id");
}
/* vi: set ts=8 sw=4 sts=4 noet: */

File diff suppressed because it is too large Load Diff

View File

@ -61,6 +61,16 @@ XMLElement::XMLElement()
// XDebug(DebugAll,"XMLElement::XMLElement [%p]. Name: '%s'",this,name());
}
XMLElement::XMLElement(const XMLElement& src)
: m_type(Invalid), m_owner(true), m_element(0)
{
TiXmlElement* e = src.get();
if (!e)
return;
m_element = new TiXmlElement(*e);
setType();
}
XMLElement::XMLElement(const char* name, NamedList* attributes,
const char* text)
: m_type(Unknown), m_owner(true), m_element(0)
@ -164,6 +174,8 @@ void XMLElement::addChild(XMLElement* element)
if (tiElement)
m_element->LinkEndChild(tiElement);
}
if (element)
delete element;
}
XMLElement* XMLElement::findFirstChild(const char* name)

View File

@ -55,13 +55,16 @@ class XMLParser;
class XMLElementOut;
/**
* This class holds an XML element.
* @short An XML element.
* This class holds an XML element
* @short An XML element
*/
class YJINGLE_API XMLElement
{
friend class XMLParser;
public:
/**
* Element type as enumeration
*/
enum Type {
// *** Stream related elements
StreamStart, // stream:stream
@ -98,82 +101,87 @@ public:
/**
* Constructor.
* Constructs an StreamEnd element.
* Constructs a StreamEnd element
*/
XMLElement();
/**
* Copy constructor
*/
XMLElement(const XMLElement& src);
/**
* Constructor.
* Constructs an XML element with a TiXmlElement element with the given name.
* Used for outgoing elements.
* @param name The element's name.
* @param attributes Optional list of attributes.
* @param text Optional text for the XML element.
* Used for outgoing elements
* @param name The element's name
* @param attributes Optional list of attributes
* @param text Optional text for the XML element
*/
XMLElement(const char* name, NamedList* attributes = 0, const char* text = 0);
/**
* Constructor.
* Constructs an XML element with a TiXmlElement element with the given type's name.
* Used for outgoing elements.
* @param type The element's type.
* @param attributes Optional list of attributes.
* @param text Optional text for the XML element.
* Used for outgoing elements
* @param type The element's type
* @param attributes Optional list of attributes
* @param text Optional text for the XML element
*/
XMLElement(Type type, NamedList* attributes = 0, const char* text = 0);
/**
* Destructor. Deletes the underlying TiXmlElement if owned.
* Destructor. Deletes the underlying TiXmlElement if owned
*/
virtual ~XMLElement();
/**
* Get the type of this object.
* @return The type of this object as enumeration.
* Get the type of this object
* @return The type of this object as enumeration
*/
inline Type type() const
{ return m_type; }
/**
* Get the TiXmlElement's name.
* @return The name of the TiXmlElement object or 0.
* Get the TiXmlElement's name
* @return The name of the TiXmlElement object or 0
*/
inline const char* name() const
{ return valid() ? m_element->Value() : 0; }
/**
* Check if the TiXmlElement's name is the given text.
* @param text Text to compare with.
* @return False if text is 0 or not equal to name.
* Check if the TiXmlElement's name is the given text
* @param text Text to compare with
* @return False if text is 0 or not equal to name
*/
inline bool nameIs(const char* text) const
{ return (text && name() && (0 == ::strcmp(name(),text))); }
/**
* Get the validity of this object.
* @return True if m_element is non null.
* Get the validity of this object
* @return True if m_element is non null
*/
inline bool valid() const
{ return m_element != 0; }
/**
* Put the element in a buffer.
* @param dest Destination string.
* @param unclose True to leave the tag unclosed.
* Put the element in a buffer
* @param dest Destination string
* @param unclose True to leave the tag unclosed
*/
void toString(String& dest, bool unclose = false) const;
/**
* Set the value of an existing attribute or adds a new one.
* @param name Attribute's name.
* @param value Attribute's value.
* Set the value of an existing attribute or adds a new one
* @param name Attribute's name
* @param value Attribute's value
*/
void setAttribute(const char* name, const char* value);
/**
* Set the value of an existing attribute or adds a new one if the value's length is not 0.
* @param name Attribute's name.
* @param value Attribute's value.
* Set the value of an existing attribute or adds a new one if the value's length is not 0
* @param name Attribute's name
* @param value Attribute's value
*/
inline void setAttributeValid(const char* name, const String& value) {
if (value)
@ -181,9 +189,9 @@ public:
}
/**
* Set the value of an existing attribute or adds a new one from an integer.
* @param name Attribute's name.
* @param value Attribute's value.
* Set the value of an existing attribute or adds a new one from an integer
* @param name Attribute's name
* @param value Attribute's value
*/
inline void setAttribute(const char* name, int value) {
String s(value);
@ -191,17 +199,17 @@ public:
}
/**
* Get the value of an attribute.
* @param name Attribute's name.
* @return Attribute's value. May be 0 if doesn't exists or empty.
* Get the value of an attribute
* @param name Attribute's name
* @return Attribute's value. May be 0 if doesn't exists or empty
*/
const char* getAttribute(const char* name);
/**
* Get the value of an attribute.
* @param name Attribute's name.
* @param value Destination string.
* @return True if attribute with the given name exists and is not empty.
* Get the value of an attribute
* @param name Attribute's name
* @param value Destination string
* @return True if attribute with the given name exists and is not empty
*/
inline bool getAttribute(const char* name, String& value) {
value = getAttribute(name);
@ -209,79 +217,77 @@ public:
}
/**
* Check if an attribute with the given name and value exists.
* @param name Attribute's name.
* @param value Attribute's value.
* @return True/False.
* Check if an attribute with the given name and value exists
* @param name Attribute's name
* @param value Attribute's value
* @return True/False
*/
bool hasAttribute(const char* name, const char* value);
/**
* Get the text of this XML element.
* @return Pointer to the text of this XML element or 0.
* Get the text of this XML element
* @return Pointer to the text of this XML element or 0
*/
const char* getText();
/**
* Add a child to this object. Release the received element.
* On exit 'element' will be invalid if the operation succeedded.
* To succeed, 'element' MUST own his 'm_element'.
* @param element XMLElement to add.
* Add a child to this object. Release the received element
* @param element XMLElement to add
*/
void addChild(XMLElement* element);
/**
* Find the first child element.
* @param name Optional name of the child.
* @return Pointer to an XMLElement or 0 if not found.
* Find the first child element
* @param name Optional name of the child
* @return Pointer to an XMLElement or 0 if not found
*/
XMLElement* findFirstChild(const char* name = 0);
/**
* Find the first child element of the given type.
* @param type Child's type to find.
* @return Pointer to an XMLElement or 0 if not found.
* Find the first child element of the given type
* @param type Child's type to find
* @return Pointer to an XMLElement or 0 if not found
*/
inline XMLElement* findFirstChild(Type type)
{ return findFirstChild(typeName(type)); }
/**
* Find the next child element.
* @param element Starting XMLElement. O to find from the beginning.
* @param name Optional name of the child.
* @return Pointer to an XMLElement or 0 if not found.
* Find the next child element
* @param element Starting XMLElement. O to find from the beginning
* @param name Optional name of the child
* @return Pointer to an XMLElement or 0 if not found
*/
XMLElement* findNextChild(const XMLElement* element, const char* name = 0);
/**
* Find the next child element of the given type.
* @param element Starting XMLElement. O to find from the beginning.
* @param type Child's type to find.
* @return Pointer to an XMLElement or 0 if not found.
* Find the next child element of the given type
* @param element Starting XMLElement. O to find from the beginning
* @param type Child's type to find
* @return Pointer to an XMLElement or 0 if not found
*/
inline XMLElement* findNextChild(const XMLElement* element, Type type)
{ return findNextChild(element,typeName(type)); }
/**
* Find the first attribute.
* @return Pointer to the first attribute or 0.
* Find the first attribute
* @return Pointer to the first attribute or 0
*/
inline const TiXmlAttribute* firstAttribute() const
{ return valid() ? m_element->FirstAttribute() : 0; }
/**
* Get the name associated with the given type.
* @param type Element type as enumeration.
* @return Pointer to the name or 0.
* Get the name associated with the given type
* @param type Element type as enumeration
* @return Pointer to the name or 0
*/
static inline const char* typeName(Type type)
{ return lookup(type,s_names); }
/**
* check if the given text is equal to the one associated with the given type.
* @param txt Text to compare.
* @param type Element type as enumeration.
* @return True if txt equals the text associated with the given type.
* check if the given text is equal to the one associated with the given type
* @param txt Text to compare
* @param type Element type as enumeration
* @return True if txt equals the text associated with the given type
*/
static inline bool isType(const char* txt, Type type) {
const char* s = typeName(type);
@ -294,28 +300,28 @@ protected:
* Constructs an XML element from a TiXmlElement.
* Used to extract elements from parser and access the children.
* When extracting elements from parser the object will own the TiXmlElement.
* When accessing the children, the object will not own the TiXmlElement.
* @param element Pointer to a valid TiXmlElement.
* @param owner Owner flag.
* When accessing the children, the object will not own the TiXmlElement
* @param element Pointer to a valid TiXmlElement
* @param owner Owner flag
*/
XMLElement(TiXmlElement* element, bool owner);
/**
* Get the underlying TiXmlElement.
* @return The underlying TiXmlElement object or 0.
* Get the underlying TiXmlElement
* @return The underlying TiXmlElement object or 0
*/
inline TiXmlElement* get() const
{ return m_element; }
/**
* Release the ownership of the underlying TiXmlElement
* and returns it if the object owns it.
* @return The underlying TiXmlElement object or 0 if not owned or 0.
* Release the ownership of the underlying TiXmlElement
* and returns it if the object owns it
* @return The underlying TiXmlElement object or 0 if not owned or 0
*/
TiXmlElement* releaseOwnership();
/**
* Associations between XML element name and type.
* Associations between XML element name and type
*/
static TokenDict s_names[];
@ -331,22 +337,22 @@ private:
/**
* This class is responsable of parsing incoming data.
* Keeps the resulting XML elements and the input buffer.
* @short An XML parser.
* Keeps the resulting XML elements and the input buffer
* @short An XML parser
*/
class YJINGLE_API XMLParser : public TiXmlDocument, public Mutex
{
public:
/**
* Constructor.
* Constructs an XML parser.
* Constructs an XML parser
*/
inline XMLParser()
: TiXmlDocument(), Mutex(true), m_findstart(true)
{}
/**
* Destructor.
* Destructor
*/
virtual ~XMLParser()
{}
@ -354,40 +360,40 @@ public:
/**
* Add data to buffer. Parse the buffer.
* On success, the already parsed data is removed from buffer.
* This method is thread safe.
* @param data Pointer to the data to consume.
* @param len Data length.
* @return True on successfully parsed.
* This method is thread safe
* @param data Pointer to the data to consume
* @param len Data length
* @return True on successfully parsed
*/
bool consume(const char* data, u_int32_t len);
/**
* Extract the first XML element from document.
* Remove non-element children of the document (e.g. declaration).
* This method is thread safe.
* @return Pointer to an XMLElement or 0 if the document is empty.
* This method is thread safe
* @return Pointer to an XMLElement or 0 if the document is empty
*/
XMLElement* extract();
/**
* Get a copy of the parser's buffer.
* @param dest Destination string.
* Get a copy of the parser's buffer
* @param dest Destination string
*/
inline void getBuffer(String& dest) const
{ dest = m_buffer; }
/**
* Clear the parser's input buffer and already parsed elements. Reset data.
* Clear the parser's input buffer and already parsed elements. Reset data
*/
void reset();
/**
* The maximum allowed buffer length.
* The maximum allowed buffer length
*/
static u_int32_t s_maxDataBuffer;
/**
* The XML encoding.
* The XML encoding
*/
static TiXmlEncoding s_xmlEncoding;
@ -397,24 +403,24 @@ private:
};
/**
* This class holds an XML element to be sent through a stream.
* @short An outgoing XML element.
* This class holds an XML element to be sent through a stream
* @short An outgoing XML element
*/
class YJINGLE_API XMLElementOut : public RefObject
{
public:
/**
* Constructor.
* @param element The XML element.
* @param senderID Optional sender id.
* Constructor
* @param element The XML element
* @param senderID Optional sender id
*/
inline XMLElementOut(XMLElement* element, const char* senderID = 0)
: m_element(element), m_offset(0), m_id(senderID)
{}
/**
* Destructor.
* Delete m_element if not 0.
* Destructor
* Delete m_element if not 0
*/
virtual ~XMLElementOut() {
if (m_element)
@ -422,37 +428,37 @@ public:
}
/**
* Get the underlying element.
* @return The underlying element.
* Get the underlying element
* @return The underlying element
*/
inline XMLElement* element() const
{ return m_element; }
/**
* Get the data buffer.
* @return The data buffer.
* Get the data buffer
* @return The data buffer
*/
inline String& buffer()
{ return m_buffer; }
/**
* Get the id member.
* @return The id member.
* Get the id member
* @return The id member
*/
inline const String& id() const
{ return m_id; }
/**
* Get the remainig byte count to send.
* @return The unsent number of bytes.
* Get the remainig byte count to send
* @return The unsent number of bytes
*/
inline u_int32_t dataCount()
{ return m_buffer.length() - m_offset; }
/**
* Get the remainig data to send. Set the buffer if not already set.
* @param nCount The number of unsent bytes.
* @return Pointer to the remaining data or 0.
* Get the remainig data to send. Set the buffer if not already set
* @param nCount The number of unsent bytes
* @return Pointer to the remaining data or 0
*/
inline const char* getData(u_int32_t& nCount) {
if (!m_buffer)
@ -462,8 +468,8 @@ public:
}
/**
* Increase the offset with nCount bytes.
* @param nCount The number of bytes sent.
* Increase the offset with nCount bytes
* @param nCount The number of bytes sent
*/
inline void dataSent(u_int32_t nCount) {
m_offset += nCount;
@ -472,9 +478,9 @@ public:
}
/**
* Release the ownership of m_element.
* The caller is responsable of returned pointer.
* @return XMLElement pointer or 0.
* Release the ownership of m_element
* The caller is responsable of returned pointer
* @return XMLElement pointer or 0
*/
inline XMLElement* release() {
XMLElement* e = m_element;
@ -483,14 +489,14 @@ public:
}
/**
* Fill a buffer with the XML element to send.
* @param buffer The buffer to fill.
* Fill a buffer with the XML element to send
* @param buffer The buffer to fill
*/
inline void toBuffer(String& buffer)
{ if (m_element) m_element->toString(buffer); }
/**
* Fill the buffer with the XML element to send.
* Fill the buffer with the XML element to send
*/
inline void prepareToSend()
{ toBuffer(m_buffer); }

View File

@ -48,7 +48,6 @@ TokenDict XMPPNamespace::s_value[] = {
{"http://jabber.org/protocol/jingle/info/dtmf#errors", DtmfError},
{"http://jabber.org/protocol/commands", Command},
{"http://www.google.com/xmpp/protocol/voice/v1", CapVoiceV1},
{0,0}
};
@ -144,11 +143,11 @@ void JabberID::set(const char* node, const char* domain, const char* resource)
if (resource != m_resource.c_str())
m_resource = resource;
clear();
if (m_node.length())
if (m_node)
*this << m_node << "@";
*this << m_domain;
m_bare = *this;
if (m_node.length() && m_resource.length())
if (m_node && m_resource)
*this << "/" << m_resource;
}
@ -186,7 +185,7 @@ void JabberID::parse()
}
// Set bare JID
m_bare = "";
if (m_node.length())
if (m_node)
m_bare << m_node << "@";
m_bare << m_domain;
}
@ -229,33 +228,6 @@ bool JIDIdentity::fromXML(const XMLElement* element)
return true;
}
/**
* JIDFeatureList
*/
JIDFeature* JIDFeatureList::get(XMPPNamespace::Type feature)
{
ObjList* obj = m_features.skipNull();
for (; obj; obj = obj->skipNext()) {
JIDFeature* f = static_cast<JIDFeature*>(obj->get());
if (*f == feature)
return f;
}
return 0;
}
XMLElement* JIDFeatureList::addTo(XMLElement* element)
{
if (!element)
return 0;
ObjList* obj = m_features.skipNull();
for (; obj; obj = obj->skipNext()) {
JIDFeature* f = static_cast<JIDFeature*>(obj->get());
XMLElement* feature = new XMLElement(XMLElement::Feature);
feature->setAttribute("var",s_ns[*f]);
element->addChild(feature);
}
return element;
}
/**
* XMPPUtils
@ -402,6 +374,29 @@ XMLElement* XMPPUtils::createStreamError(XMPPError::Type error, const char* text
return element;
}
void XMPPUtils::decodeError(XMLElement* element, String& error, String& text)
{
if (!element)
return;
if (element->type() != XMLElement::StreamError && element->type() != XMLElement::Error)
return;
error = "";
text = "";
element = element->findFirstChild("error");
if (!element)
return;
XMLElement* child = element->findFirstChild();
if (!child)
return;
error = child->name();
child = element->findFirstChild("text");
const char* t = child ? child->getText() : 0;
if (t)
text = t;
}
void XMPPUtils::print(String& xmlStr, XMLElement* element, const char* indent)
{
#define STARTLINE(indent) "\r\n" << indent
@ -463,22 +458,17 @@ bool XMPPUtils::split(NamedList& dest, const char* src, const char sep,
{
if (!src)
return false;
u_int32_t index = 1;
for (u_int32_t i = 0; src[i];) {
// Skip separator(s)
for (; src[i] && src[i] == sep; i++) ;
// Find first separator
u_int32_t start = i;
for (; src[i] && src[i] != sep; i++) ;
// Get part
if (start != i) {
String tmp(src + start,i - start);
if (nameFirst)
dest.addParam(tmp,String((int)index++));
else
dest.addParam(String((int)index++),tmp);
}
unsigned int index = 1;
String s = src;
ObjList* obj = s.split(sep,false);
for (ObjList* o = obj->skipNull(); o; o = o->skipNext(), index++) {
String* tmp = static_cast<String*>(o->get());
if (nameFirst)
dest.addParam(*tmp,String(index));
else
dest.addParam(String(index),*tmp);
}
TelEngine::destruct(obj);
return true;
}

View File

@ -48,18 +48,113 @@
*/
namespace TelEngine {
class XMPPNamespace;
class XMPPErrorCode;
class XMPPError;
class JabberID;
class JIDIdentity;
class JIDFeature;
class JIDFeatureList;
class XMPPUtils;
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 JIDFeatureList; // Feature list
class XMPPUtils; // Utilities
/**
* This class holds the XMPP/JabberComponent/Jingle namespace enumerations and the associated strings.
* @short XMPP namespaces.
* This class holds informations about a server
* @short Server info class
*/
class YJINGLE_API XMPPServerInfo : public RefObject
{
public:
/**
* 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 roster Component only: Keep the user roster
* @param autoRestart Component only: Auto restart stream when connection is down
*/
inline XMPPServerInfo(const char* name, const char* address, int port,
const char* password, const char* identity, const char* fullidentity,
bool roster, bool autoRestart)
: m_name(name), m_address(address), m_port(port), m_password(password),
m_identity(identity), m_fullIdentity(fullidentity), m_roster(roster)
{}
/**
* 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), m_roster(false)
{}
/**
* 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 someone should keep the roster for this server
* @return True if someone should keep the roster for this server
*/
inline bool roster() const
{ return m_roster; }
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
bool m_roster; // Keep roster for this server
};
/**
* This class holds the XMPP/JabberComponent/Jingle namespace enumerations and the associated strings
* @short XMPP namespaces
*/
class YJINGLE_API XMPPNamespace
{
@ -83,11 +178,20 @@ public:
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;
@ -97,6 +201,7 @@ private:
static TokenDict s_value[]; // Namespace list
};
/**
* This class holds the XMPP error type, error enumerations and associated strings
* @short XMPP errors.
@ -104,19 +209,13 @@ private:
class YJINGLE_API XMPPError
{
public:
// Error type
enum ErrorType {
TypeCancel = 0, // 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,
};
/**
* Error condition enumeration
*/
enum Type {
NoError = 0,
// Stream errors
BadFormat = TypeCount + 1, // bad-format
BadFormat, // bad-format
BadNamespace, // bad-namespace-prefix
ConnTimeout, // connection-timeout
HostGone, // host-gone
@ -167,11 +266,32 @@ public:
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); }
@ -179,53 +299,52 @@ 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.
* 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.
* Constructor
*/
inline JabberID() {}
/**
* Constructor.
* Constructs a JID from a given string.
* @param jid The JID string.
* 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.
* 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.
* 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.
* 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.
* Get the domain part of the JID
* @return The domain part of the JID
*/
inline const String& domain() const
{ return m_domain; }
@ -238,51 +357,90 @@ public:
{ set(m_node.c_str(),d,m_resource.c_str()); }
/**
* Get the resource part of the JID.
* @return The resource part of the JID.
* 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.
* (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()); }
/**
* Set the resource part of the JID.
* @param res The new resource part of the JID.
* 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.
* 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.
* 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.
* 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.
* Keep the regexp used to check the validity of a string
*/
static Regexp s_regExpValid;
@ -295,13 +453,17 @@ private:
String m_bare; // The bare JID: node@domain
};
/**
* This class holds an identity for a JID.
* @short JID identity.
* This class holds an identity for a JID
* @short A JID identity
*/
class YJINGLE_API JIDIdentity : public String, public RefObject
class YJINGLE_API JIDIdentity : public RefObject, virtual public String
{
public:
/**
* JID category enumeration
*/
enum Category {
Account, // account
Client, // client
@ -310,6 +472,9 @@ public:
CategoryUnknown
};
/**
* JID type enumeration
*/
enum Type {
AccountRegistered, // registered
ClientPhone, // phone
@ -319,26 +484,59 @@ public:
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)
: String(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);
/**
* 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); }
@ -350,28 +548,29 @@ private:
Type m_type; // Type
};
/**
* This class holds a JID feature.
* @short JID feature.
* This class holds a JID feature
* @short JID feature
*/
class YJINGLE_API JIDFeature : public RefObject
{
public:
/**
* Constructor.
* Constructor
*/
inline JIDFeature(XMPPNamespace::Type feature)
: m_feature(feature)
{}
/**
* Destructor.
* Destructor
*/
virtual ~JIDFeature()
{}
/**
* XMPPNamespace::Type conversion operator.
* XMPPNamespace::Type conversion operator
*/
inline operator XMPPNamespace::Type()
{ return m_feature; }
@ -380,17 +579,18 @@ private:
XMPPNamespace::Type m_feature; // The feature
};
/**
* This class holds a list of features.
* @short Feature list.
* This class holds a list of features
* @short Feature list
*/
class YJINGLE_API JIDFeatureList
{
public:
/**
* Add a feature to the list.
* @param feature The feature to add.
* @return False if the given feature already exists.
* Add a feature to the list
* @param feature The feature to add
* @return False if the given feature already exists
*/
inline bool add(XMPPNamespace::Type feature) {
if (get(feature))
@ -400,23 +600,23 @@ public:
}
/**
* Remove a feature from the list.
* @param feature The feature to remove.
* 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.
* 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.
* Add 'feature' children to the given element
* @param element The target XMLElement
* @return The given element
*/
XMLElement* addTo(XMLElement* element);
@ -425,14 +625,14 @@ private:
};
/**
* This class is a general XMPP utilities.
* @short General XMPP utilities.
* This class is a general XMPP utilities
* @short General XMPP utilities
*/
class YJINGLE_API XMPPUtils
{
public:
/**
* Iq type enumeration.
* Iq type enumeration
*/
enum IqType {
IqSet, // set
@ -443,7 +643,7 @@ public:
};
/**
* Message type enumeration.
* Message type enumeration
*/
enum MsgType {
MsgChat, // chat
@ -451,7 +651,7 @@ public:
};
/**
* Command action enumeration.
* Command action enumeration
*/
enum CommandAction {
CommExecute,
@ -462,7 +662,7 @@ public:
};
/**
* Command status enumeration.
* Command status enumeration
*/
enum CommandStatus {
CommExecuting,
@ -471,144 +671,152 @@ public:
};
/**
* 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.
* 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.
* 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 a 'message' element.
* Create a 'message' element
* @param type Message type as enumeration
* @param from The 'from' attribute.
* @param to The 'to' attribute.
* @param id The 'id' attribute.
* @param message The message body.
* @return A valid XMLElement pointer.
* @param from The 'from' attribute
* @param to The 'to' attribute
* @param id The 'id' attribute
* @param message The message body
* @return A valid XMLElement pointer
*/
static XMLElement* createMessage(MsgType type, const char* from,
const char* to, const char* id, const char* message);
/**
* Create an 'iq' element.
* 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.
* @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.
* 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 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.
* @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.
* 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.
* 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 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.
* 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 a 'stream:error' element.
* @param error The XMPP defined condition.
* @param text Optional text to add to the error.
* @return A valid XMLElement pointer.
* 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);
/**
* 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.
* 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);
/**
* 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.
* 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.
* False to do the other way
*/
static bool split(NamedList& dest, const char* src, const char sep,
bool nameFirst);
/**
* Get the type of an 'iq' stanza as enumeration.
* @param text The text to check.
* @return Iq type as enumeration.
* 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.
* Keep the types of 'iq' stanzas
*/
static TokenDict s_iq[];
/**
* Keep the types of 'message' stanzas.
* Keep the types of 'message' stanzas
*/
static TokenDict s_msg[];

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff