Add remaining part of libgloox.
This commit is contained in:
parent
05633562d6
commit
f487e366fb
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright (c) 2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef ADHOCPLUGIN_H__
|
||||
#define ADHOCPLUGIN_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "stanzaextension.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief A base class for Adhoc Command plugins (DataForm, IO Data, ...).
|
||||
*
|
||||
* This is just a common base class for abstractions of protocols that can be embedded into Adhoc Commands.
|
||||
* You should not need to use this class directly unless you're extending Adhoc Commands further.
|
||||
*
|
||||
* This class exists purely as an additional abstraction layer, to limit the type of objects that can be
|
||||
* added to an Adhoc Command.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.13
|
||||
*/
|
||||
class GLOOX_API AdhocPlugin : public StanzaExtension
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
AdhocPlugin( int type ) : StanzaExtension( type ) {}
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~AdhocPlugin() {}
|
||||
|
||||
/**
|
||||
* Converts to @b true if the plugin is valid, @b false otherwise.
|
||||
*/
|
||||
virtual operator bool() const = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ADHOCPLUGIN_H__
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
Copyright (c) 2007-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "atomicrefcount.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
# include <windows.h>
|
||||
#elif defined( __APPLE__ )
|
||||
# include <libkern/OSAtomic.h>
|
||||
#elif defined( HAVE_GCC_ATOMIC_BUILTINS )
|
||||
// Use intrinsic functions - no #include required.
|
||||
#else
|
||||
# include "mutexguard.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32_WCE
|
||||
# include <winbase.h>
|
||||
#endif
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace util
|
||||
{
|
||||
AtomicRefCount::AtomicRefCount()
|
||||
: m_count( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
int AtomicRefCount::increment()
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
return (int) ::InterlockedIncrement( (volatile LONG*)&m_count );
|
||||
#elif defined( __APPLE__ )
|
||||
return (int) OSAtomicIncrement32Barrier( (volatile int32_t*)&m_count );
|
||||
#elif defined( HAVE_GCC_ATOMIC_BUILTINS )
|
||||
// Use the gcc intrinsic for atomic increment if supported.
|
||||
return (int) __sync_add_and_fetch( &m_count, 1 );
|
||||
#else
|
||||
// Fallback to using a lock
|
||||
MutexGuard m( m_lock );
|
||||
return ++m_count;
|
||||
#endif
|
||||
}
|
||||
|
||||
int AtomicRefCount::decrement()
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
return (int) ::InterlockedDecrement( (volatile LONG*)&m_count );
|
||||
#elif defined( __APPLE__ )
|
||||
return (int) OSAtomicDecrement32Barrier( (volatile int32_t*)&m_count );
|
||||
#elif defined( HAVE_GCC_ATOMIC_BUILTINS )
|
||||
// Use the gcc intrinsic for atomic decrement if supported.
|
||||
return (int) __sync_sub_and_fetch( &m_count, 1 );
|
||||
#else
|
||||
// Fallback to using a lock
|
||||
MutexGuard m( m_lock );
|
||||
return --m_count;
|
||||
#endif
|
||||
}
|
||||
|
||||
void AtomicRefCount::reset()
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
::InterlockedExchange( (volatile LONG*)&m_count, (volatile LONG)0 );
|
||||
#elif defined( __APPLE__ )
|
||||
OSAtomicAnd32Barrier( (uint32_t)0, (volatile uint32_t*)&m_count );
|
||||
#elif defined( HAVE_GCC_ATOMIC_BUILTINS )
|
||||
// Use the gcc intrinsic for atomic decrement if supported.
|
||||
__sync_fetch_and_and( &m_count, 0 );
|
||||
#else
|
||||
// Fallback to using a lock
|
||||
MutexGuard m( m_lock );
|
||||
m_count = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
Copyright (c) 2007-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef ATOMICREFCOUNT_H__
|
||||
#define ATOMICREFCOUNT_H__
|
||||
|
||||
#include "macros.h"
|
||||
#include "mutex.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace util
|
||||
{
|
||||
/**
|
||||
* @brief A simple implementation of a thread safe 32-bit
|
||||
* reference count. Native functions are used where possible.
|
||||
* When not available, a mutex is used for locking and unlocking.
|
||||
*
|
||||
* @author Daniel Bowen
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.1
|
||||
*/
|
||||
class GLOOX_API AtomicRefCount
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Contructs a new atomic reference count.
|
||||
*/
|
||||
AtomicRefCount();
|
||||
|
||||
/**
|
||||
* Increments the reference count, and returns the new value.
|
||||
* @return The new value.
|
||||
*/
|
||||
int increment();
|
||||
|
||||
/**
|
||||
* Decrements the reference count, and returns the new value.
|
||||
* @return The new value.
|
||||
*/
|
||||
int decrement();
|
||||
|
||||
/**
|
||||
* Resets the reference count to zero.
|
||||
* @since 1.0.4
|
||||
*/
|
||||
void reset();
|
||||
|
||||
private:
|
||||
AtomicRefCount& operator=( const AtomicRefCount& );
|
||||
|
||||
volatile int m_count;
|
||||
|
||||
// The mutex is only used if a native function is unavailable.
|
||||
Mutex m_lock;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // ATOMICREFCOUNT_H__
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
* This file is part of the gloox library. http://camaya.net/gloox
|
||||
*
|
||||
* This software is distributed under a license. The full license
|
||||
* agreement can be found in the file LICENSE in this distribution.
|
||||
* This software may not be copied, modified, sold or distributed
|
||||
* other than expressed in the named license agreement.
|
||||
*
|
||||
* This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "carbons.h"
|
||||
|
||||
#include "forward.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
/* chat state type values */
|
||||
static const char* typeValues [] = {
|
||||
"received",
|
||||
"sent",
|
||||
"enable",
|
||||
"disable",
|
||||
"private"
|
||||
};
|
||||
|
||||
Carbons::Carbons( Carbons::Type type )
|
||||
: StanzaExtension( ExtCarbons ), m_forward( 0 ), m_type( type )
|
||||
{
|
||||
}
|
||||
|
||||
Carbons::Carbons( const Tag* tag )
|
||||
: StanzaExtension( ExtCarbons ), m_forward( 0 ), m_type( Invalid )
|
||||
{
|
||||
if( !tag )
|
||||
return;
|
||||
|
||||
const std::string& name = tag->name();
|
||||
m_type = (Type)util::lookup( name, typeValues );
|
||||
|
||||
switch( m_type )
|
||||
{
|
||||
case Sent:
|
||||
case Received:
|
||||
{
|
||||
Tag* f = tag->findChild( "forwarded", XMLNS, XMLNS_STANZA_FORWARDING );
|
||||
if( f )
|
||||
m_forward = new Forward( f );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Carbons::~Carbons()
|
||||
{
|
||||
delete m_forward;
|
||||
}
|
||||
|
||||
const std::string& Carbons::filterString() const
|
||||
{
|
||||
static const std::string filter = "/message/*[@xmlns='" + XMLNS_MESSAGE_CARBONS + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Stanza* Carbons::embeddedStanza() const
|
||||
{
|
||||
if( !m_forward || m_type == Invalid )
|
||||
return 0;
|
||||
|
||||
return m_forward->embeddedStanza();
|
||||
}
|
||||
|
||||
Tag* Carbons::embeddedTag() const
|
||||
{
|
||||
if( !m_forward || m_type == Invalid )
|
||||
return 0;
|
||||
|
||||
return m_forward->embeddedTag();
|
||||
}
|
||||
|
||||
Tag* Carbons::tag() const
|
||||
{
|
||||
if( m_type == Invalid )
|
||||
return 0;
|
||||
|
||||
Tag* t = new Tag( util::lookup( m_type, typeValues ), XMLNS, XMLNS_MESSAGE_CARBONS );
|
||||
if( m_forward && ( m_type == Received || m_type == Sent ) )
|
||||
t->addChild( m_forward->tag() );
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
StanzaExtension* Carbons::clone() const
|
||||
{
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CARBONS_H__
|
||||
#define CARBONS_H__
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include "stanzaextension.h"
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Forward;
|
||||
|
||||
/**
|
||||
* @brief An implementation of Message Carbons (@xep{0280}) as a StanzaExtension.
|
||||
*
|
||||
* @section enable Enable Mesage Carbons
|
||||
*
|
||||
* Before using Message Carbons you have to check your server for support of the extension.
|
||||
* You can do so using Disco::getDiscoInfo(). You can check the result (in DiscoHandler::handleDiscoInfo())
|
||||
* for a feature of @c XMLNS_MESSAGE_CARBONS (use Disco::Info::hasFeature()).
|
||||
*
|
||||
* If the feature exists, you can enable Message Carbons with the server.
|
||||
*
|
||||
* @code
|
||||
* Client cb( ... );
|
||||
* // ...
|
||||
*
|
||||
* // setup
|
||||
* cb.registerStanzaExtension( new Forward() ); // required for Message Carbons support
|
||||
* cb.registerStanzaExtension( new Carbons() );
|
||||
* // ...
|
||||
*
|
||||
* // enable Message Carbons
|
||||
* IQ iq( IQ::Set, JID() ); // empty JID
|
||||
* iq.addExtension( new Carbons( Carbons::Enable ) );
|
||||
* cb.send( iq, MyIqHandler, 1 ); // myIqHandler will be notified of the result with the given context ('1' in this case).
|
||||
* @endcode
|
||||
*
|
||||
* @note Once enabled, the server will automatically send all received and sent messages @b of @b type @c Chat to all other Carbons-enabled resources of
|
||||
* the current account. You have to make sure that you actually send messages of type @c Chat. The default is currently @c Normal.
|
||||
*
|
||||
* @section disable Disable Message Carbons
|
||||
*
|
||||
* Once enabled, you can easily disable Message carbons. The code is almost identical to the code used to enable the feature,
|
||||
* except that you use a Carbons::Type of Carbons::Disable when you add the Carbons extension to the IQ:
|
||||
* @code
|
||||
* iq.addExtension( new Carbons( Carbons::Disable ) );
|
||||
* @endcode
|
||||
*
|
||||
* @section private Prevent carbon copies for a single message
|
||||
*
|
||||
* To disable carbon copies for a single message, add a Carbons extension of type Private:
|
||||
*
|
||||
* @code
|
||||
* Message msg( Message::Chat, ... );
|
||||
* // ...
|
||||
* msg.addExtension( new Carbons( Carbons::Private ) );
|
||||
* @endcode
|
||||
*
|
||||
* The server will not copy this message to your other connected resources.
|
||||
*
|
||||
* @section access Access received carbon copies
|
||||
*
|
||||
* When receiving a message (sent by either another connected client of the current user, or by a 3rd party), a carbon copy will
|
||||
* have the following characteristics:
|
||||
* @li The message's @c from attribute will be the @b bare JID of the @b receiving entity.
|
||||
* @li The message's @c from attribute will be the @b full JID of the @b receiving entity.
|
||||
* @li The message contains a Carbons StanzaExtension. This extension contains the original message with the @b original
|
||||
* @c from/to attributes.
|
||||
*
|
||||
* Some sample code:
|
||||
* @code
|
||||
* bool Myclass::handleMessage( const Message& msg, MessageSession* )
|
||||
* {
|
||||
* if( msg.hasEmbeddedStanza() ) // optional, saves some processing time when there is no Carbons extension
|
||||
* {
|
||||
* const Carbons* carbon = msg.findExtension<const Carbons>( ExtCarbons );
|
||||
* if( carbon && carbon->embeddedStanza() )
|
||||
* {
|
||||
* Message* embeddedMessage = static_cast<Message *>( carbon->embeddedStanza() );
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* You can also determine whether a carbon was sent by a 3rd party or a different client of the current user by checking the return value of Carbons::type().
|
||||
* @code
|
||||
* Carbons* c = msg.findExtension<...>( ... );
|
||||
* // check that c is valid
|
||||
*
|
||||
* if( c->type() == Carbons::Received )
|
||||
* // Message was sent by a 3rd party
|
||||
* else if( c->type() == Carbons::Sent )
|
||||
* // Message was sent by a different client of the current user
|
||||
* @endcode
|
||||
*
|
||||
* XEP Version: 0.8
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class GLOOX_API Carbons : public StanzaExtension
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The types of Message Carbons stanza extensions.
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
Received, /**< Indicates that the message received has been sent by a third party. */
|
||||
Sent, /**< Indicates that the message received has been sent by one of the user's own resources. */
|
||||
Enable, /**< Indicates that the sender wishes to enable carbon copies. */
|
||||
Disable, /**< Indicates that the sender wishes to disable carbon copies. */
|
||||
Private, /**< Indicates that the sender does not want carbon copies to be sent for this message. */
|
||||
Invalid /**< Invalid type. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new Carbons instance of the given type.
|
||||
* You should only use the @c Enable, @c Disable and @c Private types.
|
||||
* @param type The Carbons type to create.
|
||||
*/
|
||||
Carbons( Type type );
|
||||
|
||||
/**
|
||||
* Constructs a new Carbons instance from the given tag.
|
||||
* @param tag The Tag to create the Carbons instance from.
|
||||
*/
|
||||
Carbons( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Carbons();
|
||||
|
||||
/**
|
||||
* Returns the current instance's type.
|
||||
* @return The intance's type.
|
||||
*/
|
||||
Type type() const { return m_type; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Stanza* embeddedStanza() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* embeddedTag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Carbons( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const;
|
||||
|
||||
private:
|
||||
Forward* m_forward;
|
||||
Type m_type;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CARBONS_H__
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "forward.h"
|
||||
|
||||
#include "delayeddelivery.h"
|
||||
#include "message.h"
|
||||
#include "stanza.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
Forward::Forward( Stanza *stanza, DelayedDelivery *delay )
|
||||
: StanzaExtension( ExtForward ),
|
||||
m_stanza( stanza ), m_tag( 0 ), m_delay( delay )
|
||||
{
|
||||
}
|
||||
|
||||
Forward::Forward( const Tag* tag )
|
||||
: StanzaExtension( ExtForward ),
|
||||
m_stanza( 0 ), m_tag( 0 ), m_delay( 0 )
|
||||
{
|
||||
if( !tag || !( tag->name() == "forwarded" && tag->hasAttribute( XMLNS, XMLNS_STANZA_FORWARDING ) ) )
|
||||
return;
|
||||
|
||||
m_delay = new DelayedDelivery( tag->findChild( "delay", XMLNS, XMLNS_DELAY ) );
|
||||
|
||||
Tag* m = tag->findChild( "message" );
|
||||
if( !m )
|
||||
return;
|
||||
|
||||
m_tag = m->clone();
|
||||
m_stanza = new Message( m );
|
||||
}
|
||||
|
||||
Forward::~Forward()
|
||||
{
|
||||
delete m_delay;
|
||||
delete m_stanza;
|
||||
delete m_tag;
|
||||
}
|
||||
|
||||
const std::string& Forward::filterString() const
|
||||
{
|
||||
static const std::string filter = "/message/forwarded[@xmlns='" + XMLNS_STANZA_FORWARDING + "']"
|
||||
"|/iq/forwarded[@xmlns='" + XMLNS_STANZA_FORWARDING + "']"
|
||||
"|/presence/forwarded[@xmlns='" + XMLNS_STANZA_FORWARDING + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Forward::tag() const
|
||||
{
|
||||
if( !m_stanza )
|
||||
return 0;
|
||||
|
||||
Tag* f = new Tag( "forwarded" );
|
||||
f->setXmlns( XMLNS_STANZA_FORWARDING );
|
||||
if( m_delay )
|
||||
f->addChild( m_delay->tag() );
|
||||
if( m_stanza )
|
||||
f->addChild( m_stanza->tag() );
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
StanzaExtension* Forward::clone() const
|
||||
{
|
||||
if( !m_tag || !m_delay )
|
||||
return 0;
|
||||
|
||||
return new Forward( new Message( m_tag ), static_cast<DelayedDelivery*>( m_delay->clone() ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef FORWARD_H__
|
||||
#define FORWARD_H__
|
||||
|
||||
#include "stanzaextension.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class DelayedDelivery;
|
||||
class Stanza;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of Stanza Forwarding (@xep{0297}) as a StanzaExtension.
|
||||
*
|
||||
* @note At this point, Forward can only hold forwarded Messages, not IQ or Presence.
|
||||
* However, Forward can be used inside any type of stanza (<message>, <iq>,
|
||||
* or <presence>).
|
||||
*
|
||||
* XEP-Version: 0.5
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @author Fernando Sanchez
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class GLOOX_API Forward : public StanzaExtension
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a forwarding StanzaExtension, embedding the given Stanza and DelayedDelivery objects.
|
||||
* @param stanza The forwarded Stanza. This Forward instance will own the Stanza object.
|
||||
* @param delay The date/time the forwarded stanza was received at by the forwarder. This
|
||||
* Forward instance will own the DelayedDelivery object.
|
||||
*/
|
||||
Forward( Stanza* stanza, DelayedDelivery* delay );
|
||||
|
||||
/**
|
||||
* Creates a forwarding Stanza from the given Tag. The original Tag will be ripped off.
|
||||
* If a valid Stanza is conatined (as a child) in the Tag it will be parsed, too.
|
||||
* It can then be accessed through embeddedStanza(). The Tag that the Stanza was built from
|
||||
* is available through embeddedTag().
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
Forward( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Forward();
|
||||
|
||||
/**
|
||||
* This function returns a pointer to a DelayedDelivery StanzaExtension which indicates
|
||||
* when the forwarder originally received the forwarded stanza.
|
||||
*
|
||||
* @return A pointer to a DelayedDelivery object. May be 0.
|
||||
*/
|
||||
const DelayedDelivery* when() const { return m_delay; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Stanza* embeddedStanza() const { return m_stanza; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* embeddedTag() const { return m_tag; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Forward( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
StanzaExtension* clone() const;
|
||||
|
||||
private:
|
||||
Stanza* m_stanza;
|
||||
Tag* m_tag;
|
||||
DelayedDelivery* m_delay;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FORWARD_H__
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
Copyright (c) 2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "iodata.h"
|
||||
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
static const char* ioTypes[] = {
|
||||
"io-schemata-get",
|
||||
"input",
|
||||
"getStatus",
|
||||
"getOutput",
|
||||
"io-schemata-result",
|
||||
"output",
|
||||
"error",
|
||||
"status"
|
||||
};
|
||||
|
||||
static inline IOData::Type ioType( const std::string& type )
|
||||
{
|
||||
return (IOData::Type)util::lookup( type, ioTypes );
|
||||
}
|
||||
|
||||
IOData::IOData( Type type )
|
||||
: AdhocPlugin( ExtIOData ),
|
||||
m_in( 0 ), m_out( 0 ), m_error( 0 ),
|
||||
m_type( type )
|
||||
{
|
||||
m_status.elapsed = -1;
|
||||
m_status.remaining = -1;
|
||||
m_status.percentage = -1;
|
||||
}
|
||||
|
||||
IOData::IOData( const Tag* tag )
|
||||
: AdhocPlugin( ExtIOData ),
|
||||
m_in( 0 ), m_out( 0 ), m_error( 0 ),
|
||||
m_type( TypeInvalid )
|
||||
{
|
||||
if( !tag || !( tag->name() == "iodata" && tag->hasAttribute( XMLNS, XMLNS_IODATA ) ) )
|
||||
return;
|
||||
|
||||
m_status.elapsed = -1;
|
||||
m_status.remaining = -1;
|
||||
m_status.percentage = -1;
|
||||
|
||||
m_type = ioType( tag->findAttribute( "type" ) );
|
||||
Tag* m = 0;
|
||||
switch( m_type )
|
||||
{
|
||||
case TypeInput:
|
||||
m = tag->findChild( "in" );
|
||||
if( m )
|
||||
m_in = m->clone();
|
||||
break;
|
||||
case TypeIoSchemataResult:
|
||||
m = tag->findChild( "desc" );
|
||||
if( m )
|
||||
m_desc = m->cdata();
|
||||
|
||||
m = tag->findChild( "out" );
|
||||
if( m )
|
||||
m_out = m->clone();
|
||||
|
||||
m = tag->findChild( "in" );
|
||||
if( m )
|
||||
m_in = m->clone();
|
||||
break;
|
||||
case TypeOutput:
|
||||
m = tag->findChild( "out" );
|
||||
if( m )
|
||||
m_out = m->clone();
|
||||
break;
|
||||
case TypeError:
|
||||
m = tag->findChild( "error" );
|
||||
if( m )
|
||||
m_error = m->clone();
|
||||
break;
|
||||
case TypeStatus:
|
||||
m = tag->findChild( "status" );
|
||||
if( m )
|
||||
{
|
||||
Tag* t = m->findChild( "elapsed" );
|
||||
if( t )
|
||||
m_status.elapsed = atoi( t->cdata().c_str() );
|
||||
|
||||
t = m->findChild( "remaining" );
|
||||
if( t )
|
||||
m_status.remaining = atoi( t->cdata().c_str() );
|
||||
|
||||
t = m->findChild( "percentage" );
|
||||
if( t )
|
||||
m_status.percentage = atoi( t->cdata().c_str() );
|
||||
|
||||
t = m->findChild( "information" );
|
||||
if( t )
|
||||
m_status.info = t->cdata();
|
||||
}
|
||||
break;
|
||||
case TypeIoSchemataGet:
|
||||
case TypeGetStatus:
|
||||
case TypeGetOutput:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
IOData::~IOData()
|
||||
{
|
||||
delete m_in;
|
||||
delete m_out;
|
||||
delete m_error;
|
||||
}
|
||||
|
||||
Tag* IOData::tag() const
|
||||
{
|
||||
if( m_type == TypeInvalid )
|
||||
return 0;
|
||||
|
||||
Tag* i = new Tag( "iodata" );
|
||||
i->setXmlns( XMLNS_IODATA );
|
||||
i->addAttribute( "type", util::lookup( m_type, ioTypes ) );
|
||||
|
||||
Tag* t = 0;
|
||||
switch( m_type )
|
||||
{
|
||||
case TypeInput:
|
||||
i->addChild( m_in );
|
||||
break;
|
||||
case TypeIoSchemataResult:
|
||||
i->addChild( m_in );
|
||||
i->addChild( m_out );
|
||||
new Tag( i, "desc", m_desc );
|
||||
break;
|
||||
case TypeOutput:
|
||||
i->addChild( m_out );
|
||||
break;
|
||||
case TypeError:
|
||||
i->addChild( m_error );
|
||||
break;
|
||||
case TypeStatus:
|
||||
t = new Tag( i, "status" );
|
||||
if( m_status.elapsed >= 0 )
|
||||
new Tag( t, "elapsed", util::int2string( m_status.elapsed ) );
|
||||
if( m_status.remaining >= 0 )
|
||||
new Tag( t, "remaining", util::int2string( m_status.remaining ) );
|
||||
if( m_status.percentage >= 0 )
|
||||
new Tag( t, "percentage", util::int2string( m_status.percentage ) );
|
||||
if( m_status.info.length() )
|
||||
new Tag( t, "information", m_status.info );
|
||||
break;
|
||||
case TypeIoSchemataGet:
|
||||
case TypeGetStatus:
|
||||
case TypeGetOutput:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
IOData* IOData::clone() const
|
||||
{
|
||||
IOData* i = new IOData( m_type );
|
||||
i->m_status = m_status;
|
||||
i->m_desc = m_desc;
|
||||
|
||||
if( m_in )
|
||||
i->m_in = m_in->clone();
|
||||
if( m_out )
|
||||
i->m_out = m_out->clone();
|
||||
if( m_error )
|
||||
i->m_error = m_error->clone();
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void IOData::setIn( Tag* in )
|
||||
{
|
||||
if( !in )
|
||||
return;
|
||||
|
||||
delete m_in;
|
||||
|
||||
m_in = new Tag( "in" );
|
||||
m_in->addChild( in );
|
||||
}
|
||||
|
||||
void IOData::setOut( Tag* out )
|
||||
{
|
||||
if( !out )
|
||||
return;
|
||||
|
||||
delete m_out;
|
||||
|
||||
m_out = new Tag( "out" );
|
||||
m_out->addChild( out );
|
||||
}
|
||||
|
||||
void IOData::setError( Tag* error )
|
||||
{
|
||||
if( !error )
|
||||
return;
|
||||
|
||||
delete m_error;
|
||||
|
||||
m_error = new Tag( "error" );
|
||||
m_error->addChild( error );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
Copyright (c) 2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef IODATA_H__
|
||||
#define IODATA_H__
|
||||
|
||||
#include "adhocplugin.h"
|
||||
|
||||
#include "gloox.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an abstraction of the IO Data specification @xep{0153}.
|
||||
*
|
||||
* This abstraction can be used to implement IO Data on top of Data Forms.
|
||||
*
|
||||
* XEP version: 0.1
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.13
|
||||
*/
|
||||
class GLOOX_API IOData : public AdhocPlugin
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The IO Data transaction types.
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
TypeIoSchemataGet, /** To request the schemata of input and output. */
|
||||
TypeInput, /** To submit the input. */
|
||||
TypeGetStatus, /** To request the status of the procedure. */
|
||||
TypeGetOutput, /** To request the output. */
|
||||
TypeIoSchemataResult, /** To return the schemata of input and output. */
|
||||
TypeOutput, /** To submit the output. */
|
||||
TypeError, /** To submit additional error information. */
|
||||
TypeStatus, /** To indicate the current status of the procedure. */
|
||||
TypeInvalid /** Invalid type. */
|
||||
};
|
||||
|
||||
struct Status
|
||||
{
|
||||
int elapsed; /** Aan integer value of the time in milliseconds that
|
||||
* elapsed since the procedure was invoked. */
|
||||
int remaining; /** An integer value of the (estimated) time in milliseconds
|
||||
* till the procedure will finish. */
|
||||
int percentage; /** The percentage of the procedure that is finished. */
|
||||
std::string info; /** Describes the current status of the procedure. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new IO Data object of the given type.
|
||||
* @param type The transaction type.
|
||||
*/
|
||||
IOData( Type type );
|
||||
|
||||
/**
|
||||
* Constructs a new IO Data object by parsing the given Tag.
|
||||
* @param tag The Tag to parse. This should be a <iodata> tag with the correct namespace and child elements.
|
||||
*/
|
||||
IOData( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~IOData();
|
||||
|
||||
/**
|
||||
* Returns the IO Data object's type.
|
||||
* @return The IO Data object's type.
|
||||
*/
|
||||
Type type() const { return m_type; }
|
||||
|
||||
/**
|
||||
* Returns the 'input' tag, if the transaction type is either @c input or @c io-schemata-result.
|
||||
* @return The 'input' tag, including the encapsulating <in>.
|
||||
* @note The IOData instance will still own the tag and delete it. Clone it if you need it later.
|
||||
*/
|
||||
const Tag* in() const { return m_in; }
|
||||
|
||||
/**
|
||||
* Sets the 'input' tag. If an 'input' tag was previosuly set, it is deleted before the new one is set.
|
||||
* @param in The new 'input' tag.
|
||||
* @note The @c in tag will be owned by this IOData instance. Clone it if you need it somewhere else.
|
||||
*/
|
||||
void setIn( Tag* in );
|
||||
|
||||
/**
|
||||
* Returns the 'output' tag, if the transaction type is either @c output or @c io-schemata-result.
|
||||
* @return The 'output' tag, including the encapsulating <out>.
|
||||
* @note The IOData instance will still own the tag and delete it. Clone it if you need it later.
|
||||
*/
|
||||
const Tag* out() const { return m_out; }
|
||||
|
||||
/**
|
||||
* Sets the 'output' tag. If an 'output' tag was previosuly set, it is deleted before the new one is set.
|
||||
* @param out The new 'output' tag.
|
||||
* @note The @c out tag will be owned by this IOData instance. Clone it if you need it somewhere else.
|
||||
*/
|
||||
void setOut( Tag* out );
|
||||
|
||||
/**
|
||||
* Returns the 'error' tag, if the transaction type is either @c error or @c io-schemata-result.
|
||||
* @return The 'error' tag, including the encapsulating <error>.
|
||||
* @note The IOData instance will still own the tag and delete it. Clone it if you need it later.
|
||||
*/
|
||||
const Tag* error() const { return m_error; }
|
||||
|
||||
/**
|
||||
* Sets the 'error' tag. If an 'error' tag was previosuly set, it is deleted before the new one is set.
|
||||
* @param out The new 'error' tag.
|
||||
* @note The @c error tag will be owned by this IOData instance. Clone it if you need it somewhere else.
|
||||
*/
|
||||
void setError( Tag* error );
|
||||
|
||||
/**
|
||||
* Sets the Schema description. Only used/valid if type is @c io-schemata-result.
|
||||
* @param desc The schema description.
|
||||
*/
|
||||
void setDesc( const std::string& desc ) { m_desc = desc; }
|
||||
|
||||
/**
|
||||
* Returns the schema description, if any. Usually only valid if transaction type is @c io-schema-result.
|
||||
* @return The schema description.
|
||||
*/
|
||||
const std::string& desc() const { return m_desc; }
|
||||
|
||||
/**
|
||||
* Sets the status of the procedure. Only used/valid if transaction type is @c status.
|
||||
* @param status The status of the procedure.
|
||||
*/
|
||||
void setStatus( Status status ) { m_status = status; }
|
||||
|
||||
/**
|
||||
* Returns the status of the procedure. Only used/valid if transaction type is @c status.
|
||||
* @return The status of the procedure.
|
||||
*/
|
||||
Status status() const { return m_status; }
|
||||
|
||||
// reimplemented from AdhocPlugin/StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from AdhocPlugin/StanzaExtension
|
||||
virtual IOData* clone() const;
|
||||
|
||||
// reimplemented from AdhocPlugin/StanzaExtension
|
||||
virtual const std::string& filterString() const { return EmptyString; }
|
||||
|
||||
// reimplemented from AdhocPlugin/StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* /*tag*/ ) const { return 0; }
|
||||
|
||||
/**
|
||||
* Converts to @b true if the IOData is valid, @b false otherwise.
|
||||
*/
|
||||
operator bool() const { return m_type != TypeInvalid; }
|
||||
|
||||
private:
|
||||
Tag* m_in;
|
||||
Tag* m_out;
|
||||
Tag* m_error;
|
||||
|
||||
std::string m_desc;
|
||||
|
||||
Status m_status;
|
||||
|
||||
Type m_type;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // IODATA_H__
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Copyright (c) 2008-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "jinglecontent.h"
|
||||
#include "jinglepluginfactory.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
static const char* creatorValues [] = {
|
||||
"initiator",
|
||||
"responder"
|
||||
};
|
||||
|
||||
static inline Content::Creator creatorType( const std::string& type )
|
||||
{
|
||||
return (Content::Creator)util::lookup( type, creatorValues );
|
||||
}
|
||||
|
||||
static const char* sendersValues [] = {
|
||||
"initiator",
|
||||
"responder",
|
||||
"both",
|
||||
"none"
|
||||
};
|
||||
|
||||
static inline Content::Senders sendersType( const std::string& type )
|
||||
{
|
||||
return (Content::Senders)util::lookup( type, sendersValues );
|
||||
}
|
||||
|
||||
Content::Content( const std::string& name, const PluginList& plugins, Creator creator,
|
||||
Senders senders, const std::string& disposition )
|
||||
: Plugin( PluginContent ), m_creator( creator ), m_disposition( disposition ),
|
||||
m_name( name ), m_senders( senders )
|
||||
{
|
||||
m_plugins = plugins;
|
||||
}
|
||||
|
||||
Content::Content( const Tag* tag, PluginFactory* factory )
|
||||
: Plugin( PluginContent )
|
||||
{
|
||||
if( !tag || tag->name() != "content" )
|
||||
return;
|
||||
|
||||
m_name = tag->findAttribute( "name" );
|
||||
m_creator = (Creator)util::lookup( tag->findAttribute( "creator" ), creatorValues );
|
||||
m_senders = (Senders)util::lookup( tag->findAttribute( "senders" ), sendersValues );
|
||||
m_disposition = tag->findAttribute( "disposition" );
|
||||
|
||||
if( factory )
|
||||
factory->addPlugins( *this, tag );
|
||||
}
|
||||
|
||||
Content::~Content()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& Content::filterString() const
|
||||
{
|
||||
static const std::string filter = "jingle/content";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Content::tag() const
|
||||
{
|
||||
if( m_creator == InvalidCreator || m_name.empty() )
|
||||
return 0;
|
||||
|
||||
Tag* t = new Tag( "content" );
|
||||
t->addAttribute( "creator", util::lookup( m_creator, creatorValues ) );
|
||||
t->addAttribute( "disposition", m_disposition );
|
||||
t->addAttribute( "name", m_name );
|
||||
t->addAttribute( "senders", util::lookup( m_senders, sendersValues ) );
|
||||
|
||||
PluginList::const_iterator it = m_plugins.begin();
|
||||
for( ; it != m_plugins.end(); ++it )
|
||||
t->addChild( (*it)->tag() );
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Plugin* Content::clone() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
Copyright (c) 2008-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JINGLECONTENT_H__
|
||||
#define JINGLECONTENT_H__
|
||||
|
||||
|
||||
#include "jingleplugin.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
class PluginFactory;
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a Jingle Content Type. This is part of Jingle (@xep{0166}).
|
||||
*
|
||||
* See @link gloox::Jingle::Session Jingle::Session @endlink for more info on Jingle.
|
||||
*
|
||||
* XEP Version: 1.1
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class GLOOX_API Content : public Plugin
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The original creator of the content type.
|
||||
*/
|
||||
enum Creator
|
||||
{
|
||||
CInitiator, /**< The creator is the initiator of the session. */
|
||||
CResponder, /**< The creator is the responder. */
|
||||
InvalidCreator /**< Invalid value. */
|
||||
};
|
||||
|
||||
/**
|
||||
* The parties in the session that will be generating content.
|
||||
*/
|
||||
enum Senders
|
||||
{
|
||||
SInitiator, /**< The initiator generates/sends content. */
|
||||
SResponder, /**< The responder generates/sends content. */
|
||||
SBoth, /**< Both parties generate/send content( default). */
|
||||
SNone, /**< No party generates/sends content. */
|
||||
InvalidSender /**< Invalid value. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new Content wrapper.
|
||||
* @param name A unique name for the content type.
|
||||
* @param plugins A list of application formats, transport methods, security preconditions, ...
|
||||
* @param creator Which party originally generated the content type; the defined values are "SInitiator" and "SResponder".
|
||||
* @param senders Which parties in the session will be generating content.
|
||||
* @param disposition How the content definition is to be interpreted by the recipient. The meaning of this attribute
|
||||
* matches the "Content-Disposition" header as defined in RFC 2183 and applied to SIP by RFC 3261.
|
||||
*/
|
||||
Content( const std::string& name, const PluginList& plugins, Creator creator = CInitiator,
|
||||
Senders senders = SBoth, const std::string& disposition = "session" );
|
||||
|
||||
/**
|
||||
* Creates a new Content object from the given tag.
|
||||
* @param tag The Tag to parse.
|
||||
* @param factory A PluginFactory instance to use for embedding plugins.
|
||||
*/
|
||||
Content( const Tag* tag = 0, PluginFactory* factory = 0 );
|
||||
|
||||
/**
|
||||
* Returns the content's creator.
|
||||
* @return The content's creator.
|
||||
*/
|
||||
Creator creator() const { return m_creator; }
|
||||
|
||||
/**
|
||||
* Returns the senders.
|
||||
* @return The senders.
|
||||
*/
|
||||
Senders senders() const { return m_senders; }
|
||||
|
||||
/**
|
||||
* Returns the disposition.
|
||||
* @return The disposition.
|
||||
*/
|
||||
const std::string& disposition() const { return m_disposition; }
|
||||
|
||||
/**
|
||||
* Returns the content name.
|
||||
* @return The content name.
|
||||
*/
|
||||
const std::string& name() const { return m_name; }
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Content();
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Plugin* newInstance( const Tag* tag ) const { return new Content( tag, m_factory ); }
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Plugin* clone() const;
|
||||
|
||||
private:
|
||||
Creator m_creator;
|
||||
std::string m_disposition;
|
||||
std::string m_name;
|
||||
Senders m_senders;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // JINGLECONTENT_H__
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "jinglefiletransfer.h"
|
||||
|
||||
#include "tag.h"
|
||||
#include "gloox.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
static const char* typeValues [] = {
|
||||
"offer",
|
||||
"request",
|
||||
"checksum",
|
||||
"abort",
|
||||
"received"
|
||||
};
|
||||
|
||||
FileTransfer::FileTransfer( Type type, const FileList& files )
|
||||
: Plugin( PluginFileTransfer ), m_type( type ), m_files( files )
|
||||
{
|
||||
}
|
||||
|
||||
FileTransfer::FileTransfer( const Tag* tag )
|
||||
: Plugin( PluginFileTransfer ), m_type( Invalid )
|
||||
{
|
||||
if( !tag || tag->xmlns() != XMLNS_JINGLE_FILE_TRANSFER )
|
||||
return;
|
||||
|
||||
std::string name = tag->name();
|
||||
if( name == "description" )
|
||||
{
|
||||
const Tag* c = tag->findTag( "description/offer|description/request" );
|
||||
if( c )
|
||||
{
|
||||
parseFileList( c->findChildren( "file" ) );
|
||||
name = c->name();
|
||||
}
|
||||
}
|
||||
else if( name == "checksum" || name == "abort" || name == "received" )
|
||||
{
|
||||
parseFileList( tag->findChildren( "file" ) );
|
||||
}
|
||||
|
||||
m_type = (Type)util::lookup( name, typeValues );
|
||||
}
|
||||
|
||||
void FileTransfer::parseFileList( const TagList& files )
|
||||
{
|
||||
TagList::const_iterator it = files.begin();
|
||||
for( ; it != files.end(); ++it )
|
||||
{
|
||||
File f;
|
||||
Tag *t = (*it)->findChild( "name" );
|
||||
f.name = t ? t->cdata() : EmptyString;
|
||||
t = (*it)->findChild( "desc" );
|
||||
f.desc = t ? t->cdata() : EmptyString;
|
||||
t = (*it)->findChild( "date" );
|
||||
f.date = t ? t->cdata() : EmptyString;
|
||||
t = (*it)->findChild( "size" );
|
||||
f.size = t ? atoi( t->cdata().c_str() ) : -1;
|
||||
t = (*it)->findChild( "range" );
|
||||
if( t )
|
||||
{
|
||||
f.range = true;
|
||||
f.offset = t->hasAttribute( "offset" ) ? atoi( t->findAttribute( "offset" ).c_str() ) : -1;
|
||||
}
|
||||
t = (*it)->findChild( "hash", XMLNS, XMLNS_HASHES );
|
||||
if( t )
|
||||
{
|
||||
f.hash_algo = t->findAttribute( "algo" );
|
||||
f.hash = t->cdata();
|
||||
}
|
||||
m_files.push_back( f );
|
||||
}
|
||||
}
|
||||
|
||||
const StringList FileTransfer::features() const
|
||||
{
|
||||
StringList sl;
|
||||
sl.push_back( XMLNS_JINGLE_FILE_TRANSFER );
|
||||
return sl;
|
||||
}
|
||||
|
||||
const std::string& FileTransfer::filterString() const
|
||||
{
|
||||
static const std::string filter = "content/description[@xmlns='" + XMLNS_JINGLE_FILE_TRANSFER + "']"
|
||||
"|jingle/abort[@xmlns='" + XMLNS_JINGLE_FILE_TRANSFER + "']"
|
||||
"|jingle/received[@xmlns='" + XMLNS_JINGLE_FILE_TRANSFER + "']"
|
||||
"|jingle/checksum[@xmlns='" + XMLNS_JINGLE_FILE_TRANSFER + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Plugin* FileTransfer::newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new FileTransfer( tag );
|
||||
}
|
||||
|
||||
Tag* FileTransfer::tag() const
|
||||
{
|
||||
if( m_type == Invalid )
|
||||
return 0;
|
||||
|
||||
Tag* r = 0;
|
||||
|
||||
switch( m_type )
|
||||
{
|
||||
case Offer:
|
||||
case Request:
|
||||
{
|
||||
r = new Tag( "description", XMLNS, XMLNS_JINGLE_FILE_TRANSFER );
|
||||
Tag* o = new Tag( r, util::lookup( m_type, typeValues ) );
|
||||
FileList::const_iterator it = m_files.begin();
|
||||
for( ; it != m_files.end(); ++it )
|
||||
{
|
||||
Tag* f = new Tag( o, "file" );
|
||||
new Tag( f, "date", (*it).date );
|
||||
new Tag( f, "name", (*it).name );
|
||||
new Tag( f, "desc", (*it).desc );
|
||||
new Tag( f, "size", util::long2string( (*it).size ) );
|
||||
Tag* h = new Tag( f, "hash", XMLNS, XMLNS_HASHES );
|
||||
h->addAttribute( "algo", (*it).hash_algo );
|
||||
h->setCData( (*it).hash );
|
||||
if( (*it).range )
|
||||
new Tag( f, "range", "offset", (*it).offset ? util::long2string( (*it).offset ) : EmptyString );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Abort:
|
||||
case Checksum:
|
||||
case Received:
|
||||
{
|
||||
r = new Tag( util::lookup( m_type, typeValues ), XMLNS, XMLNS_JINGLE_FILE_TRANSFER );
|
||||
FileList::const_iterator it = m_files.begin();
|
||||
Tag* f = new Tag( r, "file" );
|
||||
new Tag( f, "date", (*it).date );
|
||||
new Tag( f, "name", (*it).name );
|
||||
new Tag( f, "desc", (*it).desc );
|
||||
new Tag( f, "size", util::long2string( (*it).size ) );
|
||||
Tag* h = new Tag( f, "hash", XMLNS, XMLNS_HASHES );
|
||||
h->addAttribute( "algo", (*it).hash_algo );
|
||||
h->setCData( (*it).hash );
|
||||
if( (*it).range )
|
||||
new Tag( f, "range" );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JINGLEFILETRANSFER_H__
|
||||
#define JINGLEFILETRANSFER_H__
|
||||
|
||||
#include "jingleplugin.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An abstraction of the signaling part of Jingle File Transfer (@xep{0234}), implemented as a Jingle::Plugin.
|
||||
*
|
||||
* XEP Version: 0.15
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.7
|
||||
*/
|
||||
class GLOOX_API FileTransfer : public Plugin
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* The type of a FileTransfer instance.
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
Offer, /**< Signifies a file transfer offer (send). */
|
||||
Request, /**< Signifies a file request (pull). */
|
||||
Checksum, /**< Used to send a file's checksum. */
|
||||
Abort, /**< used to abort a running transfer. */
|
||||
Received, /**< Signifies a successful file transfer. */
|
||||
Invalid /**< Invalid type. */
|
||||
};
|
||||
|
||||
/**
|
||||
* A struct holding information about a file.
|
||||
*/
|
||||
struct File
|
||||
{
|
||||
std::string name; /**< The file's name. */
|
||||
std::string date; /**< The file's (creation?) date */
|
||||
std::string desc; /**< A description. */
|
||||
std::string hash; /**< The file's cehcksum. */
|
||||
std::string hash_algo; /**< The algorithm used to calculate the checksum */
|
||||
long int size; /**< The filesize in Bytes. */
|
||||
bool range; /**< Signifies that an offset transfer is possible. */
|
||||
long int offset; /**< An (optional) offset. */
|
||||
};
|
||||
|
||||
/** A list of file information structs. */
|
||||
typedef std::list<File> FileList;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
* @param type The type of the object.
|
||||
* @param files A list of files to offer, request, acknowledge, ... Most of
|
||||
* the time this list will contain only one file.
|
||||
*/
|
||||
FileTransfer( Type type, const FileList& files );
|
||||
|
||||
/**
|
||||
* Creates a new instance from the given Tag
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
FileTransfer( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~FileTransfer() {}
|
||||
|
||||
/**
|
||||
* Returns the type.
|
||||
* @return The type.
|
||||
*/
|
||||
Type type() const { return m_type; }
|
||||
|
||||
/**
|
||||
* Returns a list of embedded file infos.
|
||||
* @return A list of embedded file infos.
|
||||
*/
|
||||
const FileList& files() const { return m_files; }
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual const StringList features() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Plugin* newInstance( const Tag* tag ) const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Plugin* clone() const
|
||||
{
|
||||
return new FileTransfer( *this );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void parseFileList( const TagList& files );
|
||||
|
||||
Type m_type;
|
||||
FileList m_files;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // JINGLEFILETRANSFER_H__
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "jingleiceudp.h"
|
||||
|
||||
#include "tag.h"
|
||||
#include "gloox.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
static const char* typeValues [] = {
|
||||
"host",
|
||||
"prflx",
|
||||
"relay",
|
||||
"srflx"
|
||||
};
|
||||
|
||||
ICEUDP::ICEUDP( const std::string& pwd, const std::string& ufrag, CandidateList& candidates )
|
||||
: Plugin( PluginICEUDP ), m_pwd( pwd ), m_ufrag( ufrag), m_candidates( candidates )
|
||||
{
|
||||
}
|
||||
|
||||
ICEUDP::ICEUDP( const Tag* tag )
|
||||
: Plugin( PluginICEUDP )
|
||||
{
|
||||
if( !tag || tag->name() != "transport" || tag->xmlns() != XMLNS_JINGLE_ICE_UDP )
|
||||
return;
|
||||
|
||||
m_pwd = tag->findAttribute( "pwd" );
|
||||
m_ufrag = tag->findAttribute( "ufrag" );
|
||||
const TagList candidates = tag->findChildren( "candidate" );
|
||||
TagList::const_iterator it = candidates.begin();
|
||||
for( ; it != candidates.end(); ++it )
|
||||
{
|
||||
Candidate c;
|
||||
c.component = (*it)->findAttribute( "component" );
|
||||
c.foundation = (*it)->findAttribute( "foundation" );
|
||||
c.generation = (*it)->findAttribute( "generation" );
|
||||
c.id = (*it)->findAttribute( "id" );
|
||||
c.ip = (*it)->findAttribute( "ip" );
|
||||
c.network = (*it)->findAttribute( "network" );
|
||||
c.port = atoi( (*it)->findAttribute( "port" ).c_str() );
|
||||
c.priority = atoi( (*it)->findAttribute( "priority" ).c_str() );
|
||||
c.protocol = (*it)->findAttribute( "protocol" );
|
||||
c.rel_addr = (*it)->findAttribute( "rel-addr" );
|
||||
c.rel_port = atoi( (*it)->findAttribute( "rel-port" ).c_str() );
|
||||
c.type = (Type)util::lookup( (*it)->findAttribute( "type" ), typeValues );
|
||||
m_candidates.push_back( c );
|
||||
}
|
||||
}
|
||||
|
||||
const StringList ICEUDP::features() const
|
||||
{
|
||||
StringList sl;
|
||||
sl.push_back( XMLNS_JINGLE_ICE_UDP );
|
||||
return sl;
|
||||
}
|
||||
|
||||
const std::string& ICEUDP::filterString() const
|
||||
{
|
||||
static const std::string filter = "content/transport[@xmlns='" + XMLNS_JINGLE_ICE_UDP + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Plugin* ICEUDP::newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new ICEUDP( tag );
|
||||
}
|
||||
|
||||
Tag* ICEUDP::tag() const
|
||||
{
|
||||
Tag* t = new Tag( "transport", XMLNS, XMLNS_JINGLE_ICE_UDP );
|
||||
t->addAttribute( "pwd", m_pwd );
|
||||
t->addAttribute( "ufrag", m_ufrag );
|
||||
|
||||
CandidateList::const_iterator it = m_candidates.begin();
|
||||
for( ; it != m_candidates.end(); ++it )
|
||||
{
|
||||
Tag* c = new Tag( t, "candidate" );
|
||||
c->addAttribute( "component", (*it).component );
|
||||
c->addAttribute( "foundation", (*it).foundation );
|
||||
c->addAttribute( "generation", (*it).generation );
|
||||
c->addAttribute( "id", (*it).id );
|
||||
c->addAttribute( "ip", (*it).ip );
|
||||
c->addAttribute( "network", (*it).network );
|
||||
c->addAttribute( "port", (*it).port );
|
||||
c->addAttribute( "priority", (*it).priority );
|
||||
c->addAttribute( "protocol", (*it).protocol );
|
||||
c->addAttribute( "rel-addr", (*it).rel_addr );
|
||||
c->addAttribute( "rel-port", (*it).rel_port );
|
||||
c->addAttribute( "type", util::lookup( (*it).type, typeValues ) );
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JINGLEICEUDP_H__
|
||||
#define JINGLEICEUDP_H__
|
||||
|
||||
#include "jingleplugin.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An abstraction of the signaling part of Jingle ICE-UDP Transport Method (@xep{0176}).
|
||||
*
|
||||
* XEP Version: 1.0
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.7
|
||||
*/
|
||||
class GLOOX_API ICEUDP : public Plugin
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Describes the candidate type.
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
Host, /**< A host candidate. */
|
||||
PeerReflexive, /**< A peer reflexive candidate. */
|
||||
Relayed, /**< A relayed candidate. */
|
||||
ServerReflexive /**< A server reflexive candidate. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes a single transport candidate.
|
||||
*/
|
||||
struct Candidate
|
||||
{
|
||||
std::string component; /**< A Component ID as defined in ICE-CORE. */
|
||||
std::string foundation; /**< A Foundation as defined in ICE-CORE.*/
|
||||
std::string generation; /**< An index, starting at 0, that enables the parties to keep track of
|
||||
updates to the candidate throughout the life of the session. */
|
||||
std::string id; /**< A unique identifier for the candidate. */
|
||||
std::string ip; /**< The IP address for the candidate transport mechanism. */
|
||||
std::string network; /**< An index, starting at 0, referencing which network this candidate is on for a given peer. */
|
||||
int port; /**< The port at the candidate IP address. */
|
||||
int priority; /**< A Priority as defined in ICE-CORE. */
|
||||
std::string protocol; /**< The protocol to be used. Should be @b udp. */
|
||||
std::string rel_addr; /**< A related address as defined in ICE-CORE. */
|
||||
int rel_port; /**< A related port as defined in ICE-CORE. */
|
||||
Type type; /**< A Candidate Type as defined in ICE-CORE. */
|
||||
};
|
||||
|
||||
/** A list of transport candidates. */
|
||||
typedef std::list<Candidate> CandidateList;
|
||||
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param pwd The @c pwd value.
|
||||
* @param ufrag The @c ufrag value.
|
||||
* @param candidates A list of connection candidates.
|
||||
*/
|
||||
ICEUDP( const std::string& pwd, const std::string& ufrag, CandidateList& candidates );
|
||||
|
||||
/**
|
||||
* Constructs a new instance from the given tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
ICEUDP( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~ICEUDP() {}
|
||||
|
||||
/**
|
||||
* Returns the @c pwd value.
|
||||
* @return The @c pwd value.
|
||||
*/
|
||||
const std::string& pwd() const { return m_pwd; }
|
||||
|
||||
/**
|
||||
* Returns the @c ufrag value.
|
||||
* @return The @c ufrag value.
|
||||
*/
|
||||
const std::string& ufrag() const { return m_ufrag; }
|
||||
|
||||
/**
|
||||
* Returns the list of connection candidates.
|
||||
* @return The list of connection candidates.
|
||||
*/
|
||||
const CandidateList& candidates() const { return m_candidates; }
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual const StringList features() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Plugin* newInstance( const Tag* tag ) const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Plugin* clone() const
|
||||
{
|
||||
return new ICEUDP( *this );
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_pwd;
|
||||
std::string m_ufrag;
|
||||
CandidateList m_candidates;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // JINGLEICEUDP_H__
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
Copyright (c) 2008-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JINGLEPLUGIN_H__
|
||||
#define JINGLEPLUGIN_H__
|
||||
|
||||
#include "macros.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
class Plugin;
|
||||
class PluginFactory;
|
||||
|
||||
enum JinglePluginType
|
||||
{
|
||||
PluginNone, /**< Invalid plugin type. */
|
||||
PluginContent, /**< A plugin abstracting a <content> element. May contain further plugins. */
|
||||
PluginFileTransfer, /**< A plugin for File Transfer. */
|
||||
PluginICEUDP, /**< A plugin for ICE UDP transport negotiation. */
|
||||
PluginReason, /**< An abstraction of a Jingle (@xep{0166}) session terminate reason. */
|
||||
PluginUser /**< User-supplied plugins must use IDs above this. Do
|
||||
* not hard-code PluginUser's value anywhere, it is subject
|
||||
* to change. */
|
||||
};
|
||||
|
||||
/**
|
||||
* A list of Jingle plugins.
|
||||
*/
|
||||
typedef std::list<const Plugin*> PluginList;
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a Jingle plugin. This is part of Jingle (@xep{0166} et al.)
|
||||
*
|
||||
* This is the base class for Content and all other pluggable Jingle-related containers, e.g.
|
||||
* session information, such as the 'ringing' info in Jingle Audio, or Jingle DTMF, etc.
|
||||
*
|
||||
* A Plugin abstracts the XML that gets sent and received as part of a Jingle session negotiation.
|
||||
*
|
||||
* XEP Version: 1.1
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class GLOOX_API Plugin
|
||||
{
|
||||
|
||||
friend class PluginFactory;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Simple initializer.
|
||||
*/
|
||||
Plugin( JinglePluginType type ) : m_factory( 0 ), m_pluginType( type ) {}
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Plugin() { util::clearList( m_plugins ) ; }
|
||||
|
||||
/**
|
||||
* Adds another Plugin as child.
|
||||
* @param plugin A plugin to be embedded. Will be owned by this instance and deleted in the destructor.
|
||||
*/
|
||||
void addPlugin( const Plugin* plugin ) { if( plugin ) m_plugins.push_back( plugin ); }
|
||||
|
||||
/**
|
||||
* Finds a Jingle::Plugin of a particular type.
|
||||
* @param type JinglePluginType to search for.
|
||||
* @return A pointer to the first Jingle::Plugin of the given type, or 0 if none was found.
|
||||
*/
|
||||
const Plugin* findPlugin( int type ) const
|
||||
{
|
||||
PluginList::const_iterator it = m_plugins.begin();
|
||||
for( ; it != m_plugins.end() && (*it)->pluginType() != type; ++it ) ;
|
||||
return it != m_plugins.end() ? (*it) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a Jingle::Plugin of a particular type.
|
||||
* Example:
|
||||
* @code
|
||||
* const MyPlugin* c = plugin.findPlugin<MyPlugin>( PluginMyPlugin );
|
||||
* @endcode
|
||||
* @param type The plugin type to look for.
|
||||
* @return The static_cast' type, or 0 if none was found.
|
||||
*/
|
||||
template< class T >
|
||||
inline const T* findPlugin( int type ) const
|
||||
{
|
||||
return static_cast<const T*>( findPlugin( type ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to a list of embedded plugins.
|
||||
* @return A reference to a list of embedded plugins.
|
||||
*/
|
||||
const PluginList& plugins() const { return m_plugins; }
|
||||
|
||||
/**
|
||||
* Reimplement this function if your plugin wants to add anything to the list of
|
||||
* features announced via Disco.
|
||||
* @return A list of additional feature strings.
|
||||
*/
|
||||
virtual const StringList features() const { return StringList(); }
|
||||
|
||||
/**
|
||||
* Returns an XPath expression that describes a path to child elements of a
|
||||
* jingle element that the plugin handles.
|
||||
* The result should be a single Tag.
|
||||
*
|
||||
* @return The plugin's filter string.
|
||||
*/
|
||||
virtual const std::string& filterString() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a Tag representation of the plugin.
|
||||
* @return A Tag representation of the plugin.
|
||||
*/
|
||||
virtual Tag* tag() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a new instance of the same plugin type,
|
||||
* based on the Tag provided.
|
||||
* @param tag The Tag to parse and create a new instance from.
|
||||
* @return The new plugin instance.
|
||||
*/
|
||||
virtual Plugin* newInstance( const Tag* tag ) const = 0;
|
||||
|
||||
/**
|
||||
* Creates an identical deep copy of the current instance.
|
||||
* @return An identical deep copy of the current instance.
|
||||
*/
|
||||
virtual Plugin* clone() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the plugin type.
|
||||
* @return The plugin type.
|
||||
*/
|
||||
JinglePluginType pluginType() const { return m_pluginType; }
|
||||
|
||||
protected:
|
||||
PluginList m_plugins;
|
||||
PluginFactory* m_factory;
|
||||
|
||||
private:
|
||||
void setFactory( PluginFactory* factory ) { m_factory = factory; }
|
||||
|
||||
JinglePluginType m_pluginType;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // JINGLEPLUGIN_H__
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "jinglepluginfactory.h"
|
||||
#include "tag.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
PluginFactory::PluginFactory()
|
||||
{
|
||||
}
|
||||
|
||||
PluginFactory::~PluginFactory()
|
||||
{
|
||||
util::clearList( m_plugins );
|
||||
}
|
||||
|
||||
void PluginFactory::registerPlugin( Plugin* plugin )
|
||||
{
|
||||
if( !plugin )
|
||||
return;
|
||||
|
||||
plugin->setFactory( this );
|
||||
m_plugins.push_back( plugin );
|
||||
}
|
||||
|
||||
void PluginFactory::addPlugins( Plugin& plugin, const Tag* tag )
|
||||
{
|
||||
if( !tag )
|
||||
return;
|
||||
|
||||
ConstTagList::const_iterator it;
|
||||
|
||||
PluginList::const_iterator itp = m_plugins.begin();
|
||||
for( ; itp != m_plugins.end(); ++itp )
|
||||
{
|
||||
const ConstTagList& match = tag->findTagList( (*itp)->filterString() );
|
||||
it = match.begin();
|
||||
for( ; it != match.end(); ++it )
|
||||
{
|
||||
Plugin* pl = (*itp)->newInstance( (*it) );
|
||||
if( pl )
|
||||
{
|
||||
plugin.addPlugin( pl );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PluginFactory::addPlugins( Session::Jingle& jingle, const Tag* tag )
|
||||
{
|
||||
if( !tag )
|
||||
return;
|
||||
|
||||
ConstTagList::const_iterator it;
|
||||
|
||||
PluginList::const_iterator itp = m_plugins.begin();
|
||||
for( ; itp != m_plugins.end(); ++itp )
|
||||
{
|
||||
const ConstTagList& match = tag->findTagList( (*itp)->filterString() );
|
||||
it = match.begin();
|
||||
for( ; it != match.end(); ++it )
|
||||
{
|
||||
Plugin* pl = (*itp)->newInstance( (*it) );
|
||||
if( pl )
|
||||
{
|
||||
jingle.addPlugin( pl );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JINGLEPLUGINFACTORY_H__
|
||||
#define JINGLEPLUGINFACTORY_H__
|
||||
|
||||
#include "jingleplugin.h"
|
||||
#include "jinglesession.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A factory for which creates Plugin instances based on Tags. This is part of Jingle (@xep{0166}).
|
||||
*
|
||||
* Used by Jingle::SessionManager. You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.7
|
||||
*/
|
||||
class PluginFactory
|
||||
{
|
||||
friend class SessionManager;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~PluginFactory();
|
||||
|
||||
/**
|
||||
* Registers an empty Plugin as a template with the factory.
|
||||
* @param plugin The plugin to register.
|
||||
*/
|
||||
void registerPlugin( Plugin* plugin );
|
||||
|
||||
/**
|
||||
* Based on the template plugins' filter string, this function checks the supplied tag for
|
||||
* supported extensions and adds them as new plugins to the supplied Plugin instance.
|
||||
* @param plugin The Plugin-derived object that will have the newly created plugins embedded.
|
||||
* @param tag The Tag to check for supported extensions.
|
||||
*/
|
||||
void addPlugins( Plugin& plugin, const Tag* tag );
|
||||
|
||||
/**
|
||||
* Based on the template plugins' filter string, this function checks the supplied tag for
|
||||
* supported extensions and adds them as new plugins to the supplied Jingle instance.
|
||||
* @param jingle The Jingle object that will have the newly created plugins embedded.
|
||||
* @param tag The Tag to check for supported extensions.
|
||||
*/
|
||||
void addPlugins( Session::Jingle& jingle, const Tag* tag );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*/
|
||||
PluginFactory();
|
||||
|
||||
PluginList m_plugins;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // JINGLEPLUGINFACTORY_H__
|
|
@ -0,0 +1,501 @@
|
|||
/*
|
||||
Copyright (c) 2007-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "jinglesession.h"
|
||||
|
||||
#include "clientbase.h"
|
||||
#include "error.h"
|
||||
#include "jinglecontent.h"
|
||||
#include "jinglesessionhandler.h"
|
||||
#include "tag.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
static const char* actionValues [] = {
|
||||
"content-accept",
|
||||
"content-add",
|
||||
"content-modify",
|
||||
"content-reject",
|
||||
"content-remove",
|
||||
"description-info",
|
||||
"security-info",
|
||||
"session-accept",
|
||||
"session-info",
|
||||
"session-initiate",
|
||||
"session-terminate",
|
||||
"transport-accept",
|
||||
"transport-info",
|
||||
"transport-reject",
|
||||
"transport-replace"
|
||||
};
|
||||
|
||||
static inline Action actionType( const std::string& type )
|
||||
{
|
||||
return (Action)util::lookup( type, actionValues );
|
||||
}
|
||||
|
||||
// ---- Session::Reason ----
|
||||
static const char* reasonValues [] = {
|
||||
"alternative-session",
|
||||
"busy",
|
||||
"cancel",
|
||||
"connectivity-error",
|
||||
"decline",
|
||||
"expired",
|
||||
"failed-application",
|
||||
"failed-transport",
|
||||
"general-error",
|
||||
"gone",
|
||||
"incompatible-parameters",
|
||||
"media-error",
|
||||
"security-error",
|
||||
"success",
|
||||
"timeout",
|
||||
"unsupported-applications",
|
||||
"unsupported-transports"
|
||||
};
|
||||
|
||||
static inline Session::Reason::Reasons reasonType( const std::string& type )
|
||||
{
|
||||
return (Session::Reason::Reasons)util::lookup( type, reasonValues );
|
||||
}
|
||||
|
||||
Session::Reason::Reason( Reasons reason,
|
||||
const std::string& sid,
|
||||
const std::string& text)
|
||||
: Plugin( PluginReason ), m_reason( reason ), m_sid( sid ), m_text( text )
|
||||
{
|
||||
}
|
||||
|
||||
Session::Reason::Reason( const Tag* tag )
|
||||
: Plugin( PluginReason )
|
||||
{
|
||||
if( !tag || tag->name() != "reason" )
|
||||
return;
|
||||
|
||||
const TagList& l = tag->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
if( (*it)->name() == "text" )
|
||||
m_text = (*it)->cdata();
|
||||
else if( (*it)->xmlns() == XMLNS_JINGLE )
|
||||
m_reason = reasonType( (*it)->name() );
|
||||
}
|
||||
}
|
||||
|
||||
Session::Reason::~Reason()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& Session::Reason::filterString() const
|
||||
{
|
||||
static const std::string filter = "jingle/reason";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Session::Reason::tag() const
|
||||
{
|
||||
if( m_reason == InvalidReason )
|
||||
return 0;
|
||||
|
||||
Tag* t = new Tag( "reason" );
|
||||
Tag* r = new Tag( t, util::lookup( m_reason, reasonValues ) );
|
||||
if( m_reason == AlternativeSession && !m_sid.empty() )
|
||||
new Tag( r, "sid", m_sid );
|
||||
|
||||
if( !m_text.empty() )
|
||||
new Tag( t, "text", m_text );
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
Plugin* Session::Reason::clone() const
|
||||
{
|
||||
return new Reason( *this );
|
||||
}
|
||||
// ---- ~Session::Reason ----
|
||||
|
||||
// ---- Session::Jingle ----
|
||||
Session::Jingle::Jingle( Action action, const JID& initiator, const JID& responder,
|
||||
const PluginList& plugins, const std::string& sid )
|
||||
: StanzaExtension( ExtJingle ), m_action( action ), m_sid( sid ),
|
||||
m_initiator( initiator ), m_responder( responder ), m_plugins( plugins ), m_tag( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef JINGLE_TEST
|
||||
Session::Jingle::Jingle( Action action, const JID& initiator, const JID& responder,
|
||||
const Plugin* plugin, const std::string& sid )
|
||||
: StanzaExtension( ExtJingle ), m_action( action ), m_sid( sid ),
|
||||
m_initiator( initiator ), m_responder( responder ), m_tag( 0 )
|
||||
{
|
||||
if( plugin )
|
||||
m_plugins.push_back( plugin );
|
||||
}
|
||||
#endif
|
||||
|
||||
Session::Jingle::Jingle( const Tag* tag )
|
||||
: StanzaExtension( ExtJingle ), m_action( InvalidAction ), m_tag( 0 )
|
||||
{
|
||||
if( !tag || tag->name() != "jingle" )
|
||||
return;
|
||||
|
||||
m_action = actionType( tag->findAttribute( "action" ) );
|
||||
m_initiator.setJID( tag->findAttribute( "initiator" ) );
|
||||
m_responder.setJID( tag->findAttribute( "responder" ) );
|
||||
m_sid = tag->findAttribute( "sid" );
|
||||
|
||||
m_tag = tag->clone();
|
||||
}
|
||||
|
||||
// Session::Jingle::Jingle( const Jingle& right )
|
||||
// : StanzaExtension( ExtJingle ), m_action( right.m_action ),
|
||||
// m_sid( right.m_sid ), m_initiator( right.m_initiator ),
|
||||
// m_responder( right.m_responder )
|
||||
// {
|
||||
// PluginList::const_iterator it = right.m_plugins.begin();
|
||||
// for( ; it != right.m_plugins.end(); ++it )
|
||||
// m_plugins.push_back( (*it)->clone() );
|
||||
// }
|
||||
|
||||
Session::Jingle::~Jingle()
|
||||
{
|
||||
util::clearList( m_plugins );
|
||||
}
|
||||
|
||||
const std::string& Session::Jingle::filterString() const
|
||||
{
|
||||
static const std::string filter = "/iq/jingle[@xmlns='" + XMLNS_JINGLE + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Session::Jingle::tag() const
|
||||
{
|
||||
if( m_action == InvalidAction || m_sid.empty() )
|
||||
return 0;
|
||||
|
||||
Tag* t = new Tag( "jingle" );
|
||||
t->setXmlns( XMLNS_JINGLE );
|
||||
t->addAttribute( "action", util::lookup( m_action, actionValues ) );
|
||||
|
||||
if( m_initiator && m_action == SessionInitiate )
|
||||
t->addAttribute( "initiator", m_initiator.full() );
|
||||
|
||||
if( m_responder && m_action == SessionAccept )
|
||||
t->addAttribute( "responder", m_responder.full() );
|
||||
|
||||
t->addAttribute( "sid", m_sid );
|
||||
|
||||
PluginList::const_iterator it = m_plugins.begin();
|
||||
for( ; it != m_plugins.end(); ++it )
|
||||
t->addChild( (*it)->tag() );
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
StanzaExtension* Session::Jingle::clone() const
|
||||
{
|
||||
return new Jingle( *this );
|
||||
}
|
||||
// ---- ~Session::Jingle ----
|
||||
|
||||
// ---- Session ----
|
||||
Session::Session( ClientBase* parent, const JID& callee, SessionHandler* jsh )
|
||||
: m_parent( parent ), m_state( Ended ), m_remote( callee ),
|
||||
m_handler( jsh ), m_valid( false )
|
||||
{
|
||||
if( !m_parent || !m_handler || !m_remote )
|
||||
return;
|
||||
|
||||
m_initiator = m_parent->jid();
|
||||
m_sid = m_parent->getID();
|
||||
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
Session::Session( ClientBase* parent, const JID& callee, const Session::Jingle* jingle, SessionHandler* jsh )
|
||||
: m_parent( parent ), m_state( Ended ), m_handler( jsh ), m_valid( false )
|
||||
{
|
||||
if( !m_parent || !m_handler || !callee /*|| jingle->action() != SessionInitiate*/ )
|
||||
return;
|
||||
|
||||
m_remote = callee;
|
||||
m_sid = jingle->sid();
|
||||
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
Session::~Session()
|
||||
{
|
||||
if( m_parent )
|
||||
m_parent->removeIDHandler( this );
|
||||
}
|
||||
|
||||
bool Session::contentAccept( const Content* content )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( ContentAccept, content );
|
||||
}
|
||||
|
||||
bool Session::contentAdd( const Content* content )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( ContentAdd, content );
|
||||
}
|
||||
|
||||
bool Session::contentAdd( const PluginList& contents )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( ContentAdd, contents );
|
||||
}
|
||||
|
||||
bool Session::contentModify( const Content* content )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( ContentModify, content );
|
||||
}
|
||||
|
||||
bool Session::contentReject( const Content* content )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( ContentReject, content );
|
||||
}
|
||||
|
||||
bool Session::contentRemove( const Content* content )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( ContentRemove, content );
|
||||
}
|
||||
|
||||
bool Session::descriptionInfo( const Plugin* info )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( DescriptionInfo, info );
|
||||
}
|
||||
|
||||
bool Session::securityInfo( const Plugin* info )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( SecurityInfo, info );
|
||||
}
|
||||
|
||||
bool Session::sessionAccept( const Content* content )
|
||||
{
|
||||
if( !content || m_state > Pending )
|
||||
return false;
|
||||
|
||||
m_state = Active;
|
||||
return doAction( SessionAccept, content );
|
||||
}
|
||||
|
||||
bool Session::sessionAccept( const PluginList& plugins )
|
||||
{
|
||||
if( plugins.empty() || m_state != Pending )
|
||||
return false;
|
||||
|
||||
m_state = Active;
|
||||
return doAction( SessionAccept, plugins );
|
||||
}
|
||||
|
||||
bool Session::sessionInfo( const Plugin* info )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( SessionInfo, info );
|
||||
}
|
||||
|
||||
bool Session::sessionInitiate( const Content* content )
|
||||
{
|
||||
if( !content || !m_initiator || m_state >= Pending )
|
||||
return false;
|
||||
|
||||
m_state = Pending;
|
||||
return doAction( SessionInitiate, content );
|
||||
}
|
||||
|
||||
bool Session::sessionInitiate( const PluginList& plugins )
|
||||
{
|
||||
if( plugins.empty() || !m_initiator || m_state >= Pending )
|
||||
return false;
|
||||
|
||||
m_state = Pending;
|
||||
return doAction( SessionInitiate, plugins );
|
||||
}
|
||||
|
||||
bool Session::sessionTerminate( Session::Reason* reason )
|
||||
{
|
||||
if( m_state < Pending /*|| !m_initiator*/ )
|
||||
return false;
|
||||
|
||||
m_state = Ended;
|
||||
|
||||
return doAction( SessionTerminate, reason );
|
||||
}
|
||||
|
||||
bool Session::transportAccept( const Content* content )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( TransportAccept, content );
|
||||
}
|
||||
|
||||
bool Session::transportInfo( const Plugin* info )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( TransportInfo, info );
|
||||
}
|
||||
|
||||
bool Session::transportReject( const Content* content )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( TransportReject, content );
|
||||
}
|
||||
|
||||
bool Session::transportReplace( const Content* content )
|
||||
{
|
||||
if( m_state < Pending )
|
||||
return false;
|
||||
|
||||
return doAction( TransportReplace, content );
|
||||
}
|
||||
|
||||
bool Session::doAction( Action action, const Plugin* plugin )
|
||||
{
|
||||
PluginList pl;
|
||||
pl.push_back( plugin );
|
||||
return doAction( action, pl );
|
||||
}
|
||||
|
||||
bool Session::doAction( Action action, const PluginList& plugins )
|
||||
{
|
||||
if( !m_valid || !m_parent )
|
||||
return false;
|
||||
|
||||
IQ init( IQ::Set, m_remote, m_parent->getID() );
|
||||
init.addExtension( new Jingle( action, m_initiator, m_responder, plugins, m_sid ) );
|
||||
m_parent->send( init, this, action );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Session::handleIq( const IQ& iq )
|
||||
{
|
||||
const Jingle* j = iq.findExtension<Jingle>( ExtJingle );
|
||||
if( !j || j->sid() != m_sid || !m_handler || !m_parent )
|
||||
return false;
|
||||
|
||||
switch( j->action() )
|
||||
{
|
||||
case SessionAccept:
|
||||
m_state = Active;
|
||||
m_responder = j->responder();
|
||||
break;
|
||||
case SessionInitiate:
|
||||
m_state = Pending;
|
||||
m_initiator = j->initiator();
|
||||
if( !m_responder )
|
||||
m_responder = m_parent->jid();
|
||||
break;
|
||||
case SessionTerminate:
|
||||
m_state = Ended;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
IQ re( IQ::Result, iq.from(), iq.id() );
|
||||
m_parent->send( re );
|
||||
|
||||
m_handler->handleSessionAction( j->action(), this, j );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Session::handleIqID( const IQ& iq, int context )
|
||||
{
|
||||
if( iq.subtype() == IQ::Error )
|
||||
{
|
||||
|
||||
const Error* e = iq.findExtension<Error>( ExtError );
|
||||
m_handler->handleSessionActionError( (Action)context, this, e );
|
||||
|
||||
switch( context )
|
||||
{
|
||||
case ContentAccept:
|
||||
break;
|
||||
case ContentAdd:
|
||||
break;
|
||||
case ContentModify:
|
||||
break;
|
||||
case ContentReject:
|
||||
break;
|
||||
case ContentRemove:
|
||||
break;
|
||||
case DescriptionInfo:
|
||||
break;
|
||||
case SessionAccept:
|
||||
break;
|
||||
case SessionInfo:
|
||||
break;
|
||||
case SessionInitiate:
|
||||
m_state = Ended;
|
||||
break;
|
||||
case SessionTerminate:
|
||||
break;
|
||||
case TransportAccept:
|
||||
break;
|
||||
case TransportInfo:
|
||||
break;
|
||||
case TransportReject:
|
||||
break;
|
||||
case TransportReplace:
|
||||
break;
|
||||
case InvalidAction:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,575 @@
|
|||
/*
|
||||
Copyright (c) 2007-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JINGLESESSION_H__
|
||||
#define JINGLESESSION_H__
|
||||
|
||||
#include "stanzaextension.h"
|
||||
#include "tag.h"
|
||||
#include "iqhandler.h"
|
||||
#include "jingleplugin.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class ClientBase;
|
||||
|
||||
/**
|
||||
* @brief The namespace containing Jingle-related (@xep{0166} et. al.) classes.
|
||||
*
|
||||
* See @link gloox::Jingle::SessionManager SessionManager @endlink for more information
|
||||
* about Jingle in gloox.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
class Description;
|
||||
class Transport;
|
||||
class SessionHandler;
|
||||
class Content;
|
||||
|
||||
/**
|
||||
* Jingle Session actions.
|
||||
*/
|
||||
enum Action
|
||||
{
|
||||
ContentAccept, /**< Accept a content-add action received from another party. */
|
||||
ContentAdd, /**< Add one or more new content definitions to the session. */
|
||||
ContentModify, /**< Change the directionality of media sending. */
|
||||
ContentReject, /**< Reject a content-add action received from another party. */
|
||||
ContentRemove, /**< Remove one or more content definitions from the session. */
|
||||
DescriptionInfo, /**< Exchange information about parameters for an application type. */
|
||||
SecurityInfo, /**< Send information related to establishment or maintenance of security preconditions. */
|
||||
SessionAccept, /**< Definitively accept a session negotiation. */
|
||||
SessionInfo, /**< Send session-level information, such as a ping or a ringing message. */
|
||||
SessionInitiate, /**< Request negotiation of a new Jingle session. */
|
||||
SessionTerminate, /**< End an existing session. */
|
||||
TransportAccept, /**< Accept a transport-replace action received from another party. */
|
||||
TransportInfo, /**< Exchange transport candidates. */
|
||||
TransportReject, /**< Reject a transport-replace action received from another party. */
|
||||
TransportReplace, /**< Redefine a transport method or replace it with a different method. */
|
||||
InvalidAction /**< Invalid action. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a Jingle Session (@xep{0166}).
|
||||
*
|
||||
* See @link gloox::Jingle::SessionManager Jingle::SessionManager @endlink for info on how to use
|
||||
* Jingle in gloox.
|
||||
*
|
||||
* XEP Version: 1.1
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class GLOOX_API Session : public IqHandler
|
||||
{
|
||||
|
||||
friend class SessionManager;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Session state.
|
||||
*/
|
||||
enum State
|
||||
{
|
||||
Ended, /**< The session has ended or was not active yet. */
|
||||
Pending, /**< The session has been initiated but has not yet been accepted by the remote party. */
|
||||
Active /**< The session is active. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a Jingle (@xep{0166}) session terminate reason.
|
||||
*
|
||||
* XEP Version: 1.1
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class GLOOX_API Reason : public Plugin
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Defined reasons for terminating a Jingle Session.
|
||||
*/
|
||||
enum Reasons
|
||||
{
|
||||
AlternativeSession, /**< An alternative session exists that should be used. */
|
||||
Busy, /**< The terminating party is busy. */
|
||||
Cancel, /**< The session has been canceled. */
|
||||
ConnectivityError, /**< Connectivity error. */
|
||||
Decline, /**< The terminating party formally declines the request. */
|
||||
Expired, /**< The session has expired. */
|
||||
FailedApplication, /**< Application type setup failed. */
|
||||
FailedTransport, /**< Transport setup has failed. */
|
||||
GeneralError, /**< General error. */
|
||||
Gone, /**< Participant went away. */
|
||||
IncompatibleParameters, /**< Offered or negotiated application type parameters not supported. */
|
||||
MediaError, /**< Media error. */
|
||||
SecurityError, /**< Security error. */
|
||||
Success, /**< Session terminated after successful call. */
|
||||
Timeout, /**< A timeout occured. */
|
||||
UnsupportedApplications, /**< The terminating party does not support any of the offered application formats. */
|
||||
UnsupportedTransports, /**< The terminating party does not support any of the offered transport methods. */
|
||||
InvalidReason /**< Invalid reason. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param reason The reason for the termination of the session.
|
||||
* @param sid An optional session ID (only used if reason is AlternativeSession).
|
||||
* @param text An optional human-readable text explaining the reason for the session termination.
|
||||
*/
|
||||
Reason( Reasons reason, const std::string& sid = EmptyString,
|
||||
const std::string& text = EmptyString );
|
||||
|
||||
/**
|
||||
* Constructs a new element by parsing the given Tag.
|
||||
* @param tag A tag to parse.
|
||||
*/
|
||||
Reason( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Reason();
|
||||
|
||||
/**
|
||||
* Returns the reason for the session termination.
|
||||
* @return The reason for the session termination.
|
||||
*/
|
||||
Reasons reason() const { return m_reason; }
|
||||
|
||||
/**
|
||||
* Returns the session ID of the alternate session, if given (only applicable
|
||||
* if reason() returns AlternativeSession).
|
||||
* @return The session ID of the alternative session, or an empty string.
|
||||
*/
|
||||
const std::string& sid() const { return m_sid; }
|
||||
|
||||
/**
|
||||
* Returns the content of an optional, human-readable
|
||||
* <text> element.
|
||||
* @return An optional text describing the reason for the terminate action.
|
||||
*/
|
||||
const std::string& text() const { return m_text; }
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Plugin* newInstance( const Tag* tag ) const { return new Reason( tag ); }
|
||||
|
||||
// reimplemented from Plugin
|
||||
virtual Plugin* clone() const;
|
||||
|
||||
private:
|
||||
Reasons m_reason;
|
||||
std::string m_sid;
|
||||
std::string m_text;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This is an abstraction of Jingle's (@xep{0166}) <jingle> element as a StanzaExtension.
|
||||
*
|
||||
* XEP Version: 1.1
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class Jingle : public StanzaExtension
|
||||
{
|
||||
|
||||
friend class Session;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a new object from the given Tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
Jingle( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~Jingle();
|
||||
|
||||
/**
|
||||
* Returns the session ID.
|
||||
* @return The session ID.
|
||||
*/
|
||||
const std::string& sid() const { return m_sid; }
|
||||
|
||||
/**
|
||||
* Returns the 'session initiator'. This will usually be empty for any action other than 'session-initiate'.
|
||||
* @return The 'session initiator'.
|
||||
*/
|
||||
const JID& initiator() const { return m_initiator; }
|
||||
|
||||
/**
|
||||
* Returns the 'session responder'. This will usually be empty for any action other than 'session-accept'.
|
||||
* @return The 'session responder'.
|
||||
*/
|
||||
const JID& responder() const { return m_responder; }
|
||||
|
||||
/**
|
||||
* Returns this Jingle's action.
|
||||
* @return The action.
|
||||
*/
|
||||
Action action() const { return m_action; }
|
||||
|
||||
/**
|
||||
* Adds a Plugin as child.
|
||||
* @param plugin A plugin to be embedded. Will be owned by this instance and deleted in the destructor.
|
||||
*/
|
||||
void addPlugin( const Plugin* plugin ) { if( plugin ) m_plugins.push_back( plugin ); }
|
||||
|
||||
/**
|
||||
* Returns a reference to a list of embedded plugins.
|
||||
* @return A reference to a list of embedded plugins.
|
||||
*/
|
||||
const PluginList& plugins() const { return m_plugins; }
|
||||
|
||||
/**
|
||||
* Returns the tag to build plugins from.
|
||||
* @return The tag to build plugins from.
|
||||
*/
|
||||
Tag* embeddedTag() const { return m_tag; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Jingle( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const;
|
||||
|
||||
#ifdef JINGLE_TEST
|
||||
public:
|
||||
#else
|
||||
private:
|
||||
#endif
|
||||
/**
|
||||
* Constructs a new object and fills it according to the parameters.
|
||||
* @param action The Action to carry out.
|
||||
* @param initiator The full JID of the initiator of the session flow. Will only be used for the SessionInitiate action.
|
||||
* @param responder The full JID of the responder. Will only be used for the SessionAccept action.
|
||||
* @param plugins A list of contents (plugins) for the <jingle>
|
||||
* element. Usually, these will be Content objects, but can be any Plugin-derived objects.
|
||||
* These objects will be owned and deleted by this Jingle instance.
|
||||
* @param sid The session ID:
|
||||
*/
|
||||
Jingle( Action action, const JID& initiator, const JID& responder,
|
||||
const PluginList& plugins, const std::string& sid );
|
||||
|
||||
#ifdef JINGLE_TEST
|
||||
/**
|
||||
* Constructs a new object and fills it according to the parameters.
|
||||
* @param action The Action to carry out.
|
||||
* @param initiator The full JID of the initiator of the session flow. Will only be used for the SessionInitiate action.
|
||||
* @param responder The full JID of the responder. Will only be used for the SessionAccept action.
|
||||
* @param plugin A single content (plugin) for the <jingle>
|
||||
* element. Usually, this will be a Content object, but can be any Plugin-derived object.
|
||||
* This object will be owned and deleted by this Jingle instance.
|
||||
* @param sid The session ID:
|
||||
*/
|
||||
Jingle( Action action, const JID& initiator, const JID& responder,
|
||||
const Plugin* plugin, const std::string& sid );
|
||||
#endif
|
||||
|
||||
// /**
|
||||
// * Copy constructor.
|
||||
// * @param right The instance to copy.
|
||||
// */
|
||||
// Jingle( const Jingle& right );
|
||||
|
||||
Action m_action;
|
||||
std::string m_sid;
|
||||
JID m_initiator;
|
||||
JID m_responder;
|
||||
PluginList m_plugins;
|
||||
Tag* m_tag;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~Session();
|
||||
|
||||
/**
|
||||
* Explicitely sets a new session initiator. The initiator defaults to the initiating entity's JID.
|
||||
* Normally, you should not need to use this function.
|
||||
* @param initiator The new initiator.
|
||||
*/
|
||||
void setInitiator( const JID& initiator ) { m_initiator = initiator; }
|
||||
|
||||
/**
|
||||
* Returns the session's initiator.
|
||||
* @return The session's initiator.
|
||||
*/
|
||||
const JID& initiator() const { return m_initiator; }
|
||||
|
||||
/**
|
||||
* Returns the session's responder. This will only return something useful after the 'session-accept' action has been
|
||||
* sent/received.
|
||||
* @return The session's responder.
|
||||
*/
|
||||
const JID& responder() const { return m_responder; }
|
||||
|
||||
/**
|
||||
* Explicitely sets the 'session responder'. By default, the associated ClientBase's jid() will be used.
|
||||
* You can change this here.
|
||||
* @note Changing the session responder only affects the 'session-accept' action; it will have no effect after
|
||||
* that action has been executed or if the local entity is the session initiator.
|
||||
* @param jid The session responder's full JID.
|
||||
*/
|
||||
void setResponder( const JID& jid ) { m_responder = jid; }
|
||||
|
||||
/**
|
||||
* Explicitely sets a new handler for the session.
|
||||
* @param handler The new handler.
|
||||
*/
|
||||
void setHandler( SessionHandler* handler ) { m_handler = handler; }
|
||||
|
||||
/**
|
||||
* Sends a 'content-accept' notification.
|
||||
* @param content The accepted content.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool contentAccept( const Content* content );
|
||||
|
||||
/**
|
||||
* Sends a 'content-add' request.
|
||||
* @param content The proposed content to be added.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool contentAdd( const Content* content );
|
||||
|
||||
/**
|
||||
* Sends a 'content-add' request.
|
||||
* @param contents A list of proposed content to be added.
|
||||
* These objects will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool contentAdd( const PluginList& contents );
|
||||
|
||||
/**
|
||||
* Sends a 'content-modify' request.
|
||||
* @param content The proposed content type to be modified.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool contentModify( const Content* content );
|
||||
|
||||
/**
|
||||
* Sends a 'content-reject' reply.
|
||||
* @param content The rejected content.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool contentReject( const Content* content );
|
||||
|
||||
/**
|
||||
* Sends a 'content-remove' request.
|
||||
* @param content The content type to be removed.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool contentRemove( const Content* content );
|
||||
|
||||
/**
|
||||
* Sends a 'description-info' notice.
|
||||
* @param info The payload.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool descriptionInfo( const Plugin* info );
|
||||
|
||||
/**
|
||||
* Sends a 'security-info' notice.
|
||||
* @param info A security pre-condition.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool securityInfo( const Plugin* info );
|
||||
|
||||
/**
|
||||
* Accepts an incoming session with the given content.
|
||||
* @param content A pair of application description and transport method wrapped in a Content that describes
|
||||
* the accepted session parameters.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool sessionAccept( const Content* content );
|
||||
|
||||
/**
|
||||
* Accepts an incoming session with the given list of contents.
|
||||
* @param content A list of Content objects that describe the accepted session parameters.
|
||||
* These objects will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool sessionAccept( const PluginList& plugins );
|
||||
|
||||
/**
|
||||
* Sends a 'session-info' notice.
|
||||
* @param info The payload.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool sessionInfo( const Plugin* info );
|
||||
|
||||
/**
|
||||
* Initiates a session with a remote entity.
|
||||
* @param content A Content object. You may use initiate( const PluginList& contents ) for more than one Content.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool sessionInitiate( const Content* content );
|
||||
|
||||
/**
|
||||
* Initiates a session with a remote entity.
|
||||
* @param plugins A list of Content objects. It is important to pass a (list of) Content objects here.
|
||||
* Even though e.g. Jingle::ICEUDP are Plugin-derived, too, using anything other than Content here will result
|
||||
* in erroneous behaviour at best. You may use sessionInitiate( const Content* content ) for just one Content.
|
||||
* These objects will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool sessionInitiate( const PluginList& plugins );
|
||||
|
||||
/**
|
||||
* Terminates the current session, if it is at least in Pending state, with the given reason. The sid parameter
|
||||
* is ignored unless the reason is AlternativeSession.
|
||||
* @param reason The reason for terminating the session.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool sessionTerminate( Session::Reason* reason );
|
||||
|
||||
/**
|
||||
* Sends a 'transport-accept' reply.
|
||||
* @param content The accepted transport wrapped in a Content.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool transportAccept( const Content* content );
|
||||
|
||||
/**
|
||||
* Sends a 'transport-info' notice.
|
||||
* @param info The payload.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool transportInfo( const Plugin* info );
|
||||
|
||||
/**
|
||||
* Sends a 'transport-reject' reply.
|
||||
* @param content The rejected transport wrapped in a Content.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool transportReject( const Content* content );
|
||||
|
||||
/**
|
||||
* Sends a 'transport-replace' request.
|
||||
* @param content The proposed transport to be replaced wrapped in a Content.
|
||||
* This object will be owned and deleted by this Session instance.
|
||||
* @return @b False if a prerequisite is not met, @b true otherwise.
|
||||
*/
|
||||
bool transportReplace( const Content* content );
|
||||
|
||||
/**
|
||||
* Returns the session's state.
|
||||
* @return The session's state.
|
||||
*/
|
||||
State state() const { return m_state; }
|
||||
|
||||
/**
|
||||
* Sets the session's ID. This will be initialized to a random value (or taken from an incoming session request)
|
||||
* by default. You should not need to set the session ID manually.
|
||||
* @param sid The session's id.
|
||||
*/
|
||||
void setSID( const std::string& sid ) { m_sid = sid; }
|
||||
|
||||
/**
|
||||
* Returns the session's ID.
|
||||
* @return The session's ID.
|
||||
*/
|
||||
const std::string& sid() const { return m_sid; }
|
||||
|
||||
// reimplemented from IqHandler
|
||||
virtual bool handleIq( const IQ& iq );
|
||||
|
||||
// reimplemented from IqHandler
|
||||
virtual void handleIqID( const IQ& iq, int context );
|
||||
|
||||
#ifdef JINGLE_TEST
|
||||
public:
|
||||
#else
|
||||
private:
|
||||
#endif
|
||||
/**
|
||||
* Creates a new Jingle Session.
|
||||
* @param parent The ClientBase to use for communication.
|
||||
* @param callee The remote end of the session.
|
||||
* @param jsh The handler to receive events and results.
|
||||
*/
|
||||
Session( ClientBase* parent, const JID& callee, SessionHandler* jsh );
|
||||
|
||||
/**
|
||||
* Creates a new Session from the incoming Jingle object.
|
||||
* This is a NOOP for Jingles that have an action() different from SessionInitiate.
|
||||
* @param parent The ClientBase to use for communication.
|
||||
* @param callee The remote entity.
|
||||
* @param jingle The Jingle object to init the Session from.
|
||||
* @param jsh The handler to receive events and results.
|
||||
*/
|
||||
Session( ClientBase* parent, const JID& callee, const Session::Jingle* jingle,
|
||||
SessionHandler* jsh );
|
||||
|
||||
bool doAction( Action action, const Plugin* plugin );
|
||||
bool doAction( Action action, const PluginList& plugin );
|
||||
|
||||
ClientBase* m_parent;
|
||||
State m_state;
|
||||
JID m_remote;
|
||||
JID m_initiator;
|
||||
JID m_responder;
|
||||
SessionHandler* m_handler;
|
||||
std::string m_sid;
|
||||
bool m_valid;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // JINGLESESSION_H__
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
Copyright (c) 2008-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JINGLESESSIONHANDLER_H__
|
||||
#define JINGLESESSIONHANDLER_H__
|
||||
|
||||
#include "macros.h"
|
||||
#include "jinglesession.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A Jingle session handler.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class GLOOX_API SessionHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~SessionHandler() {}
|
||||
|
||||
/**
|
||||
* This function is called when the remote party requests an action to be taken.
|
||||
* @param action The requested action. A convenience parameter, identical to jingle->action().
|
||||
* @param session The affected session.
|
||||
* @param jingle The complete Jingle.
|
||||
* @note Note that an action can cause a session state change. You may check using session->state().
|
||||
* @note Also note that you have to reply to most actions, usually with the *Accept or *Reject counterpart,
|
||||
* using the similarly-named functions that Session offers.
|
||||
*/
|
||||
virtual void handleSessionAction( Action action, Session* session, const Session::Jingle* jingle ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called when a request to a remote entity returns an error.
|
||||
* @param action The Action that failed.
|
||||
* @param session The affected session.
|
||||
* @param error The error. May be 0 in special cases.
|
||||
* @note Note that an action can cause a session state change. You may check using session->state().
|
||||
*/
|
||||
virtual void handleSessionActionError( Action action, Session* session, const Error* error ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called if a remote entity wants to establish a Jingle session.
|
||||
* @param session The new Jingle session.
|
||||
* @note Note that you have to explicitely accept or reject the session by calling either of session->sessionAccept() and
|
||||
* session->sessionTerminate(), respectively.
|
||||
*/
|
||||
virtual void handleIncomingSession( Session* session ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // JINGLESESSIONHANDLER_H__
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#include "jinglesessionmanager.h"
|
||||
|
||||
#include "clientbase.h"
|
||||
#include "jinglesession.h"
|
||||
#include "jinglesessionhandler.h"
|
||||
#include "disco.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
SessionManager::SessionManager( ClientBase* parent, SessionHandler* sh )
|
||||
: m_parent( parent ), m_handler( sh )
|
||||
{
|
||||
if( m_parent )
|
||||
{
|
||||
m_parent->registerStanzaExtension( new Session::Jingle() );
|
||||
m_parent->registerIqHandler( this, ExtJingle );
|
||||
m_parent->disco()->addFeature( XMLNS_JINGLE );
|
||||
}
|
||||
}
|
||||
|
||||
SessionManager::~SessionManager()
|
||||
{
|
||||
util::clearList( m_sessions );
|
||||
}
|
||||
|
||||
void SessionManager::registerPlugin( Plugin* plugin )
|
||||
{
|
||||
if( !plugin )
|
||||
return;
|
||||
|
||||
m_factory.registerPlugin( plugin );
|
||||
if( m_parent )
|
||||
{
|
||||
StringList features = plugin->features();
|
||||
StringList::const_iterator it = features.begin();
|
||||
for( ; it != features.end(); ++it )
|
||||
m_parent->disco()->addFeature( (*it) );
|
||||
}
|
||||
}
|
||||
|
||||
Session* SessionManager::createSession( const JID& callee, SessionHandler* handler )
|
||||
{
|
||||
if( !( handler || m_handler ) || !callee )
|
||||
return 0;
|
||||
|
||||
Session* sess = new Session( m_parent, callee, handler ? handler : m_handler );
|
||||
m_sessions.push_back( sess );
|
||||
return sess;
|
||||
}
|
||||
|
||||
void SessionManager::discardSession( Session* session )
|
||||
{
|
||||
if( !session )
|
||||
return;
|
||||
|
||||
m_sessions.remove( session );
|
||||
delete session;
|
||||
}
|
||||
|
||||
bool SessionManager::handleIq( const IQ& iq )
|
||||
{
|
||||
const Session::Jingle* j = iq.findExtension<Session::Jingle>( ExtJingle );
|
||||
if( !j )
|
||||
return false;
|
||||
|
||||
m_factory.addPlugins( const_cast<Session::Jingle&>( *j ), j->embeddedTag() );
|
||||
|
||||
SessionList::iterator it = m_sessions.begin();
|
||||
for( ; it != m_sessions.end() && (*it)->sid() != j->sid(); ++it ) ;
|
||||
if( it == m_sessions.end() )
|
||||
{
|
||||
Session* s = new Session( m_parent, iq.from(), j, m_handler );
|
||||
m_sessions.push_back( s );
|
||||
m_handler->handleIncomingSession( s );
|
||||
s->handleIq( iq );
|
||||
}
|
||||
else
|
||||
{
|
||||
(*it)->handleIq( iq );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright (c) 2013-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef JINGLESESSIONMANAGER_H__
|
||||
#define JINGLESESSIONMANAGER_H__
|
||||
|
||||
#include "macros.h"
|
||||
#include "iqhandler.h"
|
||||
#include "jinglepluginfactory.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class ClientBase;
|
||||
|
||||
namespace Jingle
|
||||
{
|
||||
|
||||
class Session;
|
||||
class SessionHandler;
|
||||
|
||||
/**
|
||||
* @brief The SessionManager is responsible for creating and destroying Jingle sessions, as well as for delegating incoming
|
||||
* IQs to their respective sessions. This is part of Jingle (@xep{0166}).
|
||||
*
|
||||
* @note The classes in the Jingle namespace implement the signaling part of Jingle only.
|
||||
* Establishing connections to a remote entity or transfering data outside the XMPP channel
|
||||
* is out of scope of gloox.
|
||||
*
|
||||
* To use Jingle with gloox you should first instantiate a Jingle::SessionManager. The SessionManager will
|
||||
* let you create new Jingle sessions and notify the respective handler about incoming Jingle session requests.
|
||||
* It will also announce generic Jingle support via Disco. You have to register any
|
||||
* @link gloox::Jingle::Plugin Jingle plugins @endlink you want to use using registerPlugin().
|
||||
* These will automatically announce any additional features via Disco.
|
||||
*
|
||||
* Use createSession() to create a new Session.
|
||||
*
|
||||
* Implement SessionHandler::handleIncomingSession() to receive incoming session requests.
|
||||
*
|
||||
* Use discardSession() to get rid of a session. Do not delete a session manually.
|
||||
*
|
||||
* There is no limit to the number of concurrent sessions.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.5
|
||||
*/
|
||||
class GLOOX_API SessionManager : public IqHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates new instance. There should be only one SessionManager per ClientBase.
|
||||
* @param parent A ClientBase instance used for sending and receiving.
|
||||
* @param sh A session handler that will be notified about incoming session requests.
|
||||
* Only handleIncomingSession() will be called in that handler.
|
||||
*/
|
||||
SessionManager( ClientBase* parent, SessionHandler* sh );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~SessionManager();
|
||||
|
||||
/**
|
||||
* Registers an empty Plugin as a template with the manager.
|
||||
* @param plugin The plugin to register.
|
||||
*/
|
||||
void registerPlugin( Plugin* plugin );
|
||||
|
||||
/**
|
||||
* Lets you create a new Jingle session.
|
||||
* @param callee The remote entity's JID.
|
||||
* @param handler The handler responsible for handling events assicoated with the new session.
|
||||
* @return The new session.
|
||||
* @note You should not delete a session yourself. Instead, pass it to discardSession().
|
||||
*/
|
||||
Session* createSession( const JID& callee, SessionHandler* handler );
|
||||
|
||||
/**
|
||||
* Removes a given session from the nternal queue and deletes it.
|
||||
* @param session The session to delete.
|
||||
*/
|
||||
void discardSession( Session* session );
|
||||
|
||||
|
||||
// reimplemented from IqHandler
|
||||
virtual bool handleIq( const IQ& iq );
|
||||
|
||||
// reimplemented from IqHandler
|
||||
virtual void handleIqID( const IQ& /*iq*/, int /*context*/ ) {}
|
||||
|
||||
private:
|
||||
typedef std::list<Jingle::Session*> SessionList;
|
||||
|
||||
SessionList m_sessions;
|
||||
ClientBase* m_parent;
|
||||
SessionHandler* m_handler;
|
||||
PluginFactory m_factory;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // JINGLESESSIONMANAGER_H__
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Copyright (c) 2012-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
#ifndef LINKLOCAL_H__
|
||||
#define LINKLOCAL_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_MDNS
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Namespace holding all the Link-local-related structures and definitions.
|
||||
*
|
||||
* See @ref gloox::LinkLocal::Manager for more information on how to implement
|
||||
* link-local messaging.
|
||||
*/
|
||||
namespace LinkLocal
|
||||
{
|
||||
|
||||
class Client;
|
||||
|
||||
/**
|
||||
* Used in conjunction with Service to indicate whether a service has been added (newly advertised) or removed.
|
||||
*/
|
||||
enum Flag
|
||||
{
|
||||
AddService, /**< A service has been added. */
|
||||
RemoveService /**< A service has been removed. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An abstraction of the parameters of a single link-local service.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.x
|
||||
*/
|
||||
struct Service
|
||||
{
|
||||
friend class Manager;
|
||||
|
||||
private:
|
||||
Service( Flag _flag, const std::string& _service, const std::string& _regtype, const std::string& _domain, int _interface )
|
||||
: flag( _flag ), service( _service ), regtype( _regtype ), domain( _domain ), iface( _interface ) {}
|
||||
|
||||
public:
|
||||
Flag flag;
|
||||
std::string service;
|
||||
std::string regtype;
|
||||
std::string domain;
|
||||
int iface;
|
||||
};
|
||||
|
||||
/**
|
||||
* A list of services.
|
||||
*/
|
||||
typedef std::list<Service> ServiceList;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_MDNS
|
||||
|
||||
#endif // LINKLOCAL_H__
|
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
Copyright (c) 2012-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
#include "linklocalclient.h"
|
||||
|
||||
#ifdef HAVE_MDNS
|
||||
|
||||
#include "gloox.h"
|
||||
#include "tag.h"
|
||||
#include "util.h"
|
||||
#include "connectiontcpclient.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
# include <winsock.h>
|
||||
#elif defined( _WIN32_WCE )
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace LinkLocal
|
||||
{
|
||||
|
||||
Client::Client( const JID& jid )
|
||||
: gloox::Client( jid, EmptyString ), m_qRef( 0 ), m_rRef( 0 ), m_currentRef( 0 ),
|
||||
m_interface( 0 ), m_port( 0 ), m_streamSent( false )
|
||||
{
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
}
|
||||
|
||||
bool Client::connect()
|
||||
{
|
||||
return ClientBase::connect( false );
|
||||
}
|
||||
|
||||
bool Client::connect( const std::string& service, const std::string& type,
|
||||
const std::string& domain, int iface )
|
||||
{
|
||||
m_interface = interface;
|
||||
return resolve( service, type, domain );
|
||||
}
|
||||
|
||||
ConnectionError Client::recv( int timeout )
|
||||
{
|
||||
if( m_connection && m_connection->state() == StateConnected )
|
||||
return ClientBase::recv( timeout );
|
||||
else
|
||||
{
|
||||
if( !m_currentRef )
|
||||
return ConnNoError;
|
||||
|
||||
struct timeval tv;
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO( &fds );
|
||||
// the following causes a C4127 warning in VC++ Express 2008 and possibly other versions.
|
||||
// however, the reason for the warning can't be fixed in gloox.
|
||||
FD_SET( DNSServiceRefSockFD( m_currentRef ), &fds );
|
||||
|
||||
tv.tv_sec = timeout / 1000000;
|
||||
tv.tv_usec = timeout % 1000000;
|
||||
|
||||
if( select( FD_SETSIZE, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
|
||||
{
|
||||
if( FD_ISSET( DNSServiceRefSockFD( m_currentRef ), &fds ) != 0 )
|
||||
DNSServiceProcessResult( m_currentRef );
|
||||
}
|
||||
|
||||
return ConnNoError;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Client::resolve( const std::string& service, const std::string& type,
|
||||
const std::string& domain )
|
||||
{
|
||||
m_to = service;
|
||||
m_rRef = 0;
|
||||
DNSServiceErrorType e = DNSServiceResolve( &m_rRef, 0, m_interface, service.c_str(), type.c_str(),
|
||||
domain.c_str(), (DNSServiceResolveReply)&handleResolveReply, this );
|
||||
if( e != kDNSServiceErr_NoError )
|
||||
{
|
||||
DNSServiceRefDeallocate( m_rRef );
|
||||
m_rRef = 0;
|
||||
return false;
|
||||
}
|
||||
m_currentRef = m_rRef;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::handleResolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
|
||||
DNSServiceErrorType errorCode, const char* fullname, const char* hosttarget,
|
||||
uint16_t port, uint16_t txtLen, const unsigned char* txtRecord, void* context )
|
||||
{
|
||||
if( !context || errorCode != kDNSServiceErr_NoError )
|
||||
return;
|
||||
|
||||
// printf("Client::handleResolveReply susccessful, querying %s\n", hosttarget );
|
||||
|
||||
static_cast<Client*>( context )->query( hosttarget, ntohs( port ) );
|
||||
}
|
||||
|
||||
bool Client::query( const std::string& hostname, int port )
|
||||
{
|
||||
m_port = port;
|
||||
m_qRef = 0;
|
||||
DNSServiceErrorType e = DNSServiceQueryRecord( &m_qRef, 0, m_interface, hostname.c_str(), kDNSServiceType_A,
|
||||
kDNSServiceClass_IN, (DNSServiceQueryRecordReply)&handleQueryReply, this );
|
||||
if( e != kDNSServiceErr_NoError )
|
||||
{
|
||||
// printf( "Client::query() failed\n" );
|
||||
DNSServiceRefDeallocate( m_qRef );
|
||||
m_qRef = 0;
|
||||
return false;
|
||||
}
|
||||
m_currentRef = m_qRef;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::handleQueryReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
|
||||
DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype,
|
||||
uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl,
|
||||
void *context )
|
||||
{
|
||||
// printf("Client::handleQueryReply returned\n" );
|
||||
|
||||
if( !context || errorCode != kDNSServiceErr_NoError )
|
||||
return;
|
||||
|
||||
const unsigned char* rd = static_cast<const unsigned char*>( rdata );
|
||||
std::string addr = util::int2string( rd[0] );
|
||||
addr += '.';
|
||||
addr += util::int2string( rd[1] );
|
||||
addr += '.';
|
||||
addr += util::int2string( rd[2] );
|
||||
addr += '.';
|
||||
addr += util::int2string( rd[3] );
|
||||
// printf( "host %s is at %s\n", fullname, addr.c_str() );
|
||||
static_cast<Client*>( context )->handleQuery( addr );
|
||||
}
|
||||
|
||||
void Client::handleQuery( const std::string& addr )
|
||||
{
|
||||
if( m_rRef )
|
||||
{
|
||||
DNSServiceRefDeallocate( m_rRef );
|
||||
m_rRef = 0;
|
||||
}
|
||||
|
||||
ConnectionTCPClient* connection = new ConnectionTCPClient( this, logInstance(), addr, m_port );
|
||||
// printf( "LinkLocal::Client: connecting to %s:%d\n", addr.c_str(), m_port );
|
||||
ConnectionError e = connection->connect();
|
||||
if( e != ConnNoError )
|
||||
{
|
||||
// printf( "connection error: %d\n", e );
|
||||
delete connection;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::handleConnect( const ConnectionBase* connection )
|
||||
{
|
||||
if( m_qRef )
|
||||
{
|
||||
DNSServiceRefDeallocate( m_qRef );
|
||||
m_qRef = 0;
|
||||
m_currentRef = 0;
|
||||
}
|
||||
|
||||
// printf( "LinkLocal::Client::handleConnect()!!!\n" );
|
||||
ConnectionBase* cb = const_cast<ConnectionBase*>( connection );
|
||||
gloox::Client::setConnectionImpl( cb );
|
||||
gloox::Client::connect( false );
|
||||
sendStart( m_to );
|
||||
}
|
||||
|
||||
void Client::handleStartNode( const Tag* start )
|
||||
{
|
||||
// printf( "LinkLocal::Client::handleStartNode()\n" );
|
||||
if( start && !m_streamSent )
|
||||
sendStart( start->findAttribute( "from" ) );
|
||||
}
|
||||
|
||||
void Client::sendStart( const std::string& to )
|
||||
{
|
||||
m_streamSent = true;
|
||||
std::string s = "<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='";
|
||||
s += to;
|
||||
s += "' from='";
|
||||
s += m_jid.full().c_str();
|
||||
s += "' version='1.0'>";
|
||||
send( s );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_MDNS
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright (c) 2012-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LINKLOCALCLIENT_H__
|
||||
#define LINKLOCALCLIENT_H__
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_MDNS
|
||||
|
||||
#include "client.h"
|
||||
#include "jid.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <dns_sd.h>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
namespace LinkLocal
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An implementation of a link-local client.
|
||||
*
|
||||
* See @ref gloox::LinkLocal::Manager for more information on how to implement
|
||||
* link-local messaging.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.x
|
||||
*/
|
||||
class Client : public gloox::Client
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new instance.
|
||||
* @param jid The local JID to use.
|
||||
*/
|
||||
Client( const JID& jid );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Client();
|
||||
|
||||
/**
|
||||
* Internally sets up an already connected connection.
|
||||
* @note Use this function only on a Client instance that you created for an @b incoming connection.
|
||||
*/
|
||||
bool connect();
|
||||
|
||||
/**
|
||||
* Starts resolving the given service. Use values from Handler::handleBrowseReply().
|
||||
* @param service The service to connect to.
|
||||
* @param type The service type.
|
||||
* @param domain The service's domain.
|
||||
* @param interface The network interface the service was found on. May be 0 to try
|
||||
* to resolve the service on all available interfaces.
|
||||
* @return @b True if resolving the service could be started successfully, @b false otherwise.
|
||||
* @note Use this function only for @b outgoing connections.
|
||||
*/
|
||||
bool connect( const std::string& service, const std::string& type, const std::string& domain, int iface = 0 );
|
||||
|
||||
/**
|
||||
* Call this periodically to receive data from the underlying socket.
|
||||
* @param timeout An optional timeout in microseconds. Default of -1 means blocking
|
||||
* until data was available.
|
||||
* @return The state of the underlying connection.
|
||||
*/
|
||||
virtual ConnectionError recv( int timeout = -1 );
|
||||
|
||||
// reimplemented from ConnectionDataHandler, overwriting ClientBase::handleConnect()
|
||||
virtual void handleConnect( const ConnectionBase* connection );
|
||||
|
||||
protected:
|
||||
// reimplemented from ClientBase
|
||||
virtual void handleStartNode( const Tag* start );
|
||||
|
||||
private:
|
||||
static void handleResolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
|
||||
DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget,
|
||||
uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context );
|
||||
static void handleQueryReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
|
||||
DNSServiceErrorType errorCode, const char *fullname, uint16_t rrtype,
|
||||
uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl,
|
||||
void *context );
|
||||
|
||||
bool resolve( const std::string& serviceName, const std::string& regtype, const std::string& replyDomain );
|
||||
bool query( const std::string& hostname, int port );
|
||||
void handleQuery( const std::string& addr );
|
||||
void sendStart( const std::string& to );
|
||||
|
||||
DNSServiceRef m_qRef;
|
||||
DNSServiceRef m_rRef;
|
||||
DNSServiceRef m_currentRef;
|
||||
|
||||
std::string m_to;
|
||||
|
||||
int m_interface;
|
||||
int m_port;
|
||||
|
||||
bool m_streamSent;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_MDNS
|
||||
|
||||
#endif // LINKLOCALCLIENT_H__
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
Copyright (c) 2012-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
#ifndef LINKLOCALHANDLER_H__
|
||||
#define LINKLOCALHANDLER_H__
|
||||
|
||||
#ifdef HAVE_MDNS
|
||||
|
||||
#include "linklocal.h"
|
||||
#include "macros.h"
|
||||
#include "gloox.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace LinkLocal
|
||||
{
|
||||
|
||||
// class Client;
|
||||
|
||||
/**
|
||||
* @brief A base class that gets informed about advertised or removed XMPP services on the local network.
|
||||
*
|
||||
* See @ref gloox::LinkLocal::Manager for more information on how to implement
|
||||
* link-local messaging.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.x
|
||||
*/
|
||||
class GLOOX_API Handler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Reimplement this function to be notified about services available on (or removed from)
|
||||
* the local network.
|
||||
* @param services A list of services.
|
||||
* @note Make a copy of the service list as the list will not be valid after the function
|
||||
* returned.
|
||||
*/
|
||||
virtual void handleBrowseReply( const ServiceList& services ) = 0;
|
||||
|
||||
// /**
|
||||
// *
|
||||
// */
|
||||
// virtual void handleClient( Client* client ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_MDNS
|
||||
|
||||
#endif // LINKLOCALHANDLER_H__
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
Copyright (c) 2012-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
#include "linklocalmanager.h"
|
||||
|
||||
#ifdef HAVE_MDNS
|
||||
|
||||
#include "linklocalhandler.h"
|
||||
#include "connectiontcpclient.h"
|
||||
#include "jid.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
|
||||
# include <unistd.h>
|
||||
# include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
# include <winsock.h>
|
||||
#elif defined( _WIN32_WCE )
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#define LINKLOCAL_SERVICE_PORT 5562
|
||||
|
||||
const std::string LINKLOCAL_SERVICE_TYPE = "_presence._tcp";
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace LinkLocal
|
||||
{
|
||||
|
||||
Manager::Manager( const std::string& user, ConnectionHandler* connHandler, const LogSink &logInstance )
|
||||
: m_publishRef( 0 ), m_browseRef( 0 ), m_user( user ), m_interface( 0 ), m_port( 0 ),
|
||||
m_logInstance( logInstance ), m_browseFd( 0 ), m_server( connHandler, m_logInstance, EmptyString, LINKLOCAL_SERVICE_PORT ),
|
||||
m_linkLocalHandler( 0 ), m_connectionHandler( connHandler )
|
||||
{
|
||||
|
||||
setPort( LINKLOCAL_SERVICE_PORT ); // does more than just setting m_port
|
||||
addTXTData( "node", GLOOX_CAPS_NODE );
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
deregisterService();
|
||||
stopBrowsing();
|
||||
}
|
||||
|
||||
void Manager::addTXTData( const std::string& key, const std::string& value )
|
||||
{
|
||||
if( value.empty() || key.empty() || key == "txtvers" )
|
||||
return;
|
||||
|
||||
m_txtData[key] = value;
|
||||
}
|
||||
|
||||
void Manager::removeTXTData( const std::string& key )
|
||||
{
|
||||
m_txtData.erase( key );
|
||||
}
|
||||
|
||||
void Manager::registerService()
|
||||
{
|
||||
if( m_publishRef )
|
||||
deregisterService();
|
||||
|
||||
m_server.connect();
|
||||
|
||||
std::string txtRecord;
|
||||
txtRecord += (char)9; // length of mandatory txtvers=1
|
||||
txtRecord += "txtvers=1"; // this is here because it SHOULD be the first entry
|
||||
StringMap::const_iterator it = m_txtData.begin();
|
||||
for( ; it != m_txtData.end(); ++it )
|
||||
{
|
||||
txtRecord += (char)( (*it).first.length() + (*it).second.length() + 1 );
|
||||
txtRecord += (*it).first;
|
||||
txtRecord += '=';
|
||||
txtRecord += (*it).second;
|
||||
}
|
||||
|
||||
std::string service = m_user + "@";
|
||||
if( m_host.empty() )
|
||||
{
|
||||
char host[65];
|
||||
gethostname( host, 65 );
|
||||
service += host;
|
||||
}
|
||||
else
|
||||
service += m_host;
|
||||
|
||||
/*DNSServiceErrorType e =*/ DNSServiceRegister( &m_publishRef,
|
||||
0, // flags
|
||||
m_interface, // interface, 0 = any, -1 = local only
|
||||
service.c_str(), // service name, 0 = local computer name
|
||||
LINKLOCAL_SERVICE_TYPE.c_str(), // service type
|
||||
m_domain.c_str(), // domain, 0 = default domain(s)
|
||||
m_host.c_str(), // host, 0 = default host name(s)
|
||||
htons( m_port ), // port
|
||||
(short unsigned int)txtRecord.length(), // TXT record length
|
||||
(const void*)txtRecord.c_str(), // TXT record
|
||||
0, // callback
|
||||
0 ); // context
|
||||
}
|
||||
|
||||
void Manager::deregisterService()
|
||||
{
|
||||
if( m_publishRef )
|
||||
{
|
||||
DNSServiceRefDeallocate( m_publishRef );
|
||||
m_publishRef = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Manager::startBrowsing()
|
||||
{
|
||||
if( !m_linkLocalHandler )
|
||||
return false;
|
||||
|
||||
if( m_browseRef )
|
||||
stopBrowsing();
|
||||
|
||||
DNSServiceErrorType e = DNSServiceBrowse( &m_browseRef,
|
||||
0, // flags, currently ignored
|
||||
m_interface, // interface, 0 = any, -1 = local only
|
||||
LINKLOCAL_SERVICE_TYPE.c_str(), // service type
|
||||
m_domain.c_str(), // domain, 0 = default domain(s)
|
||||
&handleBrowseReply, // callback
|
||||
this ); // context
|
||||
if ( e != kDNSServiceErr_NoError )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Manager::stopBrowsing()
|
||||
{
|
||||
if( m_browseRef )
|
||||
{
|
||||
DNSServiceRefDeallocate( m_browseRef );
|
||||
m_browseRef = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::recv( int timeout )
|
||||
{
|
||||
if( !m_browseRef )
|
||||
return;
|
||||
|
||||
struct timeval tv;
|
||||
|
||||
fd_set fds;
|
||||
FD_ZERO( &fds );
|
||||
// the following causes a C4127 warning in VC++ Express 2008 and possibly other versions.
|
||||
// however, the reason for the warning can't be fixed in gloox.
|
||||
FD_SET( DNSServiceRefSockFD( m_browseRef ), &fds );
|
||||
|
||||
tv.tv_sec = timeout / 1000000;
|
||||
tv.tv_usec = timeout % 1000000;
|
||||
|
||||
if( select( FD_SETSIZE, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
|
||||
{
|
||||
if( FD_ISSET( DNSServiceRefSockFD( m_browseRef ), &fds ) != 0 )
|
||||
DNSServiceProcessResult( m_browseRef );
|
||||
}
|
||||
|
||||
m_server.recv( timeout );
|
||||
}
|
||||
|
||||
|
||||
void Manager::handleBrowseReply( DNSServiceRef /*sdRef*/, DNSServiceFlags flags, uint32_t interfaceIndex,
|
||||
DNSServiceErrorType errorCode, const char* serviceName, const char* regtype,
|
||||
const char* replyDomain, void* context )
|
||||
{
|
||||
if( !context || errorCode != kDNSServiceErr_NoError )
|
||||
return;
|
||||
|
||||
Flag f = ( flags & kDNSServiceFlagsAdd ) == kDNSServiceFlagsAdd
|
||||
? AddService
|
||||
: RemoveService;
|
||||
|
||||
Manager* m = static_cast<Manager*>( context );
|
||||
m->handleBrowse( f, serviceName, regtype, replyDomain, interfaceIndex, ( flags & kDNSServiceFlagsMoreComing ) == kDNSServiceFlagsMoreComing );
|
||||
|
||||
}
|
||||
|
||||
void Manager::handleBrowse( Flag flag, const std::string& service, const std::string& regtype, const std::string& domain, int iface, bool moreComing )
|
||||
{
|
||||
Service s( flag, service, regtype, domain, interface );
|
||||
m_tmpServices.push_back( s );
|
||||
|
||||
// switch( flag )
|
||||
// {
|
||||
// case AddService:
|
||||
// {
|
||||
// m_services.push_back( s );
|
||||
// break;
|
||||
// }
|
||||
// case RemoveService:
|
||||
// {
|
||||
// ServiceList::iterator it = m_services.begin();
|
||||
// for( ; it != m_services.end(); ++it )
|
||||
// {
|
||||
// if( (*it)->service == service && (*it)->regtype == regtype && (*it)->domain == domain )
|
||||
// {
|
||||
// m_services.erase( it );
|
||||
// }
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
if( !moreComing )
|
||||
{
|
||||
m_linkLocalHandler->handleBrowseReply( m_tmpServices );
|
||||
m_tmpServices.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// const StringMap Manager::decodeTXT( const std::string& txt )
|
||||
// {
|
||||
// StringMap result;
|
||||
// if( txt.empty() )
|
||||
// return result;
|
||||
//
|
||||
// std::string::const_iterator it = txt.begin();
|
||||
// while( it < txt.end() )
|
||||
// {
|
||||
// int len = (int)(*it);
|
||||
// std::string tmp( ++it, it + len + 1 );
|
||||
// it += len;
|
||||
// size_t pos = tmp.find( '=' );
|
||||
// result.insert( std::make_pair( tmp.substr( 0, pos ), tmp.substr( pos + 1 ) ) );
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_MDNS
|
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
Copyright (c) 2012-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
#ifndef LINKLOCALMANAGER_H___
|
||||
#define LINKLOCALMANAGER_H___
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_MDNS
|
||||
|
||||
#include "linklocal.h"
|
||||
#include "macros.h"
|
||||
#include "gloox.h"
|
||||
#include "util.h"
|
||||
#include "logsink.h"
|
||||
#include "connectiontcpserver.h"
|
||||
#include "mutex.h"
|
||||
#include "jid.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <dns_sd.h>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class ConnectionHandler;
|
||||
class ConnectionTCPClient;
|
||||
|
||||
namespace LinkLocal
|
||||
{
|
||||
|
||||
class Handler;
|
||||
|
||||
/**
|
||||
* @brief This is a manager for server-less messaging (@xep{0174}).
|
||||
*
|
||||
* Enable compilation of this code with the @c \-\-enable-mdns switch to @c configure, or add
|
||||
* @c \#define @c HAVE_MDNS to your platform's @c config.h. @c dns_sd.h, @c libdns_sd.so, as well
|
||||
* as the @c mdnsd daemon from Apple's bonjour distribution are required. The @c mdnsd daemon has
|
||||
* to be running on the local host.
|
||||
*
|
||||
* ### Browsing the local network for XMPP services
|
||||
*
|
||||
* You can use the Manager to browse the local network for XMPP services.
|
||||
* First, create a new instance, register a LinkLocal::Handler, and call startBrowsing().
|
||||
* @code
|
||||
* m_mdns = new LinkLocal::Manager( ... );
|
||||
* m_mdns->registerLinkLocalHandler( yourHandler );
|
||||
* m_mdns->startBrowsing();
|
||||
* @endcode
|
||||
*
|
||||
* Then you will need to call @c recv() periodcally. The handler will then receive lists of available
|
||||
* or removed services. Check the @c flag member of the Service struct.
|
||||
*
|
||||
* @code
|
||||
* void MyClass::handleBrowseReply( const Service& service )
|
||||
* {
|
||||
* LinkLocal::ServiceList::const_iterator it = services.begin();
|
||||
* for( ; it != services.end(); ++it )
|
||||
* {
|
||||
* if( (*it).flag == LinkLocal::AddService )
|
||||
* {
|
||||
* // new service
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // service removed
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @note Note that your own service may show up in the list, too.
|
||||
*
|
||||
* ### Connecting to an XMPP service
|
||||
*
|
||||
* Using the info from the Service struct you can initiate a connection to the remote entity.
|
||||
* First, create a new instance of LinkLocal::Client and register some basic handlers like you
|
||||
* would with a normal gloox::Client:
|
||||
*
|
||||
* @code
|
||||
* LinkLocal::Client c( JID( "romeo@montague.net" ) );
|
||||
* c.logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this ); // optional
|
||||
* c.registerConnectionListener( yourConnectionListener );
|
||||
* @endcode
|
||||
*
|
||||
* Then call @link gloox::LinkLocal::Client::connect( const std::string&, const std::string&, const std::string&, int ) connect() @endlink
|
||||
* and pass the paramters from the Service struct that you received in handleBrowseReply().
|
||||
*
|
||||
* @code
|
||||
* c.connect( "juliet@laptop", "_presence._tcp", ".local", 4 ); // don't use literal values
|
||||
* @endcode
|
||||
*
|
||||
* Put your LinkLocal::Client instance in your event loop (or in a separate thread) and call
|
||||
* @link gloox::LinkLocal::Client::recv() recv() @endlink periodically.
|
||||
*
|
||||
* ### Advertising an XMPP service on the local network
|
||||
*
|
||||
* To advertise your own XMPP service you can (re-)use the same Manager instance from 'browsing the local network'
|
||||
* above.
|
||||
*
|
||||
* You can publish some basic info about your service in a DNS TXT record. The Manager offers the addTXTData() function
|
||||
* for that. See http://xmpp.org/registrar/linklocal.html for a list of official parameters.
|
||||
*
|
||||
* @code
|
||||
* m_mdns->addTXTData("nick","July");
|
||||
* m_mdns->addTXTData("1st","Juliet");
|
||||
* m_mdns->addTXTData("last","Capulet");
|
||||
* m_mdns->addTXTData("msg","Hanging out");
|
||||
* m_mdns->addTXTData("jid","julia@capulet.com");
|
||||
* m_mdns->addTXTData("status","avail");
|
||||
* @endcode
|
||||
*
|
||||
* Then, to start publishing the availability of your service as well as the TXT record with the additional info
|
||||
* you just call @c registerService().
|
||||
*
|
||||
* @code
|
||||
* m_mdns->registerService();
|
||||
* @endcode
|
||||
*
|
||||
* Other entities on the network will now be informed about the availability of your service.
|
||||
*
|
||||
* ### Listening for incoming connections
|
||||
*
|
||||
* The second argument to Manager's constructor is a ConnectionHandler-derived class that
|
||||
* will receive incoming connections.
|
||||
*
|
||||
* When registerService() gets called, the Manager will also start a local server that will
|
||||
* accept incoming connections. By default, it will listen on port 5562.
|
||||
*
|
||||
* In @link gloox::ConnectionHandler::handleIncomingConnection() handleIncomingConnection() @endlink
|
||||
* you should create a new LinkLocal::Client and register some basic handlers:
|
||||
*
|
||||
* @code
|
||||
* LinkLocal::Client c( JID( "romeo@desktop" ) );
|
||||
* c.logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );
|
||||
* c.registerMessageHandler( this );
|
||||
* c.registerConnectionListener( this );
|
||||
* @endcode
|
||||
*
|
||||
* Finally you have to attach the incoming connection to the Client instance, and call connect().
|
||||
*
|
||||
* @code
|
||||
* connection->registerConnectionDataHandler( &c );
|
||||
* c.setConnectionImpl( connection );
|
||||
* c.connect();
|
||||
* @endcode
|
||||
*
|
||||
* Add the Client to your event loop to call recv() periodically.
|
||||
*
|
||||
* @see @c linklocal_example.cpp in @c src/examples/ for a (very) simple implementation of a bot
|
||||
* handling both incoming and outgoing connections.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0.x
|
||||
*/
|
||||
class GLOOX_API Manager
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new Link-local Manager instance. You can call @c registerService() and/or @c startBrowsing()
|
||||
* immediately on a new Manager object, it will use sane defaults.
|
||||
* @param user The username to advertise, preferably (as per @xep{0174}) the locally
|
||||
* logged-in user. This is just the local part of the local JID.
|
||||
* @param connHandler A pointer to a ConnectionHandler that will receive incoming connections.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
*/
|
||||
Manager( const std::string& user, ConnectionHandler* connHandler, const LogSink &logInstance );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
* @note @c deregisterService() and @c stopBrowsing() will be called automatically if necessary.
|
||||
*/
|
||||
virtual ~Manager();
|
||||
|
||||
/**
|
||||
* Lets you add additional data to the published TXT record.
|
||||
* @note The @c txtvers=1 parameter is included by default and cannot be changed.
|
||||
* @param key The key of a key=value parameter pair. Must be non-empty. If the given key
|
||||
* has been set before, its value will be overwritten by the new value.
|
||||
* @param value The value of a @c key=value parameter pair. Must be non-empty.
|
||||
* @note If either parameter is empty, this function is a NOOP.
|
||||
* @note The additional data will not be automatically published if you have already called
|
||||
* @c registerService(). You will have to call @c registerService() again to update the
|
||||
* TXT record.
|
||||
*/
|
||||
void addTXTData( const std::string& key, const std::string& value );
|
||||
|
||||
/**
|
||||
* Lets you remove TXT record data by key.
|
||||
* @note The @c txtvers=1 parameter is included by default and cannot be removed.
|
||||
* @param key The key of the @c key=value parameter pair that should be removed. Must be non-empty.
|
||||
* @note A published TXT record will not be automatically updated if you have already called
|
||||
* @c registerService(). You will have to call @c registerService() again to update the TXT record.
|
||||
*/
|
||||
void removeTXTData( const std::string& key );
|
||||
|
||||
/**
|
||||
* Starts advertising link-local messaging capabilities by publishing a number of DNS records,
|
||||
* as per @xep{0174}.
|
||||
* You can call this function again to publish any values you updated after the first call.
|
||||
*/
|
||||
void registerService();
|
||||
|
||||
/**
|
||||
* Removes the published DNS records and thereby stops advertising link-local messaging
|
||||
* capabilities.
|
||||
*/
|
||||
void deregisterService();
|
||||
|
||||
/**
|
||||
* Lets you specify a new username.
|
||||
* @param user The new username.
|
||||
* @note The new username will not be automatically advertised if you have already called
|
||||
* @c registerService(). You will have to call @c registerService() again to update the username.
|
||||
*/
|
||||
void setUser( const std::string& user ) { m_user = user; }
|
||||
|
||||
/**
|
||||
* Lets you specify an alternate host name to advertise. By default the local machine's hostname
|
||||
* as returned by @c gethostname() will be used.
|
||||
* @param host The hostname to use.
|
||||
* @note The new hostname will not be automatically advertised if you have already called
|
||||
* @c registerService(). You will have to call @c registerService() again to update the hostname.
|
||||
*/
|
||||
void setHost( const std::string& host ) { m_host = host; }
|
||||
|
||||
/**
|
||||
* This function lets you set an alternate browse domain. The default domain should work in most cases.
|
||||
* @param domain The browse domain to set.
|
||||
* @note The new domain will not be automatically used if you have already called
|
||||
* @c registerService(). You will have to call @c registerService() again to update the domain.
|
||||
* The same applies to @c startBrowsing().
|
||||
*/
|
||||
void setDomain( const std::string& domain ) { m_domain = domain; }
|
||||
|
||||
/**
|
||||
* Lets you specifiy a port to listen on for incoming server-less XMPP connections. Default
|
||||
* for this implementation is port 5562, but any unused port can be used.
|
||||
* @note In addition to the SRV record, the port will also be published in the TXT record
|
||||
* automaticlly, you do not have to add it manually. That is, you should not call
|
||||
* @c addTXTData() with a key of @c "port.p2pj".
|
||||
* @param port The port to use.
|
||||
* @note The new port will not be automatically advertised if you have already called
|
||||
* @c registerService(). You will have to call @c registerService() again to update the port.
|
||||
*/
|
||||
void setPort( const int port ) { m_port = port; addTXTData( "port.p2pj", util::int2string( m_port ) ); }
|
||||
|
||||
/**
|
||||
* This function can be used to set a non-default interface. Use @c if_nametoindex() to
|
||||
* find the index for a specific named device.
|
||||
* By default DNS records will be broadcast on all available interfaces, and all available
|
||||
* interfaces will be used or browsing services.
|
||||
* @param iface The interface to use. If you set an interface here, and want to change it
|
||||
* back to 'any', use @b 0. Use @b -1 to broadcast only on the local machine.
|
||||
* @note The new interface will not be automatically used if you have already called
|
||||
* @c registerService(). You will have to call @c registerService() again to use the new
|
||||
* interface. The same applies to @c startBrowsing().
|
||||
*/
|
||||
void setInterface( unsigned iface ) { m_interface = iface; }
|
||||
|
||||
/**
|
||||
* Starts looking for other entities of type @c _presence. You have to set a handler for
|
||||
* results using @c registerLinkLocalHandler() before calling this function.
|
||||
* You can call this function again to re-start browsing with updated parameters.
|
||||
* @return Returns @b true if browsing could be started successfully, @b false otherwise.
|
||||
*/
|
||||
bool startBrowsing();
|
||||
|
||||
/**
|
||||
* Stops the browsing.
|
||||
*/
|
||||
void stopBrowsing();
|
||||
|
||||
/**
|
||||
* Exposes the socket used for browsing so you can have it checked in your own event loop,
|
||||
* if desired. If your event loop signals new data on the socket, you should NOT
|
||||
* try to read from it directly. Instead you should call @c recv().
|
||||
* As an alternative to using the raw socket you could also put the Manager in a
|
||||
* separate thread and call @c recv() repeatedly, or achieve this in any other way.
|
||||
*/
|
||||
int socket() const { return m_browseFd; }
|
||||
|
||||
/**
|
||||
* Checks once for new data on the socket used for browsing.
|
||||
* @param timeout The timeout for @c select() in microseconds. Use @b -1 if blocking behavior
|
||||
* is acceptable.
|
||||
*/
|
||||
void recv( int timeout );
|
||||
|
||||
/**
|
||||
* Registers a handler that will be notfied about entities found on the network that match
|
||||
* the given browse criteria.
|
||||
* @param handler The handler to register.
|
||||
*/
|
||||
void registerLinkLocalHandler( Handler* handler ) { m_linkLocalHandler = handler; }
|
||||
|
||||
// /**
|
||||
// *
|
||||
// */
|
||||
// static const StringMap decodeTXT( const std::string& txt );
|
||||
|
||||
private:
|
||||
static void handleBrowseReply( DNSServiceRef sdRef, DNSServiceFlags flags, unsigned interfaceIndex,
|
||||
DNSServiceErrorType errorCode, const char* serviceName, const char* regtype,
|
||||
const char* replyDomain, void* context );
|
||||
|
||||
void handleBrowse( Flag flag, const std::string& service, const std::string& regtype, const std::string& domain, int iface, bool moreComing );
|
||||
|
||||
typedef std::list<ConnectionTCPClient*> ConnectionList;
|
||||
typedef std::map<ConnectionTCPClient*, const JID> ConnectionMap;
|
||||
|
||||
DNSServiceRef m_publishRef;
|
||||
DNSServiceRef m_browseRef;
|
||||
|
||||
ServiceList m_tmpServices;
|
||||
// ServiceList m_services;
|
||||
|
||||
std::string m_user;
|
||||
std::string m_host;
|
||||
std::string m_domain;
|
||||
unsigned m_interface;
|
||||
int m_port;
|
||||
|
||||
const LogSink& m_logInstance;
|
||||
|
||||
int m_browseFd;
|
||||
|
||||
StringMap m_txtData;
|
||||
|
||||
ConnectionTCPServer m_server;
|
||||
|
||||
Handler* m_linkLocalHandler;
|
||||
ConnectionHandler* m_connectionHandler;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_MDNS
|
||||
|
||||
#endif // LINKLOCALMANAGER_H___
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
Copyright (c) 2006-2015 by Jakob Schröter <js@camaya.net>
|
||||
This file is part of the gloox library. http://camaya.net/gloox
|
||||
|
||||
This software is distributed under a license. The full license
|
||||
agreement can be found in the file LICENSE in this distribution.
|
||||
This software may not be copied, modified, sold or distributed
|
||||
other than expressed in the named license agreement.
|
||||
|
||||
This software is distributed without any warranty.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "mucinvitationhandler.h"
|
||||
#include "mucroom.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
MUCInvitationHandler::MUCInvitationHandler( ClientBase* parent )
|
||||
{
|
||||
if( parent )
|
||||
parent->registerStanzaExtension( new MUCRoom::MUCUser() );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#include <winver.h>
|
||||
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,13,0
|
||||
PRODUCTVERSION 1,0,13,0
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
FILEFLAGS 0
|
||||
FILEOS VOS__WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "gloox Jabber/XMPP library\0"
|
||||
VALUE "ProductVersion", "1.0.13\0"
|
||||
VALUE "FileVersion", "1.0.13\0"
|
||||
VALUE "InternalName", "gloox\0"
|
||||
VALUE "OriginalFilename", "gloox.dll\0"
|
||||
VALUE "CompanyName", "Jakob Schroeter\0"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2004-2015 Jakob Schroeter\0"
|
||||
VALUE "Licence", "GPLv3\0"
|
||||
VALUE "Info", "http://camaya.net/gloox\0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
Ŝarĝante…
Reference in New Issue