Remove obselete libraries/protocols
This commit is contained in:
parent
43275b5e22
commit
c6c1bb349a
|
@ -1,512 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 "adhoc.h"
|
||||
#include "adhochandler.h"
|
||||
#include "adhoccommandprovider.h"
|
||||
#include "disco.h"
|
||||
#include "dataform.h"
|
||||
#include "error.h"
|
||||
#include "iodata.h"
|
||||
#include "discohandler.h"
|
||||
#include "clientbase.h"
|
||||
#include "adhocplugin.h"
|
||||
#include "util.h"
|
||||
#include "mutexguard.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
static const char* cmdActionStringValues[] =
|
||||
{
|
||||
"execute", "cancel", "prev", "next", "complete"
|
||||
};
|
||||
|
||||
static inline const std::string actionString( Adhoc::Command::Action action )
|
||||
{
|
||||
return util::lookup2( action, cmdActionStringValues );
|
||||
}
|
||||
|
||||
static const char* cmdStatusStringValues[] =
|
||||
{
|
||||
"executing", "completed", "canceled"
|
||||
};
|
||||
|
||||
static inline const std::string statusString( Adhoc::Command::Status status )
|
||||
{
|
||||
return util::lookup( status, cmdStatusStringValues );
|
||||
}
|
||||
|
||||
static const char* cmdNoteStringValues[] =
|
||||
{
|
||||
"info", "warn", "error"
|
||||
};
|
||||
|
||||
static inline const std::string noteString( Adhoc::Command::Note::Severity sev )
|
||||
{
|
||||
return util::lookup( sev, cmdNoteStringValues );
|
||||
}
|
||||
|
||||
// ---- Adhoc::Command::Note ----
|
||||
Adhoc::Command::Note::Note( const Tag* tag )
|
||||
: m_severity( InvalidSeverity )
|
||||
{
|
||||
if( !tag || tag->name() != "note" )
|
||||
return;
|
||||
|
||||
m_severity = (Severity)util::deflookup( tag->findAttribute( "type" ), cmdNoteStringValues, Info );
|
||||
m_note = tag->cdata();
|
||||
}
|
||||
|
||||
Tag* Adhoc::Command::Note::tag() const
|
||||
{
|
||||
if( m_note.empty() || m_severity == InvalidSeverity )
|
||||
return 0;
|
||||
|
||||
Tag* n = new Tag( "note", m_note );
|
||||
n->addAttribute( TYPE, noteString( m_severity ) );
|
||||
return n;
|
||||
}
|
||||
// ---- ~Adhoc::Command::Note ----
|
||||
|
||||
// ---- Adhoc::Command ----
|
||||
Adhoc::Command::Command( const std::string& node, Adhoc::Command::Action action,
|
||||
AdhocPlugin* plugin )
|
||||
: StanzaExtension( ExtAdhocCommand ), m_node( node ), m_plugin( plugin ), m_action( action ),
|
||||
m_status( InvalidStatus ), m_actions( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
Adhoc::Command::Command( const std::string& node, const std::string& sessionid, Status status,
|
||||
AdhocPlugin* plugin )
|
||||
: StanzaExtension( ExtAdhocCommand ), m_node( node ), m_sessionid( sessionid ),
|
||||
m_plugin( plugin ), m_action( InvalidAction ), m_status( status ), m_actions( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
Adhoc::Command::Command( const std::string& node, const std::string& sessionid,
|
||||
Adhoc::Command::Action action,
|
||||
AdhocPlugin* plugin )
|
||||
: StanzaExtension( ExtAdhocCommand ), m_node( node ), m_sessionid( sessionid ),
|
||||
m_plugin( plugin ), m_action( action ), m_actions( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
Adhoc::Command::Command( const std::string& node, const std::string& sessionid, Status status,
|
||||
Action executeAction, int allowedActions,
|
||||
AdhocPlugin* plugin )
|
||||
: StanzaExtension( ExtAdhocCommand ), m_node( node ), m_sessionid( sessionid ),
|
||||
m_plugin( plugin ), m_action( executeAction ), m_status( status ), m_actions( allowedActions )
|
||||
{
|
||||
}
|
||||
|
||||
Adhoc::Command::Command( const Tag* tag )
|
||||
: StanzaExtension( ExtAdhocCommand ), m_plugin( 0 ), m_actions( 0 )
|
||||
{
|
||||
if( !tag || tag->name() != "command" || tag->xmlns() != XMLNS_ADHOC_COMMANDS )
|
||||
return;
|
||||
|
||||
m_node = tag->findAttribute( "node" );
|
||||
m_sessionid = tag->findAttribute( "sessionid" );
|
||||
m_status = (Status)util::lookup( tag->findAttribute( "status" ), cmdStatusStringValues );
|
||||
|
||||
Tag* a = tag->findChild( "actions" );
|
||||
if( a )
|
||||
{
|
||||
// Multi-stage response
|
||||
m_action = (Action)util::deflookup2( a->findAttribute( "action" ), cmdActionStringValues, Complete );
|
||||
if( a->hasChild( "prev" ) )
|
||||
m_actions |= Previous;
|
||||
if( a->hasChild( "next" ) )
|
||||
m_actions |= Next;
|
||||
if( a->hasChild( "complete" ) )
|
||||
m_actions |= Complete;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_action = (Action)util::deflookup2( tag->findAttribute( "action" ), cmdActionStringValues, Execute );
|
||||
}
|
||||
|
||||
const ConstTagList& l = tag->findTagList( "/command/note" );
|
||||
ConstTagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
m_notes.push_back( new Note( (*it) ) );
|
||||
|
||||
Tag* x = tag->findChild( "x", "xmlns", XMLNS_X_DATA );
|
||||
if( x )
|
||||
m_plugin = new DataForm( x );
|
||||
else
|
||||
{
|
||||
Tag* x = tag->findChild( "iodata", "xmlns", XMLNS_IODATA );
|
||||
if( x )
|
||||
m_plugin = new IOData( x );
|
||||
}
|
||||
}
|
||||
|
||||
Adhoc::Command::~Command()
|
||||
{
|
||||
util::clearList( m_notes );
|
||||
delete m_plugin;
|
||||
}
|
||||
|
||||
const std::string& Adhoc::Command::filterString() const
|
||||
{
|
||||
static const std::string filter = "/iq/command[@xmlns='" + XMLNS_ADHOC_COMMANDS + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Adhoc::Command::tag() const
|
||||
{
|
||||
if( m_node.empty() )
|
||||
return 0;
|
||||
|
||||
Tag* c = new Tag( "command" );
|
||||
c->setXmlns( XMLNS_ADHOC_COMMANDS );
|
||||
c->addAttribute( "node", m_node );
|
||||
if( m_actions != 0 )
|
||||
{
|
||||
// Multi-stage command response
|
||||
|
||||
if( m_status != InvalidStatus )
|
||||
c->addAttribute( "status", statusString( m_status ) );
|
||||
else
|
||||
c->addAttribute( "status", statusString( Executing ) );
|
||||
|
||||
Tag* actions = new Tag( c, "actions" );
|
||||
|
||||
if( m_action != InvalidAction )
|
||||
c->addAttribute( "execute", actionString( m_action ) );
|
||||
else
|
||||
c->addAttribute( "execute", actionString( Complete ) );
|
||||
|
||||
if( ( m_actions & Previous ) == Previous )
|
||||
new Tag( actions, "prev" );
|
||||
if( ( m_actions & Next ) == Next )
|
||||
new Tag( actions, "next" );
|
||||
if( ( m_actions & Complete ) == Complete )
|
||||
new Tag( actions, "complete" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Single-stage command request/response or Multi-stage command request
|
||||
|
||||
if( m_action != InvalidAction )
|
||||
c->addAttribute( "action", actionString( m_action ) );
|
||||
if( m_status != InvalidStatus )
|
||||
c->addAttribute( "status", statusString( m_status ) );
|
||||
}
|
||||
|
||||
if ( !m_sessionid.empty() )
|
||||
c->addAttribute( "sessionid", m_sessionid );
|
||||
|
||||
if( m_plugin && *m_plugin )
|
||||
c->addChild( m_plugin->tag() );
|
||||
|
||||
NoteList::const_iterator it = m_notes.begin();
|
||||
for( ; it != m_notes.end(); ++it )
|
||||
c->addChild( (*it)->tag() );
|
||||
|
||||
return c;
|
||||
}
|
||||
// ---- ~Adhoc::Command ----
|
||||
|
||||
// ---- Adhoc ----
|
||||
Adhoc::Adhoc( ClientBase* parent )
|
||||
: m_parent( parent )
|
||||
{
|
||||
if( !m_parent || !m_parent->disco() )
|
||||
return;
|
||||
|
||||
m_parent->disco()->addFeature( XMLNS_ADHOC_COMMANDS );
|
||||
m_parent->disco()->registerNodeHandler( this, XMLNS_ADHOC_COMMANDS );
|
||||
m_parent->disco()->registerNodeHandler( this, EmptyString );
|
||||
m_parent->registerIqHandler( this, ExtAdhocCommand );
|
||||
m_parent->registerStanzaExtension( new Adhoc::Command() );
|
||||
}
|
||||
|
||||
Adhoc::~Adhoc()
|
||||
{
|
||||
m_adhocTrackMapMutex.lock();
|
||||
m_adhocTrackMap.clear();
|
||||
m_adhocTrackMapMutex.unlock();
|
||||
|
||||
if( !m_parent || !m_parent->disco() )
|
||||
return;
|
||||
|
||||
m_parent->disco()->removeFeature( XMLNS_ADHOC_COMMANDS );
|
||||
m_parent->disco()->removeNodeHandler( this, XMLNS_ADHOC_COMMANDS );
|
||||
m_parent->disco()->removeNodeHandler( this, EmptyString );
|
||||
m_parent->removeIqHandler( this, ExtAdhocCommand );
|
||||
m_parent->removeIDHandler( this );
|
||||
m_parent->removeStanzaExtension( ExtAdhocCommand );
|
||||
}
|
||||
|
||||
StringList Adhoc::handleDiscoNodeFeatures( const JID& /*from*/, const std::string& /*node*/ )
|
||||
{
|
||||
StringList features;
|
||||
features.push_back( XMLNS_ADHOC_COMMANDS );
|
||||
return features;
|
||||
// return StringList( 1, XMLNS_ADHOC_COMMANDS );
|
||||
}
|
||||
|
||||
Disco::ItemList Adhoc::handleDiscoNodeItems( const JID& from, const JID& /*to*/, const std::string& node )
|
||||
{
|
||||
Disco::ItemList l;
|
||||
if( node.empty() )
|
||||
{
|
||||
l.push_back( new Disco::Item( m_parent->jid(), XMLNS_ADHOC_COMMANDS, "Ad-Hoc Commands" ) );
|
||||
}
|
||||
else if( node == XMLNS_ADHOC_COMMANDS )
|
||||
{
|
||||
StringMap::const_iterator it = m_items.begin();
|
||||
for( ; it != m_items.end(); ++it )
|
||||
{
|
||||
AdhocCommandProviderMap::const_iterator itp = m_adhocCommandProviders.find( (*it).first );
|
||||
if( itp != m_adhocCommandProviders.end()
|
||||
&& (*itp).second
|
||||
&& (*itp).second->handleAdhocAccessRequest( from, (*it).first ) )
|
||||
{
|
||||
l.push_back( new Disco::Item( m_parent->jid(), (*it).first, (*it).second ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
Disco::IdentityList Adhoc::handleDiscoNodeIdentities( const JID& /*from*/, const std::string& node )
|
||||
{
|
||||
Disco::IdentityList l;
|
||||
StringMap::const_iterator it = m_items.find( node );
|
||||
l.push_back( new Disco::Identity( "automation",
|
||||
node == XMLNS_ADHOC_COMMANDS ? "command-list" : "command-node",
|
||||
it == m_items.end() ? "Ad-Hoc Commands" : (*it).second ) );
|
||||
return l;
|
||||
}
|
||||
|
||||
bool Adhoc::handleIq( const IQ& iq )
|
||||
{
|
||||
if( iq.subtype() != IQ::Set )
|
||||
return false;
|
||||
|
||||
const Adhoc::Command* ac = iq.findExtension<Adhoc::Command>( ExtAdhocCommand );
|
||||
if( !ac || ac->node().empty())
|
||||
return false;
|
||||
|
||||
AdhocCommandProviderMap::const_iterator it = m_adhocCommandProviders.find( ac->node() );
|
||||
if( it != m_adhocCommandProviders.end() )
|
||||
{
|
||||
const std::string& sess = ac->sessionID().empty() ? m_parent->getID() : ac->sessionID();
|
||||
m_activeSessions[sess] = iq.id();
|
||||
(*it).second->handleAdhocCommand( iq.from(), *ac, sess );
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Adhoc::handleIqID( const IQ& iq, int context )
|
||||
{
|
||||
if( context != ExecuteAdhocCommand )
|
||||
return;
|
||||
|
||||
m_adhocTrackMapMutex.lock();
|
||||
AdhocTrackMap::iterator it = m_adhocTrackMap.find( iq.id() );
|
||||
bool haveIdHandler = ( it != m_adhocTrackMap.end() );
|
||||
m_adhocTrackMapMutex.unlock();
|
||||
if( !haveIdHandler || (*it).second.context != context
|
||||
|| (*it).second.remote != iq.from() )
|
||||
return;
|
||||
|
||||
switch( iq.subtype() )
|
||||
{
|
||||
case IQ::Error:
|
||||
(*it).second.ah->handleAdhocError( iq.from(), iq.error(), (*it).second.handlerContext );
|
||||
break;
|
||||
case IQ::Result:
|
||||
{
|
||||
const Adhoc::Command* ac = iq.findExtension<Adhoc::Command>( ExtAdhocCommand );
|
||||
if( ac )
|
||||
(*it).second.ah->handleAdhocExecutionResult( iq.from(), *ac, (*it).second.handlerContext );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_adhocTrackMapMutex.lock();
|
||||
m_adhocTrackMap.erase( it );
|
||||
m_adhocTrackMapMutex.unlock();
|
||||
}
|
||||
|
||||
void Adhoc::registerAdhocCommandProvider( AdhocCommandProvider* acp, const std::string& command,
|
||||
const std::string& name )
|
||||
{
|
||||
if( !m_parent || !m_parent->disco() )
|
||||
return;
|
||||
|
||||
m_parent->disco()->registerNodeHandler( this, command );
|
||||
m_adhocCommandProviders[command] = acp;
|
||||
m_items[command] = name;
|
||||
}
|
||||
|
||||
void Adhoc::handleDiscoInfo( const JID& from, const Disco::Info& info, int context )
|
||||
{
|
||||
if( context != CheckAdhocSupport )
|
||||
return;
|
||||
|
||||
util::MutexGuard m( m_adhocTrackMapMutex );
|
||||
|
||||
AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
|
||||
for( ; it != m_adhocTrackMap.end() && (*it).second.context != context
|
||||
&& (*it).second.remote != from; ++it )
|
||||
;
|
||||
if( it == m_adhocTrackMap.end() )
|
||||
return;
|
||||
|
||||
(*it).second.ah->handleAdhocSupport( from, info.hasFeature( XMLNS_ADHOC_COMMANDS ), (*it).second.handlerContext );
|
||||
m_adhocTrackMap.erase( it );
|
||||
}
|
||||
|
||||
void Adhoc::handleDiscoItems( const JID& from, const Disco::Items& items, int context )
|
||||
{
|
||||
if( context != FetchAdhocCommands )
|
||||
return;
|
||||
|
||||
util::MutexGuard m( m_adhocTrackMapMutex );
|
||||
|
||||
AdhocTrackMap::iterator it = m_adhocTrackMap.begin();
|
||||
for( ; it != m_adhocTrackMap.end(); ++it )
|
||||
{
|
||||
if( (*it).second.context == context && (*it).second.remote == from )
|
||||
{
|
||||
StringMap commands;
|
||||
const Disco::ItemList& l = items.items();
|
||||
Disco::ItemList::const_iterator it2 = l.begin();
|
||||
for( ; it2 != l.end(); ++it2 )
|
||||
{
|
||||
commands[(*it2)->node()] = (*it2)->name();
|
||||
}
|
||||
(*it).second.ah->handleAdhocCommands( from, commands, (*it).second.handlerContext );
|
||||
|
||||
m_adhocTrackMap.erase( it );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Adhoc::handleDiscoError( const JID& from, const Error* error, int context )
|
||||
{
|
||||
util::MutexGuard m( m_adhocTrackMapMutex );
|
||||
for( AdhocTrackMap::iterator it = m_adhocTrackMap.begin(); it != m_adhocTrackMap.end(); )
|
||||
{
|
||||
if( (*it).second.context == context && (*it).second.remote == from )
|
||||
{
|
||||
(*it).second.ah->handleAdhocError( from, error, (*it).second.handlerContext );
|
||||
|
||||
// Normally we'd just assign it to the return value of the .erase() call,
|
||||
// which is either the next element, or .end(). However,
|
||||
// it's only since C++11 that this works; C++03 version returns void.
|
||||
// So instead, we do a post-increment. this increments the iterator to point
|
||||
// to the next element, then passes a copy of the old iterator (that is to the item to be deleted)
|
||||
m_adhocTrackMap.erase( it++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Adhoc::checkSupport( const JID& remote, AdhocHandler* ah, int context )
|
||||
{
|
||||
if( !remote || !ah || !m_parent || !m_parent->disco() )
|
||||
return;
|
||||
|
||||
TrackStruct track;
|
||||
track.remote = remote;
|
||||
track.context = CheckAdhocSupport;
|
||||
track.ah = ah;
|
||||
track.handlerContext = context;
|
||||
const std::string& id = m_parent->getID();
|
||||
m_adhocTrackMapMutex.lock();
|
||||
m_adhocTrackMap[id] = track;
|
||||
m_adhocTrackMapMutex.unlock();
|
||||
m_parent->disco()->getDiscoInfo( remote, EmptyString, this, CheckAdhocSupport, id );
|
||||
}
|
||||
|
||||
void Adhoc::getCommands( const JID& remote, AdhocHandler* ah, int context )
|
||||
{
|
||||
if( !remote || !ah || !m_parent || !m_parent->disco() )
|
||||
return;
|
||||
|
||||
TrackStruct track;
|
||||
track.remote = remote;
|
||||
track.context = FetchAdhocCommands;
|
||||
track.ah = ah;
|
||||
track.handlerContext = context;
|
||||
const std::string& id = m_parent->getID();
|
||||
m_adhocTrackMapMutex.lock();
|
||||
m_adhocTrackMap[id] = track;
|
||||
m_adhocTrackMapMutex.unlock();
|
||||
m_parent->disco()->getDiscoItems( remote, XMLNS_ADHOC_COMMANDS, this, FetchAdhocCommands, id );
|
||||
}
|
||||
|
||||
void Adhoc::execute( const JID& remote, const Adhoc::Command* command, AdhocHandler* ah, int context )
|
||||
{
|
||||
if( !remote || !command || !m_parent || !ah )
|
||||
return;
|
||||
|
||||
const std::string& id = m_parent->getID();
|
||||
IQ iq( IQ::Set, remote, id );
|
||||
iq.addExtension( command );
|
||||
|
||||
TrackStruct track;
|
||||
track.remote = remote;
|
||||
track.context = ExecuteAdhocCommand;
|
||||
track.session = command->sessionID();
|
||||
track.ah = ah;
|
||||
track.handlerContext = context;
|
||||
m_adhocTrackMapMutex.lock();
|
||||
m_adhocTrackMap[id] = track;
|
||||
m_adhocTrackMapMutex.unlock();
|
||||
|
||||
m_parent->send( iq, this, ExecuteAdhocCommand );
|
||||
}
|
||||
|
||||
void Adhoc::respond( const JID& remote, const Adhoc::Command* command, const Error* error )
|
||||
{
|
||||
if( !remote || !command || !m_parent )
|
||||
return;
|
||||
|
||||
StringMap::iterator it = m_activeSessions.find( command->sessionID() );
|
||||
if( it == m_activeSessions.end() )
|
||||
return;
|
||||
|
||||
IQ re( error ? IQ::Error : IQ::Result, remote, (*it).second );
|
||||
re.addExtension( command );
|
||||
if( error )
|
||||
re.addExtension( error );
|
||||
m_parent->send( re );
|
||||
m_activeSessions.erase( it );
|
||||
}
|
||||
|
||||
void Adhoc::removeAdhocCommandProvider( const std::string& command )
|
||||
{
|
||||
if( !m_parent || !m_parent->disco() )
|
||||
return;
|
||||
|
||||
m_parent->disco()->removeNodeHandler( this, command );
|
||||
m_adhocCommandProviders.erase( command );
|
||||
m_items.erase( command );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,500 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 ADHOC_H__
|
||||
#define ADHOC_H__
|
||||
|
||||
#include "adhocplugin.h"
|
||||
#include "disco.h"
|
||||
#include "disconodehandler.h"
|
||||
#include "discohandler.h"
|
||||
#include "iqhandler.h"
|
||||
#include "stanzaextension.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class ClientBase;
|
||||
class Stanza;
|
||||
class AdhocHandler;
|
||||
class AdhocCommandProvider;
|
||||
|
||||
/**
|
||||
* @brief This class implements a provider for @xep{0050} (Ad-hoc Commands).
|
||||
*
|
||||
* The current, not complete, implementation is probably best suited for fire-and-forget
|
||||
* type of commands. Any additional feature, like multiple stages, etc., would have to be
|
||||
* added separately.
|
||||
*
|
||||
* To offer commands to remote entities, use this class as follows:<br>
|
||||
* Create a class that will handle command execution requests and derive it from
|
||||
* AdhocCommandProvider. Instantiate an Adhoc object and register your
|
||||
* AdhocCommandProvider-derived object with the Adhoc object using
|
||||
* registerAdhocCommandProvider(). The additional parameters to that method are the internal
|
||||
* name of the command as used in the code, and the public name of the command as it
|
||||
* will be shown to an end user:
|
||||
* @code
|
||||
* MyClass::someFunc()
|
||||
* {
|
||||
* Adhoc* m_adhoc = new Adhoc( m_client );
|
||||
*
|
||||
* // this might be a bot monitoring a weather station, for example
|
||||
* m_adhoc->registerAdhocCommandProvider( this, "getTemp", "Retrieve current temperature" );
|
||||
* m_adhoc->registerAdhocCommandProvider( this, "getPressure", "Retrieve current air pressure" );
|
||||
* [...]
|
||||
* }
|
||||
* @endcode
|
||||
* In this example, MyClass is AdhocCommandProvider-derived so it is obviously the command handler, too.
|
||||
*
|
||||
* And that's about it you can do with the Adhoc class. Of course you can have a AdhocCommandProvider
|
||||
* handle more than one command, just register it with the Adhoc object for every desired command,
|
||||
* like shown above.
|
||||
*
|
||||
* What the Adhoc object does when you install a new command is tell the supplied Disco object
|
||||
* to advertise these commands to clients using the 'Service Discovery' protocol to learn about
|
||||
* this implementation's features. These clients can then call and execute the command. Of course you
|
||||
* are free to implement access restrictions to not let anyone mess with your bot, for example.
|
||||
* However, the commands offered using Service Discovery are publically visible in any case.
|
||||
*
|
||||
* To execute commands offered by a remote entity:<br>
|
||||
* ...TBC...
|
||||
*
|
||||
* XEP version: 1.2
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
*/
|
||||
class GLOOX_API Adhoc : public DiscoNodeHandler, public DiscoHandler, public IqHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief An abstraction of an Adhoc Command element (from Adhoc Commands, @xep{0050})
|
||||
* as a StanzaExtension.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Command : public StanzaExtension
|
||||
{
|
||||
friend class Adhoc;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Specifies the action to undertake with the given command.
|
||||
*/
|
||||
enum Action
|
||||
{
|
||||
Execute = 1, /**< The command should be executed or continue to be executed.
|
||||
* This is the default value. */
|
||||
Cancel = 2, /**< The command should be canceled. */
|
||||
Previous = 4, /**< The command should be digress to the previous stage of
|
||||
* execution. */
|
||||
Next = 8, /**< The command should progress to the next stage of
|
||||
* execution. */
|
||||
Complete = 16, /**< The command should be completed (if possible). */
|
||||
InvalidAction = 32 /**< The action is unknown or invalid. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes the current status of a command.
|
||||
*/
|
||||
enum Status
|
||||
{
|
||||
Executing, /**< The command is being executed. */
|
||||
Completed, /**< The command has completed. The command session has ended. */
|
||||
Canceled, /**< The command has been canceled. The command session has ended. */
|
||||
InvalidStatus /**< The status is unknown or invalid. */
|
||||
};
|
||||
|
||||
/**
|
||||
* An abstraction of a command note.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Note
|
||||
{
|
||||
|
||||
friend class Command;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Specifies the severity of a note.
|
||||
*/
|
||||
enum Severity
|
||||
{
|
||||
Info, /**< The note is informational only. This is not really an
|
||||
* exceptional condition. */
|
||||
Warning, /**< The note indicates a warning. Possibly due to illogical
|
||||
* (yet valid) data. */
|
||||
Error, /**< The note indicates an error. The text should indicate the
|
||||
* reason for the error. */
|
||||
InvalidSeverity /**< The note type is unknown or invalid. */
|
||||
};
|
||||
|
||||
/**
|
||||
* A convenience constructor.
|
||||
* @param sev The note's severity.
|
||||
* @param note The note's content.
|
||||
*/
|
||||
Note( Severity sev, const std::string& note )
|
||||
: m_severity( sev ), m_note( note ) {}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Note() {}
|
||||
|
||||
/**
|
||||
* Returns the note's severity.
|
||||
* @return The note's severity.
|
||||
*/
|
||||
Severity severity() const { return m_severity; }
|
||||
|
||||
/**
|
||||
* Returns the note's content.
|
||||
* @return The note's content.
|
||||
*/
|
||||
const std::string& content() const { return m_note; }
|
||||
|
||||
/**
|
||||
* Returns a Tag representation of the Note.
|
||||
* @return A Tag representation.
|
||||
*/
|
||||
Tag* tag() const;
|
||||
|
||||
private:
|
||||
#ifdef ADHOC_COMMANDS_TEST
|
||||
public:
|
||||
#endif
|
||||
/**
|
||||
* Constructs a new Note from the given Tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
Note( const Tag* tag );
|
||||
|
||||
Severity m_severity; /**< The note's severity. */
|
||||
std::string m_note; /**< The note's content. */
|
||||
};
|
||||
|
||||
/**
|
||||
* A list of command notes.
|
||||
*/
|
||||
typedef std::list<const Note*> NoteList;
|
||||
|
||||
/**
|
||||
* Creates a Command object that can be used to perform the provided Action.
|
||||
* This constructor is used best to continue execution of a multi stage command
|
||||
* (for which the session ID must be known).
|
||||
* @param node The node (command) to perform the action on.
|
||||
* @param sessionid The session ID of an already running adhoc command session.
|
||||
* @param action The action to perform.
|
||||
* @param plugin An optional AdhocPlugin (e.g. DataForm) to include in the request. Will be deleted in Command's
|
||||
* destructor.
|
||||
*/
|
||||
Command( const std::string& node, const std::string& sessionid, Action action,
|
||||
AdhocPlugin* plugin = 0 );
|
||||
|
||||
/**
|
||||
* Creates a Command object that can be used to perform the provided Action.
|
||||
* This constructor is used best to reply to an execute request.
|
||||
* @param node The node (command) to perform the action on.
|
||||
* @param sessionid The (possibly newly created) session ID of the adhoc command session.
|
||||
* @param status The execution status.
|
||||
* @param plugin An optional AdhocPlugin (e.g. DataForm) to include in the reply. Will be deleted in Command's
|
||||
* destructor.
|
||||
*/
|
||||
Command( const std::string& node, const std::string& sessionid, Status status,
|
||||
AdhocPlugin* plugin = 0 );
|
||||
|
||||
/**
|
||||
* Creates a Command object that can be used to perform the provided Action.
|
||||
* This constructor is used best to reply to a multi stage command that is not yet completed
|
||||
* (for which the session ID must be known).
|
||||
* @param node The node (command) to perform the action on.
|
||||
* @param sessionid The (possibly newly created) session ID of the adhoc command session.
|
||||
* @param status The execution status.
|
||||
* @param executeAction The action to execute.
|
||||
* @param allowedActions Allowed reply actions.
|
||||
* @param plugin An optional AdhocPlugin (e.g. DataForm) to include in the reply. Will be deleted in Command's
|
||||
* destructor.
|
||||
*/
|
||||
Command( const std::string& node, const std::string& sessionid, Status status,
|
||||
Action executeAction, int allowedActions = Complete,
|
||||
AdhocPlugin* plugin = 0 );
|
||||
|
||||
/**
|
||||
* Creates a Command object that can be used to perform the provided Action.
|
||||
* This constructor is used best to execute the initial step of a command
|
||||
* (single or multi stage).
|
||||
* @param node The node (command) to perform the action on.
|
||||
* @param action The action to perform.
|
||||
* @param plugin An optional AdhocPlugin (e.g. DataForm) to include in the request. Will be deleted in Command's
|
||||
* destructor.
|
||||
*/
|
||||
Command( const std::string& node, Action action,
|
||||
AdhocPlugin* plugin = 0 );
|
||||
|
||||
/**
|
||||
* Creates a Command object from the given Tag.
|
||||
* @param tag A <command> tag in the adhoc commands' namespace.
|
||||
*/
|
||||
Command( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Command();
|
||||
|
||||
/**
|
||||
* Returns the node identifier (the command).
|
||||
* @return The node identifier.
|
||||
*/
|
||||
const std::string& node() const { return m_node; }
|
||||
|
||||
/**
|
||||
* Returns the command's session ID, if any.
|
||||
* @return The command's session ID.
|
||||
*/
|
||||
const std::string& sessionID() const { return m_sessionid; }
|
||||
|
||||
/**
|
||||
* Returns the execution status for a command. Only valid for execution
|
||||
* results.
|
||||
* @return The execution status for a command.
|
||||
*/
|
||||
Status status() const { return m_status; }
|
||||
|
||||
/**
|
||||
* Returns the command's action.
|
||||
* @return The command's action.
|
||||
*/
|
||||
Action action() const { return m_action; }
|
||||
|
||||
/**
|
||||
* Returns the ORed actions that are allowed to be executed on the
|
||||
* current stage.
|
||||
* @return An int containing the ORed actions.
|
||||
*/
|
||||
int actions() const { return m_actions; }
|
||||
|
||||
/**
|
||||
* Returns the list of notes associated with the command.
|
||||
* @return The list of notes.
|
||||
*/
|
||||
const NoteList& notes() const { return m_notes; }
|
||||
|
||||
/**
|
||||
* Use this function to add a note to the command.
|
||||
* @param note A pointer to a Note object. The Command will own
|
||||
* the Note.
|
||||
*/
|
||||
void addNote( const Note* note ) { m_notes.push_back( note ); }
|
||||
|
||||
/**
|
||||
* Returns the command's embedded AdhocPlugin (e.g. DataForm).
|
||||
* @return The command's embedded AdhocPlugin (e.g. DataForm). May be 0.
|
||||
* @note This will be removed in 1.1. Use plugin() instead.
|
||||
*/
|
||||
GLOOX_DEPRECATED const AdhocPlugin* form() const { return m_plugin; }
|
||||
|
||||
/**
|
||||
* Returns the command's embedded AdhocPlugin (e.g. DataForm).
|
||||
* @return The command's embedded AdhocPlugin (e.g. DataForm). May be 0.
|
||||
*/
|
||||
const AdhocPlugin* plugin() const { return m_plugin; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Command( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
Command* c = new Command();
|
||||
|
||||
NoteList::const_iterator it = m_notes.begin();
|
||||
for( ; it != m_notes.end(); ++it )
|
||||
c->m_notes.push_back( new Note( *(*it) ) );
|
||||
|
||||
c->m_node = m_node;
|
||||
c->m_sessionid = m_sessionid;
|
||||
c->m_plugin = m_plugin ? static_cast<AdhocPlugin*>( m_plugin->clone() ) : 0;
|
||||
c->m_action = m_action;
|
||||
c->m_status = m_status;
|
||||
c->m_actions = m_actions;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef ADHOC_COMMANDS_TEST
|
||||
public:
|
||||
#endif
|
||||
NoteList m_notes;
|
||||
|
||||
std::string m_node;
|
||||
std::string m_sessionid;
|
||||
AdhocPlugin* m_plugin;
|
||||
Action m_action;
|
||||
Status m_status;
|
||||
int m_actions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates a new Adhoc client that registers as IqHandler with a ClientBase.
|
||||
* @param parent The ClientBase used for XMPP communication.
|
||||
*/
|
||||
Adhoc( ClientBase* parent );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Adhoc();
|
||||
|
||||
/**
|
||||
* This function queries the given remote entity for Adhoc Commands support.
|
||||
* @param remote The remote entity's JID.
|
||||
* @param ah The object handling the result of this request.
|
||||
* @param context A user defined context.
|
||||
*/
|
||||
void checkSupport( const JID& remote, AdhocHandler* ah, int context = 0 );
|
||||
|
||||
/**
|
||||
* Retrieves a list of commands from the remote entity. You should check whether the remote
|
||||
* entity actually supports Adhoc Commands by means of checkSupport().
|
||||
* @param remote The remote entity's JID.
|
||||
* @param ah The object handling the result of this request.
|
||||
* @param context A user defined context.
|
||||
*/
|
||||
void getCommands( const JID& remote, AdhocHandler* ah, int context = 0 );
|
||||
|
||||
/**
|
||||
* Executes or continues the given command on the given remote entity.
|
||||
* To construct the @c command object, it is recommended to use either
|
||||
* Command( const std::string&, Action ) to begin execution of a command, or
|
||||
* Command( const std::string&, const std::string&, Action ) to continue execution
|
||||
* of a command.
|
||||
* @param remote The remote entity's JID.
|
||||
* @param command The command to execute.
|
||||
* @param ah The object handling the result of this request.
|
||||
* @param context A user defined context.
|
||||
*/
|
||||
void execute( const JID& remote, const Adhoc::Command* command, AdhocHandler* ah, int context = 0 );
|
||||
|
||||
/**
|
||||
* Use this function to respond to an execution request submitted by means
|
||||
* of AdhocCommandProvider::handleAdhocCommand().
|
||||
* It is recommended to use
|
||||
* Command( const std::string&, const std::string&, Status, AdhocPlugin* )
|
||||
* to construct the @c command object.
|
||||
* Optionally, an Error object can be included. In that case the IQ sent is of type @c error.
|
||||
* @param remote The requester's JID.
|
||||
* @param command The response. The Adhoc object will own and delete the
|
||||
* command object pointed to.
|
||||
* @param error An optional Error obejct to include.
|
||||
*/
|
||||
void respond( const JID& remote, const Adhoc::Command* command, const Error* error = 0 );
|
||||
|
||||
/**
|
||||
* Using this function, you can register a AdhocCommandProvider -derived object as
|
||||
* handler for a specific Ad-hoc Command as defined in @xep{0050}.
|
||||
* @param acp The object to register as handler for the specified command.
|
||||
* @param command The node name of the command. Will be announced in disco#items.
|
||||
* @param name The natural-language name of the command. Will be announced in disco#items.
|
||||
*/
|
||||
void registerAdhocCommandProvider( AdhocCommandProvider* acp, const std::string& command,
|
||||
const std::string& name );
|
||||
|
||||
/**
|
||||
* Use this function to unregister an adhoc command previously registered using
|
||||
* registerAdhocCommandProvider().
|
||||
* @param command The command to unregister.
|
||||
*/
|
||||
void removeAdhocCommandProvider( const std::string& command );
|
||||
|
||||
// reimplemented from DiscoNodeHandler
|
||||
virtual StringList handleDiscoNodeFeatures( const JID& from, const std::string& node );
|
||||
|
||||
// reimplemented from DiscoNodeHandler
|
||||
virtual Disco::IdentityList handleDiscoNodeIdentities( const JID& from,
|
||||
const std::string& node );
|
||||
|
||||
// reimplemented from DiscoNodeHandler
|
||||
virtual Disco::ItemList handleDiscoNodeItems( const JID& from, const JID& to, const std::string& node );
|
||||
|
||||
// reimplemented from IqHandler
|
||||
virtual bool handleIq( const IQ& iq );
|
||||
|
||||
// reimplemented from IqHandler
|
||||
virtual void handleIqID( const IQ& iq, int context );
|
||||
|
||||
// reimplemented from DiscoHandler
|
||||
virtual void handleDiscoInfo( const JID& from, const Disco::Info& info, int context );
|
||||
|
||||
// reimplemented from DiscoHandler
|
||||
virtual void handleDiscoItems( const JID& from, const Disco::Items& items, int context );
|
||||
|
||||
// reimplemented from DiscoHandler
|
||||
virtual void handleDiscoError( const JID& from, const Error* error, int context );
|
||||
|
||||
private:
|
||||
#ifdef ADHOC_TEST
|
||||
public:
|
||||
#endif
|
||||
typedef std::map<const std::string, AdhocCommandProvider*> AdhocCommandProviderMap;
|
||||
AdhocCommandProviderMap m_adhocCommandProviders;
|
||||
|
||||
enum AdhocContext
|
||||
{
|
||||
CheckAdhocSupport,
|
||||
FetchAdhocCommands,
|
||||
ExecuteAdhocCommand
|
||||
};
|
||||
|
||||
struct TrackStruct
|
||||
{
|
||||
JID remote;
|
||||
AdhocContext context;
|
||||
std::string session;
|
||||
AdhocHandler* ah;
|
||||
int handlerContext;
|
||||
};
|
||||
typedef std::map<std::string, TrackStruct> AdhocTrackMap;
|
||||
AdhocTrackMap m_adhocTrackMap;
|
||||
util::Mutex m_adhocTrackMapMutex;
|
||||
|
||||
ClientBase* m_parent;
|
||||
|
||||
StringMap m_items;
|
||||
StringMap m_activeSessions;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ADHOC_H__
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 ADHOCCOMMANDPROVIDER_H__
|
||||
#define ADHOCCOMMANDPROVIDER_H__
|
||||
|
||||
#include "tag.h"
|
||||
#include "jid.h"
|
||||
#include "adhoc.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A virtual interface for an Ad-hoc Command Provider according to @xep{0050}.
|
||||
*
|
||||
* Derived classes can be registered as Command Providers with the Adhoc object.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
*/
|
||||
class GLOOX_API AdhocCommandProvider
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~AdhocCommandProvider() {}
|
||||
|
||||
/**
|
||||
* This function is called when an Ad-hoc Command needs to be handled.
|
||||
* The callee is responsible for the whole command execution, i.e. session
|
||||
* handling etc.
|
||||
* @param from The sender of the command request.
|
||||
* @param command The name of the command to be executed.
|
||||
* @param sessionID The session ID. Either newly generated or taken from the command.
|
||||
* When responding, its value must be passed to Adhoc::Command's constructor.
|
||||
*/
|
||||
virtual void handleAdhocCommand( const JID& from, const Adhoc::Command& command,
|
||||
const std::string& sessionID ) = 0;
|
||||
|
||||
/**
|
||||
* This function gets called for each registered command when a remote
|
||||
* entity requests the list of available commands.
|
||||
* @param from The requesting entity.
|
||||
* @param command The command's name.
|
||||
* @return @b True if the remote entity is allowed to see the command, @b false if not.
|
||||
* @note The return value of this function does not influence
|
||||
* the execution of a command. That is, you have to
|
||||
* implement additional access control at the execution
|
||||
* stage.
|
||||
* @note This function should not block.
|
||||
*/
|
||||
virtual bool handleAdhocAccessRequest( const JID& from, const std::string& command )
|
||||
{
|
||||
(void)from;
|
||||
(void)command;
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ADHOCCOMMANDPROVIDER_H__
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 ADHOCHANDLER_H__
|
||||
#define ADHOCHANDLER_H__
|
||||
|
||||
#include "adhoc.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A virtual interface for an Ad-hoc Command users according to @xep{0050}.
|
||||
*
|
||||
* Derived classes can be registered with the Adhoc object to receive notifications
|
||||
* about Adhoc Commands remote entities support.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API AdhocHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~AdhocHandler() {}
|
||||
|
||||
/**
|
||||
* This function is called in response to a call to Adhoc::checkSupport().
|
||||
* @param remote The queried remote entity's JID.
|
||||
* @param support Whether the remote entity supports Adhoc Commands.
|
||||
* @param context A user defined context.
|
||||
*/
|
||||
virtual void handleAdhocSupport( const JID& remote, bool support, int context ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called in response to a call to Adhoc::getCommands()
|
||||
* and delivers a list of supported commands.
|
||||
* @param remote The queried remote entity's JID.
|
||||
* @param commands A map of supported commands and their human-readable name.
|
||||
* @param context A user defined context.
|
||||
* The map may be empty.
|
||||
*/
|
||||
virtual void handleAdhocCommands( const JID& remote, const StringMap& commands, int context ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called in response to a call to Adhoc::getCommands() or
|
||||
* Adhoc::checkSupport() or Adhoc::execute() in case the respective request returned
|
||||
* an error.
|
||||
* @param remote The queried remote entity's JID.
|
||||
* @param error The error condition. May be 0.
|
||||
* @param context A user defined context.
|
||||
*/
|
||||
virtual void handleAdhocError( const JID& remote, const Error* error, int context ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called in response to a remote command execution.
|
||||
* @param remote The remote entity's JID.
|
||||
* @param command The command being executed.
|
||||
* @param context A user defined context.
|
||||
*/
|
||||
virtual void handleAdhocExecutionResult( const JID& remote, const Adhoc::Command& command, int context ) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ADHOCHANDLER_H__
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
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__
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
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 "amp.h"
|
||||
#include "tag.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
static const char* conditionValues[] =
|
||||
{
|
||||
"deliver", "expire-at", "match-resource"
|
||||
};
|
||||
|
||||
static const char* actionValues[] =
|
||||
{
|
||||
"alert", "error", "drop", "notify"
|
||||
};
|
||||
|
||||
static const char* deliverValues[] =
|
||||
{
|
||||
"direct", "forward", "gateway", "none", "stored"
|
||||
};
|
||||
|
||||
static const char* matchResourceValues[] =
|
||||
{
|
||||
"any", "exact", "other"
|
||||
};
|
||||
|
||||
static const char* statusValues[] =
|
||||
{
|
||||
"alert", "notify"
|
||||
};
|
||||
|
||||
// ---- AMP::Rule ----
|
||||
AMP::Rule::Rule( DeliverType deliver, ActionType action )
|
||||
: m_condition( ConditionDeliver ), m_deliver( deliver ), m_action( action )
|
||||
{
|
||||
}
|
||||
|
||||
AMP::Rule::Rule( const std::string& date, ActionType action )
|
||||
: m_condition( ConditionExpireAt ), m_expireat( new std::string( date ) ), m_action( action )
|
||||
{
|
||||
}
|
||||
|
||||
AMP::Rule::Rule( MatchResourceType match, ActionType action )
|
||||
: m_condition( ConditionMatchResource ), m_matchresource( match ), m_action( action )
|
||||
{
|
||||
}
|
||||
|
||||
AMP::Rule::Rule( const std::string& condition, const std::string& action,
|
||||
const std::string& value )
|
||||
{
|
||||
m_condition = (ConditionType)util::lookup( condition, conditionValues );
|
||||
m_action = (ActionType)util::lookup( action, actionValues );
|
||||
switch( m_condition )
|
||||
{
|
||||
case ConditionDeliver:
|
||||
m_deliver = (DeliverType)util::lookup( value, deliverValues );
|
||||
break;
|
||||
case ConditionExpireAt:
|
||||
m_expireat = new std::string( value );
|
||||
break;
|
||||
case ConditionMatchResource:
|
||||
m_matchresource = (MatchResourceType)util::lookup( value, matchResourceValues );
|
||||
break;
|
||||
default:
|
||||
case ConditionInvalid: // shouldn't happen
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
AMP::Rule::~Rule()
|
||||
{
|
||||
if( m_condition == ConditionExpireAt && m_expireat )
|
||||
delete m_expireat;
|
||||
}
|
||||
|
||||
Tag* AMP::Rule::tag() const
|
||||
{
|
||||
if( m_condition == ConditionInvalid || m_action == ActionInvalid
|
||||
|| ( m_condition == ConditionDeliver && m_deliver == DeliverInvalid )
|
||||
|| ( m_condition == ConditionMatchResource && m_matchresource == MatchResourceInvalid )
|
||||
|| ( m_condition == ConditionExpireAt && !m_expireat ) )
|
||||
return 0;
|
||||
|
||||
Tag* rule = new Tag( "rule" );
|
||||
rule->addAttribute( "condition", util::lookup( m_condition, conditionValues ) );
|
||||
rule->addAttribute( "action", util::lookup( m_action, actionValues ) );
|
||||
|
||||
switch( m_condition )
|
||||
{
|
||||
case ConditionDeliver:
|
||||
rule->addAttribute( "value", util::lookup( m_deliver, deliverValues ) );
|
||||
break;
|
||||
case ConditionExpireAt:
|
||||
rule->addAttribute( "value", *m_expireat );
|
||||
break;
|
||||
case ConditionMatchResource:
|
||||
rule->addAttribute( "value", util::lookup( m_matchresource, matchResourceValues ) );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
// ---- AMP::Rule ----
|
||||
|
||||
// ---- AMP ----
|
||||
AMP::AMP( bool perhop )
|
||||
: StanzaExtension( ExtAMP ), m_perhop( perhop ), m_status( StatusInvalid )
|
||||
{
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
AMP::AMP( const Tag* tag )
|
||||
: StanzaExtension( ExtAMP ), m_perhop( false )
|
||||
{
|
||||
if( !tag || tag->name() != "amp" || tag->xmlns() != XMLNS_AMP )
|
||||
return;
|
||||
|
||||
const ConstTagList& rules = tag->findTagList( "/amp/rule" );
|
||||
ConstTagList::const_iterator it = rules.begin();
|
||||
for( ; it != rules.end(); ++it )
|
||||
{
|
||||
m_rules.push_back( new Rule( (*it)->findAttribute( "condition" ),
|
||||
(*it)->findAttribute( "action" ),
|
||||
(*it)->findAttribute( "value" ) ) );
|
||||
}
|
||||
|
||||
m_from = tag->findAttribute( "from" );
|
||||
m_to = tag->findAttribute( "to" );
|
||||
m_status = (Status)util::lookup( tag->findAttribute( "status" ), statusValues );
|
||||
if( tag->hasAttribute( "per-hop", "true" ) || tag->hasAttribute( "per-hop", "1" ) )
|
||||
m_perhop = true;
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
AMP::~AMP()
|
||||
{
|
||||
util::clearList( m_rules );
|
||||
}
|
||||
|
||||
void AMP::addRule( const Rule* rule )
|
||||
{
|
||||
if( rule )
|
||||
m_rules.push_back( rule );
|
||||
}
|
||||
|
||||
const std::string& AMP::filterString() const
|
||||
{
|
||||
static const std::string filter = "/message/amp[@xmlns='" + XMLNS_AMP + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* AMP::tag() const
|
||||
{
|
||||
if( !m_valid || !m_rules.size() )
|
||||
return 0;
|
||||
|
||||
Tag* amp = new Tag( "amp" );
|
||||
amp->setXmlns( XMLNS_AMP );
|
||||
if( m_from )
|
||||
amp->addAttribute( "from", m_from.full() );
|
||||
if( m_to )
|
||||
amp->addAttribute( "to", m_to.full() );
|
||||
if( m_status != StatusInvalid )
|
||||
amp->addAttribute( "status", util::lookup( m_status, statusValues ) );
|
||||
if( m_perhop )
|
||||
amp->addAttribute( "per-hop", "true" );
|
||||
RuleList::const_iterator it = m_rules.begin();
|
||||
for( ; it != m_rules.end(); ++it )
|
||||
amp->addChild( (*it)->tag() );
|
||||
|
||||
return amp;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef AMP_H__
|
||||
#define AMP_H__
|
||||
|
||||
#include "stanzaextension.h"
|
||||
#include "jid.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of @xep{0079} (Advanced Message Processing)
|
||||
* as a StanzaExtension.
|
||||
*
|
||||
* XEP Version: 1.2
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @author Vincent Thomasset
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API AMP : public StanzaExtension
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Possible types for a rule's condition.
|
||||
*/
|
||||
enum ConditionType
|
||||
{
|
||||
ConditionDeliver, /**< Ensures (non-)delivery of the message */
|
||||
ConditionExpireAt, /**< Ensures delivery only before a certain time (UTC) */
|
||||
ConditionMatchResource, /**< Ensures delivery only to a specific resource type */
|
||||
ConditionInvalid /**< Invalid condition */
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible actions to take when the corresponding condition is met.
|
||||
*/
|
||||
enum ActionType
|
||||
{
|
||||
|
||||
ActionAlert, /**< Sends back a message stanza with an 'alert' status */
|
||||
ActionError, /**< Sends back a message stanza with an error type */
|
||||
ActionDrop, /**< Silently ignore the message */
|
||||
ActionNotify, /**< Sends back a message stanza with a 'notify' status */
|
||||
ActionInvalid /**< Invalid action */
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible delivery rules.
|
||||
*/
|
||||
enum DeliverType
|
||||
{
|
||||
DeliverDirect, /**< The message would be immediately delivered to the intended
|
||||
* recipient or routed to the next hop. */
|
||||
DeliverForward, /**< The message would be forwarded to another XMPP address or
|
||||
* account. */
|
||||
DeliverGateway, /**< The message would be sent through a gateway to an address
|
||||
* or account on a non-XMPP system. */
|
||||
DeliverNone, /**< The message would not be delivered at all (e.g., because
|
||||
* the intended recipient is offline and message storage is
|
||||
* not enabled). */
|
||||
DeliverStored, /**< The message would be stored offline for later delivery
|
||||
* to the intended recipient. */
|
||||
DeliverInvalid /**< Invalid deliver value */
|
||||
};
|
||||
|
||||
/**
|
||||
* Possible resource matching rules.
|
||||
*/
|
||||
enum MatchResourceType
|
||||
{
|
||||
MatchResourceAny, /**< Destination resource matches any value, effectively
|
||||
* ignoring the intended resource. */
|
||||
MatchResourceExact, /**< Destination resource exactly matches the intended
|
||||
* resource. */
|
||||
MatchResourceOther, /**< Destination resource matches any value except for
|
||||
* the intended resource. */
|
||||
MatchResourceInvalid /**< Invalid match-resource value */
|
||||
};
|
||||
|
||||
/**
|
||||
* Available Stati.
|
||||
*/
|
||||
enum Status
|
||||
{
|
||||
StatusAlert, /**< The message is a reply to a @c Alert rule. */
|
||||
StatusNotify, /**< The message is a reply to a @c Notify rule. */
|
||||
StatusInvalid /**< Invalid status. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Describes an AMP rule.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Rule
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new AMP rule object with a condition of 'deliver'.
|
||||
* @param deliver The delivery type.
|
||||
* @param action The rule's action.
|
||||
*/
|
||||
Rule( DeliverType deliver, ActionType action );
|
||||
|
||||
/**
|
||||
* Creates a new AMP rule object with a condition of 'expire-at'.
|
||||
* @param date The expiry date/time in the format defined in @xep{0082}.
|
||||
* @param action The rule's action.
|
||||
*/
|
||||
Rule( const std::string& date, ActionType action );
|
||||
|
||||
/**
|
||||
* Creates a new AMP rule object with a condition of 'match-resource'.
|
||||
* @param match The match type.
|
||||
* @param action The rule's action.
|
||||
*/
|
||||
Rule( MatchResourceType match, ActionType action );
|
||||
|
||||
/**
|
||||
* Creates a new AMP rule object from the given strings.
|
||||
* @param condition The rule's condition.
|
||||
* @param action The rule's action.
|
||||
* @param value The rule's value.
|
||||
*/
|
||||
Rule( const std::string& condition, const std::string& action,
|
||||
const std::string& value );
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Rule();
|
||||
|
||||
/**
|
||||
* Creates a Tag representation from the current rule.
|
||||
* @return A Tag representation of the rule.
|
||||
*/
|
||||
Tag* tag() const;
|
||||
|
||||
private:
|
||||
ConditionType m_condition;
|
||||
union
|
||||
{
|
||||
DeliverType m_deliver;
|
||||
MatchResourceType m_matchresource;
|
||||
std::string* m_expireat;
|
||||
};
|
||||
ActionType m_action;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* A list of AMP rules.
|
||||
*/
|
||||
typedef std::list<const Rule*> RuleList;
|
||||
|
||||
/**
|
||||
* Constructs a new object.
|
||||
* @param perhop Indicates whether the ruleset should be applied to all hops,
|
||||
* or at the edge servers only. Default: @c false (edge servers only)
|
||||
*/
|
||||
AMP( bool perhop = false );
|
||||
|
||||
/**
|
||||
* Constructs a new object from the given Tag.
|
||||
* @param tag The AMP Tag to parse.
|
||||
*/
|
||||
AMP( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Adds the given rule to the list of rules.
|
||||
* @param rule The rule to add.
|
||||
*/
|
||||
void addRule( const Rule* rule );
|
||||
|
||||
/**
|
||||
* Returns the current list of rules for inspection.
|
||||
* @return The current list of rules.
|
||||
*/
|
||||
const RuleList& rules() const { return m_rules; }
|
||||
|
||||
/**
|
||||
* @brief Virtual Destructor.
|
||||
*/
|
||||
virtual ~AMP();
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new AMP( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
AMP* a = new AMP();
|
||||
a->m_perhop = m_perhop;
|
||||
RuleList::const_iterator it = m_rules.begin();
|
||||
for( ; it != m_rules.end(); ++it )
|
||||
a->m_rules.push_back( new Rule( *(*it) ) );
|
||||
a->m_status = m_status;
|
||||
a->m_from = m_from;
|
||||
a->m_to = m_to;
|
||||
return a;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_perhop;
|
||||
RuleList m_rules;
|
||||
Status m_status;
|
||||
JID m_from;
|
||||
JID m_to;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // AMP_H__
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "annotations.h"
|
||||
#include "clientbase.h"
|
||||
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
Annotations::Annotations( ClientBase* parent )
|
||||
: PrivateXML( parent ),
|
||||
m_annotationsHandler( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
Annotations::~Annotations()
|
||||
{
|
||||
}
|
||||
|
||||
void Annotations::storeAnnotations( const AnnotationsList& aList )
|
||||
{
|
||||
Tag* s = new Tag( "storage", XMLNS, XMLNS_ANNOTATIONS );
|
||||
|
||||
AnnotationsList::const_iterator it = aList.begin();
|
||||
for( ; it != aList.end(); ++it )
|
||||
{
|
||||
Tag* n = new Tag( s, "note", (*it).note );
|
||||
n->addAttribute( "jid", (*it).jid );
|
||||
n->addAttribute( "cdate", (*it).cdate );
|
||||
n->addAttribute( "mdate", (*it).mdate );
|
||||
}
|
||||
|
||||
storeXML( s, this );
|
||||
}
|
||||
|
||||
void Annotations::requestAnnotations()
|
||||
{
|
||||
requestXML( "storage", XMLNS_ANNOTATIONS, this );
|
||||
}
|
||||
|
||||
void Annotations::handlePrivateXML( const Tag* xml )
|
||||
{
|
||||
if( !xml )
|
||||
return;
|
||||
|
||||
AnnotationsList aList;
|
||||
const TagList& l = xml->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
if( (*it)->name() == "note" )
|
||||
{
|
||||
const std::string& jid = (*it)->findAttribute( "jid" );
|
||||
const std::string& note = (*it)->cdata();
|
||||
|
||||
if( !jid.empty() && !note.empty() )
|
||||
{
|
||||
const std::string& cdate = (*it)->findAttribute( "cdate" );
|
||||
const std::string& mdate = (*it)->findAttribute( "mdate" );
|
||||
AnnotationsListItem item;
|
||||
item.jid = jid;
|
||||
item.cdate = cdate;
|
||||
item.mdate = mdate;
|
||||
item.note = note;
|
||||
aList.push_back( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_annotationsHandler )
|
||||
m_annotationsHandler->handleAnnotations( aList );
|
||||
}
|
||||
|
||||
void Annotations::handlePrivateXMLResult( const std::string& /*uid*/, PrivateXMLResult /*result*/ )
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 ANNOTATIONS_H__
|
||||
#define ANNOTATIONS_H__
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include "annotationshandler.h"
|
||||
#include "privatexml.h"
|
||||
#include "privatexmlhandler.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of @xep{0145} (Annotations).
|
||||
*
|
||||
* You can use this class to store arbitrary notes about a roster item on the server
|
||||
* (and to retrieve them later on).
|
||||
* To retrieve all stored annotations for the current user's roster you have to create
|
||||
* a class which inherits from AnnotationsHandler. This handler receives retrieved notes.
|
||||
*
|
||||
* @code
|
||||
* class MyClass : public AnnotationsHandler
|
||||
* {
|
||||
* public:
|
||||
* // ...
|
||||
* void myFuncRetrieve();
|
||||
* void myFuncStore();
|
||||
* void handleAnnotations( const AnnotationsList &aList );
|
||||
*
|
||||
* private:
|
||||
* Annotations* m_notes;
|
||||
* AnnotationsList m_list;
|
||||
* };
|
||||
*
|
||||
* void MyClass::myFuncRetrieve()
|
||||
* {
|
||||
* [...]
|
||||
* m_notes = new Annotations( m_client );
|
||||
* m_notes->requestAnnotations();
|
||||
* }
|
||||
*
|
||||
* void MyClass::handleAnnotations( const AnnotationsList &aList )
|
||||
* {
|
||||
* m_list = aList;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* To store an additional note you have to fetch the currently stored notes first,
|
||||
* add your new note to the list of notes, and transfer them all together back to the
|
||||
* server. This protocol does not support storage of 'deltas', that is, when saving
|
||||
* notes all previously saved notes are overwritten.
|
||||
*
|
||||
* @code
|
||||
* void MyClass::myFuncStore()
|
||||
* {
|
||||
* annotationsListItem item;
|
||||
* item.jid = "me@example.com";
|
||||
* item.cdate = "2006-02-04T15:23:21Z";
|
||||
* item.note = "some guy at example.com";
|
||||
* m_list.push_back( item );
|
||||
*
|
||||
* item.jid = "abc@def.com";
|
||||
* item.cdate = "2006-01-24T15:23:21Z";
|
||||
* item.mdate = "2006-02-04T05:11:46Z";
|
||||
* item.note = "some other guy";
|
||||
* m_list.push_back( item );
|
||||
*
|
||||
* m_notes->storeAnnotations( m_list );
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.3
|
||||
*/
|
||||
class GLOOX_API Annotations : public PrivateXML, public PrivateXMLHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new Annotations object.
|
||||
* @param parent The ClientBase to use for communication.
|
||||
*/
|
||||
Annotations( ClientBase* parent );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Annotations();
|
||||
|
||||
/**
|
||||
* Use this function to store notes (annotations to contacts in a roster) on the server.
|
||||
* Make sure you store the whole set of annotations, not a 'delta'.
|
||||
* @param aList A list of notes to store.
|
||||
*/
|
||||
void storeAnnotations( const AnnotationsList& aList );
|
||||
|
||||
/**
|
||||
* Use this function to initiate retrieval of annotations. Use registerAnnotationsHandler()
|
||||
* to register an object which will receive the lists of notes.
|
||||
*/
|
||||
void requestAnnotations();
|
||||
|
||||
/**
|
||||
* Use this function to register a AnnotationsHandler.
|
||||
* @param ah The AnnotationsHandler which shall receive retrieved notes.
|
||||
*/
|
||||
void registerAnnotationsHandler( AnnotationsHandler* ah )
|
||||
{ m_annotationsHandler = ah; }
|
||||
|
||||
/**
|
||||
* Use this function to un-register the AnnotationsHandler.
|
||||
*/
|
||||
void removeAnnotationsHandler()
|
||||
{ m_annotationsHandler = 0; }
|
||||
|
||||
// reimplemented from PrivateXMLHandler
|
||||
virtual void handlePrivateXML( const Tag* xml );
|
||||
|
||||
// reimplemented from PrivateXMLHandler
|
||||
virtual void handlePrivateXMLResult( const std::string& uid, PrivateXMLResult pxResult );
|
||||
|
||||
private:
|
||||
AnnotationsHandler* m_annotationsHandler;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ANNOTATIONS_H__
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 ANNOTATIONSHANDLER_H__
|
||||
#define ANNOTATIONSHANDLER_H__
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* This describes a single note item.
|
||||
*/
|
||||
struct AnnotationsListItem
|
||||
{
|
||||
std::string jid; /**< The JID of the roster item this note is about */
|
||||
std::string cdate; /**< Creation date of this note. */
|
||||
std::string mdate; /**< Date of last modification of this note. */
|
||||
std::string note; /**< The note. */
|
||||
};
|
||||
|
||||
/**
|
||||
* A list of note items.
|
||||
*/
|
||||
typedef std::list<AnnotationsListItem> AnnotationsList;
|
||||
|
||||
/**
|
||||
* @brief A virtual interface which can be reimplemented to receive notes with help of
|
||||
* the Annotations object.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.3
|
||||
*/
|
||||
class GLOOX_API AnnotationsHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~AnnotationsHandler() {}
|
||||
|
||||
/**
|
||||
* This function is called when notes arrive from the server.
|
||||
* @param aList A list of notes.
|
||||
*/
|
||||
virtual void handleAnnotations( const AnnotationsList &aList ) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // ANNOTATIONSHANDLER_H__
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
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__
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009-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 "attention.h"
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
Attention::Attention()
|
||||
: StanzaExtension( ExtAttention )
|
||||
{
|
||||
}
|
||||
|
||||
Attention::~Attention()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& Attention::filterString() const
|
||||
{
|
||||
static const std::string filter = "/message/attention[@xmlns='" + XMLNS_ATTENTION + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Attention::tag() const
|
||||
{
|
||||
Tag* t = new Tag( "attention" );
|
||||
t->setXmlns( XMLNS_ATTENTION );
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009-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 ATTENTION_H__
|
||||
#define ATTENTION_H__
|
||||
|
||||
|
||||
#include "stanzaextension.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of @xep{0224} as a StanzaExtension.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Attention : public StanzaExtension
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a new object from the given Tag.
|
||||
*/
|
||||
Attention();
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~Attention();
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* /*tag*/ ) const
|
||||
{
|
||||
return new Attention();
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new Attention();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif// ATTENTION_H__
|
|
@ -1,126 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "base64.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace Base64
|
||||
{
|
||||
|
||||
static const std::string alphabet64( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" );
|
||||
static const char pad = '=';
|
||||
static const char np = (char)std::string::npos;
|
||||
static char table64vals[] =
|
||||
{
|
||||
62, np, np, np, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, np, np, np, np, np,
|
||||
np, np, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, np, np, np, np, np, np, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
|
||||
};
|
||||
|
||||
inline char table64( unsigned char c )
|
||||
{
|
||||
return ( c < 43 || c > 122 ) ? np : table64vals[c-43];
|
||||
}
|
||||
|
||||
const std::string encode64( const std::string& input )
|
||||
{
|
||||
std::string encoded;
|
||||
char c;
|
||||
const std::string::size_type length = input.length();
|
||||
|
||||
encoded.reserve( length * 2 );
|
||||
|
||||
for( std::string::size_type i = 0; i < length; ++i )
|
||||
{
|
||||
c = static_cast<char>( ( input[i] >> 2 ) & 0x3f );
|
||||
encoded += alphabet64[c];
|
||||
|
||||
c = static_cast<char>( ( input[i] << 4 ) & 0x3f );
|
||||
if( ++i < length )
|
||||
c = static_cast<char>( c | static_cast<char>( ( input[i] >> 4 ) & 0x0f ) );
|
||||
encoded += alphabet64[c];
|
||||
|
||||
if( i < length )
|
||||
{
|
||||
c = static_cast<char>( ( input[i] << 2 ) & 0x3c );
|
||||
if( ++i < length )
|
||||
c = static_cast<char>( c | static_cast<char>( ( input[i] >> 6 ) & 0x03 ) );
|
||||
encoded += alphabet64[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
++i;
|
||||
encoded += pad;
|
||||
}
|
||||
|
||||
if( i < length )
|
||||
{
|
||||
c = static_cast<char>( input[i] & 0x3f );
|
||||
encoded += alphabet64[c];
|
||||
}
|
||||
else
|
||||
{
|
||||
encoded += pad;
|
||||
}
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
const std::string decode64( const std::string& input )
|
||||
{
|
||||
char c, d;
|
||||
const std::string::size_type length = input.length();
|
||||
std::string decoded;
|
||||
|
||||
decoded.reserve( length );
|
||||
|
||||
for( std::string::size_type i = 0; i < length; ++i )
|
||||
{
|
||||
c = table64(input[i]);
|
||||
++i;
|
||||
d = table64(input[i]);
|
||||
c = static_cast<char>( ( c << 2 ) | ( ( d >> 4 ) & 0x3 ) );
|
||||
decoded += c;
|
||||
if( ++i < length )
|
||||
{
|
||||
c = input[i];
|
||||
if( pad == c )
|
||||
break;
|
||||
|
||||
c = table64(input[i]);
|
||||
d = static_cast<char>( ( ( d << 4 ) & 0xf0 ) | ( ( c >> 2 ) & 0xf ) );
|
||||
decoded += d;
|
||||
}
|
||||
|
||||
if( ++i < length )
|
||||
{
|
||||
d = input[i];
|
||||
if( pad == d )
|
||||
break;
|
||||
|
||||
d = table64(input[i]);
|
||||
c = static_cast<char>( ( ( c << 6 ) & 0xc0 ) | d );
|
||||
decoded += c;
|
||||
}
|
||||
}
|
||||
|
||||
return decoded;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 BASE64_H__
|
||||
#define BASE64_H__
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An implementation of the Base64 data encoding (RFC 3548)
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.8
|
||||
*/
|
||||
namespace Base64
|
||||
{
|
||||
|
||||
/**
|
||||
* Base64-encodes the input according to RFC 3548.
|
||||
* @param input The data to encode.
|
||||
* @return The encoded string.
|
||||
*/
|
||||
GLOOX_API const std::string encode64( const std::string& input );
|
||||
|
||||
/**
|
||||
* Base64-decodes the input according to RFC 3548.
|
||||
* @param input The encoded data.
|
||||
* @return The decoded data.
|
||||
*/
|
||||
GLOOX_API const std::string decode64( const std::string& input );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // BASE64_H__
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 BOOKMARKHANDLER_H__
|
||||
#define BOOKMARKHANDLER_H__
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* This describes a single bookmarked URL item.
|
||||
*/
|
||||
struct BookmarkListItem
|
||||
{
|
||||
std::string name; /**< A human readable name of the bookmark. */
|
||||
std::string url; /**< The URL of the bookmark. */
|
||||
};
|
||||
|
||||
/**
|
||||
* This describes a single bookmarked conference item.
|
||||
*/
|
||||
struct ConferenceListItem
|
||||
{
|
||||
std::string name; /**< A human readable name of the conference room. */
|
||||
std::string jid; /**< The address of the room. */
|
||||
std::string nick; /**< The nick name to use in this room. */
|
||||
std::string password; /**< The password to use for a protected room. */
|
||||
bool autojoin; /**< The conference shall be joined automatically on login. */
|
||||
};
|
||||
|
||||
/**
|
||||
* A list of URL items.
|
||||
*/
|
||||
typedef std::list<BookmarkListItem> BookmarkList;
|
||||
|
||||
/**
|
||||
* A list of conference items.
|
||||
*/
|
||||
typedef std::list<ConferenceListItem> ConferenceList;
|
||||
|
||||
/**
|
||||
* @brief A virtual interface which can be reimplemented to receive bookmarks with help of a
|
||||
* BookmarkStorage object.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.3
|
||||
*/
|
||||
class GLOOX_API BookmarkHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~BookmarkHandler() {}
|
||||
|
||||
/**
|
||||
* This function is called when bookmarks arrive from the server.
|
||||
* @param bList A list of URL bookmarks.
|
||||
* @param cList A list of conference bookmarks.
|
||||
*/
|
||||
virtual void handleBookmarks( const BookmarkList &bList, const ConferenceList &cList ) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOKMARKHANDLER_H__
|
|
@ -1,118 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "bookmarkstorage.h"
|
||||
#include "clientbase.h"
|
||||
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
BookmarkStorage::BookmarkStorage( ClientBase* parent )
|
||||
: PrivateXML( parent ),
|
||||
m_bookmarkHandler( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
BookmarkStorage::~BookmarkStorage()
|
||||
{
|
||||
}
|
||||
|
||||
void BookmarkStorage::storeBookmarks( const BookmarkList& bList, const ConferenceList& cList )
|
||||
{
|
||||
Tag* s = new Tag( "storage" );
|
||||
s->addAttribute( XMLNS, XMLNS_BOOKMARKS );
|
||||
|
||||
BookmarkList::const_iterator itb = bList.begin();
|
||||
for( ; itb != bList.end(); ++itb )
|
||||
{
|
||||
Tag* i = new Tag( s, "url", "name", (*itb).name );
|
||||
i->addAttribute( "url", (*itb).url );
|
||||
}
|
||||
|
||||
ConferenceList::const_iterator itc = cList.begin();
|
||||
for( ; itc != cList.end(); ++itc )
|
||||
{
|
||||
Tag* i = new Tag( s, "conference", "name", (*itc).name );
|
||||
i->addAttribute( "jid", (*itc).jid );
|
||||
i->addAttribute( "autojoin", (*itc).autojoin ? "true" : "false" );
|
||||
|
||||
new Tag( i, "nick", (*itc).nick );
|
||||
new Tag( i, "password", (*itc).password );
|
||||
}
|
||||
|
||||
storeXML( s, this );
|
||||
}
|
||||
|
||||
void BookmarkStorage::requestBookmarks()
|
||||
{
|
||||
requestXML( "storage", XMLNS_BOOKMARKS, this );
|
||||
}
|
||||
|
||||
void BookmarkStorage::handlePrivateXML( const Tag* xml )
|
||||
{
|
||||
if( !xml )
|
||||
return;
|
||||
|
||||
BookmarkList bList;
|
||||
ConferenceList cList;
|
||||
const TagList& l = xml->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
if( (*it)->name() == "url" )
|
||||
{
|
||||
const std::string& url = (*it)->findAttribute( "url" );
|
||||
const std::string& name = (*it)->findAttribute( "name" );
|
||||
|
||||
if( !url.empty() && !name.empty() )
|
||||
{
|
||||
BookmarkListItem item;
|
||||
item.url = url;
|
||||
item.name = name;
|
||||
bList.push_back( item );
|
||||
}
|
||||
}
|
||||
else if( (*it)->name() == "conference" )
|
||||
{
|
||||
const std::string& jid = (*it)->findAttribute( "jid" );
|
||||
const std::string& name = (*it)->findAttribute( "name" );
|
||||
|
||||
if( !jid.empty() && !name.empty() )
|
||||
{
|
||||
const std::string& join = (*it)->findAttribute( "autojoin" );
|
||||
ConferenceListItem item;
|
||||
item.jid = jid;
|
||||
item.name = name;
|
||||
const Tag* nick = (*it)->findChild( "nick" );
|
||||
if( nick )
|
||||
item.nick = nick->cdata();
|
||||
const Tag* pwd = (*it)->findChild( "password" );
|
||||
if( pwd )
|
||||
item.password = pwd->cdata();
|
||||
item.autojoin = ( join == "true" || join == "1" );
|
||||
cList.push_back( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( m_bookmarkHandler )
|
||||
m_bookmarkHandler->handleBookmarks( bList, cList );
|
||||
}
|
||||
|
||||
void BookmarkStorage::handlePrivateXMLResult( const std::string& /*uid*/, PrivateXMLResult /*result*/ )
|
||||
{
|
||||
}
|
||||
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 BOOKMARKSTORAGE_H__
|
||||
#define BOOKMARKSTORAGE_H__
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include "bookmarkhandler.h"
|
||||
#include "privatexml.h"
|
||||
#include "privatexmlhandler.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of @xep{0048} (Bookmark Storage).
|
||||
*
|
||||
* You can use this class to store bookmarks to multi-user chat rooms or ordinary URLs
|
||||
* on the server (and to retrieve them later on).
|
||||
* To retrieve all stored bookmarks for the current user you have to create a class which
|
||||
* inherits from BookmarkHandler. This handler receives retrieved bookmarks.
|
||||
*
|
||||
* @code
|
||||
* class MyClass : public BookmarkHandler
|
||||
* {
|
||||
* public:
|
||||
* // ...
|
||||
* void myFuncRetrieve();
|
||||
* void myFuncStore();
|
||||
* void handleBookmarks( const BookmarkList &bList, const ConferenceList &cList );
|
||||
*
|
||||
* private:
|
||||
* BookmarkStorage* m_bs;
|
||||
* BookmarkList m_bList;
|
||||
* ConferenceList m_cList;
|
||||
* };
|
||||
*
|
||||
* void MyClass::myFuncRetrieve()
|
||||
* {
|
||||
* m_bs = new BookmarkStorage( m_client );
|
||||
* m_bs->requestBookmarks();
|
||||
* }
|
||||
*
|
||||
* void MyClass::handleBookmarks( const BookmarkList &bList, const ConferenceList &cList )
|
||||
* {
|
||||
* m_bList = bList;
|
||||
* m_cList = cList;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* To store additional bookmarks you have to fetch the currently stored ones first,
|
||||
* add your new bookmark to the list, and transfer them all together back to the
|
||||
* server. This protocol does not support storage of 'deltas', that is, when saving
|
||||
* bookmarks all previously saved bookmarks are overwritten.
|
||||
*
|
||||
* @code
|
||||
* void MyClass::myFuncStore()
|
||||
* {
|
||||
* BookmarkListItem bi;
|
||||
* bi.url = "http://www.jabber.org";
|
||||
* bi.name = "my favourite IM protocol";
|
||||
* m_bList.push_back( bi );
|
||||
*
|
||||
* conferenceListItem ci
|
||||
* ci.name = "jabber/xmpp development room";
|
||||
* ci.jid = "jdev@conference.jabber.org";
|
||||
* ci.nick = "myNick";
|
||||
* ci.password = EmptyString;
|
||||
* ci.autojoin = true;
|
||||
* m_cList.push_back( ci );
|
||||
*
|
||||
* m_bs->storeBookmarks( m_bList, m_cList );
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.3
|
||||
*/
|
||||
class GLOOX_API BookmarkStorage : public PrivateXML, public PrivateXMLHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new BookmarkStorage object.
|
||||
* @param parent The ClientBase to use for communication.
|
||||
*/
|
||||
BookmarkStorage( ClientBase* parent );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~BookmarkStorage();
|
||||
|
||||
/**
|
||||
* Use this function to store a number of URL and conference bookmarks on the server.
|
||||
* Make sure you store the whole set of bookmarks, not a 'delta'.
|
||||
* @param bList A list of URLs to store.
|
||||
* @param cList A list of conferences to store.
|
||||
*/
|
||||
void storeBookmarks( const BookmarkList& bList, const ConferenceList& cList );
|
||||
|
||||
/**
|
||||
* Use this function to initiate retrieval of bookmarks. Use registerBookmarkHandler()
|
||||
* to register an object which will receive the lists of bookmarks.
|
||||
*/
|
||||
void requestBookmarks();
|
||||
|
||||
/**
|
||||
* Use this function to register a BookmarkHandler.
|
||||
* @param bmh The BookmarkHandler which shall receive retrieved bookmarks.
|
||||
*/
|
||||
void registerBookmarkHandler( BookmarkHandler* bmh )
|
||||
{ m_bookmarkHandler = bmh; }
|
||||
|
||||
/**
|
||||
* Use this function to un-register the BookmarkHandler.
|
||||
*/
|
||||
void removeBookmarkHandler()
|
||||
{ m_bookmarkHandler = 0; }
|
||||
|
||||
// reimplemented from PrivateXMLHandler
|
||||
virtual void handlePrivateXML( const Tag* xml );
|
||||
|
||||
// reimplemented from PrivateXMLHandler
|
||||
virtual void handlePrivateXMLResult( const std::string& uid, PrivateXMLResult pxResult );
|
||||
|
||||
private:
|
||||
BookmarkHandler* m_bookmarkHandler;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BOOKMARKSTORAGE_H__
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BYTESTREAM_H__
|
||||
#define BYTESTREAM_H__
|
||||
|
||||
#include "jid.h"
|
||||
#include "logsink.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class BytestreamDataHandler;
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a single bytestream.
|
||||
*
|
||||
* Used as a base class for InBand Bytestreams as well as SOCKS5 Bytestreams.
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Bytestream
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Available stream types.
|
||||
*/
|
||||
enum StreamType
|
||||
{
|
||||
S5B, /**< SOCKS5 Bytestream */
|
||||
IBB /**< In-Band Bytestream */
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new Bytestream.
|
||||
* @param type The stream type.
|
||||
* @param logInstance A Logsink to use for logging. Obtain it from ClientBase::logInstance().
|
||||
* @param initiator The initiator of the stream (usually the sender).
|
||||
* @param target The target of the stream (usually the receiver).
|
||||
* @param sid The stream's ID.
|
||||
*/
|
||||
Bytestream( StreamType type, LogSink& logInstance, const JID& initiator, const JID& target,
|
||||
const std::string& sid )
|
||||
: m_handler( 0 ), m_logInstance( logInstance ), m_initiator( initiator ), m_target( target ),
|
||||
m_type( type ), m_sid( sid ), m_open( false )
|
||||
{}
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Bytestream() {}
|
||||
|
||||
/**
|
||||
* Returns whether the bytestream is open, that is, accepted by both parties and ready
|
||||
* to send/receive data.
|
||||
* @return Whether or not the bytestream is open.
|
||||
*/
|
||||
bool isOpen() const { return m_open; }
|
||||
|
||||
/**
|
||||
* This function starts the connection process.
|
||||
* @return @b True if a connection to a remote entity could be established, @b false
|
||||
* otherwise.
|
||||
* @note If @b false is returned you should pass this Bytestream object
|
||||
* to SIProfileFT::dispose() for deletion.
|
||||
* @note Make sure you have a BytestreamDataHandler registered (using
|
||||
* registerBytestreamDataHandler()) before calling this function.
|
||||
*/
|
||||
virtual bool connect() = 0;
|
||||
|
||||
/**
|
||||
* Closes the bytestream.
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
|
||||
/**
|
||||
* Use this function to send a chunk of data over an open bytestream.
|
||||
* If the stream is not open or has been closed again
|
||||
* (by the remote entity or locally), nothing is sent and @b false is returned.
|
||||
* This function does any base64 encoding for you, if necessary.
|
||||
* @param data The block of data to send.
|
||||
* @return @b True if the data has been sent (no guarantee of receipt), @b false
|
||||
* in case of an error.
|
||||
*/
|
||||
virtual bool send( const std::string& data ) = 0;
|
||||
|
||||
/**
|
||||
* Call this function repeatedly to receive data. You should even do this
|
||||
* if you use the bytestream to merely @b send data. May be a NOOP, depending on the actual
|
||||
* stream type.
|
||||
* @param timeout The timeout to use for select in microseconds. Default of -1 means blocking.
|
||||
* @return The state of the connection.
|
||||
*/
|
||||
virtual ConnectionError recv( int timeout = -1 ) = 0;
|
||||
|
||||
/**
|
||||
* Lets you retrieve the stream's ID.
|
||||
* @return The stream's ID.
|
||||
*/
|
||||
const std::string& sid() const { return m_sid; }
|
||||
|
||||
/**
|
||||
* Returns the stream's type.
|
||||
* @return The stream's type.
|
||||
*/
|
||||
StreamType type() const { return m_type; }
|
||||
|
||||
/**
|
||||
* Returns the target entity's JID. If this bytestream is remote-initiated, this is
|
||||
* the local JID. If it is local-initiated, this is the remote entity's JID.
|
||||
* @return The target's JID.
|
||||
*/
|
||||
const JID& target() const { return m_target; }
|
||||
|
||||
/**
|
||||
* Returns the initiating entity's JID. If this bytestream is remote-initiated, this is
|
||||
* the remote entity's JID. If it is local-initiated, this is the local JID.
|
||||
* @return The initiator's JID.
|
||||
*/
|
||||
const JID& initiator() const { return m_initiator; }
|
||||
|
||||
/**
|
||||
* Use this function to register an object that will receive any notifications from
|
||||
* the Bytestream instance. Only one BytestreamDataHandler can be registered
|
||||
* at any one time.
|
||||
* @param bdh The BytestreamDataHandler-derived object to receive notifications.
|
||||
*/
|
||||
void registerBytestreamDataHandler( BytestreamDataHandler* bdh )
|
||||
{ m_handler = bdh; }
|
||||
|
||||
/**
|
||||
* Removes the registered BytestreamDataHandler.
|
||||
*/
|
||||
void removeBytestreamDataHandler()
|
||||
{ m_handler = 0; }
|
||||
|
||||
protected:
|
||||
/** A handler for incoming data and open/close events. */
|
||||
BytestreamDataHandler* m_handler;
|
||||
|
||||
/** A LogSink instance to use for logging. */
|
||||
const LogSink& m_logInstance;
|
||||
|
||||
/** The initiator's JID. */
|
||||
const JID m_initiator;
|
||||
|
||||
/** The target's JID. */
|
||||
const JID m_target;
|
||||
|
||||
/** The stream type. */
|
||||
StreamType m_type;
|
||||
|
||||
/** The stream ID. */
|
||||
std::string m_sid;
|
||||
|
||||
/** Indicates whether or not the stream is open. */
|
||||
bool m_open;
|
||||
|
||||
private:
|
||||
Bytestream& operator=( const Bytestream& );
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BYTESTREAM_H__
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BYTESTREAMDATAHANDLER_H__
|
||||
#define BYTESTREAMDATAHANDLER_H__
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Bytestream;
|
||||
class IQ;
|
||||
|
||||
/**
|
||||
* @brief A virtual interface that allows implementors to receive data
|
||||
* sent over a SOCKS5 Bytestream as defined in @xep{0066}, or an In-Band Bytestream
|
||||
* as defined in @xep{0047}. You'll also need it for sending of data.
|
||||
*
|
||||
* An BytestreamDataHandler is registered with a Bytestream.
|
||||
*
|
||||
* See SIProfileFT for more information regarding file transfer.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API BytestreamDataHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~BytestreamDataHandler() {}
|
||||
|
||||
/**
|
||||
* Reimplement this function to receive data which is sent over the bytestream.
|
||||
* The data received here is (probably) only a single chunk of the complete data (depending
|
||||
* on the amount of data you want to send).
|
||||
* @param bs The bytestream.
|
||||
* @param data The actual stream payload.
|
||||
*/
|
||||
virtual void handleBytestreamData( Bytestream* bs, const std::string& data ) = 0;
|
||||
|
||||
/**
|
||||
* Notifies about an error occuring while using a bytestream.
|
||||
* When this handler is called the stream has already been closed.
|
||||
* @param bs The bytestream.
|
||||
* @param iq The error stanza.
|
||||
*/
|
||||
virtual void handleBytestreamError( Bytestream* bs, const IQ& iq ) = 0;
|
||||
|
||||
/**
|
||||
* Notifies the handler that the given bytestream has been acknowledged
|
||||
* and is ready to send/receive data.
|
||||
* @param bs The opened bytestream.
|
||||
*/
|
||||
virtual void handleBytestreamOpen( Bytestream* bs ) = 0;
|
||||
|
||||
/**
|
||||
* Notifies the handler that the given bytestream has been closed.
|
||||
* @param bs The closed bytestream.
|
||||
*/
|
||||
virtual void handleBytestreamClose( Bytestream* bs ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BYTESTREAMDATAHANDLER_H__
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef BYTESTREAMHANDLER_H__
|
||||
#define BYTESTREAMHANDLER_H__
|
||||
|
||||
#include "macros.h"
|
||||
#include "jid.h"
|
||||
#include "bytestream.h"
|
||||
#include "iq.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief A virtual interface that allows to receive new incoming Bytestream requests
|
||||
* from remote entities.
|
||||
*
|
||||
* You should not need to use this interface directly.
|
||||
*
|
||||
* See SIProfileFT on how to implement file transfer in general.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API BytestreamHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~BytestreamHandler() {}
|
||||
|
||||
/**
|
||||
* Notifies the implementor of a new incoming bytestream request.
|
||||
* You have to call either
|
||||
* BytestreamManager::acceptBytestream() or
|
||||
* BytestreamManager::rejectBytestream(), to accept or reject the bytestream
|
||||
* request, respectively.
|
||||
* @param sid The bytestream's id, to be passed to BytestreamManager::acceptBytestream()
|
||||
* and BytestreamManager::rejectBytestream(), respectively.
|
||||
* @param from The remote initiator of the bytestream request.
|
||||
*/
|
||||
virtual void handleIncomingBytestreamRequest( const std::string& sid, const JID& from ) = 0;
|
||||
|
||||
/**
|
||||
* Notifies the implementor of a new incoming bytestream. The bytestream is not yet ready to
|
||||
* send data.
|
||||
* To initialize the bytestream and to prepare it for data transfer, register a
|
||||
* BytestreamDataHandler with it and call its connect() method.
|
||||
* To not block your application while the data transfer lasts, you most
|
||||
* likely want to put the bytestream into its own thread or process (before calling connect() on it).
|
||||
* It is safe to do so without additional synchronization.
|
||||
* When you are finished using the bytestream, use SIProfileFT::dispose() to get rid of it.
|
||||
* @param bs The bytestream.
|
||||
*/
|
||||
virtual void handleIncomingBytestream( Bytestream* bs ) = 0;
|
||||
|
||||
/**
|
||||
* Notifies the implementor of successful establishing of an outgoing bytestream request.
|
||||
* The stream has been accepted by the remote entity and is ready to send data.
|
||||
* The BytestreamHandler does @b not become the owner of the Bytestream object.
|
||||
* Use SIProfileFT::dispose() to get rid of the bytestream object after it has been closed.
|
||||
* @param bs The new bytestream.
|
||||
*/
|
||||
virtual void handleOutgoingBytestream( Bytestream* bs ) = 0;
|
||||
|
||||
/**
|
||||
* Notifies the handler of errors occuring when a bytestream was requested.
|
||||
* For example, if the remote entity does not implement SOCKS5 bytestreams.
|
||||
* @param iq The error stanza.
|
||||
* @param sid The request's SID.
|
||||
*/
|
||||
virtual void handleBytestreamError( const IQ& iq, const std::string& sid ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BYTESTREAMHANDLER_H__
|
|
@ -1,183 +0,0 @@
|
|||
/*
|
||||
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 "capabilities.h"
|
||||
|
||||
#include "base64.h"
|
||||
#include "disco.h"
|
||||
#include "dataform.h"
|
||||
#include "sha.h"
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
Capabilities::Capabilities( Disco* disco )
|
||||
: StanzaExtension( ExtCaps ), m_disco( disco ), m_node( GLOOX_CAPS_NODE ),
|
||||
m_hash( "sha-1" ), m_valid( false )
|
||||
{
|
||||
if( m_disco )
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
Capabilities::Capabilities( const Tag* tag )
|
||||
: StanzaExtension( ExtCaps ), m_disco( 0 ), m_valid( false )
|
||||
{
|
||||
if( !tag || tag->name() != "c" || !tag->hasAttribute( XMLNS, XMLNS_CAPS )
|
||||
|| !tag->hasAttribute( "node" ) || !tag->hasAttribute( "ver" ) )
|
||||
return;
|
||||
|
||||
m_node = tag->findAttribute( "node" );
|
||||
m_ver = tag->findAttribute( "ver" );
|
||||
m_hash = tag->findAttribute( "hash" );
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
Capabilities::~Capabilities()
|
||||
{
|
||||
if( m_disco )
|
||||
m_disco->removeNodeHandlers( const_cast<Capabilities*>( this ) );
|
||||
}
|
||||
|
||||
const std::string Capabilities::ver() const
|
||||
{
|
||||
if( !m_disco )
|
||||
return m_ver;
|
||||
|
||||
SHA sha;
|
||||
sha.feed( generate( m_disco->identities(), m_disco->features( true ), m_disco->form() ) );
|
||||
const std::string& hash = Base64::encode64( sha.binary() );
|
||||
m_disco->removeNodeHandlers( const_cast<Capabilities*>( this ) );
|
||||
m_disco->registerNodeHandler( const_cast<Capabilities*>( this ), m_node + '#' + hash );
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::string Capabilities::generate( const Disco::IdentityList& il, const StringList& features, const DataForm* form )
|
||||
{
|
||||
StringList sl;
|
||||
Disco::IdentityList::const_iterator it = il.begin();
|
||||
for( ; it != il.end(); ++it )
|
||||
{
|
||||
std::string id = (*it)->category();
|
||||
id += '/';
|
||||
id += (*it)->type();
|
||||
id += '/';
|
||||
// FIXME add xml:lang caps here. see XEP-0115 Section 5
|
||||
id += '/';
|
||||
id += (*it)->name();
|
||||
sl.push_back( id );
|
||||
}
|
||||
sl.sort();
|
||||
|
||||
std::string s;
|
||||
StringList::const_iterator it2 = sl.begin();
|
||||
for( ; it2 != sl.end(); ++it2 )
|
||||
{
|
||||
s += (*it2);
|
||||
s += '<';
|
||||
}
|
||||
|
||||
StringList f = features;
|
||||
f.sort();
|
||||
it2 = f.begin();
|
||||
for( ; it2 != f.end(); ++it2 )
|
||||
{
|
||||
s += (*it2);
|
||||
s += '<';
|
||||
}
|
||||
|
||||
if( form )
|
||||
{
|
||||
DataForm::FieldList::const_iterator it3 = form->fields().begin();
|
||||
typedef std::map<std::string, StringList> MapSSL;
|
||||
|
||||
MapSSL m;
|
||||
for( ; it3 != form->fields().end(); ++it3 )
|
||||
{
|
||||
if( (*it3)->name() == "FORM_TYPE" )
|
||||
{
|
||||
s += (*it3)->value();
|
||||
s += '<';
|
||||
}
|
||||
else
|
||||
m.insert( std::make_pair( (*it3)->name(), (*it3)->values() ) );
|
||||
}
|
||||
|
||||
MapSSL::iterator it4 = m.begin();
|
||||
for( ; it4 != m.end(); ++it4 )
|
||||
{
|
||||
s += it4->first;
|
||||
s += '<';
|
||||
it2 = it4->second.begin();
|
||||
for( ; it2 != it4->second.end(); ++it2 )
|
||||
{
|
||||
s += (*it2);
|
||||
s += '<';
|
||||
}
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string Capabilities::generate( const Disco::Info* info )
|
||||
{
|
||||
return info ? generate( info->identities(), info->features(), info->form() ) : EmptyString;
|
||||
}
|
||||
|
||||
std::string Capabilities::generate( const Disco* disco )
|
||||
{
|
||||
return disco ? generate( disco->identities(), disco->features(), disco->form() ) : EmptyString;
|
||||
}
|
||||
|
||||
const std::string& Capabilities::filterString() const
|
||||
{
|
||||
static const std::string filter = "/presence/c[@xmlns='" + XMLNS_CAPS + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Capabilities::tag() const
|
||||
{
|
||||
if( !m_valid || m_node.empty() )
|
||||
return 0;
|
||||
|
||||
Tag* t = new Tag( "c" );
|
||||
t->setXmlns( XMLNS_CAPS );
|
||||
t->addAttribute( "hash", m_hash );
|
||||
t->addAttribute( "node", m_node );
|
||||
t->addAttribute( "ver", ver() );
|
||||
return t;
|
||||
}
|
||||
|
||||
StringList Capabilities::handleDiscoNodeFeatures( const JID&, const std::string& )
|
||||
{
|
||||
return m_disco->features();
|
||||
}
|
||||
|
||||
Disco::IdentityList Capabilities::handleDiscoNodeIdentities( const JID&, const std::string& )
|
||||
{
|
||||
const Disco::IdentityList& il = m_disco->identities();
|
||||
Disco::IdentityList ret;
|
||||
Disco::IdentityList::const_iterator it = il.begin();
|
||||
for( ; it != il.end(); ++it )
|
||||
{
|
||||
ret.push_back( new Disco::Identity( *(*it) ) );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Disco::ItemList Capabilities::handleDiscoNodeItems( const JID&, const JID&, const std::string& )
|
||||
{
|
||||
return Disco::ItemList();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
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 CAPABILITIES_H__
|
||||
#define CAPABILITIES_H__
|
||||
|
||||
#include "disconodehandler.h"
|
||||
#include "stanzaextension.h"
|
||||
#include "tag.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Disco;
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of @xep{0115} (Entity Capabilities).
|
||||
*
|
||||
* XEP Version: 1.5-15
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Capabilities : public StanzaExtension, public DiscoNodeHandler
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a new object and fills it according to the parameters.
|
||||
* @param disco The current Client's Disco object.
|
||||
*/
|
||||
Capabilities( Disco* disco );
|
||||
|
||||
/**
|
||||
* Constructs a new object from the given Tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
Capabilities( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~Capabilities();
|
||||
|
||||
/**
|
||||
* Returns the client's identifying node.
|
||||
* @return The node.
|
||||
*/
|
||||
const std::string& node() const { return m_node; }
|
||||
|
||||
/**
|
||||
* Sets the client's identifying node.
|
||||
* @param node The node.
|
||||
*/
|
||||
void setNode( const std::string& node ) { m_node = node; }
|
||||
|
||||
/**
|
||||
* Returns the client's identifying ver string.
|
||||
* @return The ver string.
|
||||
*/
|
||||
const std::string ver() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Capabilities( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new Capabilities( *this );
|
||||
}
|
||||
|
||||
// reimplemented from DiscoNodeHandler
|
||||
virtual StringList handleDiscoNodeFeatures( const JID& from, const std::string& node );
|
||||
|
||||
// reimplemented from DiscoNodeHandler
|
||||
virtual Disco::IdentityList handleDiscoNodeIdentities( const JID& from,
|
||||
const std::string& node );
|
||||
|
||||
// reimplemented from DiscoNodeHandler
|
||||
virtual Disco::ItemList handleDiscoNodeItems( const JID& from, const JID& to,
|
||||
const std::string& node = EmptyString );
|
||||
|
||||
private:
|
||||
/**
|
||||
* Returns the hash function used for creating the caps info.
|
||||
* @return The current hash function's name.
|
||||
*/
|
||||
const std::string& hash() const { return m_hash; }
|
||||
|
||||
/**
|
||||
* Use this function to set the hash function to use.
|
||||
* @param hash The hash function.
|
||||
* @todo Convert to using an enum and make public.
|
||||
*/
|
||||
void setHash( const std::string& hash ) { m_hash = hash; }
|
||||
|
||||
static std::string generate( const Disco::IdentityList& identities,
|
||||
const StringList& features, const DataForm* form = 0 );
|
||||
static std::string generate( const Disco::Info* info );
|
||||
static std::string generate( const Disco* disco );
|
||||
|
||||
Disco* m_disco;
|
||||
std::string m_node;
|
||||
std::string m_hash;
|
||||
std::string m_ver;
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CAPABILITIES_H__
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
||||
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
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__
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
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 "chatstate.h"
|
||||
#include "tag.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/* chat state type values */
|
||||
static const char* stateValues [] = {
|
||||
"active",
|
||||
"composing",
|
||||
"paused",
|
||||
"inactive",
|
||||
"gone"
|
||||
};
|
||||
|
||||
static inline ChatStateType chatStateType( const std::string& type )
|
||||
{
|
||||
return (ChatStateType)util::lookup2( type, stateValues );
|
||||
}
|
||||
|
||||
ChatState::ChatState( const Tag* tag )
|
||||
: StanzaExtension( ExtChatState ),
|
||||
m_state( ChatStateInvalid )
|
||||
{
|
||||
if( tag )
|
||||
m_state = chatStateType( tag->name() );
|
||||
}
|
||||
|
||||
const std::string& ChatState::filterString() const
|
||||
{
|
||||
static const std::string filter =
|
||||
"/message/active[@xmlns='" + XMLNS_CHAT_STATES + "']"
|
||||
"|/message/composing[@xmlns='" + XMLNS_CHAT_STATES + "']"
|
||||
"|/message/paused[@xmlns='" + XMLNS_CHAT_STATES + "']"
|
||||
"|/message/inactive[@xmlns='" + XMLNS_CHAT_STATES + "']"
|
||||
"|/message/gone[@xmlns='" + XMLNS_CHAT_STATES + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* ChatState::tag() const
|
||||
{
|
||||
if( m_state == ChatStateInvalid )
|
||||
return 0;
|
||||
|
||||
return new Tag( util::lookup2( m_state, stateValues ), XMLNS, XMLNS_CHAT_STATES );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
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 CHATSTATE_H__
|
||||
#define CHATSTATE_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "stanzaextension.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief An implementation of Chat State Notifications (@xep{0085}) as a StanzaExtension.
|
||||
*
|
||||
* @author Vincent Thomasset
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API ChatState : public StanzaExtension
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructs a new object from the given Tag.
|
||||
* @param tag A Tag to parse.
|
||||
*/
|
||||
ChatState( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Constructs a new object of the given type.
|
||||
* @param state The chat state.
|
||||
*/
|
||||
ChatState( ChatStateType state )
|
||||
: StanzaExtension( ExtChatState ), m_state( state )
|
||||
{}
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~ChatState() {}
|
||||
|
||||
/**
|
||||
* Returns the object's state.
|
||||
* @return The object's state.
|
||||
*/
|
||||
ChatStateType state() const { return m_state; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new ChatState( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new ChatState( *this );
|
||||
}
|
||||
|
||||
private:
|
||||
ChatStateType m_state;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CHATSTATE_H__
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "chatstatefilter.h"
|
||||
#include "chatstatehandler.h"
|
||||
#include "messageeventhandler.h"
|
||||
#include "messagesession.h"
|
||||
#include "message.h"
|
||||
#include "chatstate.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ChatStateFilter::ChatStateFilter( MessageSession* parent )
|
||||
: MessageFilter( parent ), m_chatStateHandler( 0 ), m_lastSent( ChatStateGone ),
|
||||
m_enableChatStates( true )
|
||||
{
|
||||
}
|
||||
|
||||
ChatStateFilter::~ChatStateFilter()
|
||||
{
|
||||
}
|
||||
|
||||
void ChatStateFilter::filter( Message& msg )
|
||||
{
|
||||
if( m_enableChatStates && m_chatStateHandler )
|
||||
{
|
||||
const ChatState* state = msg.findExtension<ChatState>( ExtChatState );
|
||||
|
||||
m_enableChatStates = state && state->state() != ChatStateInvalid;
|
||||
if( m_enableChatStates && msg.body().empty() )
|
||||
m_chatStateHandler->handleChatState( msg.from(), state->state() );
|
||||
}
|
||||
}
|
||||
|
||||
void ChatStateFilter::setChatState( ChatStateType state )
|
||||
{
|
||||
if( !m_enableChatStates || state == m_lastSent || state == ChatStateInvalid )
|
||||
return;
|
||||
|
||||
Message m( Message::Chat, m_parent->target() );
|
||||
m.addExtension( new ChatState( state ) );
|
||||
|
||||
m_lastSent = state;
|
||||
|
||||
send( m );
|
||||
}
|
||||
|
||||
void ChatStateFilter::decorate( Message& msg )
|
||||
{
|
||||
if( m_enableChatStates )
|
||||
msg.addExtension( new ChatState( ChatStateActive ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 CHATSTATEFILTER_H__
|
||||
#define CHATSTATEFILTER_H__
|
||||
|
||||
#include "messagefilter.h"
|
||||
#include "gloox.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
class ChatStateHandler;
|
||||
class MessageSession;
|
||||
class Message;
|
||||
|
||||
/**
|
||||
* @brief This class adds Chat State Notifications (@xep{0085}) support to a MessageSession.
|
||||
*
|
||||
* This implementation of Chat States is fully transparent to the user of the class.
|
||||
* If the remote entity does not request chat states, ChatStateFilter will not send
|
||||
* any, even if the user requests it. (This is required by the protocol specification.)
|
||||
* You MUST annouce this capability by use of Disco (associated namespace is XMLNS_CHAT_STATES).
|
||||
* (This is also required by the protocol specification.)
|
||||
*
|
||||
* @note You must register ChatState as a StanzaExtension by calling
|
||||
* ClientBase::registerStanzaExtension() for notifications to work.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.8
|
||||
*/
|
||||
class GLOOX_API ChatStateFilter : public MessageFilter
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Contstructs a new Chat State filter for a MessageSession.
|
||||
* @param parent The MessageSession to decorate.
|
||||
*/
|
||||
ChatStateFilter( MessageSession* parent );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~ChatStateFilter();
|
||||
|
||||
/**
|
||||
* Use this function to set a chat state as defined in @xep{0085}.
|
||||
* @note The Spec states that Chat States shall not be sent to an entity
|
||||
* which did not request them. Reasonable effort is taken in this function to
|
||||
* avoid spurious state sending. You should be safe to call this even if Message
|
||||
* Events were not requested by the remote entity. However,
|
||||
* calling setChatState( CHAT_STATE_COMPOSING ) for every keystroke still is
|
||||
* discouraged. ;)
|
||||
* @param state The state to set.
|
||||
*/
|
||||
void setChatState( ChatStateType state );
|
||||
|
||||
/**
|
||||
* The ChatStateHandler registered here will receive Chat States according
|
||||
* to @xep{0085}.
|
||||
* @param csh The ChatStateHandler to register.
|
||||
*/
|
||||
void registerChatStateHandler( ChatStateHandler* csh )
|
||||
{ m_chatStateHandler = csh; }
|
||||
|
||||
/**
|
||||
* This function clears the internal pointer to the ChatStateHandler.
|
||||
* Chat States will not be delivered anymore after calling this function until another
|
||||
* ChatStateHandler is registered.
|
||||
*/
|
||||
void removeChatStateHandler()
|
||||
{ m_chatStateHandler = 0; }
|
||||
|
||||
// reimplemented from MessageFilter
|
||||
virtual void decorate( Message& msg );
|
||||
|
||||
// reimplemented from MessageFilter
|
||||
virtual void filter( Message& msg );
|
||||
|
||||
protected:
|
||||
/** A handler for incoming chat state changes. */
|
||||
ChatStateHandler* m_chatStateHandler;
|
||||
|
||||
/** Holds the state sent last. */
|
||||
ChatStateType m_lastSent;
|
||||
|
||||
/** Indicates whether or not chat states are currently enabled. */
|
||||
bool m_enableChatStates;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CHATSTATEFILTER_H__
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 CHATSTATEHANDLER_H__
|
||||
#define CHATSTATEHANDLER_H__
|
||||
|
||||
#include "gloox.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class JID;
|
||||
|
||||
/**
|
||||
* @brief A virtual interface that enables an object to be notified about
|
||||
* a remote entity's Chat States (@xep{0085}).
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.8
|
||||
*/
|
||||
class GLOOX_API ChatStateHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~ChatStateHandler() {}
|
||||
|
||||
/**
|
||||
* Notifies the ChatStateHandler that a different chat state has been set by the remote
|
||||
* contact.
|
||||
* @param from The originator of the Event.
|
||||
* @param state The chat state set by the remote entity.
|
||||
*/
|
||||
virtual void handleChatState( const JID& from, ChatStateType state ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CHATSTATEHANDLER_H__
|
|
@ -1,760 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 "config.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "capabilities.h"
|
||||
#include "rostermanager.h"
|
||||
#include "disco.h"
|
||||
#include "error.h"
|
||||
#include "logsink.h"
|
||||
#include "nonsaslauth.h"
|
||||
#include "prep.h"
|
||||
#include "stanzaextensionfactory.h"
|
||||
#include "stanzaextension.h"
|
||||
#include "tag.h"
|
||||
#include "tlsbase.h"
|
||||
#include "util.h"
|
||||
|
||||
#if !defined( _WIN32 ) && !defined( _WIN32_WCE )
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
// ---- Client::ResourceBind ----
|
||||
Client::ResourceBind::ResourceBind( const std::string& resource, bool bind )
|
||||
: StanzaExtension( ExtResourceBind ), m_jid( JID() ), m_bind( bind )
|
||||
{
|
||||
prep::resourceprep( resource, m_resource );
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
Client::ResourceBind::ResourceBind( const Tag* tag )
|
||||
: StanzaExtension( ExtResourceBind ), m_resource( EmptyString ), m_bind( true )
|
||||
{
|
||||
if( !tag )
|
||||
return;
|
||||
|
||||
if( tag->name() == "unbind" )
|
||||
m_bind = false;
|
||||
else if( tag->name() == "bind" )
|
||||
m_bind = true;
|
||||
else
|
||||
return;
|
||||
|
||||
if( tag->hasChild( "jid" ) )
|
||||
m_jid.setJID( tag->findChild( "jid" )->cdata() );
|
||||
else if( tag->hasChild( "resource" ) )
|
||||
m_resource = tag->findChild( "resource" )->cdata();
|
||||
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
Client::ResourceBind::~ResourceBind()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& Client::ResourceBind::filterString() const
|
||||
{
|
||||
static const std::string filter = "/iq/bind[@xmlns='" + XMLNS_STREAM_BIND + "']"
|
||||
"|/iq/unbind[@xmlns='" + XMLNS_STREAM_BIND + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Client::ResourceBind::tag() const
|
||||
{
|
||||
if( !m_valid )
|
||||
return 0;
|
||||
|
||||
Tag* t = new Tag( m_bind ? "bind" : "unbind" );
|
||||
t->setXmlns( XMLNS_STREAM_BIND );
|
||||
|
||||
if( m_bind && m_resource.empty() && m_jid )
|
||||
new Tag( t, "jid", m_jid.full() );
|
||||
else
|
||||
new Tag( t, "resource", m_resource );
|
||||
|
||||
return t;
|
||||
}
|
||||
// ---- ~Client::ResourceBind ----
|
||||
|
||||
// ---- Client::SessionCreation ----
|
||||
Tag* Client::SessionCreation::tag() const
|
||||
{
|
||||
Tag* t = new Tag( "session" );
|
||||
t->setXmlns( XMLNS_STREAM_SESSION );
|
||||
return t;
|
||||
}
|
||||
// ---- Client::SessionCreation ----
|
||||
|
||||
// ---- Client ----
|
||||
Client::Client( const std::string& server )
|
||||
: ClientBase( XMLNS_CLIENT, server ),
|
||||
m_rosterManager( 0 ), m_auth( 0 ),
|
||||
m_presence( Presence::Available, JID() ), m_resourceBound( false ),
|
||||
m_forceNonSasl( false ), m_manageRoster( true ),
|
||||
m_smId( EmptyString ), m_smLocation( EmptyString ), m_smResume( false ), m_smWanted( false ), m_smMax( 0 ),
|
||||
m_streamFeatures( 0 )
|
||||
{
|
||||
m_jid.setServer( server );
|
||||
init();
|
||||
}
|
||||
|
||||
Client::Client( const JID& jid, const std::string& password, int port )
|
||||
: ClientBase( XMLNS_CLIENT, password, EmptyString, port ),
|
||||
m_rosterManager( 0 ), m_auth( 0 ),
|
||||
m_presence( Presence::Available, JID() ), m_resourceBound( false ),
|
||||
m_forceNonSasl( false ), m_manageRoster( true ),
|
||||
m_smId( EmptyString ), m_smLocation( EmptyString ), m_smResume( false ), m_smWanted( false ), m_smMax( 0 ),
|
||||
m_streamFeatures( 0 )
|
||||
{
|
||||
m_jid = jid;
|
||||
m_server = m_jid.serverRaw();
|
||||
init();
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
delete m_rosterManager;
|
||||
delete m_auth;
|
||||
}
|
||||
|
||||
void Client::init()
|
||||
{
|
||||
m_rosterManager = new RosterManager( this );
|
||||
m_disco->setIdentity( "client", "bot" );
|
||||
registerStanzaExtension( new ResourceBind( 0 ) );
|
||||
registerStanzaExtension( new Capabilities() );
|
||||
m_presenceExtensions.push_back( new Capabilities( m_disco ) );
|
||||
}
|
||||
|
||||
void Client::setUsername( const std::string &username )
|
||||
{
|
||||
m_jid.setUsername( username );
|
||||
}
|
||||
|
||||
bool Client::handleNormalNode( Tag* tag )
|
||||
{
|
||||
if( tag->name() == "features" && tag->xmlns() == XMLNS_STREAM )
|
||||
{
|
||||
m_streamFeatures = getStreamFeatures( tag );
|
||||
|
||||
if( m_tls == TLSRequired && !m_encryptionActive
|
||||
&& ( !m_encryption || !( m_streamFeatures & StreamFeatureStartTls ) ) )
|
||||
{
|
||||
logInstance().err( LogAreaClassClient, "Client is configured to require"
|
||||
" TLS but either the server didn't offer TLS or"
|
||||
" TLS support is not compiled in." );
|
||||
disconnect( ConnTlsNotAvailable );
|
||||
}
|
||||
else if( m_tls > TLSDisabled && m_encryption && !m_encryptionActive
|
||||
&& ( m_streamFeatures & StreamFeatureStartTls ) )
|
||||
{
|
||||
notifyStreamEvent( StreamEventEncryption );
|
||||
startTls();
|
||||
}
|
||||
else if( m_compress && m_compression && !m_compressionActive
|
||||
&& ( m_streamFeatures & StreamFeatureCompressZlib ) )
|
||||
{
|
||||
notifyStreamEvent( StreamEventCompression );
|
||||
logInstance().warn( LogAreaClassClient, "The server offers compression, but negotiating Compression at this stage is not recommended. See XEP-0170 for details. We'll continue anyway." );
|
||||
negotiateCompression( StreamFeatureCompressZlib );
|
||||
}
|
||||
else if( m_sasl )
|
||||
{
|
||||
if( m_authed )
|
||||
{
|
||||
if( m_streamFeatures & StreamFeatureStreamManagement && m_smWanted && m_smContext >= CtxSMEnabled )
|
||||
{
|
||||
sendStreamManagement();
|
||||
}
|
||||
else if( m_streamFeatures & StreamFeatureBind && m_smContext < CtxSMEnabled )
|
||||
{
|
||||
notifyStreamEvent( StreamEventResourceBinding );
|
||||
bindResource( resource() );
|
||||
}
|
||||
}
|
||||
else if( !username().empty() && !password().empty() )
|
||||
{
|
||||
if( !login() )
|
||||
{
|
||||
logInstance().err( LogAreaClassClient, "The server doesn't support"
|
||||
" any auth mechanisms we know about" );
|
||||
disconnect( ConnNoSupportedAuth );
|
||||
}
|
||||
}
|
||||
else if( !m_clientCerts.empty() && !m_clientKey.empty()
|
||||
&& m_streamFeatures & SaslMechExternal && m_availableSaslMechs & SaslMechExternal )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
startSASL( SaslMechExternal );
|
||||
}
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
else if( m_streamFeatures & SaslMechGssapi && m_availableSaslMechs & SaslMechGssapi )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
startSASL( SaslMechGssapi );
|
||||
}
|
||||
else if( m_streamFeatures & SaslMechNTLM && m_availableSaslMechs & SaslMechNTLM )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
startSASL( SaslMechNTLM );
|
||||
}
|
||||
#endif
|
||||
else if( m_streamFeatures & SaslMechAnonymous
|
||||
&& m_availableSaslMechs & SaslMechAnonymous )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
startSASL( SaslMechAnonymous );
|
||||
}
|
||||
else
|
||||
{
|
||||
notifyStreamEvent( StreamEventFinished );
|
||||
connected();
|
||||
}
|
||||
}
|
||||
else if( m_compress && m_compression && !m_compressionActive
|
||||
&& ( m_streamFeatures & StreamFeatureCompressZlib ) )
|
||||
{
|
||||
notifyStreamEvent( StreamEventCompression );
|
||||
negotiateCompression( StreamFeatureCompressZlib );
|
||||
}
|
||||
// else if( ( m_streamFeatures & StreamFeatureCompressDclz )
|
||||
// && m_connection->initCompression( StreamFeatureCompressDclz ) )
|
||||
// {
|
||||
// negotiateCompression( StreamFeatureCompressDclz );
|
||||
// }
|
||||
else if( m_streamFeatures & StreamFeatureIqAuth )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
nonSaslLogin();
|
||||
}
|
||||
else
|
||||
{
|
||||
logInstance().err( LogAreaClassClient, "fallback: the server doesn't "
|
||||
"support any auth mechanisms we know about" );
|
||||
disconnect( ConnNoSupportedAuth );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string& name = tag->name(),
|
||||
xmlns = tag->findAttribute( XMLNS );
|
||||
if( name == "proceed" && xmlns == XMLNS_STREAM_TLS )
|
||||
{
|
||||
logInstance().dbg( LogAreaClassClient, "starting TLS handshake..." );
|
||||
|
||||
if( m_encryption )
|
||||
{
|
||||
m_encryptionActive = true;
|
||||
m_encryption->handshake();
|
||||
}
|
||||
}
|
||||
else if( name == "failure" )
|
||||
{
|
||||
if( xmlns == XMLNS_STREAM_TLS )
|
||||
{
|
||||
logInstance().err( LogAreaClassClient, "TLS handshake failed (server-side)!" );
|
||||
disconnect( ConnTlsFailed );
|
||||
}
|
||||
else if( xmlns == XMLNS_COMPRESSION )
|
||||
{
|
||||
logInstance().err( LogAreaClassClient, "Stream compression init failed!" );
|
||||
disconnect( ConnCompressionFailed );
|
||||
}
|
||||
else if( xmlns == XMLNS_STREAM_SASL )
|
||||
{
|
||||
logInstance().err( LogAreaClassClient, "SASL authentication failed!" );
|
||||
processSASLError( tag );
|
||||
disconnect( ConnAuthenticationFailed );
|
||||
}
|
||||
}
|
||||
else if( name == "compressed" && xmlns == XMLNS_COMPRESSION )
|
||||
{
|
||||
logInstance().dbg( LogAreaClassClient, "Stream compression initialized" );
|
||||
m_compressionActive = true;
|
||||
header();
|
||||
}
|
||||
else if( name == "challenge" && xmlns == XMLNS_STREAM_SASL )
|
||||
{
|
||||
logInstance().dbg( LogAreaClassClient, "Processing SASL challenge" );
|
||||
processSASLChallenge( tag->cdata() );
|
||||
}
|
||||
else if( name == "success" && xmlns == XMLNS_STREAM_SASL )
|
||||
{
|
||||
if( !processSASLSuccess( tag->cdata() ) )
|
||||
{
|
||||
logInstance().err( LogAreaClassClient, "The Server response could not be verified!" );
|
||||
disconnect( ConnAuthenticationFailed );
|
||||
return false;
|
||||
}
|
||||
|
||||
logInstance().dbg( LogAreaClassClient, "SASL authentication successful" );
|
||||
setAuthed( true );
|
||||
header();
|
||||
}
|
||||
else if( name == "enabled" && xmlns == XMLNS_STREAM_MANAGEMENT )
|
||||
{
|
||||
m_smContext = CtxSMEnabled;
|
||||
m_smMax = atoi( tag->findAttribute( "max" ).c_str() );
|
||||
m_smId = tag->findAttribute( "id" );
|
||||
const std::string res = tag->findAttribute( "resume" );
|
||||
m_smResume = ( ( res == "true" || res == "1" ) && !m_smId.empty() ) ? true : false;
|
||||
m_smLocation = tag->findAttribute( "location" );
|
||||
|
||||
if( m_streamFeatures & StreamFeatureSession )
|
||||
createSession();
|
||||
else
|
||||
connected();
|
||||
}
|
||||
else if( name == "resumed" && xmlns == XMLNS_STREAM_MANAGEMENT && m_smContext == CtxSMResume )
|
||||
{
|
||||
if( tag->findAttribute( "previd" ) == m_smId )
|
||||
{
|
||||
m_smContext = CtxSMResumed;
|
||||
notifyStreamEvent( StreamEventSMResumed );
|
||||
int h = atoi( tag->findAttribute( "h" ).c_str() );
|
||||
connected();
|
||||
checkQueue( h, true );
|
||||
}
|
||||
}
|
||||
else if( name == "a" && xmlns == XMLNS_STREAM_MANAGEMENT && m_smContext >= CtxSMEnabled )
|
||||
{
|
||||
int h = atoi( tag->findAttribute( "h" ).c_str() );
|
||||
checkQueue( h, false );
|
||||
}
|
||||
else if( name == "r" && xmlns == XMLNS_STREAM_MANAGEMENT )
|
||||
{
|
||||
ackStreamManagement();
|
||||
}
|
||||
else if( name == "failed" && xmlns == XMLNS_STREAM_MANAGEMENT )
|
||||
{
|
||||
switch( m_smContext )
|
||||
{
|
||||
case CtxSMEnable:
|
||||
notifyStreamEvent( StreamEventSMEnableFailed );
|
||||
break;
|
||||
case CtxSMResume:
|
||||
notifyStreamEvent( StreamEventSMResumeFailed );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_smContext = CtxSMFailed;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Client::getStreamFeatures( Tag* tag )
|
||||
{
|
||||
if( tag->name() != "features" || tag->xmlns() != XMLNS_STREAM )
|
||||
return 0;
|
||||
|
||||
int features = 0;
|
||||
|
||||
if( tag->hasChild( "starttls", XMLNS, XMLNS_STREAM_TLS ) )
|
||||
features |= StreamFeatureStartTls;
|
||||
|
||||
if( tag->hasChild( "mechanisms", XMLNS, XMLNS_STREAM_SASL ) )
|
||||
features |= getSaslMechs( tag->findChild( "mechanisms" ) );
|
||||
|
||||
if( tag->hasChild( "bind", XMLNS, XMLNS_STREAM_BIND ) )
|
||||
features |= StreamFeatureBind;
|
||||
|
||||
if( tag->hasChild( "unbind", XMLNS, XMLNS_STREAM_BIND ) )
|
||||
features |= StreamFeatureUnbind;
|
||||
|
||||
if( tag->hasChild( "session", XMLNS, XMLNS_STREAM_SESSION ) )
|
||||
features |= StreamFeatureSession;
|
||||
|
||||
if( tag->hasChild( "auth", XMLNS, XMLNS_STREAM_IQAUTH ) )
|
||||
features |= StreamFeatureIqAuth;
|
||||
|
||||
if( tag->hasChild( "register", XMLNS, XMLNS_STREAM_IQREGISTER ) )
|
||||
features |= StreamFeatureIqRegister;
|
||||
|
||||
if( tag->hasChild( "compression", XMLNS, XMLNS_STREAM_COMPRESS ) )
|
||||
features |= getCompressionMethods( tag->findChild( "compression" ) );
|
||||
|
||||
if( tag->hasChild( "sm", XMLNS, XMLNS_STREAM_MANAGEMENT ) )
|
||||
features |= StreamFeatureStreamManagement;
|
||||
|
||||
if( features == 0 )
|
||||
features = StreamFeatureIqAuth;
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
int Client::getSaslMechs( Tag* tag )
|
||||
{
|
||||
int mechs = SaslMechNone;
|
||||
|
||||
const std::string mech = "mechanism";
|
||||
|
||||
if( tag->hasChildWithCData( mech, "SCRAM-SHA-1-PLUS" ) )
|
||||
mechs |= SaslMechScramSha1Plus;
|
||||
|
||||
if( tag->hasChildWithCData( mech, "SCRAM-SHA-1" ) )
|
||||
mechs |= SaslMechScramSha1;
|
||||
|
||||
if( tag->hasChildWithCData( mech, "DIGEST-MD5" ) )
|
||||
mechs |= SaslMechDigestMd5;
|
||||
|
||||
if( tag->hasChildWithCData( mech, "PLAIN" ) )
|
||||
mechs |= SaslMechPlain;
|
||||
|
||||
if( tag->hasChildWithCData( mech, "ANONYMOUS" ) )
|
||||
mechs |= SaslMechAnonymous;
|
||||
|
||||
if( tag->hasChildWithCData( mech, "EXTERNAL" ) )
|
||||
mechs |= SaslMechExternal;
|
||||
|
||||
if( tag->hasChildWithCData( mech, "GSSAPI" ) )
|
||||
mechs |= SaslMechGssapi;
|
||||
|
||||
if( tag->hasChildWithCData( mech, "NTLM" ) )
|
||||
mechs |= SaslMechNTLM;
|
||||
|
||||
return mechs;
|
||||
}
|
||||
|
||||
int Client::getCompressionMethods( Tag* tag )
|
||||
{
|
||||
int meths = 0;
|
||||
|
||||
if( tag->hasChildWithCData( "method", "zlib" ) )
|
||||
meths |= StreamFeatureCompressZlib;
|
||||
|
||||
if( tag->hasChildWithCData( "method", "lzw" ) )
|
||||
meths |= StreamFeatureCompressDclz;
|
||||
|
||||
return meths;
|
||||
}
|
||||
|
||||
bool Client::login()
|
||||
{
|
||||
bool retval = true;
|
||||
|
||||
if( ( m_streamFeatures & SaslMechScramSha1Plus && m_availableSaslMechs & SaslMechScramSha1Plus
|
||||
&& m_encryption && m_encryptionActive && m_encryption->hasChannelBinding() )
|
||||
&& !m_forceNonSasl )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
startSASL( SaslMechScramSha1Plus );
|
||||
}
|
||||
else if( m_streamFeatures & SaslMechScramSha1 && m_availableSaslMechs & SaslMechScramSha1
|
||||
&& !m_forceNonSasl )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
startSASL( SaslMechScramSha1 );
|
||||
}
|
||||
else if( m_streamFeatures & SaslMechDigestMd5 && m_availableSaslMechs & SaslMechDigestMd5
|
||||
&& !m_forceNonSasl )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
startSASL( SaslMechDigestMd5 );
|
||||
}
|
||||
else if( m_streamFeatures & SaslMechPlain && m_availableSaslMechs & SaslMechPlain
|
||||
&& !m_forceNonSasl )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
startSASL( SaslMechPlain );
|
||||
}
|
||||
else if( m_streamFeatures & StreamFeatureIqAuth || m_forceNonSasl )
|
||||
{
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
nonSaslLogin();
|
||||
}
|
||||
else
|
||||
retval = false;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void Client::handleIqIDForward( const IQ& iq, int context )
|
||||
{
|
||||
switch( context )
|
||||
{
|
||||
case CtxResourceUnbind:
|
||||
// we don't store known resources anyway
|
||||
break;
|
||||
case CtxResourceBind:
|
||||
processResourceBind( iq );
|
||||
break;
|
||||
case CtxSessionEstablishment:
|
||||
processCreateSession( iq );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::bindOperation( const std::string& resource, bool bind )
|
||||
{
|
||||
if( !( m_streamFeatures & StreamFeatureUnbind ) && m_resourceBound )
|
||||
return false;
|
||||
|
||||
IQ iq( IQ::Set, JID(), getID() );
|
||||
iq.addExtension( new ResourceBind( resource, bind ) );
|
||||
|
||||
send( iq, this, bind ? CtxResourceBind : CtxResourceUnbind );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Client::selectResource( const std::string& resource )
|
||||
{
|
||||
m_selectedResource = resource; // TODO: remove for 1.1
|
||||
m_jid.setResource( resource );
|
||||
|
||||
if( !( m_streamFeatures & StreamFeatureUnbind ) )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::processResourceBind( const IQ& iq )
|
||||
{
|
||||
switch( iq.subtype() )
|
||||
{
|
||||
case IQ::Result:
|
||||
{
|
||||
const ResourceBind* rb = iq.findExtension<ResourceBind>( ExtResourceBind );
|
||||
if( !rb || !rb->jid() )
|
||||
{
|
||||
notifyOnResourceBindError( 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
m_jid = rb->jid();
|
||||
m_resourceBound = true;
|
||||
m_selectedResource = m_jid.resource(); // TODO: remove for 1.1
|
||||
notifyOnResourceBind( m_jid.resource() );
|
||||
|
||||
if( m_streamFeatures & StreamFeatureStreamManagement && m_smWanted )
|
||||
sendStreamManagement();
|
||||
else if( m_streamFeatures & StreamFeatureSession )
|
||||
createSession();
|
||||
else
|
||||
connected();
|
||||
break;
|
||||
}
|
||||
case IQ::Error:
|
||||
{
|
||||
notifyOnResourceBindError( iq.error() );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::setStreamManagement( bool enable, bool resume )
|
||||
{
|
||||
m_smWanted = enable;
|
||||
m_smResume = resume;
|
||||
|
||||
if( !m_smWanted )
|
||||
{
|
||||
m_smId = EmptyString;
|
||||
m_smLocation = EmptyString;
|
||||
m_smMax = 0;
|
||||
m_smResume = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_smWanted && m_resourceBound )
|
||||
sendStreamManagement();
|
||||
}
|
||||
|
||||
void Client::sendStreamManagement()
|
||||
{
|
||||
if( !m_smWanted )
|
||||
return;
|
||||
|
||||
if( m_smContext == CtxSMInvalid )
|
||||
{
|
||||
notifyStreamEvent( StreamEventSMEnable );
|
||||
Tag* e = new Tag( "enable" );
|
||||
e->setXmlns( XMLNS_STREAM_MANAGEMENT );
|
||||
if( m_smResume )
|
||||
e->addAttribute( "resume", "true" );
|
||||
send( e );
|
||||
m_smContext = CtxSMEnable;
|
||||
m_smHandled = 0;
|
||||
}
|
||||
else if( m_smContext == CtxSMEnabled )
|
||||
{
|
||||
notifyStreamEvent( StreamEventSMResume );
|
||||
Tag* r = new Tag( "resume" );
|
||||
r->setXmlns( XMLNS_STREAM_MANAGEMENT );
|
||||
r->addAttribute( "h", m_smHandled );
|
||||
r->addAttribute( "previd", m_smId );
|
||||
send( r );
|
||||
m_smContext = CtxSMResume;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::ackStreamManagement()
|
||||
{
|
||||
if( m_smContext >= CtxSMEnabled )
|
||||
{
|
||||
Tag* a = new Tag( "a", "xmlns", XMLNS_STREAM_MANAGEMENT );
|
||||
a->addAttribute( "h", m_smHandled );
|
||||
send( a );
|
||||
}
|
||||
}
|
||||
|
||||
void Client::reqStreamManagement()
|
||||
{
|
||||
if( m_smContext >= CtxSMEnabled )
|
||||
{
|
||||
Tag* r = new Tag( "r", "xmlns", XMLNS_STREAM_MANAGEMENT );
|
||||
send( r );
|
||||
}
|
||||
}
|
||||
|
||||
void Client::createSession()
|
||||
{
|
||||
notifyStreamEvent( StreamEventSessionCreation );
|
||||
IQ iq( IQ::Set, JID(), getID() );
|
||||
iq.addExtension( new SessionCreation() );
|
||||
send( iq, this, CtxSessionEstablishment );
|
||||
}
|
||||
|
||||
void Client::processCreateSession( const IQ& iq )
|
||||
{
|
||||
switch( iq.subtype() )
|
||||
{
|
||||
case IQ::Result:
|
||||
connected();
|
||||
break;
|
||||
case IQ::Error:
|
||||
notifyOnSessionCreateError( iq.error() );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Client::negotiateCompression( StreamFeature method )
|
||||
{
|
||||
Tag* t = new Tag( "compress", XMLNS, XMLNS_COMPRESSION );
|
||||
|
||||
if( method == StreamFeatureCompressZlib )
|
||||
new Tag( t, "method", "zlib" );
|
||||
|
||||
if( method == StreamFeatureCompressDclz )
|
||||
new Tag( t, "method", "lzw" );
|
||||
|
||||
send( t );
|
||||
}
|
||||
|
||||
void Client::setPresence( Presence::PresenceType pres, int priority,
|
||||
const std::string& status )
|
||||
{
|
||||
m_presence.setPresence( pres );
|
||||
m_presence.setPriority( priority );
|
||||
m_presence.addStatus( status );
|
||||
sendPresence( m_presence );
|
||||
}
|
||||
|
||||
void Client::setPresence( const JID& to, Presence::PresenceType pres, int priority,
|
||||
const std::string& status )
|
||||
{
|
||||
Presence p( pres, to, status, priority );
|
||||
sendPresence( p );
|
||||
}
|
||||
|
||||
void Client::sendPresence( Presence& pres )
|
||||
{
|
||||
if( state() < StateConnected )
|
||||
return;
|
||||
|
||||
send( pres );
|
||||
}
|
||||
|
||||
void Client::disableRoster()
|
||||
{
|
||||
m_manageRoster = false;
|
||||
delete m_rosterManager;
|
||||
m_rosterManager = 0;
|
||||
}
|
||||
|
||||
void Client::nonSaslLogin()
|
||||
{
|
||||
if( !m_auth )
|
||||
m_auth = new NonSaslAuth( this );
|
||||
m_auth->doAuth( m_sid );
|
||||
}
|
||||
|
||||
void Client::connected()
|
||||
{
|
||||
if( m_authed && m_smContext != CtxSMResumed )
|
||||
{
|
||||
if( m_manageRoster )
|
||||
{
|
||||
notifyStreamEvent( StreamEventRoster );
|
||||
m_rosterManager->fill();
|
||||
}
|
||||
else
|
||||
rosterFilled();
|
||||
}
|
||||
else
|
||||
{
|
||||
notifyStreamEvent( StreamEventFinished );
|
||||
notifyOnConnect();
|
||||
}
|
||||
}
|
||||
|
||||
void Client::rosterFilled()
|
||||
{
|
||||
sendPresence( m_presence );
|
||||
notifyStreamEvent( StreamEventFinished );
|
||||
notifyOnConnect();
|
||||
}
|
||||
|
||||
void Client::disconnect()
|
||||
{
|
||||
m_smContext = CtxSMInvalid;
|
||||
m_smHandled = 0;
|
||||
m_smId = EmptyString;
|
||||
m_smLocation = EmptyString;
|
||||
m_smMax = 0;
|
||||
m_smResume = false;
|
||||
m_smWanted = false;
|
||||
|
||||
disconnect( ConnUserDisconnected );
|
||||
}
|
||||
|
||||
void Client::disconnect( ConnectionError reason )
|
||||
{
|
||||
m_resourceBound = false;
|
||||
m_authed = false;
|
||||
m_streamFeatures = 0;
|
||||
ClientBase::disconnect( reason );
|
||||
}
|
||||
|
||||
void Client::cleanup()
|
||||
{
|
||||
m_authed = false;
|
||||
m_resourceBound = false;
|
||||
m_streamFeatures = 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,502 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 CLIENT_H__
|
||||
#define CLIENT_H__
|
||||
|
||||
#include "clientbase.h"
|
||||
#include "presence.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Capabilities;
|
||||
class RosterManager;
|
||||
class NonSaslAuth;
|
||||
class IQ;
|
||||
|
||||
/**
|
||||
* @brief This class implements a basic Jabber/XMPP Client.
|
||||
*
|
||||
* It supports @ref sasl_auth as well as TLS (Encryption), which can be
|
||||
* switched on/off separately. They are used automatically if the server supports them.
|
||||
*
|
||||
* To use, create a new Client instance and feed it connection credentials, either in the Constructor or
|
||||
* afterwards using the setters. You should then register packet handlers implementing the corresponding
|
||||
* Interfaces (ConnectionListener, PresenceHandler, MessageHandler, IqHandler, SubscriptionHandler),
|
||||
* and call @ref connect() to establish the connection to the server.
|
||||
*
|
||||
* @note While the MessageHandler interface is still available (and will be in future versions)
|
||||
* it is now recommended to use the new @link gloox::MessageSession MessageSession @endlink for any
|
||||
* serious messaging.
|
||||
*
|
||||
* Simple usage example:
|
||||
* @code
|
||||
* using namespace gloox;
|
||||
*
|
||||
* void TestProg::doIt()
|
||||
* {
|
||||
* Client* j = new Client( "user@server/resource", "password" );
|
||||
* j->registerPresenceHandler( this );
|
||||
* j->disco()->setVersion( "TestProg", "1.0" );
|
||||
* j->disco()->setIdentity( "client", "bot" );
|
||||
* j->connect();
|
||||
* }
|
||||
*
|
||||
* virtual void TestProg::presenceHandler( Presence* presence )
|
||||
* {
|
||||
* // handle incoming presence packets here
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* However, you can skip the presence handling stuff if you make use of the RosterManager.
|
||||
*
|
||||
* By default, the library handles a few (incoming) IQ namespaces on the application's behalf. These
|
||||
* include:
|
||||
* @li jabber:iq:roster: by default the server-side roster is fetched and handled. Use
|
||||
* @ref rosterManager() and @ref RosterManager to interact with the Roster.
|
||||
* @li @xep{0092} (Software Version): If no version is specified, a name of "based on gloox" with
|
||||
* gloox's current version is announced.
|
||||
* @li @xep{0030} (Service Discovery): All supported/available services are announced. No items are
|
||||
* returned.
|
||||
* @note As of gloox 0.9, by default a priority of 0 is sent along with the initial presence.
|
||||
* @note As of gloox 0.9, initial presence is automatically sent. Presence: available, Priority: 0.
|
||||
* To disable sending of initial Presence use setPresence() with a value of Unavailable
|
||||
* prior to connecting.
|
||||
*
|
||||
* @section sasl_auth SASL Authentication
|
||||
*
|
||||
* Besides the simple, IQ-based authentication (@xep{0078}), gloox supports several SASL (Simple
|
||||
* Authentication and Security Layer, RFC 2222) authentication mechanisms.
|
||||
* @li DIGEST-MD5: This mechanism is preferred over all other mechanisms if username and password are
|
||||
* provided to the Client instance. It is secure even without TLS encryption.
|
||||
* @li PLAIN: This mechanism is used if DIGEST-MD5 is not available. It is @b not secure without
|
||||
* encryption.
|
||||
* @li ANONYMOUS This mechanism is used if neither username nor password are set. The server generates
|
||||
* random, temporary username and resource and may restrict available services.
|
||||
* @li EXTERNAL This mechanism is currently only available if client certificate and private key
|
||||
* are provided. The server tries to figure out who the client is by external means -- for instance,
|
||||
* using the provided certificate or even the IP address. (The restriction to certificate/key
|
||||
* availability is likely to be lifted in the future.)
|
||||
*
|
||||
* Of course, all these mechanisms are not tried unless the server offers them.
|
||||
*
|
||||
* @section stream_management Stream Management
|
||||
*
|
||||
* To enable Stream Management (@xep{0198}), call @ref setStreamManagement() with the first parameter set to @b true
|
||||
* at any time. This will tell the server to enable Stream Management, if the feature is available. Once switched on,
|
||||
* Stream Management can not be disabled for a given active stream. However, setting the first
|
||||
* parameter to @b false, it can be disabled inside gloox so that Stream Management will not be used
|
||||
* for subsequent connections.
|
||||
*
|
||||
* To enable the stream resumption feature, pass @b true as the second parameter to @ref setStreamManagement().
|
||||
* Upon re-connect after an unexpected (i.e. neither user-triggered nor server-triggered) disconnect, gloox will try
|
||||
* to resume the stream and re-send any non-acknowledged stanzas automatically.
|
||||
* For stream resumption to work you have to re-connect using the very same Client instance.
|
||||
*
|
||||
* After an unexpected disconnect you may check the send queue using @link ClientBase::sendQueue() sendQueue() @endlink.
|
||||
* Stanzas in the queue have been sent but not yet acknowledged by the server. Depending on the circumstances of the
|
||||
* disconnect, this does not mean that those stanzas have not been received by the recipient.
|
||||
*
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
*/
|
||||
class GLOOX_API Client : public ClientBase
|
||||
{
|
||||
public:
|
||||
|
||||
friend class NonSaslAuth;
|
||||
friend class Parser;
|
||||
|
||||
/**
|
||||
* Constructs a new Client which can be used for account registration only.
|
||||
* SASL and TLS are on by default. The port will be determined by looking up SRV records.
|
||||
* Alternatively, you can set the port explicitly by calling @ref setPort().
|
||||
* @param server The server to connect to.
|
||||
*/
|
||||
Client( const std::string& server );
|
||||
|
||||
/**
|
||||
* Constructs a new Client.
|
||||
* SASL and TLS are on by default. This should be the default constructor for most use cases.
|
||||
* The server address will be taken from the JID. The actual host will be resolved using SRV
|
||||
* records. The domain part of the JID is used as a fallback in case no SRV record is found, or
|
||||
* you can set the server address separately by calling @ref setServer().
|
||||
* @param jid A full Jabber ID used for connecting to the server.
|
||||
* @param password The password used for authentication.
|
||||
* @param port The port to connect to. The default of -1 means to look up the port via DNS SRV.
|
||||
*/
|
||||
Client( const JID& jid, const std::string& password, int port = -1 );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Client();
|
||||
|
||||
/**
|
||||
* Use this function to bind an additional resource or to @b re-try to bind a
|
||||
* resource in case previous binding failed and you were notified by means of
|
||||
* ConnectionListener::onResourceBindError(). Use hasResourceBind() to find out if the
|
||||
* server supports binding of multiple resources. bindResource() is a NOOP if it doesn't.
|
||||
* @note ConnectionListener::onResourceBound() and ConnectionListener::onResourceBindError()
|
||||
* will be called in case of success and failure, respectively.
|
||||
* @param resource The resource identifier to bind. May be empty. In that case
|
||||
* the server will assign a unique resource identifier.
|
||||
* @return Returns @b true if binding of multiple resources is supported, @b false
|
||||
* otherwise. A return value of @b true does not indicate that the resource was
|
||||
* successfully bound.
|
||||
* @note It is not necessary to call this function to bind the initial, main, resource.
|
||||
* @since 1.0
|
||||
*/
|
||||
bool bindResource( const std::string& resource )
|
||||
{ return bindOperation( resource, true ); }
|
||||
|
||||
/**
|
||||
* Use this function to select a resource identifier that has been bound
|
||||
* previously by means of bindResource(). It is not necessary to call this function
|
||||
* if only one resource is bound. Use hasResourceBind() to find out if the
|
||||
* server supports binding of multiple resources.
|
||||
* @param resource A resource string that has been bound previously.
|
||||
* @note If the resource string has not been bound previously, future sending of
|
||||
* stanzas will fail.
|
||||
*/
|
||||
bool selectResource( const std::string& resource );
|
||||
|
||||
/**
|
||||
* This function can be used to find out whether the server supports binding of multiple
|
||||
* resources.
|
||||
* @return @b True if binding of multiple resources is supported by the server,
|
||||
* @b false otherwise.
|
||||
*/
|
||||
bool hasResourceBind() const { return ((m_streamFeatures & StreamFeatureUnbind) == StreamFeatureUnbind); }
|
||||
|
||||
/**
|
||||
* Use this function to unbind a resource identifier that has been bound
|
||||
* previously by means of bindResource(). Use hasResourceBind() to find out if the
|
||||
* server supports binding of multiple resources. unbindResource() is a NOOP if it doesn't.
|
||||
* @param resource A resource string that has been bound previously.
|
||||
* @note Servers are encouraged to terminate the connection should the only bound
|
||||
* resource be unbound.
|
||||
*/
|
||||
bool unbindResource( const std::string& resource )
|
||||
{ return bindOperation( resource, false ); }
|
||||
|
||||
/**
|
||||
* Returns the current prepped main resource.
|
||||
* @return The resource used to connect.
|
||||
*/
|
||||
const std::string& resource() const { return m_jid.resource(); }
|
||||
|
||||
/**
|
||||
* This function enables Stream Management (@xep{0198}) if the server supports it.
|
||||
* Optionally, stream resumption can be disabled.
|
||||
* @note You can use this function at any time. However, gloox will make sure Stream Management
|
||||
* requests are sent only when allowed by the specification.
|
||||
* @param enable Enable or disable Stream Management. Note: once enabled on a connection, Stream
|
||||
* Management can not be disabled for that connection.
|
||||
* @param resume Tells the server whether to enable stream resumption. Defaults to @b true.
|
||||
* @note This function is part of @xep{0198}.
|
||||
* @since 1.0.4
|
||||
*/
|
||||
void setStreamManagement( bool enable = true, bool resume = true );
|
||||
|
||||
/**
|
||||
* Use this function to send an unrequested 'ack' to the server to let it know the number of handled stanzas.
|
||||
* You may use this function at any time. However, gloox will also reply to incoming 'ack requests' automatically.
|
||||
* These automatic 'acks' are not announced anywhere in gloox.
|
||||
* This function is a no-op if called in situations where sending an ack is not
|
||||
* allowed by the protocol.
|
||||
* @note This function is part of @xep{0198}.
|
||||
* @since 1.0.4
|
||||
*/
|
||||
void ackStreamManagement();
|
||||
|
||||
/**
|
||||
* Use this function to request the number of handled stanzas from the server.
|
||||
* You may use this function at any time. gloox does not send any such requests
|
||||
* automatically.
|
||||
* @note This function is part of @xep{0198}.
|
||||
* @since 1.0.4
|
||||
*/
|
||||
void reqStreamManagement();
|
||||
|
||||
/**
|
||||
* Returns the current priority.
|
||||
* @return The priority of the current resource.
|
||||
*/
|
||||
int priority() const { return m_presence.priority(); }
|
||||
|
||||
/**
|
||||
* Sets the username to use to connect to the XMPP server.
|
||||
* @param username The username to authenticate with.
|
||||
*/
|
||||
void setUsername( const std::string &username );
|
||||
|
||||
/**
|
||||
* Sets the main resource to use to connect to the XMPP server.
|
||||
* @param resource The resource to use to log into the server.
|
||||
*/
|
||||
void setResource( const std::string &resource ) { m_jid.setResource( resource ); }
|
||||
|
||||
/**
|
||||
* Sends directed presence to the given JID. This is a NOOP if there's no active connection.
|
||||
* To broadcast presence use setPresence( Presence::PresenceType, int, const std::string& ).
|
||||
* @param to The JID to send directed Presence to.
|
||||
* @param pres The presence to send.
|
||||
* @param priority The priority to include. Legal values: -128 <= priority <= 127
|
||||
* @param status The optional status message to include.
|
||||
* @note This function does not include any presence extensions (as added by
|
||||
* means of addPresenceExtension()) to the stanza.
|
||||
*/
|
||||
void setPresence( const JID& to, Presence::PresenceType pres, int priority,
|
||||
const std::string& status = EmptyString );
|
||||
|
||||
/**
|
||||
* Use this function to set the entity's presence, that is, to broadcast presence to all
|
||||
* subscribed entities. To send directed presence, use
|
||||
* setPresence( const JID&, Presence::PresenceType, int, const std::string& ).
|
||||
* If used prior to establishing a connection, the set values will be sent with
|
||||
* the initial presence stanza.
|
||||
* If used while a connection already is established, a presence stanza will be
|
||||
* sent out immediately.
|
||||
* @param pres The Presence value to set.
|
||||
* @param priority An optional priority value. Legal values: -128 <= priority <= 127
|
||||
* @param status An optional message describing the presence state.
|
||||
* @since 0.9
|
||||
*/
|
||||
void setPresence( Presence::PresenceType pres, int priority,
|
||||
const std::string& status = EmptyString );
|
||||
|
||||
/**
|
||||
* Use this function to broadcast the entity's presence to all
|
||||
* subscribed entities. This is a NOOP if there's no active connection.
|
||||
* To send directed presence, use
|
||||
* setPresence( const JID&, Presence::PresenceType, int, const std::string& ).
|
||||
* If used while a connection already is established a repective presence stanza will be
|
||||
* sent out immediately. Use presence() to modify the Presence object.
|
||||
* @note When login is finished, initial presence will be sent automatically.
|
||||
* So you do not need to call this function after login.
|
||||
* @since 1.0
|
||||
*/
|
||||
void setPresence() { sendPresence( m_presence ); }
|
||||
|
||||
/**
|
||||
* Returns the current presence.
|
||||
* @return The current presence.
|
||||
*/
|
||||
Presence& presence() { return m_presence; }
|
||||
|
||||
/**
|
||||
* This is a temporary hack to enforce Non-SASL login. You should not need to use it.
|
||||
* @param force Whether to force non-SASL auth. Default @b true.
|
||||
* @deprecated Please update the server to properly support SASL instead.
|
||||
*/
|
||||
GLOOX_DEPRECATED void setForceNonSasl( bool force = true ) { m_forceNonSasl = force; }
|
||||
|
||||
/**
|
||||
* Disables the automatic roster management.
|
||||
* You have to keep track of incoming presence yourself if
|
||||
* you want to have a roster.
|
||||
*/
|
||||
void disableRoster();
|
||||
|
||||
/**
|
||||
* This function gives access to the @c RosterManager object.
|
||||
* @return A pointer to the RosterManager.
|
||||
*/
|
||||
RosterManager* rosterManager() { return m_rosterManager; }
|
||||
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
/**
|
||||
* Initiates a login attempt (currently SASL External not supported).
|
||||
* This is useful after registering a new account. Simply use setUsername() and setPassword(),
|
||||
* and call login().
|
||||
* @return @b True if a login attempt could be started, @b false otherwise. A return
|
||||
* value of @b true does not indicate that login was successful.
|
||||
*/
|
||||
bool login();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Initiates non-SASL login.
|
||||
*/
|
||||
void nonSaslLogin();
|
||||
|
||||
private:
|
||||
#ifdef CLIENT_TEST
|
||||
public:
|
||||
#endif
|
||||
/**
|
||||
* @brief This is an implementation of a resource binding StanzaExtension.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class ResourceBind : public StanzaExtension
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a new object with the given resource string.
|
||||
* @param resource The resource to set.
|
||||
* @param bind Indicates whether this is an bind or unbind request.
|
||||
* Defaults to @b true (bind).
|
||||
*/
|
||||
ResourceBind( const std::string& resource, bool bind = true );
|
||||
|
||||
/**
|
||||
* Constructs a new object from the given Tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
ResourceBind( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~ResourceBind();
|
||||
|
||||
/**
|
||||
* Returns the requested resource.
|
||||
* @return The requested resource.
|
||||
*/
|
||||
const std::string& resource() const { return m_resource; }
|
||||
|
||||
/**
|
||||
* Returns the assigned JID.
|
||||
* @return The assigned JID.
|
||||
*/
|
||||
const JID& jid() const { return m_jid; }
|
||||
|
||||
/**
|
||||
* Use this function to find out whether the extension contains a
|
||||
* bind or unbind request.
|
||||
* @return @b True if the extension contains an unbind request, @b false otherwise.
|
||||
*/
|
||||
bool unbind() const { return !m_bind; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new ResourceBind( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new ResourceBind( *this );
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_resource;
|
||||
JID m_jid;
|
||||
bool m_bind;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a session creating StanzaExtension.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class SessionCreation : public StanzaExtension
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a new object.
|
||||
*/
|
||||
SessionCreation() : StanzaExtension( ExtSessionCreation ) {}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~SessionCreation() {}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const { return EmptyString; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{ (void)tag; return 0; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{ return 0; }
|
||||
|
||||
};
|
||||
|
||||
virtual void handleStartNode( const Tag* /*start*/ ) {}
|
||||
virtual bool handleNormalNode( Tag* tag );
|
||||
virtual void disconnect( ConnectionError reason );
|
||||
virtual void handleIqIDForward( const IQ& iq, int context );
|
||||
|
||||
int getStreamFeatures( Tag* tag );
|
||||
int getSaslMechs( Tag* tag );
|
||||
int getCompressionMethods( Tag* tag );
|
||||
void processResourceBind( const IQ& iq );
|
||||
void processCreateSession( const IQ& iq );
|
||||
void sendPresence( Presence& pres );
|
||||
void createSession();
|
||||
void negotiateCompression( StreamFeature method );
|
||||
void connected();
|
||||
virtual void rosterFilled();
|
||||
virtual void cleanup();
|
||||
bool bindOperation( const std::string& resource, bool bind );
|
||||
void sendStreamManagement();
|
||||
|
||||
void init();
|
||||
|
||||
enum TrackContext
|
||||
{
|
||||
CtxResourceBind = 1000, // must be higher than the last element in ClientBase's TrackContext
|
||||
CtxResourceUnbind,
|
||||
CtxSessionEstablishment
|
||||
};
|
||||
|
||||
RosterManager* m_rosterManager;
|
||||
NonSaslAuth* m_auth;
|
||||
|
||||
Presence m_presence;
|
||||
|
||||
bool m_resourceBound;
|
||||
bool m_forceNonSasl;
|
||||
bool m_manageRoster;
|
||||
|
||||
std::string m_smId;
|
||||
std::string m_smLocation;
|
||||
bool m_smResume;
|
||||
bool m_smWanted;
|
||||
int m_smMax;
|
||||
|
||||
int m_streamFeatures;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CLIENT_H__
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "component.h"
|
||||
|
||||
#include "disco.h"
|
||||
#include "stanza.h"
|
||||
#include "prep.h"
|
||||
#include "sha.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
Component::Component( const std::string& ns, const std::string& server,
|
||||
const std::string& component, const std::string& password, int port )
|
||||
: ClientBase( ns, password, server, port )
|
||||
{
|
||||
m_jid.setServer( component );
|
||||
m_disco->setIdentity( "component", "generic" );
|
||||
}
|
||||
|
||||
void Component::handleStartNode( const Tag* /*start*/ )
|
||||
{
|
||||
if( m_sid.empty() )
|
||||
return;
|
||||
|
||||
notifyStreamEvent( StreamEventAuthentication );
|
||||
|
||||
SHA sha;
|
||||
sha.feed( m_sid + m_password );
|
||||
sha.finalize();
|
||||
|
||||
Tag* h = new Tag( "handshake", sha.hex() );
|
||||
send( h );
|
||||
}
|
||||
|
||||
bool Component::handleNormalNode( Tag* tag )
|
||||
{
|
||||
if( tag->name() != "handshake" )
|
||||
return false;
|
||||
|
||||
m_authed = true;
|
||||
notifyStreamEvent( StreamEventFinished );
|
||||
notifyOnConnect();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 COMPONENT_H__
|
||||
#define COMPONENT_H__
|
||||
|
||||
#include "clientbase.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a basic jabber Component.
|
||||
*
|
||||
* It's using @xep{0114} (Jabber Component Protocol) to authenticate with a server.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.3
|
||||
*/
|
||||
class GLOOX_API Component : public ClientBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new Component.
|
||||
* @param ns The namespace that qualifies the stream. Either @b jabber:component:accept or
|
||||
* @b jabber:component:connect. See @xep{0114} for details.
|
||||
* @param server The server to connect to.
|
||||
* @param component The component's hostname. FQDN.
|
||||
* @param password The component's password.
|
||||
* @param port The port to connect to. The default of 5347 is the default port of the router
|
||||
* in jabberd2.
|
||||
*/
|
||||
Component( const std::string& ns, const std::string& server,
|
||||
const std::string& component, const std::string& password, int port = 5347 );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~Component() {}
|
||||
|
||||
/**
|
||||
* Disconnects from the server.
|
||||
*/
|
||||
virtual void disconnect() { ClientBase::disconnect( ConnUserDisconnected ); }
|
||||
|
||||
protected:
|
||||
// reimplemented from ClientBase
|
||||
virtual void handleStartNode( const Tag* start );
|
||||
|
||||
// reimplemented from ClientBase
|
||||
virtual bool handleNormalNode( Tag* tag );
|
||||
|
||||
// reimplemented from ClientBase
|
||||
virtual bool checkStreamVersion( const std::string& /*version*/ ) { return true; }
|
||||
|
||||
private:
|
||||
// reimplemented from ClientBase
|
||||
virtual void rosterFilled() {}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // COMPONENT_H__
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 COMPRESSIONBASE_H__
|
||||
#define COMPRESSIONBASE_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "compressiondatahandler.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an abstract base class for stream compression implementations.
|
||||
*
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API CompressionBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Contructor.
|
||||
* @param cdh A CompressionDataHandler-derived object that will be notified
|
||||
* about finished de/compression.
|
||||
*/
|
||||
CompressionBase( CompressionDataHandler* cdh ) : m_handler( cdh ), m_valid( false ) {}
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~CompressionBase() {}
|
||||
|
||||
/**
|
||||
* This function initializes the compression module.
|
||||
* it is mandatory to be called.
|
||||
* @return @b True if the module was initialized successfully, false otherwise.
|
||||
*/
|
||||
virtual bool init() = 0;
|
||||
|
||||
/**
|
||||
* Compresses the given chunk of data.
|
||||
* @param data The original (uncompressed) data.
|
||||
*/
|
||||
virtual void compress( const std::string& data ) = 0;
|
||||
|
||||
/**
|
||||
* Decompresses the given chunk of data.
|
||||
* @param data The compressed data.
|
||||
*/
|
||||
virtual void decompress( const std::string& data ) = 0;
|
||||
|
||||
/**
|
||||
* Performs internal cleanup.
|
||||
* @since 1.0
|
||||
*/
|
||||
virtual void cleanup() = 0;
|
||||
|
||||
protected:
|
||||
/** A handler for compressed/uncompressed data. */
|
||||
CompressionDataHandler* m_handler;
|
||||
|
||||
/** Whether the compression module can be used. */
|
||||
bool m_valid;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // COMPRESSIONBASE_H__
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
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 COMPRESSIONDATAHANDLER_H__
|
||||
#define COMPRESSIONDATAHANDLER_H__
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An abstract base class used to receive de/compressed data from a
|
||||
* CompressionBase-derived object.
|
||||
*
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API CompressionDataHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~CompressionDataHandler() {}
|
||||
|
||||
/**
|
||||
* This function is called when compression is finished.
|
||||
* @param data The compressed data.
|
||||
*/
|
||||
virtual void handleCompressedData( const std::string& data ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called when decompression is finished.
|
||||
* @param data The decompressed data.
|
||||
*/
|
||||
virtual void handleDecompressedData( const std::string& data ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // COMPRESSIONDATAHANDLER_H__
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2009-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 "compressiondefault.h"
|
||||
|
||||
#include "compressiondatahandler.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined( HAVE_ZLIB )
|
||||
# define HAVE_COMPRESSION
|
||||
# include "compressionzlib.h"
|
||||
#endif
|
||||
|
||||
// #if defined( HAVE_LZW )
|
||||
// # define HAVE_COMPRESSION
|
||||
// # include "compressionlzw.h"
|
||||
// #endif
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
CompressionDefault::CompressionDefault( CompressionDataHandler* cdh, Method method )
|
||||
: CompressionBase( cdh ), m_impl( 0 )
|
||||
{
|
||||
switch( method )
|
||||
{
|
||||
case MethodZlib:
|
||||
#ifdef HAVE_ZLIB
|
||||
m_impl = new CompressionZlib( cdh );
|
||||
#endif
|
||||
break;
|
||||
case MethodLZW:
|
||||
#ifdef HAVE_LZW
|
||||
m_impl = new CompressionLZW( cdh );
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CompressionDefault::~CompressionDefault()
|
||||
{
|
||||
delete m_impl;
|
||||
}
|
||||
|
||||
bool CompressionDefault::init()
|
||||
{
|
||||
return m_impl ? m_impl->init() : false;
|
||||
}
|
||||
|
||||
int CompressionDefault::types()
|
||||
{
|
||||
int types = 0;
|
||||
#ifdef HAVE_ZLIB
|
||||
types |= MethodZlib;
|
||||
#endif
|
||||
#ifdef HAVE_LZW
|
||||
types |= MethodLZW;
|
||||
#endif
|
||||
return types;
|
||||
}
|
||||
|
||||
void CompressionDefault::compress( const std::string& data )
|
||||
{
|
||||
if( m_impl )
|
||||
m_impl->compress( data );
|
||||
}
|
||||
|
||||
void CompressionDefault::decompress( const std::string& data )
|
||||
{
|
||||
if( m_impl )
|
||||
m_impl->decompress( data );
|
||||
}
|
||||
|
||||
void CompressionDefault::cleanup()
|
||||
{
|
||||
if( m_impl )
|
||||
m_impl->cleanup();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2009-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 COMPRESSIONDEFAULT_H__
|
||||
#define COMPRESSIONDEFAULT_H__
|
||||
|
||||
#include "compressionbase.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class CompressionDataHandler;
|
||||
|
||||
/**
|
||||
* @brief This is an abstraction of the various Compression implementations.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API CompressionDefault : public CompressionBase
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Supported ctypes.
|
||||
*/
|
||||
enum Method
|
||||
{
|
||||
MethodZlib = 1, /**< Zlib compression. */
|
||||
MethodLZW = 2 /**< LZW compression. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new compression wrapper.
|
||||
* @param cdh The CompressionDataHandler to handle de/compressed data.
|
||||
* @param method The desired compression method.
|
||||
*/
|
||||
CompressionDefault( CompressionDataHandler* cdh, Method method = MethodZlib );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~CompressionDefault();
|
||||
|
||||
/**
|
||||
* Returns an int holding the available compression types, ORed.
|
||||
* @return An int holding the available compression types, ORed.
|
||||
*/
|
||||
static int types();
|
||||
|
||||
// reimplemented from CompressionBase
|
||||
virtual bool init();
|
||||
|
||||
// reimplemented from CompressionBase
|
||||
virtual void compress( const std::string& data );
|
||||
|
||||
// reimplemented from CompressionBase
|
||||
virtual void decompress( const std::string& data );
|
||||
|
||||
// reimplemented from CompressionBase
|
||||
virtual void cleanup();
|
||||
|
||||
private:
|
||||
CompressionBase* m_impl;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // COMPRESSIONDEFAULT_H__
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "compressionzlib.h"
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
CompressionZlib::CompressionZlib( CompressionDataHandler* cdh )
|
||||
: CompressionBase( cdh )
|
||||
{
|
||||
}
|
||||
|
||||
bool CompressionZlib::init()
|
||||
{
|
||||
int ret = Z_OK;
|
||||
m_zinflate.zalloc = Z_NULL;
|
||||
m_zinflate.zfree = Z_NULL;
|
||||
m_zinflate.opaque = Z_NULL;
|
||||
m_zinflate.avail_in = 0;
|
||||
m_zinflate.next_in = Z_NULL;
|
||||
ret = inflateInit( &m_zinflate );
|
||||
if( ret != Z_OK )
|
||||
return false;
|
||||
|
||||
m_zdeflate.zalloc = Z_NULL;
|
||||
m_zdeflate.zfree = Z_NULL;
|
||||
m_zdeflate.opaque = Z_NULL;
|
||||
m_zinflate.avail_in = 0;
|
||||
m_zinflate.next_in = Z_NULL;
|
||||
ret = deflateInit( &m_zdeflate, Z_BEST_COMPRESSION/*Z_DEFAULT_COMPRESSION*/ );
|
||||
if( ret != Z_OK )
|
||||
return false;
|
||||
|
||||
m_valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
CompressionZlib::~CompressionZlib()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void CompressionZlib::compress( const std::string& data )
|
||||
{
|
||||
if( !m_valid )
|
||||
init();
|
||||
|
||||
if( !m_valid || !m_handler || data.empty() )
|
||||
return;
|
||||
|
||||
long unsigned int CHUNK = data.length() + ( data.length() / 100 ) + 13;
|
||||
Bytef* out = new Bytef[CHUNK];
|
||||
char* in = const_cast<char*>( data.c_str() );
|
||||
|
||||
m_compressMutex.lock();
|
||||
|
||||
m_zdeflate.avail_in = static_cast<uInt>( data.length() );
|
||||
m_zdeflate.next_in = (Bytef*)in;
|
||||
|
||||
std::string result;
|
||||
do {
|
||||
m_zdeflate.avail_out = static_cast<uInt>( CHUNK );
|
||||
m_zdeflate.next_out = (Bytef*)out;
|
||||
|
||||
deflate( &m_zdeflate, Z_SYNC_FLUSH );
|
||||
result.append( (char*)out, CHUNK - m_zdeflate.avail_out );
|
||||
} while( m_zdeflate.avail_out == 0 );
|
||||
|
||||
m_compressMutex.unlock();
|
||||
|
||||
delete[] out;
|
||||
|
||||
m_handler->handleCompressedData( result );
|
||||
}
|
||||
|
||||
void CompressionZlib::decompress( const std::string& data )
|
||||
{
|
||||
if( !m_valid )
|
||||
init();
|
||||
|
||||
if( !m_valid || !m_handler || data.empty() )
|
||||
return;
|
||||
|
||||
int CHUNK = 50;
|
||||
char* out = new char[CHUNK];
|
||||
char* in = const_cast<char*>( data.c_str() );
|
||||
|
||||
m_zinflate.avail_in = static_cast<uInt>( data.length() );
|
||||
m_zinflate.next_in = (Bytef*)in;
|
||||
|
||||
std::string result;
|
||||
do
|
||||
{
|
||||
m_zinflate.avail_out = CHUNK;
|
||||
m_zinflate.next_out = (Bytef*)out;
|
||||
|
||||
inflate( &m_zinflate, Z_SYNC_FLUSH );
|
||||
result.append( out, CHUNK - m_zinflate.avail_out );
|
||||
} while( m_zinflate.avail_out == 0 );
|
||||
|
||||
delete[] out;
|
||||
|
||||
m_handler->handleDecompressedData( result );
|
||||
}
|
||||
|
||||
void CompressionZlib::cleanup()
|
||||
{
|
||||
m_compressMutex.lock();
|
||||
|
||||
if( m_valid )
|
||||
{
|
||||
inflateEnd( &m_zinflate );
|
||||
deflateEnd( &m_zdeflate );
|
||||
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
m_compressMutex.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_ZLIB
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 COMPRESSIONZLIB_H__
|
||||
#define COMPRESSIONZLIB_H__
|
||||
|
||||
#include "compressionbase.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
/**
|
||||
* An implementation of CompressionBase using zlib.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API CompressionZlib : public CompressionBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Contructor.
|
||||
* @param cdh The CompressionDataHandler to receive de/compressed data.
|
||||
*/
|
||||
CompressionZlib( CompressionDataHandler* cdh );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~CompressionZlib();
|
||||
|
||||
// reimplemented from CompressionBase
|
||||
virtual bool init();
|
||||
|
||||
// reimplemented from CompressionBase
|
||||
virtual void compress( const std::string& data );
|
||||
|
||||
// reimplemented from CompressionBase
|
||||
virtual void decompress( const std::string& data );
|
||||
|
||||
// reimplemented from CompressionBase
|
||||
virtual void cleanup();
|
||||
|
||||
private:
|
||||
z_stream m_zinflate;
|
||||
z_stream m_zdeflate;
|
||||
|
||||
util::Mutex m_compressMutex;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // HAVE_ZLIB
|
||||
|
||||
#endif // COMPRESSIONZLIB_H__
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009-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 CONFIG_H__
|
||||
#define CONFIG_H__
|
||||
|
||||
#if ( defined _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
# include "../config.h.win"
|
||||
#elif defined( _WIN32_WCE )
|
||||
# include "../config.h.win"
|
||||
#elif defined( __SYMBIAN32__ )
|
||||
# include "../config.h.symbian"
|
||||
#elif defined(__HAIKU__) && __GNUC__ < 4
|
||||
# include "config.h.unix.gcc2" // run ./configure to create config.h.unix
|
||||
#else
|
||||
# include "config.h.unix.gcc4"
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_H__
|
|
@ -1,130 +0,0 @@
|
|||
/* config.h.unix. Generated from config.h.unix.in by configure. */
|
||||
/* config.h.unix.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <arpa/nameser.h> header file. */
|
||||
#define HAVE_ARPA_NAMESER_H 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the `dn_skipname' function. */
|
||||
/* #undef HAVE_DN_SKIPNAME */
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#define HAVE_ERRNO_H 1
|
||||
|
||||
/* Define to 1 if GCC atomic builtins are available */
|
||||
/* #undef HAVE_GCC_ATOMIC_BUILTINS */
|
||||
|
||||
/* Define to 1 if you have the `getaddrinfo' function. */
|
||||
/* #undef HAVE_GETADDRINFO */
|
||||
|
||||
/* Define to 1 if you want TLS support (GnuTLS). Undefine HAVE_OPENSSL. */
|
||||
/* #undef HAVE_GNUTLS */
|
||||
|
||||
/* Define to 1 if you have GnuTLS 2.12.0 or above. */
|
||||
/* #undef HAVE_GNUTLS_SESSION_CHANNEL_BINDING */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `bind' library (-lbind). */
|
||||
/* #undef HAVE_LIBBIND */
|
||||
|
||||
/* Define to 1 if you want IDN support. */
|
||||
/* #undef HAVE_LIBIDN */
|
||||
|
||||
/* Define to 1 if you have the `resolv' library (-lresolv). */
|
||||
/* #undef HAVE_LIBRESOLV */
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
#define HAVE_LIBSOCKET 1
|
||||
|
||||
/* enable mdns support */
|
||||
/* #undef HAVE_MDNS */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you want TLS support (OpenSSL). Undefine HAVE_GNUTLS. */
|
||||
#define HAVE_OPENSSL 1
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#define HAVE_PTHREAD 1
|
||||
|
||||
/* Define to 1 if you have the `res_query' function. */
|
||||
/* #undef HAVE_RES_QUERY */
|
||||
|
||||
/* Define to 1 if you have the `res_querydomain' function. */
|
||||
/* #undef HAVE_RES_QUERYDOMAIN */
|
||||
|
||||
/* Define to 1 if you have the `setsockopt' function. */
|
||||
/* #undef HAVE_SETSOCKOPT */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you want Stream Compression support. */
|
||||
#define HAVE_ZLIB 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "gloox"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "js@camaya.net"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "gloox"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "gloox 1.0.13"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "gloox"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.0.13"
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
//#define VERSION "1.0.13"
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
|
@ -1,130 +0,0 @@
|
|||
/* config.h.unix. Generated from config.h.unix.in by configure. */
|
||||
/* config.h.unix.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have the <arpa/nameser.h> header file. */
|
||||
#define HAVE_ARPA_NAMESER_H 1
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the `dn_skipname' function. */
|
||||
/* #undef HAVE_DN_SKIPNAME */
|
||||
|
||||
/* Define to 1 if you have the <errno.h> header file. */
|
||||
#define HAVE_ERRNO_H 1
|
||||
|
||||
/* Define to 1 if GCC atomic builtins are available */
|
||||
#define HAVE_GCC_ATOMIC_BUILTINS 1
|
||||
|
||||
/* Define to 1 if you have the `getaddrinfo' function. */
|
||||
/* #undef HAVE_GETADDRINFO */
|
||||
|
||||
/* Define to 1 if you want TLS support (GnuTLS). Undefine HAVE_OPENSSL. */
|
||||
/* #undef HAVE_GNUTLS */
|
||||
|
||||
/* Define to 1 if you have GnuTLS 2.12.0 or above. */
|
||||
/* #undef HAVE_GNUTLS_SESSION_CHANNEL_BINDING */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the `bind' library (-lbind). */
|
||||
/* #undef HAVE_LIBBIND */
|
||||
|
||||
/* Define to 1 if you want IDN support. */
|
||||
/* #undef HAVE_LIBIDN */
|
||||
|
||||
/* Define to 1 if you have the `resolv' library (-lresolv). */
|
||||
/* #undef HAVE_LIBRESOLV */
|
||||
|
||||
/* Define to 1 if you have the `socket' library (-lsocket). */
|
||||
/* #undef HAVE_LIBSOCKET */
|
||||
|
||||
/* enable mdns support */
|
||||
/* #undef HAVE_MDNS */
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you want TLS support (OpenSSL). Undefine HAVE_GNUTLS. */
|
||||
#define HAVE_OPENSSL 1
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#define HAVE_PTHREAD 1
|
||||
|
||||
/* Define to 1 if you have the `res_query' function. */
|
||||
/* #undef HAVE_RES_QUERY */
|
||||
|
||||
/* Define to 1 if you have the `res_querydomain' function. */
|
||||
/* #undef HAVE_RES_QUERYDOMAIN */
|
||||
|
||||
/* Define to 1 if you have the `setsockopt' function. */
|
||||
/* #undef HAVE_SETSOCKOPT */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you want Stream Compression support. */
|
||||
#define HAVE_ZLIB 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "gloox"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "js@camaya.net"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "gloox"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "gloox 1.0.13"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "gloox"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "1.0.13"
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
//#define VERSION "1.0.13"
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
/* #undef inline */
|
||||
#endif
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
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 CONNECTIONBASE_H__
|
||||
#define CONNECTIONBASE_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "connectiondatahandler.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An abstract base class for a connection.
|
||||
*
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API ConnectionBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* @param cdh An object derived from @ref ConnectionDataHandler that will receive
|
||||
* received data.
|
||||
*/
|
||||
ConnectionBase( ConnectionDataHandler* cdh )
|
||||
: m_handler( cdh ), m_state( StateDisconnected ), m_port( -1 )
|
||||
{}
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~ConnectionBase() { cleanup(); }
|
||||
|
||||
/**
|
||||
* Used to initiate the connection.
|
||||
* @return Returns the connection state.
|
||||
*/
|
||||
virtual ConnectionError connect() = 0;
|
||||
|
||||
/**
|
||||
* Use this periodically to receive data from the socket.
|
||||
* @param timeout The timeout to use for select in microseconds. Default of -1 means blocking.
|
||||
* @return The state of the connection.
|
||||
*/
|
||||
virtual ConnectionError recv( int timeout = -1 ) = 0;
|
||||
|
||||
/**
|
||||
* Use this function to send a string of data over the wire. The function returns only after
|
||||
* all data has been sent.
|
||||
* @param data The data to send.
|
||||
* @return @b True if the data has been sent (no guarantee of receipt), @b false
|
||||
* in case of an error.
|
||||
*/
|
||||
virtual bool send( const std::string& data ) = 0;
|
||||
|
||||
/**
|
||||
* Use this function to put the connection into 'receive mode', i.e. this function returns only
|
||||
* when the connection is terminated.
|
||||
* @return Returns a value indicating the disconnection reason.
|
||||
*/
|
||||
virtual ConnectionError receive() = 0;
|
||||
|
||||
/**
|
||||
* Disconnects an established connection. NOOP if no active connection exists.
|
||||
*/
|
||||
virtual void disconnect() = 0;
|
||||
|
||||
/**
|
||||
* This function is called after a disconnect to clean up internal state. It is also called by
|
||||
* ConnectionBase's destructor.
|
||||
*/
|
||||
virtual void cleanup() {}
|
||||
|
||||
/**
|
||||
* Returns the current connection state.
|
||||
* @return The state of the connection.
|
||||
*/
|
||||
ConnectionState state() const { return m_state; }
|
||||
|
||||
/**
|
||||
* Use this function to register a new ConnectionDataHandler. There can be only one
|
||||
* ConnectionDataHandler at any one time.
|
||||
* @param cdh The new ConnectionDataHandler.
|
||||
*/
|
||||
void registerConnectionDataHandler( ConnectionDataHandler* cdh ) { m_handler = cdh; }
|
||||
|
||||
/**
|
||||
* Sets the server to connect to.
|
||||
* @param server The server to connect to. Either IP or fully qualified domain name.
|
||||
* @param port The port to connect to.
|
||||
*/
|
||||
void setServer( const std::string &server, int port = -1 ) { m_server = server; m_port = port; }
|
||||
|
||||
/**
|
||||
* Returns the currently set server/IP.
|
||||
* @return The server host/IP.
|
||||
*/
|
||||
const std::string& server() const { return m_server; }
|
||||
|
||||
/**
|
||||
* Returns the currently set port.
|
||||
* @return The server port.
|
||||
*/
|
||||
int port() const { return m_port; }
|
||||
|
||||
/**
|
||||
* Returns the local port.
|
||||
* @return The local port.
|
||||
*/
|
||||
virtual int localPort() const { return -1; }
|
||||
|
||||
/**
|
||||
* Returns the locally bound IP address.
|
||||
* @return The locally bound IP address.
|
||||
*/
|
||||
virtual const std::string localInterface() const { return EmptyString; }
|
||||
|
||||
/**
|
||||
* Returns current connection statistics.
|
||||
* @param totalIn The total number of bytes received.
|
||||
* @param totalOut The total number of bytes sent.
|
||||
*/
|
||||
virtual void getStatistics( long int &totalIn, long int &totalOut ) = 0;
|
||||
|
||||
/**
|
||||
* This function returns a new instance of the current ConnectionBase-derived object.
|
||||
* The idea is to be able to 'clone' ConnectionBase-derived objects without knowing of
|
||||
* what type they are exactly.
|
||||
* @return A new Connection* instance.
|
||||
*/
|
||||
virtual ConnectionBase* newInstance() const = 0;
|
||||
|
||||
protected:
|
||||
/** A handler for incoming data and connect/disconnect events. */
|
||||
ConnectionDataHandler* m_handler;
|
||||
|
||||
/** Holds the current connection state. */
|
||||
ConnectionState m_state;
|
||||
|
||||
/** Holds the server's name/address. */
|
||||
std::string m_server;
|
||||
|
||||
/** Holds the port to connect to. */
|
||||
int m_port;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONBASE_H__
|
|
@ -1,651 +0,0 @@
|
|||
/*
|
||||
* 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 "config.h"
|
||||
|
||||
#include "gloox.h"
|
||||
|
||||
#include "connectionbosh.h"
|
||||
#include "logsink.h"
|
||||
#include "prep.h"
|
||||
#include "tag.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(__HAIKU__) && __GNUC__ < 4
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ConnectionBOSH::ConnectionBOSH( ConnectionBase* connection, const LogSink& logInstance,
|
||||
const std::string& boshHost, const std::string& xmppServer,
|
||||
int xmppPort )
|
||||
: ConnectionBase( 0 ),
|
||||
m_logInstance( logInstance ), m_parser( this ), m_boshHost( boshHost ), m_path( "/http-bind/" ),
|
||||
m_rid( 0 ), m_initialStreamSent( false ), m_openRequests( 0 ),
|
||||
m_maxOpenRequests( 2 ), m_wait( 30 ), m_hold( 2 ), m_streamRestart( false ),
|
||||
m_lastRequestTime( std::time( 0 ) ), m_minTimePerRequest( 0 ), m_bufferContentLength( 0 ),
|
||||
m_connMode( ModePipelining )
|
||||
{
|
||||
initInstance( connection, xmppServer, xmppPort );
|
||||
}
|
||||
|
||||
ConnectionBOSH::ConnectionBOSH( ConnectionDataHandler* cdh, ConnectionBase* connection,
|
||||
const LogSink& logInstance, const std::string& boshHost,
|
||||
const std::string& xmppServer, int xmppPort )
|
||||
: ConnectionBase( cdh ),
|
||||
m_logInstance( logInstance ), m_parser( this ), m_boshHost( boshHost ), m_path( "/http-bind/" ),
|
||||
m_rid( 0 ), m_initialStreamSent( false ), m_openRequests( 0 ),
|
||||
m_maxOpenRequests( 2 ), m_wait( 30 ), m_hold( 2 ), m_streamRestart( false ),
|
||||
m_lastRequestTime( std::time( 0 ) ), m_minTimePerRequest( 0 ), m_bufferContentLength( 0 ),
|
||||
m_connMode( ModePipelining )
|
||||
{
|
||||
initInstance( connection, xmppServer, xmppPort );
|
||||
}
|
||||
|
||||
void ConnectionBOSH::initInstance( ConnectionBase* connection, const std::string& xmppServer,
|
||||
const int xmppPort )
|
||||
{
|
||||
// FIXME: check return value
|
||||
prep::idna( xmppServer, m_server );
|
||||
m_port = xmppPort;
|
||||
if( m_port != -1 )
|
||||
{
|
||||
m_boshedHost = m_boshHost + ":" + util::int2string( m_port );
|
||||
}
|
||||
|
||||
// drop this connection into our pool of available connections
|
||||
if( connection )
|
||||
{
|
||||
connection->registerConnectionDataHandler( this );
|
||||
m_connectionPool.push_back( connection );
|
||||
}
|
||||
}
|
||||
|
||||
ConnectionBOSH::~ConnectionBOSH()
|
||||
{
|
||||
util::clearList( m_activeConnections );
|
||||
util::clearList( m_connectionPool );
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionBOSH::newInstance() const
|
||||
{
|
||||
ConnectionBase* pBaseConn = 0;
|
||||
|
||||
if( !m_connectionPool.empty() )
|
||||
{
|
||||
pBaseConn = m_connectionPool.front()->newInstance();
|
||||
}
|
||||
else if( !m_activeConnections.empty() )
|
||||
{
|
||||
pBaseConn = m_activeConnections.front()->newInstance();
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return new ConnectionBOSH( m_handler, pBaseConn, m_logInstance,
|
||||
m_boshHost, m_server, m_port );
|
||||
}
|
||||
|
||||
ConnectionError ConnectionBOSH::connect()
|
||||
{
|
||||
if( m_state >= StateConnecting )
|
||||
return ConnNoError;
|
||||
|
||||
if( !m_handler )
|
||||
return ConnNotConnected;
|
||||
|
||||
m_state = StateConnecting;
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"Initiating BOSH connection to server: " +
|
||||
( ( m_connMode == ModePipelining ) ? std::string( "Pipelining" )
|
||||
: ( ( m_connMode == ModeLegacyHTTP ) ? std::string( "LegacyHTTP" )
|
||||
: std::string( "PersistentHTTP" ) ) ) );
|
||||
getConnection();
|
||||
return ConnNoError; // FIXME?
|
||||
}
|
||||
|
||||
void ConnectionBOSH::disconnect()
|
||||
{
|
||||
if( ( m_connMode == ModePipelining && m_activeConnections.empty() )
|
||||
|| ( m_connectionPool.empty() && m_activeConnections.empty() ) )
|
||||
return;
|
||||
|
||||
if( m_state != StateDisconnected )
|
||||
{
|
||||
++m_rid;
|
||||
|
||||
std::string requestBody = "<body rid='" + util::int2string( m_rid ) + "' ";
|
||||
requestBody += "sid='" + m_sid + "' ";
|
||||
requestBody += "type='terminal' ";
|
||||
requestBody += "xml:lang='en' ";
|
||||
requestBody += "xmlns='" + XMLNS_HTTPBIND + "'";
|
||||
if( m_sendBuffer.empty() ) // Make sure that any data in the send buffer gets sent
|
||||
requestBody += "/>";
|
||||
else
|
||||
{
|
||||
requestBody += ">" + m_sendBuffer + "</body>";
|
||||
m_sendBuffer = EmptyString;
|
||||
}
|
||||
sendRequest( requestBody );
|
||||
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "BOSH disconnection request sent" );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_logInstance.err( LogAreaClassConnectionBOSH,
|
||||
"Disconnecting from server in a non-graceful fashion" );
|
||||
}
|
||||
|
||||
util::ForEach( m_activeConnections, &ConnectionBase::disconnect );
|
||||
util::ForEach( m_connectionPool, &ConnectionBase::disconnect );
|
||||
|
||||
m_state = StateDisconnected;
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, ConnUserDisconnected );
|
||||
}
|
||||
|
||||
ConnectionError ConnectionBOSH::recv( int timeout )
|
||||
{
|
||||
ConnectionError ret = ConnNoError;
|
||||
|
||||
if( m_state == StateDisconnected )
|
||||
return ConnNotConnected;
|
||||
|
||||
if( !m_connectionPool.empty() )
|
||||
ret = m_connectionPool.front()->recv( 0 );
|
||||
if( !m_activeConnections.empty() )
|
||||
ret = m_activeConnections.front()->recv( timeout );
|
||||
|
||||
// If there are no open requests then the spec allows us to send an empty request...
|
||||
// (Some CMs do not obey this, it seems)
|
||||
if( ( m_openRequests == 0 || m_sendBuffer.size() > 0 ) && m_state == StateConnected )
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"Sending empty request (or there is data in the send buffer)" );
|
||||
sendXML();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ConnectionBOSH::send( const std::string& data )
|
||||
{
|
||||
|
||||
if( m_state == StateDisconnected )
|
||||
return false;
|
||||
|
||||
if( data.substr( 0, 2 ) == "<?" )
|
||||
{
|
||||
// if( m_initialStreamSent )
|
||||
{
|
||||
m_streamRestart = true;
|
||||
sendXML();
|
||||
return true;
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// m_initialStreamSent = true;
|
||||
// m_logInstance.dbg( LogAreaClassConnectionBOSH, "Initial <stream:stream> dropped" );
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
else if( data == "</stream:stream>" )
|
||||
return true;
|
||||
|
||||
m_sendBuffer += data;
|
||||
sendXML();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Sends XML. Wraps data in a <body/> tag, and then passes to sendRequest(). */
|
||||
bool ConnectionBOSH::sendXML()
|
||||
{
|
||||
if( m_state != StateConnected )
|
||||
{
|
||||
m_logInstance.warn( LogAreaClassConnectionBOSH,
|
||||
"Data sent before connection established (will be buffered)" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_sendBuffer.empty() )
|
||||
{
|
||||
time_t now = time( 0 );
|
||||
unsigned int delta = (int)(now - m_lastRequestTime);
|
||||
if( delta < m_minTimePerRequest && m_openRequests > 0 )
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Too little time between requests: " + util::int2string( delta ) + " seconds" );
|
||||
return false;
|
||||
}
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Send buffer is empty, sending empty request" );
|
||||
}
|
||||
|
||||
++m_rid;
|
||||
|
||||
std::string requestBody = "<body rid='" + util::int2string( m_rid ) + "' ";
|
||||
requestBody += "sid='" + m_sid + "' ";
|
||||
requestBody += "xmlns='" + XMLNS_HTTPBIND + "'";
|
||||
|
||||
if( m_streamRestart )
|
||||
{
|
||||
requestBody += " xmpp:restart='true' to='" + m_server + "' xml:lang='en' xmlns:xmpp='"
|
||||
+ XMLNS_XMPP_BOSH + "' />";
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Restarting stream" );
|
||||
}
|
||||
else
|
||||
{
|
||||
requestBody += ">" + m_sendBuffer + "</body>";
|
||||
}
|
||||
// Send a request. Force if we are not sending an empty request, or if there are no connections open
|
||||
if( sendRequest( requestBody ) )
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Successfully sent m_sendBuffer" );
|
||||
m_sendBuffer = EmptyString;
|
||||
m_streamRestart = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
--m_rid; // I think... (may need to rethink when acks are implemented)
|
||||
m_logInstance.warn( LogAreaClassConnectionBOSH,
|
||||
"Unable to send. Connection not complete, or too many open requests,"
|
||||
" so added to buffer." );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Chooses the appropriate connection, or opens a new one if necessary. Wraps xml in HTTP and sends. */
|
||||
bool ConnectionBOSH::sendRequest( const std::string& xml )
|
||||
{
|
||||
ConnectionBase* conn = getConnection();
|
||||
if( !conn )
|
||||
return false;
|
||||
|
||||
std::string request = "POST " + m_path;
|
||||
if( m_connMode == ModeLegacyHTTP )
|
||||
{
|
||||
request += " HTTP/1.0\r\n";
|
||||
request += "Connection: close\r\n";
|
||||
}
|
||||
else
|
||||
request += " HTTP/1.1\r\n";
|
||||
|
||||
request += "Host: " + m_boshedHost + "\r\n";
|
||||
request += "Content-Type: text/xml; charset=utf-8\r\n";
|
||||
request += "Content-Length: " + util::int2string( xml.length() ) + "\r\n";
|
||||
request += "User-Agent: gloox/" + GLOOX_VERSION + "\r\n\r\n";
|
||||
request += xml;
|
||||
|
||||
|
||||
if( conn->send( request ) )
|
||||
{
|
||||
m_lastRequestTime = time( 0 );
|
||||
++m_openRequests;
|
||||
return true;
|
||||
}
|
||||
// else // FIXME What to do in this case?
|
||||
// printf( "Error while trying to send on socket (state: %d)\n", conn->state() );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ci_equal( char ch1, char ch2 )
|
||||
{
|
||||
#if defined(__HAIKU__) && __GNUC__ < 4
|
||||
return toupper( (unsigned char)ch1 ) == toupper( (unsigned char)ch2 );
|
||||
#else
|
||||
return std::toupper( (unsigned char)ch1 ) == std::toupper( (unsigned char)ch2 );
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string::size_type ci_find( const std::string& str1, const std::string& str2 )
|
||||
{
|
||||
std::string::const_iterator pos = std::search( str1.begin(), str1.end(),
|
||||
str2.begin(), str2.end(), ci_equal );
|
||||
if( pos == str1.end() )
|
||||
return std::string::npos;
|
||||
else
|
||||
return std::distance( str1.begin(), pos );
|
||||
}
|
||||
|
||||
const std::string ConnectionBOSH::getHTTPField( const std::string& field )
|
||||
{
|
||||
std::string::size_type fp = ci_find( m_bufferHeader, "\r\n" + field + ": " );
|
||||
|
||||
if( fp == std::string::npos )
|
||||
return EmptyString;
|
||||
|
||||
fp += field.length() + 4;
|
||||
|
||||
const std::string::size_type fp2 = m_bufferHeader.find( "\r\n", fp );
|
||||
if( fp2 == std::string::npos )
|
||||
return EmptyString;
|
||||
|
||||
return m_bufferHeader.substr( fp, fp2 - fp );
|
||||
}
|
||||
|
||||
ConnectionError ConnectionBOSH::receive()
|
||||
{
|
||||
ConnectionError err = ConnNoError;
|
||||
while( m_state != StateDisconnected && ( err = recv( 10 ) ) == ConnNoError )
|
||||
;
|
||||
return err == ConnNoError ? ConnNotConnected : err;
|
||||
}
|
||||
|
||||
void ConnectionBOSH::cleanup()
|
||||
{
|
||||
m_state = StateDisconnected;
|
||||
|
||||
util::ForEach( m_activeConnections, &ConnectionBase::cleanup );
|
||||
util::ForEach( m_connectionPool, &ConnectionBase::cleanup );
|
||||
}
|
||||
|
||||
void ConnectionBOSH::getStatistics( long int& totalIn, long int& totalOut )
|
||||
{
|
||||
util::ForEach( m_activeConnections, &ConnectionBase::getStatistics, totalIn, totalOut );
|
||||
util::ForEach( m_connectionPool, &ConnectionBase::getStatistics, totalIn, totalOut );
|
||||
}
|
||||
|
||||
void ConnectionBOSH::handleReceivedData( const ConnectionBase* /*connection*/,
|
||||
const std::string& data )
|
||||
{
|
||||
m_buffer += data;
|
||||
std::string::size_type headerLength = 0;
|
||||
while( ( headerLength = m_buffer.find( "\r\n\r\n" ) ) != std::string::npos )
|
||||
{
|
||||
m_bufferHeader = m_buffer.substr( 0, headerLength+2 );
|
||||
|
||||
const std::string& statusCode = m_bufferHeader.substr( 9, 3 );
|
||||
if( statusCode != "200" )
|
||||
{
|
||||
m_logInstance.warn( LogAreaClassConnectionBOSH,
|
||||
"Received error via legacy HTTP status code: " + statusCode
|
||||
+ ". Disconnecting." );
|
||||
m_state = StateDisconnected; // As per XEP, consider connection broken
|
||||
disconnect();
|
||||
}
|
||||
|
||||
m_bufferContentLength = atol( getHTTPField( "Content-Length" ).c_str() );
|
||||
if( !m_bufferContentLength )
|
||||
return;
|
||||
|
||||
if( m_connMode != ModeLegacyHTTP && ( getHTTPField( "Connection" ) == "close"
|
||||
|| m_bufferHeader.substr( 0, 8 ) == "HTTP/1.0" ) )
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"Server indicated lack of support for HTTP/1.1 - falling back to HTTP/1.0" );
|
||||
m_connMode = ModeLegacyHTTP;
|
||||
}
|
||||
|
||||
if( m_buffer.length() >= ( headerLength + 4 + m_bufferContentLength ) )
|
||||
{
|
||||
putConnection();
|
||||
--m_openRequests;
|
||||
std::string xml = m_buffer.substr( headerLength + 4, m_bufferContentLength );
|
||||
m_parser.feed( xml );
|
||||
m_buffer.erase( 0, headerLength + 4 + m_bufferContentLength );
|
||||
m_bufferContentLength = 0;
|
||||
m_bufferHeader = EmptyString;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_logInstance.warn( LogAreaClassConnectionBOSH, "Buffer length mismatch" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionBOSH::handleConnect( const ConnectionBase* /*connection*/ )
|
||||
{
|
||||
if( m_state == StateConnecting )
|
||||
{
|
||||
m_rid = rand() % 100000 + 1728679472;
|
||||
|
||||
Tag requestBody( "body" );
|
||||
requestBody.setXmlns( XMLNS_HTTPBIND );
|
||||
requestBody.setXmlns( XMLNS_XMPP_BOSH, "xmpp" );
|
||||
|
||||
requestBody.addAttribute( "content", "text/xml; charset=utf-8" );
|
||||
requestBody.addAttribute( "hold", (long)m_hold );
|
||||
requestBody.addAttribute( "rid", (long)m_rid );
|
||||
requestBody.addAttribute( "ver", "1.6" );
|
||||
requestBody.addAttribute( "wait", (long)m_wait );
|
||||
requestBody.addAttribute( "ack", 0 );
|
||||
requestBody.addAttribute( "secure", "false" );
|
||||
requestBody.addAttribute( "route", "xmpp:" + m_server + ":5222" );
|
||||
requestBody.addAttribute( "xml:lang", "en" );
|
||||
requestBody.addAttribute( "xmpp:version", "1.0" );
|
||||
requestBody.addAttribute( "to", m_server );
|
||||
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Sending BOSH connection request" );
|
||||
sendRequest( requestBody.xml() );
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionBOSH::handleDisconnect( const ConnectionBase* /*connection*/,
|
||||
ConnectionError reason )
|
||||
{
|
||||
if( m_handler && m_state == StateConnecting )
|
||||
{
|
||||
m_state = StateDisconnected;
|
||||
m_handler->handleDisconnect( this, reason );
|
||||
return;
|
||||
}
|
||||
|
||||
switch( m_connMode ) // FIXME avoid that if we're disconnecting on purpose
|
||||
{
|
||||
case ModePipelining:
|
||||
m_connMode = ModeLegacyHTTP; // Server seems not to support pipelining
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"Connection closed - falling back to HTTP/1.0 connection method" );
|
||||
break;
|
||||
case ModeLegacyHTTP:
|
||||
case ModePersistentHTTP:
|
||||
// FIXME do we need to do anything here?
|
||||
// printf( "A TCP connection %p was disconnected (reason: %d).\n", connection, reason );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionBOSH::handleTag( Tag* tag )
|
||||
{
|
||||
if( !m_handler || tag->name() != "body" )
|
||||
return;
|
||||
|
||||
if( m_streamRestart )
|
||||
{
|
||||
m_streamRestart = false;
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Sending spoofed <stream:stream>" );
|
||||
m_handler->handleReceivedData( this, "<?xml version='1.0' ?>"
|
||||
"<stream:stream xmlns:stream='http://etherx.jabber.org/streams'"
|
||||
" xmlns='" + XMLNS_CLIENT + "' version='" + XMPP_STREAM_VERSION_MAJOR
|
||||
+ "." + XMPP_STREAM_VERSION_MINOR + "' from='" + m_server + "' id ='"
|
||||
+ m_sid + "' xml:lang='en'>" );
|
||||
}
|
||||
|
||||
if( tag->hasAttribute( "sid" ) )
|
||||
{
|
||||
m_state = StateConnected;
|
||||
m_sid = tag->findAttribute( "sid" );
|
||||
|
||||
if( tag->hasAttribute( "requests" ) )
|
||||
{
|
||||
const int serverRequests = atoi( tag->findAttribute( "requests" ).c_str() );
|
||||
if( serverRequests < m_maxOpenRequests )
|
||||
{
|
||||
m_maxOpenRequests = serverRequests;
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"BOSH parameter 'requests' now set to " + tag->findAttribute( "requests" ) );
|
||||
}
|
||||
}
|
||||
if( tag->hasAttribute( "hold" ) )
|
||||
{
|
||||
const int maxHold = atoi( tag->findAttribute( "hold" ).c_str() );
|
||||
if( maxHold < m_hold )
|
||||
{
|
||||
m_hold = maxHold;
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"BOSH parameter 'hold' now set to " + tag->findAttribute( "hold" ) );
|
||||
}
|
||||
}
|
||||
if( tag->hasAttribute( "wait" ) )
|
||||
{
|
||||
const int maxWait = atoi( tag->findAttribute( "wait" ).c_str() );
|
||||
if( maxWait < m_wait )
|
||||
{
|
||||
m_wait = maxWait;
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"BOSH parameter 'wait' now set to " + tag->findAttribute( "wait" )
|
||||
+ " seconds" );
|
||||
}
|
||||
}
|
||||
if( tag->hasAttribute( "polling" ) )
|
||||
{
|
||||
const int minTime = atoi( tag->findAttribute( "polling" ).c_str() );
|
||||
m_minTimePerRequest = minTime;
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"BOSH parameter 'polling' now set to " + tag->findAttribute( "polling" )
|
||||
+ " seconds" );
|
||||
}
|
||||
|
||||
if( m_state < StateConnected )
|
||||
m_handler->handleConnect( this );
|
||||
|
||||
m_handler->handleReceivedData( this, "<?xml version='1.0' ?>" // FIXME move to send() so that
|
||||
// it is more clearly a response
|
||||
// to the initial stream opener?
|
||||
"<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "
|
||||
"xmlns='" + XMLNS_CLIENT
|
||||
+ "' version='" + XMPP_STREAM_VERSION_MAJOR + "." + XMPP_STREAM_VERSION_MINOR
|
||||
+ "' from='" + m_server + "' id ='" + m_sid + "' xml:lang='en'>" );
|
||||
}
|
||||
|
||||
if( tag->findAttribute( "type" ) == "terminate" )
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH,
|
||||
"BOSH connection closed by server: " + tag->findAttribute( "condition" ) );
|
||||
m_state = StateDisconnected;
|
||||
m_handler->handleDisconnect( this, ConnStreamClosed );
|
||||
return;
|
||||
}
|
||||
|
||||
const TagList& stanzas = tag->children();
|
||||
TagList::const_iterator it = stanzas.begin();
|
||||
for( ; it != stanzas.end(); ++it )
|
||||
m_handler->handleReceivedData( this, (*it)->xml() );
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionBOSH::getConnection()
|
||||
{
|
||||
if( m_openRequests > 0 && m_openRequests >= m_maxOpenRequests )
|
||||
{
|
||||
m_logInstance.warn( LogAreaClassConnectionBOSH,
|
||||
"Too many requests already open. Cannot send." );
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConnectionBase* conn = 0;
|
||||
switch( m_connMode )
|
||||
{
|
||||
case ModePipelining:
|
||||
if( !m_activeConnections.empty() )
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Using default connection for Pipelining." );
|
||||
return m_activeConnections.front();
|
||||
}
|
||||
else if( !m_connectionPool.empty() )
|
||||
{
|
||||
m_logInstance.warn( LogAreaClassConnectionBOSH,
|
||||
"Pipelining selected, but no connection open. Opening one." );
|
||||
return activateConnection();
|
||||
}
|
||||
else
|
||||
m_logInstance.warn( LogAreaClassConnectionBOSH,
|
||||
"No available connections to pipeline on." );
|
||||
break;
|
||||
case ModeLegacyHTTP:
|
||||
case ModePersistentHTTP:
|
||||
{
|
||||
if( !m_connectionPool.empty() )
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "LegacyHTTP/PersistentHTTP selected, "
|
||||
"using connection from pool." );
|
||||
return activateConnection();
|
||||
}
|
||||
else if( !m_activeConnections.empty() )
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "No connections in pool, creating a new one." );
|
||||
conn = m_activeConnections.front()->newInstance();
|
||||
conn->registerConnectionDataHandler( this );
|
||||
m_connectionPool.push_back( conn );
|
||||
conn->connect();
|
||||
}
|
||||
else
|
||||
m_logInstance.warn( LogAreaClassConnectionBOSH,
|
||||
"No available connections to send on." );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionBOSH::activateConnection()
|
||||
{
|
||||
ConnectionBase* conn = m_connectionPool.front();
|
||||
m_connectionPool.pop_front();
|
||||
if( conn->state() == StateConnected )
|
||||
{
|
||||
m_activeConnections.push_back( conn );
|
||||
return conn;
|
||||
}
|
||||
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Connecting pooled connection." );
|
||||
m_connectionPool.push_back( conn );
|
||||
conn->connect();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConnectionBOSH::putConnection()
|
||||
{
|
||||
ConnectionBase* conn = m_activeConnections.front();
|
||||
|
||||
switch( m_connMode )
|
||||
{
|
||||
case ModeLegacyHTTP:
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Disconnecting LegacyHTTP connection" );
|
||||
conn->disconnect();
|
||||
conn->cleanup(); // This is necessary
|
||||
m_activeConnections.pop_front();
|
||||
m_connectionPool.push_back( conn );
|
||||
break;
|
||||
case ModePersistentHTTP:
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Deactivating PersistentHTTP connection" );
|
||||
m_activeConnections.pop_front();
|
||||
m_connectionPool.push_back( conn );
|
||||
break;
|
||||
case ModePipelining:
|
||||
m_logInstance.dbg( LogAreaClassConnectionBOSH, "Keeping Pipelining connection" );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,225 +0,0 @@
|
|||
/*
|
||||
* 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 CONNECTIONBOSH_H__
|
||||
#define CONNECTIONBOSH_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "connectionbase.h"
|
||||
#include "logsink.h"
|
||||
#include "taghandler.h"
|
||||
#include "parser.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <ctime>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a BOSH (HTTP binding) connection.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* @code
|
||||
* Client *c = new Client( ... );
|
||||
* c->setConnectionImpl( new ConnectionBOSH( c,
|
||||
* new ConnectionTCPClient( c->logInstance(), httpServer, httpPort ),
|
||||
* c->logInstance(), boshHost, xmpphost, xmppPort ) );
|
||||
* @endcode
|
||||
*
|
||||
* Make sure to pass the BOSH connection manager's host/port to the transport connection
|
||||
* (ConnectionTCPClient in this case), and the XMPP server's host and port to the BOSH connection.
|
||||
* You must also pass to BOSH the address of the BOSH server you are dealing with, this is used
|
||||
* in the HTTP Host header.
|
||||
*
|
||||
* In the case of using ConnectionBOSH through a HTTP proxy, supply httpServer and httpPort as
|
||||
* those of the proxy. In all cases, boshHost should be set to the hostname (not IP address) of
|
||||
* the server running the BOSH connection manager.
|
||||
*
|
||||
* The reason why ConnectionBOSH doesn't manage its own ConnectionTCPClient is that it allows it
|
||||
* to be used with other transports (like chained SOCKS5/HTTP proxies, or ConnectionTLS
|
||||
* for HTTPS).
|
||||
*
|
||||
* @note To avoid problems, you should disable TLS in gloox by calling
|
||||
* ClientBase::setTls( TLSDisabled ).
|
||||
*
|
||||
* Sample configurations for different servers can be found in the bosh_example.cpp file included
|
||||
* with gloox in the @b src/examples/ directory.
|
||||
*
|
||||
* @author Matthew Wild <mwild1@gmail.com>
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API ConnectionBOSH : public ConnectionBase, ConnectionDataHandler, TagHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new ConnectionBOSH object.
|
||||
* @param connection A transport connection. It should be configured to connect to
|
||||
* the BOSH connection manager's (or a HTTP proxy's) host and port, @b not to the XMPP host.
|
||||
* ConnectionBOSH will own the transport connection and delete it in its destructor.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param boshHost The hostname of the BOSH connection manager
|
||||
* @param xmppServer A server to connect to. This is the XMPP server's address, @b not the
|
||||
* connection manager's.
|
||||
* @param xmppPort The port to connect to. This is the XMPP server's port, @b not the connection
|
||||
* manager's.
|
||||
* @note To properly use this object, you have to set a ConnectionDataHandler using
|
||||
* registerConnectionDataHandler(). This is not necessary if this object is
|
||||
* part of a 'connection chain', e.g. with ConnectionSOCKS5Proxy.
|
||||
*/
|
||||
ConnectionBOSH( ConnectionBase* connection, const LogSink& logInstance, const std::string& boshHost,
|
||||
const std::string& xmppServer, int xmppPort = 5222 );
|
||||
|
||||
/**
|
||||
* Constructs a new ConnectionBOSH object.
|
||||
* @param cdh An ConnectionDataHandler-derived object that will handle incoming data.
|
||||
* @param connection A transport connection. It should be configured to connect to
|
||||
* the connection manager's (or proxy's) host and port, @b not to the XMPP host. ConnectionBOSH
|
||||
* will own the transport connection and delete it in its destructor.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param boshHost The hostname of the BOSH connection manager (not any intermediate proxy)
|
||||
* @param xmppServer A server to connect to. This is the XMPP server's address, @b not the connection
|
||||
* manager's.
|
||||
* @param xmppPort The port to connect to. This is the XMPP server's port, @b not the connection
|
||||
* manager's.
|
||||
*/
|
||||
ConnectionBOSH( ConnectionDataHandler* cdh, ConnectionBase* connection,
|
||||
const LogSink& logInstance, const std::string& boshHost,
|
||||
const std::string& xmppServer, int xmppPort = 5222 );
|
||||
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~ConnectionBOSH();
|
||||
|
||||
/**
|
||||
* The supported connection modes. Usually auto-detected.
|
||||
*/
|
||||
enum ConnMode
|
||||
{
|
||||
ModeLegacyHTTP, /**< HTTP 1.0 connections, closed after receiving a response */
|
||||
ModePersistentHTTP, /**< HTTP 1.1 connections, re-used after receiving a response */
|
||||
ModePipelining /**< HTTP Pipelining (implies HTTP 1.1) a single connection is used */
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the XMPP server to proxy to.
|
||||
* @param xmppHost The XMPP server hostname (IP address).
|
||||
* @param xmppPort The XMPP server port.
|
||||
*/
|
||||
void setServer( const std::string& xmppHost, unsigned short xmppPort = 5222 )
|
||||
{ m_server = xmppHost; m_port = xmppPort; }
|
||||
|
||||
/**
|
||||
* Sets the path on the connection manager to request
|
||||
* @param path The path, the default is "/http-bind/", which is the default for
|
||||
* many connection managers.
|
||||
*/
|
||||
void setPath( const std::string& path ) { m_path = path; }
|
||||
|
||||
/**
|
||||
* Sets the connection mode
|
||||
* @param mode The connection mode, @sa ConnMode
|
||||
* @note In the case that a mode is selected that the connection manager
|
||||
* or proxy does not support, gloox will fall back to using HTTP/1.0 connections,
|
||||
* which should work with any server.
|
||||
*/
|
||||
void setMode( ConnMode mode ) { m_connMode = mode; }
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError connect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError recv( int timeout = -1 );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual bool send( const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError receive();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void disconnect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void cleanup();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void getStatistics( long int& totalIn, long int& totalOut );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleReceivedData( const ConnectionBase* connection, const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleConnect( const ConnectionBase* connection );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleDisconnect( const ConnectionBase* connection, ConnectionError reason );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual ConnectionBase* newInstance() const;
|
||||
|
||||
// reimplemented from TagHandler
|
||||
virtual void handleTag( Tag* tag );
|
||||
|
||||
private:
|
||||
ConnectionBOSH& operator=( const ConnectionBOSH& );
|
||||
void initInstance( ConnectionBase* connection, const std::string& xmppServer, const int xmppPort );
|
||||
bool sendRequest( const std::string& xml );
|
||||
bool sendXML();
|
||||
const std::string getHTTPField( const std::string& field );
|
||||
ConnectionBase* getConnection();
|
||||
ConnectionBase* activateConnection();
|
||||
void putConnection();
|
||||
|
||||
//ConnectionBase *m_connection;
|
||||
const LogSink& m_logInstance;
|
||||
|
||||
Parser m_parser; // Used for parsing XML section of responses
|
||||
std::string m_boshHost; // The hostname of the BOSH connection manager
|
||||
std::string m_boshedHost; // The hostname of the BOSH connection manager + : + port
|
||||
std::string m_path; // The path part of the URL that we need to request
|
||||
|
||||
// BOSH parameters
|
||||
unsigned long m_rid;
|
||||
std::string m_sid;
|
||||
|
||||
bool m_initialStreamSent;
|
||||
int m_openRequests;
|
||||
int m_maxOpenRequests;
|
||||
int m_wait;
|
||||
int m_hold;
|
||||
|
||||
bool m_streamRestart; // Set to true if we are waiting for an acknowledgement of a stream restart
|
||||
|
||||
time_t m_lastRequestTime;
|
||||
unsigned long m_minTimePerRequest;
|
||||
|
||||
std::string m_buffer; // Buffer of received data
|
||||
std::string m_bufferHeader; // HTTP header of data currently in buffer // FIXME doens't need to be member
|
||||
std::string::size_type m_bufferContentLength; // Length of the data in the current response
|
||||
|
||||
std::string m_sendBuffer; // Data waiting to be sent
|
||||
|
||||
typedef std::list<ConnectionBase*> ConnectionList;
|
||||
ConnectionList m_activeConnections;
|
||||
ConnectionList m_connectionPool;
|
||||
ConnMode m_connMode;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONBOSH_H__
|
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
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 CONNECTIONDATAHANDLER_H__
|
||||
#define CONNECTIONDATAHANDLER_H__
|
||||
|
||||
#include "gloox.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class ConnectionBase;
|
||||
|
||||
/**
|
||||
* @brief This is an abstract base class to receive events from a ConnectionBase-derived object.
|
||||
*
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API ConnectionDataHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~ConnectionDataHandler() {}
|
||||
|
||||
/**
|
||||
* This function is called for received from the underlying transport.
|
||||
* @param connection The connection that received the data.
|
||||
* @param data The data received.
|
||||
*/
|
||||
virtual void handleReceivedData( const ConnectionBase* connection, const std::string& data ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called when e.g. the raw TCP connection was established.
|
||||
* @param connection The connection.
|
||||
*/
|
||||
virtual void handleConnect( const ConnectionBase* connection ) = 0;
|
||||
|
||||
/**
|
||||
* This connection is called when e.g. the raw TCP connection was closed.
|
||||
* @param connection The connection.
|
||||
* @param reason The reason for the disconnect.
|
||||
*/
|
||||
virtual void handleDisconnect( const ConnectionBase* connection, ConnectionError reason ) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONDATAHANDLER_H__
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
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 CONNECTIONHANDLER_H__
|
||||
#define CONNECTIONHANDLER_H__
|
||||
|
||||
#include "connectionbase.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an abstract base class to receive incoming connection attempts. Do not
|
||||
* confuse this with ConnectionListener, which is used with XMPP streams and has a
|
||||
* completely different meaning.
|
||||
*
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API ConnectionHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~ConnectionHandler() {}
|
||||
|
||||
/**
|
||||
* This function is called to receive an incoming connection.
|
||||
* @param server The server that the connection was made to.
|
||||
* @param connection The incoming connection.
|
||||
*/
|
||||
virtual void handleIncomingConnection( ConnectionBase* server, ConnectionBase* connection ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONHANDLER_H__
|
|
@ -1,215 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 "gloox.h"
|
||||
|
||||
#include "connectionhttpproxy.h"
|
||||
#include "dns.h"
|
||||
#include "logsink.h"
|
||||
#include "prep.h"
|
||||
#include "base64.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ConnectionHTTPProxy::ConnectionHTTPProxy( ConnectionBase* connection,
|
||||
const LogSink& logInstance,
|
||||
const std::string& server, int port )
|
||||
: ConnectionBase( 0 ), m_connection( connection ),
|
||||
m_logInstance( logInstance ), m_http11( false )
|
||||
{
|
||||
// FIXME check return value?
|
||||
prep::idna( server, m_server );
|
||||
m_port = port;
|
||||
|
||||
if( m_connection )
|
||||
m_connection->registerConnectionDataHandler( this );
|
||||
}
|
||||
|
||||
ConnectionHTTPProxy::ConnectionHTTPProxy( ConnectionDataHandler* cdh,
|
||||
ConnectionBase* connection,
|
||||
const LogSink& logInstance,
|
||||
const std::string& server, int port )
|
||||
: ConnectionBase( cdh ), m_connection( connection ),
|
||||
m_logInstance( logInstance )
|
||||
{
|
||||
// FIXME check return value?
|
||||
prep::idna( server, m_server );
|
||||
m_port = port;
|
||||
|
||||
if( m_connection )
|
||||
m_connection->registerConnectionDataHandler( this );
|
||||
}
|
||||
|
||||
ConnectionHTTPProxy::~ConnectionHTTPProxy()
|
||||
{
|
||||
delete m_connection;
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionHTTPProxy::newInstance() const
|
||||
{
|
||||
ConnectionBase* conn = m_connection ? m_connection->newInstance() : 0;
|
||||
return new ConnectionHTTPProxy( m_handler, conn, m_logInstance, m_server, m_port );
|
||||
}
|
||||
|
||||
void ConnectionHTTPProxy::setConnectionImpl( ConnectionBase* connection )
|
||||
{
|
||||
if( m_connection )
|
||||
delete m_connection;
|
||||
|
||||
m_connection = connection;
|
||||
}
|
||||
|
||||
ConnectionError ConnectionHTTPProxy::connect()
|
||||
{
|
||||
if( m_connection && m_handler )
|
||||
{
|
||||
m_state = StateConnecting;
|
||||
return m_connection->connect();
|
||||
}
|
||||
|
||||
return ConnNotConnected;
|
||||
}
|
||||
|
||||
void ConnectionHTTPProxy::disconnect()
|
||||
{
|
||||
m_state = StateDisconnected;
|
||||
if( m_connection )
|
||||
m_connection->disconnect();
|
||||
}
|
||||
|
||||
ConnectionError ConnectionHTTPProxy::recv( int timeout )
|
||||
{
|
||||
return m_connection ? m_connection->recv( timeout ) : ConnNotConnected;
|
||||
}
|
||||
|
||||
ConnectionError ConnectionHTTPProxy::receive()
|
||||
{
|
||||
return m_connection ? m_connection->receive() : ConnNotConnected;
|
||||
}
|
||||
|
||||
bool ConnectionHTTPProxy::send( const std::string& data )
|
||||
{
|
||||
return m_connection && m_connection->send( data );
|
||||
}
|
||||
|
||||
void ConnectionHTTPProxy::cleanup()
|
||||
{
|
||||
m_state = StateDisconnected;
|
||||
|
||||
if( m_connection )
|
||||
m_connection->cleanup();
|
||||
}
|
||||
|
||||
void ConnectionHTTPProxy::getStatistics( long int& totalIn, long int& totalOut )
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->getStatistics( totalIn, totalOut );
|
||||
else
|
||||
totalIn = totalOut = 0;
|
||||
}
|
||||
|
||||
void ConnectionHTTPProxy::handleReceivedData( const ConnectionBase* /*connection*/,
|
||||
const std::string& data )
|
||||
{
|
||||
if( !m_handler )
|
||||
return;
|
||||
|
||||
if( m_state == StateConnecting )
|
||||
{
|
||||
m_proxyHandshakeBuffer += data;
|
||||
if( ( !m_proxyHandshakeBuffer.compare( 0, 12, "HTTP/1.0 200" )
|
||||
|| !m_proxyHandshakeBuffer.compare( 0, 12, "HTTP/1.1 200" ) )
|
||||
&& !m_proxyHandshakeBuffer.compare( m_proxyHandshakeBuffer.length() - 4, 4, "\r\n\r\n" ) )
|
||||
{
|
||||
m_proxyHandshakeBuffer = EmptyString;
|
||||
m_state = StateConnected;
|
||||
m_logInstance.dbg( LogAreaClassConnectionHTTPProxy,
|
||||
"HTTP proxy connection established" );
|
||||
m_handler->handleConnect( this );
|
||||
}
|
||||
else if( !m_proxyHandshakeBuffer.compare( 9, 3, "407" ) )
|
||||
{
|
||||
m_handler->handleDisconnect( this, ConnProxyAuthRequired );
|
||||
m_connection->disconnect();
|
||||
}
|
||||
else if( !m_proxyHandshakeBuffer.compare( 9, 3, "403" )
|
||||
|| !m_proxyHandshakeBuffer.compare( 9, 3, "404" ) )
|
||||
{
|
||||
m_handler->handleDisconnect( this, ConnProxyAuthFailed );
|
||||
m_connection->disconnect();
|
||||
}
|
||||
}
|
||||
else if( m_state == StateConnected )
|
||||
m_handler->handleReceivedData( this, data );
|
||||
}
|
||||
|
||||
void ConnectionHTTPProxy::handleConnect( const ConnectionBase* /*connection*/ )
|
||||
{
|
||||
if( m_connection )
|
||||
{
|
||||
std::string server = m_server;
|
||||
int port = m_port;
|
||||
if( port == -1 )
|
||||
{
|
||||
const DNS::HostMap& servers = DNS::resolve( m_server, m_logInstance );
|
||||
if( !servers.empty() )
|
||||
{
|
||||
const std::pair< std::string, int >& host = *servers.begin();
|
||||
server = host.first;
|
||||
port = host.second;
|
||||
}
|
||||
}
|
||||
std::string message = "Requesting HTTP proxy connection to " + server + ":"
|
||||
+ util::int2string( port );
|
||||
m_logInstance.dbg( LogAreaClassConnectionHTTPProxy, message );
|
||||
|
||||
std::string os = "CONNECT " + server + ":" + util::int2string( port ) + " HTTP/1."
|
||||
+ util::int2string( m_http11 ? 1 : 0 ) + "\r\n"
|
||||
"Host: " + server + "\r\n"
|
||||
"Content-Length: 0\r\n"
|
||||
"Proxy-Connection: Keep-Alive\r\n"
|
||||
"Pragma: no-cache\r\n"
|
||||
"User-Agent: gloox/" + GLOOX_VERSION + "\r\n";
|
||||
|
||||
if( !m_proxyUser.empty() && !m_proxyPwd.empty() )
|
||||
{
|
||||
os += "Proxy-Authorization: Basic " + Base64::encode64( m_proxyUser + ":" + m_proxyPwd )
|
||||
+ "\r\n";
|
||||
}
|
||||
os += "\r\n";
|
||||
|
||||
if( !m_connection->send( os ) )
|
||||
{
|
||||
m_state = StateDisconnected;
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, ConnIoError );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionHTTPProxy::handleDisconnect( const ConnectionBase* /*connection*/,
|
||||
ConnectionError reason )
|
||||
{
|
||||
m_state = StateDisconnected;
|
||||
m_logInstance.dbg( LogAreaClassConnectionHTTPProxy, "HTTP Proxy connection closed" );
|
||||
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, reason );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 CONNECTIONHTTPPROXY_H__
|
||||
#define CONNECTIONHTTPPROXY_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "connectionbase.h"
|
||||
#include "logsink.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a simple HTTP Proxying connection.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* @code
|
||||
* Client* c = new Client( ... );
|
||||
* ConnectionTCPClient* conn0 = new ConnectionTCPClient( c->logInstance(),
|
||||
* proxyHost, proxyPort );
|
||||
* ConnectionHTTPProxy* conn1 = new ConnectionHTTPProxy( c, conn0, c->logInstance(),
|
||||
* xmppHost, xmppPort );
|
||||
* c->setConnectionImpl( conn1 );
|
||||
* @endcode
|
||||
*
|
||||
* Make sure to pass the proxy host/port to the transport connection (ConnectionTCPClient in this case),
|
||||
* and the XMPP host/port to the proxy connection.
|
||||
*
|
||||
* ConnectionHTTPProxy uses the CONNECT method to pass through the proxy. If your proxy does not
|
||||
* allow this kind of connections, or if it kills connections after some time, you may want to use
|
||||
* ConnectionBOSH instead or in addition.
|
||||
*
|
||||
* The reason why ConnectionHTTPProxy doesn't manage its own ConnectionTCPClient is that it allows it
|
||||
* to be used with other transports (like IPv6 or chained SOCKS5/HTTP proxies).
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API ConnectionHTTPProxy : public ConnectionBase, public ConnectionDataHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new ConnectionHTTPProxy object.
|
||||
* @param connection A transport connection. It should be configured to connect to
|
||||
* the proxy host and port, @b not to the XMPP host. ConnectionHTTPProxy will own the
|
||||
* transport connection and delete it in its destructor.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param server A server to connect to. This is the XMPP server's address, @b not the proxy.
|
||||
* @param port The port to connect to. This is the XMPP server's port, @b not the proxy's.
|
||||
* The default of -1 means that SRV records will be used to find out about the actual host:port.
|
||||
* @note To properly use this object, you have to set a ConnectionDataHandler using
|
||||
* registerConnectionDataHandler(). This is not necessary if this object is
|
||||
* part of a 'connection chain', e.g. with ConnectionSOCKS5Proxy.
|
||||
*/
|
||||
ConnectionHTTPProxy( ConnectionBase* connection, const LogSink& logInstance,
|
||||
const std::string& server, int port = -1 );
|
||||
|
||||
/**
|
||||
* Constructs a new ConnectionHTTPProxy object.
|
||||
* @param cdh An ConnectionDataHandler-derived object that will handle incoming data.
|
||||
* @param connection A transport connection. It should be configured to connect to
|
||||
* the proxy host and port, @b not to the XMPP host. ConnectionHTTPProxy will own the
|
||||
* transport connection and delete it in its destructor.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param server A server to connect to. This is the XMPP server's address, @b not the proxy.
|
||||
* @param port The port to connect to. This is the XMPP server's port, @b not the proxy's.
|
||||
* The default of -1 means that SRV records will be used to find out about the actual host:port.
|
||||
*/
|
||||
ConnectionHTTPProxy( ConnectionDataHandler* cdh, ConnectionBase* connection,
|
||||
const LogSink& logInstance,
|
||||
const std::string& server, int port = -1 );
|
||||
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~ConnectionHTTPProxy();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError connect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError recv( int timeout = -1 );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual bool send( const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError receive();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void disconnect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void cleanup();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void getStatistics( long int &totalIn, long int &totalOut );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleReceivedData( const ConnectionBase* connection, const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleConnect( const ConnectionBase* connection );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleDisconnect( const ConnectionBase* connection, ConnectionError reason );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual ConnectionBase* newInstance() const;
|
||||
|
||||
/**
|
||||
* Sets the XMPP server to proxy to.
|
||||
* @param host The XMPP server hostname (IP address).
|
||||
* @param port The XMPP server port. The default of -1 means that SRV records will be used
|
||||
* to find out about the actual host:port.
|
||||
*/
|
||||
void setServer( const std::string& host, int port = -1 )
|
||||
{ m_server = host; m_port = port; }
|
||||
|
||||
/**
|
||||
* Sets proxy authorization credentials.
|
||||
* @param user The user name to use for proxy authorization.
|
||||
* @param password The password to use for proxy authorization.
|
||||
*/
|
||||
void setProxyAuth( const std::string& user, const std::string& password )
|
||||
{ m_proxyUser = user; m_proxyPwd = password; }
|
||||
|
||||
/**
|
||||
* Sets the underlying transport connection. A possibly existing connection will be deleted.
|
||||
* @param connection The ConnectionBase to replace the current connection, if any.
|
||||
*/
|
||||
void setConnectionImpl( ConnectionBase* connection );
|
||||
|
||||
/**
|
||||
* Switches usage of HTTP/1.1 on or off.
|
||||
* @param http11 Set this to @b true to connect through a HTTP/1.1-only proxy, or @b false
|
||||
* to use HTTP/1.0. Defaults to HTTP/1.0 which should work with 99.9% of proxies.
|
||||
*/
|
||||
void setHTTP11( bool http11 ) { m_http11 = http11; }
|
||||
|
||||
private:
|
||||
ConnectionHTTPProxy &operator=( const ConnectionHTTPProxy& );
|
||||
|
||||
ConnectionBase* m_connection;
|
||||
const LogSink& m_logInstance;
|
||||
|
||||
std::string m_proxyUser;
|
||||
std::string m_proxyPwd;
|
||||
std::string m_proxyHandshakeBuffer;
|
||||
|
||||
bool m_http11;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONHTTPPROXY_H__
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 CONNECTIONLISTENER_H__
|
||||
#define CONNECTIONLISTENER_H__
|
||||
|
||||
#include "gloox.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Error;
|
||||
|
||||
/**
|
||||
* @brief Derived classes can be registered as ConnectionListeners with the Client.
|
||||
*
|
||||
* This interface is mandatory to implement if a connection is to be made TLS-encrypted.
|
||||
* In onTLSConnect(), the server's certificate information needs to be checked, and @b true
|
||||
* returned if the certificate is to be accepted.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
*/
|
||||
class GLOOX_API ConnectionListener
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~ConnectionListener() {}
|
||||
|
||||
/**
|
||||
* This function notifies about successful connections. It will be called either after all
|
||||
* authentication is finished if username/password were supplied, or after a connection has
|
||||
* been established if no credentials were supplied. Depending on the setting of AutoPresence,
|
||||
* a presence stanza is sent or not.
|
||||
*/
|
||||
virtual void onConnect() = 0;
|
||||
|
||||
/**
|
||||
* This function notifies about disconnection and its reason.
|
||||
* If @b e indicates a stream error, you can use @ref ClientBase::streamError() to find out
|
||||
* what exactly went wrong, and @ref ClientBase::streamErrorText() to retrieve any explaining text
|
||||
* sent along with the error.
|
||||
* If @b e indicates an authentication error, you can use @ref ClientBase::authError()
|
||||
* to get a finer grained reason.
|
||||
* @param e The reason for the disconnection.
|
||||
*/
|
||||
virtual void onDisconnect( ConnectionError e ) = 0;
|
||||
|
||||
/**
|
||||
* This function will be called when a resource has been bound to the stream. It
|
||||
* will be called for any bound resource, including the main one.
|
||||
* @note The bound resource may be different from the one requested. The server
|
||||
* has the authority to change/overwrite the requested resource.
|
||||
* @param resource The resource string.
|
||||
* @since 1.0
|
||||
*/
|
||||
virtual void onResourceBind( const std::string& resource ) { (void)resource; }
|
||||
|
||||
/**
|
||||
* This function is called (by a Client object) if an error occurs while trying to bind a resource.
|
||||
* @param error A pointer to an Error object that contains more
|
||||
* information. May be 0.
|
||||
*/
|
||||
virtual void onResourceBindError( const Error* error ) { (void) (error); }
|
||||
|
||||
/**
|
||||
* This function is called (by a Client object) if an error occurs while trying to establish
|
||||
* a session.
|
||||
* @param error A pointer to an Error object that contains more
|
||||
* information. May be 0.
|
||||
*/
|
||||
virtual void onSessionCreateError( const Error* error ) { (void) (error); }
|
||||
|
||||
/**
|
||||
* This function is called when the connection was TLS/SSL secured.
|
||||
* @param info Comprehensive info on the certificate.
|
||||
* @return @b True if cert credentials are accepted, @b false otherwise. If @b false is returned
|
||||
* the connection is terminated.
|
||||
*/
|
||||
virtual bool onTLSConnect( const CertInfo& info ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called for certain stream events. Notifications are purely informational
|
||||
* and implementation is optional. Not all StreamEvents will necessarily be emitted for
|
||||
* a given connection.
|
||||
* @param event A stream event.
|
||||
* @since 0.9
|
||||
*/
|
||||
virtual void onStreamEvent( StreamEvent event ) { (void) (event); }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONLISTENER_H__
|
|
@ -1,377 +0,0 @@
|
|||
/*
|
||||
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 "config.h"
|
||||
|
||||
#include "gloox.h"
|
||||
|
||||
#include "connectionsocks5proxy.h"
|
||||
#include "dns.h"
|
||||
#include "logsink.h"
|
||||
#include "prep.h"
|
||||
#include "base64.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
# include <winsock.h>
|
||||
#elif defined( _WIN32_WCE )
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ConnectionSOCKS5Proxy::ConnectionSOCKS5Proxy( ConnectionBase* connection,
|
||||
const LogSink& logInstance,
|
||||
const std::string& server,
|
||||
int port, bool ip )
|
||||
: ConnectionBase( 0 ), m_connection( connection ),
|
||||
m_logInstance( logInstance ), m_s5state( S5StateDisconnected ), m_ip( ip )
|
||||
{
|
||||
// FIXME check return value?
|
||||
prep::idna( server, m_server );
|
||||
m_port = port;
|
||||
|
||||
if( m_connection )
|
||||
m_connection->registerConnectionDataHandler( this );
|
||||
}
|
||||
|
||||
ConnectionSOCKS5Proxy::ConnectionSOCKS5Proxy( ConnectionDataHandler* cdh,
|
||||
ConnectionBase* connection,
|
||||
const LogSink& logInstance,
|
||||
const std::string& server,
|
||||
int port, bool ip )
|
||||
: ConnectionBase( cdh ), m_connection( connection ),
|
||||
m_logInstance( logInstance ), m_s5state( S5StateDisconnected ), m_ip( ip )
|
||||
{
|
||||
// FIXME check return value?
|
||||
prep::idna( server, m_server );
|
||||
m_port = port;
|
||||
|
||||
if( m_connection )
|
||||
m_connection->registerConnectionDataHandler( this );
|
||||
}
|
||||
|
||||
ConnectionSOCKS5Proxy::~ConnectionSOCKS5Proxy()
|
||||
{
|
||||
if( m_connection )
|
||||
delete m_connection;
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionSOCKS5Proxy::newInstance() const
|
||||
{
|
||||
ConnectionBase* conn = m_connection ? m_connection->newInstance() : 0;
|
||||
return new ConnectionSOCKS5Proxy( m_handler, conn, m_logInstance, m_server, m_port, m_ip );
|
||||
}
|
||||
|
||||
void ConnectionSOCKS5Proxy::setConnectionImpl( ConnectionBase* connection )
|
||||
{
|
||||
if( m_connection )
|
||||
delete m_connection;
|
||||
|
||||
m_connection = connection;
|
||||
}
|
||||
|
||||
ConnectionError ConnectionSOCKS5Proxy::connect()
|
||||
{
|
||||
// FIXME CHECKME
|
||||
if( m_connection && m_connection->state() == StateConnected && m_handler )
|
||||
{
|
||||
m_state = StateConnected;
|
||||
m_s5state = S5StateConnected;
|
||||
return ConnNoError;
|
||||
}
|
||||
|
||||
if( m_connection && m_handler )
|
||||
{
|
||||
m_state = StateConnecting;
|
||||
m_s5state = S5StateConnecting;
|
||||
return m_connection->connect();
|
||||
}
|
||||
|
||||
return ConnNotConnected;
|
||||
}
|
||||
|
||||
void ConnectionSOCKS5Proxy::disconnect()
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->disconnect();
|
||||
cleanup();
|
||||
}
|
||||
|
||||
ConnectionError ConnectionSOCKS5Proxy::recv( int timeout )
|
||||
{
|
||||
if( m_connection )
|
||||
return m_connection->recv( timeout );
|
||||
else
|
||||
return ConnNotConnected;
|
||||
}
|
||||
|
||||
ConnectionError ConnectionSOCKS5Proxy::receive()
|
||||
{
|
||||
if( m_connection )
|
||||
return m_connection->receive();
|
||||
else
|
||||
return ConnNotConnected;
|
||||
}
|
||||
|
||||
bool ConnectionSOCKS5Proxy::send( const std::string& data )
|
||||
{
|
||||
// if( m_s5state != S5StateConnected )
|
||||
// {
|
||||
// printf( "p data sent: " );
|
||||
// const char* x = data.c_str();
|
||||
// for( unsigned int i = 0; i < data.length(); ++i )
|
||||
// printf( "%02X ", (const char)x[i] );
|
||||
// printf( "\n" );
|
||||
// }
|
||||
|
||||
if( m_connection )
|
||||
return m_connection->send( data );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConnectionSOCKS5Proxy::cleanup()
|
||||
{
|
||||
m_state = StateDisconnected;
|
||||
m_s5state = S5StateDisconnected;
|
||||
|
||||
if( m_connection )
|
||||
m_connection->cleanup();
|
||||
}
|
||||
|
||||
void ConnectionSOCKS5Proxy::getStatistics( long int &totalIn, long int &totalOut )
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->getStatistics( totalIn, totalOut );
|
||||
else
|
||||
{
|
||||
totalIn = 0;
|
||||
totalOut = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionSOCKS5Proxy::handleReceivedData( const ConnectionBase* /*connection*/,
|
||||
const std::string& data )
|
||||
{
|
||||
// if( m_s5state != S5StateConnected )
|
||||
// {
|
||||
// printf( "data recv: " );
|
||||
// const char* x = data.c_str();
|
||||
// for( unsigned int i = 0; i < data.length(); ++i )
|
||||
// printf( "%02X ", (const char)x[i] );
|
||||
// printf( "\n" );
|
||||
// }
|
||||
|
||||
if( !m_connection || !m_handler )
|
||||
return;
|
||||
|
||||
ConnectionError connError = ConnNoError;
|
||||
|
||||
switch( m_s5state )
|
||||
{
|
||||
case S5StateConnecting:
|
||||
if( data.length() != 2 || data[0] != 0x05 )
|
||||
connError = ConnIoError;
|
||||
|
||||
if( data[1] == 0x00 ) // no auth
|
||||
{
|
||||
negotiate();
|
||||
}
|
||||
else if( data[1] == 0x02 && !m_proxyUser.empty() && !m_proxyPwd.empty() ) // user/password auth
|
||||
{
|
||||
m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy,
|
||||
"authenticating to socks5 proxy as user " + m_proxyUser );
|
||||
m_s5state = S5StateAuthenticating;
|
||||
char* d = new char[3 + m_proxyUser.length() + m_proxyPwd.length()];
|
||||
size_t pos = 0;
|
||||
d[pos++] = 0x01;
|
||||
d[pos++] = (char)m_proxyUser.length();
|
||||
strncpy( d + pos, m_proxyUser.c_str(), m_proxyUser.length() );
|
||||
pos += m_proxyUser.length();
|
||||
d[pos++] = (char)m_proxyPwd.length();
|
||||
strncpy( d + pos, m_proxyPwd.c_str(), m_proxyPwd.length() );
|
||||
pos += m_proxyPwd.length();
|
||||
|
||||
if( !send( std::string( d, pos ) ) )
|
||||
{
|
||||
cleanup();
|
||||
m_handler->handleDisconnect( this, ConnIoError );
|
||||
}
|
||||
delete[] d;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( data[1] == (char)(unsigned char)0xFF && !m_proxyUser.empty() && !m_proxyPwd.empty() )
|
||||
connError = ConnProxyNoSupportedAuth;
|
||||
else
|
||||
connError = ConnProxyAuthRequired;
|
||||
}
|
||||
break;
|
||||
case S5StateNegotiating:
|
||||
if( data.length() >= 6 && data[0] == 0x05 )
|
||||
{
|
||||
if( data[1] == 0x00 )
|
||||
{
|
||||
m_state = StateConnected;
|
||||
m_s5state = S5StateConnected;
|
||||
m_handler->handleConnect( this );
|
||||
}
|
||||
else // connection refused
|
||||
connError = ConnConnectionRefused;
|
||||
}
|
||||
else
|
||||
connError = ConnIoError;
|
||||
break;
|
||||
case S5StateAuthenticating:
|
||||
if( data.length() == 2 && data[0] == 0x01 && data[1] == 0x00 )
|
||||
negotiate();
|
||||
else
|
||||
connError = ConnProxyAuthFailed;
|
||||
break;
|
||||
case S5StateConnected:
|
||||
m_handler->handleReceivedData( this, data );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if( connError != ConnNoError )
|
||||
{
|
||||
m_connection->disconnect();
|
||||
m_handler->handleDisconnect( this, connError );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ConnectionSOCKS5Proxy::negotiate()
|
||||
{
|
||||
m_s5state = S5StateNegotiating;
|
||||
char* d = new char[m_ip ? 10 : 6 + m_server.length() + 1];
|
||||
size_t pos = 0;
|
||||
d[pos++] = 0x05; // SOCKS version 5
|
||||
d[pos++] = 0x01; // command CONNECT
|
||||
d[pos++] = 0x00; // reserved
|
||||
int port = m_port;
|
||||
std::string server = m_server;
|
||||
if( m_ip ) // IP address
|
||||
{
|
||||
d[pos++] = 0x01; // IPv4 address
|
||||
std::string s;
|
||||
const size_t j = server.length();
|
||||
size_t l = 0;
|
||||
for( size_t k = 0; k < j && l < 4; ++k )
|
||||
{
|
||||
if( server[k] != '.' )
|
||||
s += server[k];
|
||||
|
||||
if( server[k] == '.' || k == j-1 )
|
||||
{
|
||||
d[pos++] = static_cast<char>( atoi( s.c_str() ) & 0xFF );
|
||||
s = EmptyString;
|
||||
++l;
|
||||
}
|
||||
}
|
||||
}
|
||||
else // hostname
|
||||
{
|
||||
if( port == -1 )
|
||||
{
|
||||
const DNS::HostMap& servers = DNS::resolve( m_server, m_logInstance );
|
||||
if( servers.size() )
|
||||
{
|
||||
const std::pair< std::string, int >& host = *servers.begin();
|
||||
server = host.first;
|
||||
port = host.second;
|
||||
}
|
||||
}
|
||||
d[pos++] = 0x03; // hostname
|
||||
d[pos++] = (char)m_server.length();
|
||||
strncpy( d + pos, m_server.c_str(), m_server.length() );
|
||||
pos += m_server.length();
|
||||
}
|
||||
int nport = htons( port );
|
||||
d[pos++] = static_cast<char>( nport );
|
||||
d[pos++] = static_cast<char>( nport >> 8 );
|
||||
|
||||
std::string message = "Requesting socks5 proxy connection to " + server + ":"
|
||||
+ util::int2string( port );
|
||||
m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy, message );
|
||||
|
||||
if( !send( std::string( d, pos ) ) )
|
||||
{
|
||||
cleanup();
|
||||
m_handler->handleDisconnect( this, ConnIoError );
|
||||
}
|
||||
delete[] d;
|
||||
}
|
||||
|
||||
void ConnectionSOCKS5Proxy::handleConnect( const ConnectionBase* /*connection*/ )
|
||||
{
|
||||
if( m_connection )
|
||||
{
|
||||
std::string server = m_server;
|
||||
int port = m_port;
|
||||
if( port == -1 )
|
||||
{
|
||||
const DNS::HostMap& servers = DNS::resolve( m_server, m_logInstance );
|
||||
if( !servers.empty() )
|
||||
{
|
||||
const std::pair< std::string, int >& host = *servers.begin();
|
||||
server = host.first;
|
||||
port = host.second;
|
||||
}
|
||||
}
|
||||
m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy,
|
||||
"Attempting to negotiate socks5 proxy connection" );
|
||||
|
||||
const bool auth = !m_proxyUser.empty() && !m_proxyPwd.empty();
|
||||
const char d[4] = {
|
||||
0x05, // SOCKS version 5
|
||||
static_cast<char>( auth ? 0x02 // two methods
|
||||
: 0x01 ), // one method
|
||||
0x00, // method: no auth
|
||||
0x02 // method: username/password auth
|
||||
};
|
||||
|
||||
if( !send( std::string( d, auth ? 4 : 3 ) ) )
|
||||
{
|
||||
cleanup();
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, ConnIoError );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionSOCKS5Proxy::handleDisconnect( const ConnectionBase* /*connection*/,
|
||||
ConnectionError reason )
|
||||
{
|
||||
cleanup();
|
||||
m_logInstance.dbg( LogAreaClassConnectionSOCKS5Proxy, "socks5 proxy connection closed" );
|
||||
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, reason );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
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 CONNECTIONSOCKS5PROXY_H__
|
||||
#define CONNECTIONSOCKS5PROXY_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "connectionbase.h"
|
||||
#include "logsink.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a simple SOCKS5 Proxying connection (RFC 1928 + RFC 1929).
|
||||
*
|
||||
* To use with a SOCKS5 proxy:
|
||||
*
|
||||
* @code
|
||||
* Client* c = new Client( ... );
|
||||
* c->setConnectionImpl( new ConnectionSOCKS5Proxy( c,
|
||||
* new ConnectionTCPClient( c->logInstance(), proxyHost, proxyPort ),
|
||||
* c->logInstance(), xmppHost, xmppPort ) );
|
||||
* @endcode
|
||||
*
|
||||
* Make sure to pass the proxy host/port to the transport connection (ConnectionTCPClient in this case),
|
||||
* and the XMPP host/port to the proxy connection.
|
||||
*
|
||||
* The reason why ConnectionSOCKS5Proxy doesn't manage its own ConnectionTCPClient is that it allows it
|
||||
* to be used with other transports (like IPv6 or chained HTTP/SOCKS5 proxies).
|
||||
*
|
||||
* @note This class is also used by the SOCKS5 bytestreams implementation (with slightly different
|
||||
* semantics).
|
||||
*
|
||||
* @note Simple @b plain-text username/password authentication is supported. GSSAPI authentication
|
||||
* is not supported.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API ConnectionSOCKS5Proxy : public ConnectionBase, public ConnectionDataHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new ConnectionSOCKS5Proxy object.
|
||||
* @param connection A transport connection. It should be configured to connect to
|
||||
* the proxy host and port, @b not to the (XMPP) host. ConnectionSOCKS5Proxy will own the
|
||||
* transport connection and delete it in its destructor.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param server A server to connect to. This is the XMPP server's address, @b not the proxy.
|
||||
* @param port The proxy's port to connect to. This is the (XMPP) server's port, @b not the proxy's.
|
||||
* The default of -1 means that SRV records will be used to find out about the actual host:port.
|
||||
* @param ip Indicates whether @c server is an IP address (true) or a host name (false).
|
||||
* @note To properly use this object, you have to set a ConnectionDataHandler using
|
||||
* registerConnectionDataHandler(). This is not necessary if this object is
|
||||
* part of a 'connection chain', e.g. with ConnectionHTTPProxy.
|
||||
*/
|
||||
ConnectionSOCKS5Proxy( ConnectionBase* connection, const LogSink& logInstance,
|
||||
const std::string& server, int port = -1, bool ip = false );
|
||||
|
||||
/**
|
||||
* Constructs a new ConnectionSOCKS5Proxy object.
|
||||
* @param cdh A ConnectionDataHandler-derived object that will handle incoming data.
|
||||
* @param connection A transport connection. It should be configured to connect to
|
||||
* the proxy host and port, @b not to the (XMPP) host. ConnectionSOCKS5Proxy will own the
|
||||
* transport connection and delete it in its destructor.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param server A server to connect to. This is the XMPP server's address, @b not the proxy.
|
||||
* @param port The proxy's port to connect to. This is the (XMPP) server's port, @b not the proxy's.
|
||||
* The default of -1 means that SRV records will be used to find out about the actual host:port.
|
||||
* @param ip Indicates whether @c server is an IP address (true) or a host name (false).
|
||||
*/
|
||||
ConnectionSOCKS5Proxy( ConnectionDataHandler* cdh, ConnectionBase* connection,
|
||||
const LogSink& logInstance,
|
||||
const std::string& server, int port = -1, bool ip = false );
|
||||
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~ConnectionSOCKS5Proxy();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError connect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError recv( int timeout = -1 );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual bool send( const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError receive();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void disconnect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void cleanup();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void getStatistics( long int &totalIn, long int &totalOut );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleReceivedData( const ConnectionBase* connection, const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleConnect( const ConnectionBase* connection );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleDisconnect( const ConnectionBase* connection, ConnectionError reason );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual ConnectionBase* newInstance() const;
|
||||
|
||||
/**
|
||||
* Sets the server to proxy to.
|
||||
* @param host The server hostname (IP address).
|
||||
* @param port The server port. The default of -1 means that SRV records will be used
|
||||
* to find out about the actual host:port.
|
||||
* @param ip Indicates whether @c host is an IP address (true) or a host name (false).
|
||||
*/
|
||||
void setServer( const std::string& host, int port = -1, bool ip = false )
|
||||
{ m_server = host; m_port = port; m_ip = ip; }
|
||||
|
||||
/**
|
||||
* Sets proxy authorization credentials.
|
||||
* @param user The user name to use for proxy authorization.
|
||||
* @param password The password to use for proxy authorization.
|
||||
*/
|
||||
void setProxyAuth( const std::string& user, const std::string& password )
|
||||
{ m_proxyUser = user; m_proxyPwd = password; }
|
||||
|
||||
/**
|
||||
* Sets the underlying transport connection. A possibly existing connection will be deleted.
|
||||
* @param connection The ConnectionBase to replace the current connection, if any.
|
||||
*/
|
||||
void setConnectionImpl( ConnectionBase* connection );
|
||||
|
||||
private:
|
||||
enum Socks5State
|
||||
{
|
||||
S5StateDisconnected,
|
||||
S5StateConnecting,
|
||||
S5StateNegotiating,
|
||||
S5StateAuthenticating,
|
||||
S5StateConnected
|
||||
};
|
||||
|
||||
ConnectionSOCKS5Proxy &operator=( const ConnectionSOCKS5Proxy& );
|
||||
void negotiate();
|
||||
|
||||
ConnectionBase* m_connection;
|
||||
const LogSink& m_logInstance;
|
||||
|
||||
Socks5State m_s5state;
|
||||
|
||||
std::string m_proxyUser;
|
||||
std::string m_proxyPwd;
|
||||
std::string m_proxyHandshakeBuffer;
|
||||
bool m_ip;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONSOCKS5PROXY_H__
|
|
@ -1,214 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 "gloox.h"
|
||||
|
||||
#include "connectiontcpbase.h"
|
||||
#include "dns.h"
|
||||
#include "logsink.h"
|
||||
#include "prep.h"
|
||||
#include "mutexguard.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __MINGW32__
|
||||
# include <winsock.h>
|
||||
#endif
|
||||
|
||||
#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
|
||||
# include <arpa/inet.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/select.h>
|
||||
# include <netinet/in.h>
|
||||
# include <unistd.h>
|
||||
# include <string.h>
|
||||
# include <errno.h>
|
||||
#elif ( defined( _WIN32 ) || defined( _WIN32_WCE ) ) && !defined( __SYMBIAN32__ )
|
||||
# include <winsock.h>
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ConnectionTCPBase::ConnectionTCPBase( const LogSink& logInstance,
|
||||
const std::string& server, int port )
|
||||
: ConnectionBase( 0 ),
|
||||
m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ),
|
||||
m_totalBytesOut( 0 ), m_bufsize( 8192 ), m_cancel( true )
|
||||
{
|
||||
init( server, port );
|
||||
}
|
||||
|
||||
ConnectionTCPBase::ConnectionTCPBase( ConnectionDataHandler* cdh, const LogSink& logInstance,
|
||||
const std::string& server, int port )
|
||||
: ConnectionBase( cdh ),
|
||||
m_logInstance( logInstance ), m_buf( 0 ), m_socket( -1 ), m_totalBytesIn( 0 ),
|
||||
m_totalBytesOut( 0 ), m_bufsize( 8192 ), m_cancel( true )
|
||||
{
|
||||
init( server, port );
|
||||
}
|
||||
|
||||
void ConnectionTCPBase::init( const std::string& server, int port )
|
||||
{
|
||||
// FIXME check return value?
|
||||
prep::idna( server, m_server );
|
||||
m_port = port;
|
||||
m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
|
||||
}
|
||||
|
||||
ConnectionTCPBase::~ConnectionTCPBase()
|
||||
{
|
||||
cleanup();
|
||||
free( m_buf );
|
||||
m_buf = 0;
|
||||
}
|
||||
|
||||
void ConnectionTCPBase::disconnect()
|
||||
{
|
||||
util::MutexGuard rm( m_recvMutex );
|
||||
m_cancel = true;
|
||||
}
|
||||
|
||||
bool ConnectionTCPBase::dataAvailable( int timeout )
|
||||
{
|
||||
if( m_socket < 0 )
|
||||
return true; // let recv() catch the closed fd
|
||||
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
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( m_socket, &fds );
|
||||
|
||||
tv.tv_sec = timeout / 1000000;
|
||||
tv.tv_usec = timeout % 1000000;
|
||||
|
||||
return ( ( select( m_socket + 1, &fds, 0, 0, timeout == -1 ? 0 : &tv ) > 0 )
|
||||
&& FD_ISSET( m_socket, &fds ) != 0 );
|
||||
}
|
||||
|
||||
ConnectionError ConnectionTCPBase::receive()
|
||||
{
|
||||
if( m_socket < 0 )
|
||||
return ConnNotConnected;
|
||||
|
||||
ConnectionError err = ConnNoError;
|
||||
while( !m_cancel && ( err = recv( 1000000 ) ) == ConnNoError )
|
||||
;
|
||||
return err == ConnNoError ? ConnNotConnected : err;
|
||||
}
|
||||
|
||||
bool ConnectionTCPBase::send( const std::string& data )
|
||||
{
|
||||
m_sendMutex.lock();
|
||||
|
||||
if( data.empty() || ( m_socket < 0 ) )
|
||||
{
|
||||
m_sendMutex.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
int sent = 0;
|
||||
for( size_t num = 0, len = data.length(); sent != -1 && num < len; num += sent )
|
||||
{
|
||||
sent = static_cast<int>( ::send( m_socket, (data.c_str()+num), (int)(len - num), 0 ) );
|
||||
}
|
||||
|
||||
m_totalBytesOut += (int)data.length();
|
||||
|
||||
m_sendMutex.unlock();
|
||||
|
||||
if( sent == -1 )
|
||||
{
|
||||
// send() failed for an unexpected reason
|
||||
std::string message = "send() failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
|
||||
#else
|
||||
"errno: " + util::int2string( errno ) + ": " + strerror( errno );
|
||||
#endif
|
||||
m_logInstance.err( LogAreaClassConnectionTCPBase, message );
|
||||
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, ConnIoError );
|
||||
}
|
||||
|
||||
return sent != -1;
|
||||
}
|
||||
|
||||
void ConnectionTCPBase::getStatistics( long int &totalIn, long int &totalOut )
|
||||
{
|
||||
totalIn = m_totalBytesIn;
|
||||
totalOut = m_totalBytesOut;
|
||||
}
|
||||
|
||||
void ConnectionTCPBase::cleanup()
|
||||
{
|
||||
if( !m_sendMutex.trylock() )
|
||||
return;
|
||||
|
||||
if( !m_recvMutex.trylock() )
|
||||
{
|
||||
m_sendMutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_socket >= 0 )
|
||||
{
|
||||
DNS::closeSocket( m_socket, m_logInstance );
|
||||
m_socket = -1;
|
||||
}
|
||||
|
||||
m_state = StateDisconnected;
|
||||
m_cancel = true;
|
||||
m_totalBytesIn = 0;
|
||||
m_totalBytesOut = 0;
|
||||
|
||||
m_recvMutex.unlock(),
|
||||
m_sendMutex.unlock();
|
||||
}
|
||||
|
||||
int ConnectionTCPBase::localPort() const
|
||||
{
|
||||
struct sockaddr local;
|
||||
socklen_t len = (socklen_t)sizeof( local );
|
||||
if( getsockname ( m_socket, &local, &len ) < 0 )
|
||||
return -1;
|
||||
else
|
||||
return ntohs( ((struct sockaddr_in *)&local)->sin_port );
|
||||
}
|
||||
|
||||
const std::string ConnectionTCPBase::localInterface() const
|
||||
{
|
||||
struct sockaddr_in local;
|
||||
socklen_t len = (socklen_t)sizeof( local );
|
||||
if( getsockname ( m_socket, (reinterpret_cast<struct sockaddr*>( &local )), &len ) < 0 )
|
||||
return EmptyString;
|
||||
else
|
||||
{
|
||||
// char addr[INET_ADDRSTRLEN];
|
||||
// return inet_ntop( AF_INET, &(local.sin_addr), addr, sizeof( addr ) ); //FIXME is this portable?
|
||||
return inet_ntoa( local.sin_addr );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 CONNECTIONTCPBASE_H__
|
||||
#define CONNECTIONTCPBASE_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "connectionbase.h"
|
||||
#include "logsink.h"
|
||||
#include "mutex.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
namespace util
|
||||
{
|
||||
class Mutex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This is a base class for a simple TCP connection.
|
||||
*
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API ConnectionTCPBase : public ConnectionBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new ConnectionTCPBase object.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param server A server to connect to.
|
||||
* @param port The port to connect to. The default of -1 means that XMPP SRV records
|
||||
* will be used to find out about the actual host:port.
|
||||
* @note To properly use this object, you have to set a ConnectionDataHandler using
|
||||
* registerConnectionDataHandler(). This is not necessary if this object is
|
||||
* part of a 'connection chain', e.g. with ConnectionHTTPProxy.
|
||||
*/
|
||||
ConnectionTCPBase( const LogSink& logInstance, const std::string& server, int port = -1 );
|
||||
|
||||
/**
|
||||
* Constructs a new ConnectionTCPBase object.
|
||||
* @param cdh An ConnectionDataHandler-derived object that will handle incoming data.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param server A server to connect to.
|
||||
* @param port The port to connect to. The default of -1 means that SRV records will be used
|
||||
* to find out about the actual host:port.
|
||||
*/
|
||||
ConnectionTCPBase( ConnectionDataHandler* cdh, const LogSink& logInstance,
|
||||
const std::string& server, int port = -1 );
|
||||
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~ConnectionTCPBase();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual bool send( const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError receive();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void disconnect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void cleanup();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void getStatistics( long int &totalIn, long int &totalOut );
|
||||
|
||||
/**
|
||||
* Gives access to the raw socket of this connection. Use it wisely. You can
|
||||
* select()/poll() it and use ConnectionTCPBase::recv( -1 ) to fetch the data.
|
||||
* @return The socket of the active connection, or -1 if no connection is established.
|
||||
*/
|
||||
int socket() const { return m_socket; }
|
||||
|
||||
/**
|
||||
* This function allows to set an existing socket with an established
|
||||
* connection to use in this connection. You will still need to call connect() in order to
|
||||
* negotiate the XMPP stream. You should not set a new socket after having called connect().
|
||||
* @param socket The existing socket.
|
||||
*/
|
||||
void setSocket( int socket ) { m_cancel = false; m_state = StateConnected; m_socket = socket; }
|
||||
|
||||
/**
|
||||
* Returns the local port.
|
||||
* @return The local port.
|
||||
*/
|
||||
virtual int localPort() const;
|
||||
|
||||
/**
|
||||
* Returns the locally bound IP address.
|
||||
* @return The locally bound IP address.
|
||||
*/
|
||||
virtual const std::string localInterface() const;
|
||||
|
||||
protected:
|
||||
ConnectionTCPBase& operator=( const ConnectionTCPBase& );
|
||||
void init( const std::string& server, int port );
|
||||
bool dataAvailable( int timeout = -1 );
|
||||
void cancel();
|
||||
|
||||
const LogSink& m_logInstance;
|
||||
util::Mutex m_sendMutex;
|
||||
util::Mutex m_recvMutex;
|
||||
|
||||
char* m_buf;
|
||||
int m_socket;
|
||||
long int m_totalBytesIn;
|
||||
long int m_totalBytesOut;
|
||||
const int m_bufsize;
|
||||
bool m_cancel;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONTCPBASE_H__
|
|
@ -1,174 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 "gloox.h"
|
||||
|
||||
#include "connectiontcpclient.h"
|
||||
#include "dns.h"
|
||||
#include "logsink.h"
|
||||
#include "mutexguard.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __MINGW32__
|
||||
# include <winsock.h>
|
||||
#endif
|
||||
|
||||
#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/select.h>
|
||||
# include <unistd.h>
|
||||
# include <string.h>
|
||||
# include <errno.h>
|
||||
#elif ( defined( _WIN32 ) || defined( _WIN32_WCE ) ) && !defined( __SYMBIAN32__ )
|
||||
# include <winsock.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ConnectionTCPClient::ConnectionTCPClient( const LogSink& logInstance,
|
||||
const std::string& server, int port )
|
||||
: ConnectionTCPBase( logInstance, server, port )
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionTCPClient::ConnectionTCPClient( ConnectionDataHandler* cdh, const LogSink& logInstance,
|
||||
const std::string& server, int port )
|
||||
: ConnectionTCPBase( cdh, logInstance, server, port )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ConnectionTCPClient::~ConnectionTCPClient()
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionTCPClient::newInstance() const
|
||||
{
|
||||
return new ConnectionTCPClient( m_handler, m_logInstance, m_server, m_port );
|
||||
}
|
||||
|
||||
ConnectionError ConnectionTCPClient::connect()
|
||||
{
|
||||
m_sendMutex.lock();
|
||||
// FIXME CHECKME
|
||||
if( !m_handler )
|
||||
{
|
||||
m_sendMutex.unlock();
|
||||
return ConnNotConnected;
|
||||
}
|
||||
|
||||
if( m_socket >= 0 && m_state > StateDisconnected )
|
||||
{
|
||||
m_sendMutex.unlock();
|
||||
return ConnNoError;
|
||||
}
|
||||
|
||||
m_state = StateConnecting;
|
||||
|
||||
if( m_socket < 0 )
|
||||
{
|
||||
if( m_port == -1 )
|
||||
m_socket = DNS::connect( m_server, m_logInstance );
|
||||
else
|
||||
m_socket = DNS::connect( m_server, m_port, m_logInstance );
|
||||
}
|
||||
|
||||
m_sendMutex.unlock();
|
||||
|
||||
if( m_socket < 0 )
|
||||
{
|
||||
switch( m_socket )
|
||||
{
|
||||
case -ConnConnectionRefused:
|
||||
m_logInstance.err( LogAreaClassConnectionTCPClient,
|
||||
m_server + ": connection refused" );
|
||||
break;
|
||||
case -ConnDnsError:
|
||||
m_logInstance.err( LogAreaClassConnectionTCPClient,
|
||||
m_server + ": host not found" );
|
||||
break;
|
||||
default:
|
||||
m_logInstance.err( LogAreaClassConnectionTCPClient,
|
||||
"Unknown error condition" );
|
||||
break;
|
||||
}
|
||||
m_handler->handleDisconnect( this, (ConnectionError)-m_socket );
|
||||
return (ConnectionError)-m_socket;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = StateConnected;
|
||||
}
|
||||
|
||||
m_cancel = false;
|
||||
m_handler->handleConnect( this );
|
||||
return ConnNoError;
|
||||
}
|
||||
|
||||
ConnectionError ConnectionTCPClient::recv( int timeout )
|
||||
{
|
||||
m_recvMutex.lock();
|
||||
|
||||
if( m_cancel || m_socket < 0 )
|
||||
{
|
||||
m_recvMutex.unlock();
|
||||
return ConnNotConnected;
|
||||
}
|
||||
|
||||
if( !dataAvailable( timeout ) )
|
||||
{
|
||||
m_recvMutex.unlock();
|
||||
return ConnNoError;
|
||||
}
|
||||
|
||||
int size = static_cast<int>( ::recv( m_socket, m_buf, m_bufsize, 0 ) );
|
||||
if( size > 0 )
|
||||
m_totalBytesIn += size;
|
||||
|
||||
m_recvMutex.unlock();
|
||||
|
||||
if( size <= 0 )
|
||||
{
|
||||
if( size == -1 )
|
||||
{
|
||||
// recv() failed for an unexpected reason
|
||||
std::string message = "recv() failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
|
||||
#else
|
||||
"errno: " + util::int2string( errno ) + ": " + strerror( errno );
|
||||
#endif
|
||||
m_logInstance.err( LogAreaClassConnectionTCPClient, message );
|
||||
}
|
||||
|
||||
ConnectionError error = ( size ? ConnIoError : ConnStreamClosed );
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, error );
|
||||
return error;
|
||||
}
|
||||
|
||||
m_buf[size] = '\0';
|
||||
|
||||
if( m_handler )
|
||||
m_handler->handleReceivedData( this, std::string( m_buf, size ) );
|
||||
|
||||
return ConnNoError;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 CONNECTIONTCPCLIENT_H__
|
||||
#define CONNECTIONTCPCLIENT_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "connectiontcpbase.h"
|
||||
#include "logsink.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a simple TCP connection.
|
||||
*
|
||||
* You should only need to use this class directly if you need access to some special feature, like
|
||||
* the raw socket(), or if you need HTTP proxy support (see @ref gloox::ConnectionHTTPProxy for more
|
||||
* information).
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API ConnectionTCPClient : public ConnectionTCPBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new ConnectionTCPClient object.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param server A server to connect to.
|
||||
* @param port The port to connect to. The default of -1 means that XMPP SRV records
|
||||
* will be used to find out about the actual host:port.
|
||||
* @note To properly use this object, you have to set a ConnectionDataHandler using
|
||||
* registerConnectionDataHandler(). This is not necessary if this object is
|
||||
* part of a 'connection chain', e.g. with ConnectionHTTPProxy.
|
||||
*/
|
||||
ConnectionTCPClient( const LogSink& logInstance, const std::string& server, int port = -1 );
|
||||
|
||||
/**
|
||||
* Constructs a new ConnectionTCPClient object.
|
||||
* @param cdh An ConnectionDataHandler-derived object that will handle incoming data.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param server A server to connect to.
|
||||
* @param port The port to connect to. The default of -1 means that SRV records will be used
|
||||
* to find out about the actual host:port.
|
||||
*/
|
||||
ConnectionTCPClient( ConnectionDataHandler* cdh, const LogSink& logInstance,
|
||||
const std::string& server, int port = -1 );
|
||||
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~ConnectionTCPClient();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError recv( int timeout = -1 );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError connect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionBase* newInstance() const;
|
||||
|
||||
private:
|
||||
ConnectionTCPClient &operator=( const ConnectionTCPClient & );
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONTCPCLIENT_H__
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 "gloox.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "connectiontcpserver.h"
|
||||
#include "connectiontcpclient.h"
|
||||
#include "connectionhandler.h"
|
||||
#include "dns.h"
|
||||
#include "logsink.h"
|
||||
#include "mutex.h"
|
||||
#include "mutexguard.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifdef __MINGW32__
|
||||
# include <winsock.h>
|
||||
#endif
|
||||
|
||||
#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/nameser.h>
|
||||
# include <resolv.h>
|
||||
# include <netdb.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
# include <sys/select.h>
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
# include <winsock.h>
|
||||
#elif defined( _WIN32_WCE )
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ConnectionTCPServer::ConnectionTCPServer( ConnectionHandler* ch, const LogSink& logInstance,
|
||||
const std::string& ip, int port )
|
||||
: ConnectionTCPBase( 0, logInstance, ip, port ),
|
||||
m_connectionHandler( ch )
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionTCPServer::~ConnectionTCPServer()
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionTCPServer::newInstance() const
|
||||
{
|
||||
return new ConnectionTCPServer( m_connectionHandler, m_logInstance, m_server, m_port );
|
||||
}
|
||||
|
||||
ConnectionError ConnectionTCPServer::connect()
|
||||
{
|
||||
util::MutexGuard mg( &m_sendMutex );
|
||||
|
||||
if( m_socket >= 0 || m_state > StateDisconnected )
|
||||
return ConnNoError;
|
||||
|
||||
m_state = StateConnecting;
|
||||
|
||||
if( m_socket < 0 )
|
||||
m_socket = DNS::getSocket( m_logInstance );
|
||||
|
||||
if( m_socket < 0 )
|
||||
return ConnIoError;
|
||||
|
||||
#ifdef HAVE_SETSOCKOPT
|
||||
int buf = 0;
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
int bufbytes = sizeof( int );
|
||||
#else
|
||||
socklen_t bufbytes = sizeof( int );
|
||||
#endif
|
||||
if( ( getsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&buf, &bufbytes ) != -1 ) &&
|
||||
( m_bufsize > buf ) )
|
||||
setsockopt( m_socket, SOL_SOCKET, SO_RCVBUF, (char*)&m_bufsize, sizeof( m_bufsize ) );
|
||||
|
||||
if( ( getsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&buf, &bufbytes ) != -1 ) &&
|
||||
( m_bufsize > buf ) )
|
||||
setsockopt( m_socket, SOL_SOCKET, SO_SNDBUF, (char*)&m_bufsize, sizeof( m_bufsize ) );
|
||||
#endif
|
||||
|
||||
struct sockaddr_in local;
|
||||
local.sin_family = AF_INET;
|
||||
local.sin_port = static_cast<unsigned short int>( htons( m_port ) );
|
||||
local.sin_addr.s_addr = m_server.empty() ? INADDR_ANY : inet_addr( m_server.c_str() );
|
||||
memset( local.sin_zero, '\0', 8 );
|
||||
|
||||
if( bind( m_socket, (struct sockaddr*)&local, sizeof( struct sockaddr ) ) < 0 )
|
||||
{
|
||||
std::string message = "bind() to " + ( m_server.empty() ? std::string( "*" ) : m_server )
|
||||
+ " (" + inet_ntoa( local.sin_addr ) + ":" + util::int2string( m_port ) + ") failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
|
||||
#else
|
||||
"errno: " + util::int2string( errno );
|
||||
#endif
|
||||
m_logInstance.dbg( LogAreaClassConnectionTCPServer, message );
|
||||
|
||||
return ConnIoError;
|
||||
}
|
||||
|
||||
if( listen( m_socket, 10 ) < 0 )
|
||||
{
|
||||
std::string message = "listen on " + ( m_server.empty() ? std::string( "*" ) : m_server )
|
||||
+ " (" + inet_ntoa( local.sin_addr ) + ":" + util::int2string( m_port ) + ") failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
|
||||
#else
|
||||
"errno: " + util::int2string( errno );
|
||||
#endif
|
||||
m_logInstance.dbg( LogAreaClassConnectionTCPServer, message );
|
||||
|
||||
return ConnIoError;
|
||||
}
|
||||
|
||||
m_cancel = false;
|
||||
return ConnNoError;
|
||||
}
|
||||
|
||||
ConnectionError ConnectionTCPServer::recv( int timeout )
|
||||
{
|
||||
m_recvMutex.lock();
|
||||
|
||||
if( m_cancel || m_socket < 0 || !m_connectionHandler )
|
||||
{
|
||||
m_recvMutex.unlock();
|
||||
return ConnNotConnected;
|
||||
}
|
||||
|
||||
if( !dataAvailable( timeout ) )
|
||||
{
|
||||
m_recvMutex.unlock();
|
||||
return ConnNoError;
|
||||
}
|
||||
|
||||
struct sockaddr_in they;
|
||||
int sin_size = sizeof( struct sockaddr_in );
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
int newfd = static_cast<int>( accept( static_cast<SOCKET>( m_socket ), (struct sockaddr*)&they, &sin_size ) );
|
||||
#else
|
||||
int newfd = accept( m_socket, (struct sockaddr*)&they, (socklen_t*)&sin_size );
|
||||
#endif
|
||||
|
||||
m_recvMutex.unlock();
|
||||
|
||||
ConnectionTCPClient* conn = new ConnectionTCPClient( m_logInstance, inet_ntoa( they.sin_addr ),
|
||||
ntohs( they.sin_port ) );
|
||||
conn->setSocket( newfd );
|
||||
m_connectionHandler->handleIncomingConnection( this, conn );
|
||||
|
||||
return ConnNoError;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
/*
|
||||
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 CONNECTIONTCPSERVER_H__
|
||||
#define CONNECTIONTCPSERVER_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "connectiontcpbase.h"
|
||||
#include "logsink.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class ConnectionHandler;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a simple listening TCP connection.
|
||||
*
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API ConnectionTCPServer : public ConnectionTCPBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new ConnectionTCPServer object.
|
||||
* @param ch A ConnectionHandler-derived object that will handle incoming connections.
|
||||
* @param logInstance The log target. Obtain it from ClientBase::logInstance().
|
||||
* @param ip The local IP address to listen on. This must @b not be a hostname.
|
||||
* Leave this empty to listen on all local interfaces.
|
||||
* @param port The port to listen on.
|
||||
*/
|
||||
ConnectionTCPServer( ConnectionHandler* ch, const LogSink& logInstance,
|
||||
const std::string& ip, int port );
|
||||
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~ConnectionTCPServer();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError recv( int timeout = -1 );
|
||||
|
||||
/**
|
||||
* This function actually starts @c listening on the port given in the
|
||||
* constructor.
|
||||
*/
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError connect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionBase* newInstance() const;
|
||||
|
||||
private:
|
||||
ConnectionTCPServer &operator=( const ConnectionTCPServer & );
|
||||
|
||||
ConnectionHandler* m_connectionHandler;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONTCPSERVER_H__
|
|
@ -1,200 +0,0 @@
|
|||
/*
|
||||
* 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 "connectiontls.h"
|
||||
#include "tlsdefault.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ConnectionTLS::ConnectionTLS( ConnectionDataHandler* cdh, ConnectionBase* conn, const LogSink& log )
|
||||
: ConnectionBase( cdh ),
|
||||
m_connection( conn ), m_tls( 0 ), m_tlsHandler( 0 ),
|
||||
m_log( log )
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->registerConnectionDataHandler( this );
|
||||
}
|
||||
|
||||
ConnectionTLS::ConnectionTLS( ConnectionBase* conn, const LogSink& log )
|
||||
: ConnectionBase( 0 ),
|
||||
m_connection( conn ), m_tls( 0 ), m_tlsHandler( 0 ), m_log( log )
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->registerConnectionDataHandler( this );
|
||||
}
|
||||
|
||||
ConnectionTLS::~ConnectionTLS()
|
||||
{
|
||||
delete m_connection;
|
||||
delete m_tls;
|
||||
}
|
||||
|
||||
void ConnectionTLS::setConnectionImpl( ConnectionBase* connection )
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->registerConnectionDataHandler( 0 );
|
||||
|
||||
m_connection = connection;
|
||||
|
||||
if( m_connection )
|
||||
m_connection->registerConnectionDataHandler( this );
|
||||
}
|
||||
|
||||
ConnectionError ConnectionTLS::connect()
|
||||
{
|
||||
if( !m_connection )
|
||||
return ConnNotConnected;
|
||||
|
||||
if( m_state == StateConnected )
|
||||
return ConnNoError;
|
||||
|
||||
if( !m_tls )
|
||||
m_tls = getTLSBase( this, m_connection->server() );
|
||||
|
||||
if( !m_tls )
|
||||
return ConnTlsNotAvailable;
|
||||
|
||||
if( !m_tls->init( m_clientKey, m_clientCerts, m_cacerts ) )
|
||||
return ConnTlsFailed;
|
||||
|
||||
// m_tls->setCACerts( m_cacerts );
|
||||
// m_tls->setClientCert( m_clientKey, m_clientCerts );
|
||||
|
||||
m_state = StateConnecting;
|
||||
|
||||
if( m_connection->state() != StateConnected )
|
||||
return m_connection->connect();
|
||||
|
||||
if( m_tls->handshake() )
|
||||
return ConnNoError;
|
||||
else
|
||||
return ConnTlsFailed;
|
||||
}
|
||||
|
||||
ConnectionError ConnectionTLS::recv( int timeout )
|
||||
{
|
||||
return m_connection ? m_connection->recv( timeout ) : ConnNotConnected;
|
||||
}
|
||||
|
||||
bool ConnectionTLS::send( const std::string& data )
|
||||
{
|
||||
if( m_state != StateConnected )
|
||||
return false;
|
||||
|
||||
m_tls->encrypt( data );
|
||||
return true;
|
||||
}
|
||||
|
||||
ConnectionError ConnectionTLS::receive()
|
||||
{
|
||||
if( m_connection )
|
||||
return m_connection->receive();
|
||||
else
|
||||
return ConnNotConnected;
|
||||
}
|
||||
|
||||
void ConnectionTLS::disconnect()
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->disconnect();
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void ConnectionTLS::cleanup()
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->cleanup();
|
||||
if( m_tls )
|
||||
m_tls->cleanup();
|
||||
|
||||
m_state = StateDisconnected;
|
||||
}
|
||||
|
||||
void ConnectionTLS::getStatistics( long int& totalIn, long int& totalOut )
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->getStatistics( totalIn, totalOut );
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionTLS::newInstance() const
|
||||
{
|
||||
ConnectionBase* newConn = 0;
|
||||
if( m_connection )
|
||||
newConn = m_connection->newInstance();
|
||||
return new ConnectionTLS( m_handler, newConn, m_log );
|
||||
}
|
||||
|
||||
void ConnectionTLS::handleReceivedData( const ConnectionBase* /*connection*/, const std::string& data )
|
||||
{
|
||||
if( m_tls )
|
||||
m_tls->decrypt( data );
|
||||
}
|
||||
|
||||
void ConnectionTLS::handleConnect( const ConnectionBase* /*connection*/ )
|
||||
{
|
||||
if( m_tls )
|
||||
m_tls->handshake();
|
||||
}
|
||||
|
||||
void ConnectionTLS::handleDisconnect( const ConnectionBase* /*connection*/, ConnectionError reason )
|
||||
{
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, reason );
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void ConnectionTLS::handleEncryptedData( const TLSBase* /*tls*/, const std::string& data )
|
||||
{
|
||||
if( m_connection )
|
||||
m_connection->send( data );
|
||||
}
|
||||
|
||||
void ConnectionTLS::handleDecryptedData( const TLSBase* /*tls*/, const std::string& data )
|
||||
{
|
||||
if( m_handler )
|
||||
m_handler->handleReceivedData( this, data );
|
||||
else
|
||||
{
|
||||
m_log.log( LogLevelDebug, LogAreaClassConnectionTLS, "Data received and decrypted but no handler" );
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionTLS::handleHandshakeResult( const TLSBase* tls, bool success, CertInfo& certinfo )
|
||||
{
|
||||
if( success )
|
||||
{
|
||||
m_state = StateConnected;
|
||||
m_log.log( LogLevelDebug, LogAreaClassConnectionTLS, "TLS handshake succeeded" );
|
||||
if( m_tlsHandler )
|
||||
m_tlsHandler->handleHandshakeResult( tls, success, certinfo );
|
||||
if( m_handler )
|
||||
m_handler->handleConnect( this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = StateDisconnected;
|
||||
m_log.log( LogLevelWarning, LogAreaClassConnectionTLS, "TLS handshake failed" );
|
||||
if( m_tlsHandler )
|
||||
m_tlsHandler->handleHandshakeResult( tls, success, certinfo );
|
||||
cleanup();
|
||||
if( m_handler )
|
||||
m_handler->handleDisconnect( this, ConnTlsFailed );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
/*
|
||||
* 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 CONNECTIONTLS_H__
|
||||
#define CONNECTIONTLS_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "logsink.h"
|
||||
#include "connectionbase.h"
|
||||
#include "tlsdefault.h"
|
||||
#include "connectiondatahandler.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of a TLS/SSL connection.
|
||||
*
|
||||
* You should not need to use this function directly. However,
|
||||
* you can use it to connect to the legacy Jabber SSL port,
|
||||
* 5223.
|
||||
*
|
||||
* Usage:
|
||||
* @code
|
||||
* Client *c = new Client( ... );
|
||||
* c->setConnectionImpl( new ConnectionTLS( c,
|
||||
* new ConnectionTCPClient( c->logInstance(), server, 5223 ),
|
||||
* c->logInstance()) );
|
||||
* @endcode
|
||||
*
|
||||
* Due to the need for handshaking data to be sent/received before the connection is fully
|
||||
* established, be sure not to use the connection until ConnectionDataHandler::handleConnect()
|
||||
* of the specified ConnectionDataHandler is called.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @author Matthew Wild <mwild1@gmail.com>
|
||||
* @since 1.0
|
||||
*/
|
||||
|
||||
class GLOOX_API ConnectionTLS : public TLSHandler, public ConnectionBase, public ConnectionDataHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new ConnectionTLS object.
|
||||
* @param cdh The ConnectionDataHandler that will be notified of events from this connection
|
||||
* @param conn A transport connection. It should be configured to connect to
|
||||
* the server and port you wish to make the encrypted connection to.
|
||||
* ConnectionTLS will own the transport connection and delete it in its destructor.
|
||||
* @param log The log target. Obtain it from ClientBase::logInstance().
|
||||
*/
|
||||
ConnectionTLS( ConnectionDataHandler* cdh, ConnectionBase* conn, const LogSink& log );
|
||||
|
||||
/**
|
||||
* Constructs a new ConnectionTLS object.
|
||||
* @param conn A transport connection. It should be configured to connect to
|
||||
* the server and port you wish to make the encrypted connection to.
|
||||
* ConnectionTLS will own the transport connection and delete it in its destructor.
|
||||
* @param log The log target. Obtain it from ClientBase::logInstance().
|
||||
*/
|
||||
ConnectionTLS( ConnectionBase* conn, const LogSink& log );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~ConnectionTLS();
|
||||
|
||||
/**
|
||||
* Use this function to set a number of trusted root CA certificates which shall be
|
||||
* used to verify a servers certificate.
|
||||
* @param cacerts A list of absolute paths to CA root certificate files in PEM format.
|
||||
* @note This function is a wrapper for TLSBase::setCACerts().
|
||||
*/
|
||||
void setCACerts( const StringList& cacerts )
|
||||
{
|
||||
m_cacerts = cacerts;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to retrieve certificate and connection info of a encrypted connection.
|
||||
* @return Certificate information.
|
||||
* @note This funcztion is a wrapper around TLSBase::fetchTLSInfo().
|
||||
*/
|
||||
const CertInfo& fetchTLSInfo() const { return m_certInfo; }
|
||||
|
||||
/**
|
||||
* Use this function to set the user's certificate and private key. The certificate will
|
||||
* be presented to the server upon request and can be used for SASL EXTERNAL authentication.
|
||||
* The user's certificate file should be a bundle of more than one certificate in PEM format.
|
||||
* The first one in the file should be the user's certificate, each cert following that one
|
||||
* should have signed the previous one.
|
||||
* @note These certificates are not necessarily the same as those used to verify the server's
|
||||
* certificate.
|
||||
* @param clientKey The absolute path to the user's private key in PEM format.
|
||||
* @param clientCerts A path to a certificate bundle in PEM format.
|
||||
* @note This function is a wrapper around TLSBase::setClientCert().
|
||||
*/
|
||||
void setClientCert( const std::string& clientKey, const std::string& clientCerts )
|
||||
{
|
||||
m_clientKey = clientKey;
|
||||
m_clientCerts = clientCerts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transport connection.
|
||||
* @param connection The transport connection to use.
|
||||
*/
|
||||
void setConnectionImpl( ConnectionBase* connection );
|
||||
|
||||
/**
|
||||
* Registers an TLSHandler derived object. Only the handleHandshakeResult()
|
||||
* function will be used after a handshake took place.
|
||||
* You can review certificate info there.
|
||||
* @param th The TLSHandler to register.
|
||||
* @note If no handler is set, ConnectionTLS will accept
|
||||
* any certificate and continue with the connection.
|
||||
*/
|
||||
void registerTLSHandler( TLSHandler* th ) { m_tlsHandler = th; }
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError connect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError recv( int timeout = -1 );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual bool send( const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual ConnectionError receive();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void disconnect();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void cleanup();
|
||||
|
||||
// reimplemented from ConnectionBase
|
||||
virtual void getStatistics( long int& totalIn, long int& totalOut );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleReceivedData( const ConnectionBase* connection, const std::string& data );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleConnect( const ConnectionBase* connection );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual void handleDisconnect( const ConnectionBase* connection, ConnectionError reason );
|
||||
|
||||
// reimplemented from ConnectionDataHandler
|
||||
virtual ConnectionBase* newInstance() const;
|
||||
|
||||
// reimplemented from TLSHandler
|
||||
virtual void handleEncryptedData( const TLSBase*, const std::string& data );
|
||||
|
||||
// reimplemented from TLSHandler
|
||||
virtual void handleDecryptedData( const TLSBase*, const std::string& data );
|
||||
|
||||
// reimplemented from TLSHandler
|
||||
virtual void handleHandshakeResult( const TLSBase* base, bool success, CertInfo& certinfo );
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Returns a TLS object (client). Reimplement to change the
|
||||
* type of the object.
|
||||
* @return A TLS object.
|
||||
*/
|
||||
virtual TLSBase* getTLSBase( TLSHandler* th, const std::string server )
|
||||
{
|
||||
return new TLSDefault( th, server, TLSDefault::VerifyingClient );
|
||||
}
|
||||
|
||||
ConnectionBase* m_connection;
|
||||
TLSBase* m_tls;
|
||||
TLSHandler* m_tlsHandler;
|
||||
CertInfo m_certInfo;
|
||||
const LogSink& m_log;
|
||||
StringList m_cacerts;
|
||||
std::string m_clientCerts;
|
||||
std::string m_clientKey;
|
||||
|
||||
private:
|
||||
ConnectionTLS& operator=( const ConnectionTLS& );
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONTLS_H__
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2009-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 "connectiontlsserver.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
ConnectionTLSServer::ConnectionTLSServer( ConnectionDataHandler* cdh, ConnectionBase* conn,
|
||||
const LogSink& log )
|
||||
: ConnectionTLS( cdh, conn, log )
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionTLSServer::ConnectionTLSServer( ConnectionBase* conn, const LogSink& log )
|
||||
: ConnectionTLS( conn, log )
|
||||
{
|
||||
}
|
||||
|
||||
ConnectionTLSServer::~ConnectionTLSServer()
|
||||
{
|
||||
}
|
||||
|
||||
TLSBase* ConnectionTLSServer::getTLSBase( TLSHandler* th, const std::string server )
|
||||
{
|
||||
return new TLSDefault( th, server, TLSDefault::VerifyingServer );
|
||||
}
|
||||
|
||||
ConnectionBase* ConnectionTLSServer::newInstance() const
|
||||
{
|
||||
ConnectionBase* newConn = 0;
|
||||
if( m_connection )
|
||||
newConn = m_connection->newInstance();
|
||||
return new ConnectionTLSServer( m_handler, newConn, m_log );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2009-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 CONNECTIONTLSSERVER_H__
|
||||
#define CONNECTIONTLSSERVER_H__
|
||||
|
||||
#include "macros.h"
|
||||
#include "logsink.h"
|
||||
#include "connectionbase.h"
|
||||
#include "connectiontls.h"
|
||||
#include "tlsdefault.h"
|
||||
#include "tlshandler.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class ConnectionDataHandler;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of the server-side of a TLS/SSL connection.
|
||||
*
|
||||
* You should not need to use this class directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API ConnectionTLSServer : public ConnectionTLS
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new ConnectionTLSServer object.
|
||||
* @param cdh The ConnectionDataHandler that will be notified of events from this connection
|
||||
* @param conn A transport connection. It should be an established connection from
|
||||
* a client that is about to perform a TLS handshake.
|
||||
* ConnectionTLSServer will own the transport connection and delete it in its destructor.
|
||||
* @param log The log target. Obtain it from ClientBase::logInstance().
|
||||
*/
|
||||
ConnectionTLSServer( ConnectionDataHandler* cdh, ConnectionBase* conn, const LogSink& log );
|
||||
|
||||
/**
|
||||
* Constructs a new ConnectionTLSServer object.
|
||||
* @param conn A transport connection. It should be an established connection from
|
||||
* a client that is about to perform a TLS handshake.
|
||||
* ConnectionTLSServer will own the transport connection and delete it in its destructor.
|
||||
* @param log The log target. Obtain it from ClientBase::logInstance().
|
||||
*/
|
||||
ConnectionTLSServer( ConnectionBase* conn, const LogSink& log );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~ConnectionTLSServer();
|
||||
|
||||
/**
|
||||
* Returns a TLS server.
|
||||
* @return A TLS server.
|
||||
*/
|
||||
virtual TLSBase* getTLSBase( TLSHandler* th, const std::string server );
|
||||
|
||||
// reimplemented from ConnectionTLS
|
||||
virtual ConnectionBase* newInstance() const;
|
||||
|
||||
private:
|
||||
ConnectionTLSServer& operator=( const ConnectionTLSServer& );
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CONNECTIONTLSSERVER_H__
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "dataform.h"
|
||||
#include "dataformfield.h"
|
||||
#include "dataformitem.h"
|
||||
#include "dataformreported.h"
|
||||
#include "util.h"
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
DataForm::DataForm( FormType type, const StringList& instructions, const std::string& title )
|
||||
: AdhocPlugin( ExtDataForm ),
|
||||
m_type( type ), m_instructions( instructions ), m_title( title ), m_reported( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
DataForm::DataForm( FormType type, const std::string& title )
|
||||
: AdhocPlugin( ExtDataForm ),
|
||||
m_type( type ), m_title( title ), m_reported( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
DataForm::DataForm( const Tag* tag )
|
||||
: AdhocPlugin( ExtDataForm ),
|
||||
m_type( TypeInvalid ), m_reported( 0 )
|
||||
{
|
||||
parse( tag );
|
||||
}
|
||||
|
||||
DataForm::DataForm( const DataForm& form )
|
||||
: AdhocPlugin( ExtDataForm ), DataFormFieldContainer( form ),
|
||||
m_type( form.m_type ), m_instructions( form.m_instructions ),
|
||||
m_title( form.m_title ), m_reported( form.m_reported ? new DataFormReported( form.m_reported->tag() ) : 0 )
|
||||
{
|
||||
}
|
||||
|
||||
DataForm::~DataForm()
|
||||
{
|
||||
util::clearList( m_items );
|
||||
delete m_reported;
|
||||
m_reported = NULL;
|
||||
}
|
||||
|
||||
static const char* dfTypeValues[] =
|
||||
{
|
||||
"form", "submit", "cancel", "result"
|
||||
};
|
||||
|
||||
bool DataForm::parse( const Tag* tag )
|
||||
{
|
||||
if( !tag || tag->xmlns() != XMLNS_X_DATA || tag->name() != "x" )
|
||||
return false;
|
||||
|
||||
const std::string& type = tag->findAttribute( TYPE );
|
||||
if( type.empty() )
|
||||
m_type = TypeForm;
|
||||
else
|
||||
{
|
||||
m_type = (FormType)util::lookup( type, dfTypeValues );
|
||||
if( m_type == TypeInvalid )
|
||||
return false;
|
||||
}
|
||||
|
||||
const TagList& l = tag->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
if( (*it)->name() == "title" )
|
||||
m_title = (*it)->cdata();
|
||||
else if( (*it)->name() == "instructions" )
|
||||
m_instructions.push_back( (*it)->cdata() );
|
||||
else if( (*it)->name() == "field" )
|
||||
m_fields.push_back( new DataFormField( (*it) ) );
|
||||
else if( (*it)->name() == "reported" )
|
||||
{
|
||||
if( m_reported == NULL )
|
||||
m_reported = new DataFormReported( (*it) );
|
||||
// else - Invalid data form - only one "reported" is allowed
|
||||
}
|
||||
else if( (*it)->name() == "item" )
|
||||
m_items.push_back( new DataFormItem( (*it) ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::string& DataForm::filterString() const
|
||||
{
|
||||
static const std::string filter = "/message/x[@xmlns='" + XMLNS_X_DATA + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* DataForm::tag() const
|
||||
{
|
||||
if( m_type == TypeInvalid )
|
||||
return 0;
|
||||
|
||||
Tag* x = new Tag( "x" );
|
||||
x->setXmlns( XMLNS_X_DATA );
|
||||
x->addAttribute( TYPE, util::lookup( m_type, dfTypeValues ) );
|
||||
if( !m_title.empty() )
|
||||
new Tag( x, "title", m_title );
|
||||
|
||||
StringList::const_iterator it_i = m_instructions.begin();
|
||||
for( ; it_i != m_instructions.end(); ++it_i )
|
||||
new Tag( x, "instructions", (*it_i) );
|
||||
|
||||
FieldList::const_iterator it = m_fields.begin();
|
||||
for( ; it != m_fields.end(); ++it )
|
||||
x->addChild( (*it)->tag() );
|
||||
|
||||
if( m_reported != NULL )
|
||||
{
|
||||
x->addChild( m_reported->tag() );
|
||||
}
|
||||
|
||||
ItemList::const_iterator iti = m_items.begin();
|
||||
for( ; iti != m_items.end(); ++iti )
|
||||
x->addChild( (*iti)->tag() );
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 DATAFORM_H__
|
||||
#define DATAFORM_H__
|
||||
|
||||
#include "dataformfieldcontainer.h"
|
||||
#include "adhocplugin.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
class DataFormItem;
|
||||
class DataFormReported;
|
||||
|
||||
/**
|
||||
* Describes the possible Form Types.
|
||||
*/
|
||||
enum FormType
|
||||
{
|
||||
TypeForm, /**< The forms-processing entity is asking the forms-submitting
|
||||
* entity to complete a form. */
|
||||
TypeSubmit, /**< The forms-submitting entity is submitting data to the
|
||||
* forms-processing entity. */
|
||||
TypeCancel, /**< The forms-submitting entity has cancelled submission of data
|
||||
* to the forms-processing entity. */
|
||||
TypeResult, /**< The forms-processing entity is returning data (e.g., search
|
||||
* results) to the forms-submitting entity, or the data is a
|
||||
* generic data set. */
|
||||
TypeInvalid /**< The form is invalid. Only possible if the form was created
|
||||
* from an Tag which doesn't correctly describe a Data Form. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a @xep{0004} Data Form.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.7
|
||||
*/
|
||||
class GLOOX_API DataForm : public AdhocPlugin, public DataFormFieldContainer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* A list of DataFormItems.
|
||||
*/
|
||||
typedef std::list<DataFormItem*> ItemList;
|
||||
|
||||
/**
|
||||
* Constructs a new, empty form.
|
||||
* @param type The form type.
|
||||
* @param instructions Natural-language instructions for filling out the form. Should not contain
|
||||
* newlines (\\n, \\r).
|
||||
* @param title The natural-language title of the form. Should not contain newlines (\\n, \\r).
|
||||
*/
|
||||
DataForm( FormType type, const StringList& instructions, const std::string& title = EmptyString );
|
||||
|
||||
/**
|
||||
* Constructs a new, empty form without any instructions or title set. Probably best suited for
|
||||
* result forms.
|
||||
* @param type The form type.
|
||||
* @param title The natural-language title of the form. Should not contain newlines (\\n, \\r).
|
||||
* @since 0.9
|
||||
*/
|
||||
DataForm( FormType type, const std::string& title = EmptyString );
|
||||
|
||||
/**
|
||||
* Constructs a new DataForm from an existing Tag/XML representation.
|
||||
* @param tag The existing form to parse.
|
||||
*/
|
||||
DataForm( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Creates a new DataForm, copying the given one.
|
||||
* @param form The form to copy.
|
||||
*/
|
||||
DataForm( const DataForm& form );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~DataForm();
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the title of the form.
|
||||
* @return The title of the form.
|
||||
*/
|
||||
const std::string& title() const { return m_title; }
|
||||
|
||||
/**
|
||||
* Use this function to set the title of the form.
|
||||
* @param title The new title of the form.
|
||||
* @note The title should not contain newlines (\\n, \\r).
|
||||
*/
|
||||
void setTitle( const std::string& title ) { m_title = title; }
|
||||
|
||||
/**
|
||||
* Retrieves the natural-language instructions for the form.
|
||||
* @return The fill-in instructions for the form.
|
||||
*/
|
||||
const StringList& instructions() const { return m_instructions; }
|
||||
|
||||
/**
|
||||
* Use this function to set natural-language instructions for the form.
|
||||
* @param instructions The instructions for the form.
|
||||
* @note The instructions should not contain newlines (\\n, \\r). Instead, every line should be an
|
||||
* element of the StringMap. This allows for platform dependent newline handling on the target
|
||||
* platform.
|
||||
*/
|
||||
void setInstructions( const StringList& instructions ) { m_instructions = instructions; }
|
||||
|
||||
/**
|
||||
* Returns the reported field list in a DataForm.
|
||||
* @return The reported section, containing 0..n fields.
|
||||
*/
|
||||
const DataFormReported* reported() const { return m_reported; }
|
||||
|
||||
/**
|
||||
* Returns a list of items in a DataForm.
|
||||
* @return A list of items.
|
||||
*/
|
||||
const ItemList& items() const { return m_items; }
|
||||
|
||||
/**
|
||||
* Returns the form's type.
|
||||
* @return The form's type.
|
||||
* @since 0.9
|
||||
*/
|
||||
FormType type() const { return m_type; }
|
||||
|
||||
/**
|
||||
* Sets the form's type.
|
||||
* @param type The form's new type.
|
||||
*/
|
||||
void setType( FormType type ) { m_type = type; }
|
||||
|
||||
/**
|
||||
* Parses the given Tag and creates an appropriate DataForm representation.
|
||||
* @param tag The Tag to parse.
|
||||
* @return @b True on success, @b false otherwise.
|
||||
* @since 0.9
|
||||
*/
|
||||
bool parse( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Converts to @b true if the DataForm is valid, @b false otherwise.
|
||||
*/
|
||||
operator bool() const { return m_type != TypeInvalid; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new DataForm( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new DataForm( *this );
|
||||
}
|
||||
|
||||
protected:
|
||||
FormType m_type;
|
||||
|
||||
private:
|
||||
StringList m_instructions;
|
||||
|
||||
std::string m_title;
|
||||
DataFormReported* m_reported;
|
||||
ItemList m_items;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DATAFORM_H__
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "dataformfield.h"
|
||||
#include "util.h"
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
static const char* fieldTypeValues[] =
|
||||
{
|
||||
"boolean", "fixed", "hidden", "jid-multi", "jid-single",
|
||||
"list-multi", "list-single", "text-multi", "text-private", "text-single", ""
|
||||
};
|
||||
|
||||
DataFormField::DataFormField( FieldType type )
|
||||
: m_type( type ), m_required( false )
|
||||
{
|
||||
}
|
||||
|
||||
DataFormField::DataFormField( const std::string& name, const std::string& value,
|
||||
const std::string& label, FieldType type )
|
||||
: m_type( type ), m_name( name ), m_label( label ), m_required( false )
|
||||
{
|
||||
m_values.push_back( value );
|
||||
}
|
||||
|
||||
DataFormField::DataFormField( const Tag* tag )
|
||||
: m_type( TypeInvalid ), m_required( false )
|
||||
{
|
||||
if( !tag )
|
||||
return;
|
||||
|
||||
const std::string& type = tag->findAttribute( TYPE );
|
||||
if( type.empty() )
|
||||
{
|
||||
if( !tag->name().empty() )
|
||||
m_type = TypeNone;
|
||||
}
|
||||
else
|
||||
m_type = (FieldType)util::lookup( type, fieldTypeValues );
|
||||
|
||||
if( tag->hasAttribute( "var" ) )
|
||||
m_name = tag->findAttribute( "var" );
|
||||
|
||||
if( tag->hasAttribute( "label" ) )
|
||||
m_label = tag->findAttribute( "label" );
|
||||
|
||||
const TagList& l = tag->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
if( (*it)->name() == "desc" )
|
||||
m_desc = (*it)->cdata();
|
||||
else if( (*it)->name() == "required" )
|
||||
m_required = true;
|
||||
else if( (*it)->name() == "value" )
|
||||
{
|
||||
if( m_type == TypeTextMulti || m_type == TypeListMulti || m_type == TypeJidMulti )
|
||||
addValue( (*it)->cdata() );
|
||||
else
|
||||
setValue( (*it)->cdata() );
|
||||
}
|
||||
else if( (*it)->name() == "option" )
|
||||
{
|
||||
Tag* v = (*it)->findChild( "value" );
|
||||
if( v )
|
||||
m_options.insert( std::make_pair( (*it)->findAttribute( "label" ), v->cdata() ) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DataFormField::~DataFormField()
|
||||
{
|
||||
}
|
||||
|
||||
Tag* DataFormField::tag() const
|
||||
{
|
||||
if( m_type == TypeInvalid )
|
||||
return 0;
|
||||
|
||||
Tag* field = new Tag( "field" );
|
||||
field->addAttribute( TYPE, util::lookup( m_type, fieldTypeValues ) );
|
||||
field->addAttribute( "var", m_name );
|
||||
field->addAttribute( "label", m_label );
|
||||
if( m_required )
|
||||
new Tag( field, "required" );
|
||||
|
||||
if( !m_desc.empty() )
|
||||
new Tag( field, "desc", m_desc );
|
||||
|
||||
if( m_type == TypeListSingle || m_type == TypeListMulti )
|
||||
{
|
||||
StringMultiMap::const_iterator it = m_options.begin();
|
||||
for( ; it != m_options.end(); ++it )
|
||||
{
|
||||
Tag* option = new Tag( field, "option", "label", (*it).first );
|
||||
new Tag( option, "value", (*it).second );
|
||||
}
|
||||
}
|
||||
else if( m_type == TypeBoolean )
|
||||
{
|
||||
if( m_values.size() == 0 || m_values.front() == "false" || m_values.front() == "0" )
|
||||
new Tag( field, "value", "0" );
|
||||
else
|
||||
new Tag( field, "value", "1" );
|
||||
}
|
||||
|
||||
if( m_type == TypeTextMulti || m_type == TypeListMulti || m_type == TypeJidMulti )
|
||||
{
|
||||
StringList::const_iterator it = m_values.begin();
|
||||
for( ; it != m_values.end() ; ++it )
|
||||
new Tag( field, "value", (*it) );
|
||||
}
|
||||
|
||||
if( m_values.size() && !( m_type == TypeTextMulti || m_type == TypeListMulti
|
||||
|| m_type == TypeBoolean || m_type == TypeJidMulti ) )
|
||||
new Tag( field, "value", m_values.front() );
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 DATAFORMFIELD_H__
|
||||
#define DATAFORMFIELD_H__
|
||||
|
||||
#include "gloox.h"
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a single field in a @xep{0004} Data Form.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.7
|
||||
*/
|
||||
class GLOOX_API DataFormField
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Describes the possible types of a Data Form Field.
|
||||
*/
|
||||
enum FieldType
|
||||
{
|
||||
TypeBoolean, /**< The field enables an entity to gather or provide an either-or
|
||||
* choice between two options. The default value is "false". */
|
||||
TypeFixed, /**< The field is intended for data description (e.g.,
|
||||
* human-readable text such as "section" headers) rather than data
|
||||
* gathering or provision. The <value/> child SHOULD NOT contain
|
||||
* newlines (the \\n and \\r characters); instead an application SHOULD
|
||||
* generate multiple fixed fields, each with one <value/> child. */
|
||||
TypeHidden, /**< The field is not shown to the entity providing information, but
|
||||
* instead is returned with the form. */
|
||||
TypeJidMulti, /**< The field enables an entity to gather or provide multiple Jabber
|
||||
* IDs.*/
|
||||
TypeJidSingle, /**< The field enables an entity to gather or provide a single Jabber
|
||||
* ID.*/
|
||||
TypeListMulti, /**< The field enables an entity to gather or provide one or more options
|
||||
* from among many. */
|
||||
TypeListSingle, /**< The field enables an entity to gather or provide one option from
|
||||
* among many. */
|
||||
TypeTextMulti, /**< The field enables an entity to gather or provide multiple lines of
|
||||
* text. */
|
||||
TypeTextPrivate, /**< The field enables an entity to gather or provide a single line or
|
||||
* word of text, which shall be obscured in an interface
|
||||
* (e.g., *****). */
|
||||
TypeTextSingle, /**< The field enables an entity to gather or provide a single line or
|
||||
* word of text, which may be shown in an interface. This field type is
|
||||
* the default and MUST be assumed if an entity receives a field type it
|
||||
* does not understand.*/
|
||||
TypeNone, /**< The field is child of either a <reported> or <item>
|
||||
* element or has no type attribute. */
|
||||
TypeInvalid /**< The field is invalid. Only possible if the field was created from
|
||||
* a Tag not correctly describing a Data Form Field. */
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructs a new DataForm field.
|
||||
* @param type The type of the field. Default: text-single.
|
||||
*/
|
||||
DataFormField( FieldType type = TypeTextSingle );
|
||||
|
||||
/**
|
||||
* Constructs a new DataForm field and fills it with the given values.
|
||||
* @param name The field's name (the value of the 'var' attribute).
|
||||
* @param value The field's value.
|
||||
* @param label The field's label.
|
||||
* @param type The field's type.
|
||||
* @since 0.9
|
||||
*/
|
||||
DataFormField( const std::string& name, const std::string& value = EmptyString,
|
||||
const std::string& label = EmptyString, FieldType type = TypeTextSingle );
|
||||
|
||||
/**
|
||||
* Constructs a new Data Form Field from an existing tag that describes a field.
|
||||
* @param tag The tag to parse.
|
||||
*/
|
||||
DataFormField( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~DataFormField();
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the optional values of a field.
|
||||
* @return The options of a field.
|
||||
*/
|
||||
const StringMultiMap& options() const { return m_options; }
|
||||
|
||||
/**
|
||||
* Use this function to create a Tag representation of the form field. This is usually called by
|
||||
* DataForm.
|
||||
* @return A Tag hierarchically describing the form field, or NULL if the field is invalid (i.e.
|
||||
* created from a Tag not correctly describing a Data Form Field).
|
||||
*/
|
||||
virtual Tag* tag() const;
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the name of the field (the content of the 'var' attribute).
|
||||
* @return The name of the field.
|
||||
*/
|
||||
const std::string& name() const { return m_name; }
|
||||
|
||||
/**
|
||||
* Sets the name (the content of the 'var' attribute) of the field. The name identifies the
|
||||
* field uniquely in the form.
|
||||
* @param name The new name of the field.
|
||||
* @note Fields of type other than 'fixed' MUST have a name, if it is 'fixed', it MAY.
|
||||
*/
|
||||
void setName( const std::string& name ) { m_name = name; }
|
||||
|
||||
/**
|
||||
* Use this function to set the optional values of the field. The key of the map
|
||||
* will be used as the label of the option, while the value will be used as ... the
|
||||
* value. ;)
|
||||
* @param options The optional values of a list* or *multi type of field.
|
||||
*/
|
||||
void setOptions( const StringMultiMap& options ) { m_options = options; }
|
||||
|
||||
/**
|
||||
* Adds a single option to the list of options.
|
||||
* @param label The label of the option.
|
||||
* @param value The value of the option.
|
||||
* @since 0.9.4
|
||||
*/
|
||||
void addOption( const std::string& label, const std::string& value )
|
||||
{ m_options.insert( std::make_pair( label, value ) ); }
|
||||
|
||||
/**
|
||||
* Use this function to determine whether or not this field is required.
|
||||
* @return Whether or not this field is required.
|
||||
*/
|
||||
bool required() const { return m_required; }
|
||||
|
||||
/**
|
||||
* Use this field to set this field to be required.
|
||||
* @param required Whether or not this field is required.
|
||||
*/
|
||||
void setRequired( bool required ) { m_required = required; }
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the describing label of this field.
|
||||
* @return The describing label of this field.
|
||||
*/
|
||||
const std::string& label() const { return m_label; }
|
||||
|
||||
/**
|
||||
* Use this function to set the describing label of this field.
|
||||
* @param label The describing label of this field.
|
||||
*/
|
||||
void setLabel( const std::string& label ) { m_label = label; }
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the description of this field.
|
||||
* @return The description of this field
|
||||
*/
|
||||
const std::string& description() const { return m_desc; }
|
||||
|
||||
/**
|
||||
* Use this function to set the description of this field.
|
||||
* @param desc The description of this field.
|
||||
*/
|
||||
void setDescription( const std::string& desc ) { m_desc = desc; }
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the value of this field.
|
||||
* @return The value of this field.
|
||||
*/
|
||||
const std::string& value() const { return ( m_values.size() > 0 ) ? m_values.front() : EmptyString; }
|
||||
|
||||
/**
|
||||
* Use this function to set the value of this field.
|
||||
* @param value The new value of this field.
|
||||
*/
|
||||
void setValue( const std::string& value ) { m_values.clear(); addValue( value ); }
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the values of this field, if its of type 'text-multi'.
|
||||
* @return The value of this field.
|
||||
*/
|
||||
const StringList& values() const { return m_values; }
|
||||
|
||||
/**
|
||||
* Use this function to set multiple values of this field, if it is of type 'text-multi'. If its not,
|
||||
* use @ref setValue() instead.
|
||||
* @param values The new values of this field.
|
||||
*/
|
||||
void setValues( const StringList& values ) { m_values = values; }
|
||||
|
||||
/**
|
||||
* Adds a single value to the list of values.
|
||||
* @param value The value to add.
|
||||
*/
|
||||
void addValue( const std::string& value ) { m_values.push_back( value ); }
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the type of this field.
|
||||
* @return The type of this field.
|
||||
*/
|
||||
FieldType type() const { return m_type; }
|
||||
|
||||
/**
|
||||
* Converts to @b true if the FormBase is valid, @b false otherwise.
|
||||
*/
|
||||
operator bool() const { return m_type != TypeInvalid; }
|
||||
|
||||
private:
|
||||
FieldType m_type;
|
||||
|
||||
StringMultiMap m_options;
|
||||
StringList m_values;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_desc;
|
||||
std::string m_label;
|
||||
|
||||
bool m_required;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DATAFORMFIELD_H__
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "dataformfieldcontainer.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
DataFormFieldContainer::DataFormFieldContainer()
|
||||
{
|
||||
}
|
||||
|
||||
DataFormFieldContainer::DataFormFieldContainer( const DataFormFieldContainer& dffc )
|
||||
{
|
||||
FieldList::const_iterator it = dffc.m_fields.begin();
|
||||
for( ; it != dffc.m_fields.end(); ++it )
|
||||
{
|
||||
m_fields.push_back( new DataFormField( *(*it) ) );
|
||||
}
|
||||
}
|
||||
|
||||
DataFormFieldContainer::~DataFormFieldContainer()
|
||||
{
|
||||
util::clearList( m_fields );
|
||||
}
|
||||
|
||||
DataFormField* DataFormFieldContainer::field( const std::string& field ) const
|
||||
{
|
||||
FieldList::const_iterator it = m_fields.begin();
|
||||
for( ; it != m_fields.end() && (*it)->name() != field; ++it )
|
||||
;
|
||||
return it != m_fields.end() ? (*it) : 0;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 DATAFORMFIELDCONTAINER_H__
|
||||
#define DATAFORMFIELDCONTAINER_H__
|
||||
|
||||
#include "dataformfield.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class DataFormField;
|
||||
|
||||
/**
|
||||
* @brief An abstract base class for a @xep{0004} Data Form.
|
||||
*
|
||||
* You shouldn't need to use this class directly. Use DataForm instead.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.7
|
||||
*/
|
||||
class GLOOX_API DataFormFieldContainer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new FieldContainer.
|
||||
*/
|
||||
DataFormFieldContainer();
|
||||
|
||||
/**
|
||||
* Creates a new FieldContainer, copying all fields from the given FieldContainer.
|
||||
* @param dffc The FieldContainer to copy.
|
||||
*/
|
||||
DataFormFieldContainer( const DataFormFieldContainer& dffc );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~DataFormFieldContainer();
|
||||
|
||||
/**
|
||||
* A list of @xep{0004} Data Form Fields.
|
||||
*/
|
||||
typedef std::list<DataFormField*> FieldList;
|
||||
|
||||
/**
|
||||
* Use this function to check whether this form contains a field with the given name.
|
||||
* @param field The name of the field (the content of the 'var' attribute).
|
||||
* @return Whether or not the form contains the named field.
|
||||
*/
|
||||
bool hasField( const std::string& field ) const
|
||||
{ return DataFormFieldContainer::field( field ) != 0; }
|
||||
|
||||
/**
|
||||
* Use this function to fetch a pointer to a field of the form. If no such field exists,
|
||||
* 0 is returned.
|
||||
* @param field The name of the field (the content of the 'var' attribute).
|
||||
* @return A copy of the field with the given name if it exists, 0 otherwise.
|
||||
*/
|
||||
DataFormField* field( const std::string& field ) const;
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the list of fields of a form.
|
||||
* @return The list of fields the form contains.
|
||||
*/
|
||||
FieldList& fields() { return m_fields; }
|
||||
|
||||
/**
|
||||
* Use this function to retrieve the const list of fields of a form.
|
||||
* @return The const list of fields the form contains.
|
||||
*/
|
||||
const FieldList& fields() const { return m_fields; }
|
||||
|
||||
/**
|
||||
* Use this function to set the fields the form contains.
|
||||
* @param fields The list of fields.
|
||||
* @note Any previously set fields will be deleted. Always set all fields, not a delta.
|
||||
*/
|
||||
virtual void setFields( FieldList& fields ) { m_fields = fields; }
|
||||
|
||||
/**
|
||||
* Use this function to add a single field to the list of existing fields.
|
||||
* @param field The field to add.
|
||||
* @since 0.9
|
||||
*/
|
||||
virtual void addField( DataFormField* field ) { m_fields.push_back( field ); }
|
||||
|
||||
/**
|
||||
* Adds a single new Field and returns a pointer to that field.
|
||||
* @param type The field's type.
|
||||
* @param name The field's name (the value of the 'var' attribute).
|
||||
* @param value The field's value.
|
||||
* @param label The field's label.
|
||||
* @since 0.9.4
|
||||
*/
|
||||
DataFormField* addField( DataFormField::FieldType type, const std::string& name,
|
||||
const std::string& value = EmptyString,
|
||||
const std::string& label = EmptyString )
|
||||
{
|
||||
DataFormField* field = new DataFormField( name, value, label, type );
|
||||
m_fields.push_back( field );
|
||||
return field;
|
||||
}
|
||||
|
||||
protected:
|
||||
FieldList m_fields;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DATAFORMFIELDCONTAINER_H__
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
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 "dataformitem.h"
|
||||
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
DataFormItem::DataFormItem()
|
||||
{
|
||||
}
|
||||
|
||||
DataFormItem::DataFormItem( const Tag* tag )
|
||||
{
|
||||
if( tag->name() != "item" )
|
||||
return;
|
||||
|
||||
const TagList &l = tag->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
DataFormField* f = new DataFormField( (*it) );
|
||||
m_fields.push_back( f );
|
||||
}
|
||||
}
|
||||
|
||||
DataFormItem::~DataFormItem()
|
||||
{
|
||||
}
|
||||
|
||||
Tag* DataFormItem::tag() const
|
||||
{
|
||||
Tag* i = new Tag ( "item" );
|
||||
DataFormFieldContainer::FieldList::const_iterator it = m_fields.begin();
|
||||
for( ; it != m_fields.end(); ++it )
|
||||
{
|
||||
i->addChild( (*it)->tag() );
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 DATAFORMITEM_H__
|
||||
#define DATAFORMITEM_H__
|
||||
|
||||
#include "dataformfieldcontainer.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An abstraction of an <item> element in a @xep{0004} Data Form of type result.
|
||||
*
|
||||
* There are some constraints regarding usage of this element you should be aware of. Check @xep{0004}
|
||||
* section 3.4. This class does not enforce correct usage at this point.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.7
|
||||
*/
|
||||
class GLOOX_API DataFormItem : public DataFormFieldContainer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates an empty 'item' element you can add fields to.
|
||||
*/
|
||||
DataFormItem();
|
||||
|
||||
/**
|
||||
* Creates a 'item' element and fills it with the 'field' elements contained in the given Tag.
|
||||
* The Tag's root element must be a 'item' element. Its child element should be 'field' elements.
|
||||
* @param tag The tag to read the 'field' elements from.
|
||||
* @since 0.8.5
|
||||
*/
|
||||
DataFormItem( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~DataFormItem();
|
||||
|
||||
/**
|
||||
* Creates and returns a Tag representation of the current object.
|
||||
* @return A Tag representation of the current object.
|
||||
*/
|
||||
virtual Tag* tag() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DATAFORMITEM_H__
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
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 "dataformreported.h"
|
||||
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
DataFormReported::DataFormReported()
|
||||
{
|
||||
}
|
||||
|
||||
DataFormReported::DataFormReported( Tag* tag )
|
||||
{
|
||||
if( tag->name() != "reported" )
|
||||
return;
|
||||
|
||||
const TagList &l = tag->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
DataFormField* f = new DataFormField( (*it) );
|
||||
m_fields.push_back( f );
|
||||
}
|
||||
}
|
||||
|
||||
DataFormReported::~DataFormReported()
|
||||
{
|
||||
}
|
||||
|
||||
Tag* DataFormReported::tag() const
|
||||
{
|
||||
Tag* r = new Tag ( "reported" );
|
||||
DataFormFieldContainer::FieldList::const_iterator it = m_fields.begin();
|
||||
for( ; it != m_fields.end(); ++it )
|
||||
{
|
||||
r->addChild( (*it)->tag() );
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 DATAFORMREPORTED_H__
|
||||
#define DATAFORMREPORTED_H__
|
||||
|
||||
#include "dataformfieldcontainer.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a <reported> element in a @xep{0004} Data Form of type result.
|
||||
*
|
||||
* There are some constraints regarding usage of this element you should be aware of. Check @xep{0004}
|
||||
* section 3.4. This class does not enforce correct usage at this point.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.7
|
||||
*/
|
||||
class GLOOX_API DataFormReported : public DataFormFieldContainer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates an empty 'reported' element you can add fields to.
|
||||
*/
|
||||
DataFormReported();
|
||||
|
||||
/**
|
||||
* Creates a 'reported' element and fills it with the 'field' elements contained in the given Tag.
|
||||
* The Tag's root element must be a 'reported' element. Its child element should be 'field' elements.
|
||||
* @param tag The tag to read the 'field' elements from.
|
||||
* @since 0.8.5
|
||||
*/
|
||||
DataFormReported( Tag* tag );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~DataFormReported();
|
||||
|
||||
/**
|
||||
* Creates and returns a Tag representation of the current object.
|
||||
* @return A Tag representation of the current object.
|
||||
*/
|
||||
virtual Tag* tag() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DATAFORMREPORTED_H__
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
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 "delayeddelivery.h"
|
||||
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
DelayedDelivery::DelayedDelivery( const JID& from, const std::string stamp, const std::string& reason )
|
||||
: StanzaExtension( ExtDelay ), m_from( from ), m_stamp( stamp ), m_reason( reason ), m_valid( false )
|
||||
{
|
||||
if( !m_stamp.empty() )
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
|
||||
DelayedDelivery::DelayedDelivery( const Tag* tag )
|
||||
: StanzaExtension( ExtDelay ), m_valid( false )
|
||||
{
|
||||
if( !tag || !tag->hasAttribute( "stamp" ) )
|
||||
return;
|
||||
|
||||
if( !( tag->name() == "x" && tag->hasAttribute( XMLNS, XMLNS_X_DELAY ) ) )
|
||||
if( !( tag->name() == "delay" && tag->hasAttribute( XMLNS, XMLNS_DELAY ) ) )
|
||||
return;
|
||||
|
||||
m_reason = tag->cdata();
|
||||
m_stamp = tag->findAttribute( "stamp" );
|
||||
m_from = tag->findAttribute( "from" );
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
DelayedDelivery::~DelayedDelivery()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& DelayedDelivery::filterString() const
|
||||
{
|
||||
static const std::string filter =
|
||||
"/presence/delay[@xmlns='" + XMLNS_DELAY + "']"
|
||||
"|/message/delay[@xmlns='" + XMLNS_DELAY + "']"
|
||||
"|/presence/x[@xmlns='" + XMLNS_X_DELAY + "']"
|
||||
"|/message/x[@xmlns='" + XMLNS_X_DELAY + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* DelayedDelivery::tag() const
|
||||
{
|
||||
if( !m_valid )
|
||||
return 0;
|
||||
|
||||
Tag* t = new Tag( "delay" );
|
||||
t->addAttribute( XMLNS, XMLNS_DELAY );
|
||||
if( m_from )
|
||||
t->addAttribute( "from", m_from.full() );
|
||||
if( !m_stamp.empty() )
|
||||
t->addAttribute( "stamp", m_stamp );
|
||||
if( !m_reason.empty() )
|
||||
t->setCData( m_reason );
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DELAYEDDELIVERY_H__
|
||||
#define DELAYEDDELIVERY_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "jid.h"
|
||||
#include "stanzaextension.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief This is an implementation of @xep{0203} (Delayed Delivery).
|
||||
*
|
||||
* The class also implements the deprecated @xep{0091} (Delayed Delivery) in a read-only fashion.
|
||||
* It understands both XEP formats for input, but any output will conform to @xep{0203}.
|
||||
*
|
||||
* XEP Version: 0.1
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.9
|
||||
*/
|
||||
class GLOOX_API DelayedDelivery : public StanzaExtension
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a new object and fills it according to the parameters.
|
||||
* @param from The JID of the original sender or the entity that delayed the sending.
|
||||
* @param stamp The datetime stamp of the original send.
|
||||
* @param reason An optional natural language reason for the delay.
|
||||
*/
|
||||
DelayedDelivery( const JID& from, const std::string stamp,
|
||||
const std::string& reason = "" );
|
||||
|
||||
/**
|
||||
* Constructs a new object from the given Tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
DelayedDelivery( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~DelayedDelivery();
|
||||
|
||||
/**
|
||||
* Returns the datetime when the stanza was originally sent.
|
||||
* The format MUST adhere to the dateTime format specified in @xep{0082} and MUST
|
||||
* be expressed in UTC.
|
||||
* @return The original datetime.
|
||||
*/
|
||||
const std::string& stamp() const { return m_stamp; }
|
||||
|
||||
/**
|
||||
* Sets the original datetime.
|
||||
* @param stamp The original datetime.
|
||||
*/
|
||||
void setStamp( const std::string& stamp ) { m_stamp = stamp; }
|
||||
|
||||
/**
|
||||
* Returns the JID of the original sender of the stanza or the entity that
|
||||
* delayed the sending.
|
||||
* The format MUST adhere to the dateTime format specified in @xep{0082} and MUST
|
||||
* be expressed in UTC.
|
||||
* @return The JID.
|
||||
*/
|
||||
const JID& from() const { return m_from; }
|
||||
|
||||
/**
|
||||
* Sets the JID of the origianl sender or the entity that delayed the sending.
|
||||
* @param from The JID.
|
||||
*/
|
||||
void setFrom( const JID& from ) { m_from = from; }
|
||||
|
||||
/**
|
||||
* Returns a natural language reason for the delay.
|
||||
* @return A natural language reason for the delay.
|
||||
*/
|
||||
const std::string& reason() const { return m_reason; }
|
||||
|
||||
/**
|
||||
* Sets the reason for the delay.
|
||||
* @param reason The reason for the delay.
|
||||
*/
|
||||
void setReason( const std::string& reason ) { m_reason = reason; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new DelayedDelivery( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new DelayedDelivery( *this );
|
||||
}
|
||||
|
||||
private:
|
||||
JID m_from;
|
||||
std::string m_stamp;
|
||||
std::string m_reason;
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DELAYEDDELIVERY_H__
|
|
@ -1,535 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 "disco.h"
|
||||
#include "discohandler.h"
|
||||
#include "dataform.h"
|
||||
#include "error.h"
|
||||
#include "clientbase.h"
|
||||
#include "disconodehandler.h"
|
||||
#include "softwareversion.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
// ---- Disco::Identity ----
|
||||
Disco::Identity::Identity( const std::string& category,
|
||||
const std::string& type,
|
||||
const std::string& name )
|
||||
: m_category( category ), m_type( type ), m_name( name )
|
||||
{
|
||||
}
|
||||
|
||||
Disco::Identity::Identity( const Tag* tag )
|
||||
{
|
||||
if( !tag || tag->name() != "identity" )
|
||||
return;
|
||||
|
||||
m_category = tag->findAttribute( "category" );
|
||||
m_type = tag->findAttribute( "type" );
|
||||
m_name = tag->findAttribute( "name" );
|
||||
}
|
||||
|
||||
Disco::Identity::Identity( const Identity& id )
|
||||
: m_category( id.m_category ), m_type( id.m_type ), m_name( id.m_name )
|
||||
{
|
||||
}
|
||||
|
||||
Disco::Identity::~Identity()
|
||||
{
|
||||
}
|
||||
|
||||
Tag* Disco::Identity::tag() const
|
||||
{
|
||||
if( m_category.empty() || m_type.empty() )
|
||||
return 0;
|
||||
|
||||
Tag* i = new Tag( "identity" );
|
||||
i->addAttribute( "category", m_category );
|
||||
i->addAttribute( "type", m_type );
|
||||
|
||||
if( !m_name.empty() )
|
||||
i->addAttribute( "name", m_name );
|
||||
|
||||
return i;
|
||||
}
|
||||
// ---- ~Disco::Identity ----
|
||||
|
||||
// ---- Disco::Info ----
|
||||
Disco::Info::Info( const std::string& node, bool defaultFeatures )
|
||||
: StanzaExtension( ExtDiscoInfo ), m_node( node ), m_form( 0 )
|
||||
{
|
||||
if( defaultFeatures )
|
||||
{
|
||||
m_features.push_back( XMLNS_DISCO_INFO );
|
||||
m_features.push_back( XMLNS_DISCO_ITEMS );
|
||||
}
|
||||
}
|
||||
|
||||
Disco::Info::Info( const Tag* tag )
|
||||
: StanzaExtension( ExtDiscoInfo ), m_form( 0 )
|
||||
{
|
||||
if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_DISCO_INFO )
|
||||
return;
|
||||
|
||||
m_node = tag->findAttribute( "node" );
|
||||
|
||||
const TagList& l = tag->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
const std::string& name = (*it)->name();
|
||||
if( name == "identity" )
|
||||
m_identities.push_back( new Identity( (*it) ) );
|
||||
else if( name == "feature" && (*it)->hasAttribute( "var" ) )
|
||||
m_features.push_back( (*it)->findAttribute( "var" ) );
|
||||
else if( !m_form && name == "x" && (*it)->xmlns() == XMLNS_X_DATA )
|
||||
m_form = new DataForm( (*it) );
|
||||
}
|
||||
}
|
||||
|
||||
Disco::Info::Info( const Info& info )
|
||||
: StanzaExtension( ExtDiscoInfo ), m_node( info.m_node ), m_features( info.m_features ),
|
||||
m_identities( info.m_identities ), m_form( info.m_form ? new DataForm( *(info.m_form) ) : 0 )
|
||||
{
|
||||
}
|
||||
|
||||
Disco::Info::~Info()
|
||||
{
|
||||
delete m_form;
|
||||
util::clearList( m_identities );
|
||||
}
|
||||
|
||||
void Disco::Info::setForm( DataForm* form )
|
||||
{
|
||||
delete m_form;
|
||||
m_form = form;
|
||||
}
|
||||
|
||||
bool Disco::Info::hasFeature( const std::string& feature ) const
|
||||
{
|
||||
StringList::const_iterator it = m_features.begin();
|
||||
for( ; it != m_features.end() && (*it) != feature; ++it )
|
||||
;
|
||||
return it != m_features.end();
|
||||
}
|
||||
|
||||
const std::string& Disco::Info::filterString() const
|
||||
{
|
||||
static const std::string filter = "/iq/query[@xmlns='" + XMLNS_DISCO_INFO + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Disco::Info::tag() const
|
||||
{
|
||||
Tag* t = new Tag( "query", XMLNS, XMLNS_DISCO_INFO );
|
||||
|
||||
if( !m_node.empty() )
|
||||
t->addAttribute( "node", m_node );
|
||||
|
||||
IdentityList::const_iterator it_i = m_identities.begin();
|
||||
for( ; it_i != m_identities.end(); ++it_i )
|
||||
t->addChild( (*it_i)->tag() );
|
||||
|
||||
StringList::const_iterator it_f = m_features.begin();
|
||||
for( ; it_f != m_features.end(); ++it_f )
|
||||
new Tag( t, "feature", "var", (*it_f) );
|
||||
|
||||
if( m_form )
|
||||
t->addChild( m_form->tag() );
|
||||
|
||||
return t;
|
||||
}
|
||||
// ---- ~Disco::Info ----
|
||||
|
||||
// ---- Disco::Item ----
|
||||
Disco::Item::Item( const Tag* tag )
|
||||
{
|
||||
if( !tag || tag->name() != "item" )
|
||||
return;
|
||||
|
||||
m_jid = tag->findAttribute( "jid" );
|
||||
m_node = tag->findAttribute( "node" );
|
||||
m_name = tag->findAttribute( "name" );
|
||||
}
|
||||
|
||||
Tag* Disco::Item::tag() const
|
||||
{
|
||||
if( !m_jid )
|
||||
return 0;
|
||||
|
||||
Tag* i = new Tag( "item" );
|
||||
i->addAttribute( "jid", m_jid.full() );
|
||||
|
||||
if( !m_node.empty() )
|
||||
i->addAttribute( "node", m_node );
|
||||
if( !m_name.empty() )
|
||||
i->addAttribute( "name", m_name );
|
||||
|
||||
return i;
|
||||
}
|
||||
// ---- ~Disco::Item ----
|
||||
|
||||
// ---- Disco::Items ----
|
||||
Disco::Items::Items( const std::string& node )
|
||||
: StanzaExtension( ExtDiscoItems ), m_node( node )
|
||||
{
|
||||
}
|
||||
|
||||
Disco::Items::Items( const Tag* tag )
|
||||
: StanzaExtension( ExtDiscoItems )
|
||||
{
|
||||
if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_DISCO_ITEMS )
|
||||
return;
|
||||
|
||||
m_node = tag->findAttribute( "node" );
|
||||
|
||||
const TagList& l = tag->children();
|
||||
TagList::const_iterator it = l.begin();
|
||||
for( ; it != l.end(); ++it )
|
||||
{
|
||||
const std::string& name = (*it)->name();
|
||||
if( name == "item" )
|
||||
m_items.push_back( new Item( (*it) ) );
|
||||
}
|
||||
}
|
||||
|
||||
Disco::Items::~Items()
|
||||
{
|
||||
util::clearList( m_items );
|
||||
}
|
||||
|
||||
void Disco::Items::setItems( const ItemList& items )
|
||||
{
|
||||
util::clearList( m_items );
|
||||
m_items = items;
|
||||
}
|
||||
|
||||
|
||||
const std::string& Disco::Items::filterString() const
|
||||
{
|
||||
static const std::string filter = "/iq/query[@xmlns='" + XMLNS_DISCO_ITEMS + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* Disco::Items::tag() const
|
||||
{
|
||||
Tag* t = new Tag( "query", XMLNS, XMLNS_DISCO_ITEMS );
|
||||
|
||||
if( !m_node.empty() )
|
||||
t->addAttribute( "node", m_node );
|
||||
|
||||
ItemList::const_iterator it_i = m_items.begin();
|
||||
for( ; it_i != m_items.end(); ++it_i )
|
||||
t->addChild( (*it_i)->tag() );
|
||||
|
||||
return t;
|
||||
}
|
||||
// ---- ~Disco::Items ----
|
||||
|
||||
// ---- Disco ----
|
||||
Disco::Disco( ClientBase* parent )
|
||||
: m_parent( parent ), m_form( 0 )
|
||||
{
|
||||
addFeature( XMLNS_VERSION );
|
||||
// addFeature( XMLNS_DISCO_INFO ); //handled by Disco::Info now
|
||||
// addFeature( XMLNS_DISCO_ITEMS ); //handled by Disco::Info now
|
||||
if( m_parent )
|
||||
{
|
||||
m_parent->registerIqHandler( this, ExtDiscoInfo );
|
||||
m_parent->registerIqHandler( this, ExtDiscoItems );
|
||||
m_parent->registerIqHandler( this, ExtVersion );
|
||||
m_parent->registerStanzaExtension( new Disco::Info() );
|
||||
m_parent->registerStanzaExtension( new Disco::Items() );
|
||||
m_parent->registerStanzaExtension( new SoftwareVersion() );
|
||||
}
|
||||
}
|
||||
|
||||
Disco::~Disco()
|
||||
{
|
||||
util::clearList( m_identities );
|
||||
delete m_form;
|
||||
|
||||
if( m_parent )
|
||||
{
|
||||
m_parent->removeIqHandler( this, ExtDiscoInfo );
|
||||
m_parent->removeIqHandler( this, ExtDiscoItems );
|
||||
m_parent->removeIqHandler( this, ExtVersion );
|
||||
m_parent->removeStanzaExtension( ExtDiscoInfo );
|
||||
m_parent->removeStanzaExtension( ExtDiscoItems );
|
||||
m_parent->removeStanzaExtension( ExtVersion );
|
||||
m_parent->removeIDHandler( this );
|
||||
}
|
||||
}
|
||||
|
||||
void Disco::setForm( DataForm* form )
|
||||
{
|
||||
delete m_form;
|
||||
m_form = form;
|
||||
}
|
||||
|
||||
bool Disco::handleIq( const IQ& iq )
|
||||
{
|
||||
switch( iq.subtype() )
|
||||
{
|
||||
case IQ::Get:
|
||||
{
|
||||
IQ re( IQ::Result, iq.from(), iq.id() );
|
||||
re.setFrom( iq.to() );
|
||||
|
||||
const SoftwareVersion* sv = iq.findExtension<SoftwareVersion>( ExtVersion );
|
||||
if( sv )
|
||||
{
|
||||
re.addExtension( new SoftwareVersion( m_versionName, m_versionVersion, m_versionOs ) );
|
||||
m_parent->send( re );
|
||||
return true;
|
||||
}
|
||||
|
||||
const Info *info = iq.findExtension<Info>( ExtDiscoInfo );
|
||||
if( info )
|
||||
{
|
||||
Info *i = new Info( EmptyString, true );
|
||||
if( !info->node().empty() )
|
||||
{
|
||||
i->setNode( info->node() );
|
||||
IdentityList identities;
|
||||
StringList features;
|
||||
DiscoNodeHandlerMap::const_iterator it = m_nodeHandlers.find( info->node() );
|
||||
if( it == m_nodeHandlers.end() )
|
||||
{
|
||||
delete i;
|
||||
IQ re( IQ::Error, iq.from(), iq.id() );
|
||||
re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound ) );
|
||||
m_parent->send( re );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DiscoNodeHandlerList::const_iterator in = (*it).second.begin();
|
||||
for( ; in != (*it).second.end(); ++in )
|
||||
{
|
||||
IdentityList il = (*in)->handleDiscoNodeIdentities( iq.from(), info->node() );
|
||||
il.sort(); // needed on win32
|
||||
identities.merge( il );
|
||||
StringList fl = (*in)->handleDiscoNodeFeatures( iq.from(), info->node() );
|
||||
fl.sort(); // needed on win32
|
||||
features.merge( fl );
|
||||
}
|
||||
}
|
||||
i->setIdentities( identities );
|
||||
i->setFeatures( features );
|
||||
}
|
||||
else
|
||||
{
|
||||
IdentityList il;
|
||||
IdentityList::const_iterator it = m_identities.begin();
|
||||
for( ; it != m_identities.end(); ++it )
|
||||
{
|
||||
il.push_back( new Identity( *(*it) ) );
|
||||
}
|
||||
i->setIdentities( il );
|
||||
i->setFeatures( m_features );
|
||||
if( m_form )
|
||||
i->setForm( new DataForm( *m_form ) );
|
||||
}
|
||||
|
||||
re.addExtension( i );
|
||||
m_parent->send( re );
|
||||
return true;
|
||||
}
|
||||
|
||||
const Items *items = iq.findExtension<Items>( ExtDiscoItems );
|
||||
if( items )
|
||||
{
|
||||
Items *i = new Items( items->node() );
|
||||
if( !items->node().empty() )
|
||||
{
|
||||
DiscoNodeHandlerMap::const_iterator it = m_nodeHandlers.find( items->node() );
|
||||
if( it == m_nodeHandlers.end() )
|
||||
{
|
||||
delete i;
|
||||
IQ re( IQ::Error, iq.from(), iq.id() );
|
||||
re.addExtension( new Error( StanzaErrorTypeCancel, StanzaErrorItemNotFound ) );
|
||||
m_parent->send( re );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ItemList itemlist;
|
||||
DiscoNodeHandlerList::const_iterator in = (*it).second.begin();
|
||||
for( ; in != (*it).second.end(); ++in )
|
||||
{
|
||||
ItemList il = (*in)->handleDiscoNodeItems( iq.from(), iq.to(), items->node() );
|
||||
il.sort(); // needed on win32
|
||||
itemlist.merge( il );
|
||||
}
|
||||
i->setItems( itemlist );
|
||||
}
|
||||
}
|
||||
|
||||
re.addExtension( i );
|
||||
m_parent->send( re );
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case IQ::Set:
|
||||
{
|
||||
bool res = false;
|
||||
DiscoHandlerList::const_iterator it = m_discoHandlers.begin();
|
||||
for( ; it != m_discoHandlers.end(); ++it )
|
||||
{
|
||||
if( (*it)->handleDiscoSet( iq ) )
|
||||
res = true;
|
||||
}
|
||||
return res;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Disco::handleIqID( const IQ& iq, int context )
|
||||
{
|
||||
DiscoHandlerMap::iterator it = m_track.find( iq.id() );
|
||||
if( it != m_track.end() && (*it).second.dh )
|
||||
{
|
||||
switch( iq.subtype() )
|
||||
{
|
||||
case IQ::Result:
|
||||
switch( context )
|
||||
{
|
||||
case GetDiscoInfo:
|
||||
{
|
||||
const Info* di = iq.findExtension<Info>( ExtDiscoInfo );
|
||||
if( di )
|
||||
(*it).second.dh->handleDiscoInfo( iq.from(), *di, (*it).second.context );
|
||||
break;
|
||||
}
|
||||
case GetDiscoItems:
|
||||
{
|
||||
const Items* di = iq.findExtension<Items>( ExtDiscoItems );
|
||||
if( di )
|
||||
(*it).second.dh->handleDiscoItems( iq.from(), *di, (*it).second.context );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IQ::Error:
|
||||
{
|
||||
(*it).second.dh->handleDiscoError( iq.from(), iq.error(), (*it).second.context );
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_track.erase( it );
|
||||
}
|
||||
}
|
||||
|
||||
void Disco::getDisco( const JID& to, const std::string& node, DiscoHandler* dh, int context,
|
||||
IdType idType, const std::string& tid )
|
||||
{
|
||||
const std::string& id = tid.empty() ? m_parent->getID() : tid;
|
||||
|
||||
IQ iq( IQ::Get, to, id );
|
||||
if( idType == GetDiscoInfo )
|
||||
iq.addExtension( new Info( node ) );
|
||||
else
|
||||
iq.addExtension( new Items( node ) );
|
||||
|
||||
DiscoHandlerContext ct;
|
||||
ct.dh = dh;
|
||||
ct.context = context;
|
||||
m_track[id] = ct;
|
||||
m_parent->send( iq, this, idType );
|
||||
}
|
||||
|
||||
void Disco::setVersion( const std::string& name, const std::string& version, const std::string& os )
|
||||
{
|
||||
m_versionName = name;
|
||||
m_versionVersion = version;
|
||||
m_versionOs = os;
|
||||
}
|
||||
|
||||
void Disco::setIdentity( const std::string& category, const std::string& type,
|
||||
const std::string& name )
|
||||
{
|
||||
util::clearList( m_identities );
|
||||
addIdentity( category, type, name );
|
||||
}
|
||||
|
||||
void Disco::removeDiscoHandler( DiscoHandler* dh )
|
||||
{
|
||||
m_discoHandlers.remove( dh );
|
||||
DiscoHandlerMap::iterator t;
|
||||
DiscoHandlerMap::iterator it = m_track.begin();
|
||||
while( it != m_track.end() )
|
||||
{
|
||||
t = it;
|
||||
++it;
|
||||
if( dh == (*t).second.dh )
|
||||
{
|
||||
m_track.erase( t );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Disco::registerNodeHandler( DiscoNodeHandler* nh, const std::string& node )
|
||||
{
|
||||
m_nodeHandlers[node].push_back( nh );
|
||||
}
|
||||
|
||||
void Disco::removeNodeHandler( DiscoNodeHandler* nh, const std::string& node )
|
||||
{
|
||||
DiscoNodeHandlerMap::iterator it = m_nodeHandlers.find( node );
|
||||
if( it != m_nodeHandlers.end() )
|
||||
{
|
||||
(*it).second.remove( nh );
|
||||
if( (*it).second.empty() )
|
||||
m_nodeHandlers.erase( it );
|
||||
}
|
||||
}
|
||||
|
||||
void Disco::removeNodeHandlers( DiscoNodeHandler* nh )
|
||||
{
|
||||
DiscoNodeHandlerMap::iterator it = m_nodeHandlers.begin();
|
||||
DiscoNodeHandlerMap::iterator it2;
|
||||
while( it != m_nodeHandlers.end() )
|
||||
{
|
||||
it2 = it++;
|
||||
removeNodeHandler( nh, (*it2).first );
|
||||
}
|
||||
}
|
||||
|
||||
const StringList Disco::features( bool defaultFeatures ) const
|
||||
{
|
||||
StringList f = m_features;
|
||||
if( defaultFeatures )
|
||||
{
|
||||
f.push_back( XMLNS_DISCO_INFO );
|
||||
f.push_back( XMLNS_DISCO_ITEMS );
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,636 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 DISCO_H__
|
||||
#define DISCO_H__
|
||||
|
||||
#include "gloox.h"
|
||||
|
||||
#include "iqhandler.h"
|
||||
#include "jid.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class ClientBase;
|
||||
class DataForm;
|
||||
class DiscoHandler;
|
||||
class DiscoNodeHandler;
|
||||
class IQ;
|
||||
|
||||
/**
|
||||
* @brief This class implements @xep{0030} (Service Discovery) and @xep{0092} (Software Version).
|
||||
*
|
||||
* ClientBase will automatically instantiate a Disco object. It can be used to
|
||||
* announce special features of your client, or its version, or...
|
||||
*
|
||||
* XEP version: 2.2
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
*/
|
||||
class GLOOX_API Disco : public IqHandler
|
||||
{
|
||||
friend class ClientBase;
|
||||
|
||||
public:
|
||||
|
||||
class Identity; // declared below class Info
|
||||
|
||||
/**
|
||||
* A list of pointers to Identity objects. Used with Disco::Info.
|
||||
*/
|
||||
typedef std::list<Identity*> IdentityList;
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a Disco Info element (from Service Discovery, @xep{0030})
|
||||
* as a StanzaExtension.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Info : public StanzaExtension
|
||||
{
|
||||
friend class Disco;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Returns the queried node identifier, if any.
|
||||
* @return The node identifier. May be empty.
|
||||
*/
|
||||
const std::string& node() const { return m_node; }
|
||||
|
||||
/**
|
||||
* Returns the entity's supported features.
|
||||
* @return A list of supported features/namespaces.
|
||||
*/
|
||||
const StringList& features() const { return m_features; }
|
||||
|
||||
/**
|
||||
* Use this function to check if the entity the Info came from supports agiven feature.
|
||||
* @param feature The feature to check for.
|
||||
* @return @b True if the entity announces support for the feature, @b false otherwise.
|
||||
*/
|
||||
bool hasFeature( const std::string& feature ) const;
|
||||
|
||||
/**
|
||||
* Returns the entity's identities.
|
||||
* @return A list of pointers to Identity objects.
|
||||
*/
|
||||
const IdentityList& identities() const { return m_identities; }
|
||||
|
||||
/**
|
||||
* Returns an optionally included data form. This is used by e.g. MUC (@xep{0045}).
|
||||
* @return An optional data form included in the disco#info. May be 0.
|
||||
*/
|
||||
const DataForm* form() const { return m_form; }
|
||||
|
||||
/**
|
||||
* Adds an optional DataForm, e.g. for @xep{0232}. Only one form can be added
|
||||
* at this point.
|
||||
* @param form An optional DataForm to include in the Info reply.
|
||||
* The form will be owned by and deleted on destruction of the Info object.
|
||||
* @note If called more than once the previously set form will be deleted.
|
||||
*/
|
||||
void setForm( DataForm* form );
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Info( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new Info( *this );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
private:
|
||||
#ifdef DISCO_INFO_TEST
|
||||
public:
|
||||
#endif
|
||||
/**
|
||||
* Creates a empty Info object, suitable for making disco#info requests.
|
||||
* @param node The node identifier to query (optional).
|
||||
* @param defaultFeatures Indicates whether or not the default features should be
|
||||
* included in the Info. Should be @b false for requests, @b true for replies.
|
||||
* Defaults to @b false.
|
||||
*/
|
||||
Info( const std::string& node = EmptyString, bool defaultFeatures = false );
|
||||
|
||||
/**
|
||||
* Creates an Info object from the given Tag.
|
||||
* @param tag A <query> tag in the disco#info namespace, (possibly) containing
|
||||
* a disco#info reply.
|
||||
*/
|
||||
Info( const Tag* tag );
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
* @param info An Info object to copy.
|
||||
*/
|
||||
Info( const Info& info );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Info();
|
||||
|
||||
/**
|
||||
* Sets the current info node.
|
||||
* @param node The info node.
|
||||
*/
|
||||
void setNode( const std::string& node ) { m_node = node; }
|
||||
|
||||
/**
|
||||
* This function can be used to set the entity's features.
|
||||
* @param features A list of supported features/namespaces.
|
||||
*/
|
||||
void setFeatures( const StringList& features )
|
||||
{
|
||||
StringList fl( features );
|
||||
fl.sort(); // needed on win32
|
||||
m_features.merge( fl );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function can be used to set the entity's identities.
|
||||
* @param identities A list of pointers to the entity's identities.
|
||||
* @note The Identity objects pointed to will be owned by the Info object. The
|
||||
* list should neither be used again nor should the Identity objects be deleted.
|
||||
*/
|
||||
void setIdentities( const IdentityList& identities ) { m_identities = identities; }
|
||||
|
||||
std::string m_node;
|
||||
StringList m_features;
|
||||
IdentityList m_identities;
|
||||
DataForm* m_form;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a Disco identity (Service Discovery, @xep{0030}).
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Identity
|
||||
{
|
||||
friend class Info;
|
||||
friend class Disco;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a Disco Identity from a category, type and name.
|
||||
* See http://www.xmpp.org/registrar/disco-categories.html for more info.
|
||||
* @param category The identity's category.
|
||||
* @param type The identity's type.
|
||||
* @param name The identity's name.
|
||||
*/
|
||||
Identity( const std::string& category,
|
||||
const std::string& type,
|
||||
const std::string& name );
|
||||
|
||||
/**
|
||||
* Copy Contructor.
|
||||
* @param id An Identity to create a new Identity object from.
|
||||
*/
|
||||
Identity( const Identity& id );
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Identity();
|
||||
|
||||
/**
|
||||
* Returns the identity's category.
|
||||
* @return The identity's category.
|
||||
*/
|
||||
const std::string& category() const { return m_category; }
|
||||
|
||||
/**
|
||||
* Returns the identity's type.
|
||||
* @return The identity's type.
|
||||
*/
|
||||
const std::string& type() const { return m_type; }
|
||||
|
||||
/**
|
||||
* Returns the identity's name.
|
||||
* @return The identity's name.
|
||||
*/
|
||||
const std::string& name() const { return m_name; }
|
||||
|
||||
/**
|
||||
* Creates and returns a Tag representation of this identity.
|
||||
* @return A Tag, or 0.
|
||||
*/
|
||||
Tag* tag() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Creates a Disco Identity from the given Tag.
|
||||
* @param tag A Tag representation of a disco identity.
|
||||
*/
|
||||
Identity( const Tag* tag );
|
||||
|
||||
std::string m_category; /**< The identity's category. */
|
||||
std::string m_type; /**< The identity's type. */
|
||||
std::string m_name; /**< The identity's name. */
|
||||
|
||||
};
|
||||
|
||||
class Item; // declared below class Items
|
||||
|
||||
/**
|
||||
* A list of pointers to Item objects. Used with Disco::Items.
|
||||
*/
|
||||
typedef std::list<Item*> ItemList;
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a Disco query element (from Service Discovery, @xep{0030})
|
||||
* in the disco#items namespace, implemented as a StanzaExtension.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Items : public StanzaExtension
|
||||
{
|
||||
friend class Disco;
|
||||
|
||||
public:
|
||||
// This needs to be public so one can proactively send a list of adhoc commands
|
||||
// see @xep{0050}
|
||||
/**
|
||||
* Creates an empty Items object, suitable for making disco#items requests.
|
||||
* @param node The node identifier to query (optional).
|
||||
*/
|
||||
Items( const std::string& node = EmptyString );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Items();
|
||||
|
||||
/**
|
||||
* This function can be used to set the entity's/node's items.
|
||||
* @param items A list of pointers to the entity's/node's items.
|
||||
* @note The Item objects pointed to will be owned by the Items object. The
|
||||
* list should neither be used again nor should the Item objects be deleted.
|
||||
*/
|
||||
void setItems( const ItemList& items );
|
||||
|
||||
/**
|
||||
* Returns the queried node identifier, if any.
|
||||
* @return The node identifier. May be empty.
|
||||
*/
|
||||
const std::string& node() const { return m_node; }
|
||||
|
||||
/**
|
||||
* Returns the entity's/node's items.
|
||||
* @return A list of pointers to Item objects.
|
||||
*/
|
||||
const ItemList& items() const { return m_items; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Items( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new Items( *this );
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef DISCO_ITEMS_TEST
|
||||
public:
|
||||
#endif
|
||||
/**
|
||||
* Creates an Items object from the given Tag.
|
||||
* @param tag A <query> tag in the disco#items namespace, (possibly) containing
|
||||
* a disco#items reply.
|
||||
*/
|
||||
Items( const Tag* tag );
|
||||
|
||||
std::string m_node;
|
||||
ItemList m_items;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief An abstraction of a Disco item (Service Discovery, @xep{0030}).
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Item
|
||||
{
|
||||
friend class Items;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a Disco Item from a JID, node and name.
|
||||
* @param jid The item's JID.
|
||||
* @param node The item's type.
|
||||
* @param name The item's name.
|
||||
*/
|
||||
Item( const JID& jid,
|
||||
const std::string& node,
|
||||
const std::string& name )
|
||||
: m_jid( jid ), m_node( node ), m_name( name ) {}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~Item() {}
|
||||
|
||||
/**
|
||||
* Returns the item's JID.
|
||||
* @return The item's JID.
|
||||
*/
|
||||
const JID& jid() const { return m_jid; }
|
||||
|
||||
/**
|
||||
* Returns the item's node.
|
||||
* @return The item's node.
|
||||
*/
|
||||
const std::string& node() const { return m_node; }
|
||||
|
||||
/**
|
||||
* Returns the item's name.
|
||||
* @return The item's name.
|
||||
*/
|
||||
const std::string& name() const { return m_name; }
|
||||
|
||||
/**
|
||||
* Creates and returns a Tag representation of this item.
|
||||
* @return A Tag, or 0.
|
||||
*/
|
||||
Tag* tag() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Creates a Disco Item from the given Tag.
|
||||
* @param tag A Tag representation of a Disco item.
|
||||
*/
|
||||
Item( const Tag* tag );
|
||||
|
||||
JID m_jid; /**< The item's jid. */
|
||||
std::string m_node; /**< The item's type. */
|
||||
std::string m_name; /**< The item's name. */
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a feature to the list of supported Jabber features.
|
||||
* The list will be posted as an answer to IQ queries in the
|
||||
* "http://jabber.org/protocol/disco#info" namespace.
|
||||
* These IQ packets will also be forwarded to the
|
||||
* application's IqHandler, if it listens to the @c disco\#info namespace.
|
||||
* By default, disco(very) queries are handled by the library.
|
||||
* By default, all supported, not disabled features are announced.
|
||||
* @param feature A feature (namespace) the host app supports.
|
||||
* @note Use this function for non-queryable features. For nodes that shall
|
||||
* answer to @c disco\#info queries, use registerNodeHandler().
|
||||
*/
|
||||
void addFeature( const std::string& feature )
|
||||
{ m_features.push_back( feature ); }
|
||||
|
||||
/**
|
||||
* Removes the given feature from the list of advertised client features.
|
||||
* @param feature The feature to remove.
|
||||
* @since 0.9
|
||||
*/
|
||||
void removeFeature( const std::string& feature )
|
||||
{ m_features.remove( feature ); }
|
||||
|
||||
/**
|
||||
* Lets you retrieve the features this Disco instance supports.
|
||||
* @param defaultFeatures Include default features. Defaults to @b false.
|
||||
* @return A list of supported features/namespaces.
|
||||
*/
|
||||
const StringList features( bool defaultFeatures = false ) const;
|
||||
|
||||
/**
|
||||
* Queries the given JID for general infomation according to
|
||||
* @xep{0030} (Service Discovery).
|
||||
* To receive the results inherit from DiscoHandler and register with the Disco object.
|
||||
* @param to The destination-JID of the query.
|
||||
* @param node An optional node to query. Not inserted if empty.
|
||||
* @param dh The DiscoHandler to notify about results.
|
||||
* @param context A context identifier.
|
||||
* @param tid An optional id that is going to be used as the IQ request's id. Only
|
||||
* necessary if you need to know the request's id.
|
||||
*/
|
||||
void getDiscoInfo( const JID& to, const std::string& node, DiscoHandler* dh, int context,
|
||||
const std::string& tid = EmptyString )
|
||||
{ getDisco( to, node, dh, context, GetDiscoInfo, tid ); }
|
||||
|
||||
/**
|
||||
* Queries the given JID for its items according to
|
||||
* @xep{0030} (Service Discovery).
|
||||
* To receive the results inherit from DiscoHandler and register with the Disco object.
|
||||
* @param to The destination-JID of the query.
|
||||
* @param node An optional node to query. Not inserted if empty.
|
||||
* @param dh The DiscoHandler to notify about results.
|
||||
* @param context A context identifier.
|
||||
* @param tid An optional id that is going to be used as the IQ request's id. Only
|
||||
* necessary if you need to know the request's id.
|
||||
*/
|
||||
void getDiscoItems( const JID& to, const std::string& node, DiscoHandler* dh, int context,
|
||||
const std::string& tid = EmptyString )
|
||||
{ getDisco( to, node, dh, context, GetDiscoItems, tid ); }
|
||||
|
||||
/**
|
||||
* Sets the version of the host application using this library.
|
||||
* The library takes care of jabber:iq:version requests. These
|
||||
* IQ packets will not be forwarded to the IqHandlers.
|
||||
* @param name The name to be returned to inquiring clients.
|
||||
* @param version The version to be returned to inquiring clients.
|
||||
* @param os The operating system to announce. Default: don't include.
|
||||
*/
|
||||
void setVersion( const std::string& name, const std::string& version,
|
||||
const std::string& os = EmptyString );
|
||||
|
||||
/**
|
||||
* Returns the application's advertised name.
|
||||
* @return The application's advertised name.
|
||||
*/
|
||||
const std::string& name() const { return m_versionName; }
|
||||
|
||||
/**
|
||||
* Returns the application's advertised version.
|
||||
* @return The application's advertised version.
|
||||
*/
|
||||
const std::string& version() const { return m_versionVersion; }
|
||||
|
||||
/**
|
||||
* Returns the application's advertised operating system.
|
||||
* @return The application's advertised operating system.
|
||||
*/
|
||||
const std::string& os() const { return m_versionOs; }
|
||||
|
||||
/**
|
||||
* Sets the identity of this entity.
|
||||
* The library uses this information to answer disco#info requests
|
||||
* with a correct identity.
|
||||
* @xep{0030} requires an entity to have at least one identity. See @xep{0030}
|
||||
* for more information on categories and types.
|
||||
* @param category The entity category of this client. Default: client. May not be empty.
|
||||
* @param type The type of this entity. Default: bot. May not be empty.
|
||||
* @param name The name of the entity. Default: empty.
|
||||
* @note An entity can have more than one identity. You cann add more identities
|
||||
* using addIdentity(). A call to setIdentity() will clear the list of identities
|
||||
* and, after that, add the new identity given by the arguments to setIdentity().
|
||||
*/
|
||||
void setIdentity( const std::string& category, const std::string& type,
|
||||
const std::string& name = EmptyString );
|
||||
|
||||
/**
|
||||
* Adds another identity to the list of identities.
|
||||
* @param category The entity category of this client. Default: client. May not be empty.
|
||||
* @param type The type of this entity. Default: bot. May not be empty.
|
||||
* @param name The name of the entity. Default: empty.
|
||||
*/
|
||||
void addIdentity( const std::string& category, const std::string& type,
|
||||
const std::string& name = EmptyString )
|
||||
{ m_identities.push_back( new Identity( category, type, name ) ); }
|
||||
|
||||
/**
|
||||
* Returns the entity's identities.
|
||||
* @return The entity's identities.
|
||||
*/
|
||||
const IdentityList& identities() const { return m_identities; }
|
||||
|
||||
/**
|
||||
* Adds an optional DataForm to Disco:Info replies, e.g. for @xep{0232}.
|
||||
* Only one form can be added at this point.
|
||||
* @param form An optional DataForm to include in the Info reply.
|
||||
* The form will be owned by and deleted on destruction of the Disco object.
|
||||
* @note If called more than once the previously set form will be deleted.
|
||||
*/
|
||||
void setForm( DataForm* form );
|
||||
|
||||
/**
|
||||
* Returns the DataForm set by setForm(). Used by Capabilities.
|
||||
* @return The DataForm, or 0.
|
||||
*/
|
||||
const DataForm* form() const { return m_form; }
|
||||
|
||||
/**
|
||||
* Use this function to register an @ref DiscoHandler with the Disco
|
||||
* object. This is only necessary if you want to receive Disco-set requests. Else
|
||||
* a one-time registration happens when calling getDiscoInfo() and getDiscoItems(), respectively.
|
||||
* @param dh The DiscoHandler-derived object to register.
|
||||
*/
|
||||
void registerDiscoHandler( DiscoHandler* dh )
|
||||
{ m_discoHandlers.push_back( dh ); }
|
||||
|
||||
/**
|
||||
* Unregisters the given DiscoHandler.
|
||||
* @param dh The DiscoHandler to unregister.
|
||||
*/
|
||||
void removeDiscoHandler( DiscoHandler* dh );
|
||||
|
||||
/**
|
||||
* Use this function to register a @ref DiscoNodeHandler with the Disco
|
||||
* object. The DiscoNodeHandler will receive disco#items queries which are
|
||||
* directed to the corresponding node registered for the handler.
|
||||
* @param nh The NodeHandler-derived object to register.
|
||||
* @param node The node name to associate with this handler. Use an empty string to
|
||||
* register for the root node.
|
||||
*/
|
||||
void registerNodeHandler( DiscoNodeHandler* nh, const std::string& node );
|
||||
|
||||
/**
|
||||
* Removes the node handler for the given node.
|
||||
* @param nh The NodeHandler to unregister.
|
||||
* @param node The node for which the handler shall be removed. Use an empty string to
|
||||
* remove the root node's handler.
|
||||
*/
|
||||
void removeNodeHandler( DiscoNodeHandler* nh, const std::string& node );
|
||||
|
||||
/**
|
||||
* Removes all registered nodes of the given node handler.
|
||||
* @param nh The NodeHandler to unregister.
|
||||
*/
|
||||
void removeNodeHandlers( DiscoNodeHandler* nh );
|
||||
|
||||
// reimplemented from IqHandler.
|
||||
virtual bool handleIq( const IQ& iq );
|
||||
|
||||
// reimplemented from IqHandler.
|
||||
virtual void handleIqID( const IQ& iq, int context );
|
||||
|
||||
private:
|
||||
#ifdef DISCO_TEST
|
||||
public:
|
||||
#endif
|
||||
Disco( ClientBase* parent );
|
||||
virtual ~Disco();
|
||||
|
||||
enum IdType
|
||||
{
|
||||
GetDiscoInfo,
|
||||
GetDiscoItems
|
||||
};
|
||||
|
||||
void getDisco( const JID& to, const std::string& node, DiscoHandler* dh,
|
||||
int context, IdType idType, const std::string& tid );
|
||||
|
||||
struct DiscoHandlerContext
|
||||
{
|
||||
DiscoHandler* dh;
|
||||
int context;
|
||||
};
|
||||
|
||||
ClientBase* m_parent;
|
||||
|
||||
typedef std::list<DiscoHandler*> DiscoHandlerList;
|
||||
typedef std::list<DiscoNodeHandler*> DiscoNodeHandlerList;
|
||||
typedef std::map<std::string, DiscoNodeHandlerList> DiscoNodeHandlerMap;
|
||||
typedef std::map<std::string, DiscoHandlerContext> DiscoHandlerMap;
|
||||
|
||||
DiscoHandlerList m_discoHandlers;
|
||||
DiscoNodeHandlerMap m_nodeHandlers;
|
||||
DiscoHandlerMap m_track;
|
||||
IdentityList m_identities;
|
||||
StringList m_features;
|
||||
StringMap m_queryIDs;
|
||||
DataForm* m_form;
|
||||
|
||||
std::string m_versionName;
|
||||
std::string m_versionVersion;
|
||||
std::string m_versionOs;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DISCO_H__
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 DISCOHANDLER_H__
|
||||
#define DISCOHANDLER_H__
|
||||
|
||||
#include "macros.h"
|
||||
#include "disco.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class IQ;
|
||||
|
||||
/**
|
||||
* @brief A virtual interface that enables objects to receive Service Discovery (@xep{0030}) events.
|
||||
*
|
||||
* A class implementing this interface can receive the results of sent disco queries.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
*/
|
||||
class GLOOX_API DiscoHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~DiscoHandler() {}
|
||||
|
||||
/**
|
||||
* Reimplement this function if you want to be notified about the result
|
||||
* of an disco#info query.
|
||||
* @param from The sender of the disco#info result.
|
||||
* @param info The Info.
|
||||
* @param context A context identifier.
|
||||
* @since 1.0
|
||||
*/
|
||||
virtual void handleDiscoInfo( const JID& from, const Disco::Info& info, int context ) = 0;
|
||||
|
||||
/**
|
||||
* Reimplement this function if you want to be notified about the result
|
||||
* of a disco#items query.
|
||||
* @param from The sender of the disco#items result.
|
||||
* @param items The Items.
|
||||
* @param context A context identifier.
|
||||
* @since 1.0
|
||||
*/
|
||||
virtual void handleDiscoItems( const JID& from, const Disco::Items& items, int context ) = 0;
|
||||
|
||||
/**
|
||||
* Reimplement this function to receive disco error notifications.
|
||||
* @param from The sender of the error result.
|
||||
* @param error The Error. May be 0.
|
||||
* @param context A context identifier.
|
||||
* @since 1.0
|
||||
*/
|
||||
virtual void handleDiscoError( const JID& from, const Error* error, int context ) = 0;
|
||||
|
||||
/**
|
||||
* Reimplement this function to receive notifications about incoming IQ
|
||||
* stanzas of type 'set' in the disco namespace.
|
||||
* @param iq The full IQ.
|
||||
* @return Returns @b true if the stanza was handled and answered, @b false otherwise.
|
||||
*/
|
||||
virtual bool handleDiscoSet( const IQ& iq ) { (void)iq; return false; }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DISCOHANDLER_H__
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2004-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 DISCONODEHANDLER_H__
|
||||
#define DISCONODEHANDLER_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "disco.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Derived classes can be registered as NodeHandlers for certain nodes with the Disco object.
|
||||
*
|
||||
* Incoming disco#info and disco#items queries are delegated to their respective handlers.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
*/
|
||||
class GLOOX_API DiscoNodeHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~DiscoNodeHandler() {}
|
||||
|
||||
/**
|
||||
* In addition to @c handleDiscoNodeIdentities, this function is used to gather
|
||||
* more information on a specific node. It is called when a disco#info query
|
||||
* arrives with a node attribute that matches the one registered for this handler.
|
||||
* @param from The sender of the request.
|
||||
* @param node The node this handler is supposed to handle.
|
||||
* @return A list of features supported by this node.
|
||||
*/
|
||||
virtual StringList handleDiscoNodeFeatures( const JID& from, const std::string& node ) = 0;
|
||||
|
||||
/**
|
||||
* In addition to @c handleDiscoNodeFeatures, this function is used to gather
|
||||
* more information on a specific node. It is called when a disco#info query
|
||||
* arrives with a node attribute that matches the one registered for this handler.
|
||||
* @param from The sender of the request.
|
||||
* @param node The node this handler is supposed to handle.
|
||||
* @return A list of identities for the given node. The caller will own the identities.
|
||||
*/
|
||||
virtual Disco::IdentityList handleDiscoNodeIdentities( const JID& from,
|
||||
const std::string& node ) = 0;
|
||||
|
||||
/**
|
||||
* This function is used to gather more information on a specific node.
|
||||
* It is called when a disco#items query arrives with a node attribute that
|
||||
* matches the one registered for this handler. If node is empty, items for the
|
||||
* root node (no node) shall be returned.
|
||||
* @param from The sender of the request.
|
||||
* @param to The receiving JID (useful for transports).
|
||||
* @param node The node this handler is supposed to handle.
|
||||
* @return A list of items supported by this node.
|
||||
*/
|
||||
virtual Disco::ItemList handleDiscoNodeItems( const JID& from, const JID& to,
|
||||
const std::string& node = EmptyString ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DISCONODEHANDLER_H__
|
|
@ -1,498 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "config.h"
|
||||
|
||||
#include "gloox.h"
|
||||
#include "dns.h"
|
||||
#include "util.h"
|
||||
|
||||
#ifndef _WIN32_WCE
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if ( !defined( _WIN32 ) && !defined( _WIN32_WCE ) ) || defined( __SYMBIAN32__ )
|
||||
# include <netinet/in.h>
|
||||
# include <arpa/nameser.h>
|
||||
# include <resolv.h>
|
||||
# include <netdb.h>
|
||||
# include <arpa/inet.h>
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
# include <unistd.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
# include <winsock.h>
|
||||
#elif defined( _WIN32_WCE )
|
||||
# include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_WINDNS_H
|
||||
# include <windns.h>
|
||||
#endif
|
||||
|
||||
#if defined(__HAIKU__)
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#define SRV_COST (RRFIXEDSZ+0)
|
||||
#define SRV_WEIGHT (RRFIXEDSZ+2)
|
||||
#define SRV_PORT (RRFIXEDSZ+4)
|
||||
#define SRV_SERVER (RRFIXEDSZ+6)
|
||||
#define SRV_FIXEDSZ (RRFIXEDSZ+6)
|
||||
|
||||
#ifndef T_SRV
|
||||
# define T_SRV 33
|
||||
#endif
|
||||
|
||||
// mingw
|
||||
#ifndef DNS_TYPE_SRV
|
||||
# define DNS_TYPE_SRV 33
|
||||
#endif
|
||||
|
||||
#ifndef NS_CMPRSFLGS
|
||||
# define NS_CMPRSFLGS 0xc0
|
||||
#endif
|
||||
|
||||
#ifndef C_IN
|
||||
# define C_IN 1
|
||||
#endif
|
||||
|
||||
#ifndef INVALID_SOCKET
|
||||
# define INVALID_SOCKET -1
|
||||
#endif
|
||||
|
||||
#define XMPP_PORT 5222
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
#if defined( HAVE_RES_QUERYDOMAIN ) && defined( HAVE_DN_SKIPNAME ) && defined( HAVE_RES_QUERY )
|
||||
DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto,
|
||||
const std::string& domain, const LogSink& logInstance )
|
||||
{
|
||||
buffer srvbuf;
|
||||
bool error = false;
|
||||
|
||||
const std::string dname = "_" + service + "._" + proto;
|
||||
|
||||
if( !domain.empty() )
|
||||
srvbuf.len = res_querydomain( dname.c_str(), const_cast<char*>( domain.c_str() ),
|
||||
C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
|
||||
else
|
||||
srvbuf.len = res_query( dname.c_str(), C_IN, T_SRV, srvbuf.buf, NS_PACKETSZ );
|
||||
|
||||
if( srvbuf.len < 0 )
|
||||
return defaultHostMap( domain, logInstance );
|
||||
|
||||
HEADER* hdr = (HEADER*)srvbuf.buf;
|
||||
unsigned char* here = srvbuf.buf + NS_HFIXEDSZ;
|
||||
|
||||
if( srvbuf.len < NS_HFIXEDSZ )
|
||||
error = true;
|
||||
|
||||
if( hdr->rcode >= 1 && hdr->rcode <= 5 )
|
||||
error = true;
|
||||
|
||||
if( ntohs( hdr->ancount ) == 0 )
|
||||
error = true;
|
||||
|
||||
if( ntohs( hdr->ancount ) > NS_PACKETSZ )
|
||||
error = true;
|
||||
|
||||
int cnt;
|
||||
for( cnt = ntohs( hdr->qdcount ); cnt > 0; --cnt )
|
||||
{
|
||||
int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
|
||||
here += strlen + NS_QFIXEDSZ;
|
||||
}
|
||||
|
||||
unsigned char* srv[NS_PACKETSZ];
|
||||
int srvnum = 0;
|
||||
for( cnt = ntohs( hdr->ancount ); cnt > 0; --cnt )
|
||||
{
|
||||
int strlen = dn_skipname( here, srvbuf.buf + srvbuf.len );
|
||||
here += strlen;
|
||||
srv[srvnum++] = here;
|
||||
here += SRV_FIXEDSZ;
|
||||
here += dn_skipname( here, srvbuf.buf + srvbuf.len );
|
||||
}
|
||||
|
||||
if( error )
|
||||
{
|
||||
return defaultHostMap( domain, logInstance );
|
||||
}
|
||||
|
||||
// (q)sort here
|
||||
|
||||
HostMap servers;
|
||||
for( cnt = 0; cnt < srvnum; ++cnt )
|
||||
{
|
||||
char srvname[NS_MAXDNAME];
|
||||
srvname[0] = '\0';
|
||||
|
||||
if( dn_expand( srvbuf.buf, srvbuf.buf + NS_PACKETSZ,
|
||||
srv[cnt] + SRV_SERVER, srvname, NS_MAXDNAME ) < 0
|
||||
|| !(*srvname) )
|
||||
continue;
|
||||
|
||||
unsigned char* c = srv[cnt] + SRV_PORT;
|
||||
servers.insert( std::make_pair( (char*)srvname, ntohs( c[1] << 8 | c[0] ) ) );
|
||||
}
|
||||
|
||||
if( !servers.size() )
|
||||
return defaultHostMap( domain, logInstance );
|
||||
|
||||
return servers;
|
||||
}
|
||||
|
||||
#elif defined( _WIN32 ) && defined( HAVE_WINDNS_H ) && !defined( __MINGW32__ )
|
||||
DNS::HostMap DNS::resolve( const std::string& service, const std::string& proto,
|
||||
const std::string& domain, const LogSink& logInstance )
|
||||
{
|
||||
const std::string dname = "_" + service + "._" + proto + "." + domain;
|
||||
bool error = false;
|
||||
|
||||
DNS::HostMap servers;
|
||||
DNS_RECORD* pRecord = NULL;
|
||||
DNS_STATUS status = DnsQuery_UTF8( dname.c_str(), DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &pRecord, NULL );
|
||||
if( status == ERROR_SUCCESS )
|
||||
{
|
||||
// NOTE: DnsQuery_UTF8 and DnsQuery_A really should have been defined with
|
||||
// PDNS_RECORDA instead of PDNS_RECORD, since that's what it is (even with _UNICODE defined).
|
||||
// We'll correct for that mistake with a cast.
|
||||
DNS_RECORDA* pRec = (DNS_RECORDA*)pRecord;
|
||||
do
|
||||
{
|
||||
if( pRec->wType == DNS_TYPE_SRV )
|
||||
{
|
||||
servers[pRec->Data.SRV.pNameTarget] = pRec->Data.SRV.wPort;
|
||||
}
|
||||
pRec = pRec->pNext;
|
||||
}
|
||||
while( pRec != NULL );
|
||||
DnsRecordListFree( pRecord, DnsFreeRecordList );
|
||||
}
|
||||
else
|
||||
{
|
||||
logInstance.warn( LogAreaClassDns, "DnsQuery_UTF8() failed: " + util::int2string( status ) );
|
||||
error = true;
|
||||
}
|
||||
|
||||
if( error || !servers.size() )
|
||||
{
|
||||
servers = defaultHostMap( domain, logInstance );
|
||||
}
|
||||
|
||||
return servers;
|
||||
}
|
||||
|
||||
#else
|
||||
DNS::HostMap DNS::resolve( const std::string& /*service*/, const std::string& /*proto*/,
|
||||
const std::string& domain, const LogSink& logInstance )
|
||||
{
|
||||
logInstance.warn( LogAreaClassDns, "Notice: gloox does not support SRV "
|
||||
"records on this platform. Using A records instead." );
|
||||
return defaultHostMap( domain, logInstance );
|
||||
}
|
||||
#endif
|
||||
|
||||
DNS::HostMap DNS::defaultHostMap( const std::string& domain, const LogSink& logInstance )
|
||||
{
|
||||
HostMap server;
|
||||
|
||||
logInstance.warn( LogAreaClassDns, "Notice: no SRV record found for "
|
||||
+ domain + ", using default port." );
|
||||
|
||||
if( !domain.empty() )
|
||||
server[domain] = XMPP_PORT;
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
void DNS::resolve( struct addrinfo** res, const std::string& service, const std::string& proto,
|
||||
const std::string& domain, const LogSink& logInstance )
|
||||
{
|
||||
logInstance.dbg( LogAreaClassDns, "Resolving: _" + service + "._" + proto + "." + domain );
|
||||
struct addrinfo hints;
|
||||
if( proto == "tcp" )
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
else if( proto == "udp" )
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
else
|
||||
{
|
||||
logInstance.err( LogAreaClassDns, "Unknown/Invalid protocol: " + proto );
|
||||
}
|
||||
memset( &hints, '\0', sizeof( hints ) );
|
||||
hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
int e = getaddrinfo( domain.c_str(), service.c_str(), &hints, res );
|
||||
if( e )
|
||||
logInstance.err( LogAreaClassDns, "getaddrinfo() failed" );
|
||||
}
|
||||
|
||||
int DNS::connect( const std::string& host, const LogSink& logInstance )
|
||||
{
|
||||
struct addrinfo* results = 0;
|
||||
|
||||
resolve( &results, host, logInstance );
|
||||
if( !results )
|
||||
{
|
||||
logInstance.err( LogAreaClassDns, "host not found: " + host );
|
||||
return -ConnDnsError;
|
||||
}
|
||||
|
||||
struct addrinfo* runp = results;
|
||||
while( runp )
|
||||
{
|
||||
int fd = DNS::connect( runp, logInstance );
|
||||
if( fd >= 0 )
|
||||
return fd;
|
||||
|
||||
runp = runp->ai_next;
|
||||
}
|
||||
|
||||
freeaddrinfo( results );
|
||||
|
||||
return -ConnConnectionRefused;
|
||||
}
|
||||
|
||||
int DNS::connect( struct addrinfo* res, const LogSink& logInstance )
|
||||
{
|
||||
if( !res )
|
||||
return -1;
|
||||
|
||||
int fd = getSocket( res->ai_family, res->ai_socktype, res->ai_protocol, logInstance );
|
||||
if( fd < 0 )
|
||||
return fd;
|
||||
|
||||
if( ::connect( fd, res->ai_addr, res->ai_addrlen ) == 0 )
|
||||
{
|
||||
char ip[NI_MAXHOST];
|
||||
char port[NI_MAXSERV];
|
||||
|
||||
if( getnameinfo( res->ai_addr, sizeof( sockaddr ),
|
||||
ip, sizeof( ip ),
|
||||
port, sizeof( port ),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV ) )
|
||||
{
|
||||
//FIXME do we need to handle this? How? Can it actually happen at all?
|
||||
// printf( "could not get numeric hostname");
|
||||
}
|
||||
|
||||
if( res->ai_canonname )
|
||||
logInstance.dbg( LogAreaClassDns, std::string( "Connecting to " ).append( res->ai_canonname ).append( " (" ).append( ip ).append( "), port " ).append( port ) );
|
||||
else
|
||||
logInstance.dbg( LogAreaClassDns, std::string( "Connecting to " ).append( ip ).append( ":" ).append( port ) );
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
std::string message = "connect() failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
|
||||
#else
|
||||
"errno: " + util::int2string( errno ) + ": " + strerror( errno );
|
||||
#endif
|
||||
logInstance.dbg( LogAreaClassDns, message );
|
||||
|
||||
closeSocket( fd, logInstance );
|
||||
return -ConnConnectionRefused;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int DNS::connect( const std::string& host, const LogSink& logInstance )
|
||||
{
|
||||
HostMap hosts = resolve( host, logInstance );
|
||||
if( hosts.size() == 0 )
|
||||
return -ConnDnsError;
|
||||
|
||||
HostMap::const_iterator it = hosts.begin();
|
||||
for( ; it != hosts.end(); ++it )
|
||||
{
|
||||
int fd = DNS::connect( (*it).first, (*it).second, logInstance );
|
||||
if( fd >= 0 )
|
||||
return fd;
|
||||
}
|
||||
|
||||
return -ConnConnectionRefused;
|
||||
}
|
||||
#endif
|
||||
|
||||
int DNS::getSocket( const LogSink& logInstance )
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
WSADATA wsaData;
|
||||
if( WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) != 0 )
|
||||
{
|
||||
logInstance.dbg( LogAreaClassDns, "WSAStartup() failed. WSAGetLastError: "
|
||||
+ util::int2string( ::WSAGetLastError() ) );
|
||||
return -ConnDnsError;
|
||||
}
|
||||
#endif
|
||||
|
||||
int protocol = IPPROTO_TCP;
|
||||
#if !defined( __APPLE__ ) // Sandboxing on Apple doesn't like you to use getprotobyname
|
||||
struct protoent* prot;
|
||||
if( ( prot = getprotobyname( "tcp" ) ) != 0 )
|
||||
{
|
||||
protocol = prot->p_proto;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string message = "getprotobyname( \"tcp\" ) failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() )
|
||||
#else
|
||||
"errno: " + util::int2string( errno ) + ": " + strerror( errno );
|
||||
#endif
|
||||
+ ". Falling back to IPPROTO_TCP: " + util::int2string( IPPROTO_TCP );
|
||||
logInstance.dbg( LogAreaClassDns, message );
|
||||
|
||||
// Do not return an error. We'll fall back to IPPROTO_TCP.
|
||||
}
|
||||
#endif // !defined( __APPLE__ )
|
||||
|
||||
return getSocket( PF_INET, SOCK_STREAM, protocol, logInstance );
|
||||
}
|
||||
|
||||
int DNS::getSocket( int af, int socktype, int proto, const LogSink& logInstance )
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
SOCKET fd;
|
||||
#else
|
||||
int fd;
|
||||
#endif
|
||||
if( ( fd = socket( af, socktype, proto ) ) == INVALID_SOCKET )
|
||||
{
|
||||
std::string message = "getSocket( "
|
||||
+ util::int2string( af ) + ", "
|
||||
+ util::int2string( socktype ) + ", "
|
||||
+ util::int2string( proto )
|
||||
+ " ) failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
|
||||
#else
|
||||
"errno: " + util::int2string( errno ) + ": " + strerror( errno );
|
||||
#endif
|
||||
logInstance.dbg( LogAreaClassDns, message );
|
||||
|
||||
cleanup( logInstance );
|
||||
return -ConnConnectionRefused;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SETSOCKOPT
|
||||
int timeout = 5000;
|
||||
int reuseaddr = 1;
|
||||
setsockopt( fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof( timeout ) );
|
||||
setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (char*)&reuseaddr, sizeof( reuseaddr ) );
|
||||
#endif
|
||||
|
||||
return (int)fd;
|
||||
}
|
||||
|
||||
int DNS::connect( const std::string& host, int port, const LogSink& logInstance )
|
||||
{
|
||||
int fd = getSocket( logInstance );
|
||||
if( fd < 0 )
|
||||
return fd;
|
||||
|
||||
struct hostent* h;
|
||||
if( ( h = gethostbyname( host.c_str() ) ) == 0 )
|
||||
{
|
||||
logInstance.dbg( LogAreaClassDns, "gethostbyname() failed for " + host + "." );
|
||||
cleanup( logInstance );
|
||||
closeSocket( fd, logInstance );
|
||||
return -ConnDnsError;
|
||||
}
|
||||
|
||||
struct sockaddr_in target;
|
||||
target.sin_family = AF_INET;
|
||||
target.sin_port = htons( static_cast<unsigned short int>( port ) );
|
||||
|
||||
if( h->h_length != sizeof( struct in_addr ) )
|
||||
{
|
||||
logInstance.dbg( LogAreaClassDns, "gethostbyname() returned unexpected structure." );
|
||||
cleanup( logInstance );
|
||||
closeSocket( fd, logInstance );
|
||||
return -ConnDnsError;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy( &target.sin_addr, h->h_addr, sizeof( struct in_addr ) );
|
||||
}
|
||||
|
||||
logInstance.dbg( LogAreaClassDns, "Connecting to " + host
|
||||
+ " (" + inet_ntoa( target.sin_addr ) + ":" + util::int2string( port ) + ")" );
|
||||
|
||||
memset( target.sin_zero, '\0', 8 );
|
||||
if( ::connect( fd, (struct sockaddr *)&target, sizeof( struct sockaddr ) ) == 0 )
|
||||
{
|
||||
logInstance.dbg( LogAreaClassDns, "Connected to " + host + " ("
|
||||
+ inet_ntoa( target.sin_addr ) + ":" + util::int2string( port ) + ")" );
|
||||
return fd;
|
||||
}
|
||||
|
||||
std::string message = "Connection to " + host + " ("
|
||||
+ inet_ntoa( target.sin_addr ) + ":" + util::int2string( port ) + ") failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
|
||||
#else
|
||||
"errno: " + util::int2string( errno ) + ": " + strerror( errno );
|
||||
#endif
|
||||
logInstance.dbg( LogAreaClassDns, message );
|
||||
|
||||
closeSocket( fd, logInstance );
|
||||
return -ConnConnectionRefused;
|
||||
}
|
||||
|
||||
void DNS::closeSocket( int fd, const LogSink& logInstance )
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
int result = closesocket( fd );
|
||||
#else
|
||||
int result = close( fd );
|
||||
#endif
|
||||
|
||||
if( result != 0 )
|
||||
{
|
||||
std::string message = "closeSocket() failed. "
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
"WSAGetLastError: " + util::int2string( ::WSAGetLastError() );
|
||||
#else
|
||||
"errno: " + util::int2string( errno ) + ": " + strerror( errno );
|
||||
#endif
|
||||
logInstance.dbg( LogAreaClassDns, message );
|
||||
}
|
||||
}
|
||||
|
||||
void DNS::cleanup( const LogSink& logInstance )
|
||||
{
|
||||
#if defined( _WIN32 ) && !defined( __SYMBIAN32__ )
|
||||
if( WSACleanup() != 0 )
|
||||
{
|
||||
logInstance.dbg( LogAreaClassDns, "WSACleanup() failed. WSAGetLastError: "
|
||||
+ util::int2string( ::WSAGetLastError() ) );
|
||||
}
|
||||
#else
|
||||
(void)logInstance;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 DNS_H__
|
||||
#define DNS_H__
|
||||
|
||||
#include "macros.h"
|
||||
#include "logsink.h"
|
||||
|
||||
#ifdef __MINGW32__
|
||||
# include <windows.h>
|
||||
# include <windns.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ARPA_NAMESER_H
|
||||
# include <arpa/nameser.h>
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
# include <arpa/nameser_compat.h>
|
||||
#endif
|
||||
|
||||
#ifndef NS_MAXDNAME
|
||||
# define NS_MAXDNAME 1025
|
||||
#endif
|
||||
|
||||
#ifndef NS_PACKETSZ
|
||||
# define NS_PACKETSZ 512
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
# include <netdb.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This class holds a number of static functions used for DNS related stuff.
|
||||
*
|
||||
* You should not need to use these functions directly.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.3
|
||||
*/
|
||||
class GLOOX_API DNS
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* A list of strings (used for server addresses) and ints (used for port numbers).
|
||||
*/
|
||||
typedef std::map<std::string, int> HostMap;
|
||||
|
||||
/**
|
||||
* This function resolves a service/protocol/domain tuple.
|
||||
* @param service The SRV service type.
|
||||
* @param proto The SRV protocol.
|
||||
* @param domain The domain to search for SRV records.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
* @return A list of weighted hostname/port pairs from SRV records, or A records if no SRV
|
||||
* records where found.
|
||||
*/
|
||||
static HostMap resolve( const std::string& service, const std::string& proto,
|
||||
const std::string& domain, const LogSink& logInstance );
|
||||
|
||||
/**
|
||||
* This is a convenience funtion which uses @ref resolve() to resolve SRV records
|
||||
* for a given domain, using a service of @b xmpp-client and a proto of @b tcp.
|
||||
* @param domain The domain to resolve SRV records for.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
* @return A list of weighted hostname/port pairs from SRV records, or A records if no SRV
|
||||
* records where found.
|
||||
*/
|
||||
static HostMap resolve( const std::string& domain, const LogSink& logInstance )
|
||||
{ return resolve( "xmpp-client", "tcp", domain, logInstance ); }
|
||||
|
||||
/**
|
||||
* This is a convenience function which uses @ref resolve() to get a list of hosts
|
||||
* and connects to one of them.
|
||||
* @param host The host to resolve SRV records for.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
* @return A file descriptor for the established connection.
|
||||
*/
|
||||
static int connect( const std::string& host, const LogSink& logInstance );
|
||||
|
||||
/**
|
||||
* This is a convenience function which connects to the given host and port. No SRV
|
||||
* records are resolved. Use this function for special setups.
|
||||
* @param host The host/IP address to connect to.
|
||||
* @param port A custom port to connect to.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
* @return A file descriptor for the established connection.
|
||||
*/
|
||||
static int connect( const std::string& host, int port, const LogSink& logInstance );
|
||||
|
||||
/**
|
||||
* A convenience function that prepares and returnes a simple, unconnected TCP socket.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
* @return A TCP socket.
|
||||
*/
|
||||
static int getSocket( const LogSink& logInstance );
|
||||
|
||||
/**
|
||||
* Closes the given socket.
|
||||
* @param fd The socket to close.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
*/
|
||||
static void closeSocket( int fd, const LogSink& logInstance );
|
||||
|
||||
private:
|
||||
#ifdef HAVE_GETADDRINFO
|
||||
/**
|
||||
* Resolves the given service for the given domain and protocol, using the IPv6-ready
|
||||
* getaddrinfo(). The result is put into the first parameter.
|
||||
* @param res A pointer to a pointer holding the query results.
|
||||
* @param service A service string to query for, e.g. xmpp-client.
|
||||
* @param proto A protocol name.
|
||||
* @param domain The domain to query for.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
*/
|
||||
static void resolve( struct addrinfo** res, const std::string& service, const std::string& proto,
|
||||
const std::string& domain, const LogSink& logInstance );
|
||||
|
||||
/**
|
||||
* This is a convenience funtion which uses @ref resolve() to resolve SRV records
|
||||
* for a given domain, using a service of @b xmpp-client and a proto of @b tcp.
|
||||
* @param res A pointer to a pointer holding the query results.
|
||||
* @param domain The domain to resolve SRV records for.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
*/
|
||||
static void resolve( struct addrinfo** res, const std::string& domain, const LogSink& logInstance )
|
||||
{ resolve( res, "xmpp-client", "tcp", domain, logInstance ); }
|
||||
|
||||
/**
|
||||
* Tries to connect to the host/address contained in the addrinfo structure.
|
||||
* @param res The connection parameters.
|
||||
* @param logInstance A LogSink to use for logging.
|
||||
* @return A file descriptor for the established connection.
|
||||
*/
|
||||
static int connect( struct addrinfo* res, const LogSink& logInstance );
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function prepares and returns a socket with the given parameters.
|
||||
* @param af The address family. E.g. PF_INET.
|
||||
* @param socktype The socket type. E.g. SOCK_STREAM.
|
||||
* @param proto The protocol number. E.g. 6 (TCP).
|
||||
*/
|
||||
static int getSocket( int af, int socktype, int proto, const LogSink& logInstance );
|
||||
|
||||
static HostMap defaultHostMap( const std::string& domain, const LogSink& logInstance );
|
||||
static void cleanup( const LogSink& logInstance );
|
||||
|
||||
struct buffer
|
||||
{
|
||||
unsigned char buf[NS_PACKETSZ];
|
||||
int len;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // DNS_H__
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
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 "error.h"
|
||||
#include "tag.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/* Error type values */
|
||||
static const char* errValues [] = {
|
||||
"auth",
|
||||
"cancel",
|
||||
"continue",
|
||||
"modify",
|
||||
"wait"
|
||||
};
|
||||
|
||||
/* Stanza error values */
|
||||
static const char* stanzaErrValues [] = {
|
||||
"bad-request",
|
||||
"conflict",
|
||||
"feature-not-implemented",
|
||||
"forbidden",
|
||||
"gone",
|
||||
"internal-server-error",
|
||||
"item-not-found",
|
||||
"jid-malformed",
|
||||
"not-acceptable",
|
||||
"not-allowed",
|
||||
"not-authorized",
|
||||
"not-modified",
|
||||
"payment-required",
|
||||
"recipient-unavailable",
|
||||
"redirect",
|
||||
"registration-required",
|
||||
"remote-server-not-found",
|
||||
"remote-server-timeout",
|
||||
"resource-constraint",
|
||||
"service-unavailable",
|
||||
"subscription-required",
|
||||
"undefined-condition",
|
||||
"unexpected-request",
|
||||
"unknown-sender"
|
||||
};
|
||||
|
||||
static inline StanzaErrorType stanzaErrorType( const std::string& type )
|
||||
{
|
||||
return (StanzaErrorType)util::lookup( type, errValues );
|
||||
}
|
||||
|
||||
static inline StanzaError stanzaError( const std::string& type )
|
||||
{
|
||||
return (StanzaError)util::lookup( type, stanzaErrValues );
|
||||
}
|
||||
|
||||
Error::Error( const Tag* tag )
|
||||
: StanzaExtension( ExtError ),
|
||||
m_error( StanzaErrorUndefined ), m_appError( 0 )
|
||||
{
|
||||
if( !tag || tag->name() != "error" )
|
||||
return;
|
||||
|
||||
m_type = stanzaErrorType( tag->findAttribute( TYPE ) );
|
||||
|
||||
TagList::const_iterator it = tag->children().begin();
|
||||
for( ; it != tag->children().end(); ++it )
|
||||
{
|
||||
StanzaError srt = gloox::stanzaError( (*it)->name() );
|
||||
if( srt != StanzaErrorUndefined )
|
||||
m_error = srt;
|
||||
else if( (*it)->name() == "text" )
|
||||
m_text[(*it)->findAttribute("xml:lang")] = (*it)->cdata();
|
||||
else
|
||||
m_appError = (*it)->clone();
|
||||
}
|
||||
}
|
||||
|
||||
Error::Error( const Error& error )
|
||||
: StanzaExtension( ExtError ), m_type( error.m_type ),
|
||||
m_error( error.m_error ), m_appError( error.m_appError ? m_appError->clone() : 0 )
|
||||
{}
|
||||
|
||||
Error::~Error()
|
||||
{
|
||||
delete m_appError;
|
||||
}
|
||||
|
||||
const std::string& Error::filterString() const
|
||||
{
|
||||
static const std::string filter = "/iq/error"
|
||||
"|/message/error"
|
||||
"|/presence/error"
|
||||
"|/subscription/error";
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
Tag* Error::tag() const
|
||||
{
|
||||
if( m_type == StanzaErrorTypeUndefined || m_error == StanzaErrorUndefined )
|
||||
return 0;
|
||||
|
||||
Tag* error = new Tag( "error", TYPE, util::lookup( m_type, errValues ) );
|
||||
new Tag( error, util::lookup( m_error, stanzaErrValues ), XMLNS, XMLNS_XMPP_STANZAS );
|
||||
|
||||
StringMap::const_iterator it = m_text.begin();
|
||||
for( ; it != m_text.end(); ++it )
|
||||
{
|
||||
Tag* txt = new Tag( error, "text" );
|
||||
txt->setXmlns( XMLNS_XMPP_STANZAS );
|
||||
txt->addAttribute( "xml:lang", (*it).first );
|
||||
txt->setCData( (*it).second );
|
||||
}
|
||||
|
||||
if( m_appError )
|
||||
error->addChild( m_appError->clone() );
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
const std::string& Error::text( const std::string& lang ) const
|
||||
{
|
||||
StringMap::const_iterator it = m_text.find( lang );
|
||||
return it != m_text.end() ? (*it).second : EmptyString;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
/*
|
||||
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 ERROR_H__
|
||||
#define ERROR_H__
|
||||
|
||||
#include "gloox.h"
|
||||
#include "stanzaextension.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief A stanza error abstraction implemented as a StanzaExtension.
|
||||
*
|
||||
* @author Vincent Thomasset
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API Error : public StanzaExtension
|
||||
{
|
||||
public:
|
||||
|
||||
// Error()
|
||||
// : StanzaExtension( ExtError ), m_type( StanzaErrorTypeUndefined ),
|
||||
// m_error( StanzaErrorUndefined ), m_appError( 0 )
|
||||
// {}
|
||||
|
||||
/**
|
||||
* Creates a new Error object from the given Tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
Error( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Creates a new Error object.
|
||||
* @param type The error type.
|
||||
* @param error The actual stanza error.
|
||||
* @param appError An optional application-specific error.
|
||||
*/
|
||||
Error( StanzaErrorType type, StanzaError error, Tag* appError = 0 )
|
||||
: StanzaExtension( ExtError ), m_type( type ),
|
||||
m_error( error ), m_appError( appError )
|
||||
{}
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Error();
|
||||
|
||||
/**
|
||||
* Returns the error type.
|
||||
* @return The error type.
|
||||
*/
|
||||
StanzaErrorType type() const { return m_type; }
|
||||
|
||||
/**
|
||||
* Return the stanza error.
|
||||
* @return The actual error.
|
||||
*/
|
||||
StanzaError error() const { return m_error; }
|
||||
|
||||
/**
|
||||
* This function can be used to retrieve the application-specific error
|
||||
* condition of a stanza error.
|
||||
* @return The application-specific error element of a stanza error.
|
||||
* 0 if no respective element was found or no error occured.
|
||||
*/
|
||||
const Tag* appError() const { return m_appError; }
|
||||
|
||||
/**
|
||||
* Returns the text of a error stanza for the given language if available.
|
||||
* If the requested language is not available, the default text (without
|
||||
* a xml:lang attribute) will be returned.
|
||||
* @param lang The language identifier for the desired language. It must
|
||||
* conform to section 2.12 of the XML specification and RFC 3066. If
|
||||
* empty, the default text will be returned, if any.
|
||||
* @return The text of an error stanza.
|
||||
*/
|
||||
const std::string& text( const std::string& lang = EmptyString ) const;
|
||||
|
||||
/**
|
||||
* Sets the text of a error stanza for the given language.
|
||||
* @param text The error text to set.
|
||||
* @param lang The language identifier for the desired language. It must
|
||||
* conform to section 2.12 of the XML specification and RFC 3066. If
|
||||
* empty, the default text will be set.
|
||||
*/
|
||||
void setText( const std::string& text, const std::string& lang = EmptyString )
|
||||
{
|
||||
m_text[lang] = text;
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Error( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new Error( *this );
|
||||
}
|
||||
|
||||
private:
|
||||
Error( const Error& error );
|
||||
|
||||
void setValues( const Tag* tag );
|
||||
|
||||
StanzaErrorType m_type;
|
||||
StanzaError m_error;
|
||||
Tag* m_appError;
|
||||
StringMap m_text;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ERROR_H__ */
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
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 EVENT_H__
|
||||
#define EVENT_H__
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Stanza;
|
||||
|
||||
/**
|
||||
* @brief A base class for events.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class Event
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Event types.
|
||||
*/
|
||||
enum EventType
|
||||
{
|
||||
PingPing, /**< Incoming Ping (@xep{0199}). */
|
||||
PingPong, /**< Incoming Pong (@xep{0199}). */
|
||||
PingError /**< Incoming Error Pong (@xep{0199}). */
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new Event of the given type.
|
||||
* @param type The Event type.
|
||||
*/
|
||||
Event( EventType type ) : m_eventType( type ), m_stanza( 0 ) {}
|
||||
|
||||
/**
|
||||
* Creates a new Event of the given type, referencing the given Stanza.
|
||||
* @param type The Event type.
|
||||
* @param stanza A Stanza to point at. No copy of the Stanza is taken, just its address.
|
||||
*/
|
||||
Event( EventType type, const Stanza& stanza ) : m_eventType( type ), m_stanza( &stanza ) {}
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~Event() {}
|
||||
|
||||
/**
|
||||
* Returns the Event's type.
|
||||
* @return The Event's type.
|
||||
*/
|
||||
EventType eventType() const { return m_eventType; }
|
||||
|
||||
/**
|
||||
* Returns a pointer to a Stanza-derived object.
|
||||
* @return A pointer to a Stanza that caused the event. May be 0.
|
||||
* @note You should @b not delete the Stanza object.
|
||||
*/
|
||||
const Stanza* stanza() const { return m_stanza; }
|
||||
|
||||
protected:
|
||||
EventType m_eventType;
|
||||
const Stanza* m_stanza;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // EVENT_H__
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
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 "eventdispatcher.h"
|
||||
#include "eventhandler.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
EventDispatcher::EventDispatcher()
|
||||
{
|
||||
}
|
||||
|
||||
EventDispatcher::~EventDispatcher()
|
||||
{
|
||||
}
|
||||
|
||||
void EventDispatcher::dispatch( const Event& event, const std::string& context, bool remove )
|
||||
{
|
||||
typedef ContextHandlerMap::iterator Ei;
|
||||
std::pair<Ei, Ei> g = m_contextHandlers.equal_range( context );
|
||||
Ei it = g.first;
|
||||
Ei it2;
|
||||
while( it != g.second )
|
||||
{
|
||||
it2 = it++;
|
||||
(*it2).second->handleEvent( event );
|
||||
if( remove )
|
||||
m_contextHandlers.erase( it2 );
|
||||
}
|
||||
}
|
||||
|
||||
void EventDispatcher::dispatch( const Event& event )
|
||||
{
|
||||
TypeHandlerMap::iterator it = m_typeHandlers.begin();
|
||||
for( ; it != m_typeHandlers.end(); ++it )
|
||||
{
|
||||
if( (*it).first == event.eventType() )
|
||||
(*it).second->handleEvent( event );
|
||||
}
|
||||
}
|
||||
|
||||
void EventDispatcher::registerEventHandler( EventHandler* eh, const std::string& context )
|
||||
{
|
||||
if( !eh || context.empty() )
|
||||
return;
|
||||
|
||||
m_contextHandlers.insert( std::make_pair( context, eh ) );
|
||||
}
|
||||
|
||||
void EventDispatcher::removeEventHandler( EventHandler* eh )
|
||||
{
|
||||
ContextHandlerMap::iterator it = m_contextHandlers.begin();
|
||||
ContextHandlerMap::iterator it2;
|
||||
while( it != m_contextHandlers.end() )
|
||||
{
|
||||
it2 = it++;
|
||||
if( (*it2).second == eh )
|
||||
m_contextHandlers.erase( it2 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
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 EVENTDISPATCHER_H__
|
||||
#define EVENTDISPATCHER_H__
|
||||
|
||||
#include "event.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class EventHandler;
|
||||
|
||||
/**
|
||||
* @brief An Event dispatcher.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class EventDispatcher
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new EventDispatcher object. You should not need to use this class directly.
|
||||
*/
|
||||
EventDispatcher();
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~EventDispatcher();
|
||||
|
||||
/**
|
||||
* Looks for handlers for the given Event, and removes the handlers if requested.
|
||||
* @param event The Event to dispatch.
|
||||
* @param context An identifier that limits the EventHandlers that will get notified to
|
||||
* those that are specifically interested in this context.
|
||||
* @param remove Whether or not to remove the context from the list of known contexts. Useful for
|
||||
* IQ IDs.
|
||||
*/
|
||||
void dispatch( const Event& event, const std::string& context, bool remove );
|
||||
|
||||
/**
|
||||
* Looks for handlers for the given Event, identified by its type.
|
||||
* @param event The event to dispatch.
|
||||
*/
|
||||
void dispatch( const Event& event );
|
||||
|
||||
/**
|
||||
* Registers the given EventHandler to be notified about Events with the given context.
|
||||
* The context will usually be an IQ ID.
|
||||
* @param eh The EventHandler to register.
|
||||
* @param context The context to register the EventHandler for.
|
||||
*/
|
||||
void registerEventHandler( EventHandler* eh, const std::string& context );
|
||||
|
||||
/**
|
||||
* Removes the given EventHandler.
|
||||
* @param eh The EventHandler to remove.
|
||||
*/
|
||||
void removeEventHandler( EventHandler* eh );
|
||||
|
||||
private:
|
||||
typedef std::multimap<const std::string, EventHandler*> ContextHandlerMap;
|
||||
typedef std::multimap<Event::EventType, EventHandler*> TypeHandlerMap;
|
||||
|
||||
ContextHandlerMap m_contextHandlers;
|
||||
TypeHandlerMap m_typeHandlers;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // EVENTDISPATCHER_H__
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
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 EVENTHANDLER_H__
|
||||
#define EVENTHANDLER_H__
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class Event;
|
||||
|
||||
/**
|
||||
* @brief An base class for event handlers.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class EventHandler
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~EventHandler() {}
|
||||
|
||||
/**
|
||||
* This function gets called for Events this handler was registered for.
|
||||
* @param event The Event.
|
||||
*/
|
||||
virtual void handleEvent( const Event& event ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // EVENTHANDLER_H__
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
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 "featureneg.h"
|
||||
#include "dataform.h"
|
||||
#include "tag.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
FeatureNeg::FeatureNeg( DataForm* form )
|
||||
: StanzaExtension( ExtFeatureNeg ), m_form( form )
|
||||
{
|
||||
}
|
||||
|
||||
FeatureNeg::FeatureNeg( const Tag* tag )
|
||||
: StanzaExtension( ExtFeatureNeg ), m_form( 0 )
|
||||
{
|
||||
if( !tag || tag->name() != "feature" || tag->xmlns() != XMLNS_FEATURE_NEG )
|
||||
return;
|
||||
|
||||
const Tag* f = tag->findTag( "feature/x[@xmlns='" + XMLNS_X_DATA + "']" );
|
||||
if( f )
|
||||
m_form = new DataForm( f );
|
||||
}
|
||||
|
||||
FeatureNeg::~FeatureNeg()
|
||||
{
|
||||
delete m_form;
|
||||
}
|
||||
|
||||
const std::string& FeatureNeg::filterString() const
|
||||
{
|
||||
static const std::string filter = "/message/feature[@xmlns='" + XMLNS_FEATURE_NEG + "']"
|
||||
"|/iq/feature[@xmlns='" + XMLNS_FEATURE_NEG + "']" ;
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* FeatureNeg::tag() const
|
||||
{
|
||||
if( !m_form )
|
||||
return 0;
|
||||
|
||||
Tag* t = new Tag( "feature" );
|
||||
t->setXmlns( XMLNS_FEATURE_NEG );
|
||||
t->addChild( m_form->tag() );
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
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 FEATURENEG_H__
|
||||
#define FEATURENEG_H__
|
||||
|
||||
#include "stanzaextension.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
class DataForm;
|
||||
class Tag;
|
||||
|
||||
/**
|
||||
* @brief An abstraction of Feature Negotiation (@xep{0020}), implemented
|
||||
* as a StanzaExtension.
|
||||
*
|
||||
* XEP Version: 1.5
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 1.0
|
||||
*/
|
||||
class GLOOX_API FeatureNeg : public StanzaExtension
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new wrapper object using the given DataForm.
|
||||
* @param form The DataForm to embed. The FeatureNeg object will own the DataForm.
|
||||
*/
|
||||
FeatureNeg( DataForm* form );
|
||||
|
||||
/**
|
||||
* Creates a new wrapper object from the given Tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
FeatureNeg( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~FeatureNeg();
|
||||
|
||||
/**
|
||||
* Returns the wrapped DataForm.
|
||||
* @return The wrapped DataForm. May be 0.
|
||||
*/
|
||||
const DataForm* form() const { return m_form; }
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new FeatureNeg( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new FeatureNeg( m_form );
|
||||
}
|
||||
|
||||
private:
|
||||
DataForm* m_form;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FEATURENEG_H__
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "flexoff.h"
|
||||
#include "dataform.h"
|
||||
#include "disco.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
// ---- FlexibleOffline::Offline ----
|
||||
FlexibleOffline::Offline::Offline( const Tag* /*tag*/ )
|
||||
: StanzaExtension( ExtFlexOffline )
|
||||
{
|
||||
// FIXME what to do here?
|
||||
}
|
||||
|
||||
FlexibleOffline::Offline::Offline( int context, const StringList& msgs )
|
||||
: StanzaExtension( ExtFlexOffline ), m_context( context ), m_msgs( msgs )
|
||||
{
|
||||
}
|
||||
|
||||
FlexibleOffline::Offline::~Offline()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& FlexibleOffline::Offline::filterString() const
|
||||
{
|
||||
static const std::string filter = "/iq/offline[@xmlns='" + XMLNS_OFFLINE + "']";
|
||||
return filter;
|
||||
}
|
||||
|
||||
Tag* FlexibleOffline::Offline::tag() const
|
||||
{
|
||||
Tag* t = new Tag( "offline" );
|
||||
t->setXmlns( XMLNS_OFFLINE );
|
||||
|
||||
if( m_msgs.empty() )
|
||||
new Tag( t, m_context == FORequestMsgs ? "fetch" : "purge" );
|
||||
else
|
||||
{
|
||||
const std::string action = m_context == FORequestMsgs ? "view" : "remove";
|
||||
StringList::const_iterator it = m_msgs.begin();
|
||||
for( ; it != m_msgs.end(); ++it )
|
||||
{
|
||||
Tag* i = new Tag( t, "item", "action", action );
|
||||
i->addAttribute( "node", (*it) );
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
// ---- ~FlexibleOffline::Offline ----
|
||||
|
||||
// ---- FlexibleOffline ----
|
||||
FlexibleOffline::FlexibleOffline( ClientBase* parent )
|
||||
: m_parent( parent ), m_flexibleOfflineHandler( 0 )
|
||||
{
|
||||
if( m_parent )
|
||||
m_parent->registerStanzaExtension( new Offline() );
|
||||
}
|
||||
|
||||
FlexibleOffline::~FlexibleOffline()
|
||||
{
|
||||
if( m_parent )
|
||||
m_parent->removeIDHandler( this );
|
||||
}
|
||||
|
||||
void FlexibleOffline::checkSupport()
|
||||
{
|
||||
m_parent->disco()->getDiscoInfo( m_parent->jid().server(), EmptyString, this, FOCheckSupport );
|
||||
}
|
||||
|
||||
void FlexibleOffline::getMsgCount()
|
||||
{
|
||||
m_parent->disco()->getDiscoInfo( m_parent->jid().server(), XMLNS_OFFLINE, this, FORequestNum );
|
||||
}
|
||||
|
||||
void FlexibleOffline::fetchHeaders()
|
||||
{
|
||||
m_parent->disco()->getDiscoItems( m_parent->jid().server(), XMLNS_OFFLINE, this, FORequestHeaders );
|
||||
}
|
||||
|
||||
void FlexibleOffline::messageOperation( int context, const StringList& msgs )
|
||||
{
|
||||
const std::string& id = m_parent->getID();
|
||||
IQ::IqType iqType = context == FORequestMsgs ? IQ::Get : IQ::Set;
|
||||
IQ iq( iqType, JID(), id );
|
||||
iq.addExtension( new Offline( context, msgs ) );
|
||||
m_parent->send( iq, this, context );
|
||||
}
|
||||
|
||||
void FlexibleOffline::registerFlexibleOfflineHandler( FlexibleOfflineHandler* foh )
|
||||
{
|
||||
m_flexibleOfflineHandler = foh;
|
||||
}
|
||||
|
||||
void FlexibleOffline::removeFlexibleOfflineHandler()
|
||||
{
|
||||
m_flexibleOfflineHandler = 0;
|
||||
}
|
||||
|
||||
void FlexibleOffline::handleDiscoInfo( const JID& /*from*/, const Disco::Info& info, int context )
|
||||
{
|
||||
if( !m_flexibleOfflineHandler )
|
||||
return;
|
||||
|
||||
switch( context )
|
||||
{
|
||||
case FOCheckSupport:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineSupport( info.hasFeature( XMLNS_OFFLINE ) );
|
||||
break;
|
||||
|
||||
case FORequestNum:
|
||||
int num = -1;
|
||||
if( info.form() && info.form()->hasField( "number_of_messages" ) )
|
||||
num = atoi( info.form()->field( "number_of_messages" )->value().c_str() );
|
||||
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineMsgNum( num );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FlexibleOffline::handleDiscoItems( const JID& /*from*/, const Disco::Items& items, int context )
|
||||
{
|
||||
if( context == FORequestHeaders && m_flexibleOfflineHandler )
|
||||
{
|
||||
if( items.node() == XMLNS_OFFLINE )
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineMessageHeaders( items.items() );
|
||||
}
|
||||
}
|
||||
|
||||
void FlexibleOffline::handleDiscoError( const JID& /*from*/, const Error* /*error*/, int /*context*/ )
|
||||
{
|
||||
}
|
||||
|
||||
void FlexibleOffline::handleIqID( const IQ& iq, int context )
|
||||
{
|
||||
if( !m_flexibleOfflineHandler )
|
||||
return;
|
||||
|
||||
switch( context )
|
||||
{
|
||||
case FORequestMsgs:
|
||||
switch( iq.subtype() )
|
||||
{
|
||||
case IQ::Result:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineResult( FomrRequestSuccess );
|
||||
break;
|
||||
case IQ::Error:
|
||||
switch( iq.error()->error() )
|
||||
{
|
||||
case StanzaErrorForbidden:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineResult( FomrForbidden );
|
||||
break;
|
||||
case StanzaErrorItemNotFound:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineResult( FomrItemNotFound );
|
||||
break;
|
||||
default:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineResult( FomrUnknownError );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FORemoveMsgs:
|
||||
switch( iq.subtype() )
|
||||
{
|
||||
case IQ::Result:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineResult( FomrRemoveSuccess );
|
||||
break;
|
||||
case IQ::Error:
|
||||
switch( iq.error()->error() )
|
||||
{
|
||||
case StanzaErrorForbidden:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineResult( FomrForbidden );
|
||||
break;
|
||||
case StanzaErrorItemNotFound:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineResult( FomrItemNotFound );
|
||||
break;
|
||||
default:
|
||||
m_flexibleOfflineHandler->handleFlexibleOfflineResult( FomrUnknownError );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 FLEXOFF_H__
|
||||
#define FLEXOFF_H__
|
||||
|
||||
#include "clientbase.h"
|
||||
#include "discohandler.h"
|
||||
#include "flexoffhandler.h"
|
||||
#include "iqhandler.h"
|
||||
#include "stanzaextension.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief An implementation of @xep{0013} (Flexible Offline Message Retrieval).
|
||||
*
|
||||
* Use the FlexibleOfflineHandler to receive results.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.7
|
||||
*/
|
||||
class GLOOX_API FlexibleOffline : public DiscoHandler, public IqHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new FlexibleOffline object that manages retrieval of offline messages.
|
||||
* @param parent The ClientBase to use for communication.
|
||||
*/
|
||||
FlexibleOffline( ClientBase* parent );
|
||||
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~FlexibleOffline();
|
||||
|
||||
/**
|
||||
* Initiates querying the server for Flexible Offline Message Retrieval-support.
|
||||
* The result is announced through the FlexibleOfflineHandler.
|
||||
* An application could cache the result on a per-server basis to eliminate the associated delay.
|
||||
*/
|
||||
void checkSupport();
|
||||
|
||||
/**
|
||||
* Asks the server for the number of stored offline messages.
|
||||
* The result is announced through the FlexibleOfflineHandler.
|
||||
*/
|
||||
void getMsgCount();
|
||||
|
||||
/**
|
||||
* Initiates fetching the offline message headers.
|
||||
* The result is announced through the FlexibleOfflineHandler.
|
||||
*/
|
||||
void fetchHeaders();
|
||||
|
||||
/**
|
||||
* Initiates fetching of one or more specific messages, or all messages.
|
||||
* The result is announced through the FlexibleOfflineHandler.
|
||||
* If the list of message nodes contains one or more nodes, the corresponding messages are
|
||||
* fetched. If the list is empty all messages are fetched (<fetch>).
|
||||
* @param msgs A list of message nodes to fetch.
|
||||
*/
|
||||
void fetchMessages( const StringList& msgs )
|
||||
{ messageOperation( FORequestMsgs, msgs ); }
|
||||
|
||||
/**
|
||||
* Initiates removing of one or more specific messages, or all messages.
|
||||
* The result is announced through the FlexibleOfflineHandler.
|
||||
* If the list of message nodes contains one or more nodes, the corresponding messages are
|
||||
* removed. If the list is empty all messages are removed (<purge>).
|
||||
*/
|
||||
void removeMessages( const StringList& msgs )
|
||||
{ messageOperation( FORemoveMsgs, msgs ); }
|
||||
|
||||
/**
|
||||
* Registers a FlexibleOfflineHandler as object that receives results of @xep{0013} queries.
|
||||
* Only one Handler at a time is possible.
|
||||
* @param foh The Handler object to register.
|
||||
*/
|
||||
void registerFlexibleOfflineHandler( FlexibleOfflineHandler* foh );
|
||||
|
||||
/**
|
||||
* Removes the registered handler.
|
||||
*/
|
||||
void removeFlexibleOfflineHandler();
|
||||
|
||||
// reimplemented from DiscoHandler
|
||||
virtual void handleDiscoInfo( const JID& from, const Disco::Info& info, int context );
|
||||
|
||||
// reimplemented from DiscoHandler
|
||||
virtual void handleDiscoItems( const JID& from, const Disco::Items& items, int context );
|
||||
|
||||
// reimplemented from DiscoHandler
|
||||
virtual void handleDiscoError( const JID& from, const Error* error, int context );
|
||||
|
||||
// reimplemented from IqHandler.
|
||||
virtual bool handleIq( const IQ& iq ) { (void)iq; return false; }
|
||||
|
||||
// reimplemented from IqHandler.
|
||||
virtual void handleIqID( const IQ& iq, int context );
|
||||
|
||||
private:
|
||||
#ifdef FLEXOFF_TEST
|
||||
public:
|
||||
#endif
|
||||
class Offline : public StanzaExtension
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructs a new Offline object from the given Tag.
|
||||
* @param tag The Tag to parse.
|
||||
*/
|
||||
Offline( const Tag* tag = 0 );
|
||||
|
||||
/**
|
||||
* Constructs a new Offline object for the given context and messages.
|
||||
* @param context The context.
|
||||
* @param msgs The messages.
|
||||
*/
|
||||
Offline( int context, const StringList& msgs );
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~Offline();
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual const std::string& filterString() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* newInstance( const Tag* tag ) const
|
||||
{
|
||||
return new Offline( tag );
|
||||
}
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual Tag* tag() const;
|
||||
|
||||
// reimplemented from StanzaExtension
|
||||
virtual StanzaExtension* clone() const
|
||||
{
|
||||
return new Offline( *this );
|
||||
}
|
||||
|
||||
private:
|
||||
int m_context;
|
||||
StringList m_msgs;
|
||||
};
|
||||
|
||||
void messageOperation( int context, const StringList& msgs );
|
||||
|
||||
enum FOContext
|
||||
{
|
||||
FOCheckSupport,
|
||||
FORequestNum,
|
||||
FORequestHeaders,
|
||||
FORequestMsgs,
|
||||
FORemoveMsgs
|
||||
};
|
||||
|
||||
ClientBase* m_parent;
|
||||
FlexibleOfflineHandler* m_flexibleOfflineHandler;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FLEXOFF_H__
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 FLEXOFFHANDLER_H__
|
||||
#define FLEXOFFHANDLER_H__
|
||||
|
||||
#include "disco.h"
|
||||
#include "gloox.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
/**
|
||||
* Describes the possible results of a message retrieval or deletion request.
|
||||
*/
|
||||
enum FlexibleOfflineResult
|
||||
{
|
||||
FomrRemoveSuccess, /**< Message(s) were removed successfully. */
|
||||
FomrRequestSuccess, /**< Message(s) were fetched successfully. */
|
||||
FomrForbidden, /**< The requester is a JID other than an authorized resource of the
|
||||
* user. Something wnet serieously wrong */
|
||||
FomrItemNotFound, /**< The requested node (message ID) does not exist. */
|
||||
FomrUnknownError /**< An error occurred which is not specified in @xep{0013}. */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implementation of this virtual interface allows for retrieval of offline messages following
|
||||
* @xep{0030}.
|
||||
*
|
||||
* @author Jakob Schröter <js@camaya.net>
|
||||
* @since 0.7
|
||||
*/
|
||||
class GLOOX_API FlexibleOfflineHandler
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Virtual Destructor.
|
||||
*/
|
||||
virtual ~FlexibleOfflineHandler() {}
|
||||
|
||||
/**
|
||||
* This function is called to indicate whether the server supports @xep{0013} or not.
|
||||
* Call @ref FlexibleOffline::checkSupport() to trigger the check.
|
||||
* @param support Whether the server support @xep{0013} or not.
|
||||
*/
|
||||
virtual void handleFlexibleOfflineSupport( bool support ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called to announce the number of available offline messages.
|
||||
* Call @ref FlexibleOffline::getMsgCount() to trigger the check.
|
||||
* @param num The number of stored offline messages.
|
||||
*/
|
||||
virtual void handleFlexibleOfflineMsgNum( int num ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called when the offline message headers arrive.
|
||||
* Call @ref FlexibleOffline::fetchHeaders() to trigger the check.
|
||||
* @param headers A map of ID/sender pairs describing the offline messages.
|
||||
*/
|
||||
virtual void handleFlexibleOfflineMessageHeaders( const Disco::ItemList& headers ) = 0;
|
||||
|
||||
/**
|
||||
* This function is called to indicate the result of a fetch or delete instruction.
|
||||
* @param foResult The result of the operation.
|
||||
*/
|
||||
virtual void handleFlexibleOfflineResult( FlexibleOfflineResult foResult ) = 0;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FLEXOFFHANDLER_H__
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
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() ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -1,104 +0,0 @@
|
|||
/*
|
||||
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__
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2005-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 "gloox.h"
|
||||
|
||||
namespace gloox
|
||||
{
|
||||
|
||||
const std::string XMLNS_CLIENT = "jabber:client";
|
||||
const std::string XMLNS_COMPONENT_ACCEPT = "jabber:component:accept";
|
||||
const std::string XMLNS_COMPONENT_CONNECT = "jabber:component:connect";
|
||||
|
||||
const std::string XMLNS_DISCO_INFO = "http://jabber.org/protocol/disco#info";
|
||||
const std::string XMLNS_DISCO_ITEMS = "http://jabber.org/protocol/disco#items";
|
||||
const std::string XMLNS_DISCO_PUBLISH = "http://jabber.org/protocol/disco#publish";
|
||||
const std::string XMLNS_ADHOC_COMMANDS = "http://jabber.org/protocol/commands";
|
||||
const std::string XMLNS_COMPRESSION = "http://jabber.org/protocol/compress";
|
||||
|
||||
const std::string XMLNS_OFFLINE = "http://jabber.org/protocol/offline";
|
||||
const std::string XMLNS_CHAT_STATES = "http://jabber.org/protocol/chatstates";
|
||||
const std::string XMLNS_AMP = "http://jabber.org/protocol/amp";
|
||||
const std::string XMLNS_IBB = "http://jabber.org/protocol/ibb";
|
||||
const std::string XMLNS_FEATURE_NEG = "http://jabber.org/protocol/feature-neg";
|
||||
|
||||
const std::string XMLNS_CHATNEG = "http://jabber.org/protocol/chatneg";
|
||||
const std::string XMLNS_XHTML_IM = "http://jabber.org/protocol/xhtml-im";
|
||||
const std::string XMLNS_DELAY = "urn:xmpp:delay";
|
||||
const std::string XMLNS_ROSTER = "jabber:iq:roster";
|
||||
const std::string XMLNS_VERSION = "jabber:iq:version";
|
||||
|
||||
const std::string XMLNS_REGISTER = "jabber:iq:register";
|
||||
const std::string XMLNS_PRIVACY = "jabber:iq:privacy";
|
||||
const std::string XMLNS_AUTH = "jabber:iq:auth";
|
||||
const std::string XMLNS_PRIVATE_XML = "jabber:iq:private";
|
||||
const std::string XMLNS_LAST = "jabber:iq:last";
|
||||
|
||||
const std::string XMLNS_SEARCH = "jabber:iq:search";
|
||||
const std::string XMLNS_IQ_OOB = "jabber:iq:oob";
|
||||
const std::string XMLNS_X_DATA = "jabber:x:data";
|
||||
const std::string XMLNS_X_EVENT = "jabber:x:event";
|
||||
const std::string XMLNS_X_OOB = "jabber:x:oob";
|
||||
|
||||
const std::string XMLNS_X_DELAY = "jabber:x:delay";
|
||||
const std::string XMLNS_X_GPGSIGNED = "jabber:x:signed";
|
||||
const std::string XMLNS_X_GPGENCRYPTED = "jabber:x:encrypted";
|
||||
const std::string XMLNS_VCARD_TEMP = "vcard-temp";
|
||||
const std::string XMLNS_X_VCARD_UPDATE = "vcard-temp:x:update";
|
||||
|
||||
const std::string XMLNS_BOOKMARKS = "storage:bookmarks";
|
||||
const std::string XMLNS_ANNOTATIONS = "storage:rosternotes";
|
||||
const std::string XMLNS_ROSTER_DELIMITER = "roster:delimiter";
|
||||
const std::string XMLNS_XMPP_PING = "urn:xmpp:ping";
|
||||
const std::string XMLNS_SI = "http://jabber.org/protocol/si";
|
||||
|
||||
const std::string XMLNS_SI_FT = "http://jabber.org/protocol/si/profile/file-transfer";
|
||||
const std::string XMLNS_BYTESTREAMS = "http://jabber.org/protocol/bytestreams";
|
||||
const std::string XMLNS_MUC = "http://jabber.org/protocol/muc";
|
||||
const std::string XMLNS_MUC_USER = "http://jabber.org/protocol/muc#user";
|
||||
const std::string XMLNS_MUC_ADMIN = "http://jabber.org/protocol/muc#admin";
|
||||
|
||||
const std::string XMLNS_MUC_UNIQUE = "http://jabber.org/protocol/muc#unique";
|
||||
const std::string XMLNS_MUC_OWNER = "http://jabber.org/protocol/muc#owner";
|
||||
const std::string XMLNS_MUC_ROOMINFO = "http://jabber.org/protocol/muc#roominfo";
|
||||
const std::string XMLNS_MUC_ROOMS = "http://jabber.org/protocol/muc#rooms";
|
||||
const std::string XMLNS_MUC_REQUEST = "http://jabber.org/protocol/muc#request";
|
||||
|
||||
const std::string XMLNS_PUBSUB = "http://jabber.org/protocol/pubsub";
|
||||
const std::string XMLNS_PUBSUB_ERRORS = "http://jabber.org/protocol/pubsub#errors";
|
||||
const std::string XMLNS_PUBSUB_EVENT = "http://jabber.org/protocol/pubsub#event";
|
||||
const std::string XMLNS_PUBSUB_OWNER = "http://jabber.org/protocol/pubsub#owner";
|
||||
const std::string XMLNS_CAPS = "http://jabber.org/protocol/caps";
|
||||
|
||||
const std::string XMLNS_FT_FASTMODE = "http://affinix.com/jabber/stream";
|
||||
const std::string XMLNS_STREAM = "http://etherx.jabber.org/streams";
|
||||
const std::string XMLNS_XMPP_STREAM = "urn:ietf:params:xml:ns:xmpp-streams";
|
||||
const std::string XMLNS_XMPP_STANZAS = "urn:ietf:params:xml:ns:xmpp-stanzas";
|
||||
const std::string XMLNS_STREAM_TLS = "urn:ietf:params:xml:ns:xmpp-tls";
|
||||
|
||||
const std::string XMLNS_STREAM_SASL = "urn:ietf:params:xml:ns:xmpp-sasl";
|
||||
const std::string XMLNS_STREAM_BIND = "urn:ietf:params:xml:ns:xmpp-bind";
|
||||
const std::string XMLNS_STREAM_SESSION = "urn:ietf:params:xml:ns:xmpp-session";
|
||||
const std::string XMLNS_STREAM_IQAUTH = "http://jabber.org/features/iq-auth";
|
||||
const std::string XMLNS_STREAM_IQREGISTER = "http://jabber.org/features/iq-register";
|
||||
|
||||
const std::string XMLNS_STREAM_COMPRESS = "http://jabber.org/features/compress";
|
||||
const std::string XMLNS_HTTPBIND = "http://jabber.org/protocol/httpbind";
|
||||
const std::string XMLNS_XMPP_BOSH = "urn:xmpp:xbosh";
|
||||
const std::string XMLNS_RECEIPTS = "urn:xmpp:receipts";
|
||||
const std::string XMLNS_NICKNAME = "http://jabber.org/protocol/nick";
|
||||
|
||||
const std::string XMLNS_JINGLE = "urn:xmpp:jingle:1";
|
||||
const std::string XMLNS_JINGLE_ERRORS = "urn:xmpp:jingle:errors:1";
|
||||
const std::string XMLNS_JINGLE_ICE_UDP = "urn:xmpp:jingle:transports:ice-udp:1";
|
||||
const std::string XMLNS_JINGLE_FILE_TRANSFER = "urn:xmpp:jingle:apps:file-transfer:3";
|
||||
const std::string XMLNS_JINGLE_FILE_TRANSFER_MULTI = "urn:xmpp:jingle:apps:file-transfer:multi";
|
||||
|
||||
const std::string XMLNS_SHIM = "http://jabber.org/protocol/shim";
|
||||
const std::string XMLNS_ATTENTION = "urn:xmpp:attention:0";
|
||||
const std::string XMLNS_STREAM_MANAGEMENT = "urn:xmpp:sm:3";
|
||||
const std::string XMLNS_STANZA_FORWARDING = "urn:xmpp:forward:0";
|
||||
const std::string XMLNS_MESSAGE_CARBONS = "urn:xmpp:carbons:2";
|
||||
|
||||
const std::string XMLNS_HASHES = "urn:xmpp:hashes:1";
|
||||
const std::string XMLNS_IODATA = "urn:xmpp:tmp:io-data";
|
||||
|
||||
const std::string XMPP_STREAM_VERSION_MAJOR = "1";
|
||||
const std::string XMPP_STREAM_VERSION_MINOR = "0";
|
||||
const std::string GLOOX_VERSION = "1.0.13";
|
||||
const std::string GLOOX_CAPS_NODE = "http://camaya.net/gloox";
|
||||
|
||||
const std::string XMLNS = "xmlns";
|
||||
const std::string TYPE = "type";
|
||||
const std::string EmptyString = "";
|
||||
}
|
||||
|
||||
const char* gloox_version()
|
||||
{
|
||||
return gloox::GLOOX_VERSION.c_str();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2009-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.
|
||||
*/
|
||||
|
||||
#define GLOOXVERSION 0x010013
|
Some files were not shown because too many files have changed in this diff Show More
Ŝarĝante…
Reference in New Issue