diff --git a/include/tomahawk/sourcelist.h b/include/tomahawk/sourcelist.h index ef94be5d8..12320c6d7 100644 --- a/include/tomahawk/sourcelist.h +++ b/include/tomahawk/sourcelist.h @@ -21,8 +21,8 @@ public: void remove( Tomahawk::Source* s ); QList sources() const; - Tomahawk::source_ptr lookup( const QString& username ) const; - Tomahawk::source_ptr lookup( unsigned int id ) const; + Tomahawk::source_ptr get( const QString& username ) const; + Tomahawk::source_ptr get( unsigned int id ) const; unsigned int count() const; signals: diff --git a/include/tomahawk/tomahawkapp.h b/include/tomahawk/tomahawkapp.h index 1477e4b11..2210f7afe 100644 --- a/include/tomahawk/tomahawkapp.h +++ b/include/tomahawk/tomahawkapp.h @@ -29,10 +29,10 @@ class AudioEngine; class Database; -class Jabber; -class XMPPBot; +class SipHandler; class TomahawkZeroconf; class TomahawkSettings; +class XMPPBot; namespace Tomahawk { @@ -72,6 +72,7 @@ public: Database* database() { return m_db; } SourceList& sourcelist() { return m_sources; } Servent& servent() { return m_servent; } + SipHandler* sipHandler() { return m_sipHandler; } QNetworkAccessManager* nam() { return m_nam; } QNetworkProxy* proxy() { return m_proxy; } Tomahawk::InfoSystem::InfoSystem* infoSystem() { return m_infoSystem; } @@ -95,17 +96,8 @@ signals: public slots: QSharedPointer getIODeviceForUrl( const Tomahawk::result_ptr& result ); - void reconnectJabber(); - void jabberAddContact( const QString& jid ); private slots: - void jabberMessage( const QString&, const QString& ); - void jabberPeerOffline( const QString& ); - void jabberPeerOnline( const QString& ); - void jabberAuthError( int code, const QString& msg ); - void jabberDisconnected(); - void jabberConnected(); - void lanHostFound( const QString&, int, const QString&, const QString& ); private: @@ -114,7 +106,7 @@ private: void registerMetaTypes(); void startServent(); void setupDatabase(); - void setupJabber(); + void setupSIP(); void setupPipeline(); void startHTTP(); @@ -127,7 +119,7 @@ private: Servent m_servent; SourceList m_sources; TomahawkZeroconf* m_zeroconf; - QSharedPointer m_jabber; + SipHandler* m_sipHandler; XMPPBot* m_xmppBot; #ifndef NO_LIBLASTFM diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a2725747b..9697983e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,7 +43,9 @@ SET( tomahawkSources ${tomahawkSources} audio/audioengine.cpp utils/tomahawkutils.cpp - jabber/jabber_p.cpp + + sip/SipHandler.cpp + sip/SipPlugin.cpp infosystem/infosystem.cpp infosystem/infoplugins/echonestplugin.cpp @@ -205,8 +207,8 @@ SET( tomahawkHeaders ${tomahawkHeaders} database/databasecommand_updatesearchindex.h database/databasecollection.h - jabber/jabber.h - jabber/jabber_p.h + sip/SipHandler.h + sip/SipPlugin.h infosystem/infoplugins/echonestplugin.h infosystem/infoplugins/musixmatchplugin.h @@ -329,6 +331,8 @@ IF( UNIX ) INCLUDE( "CMakeLists.unix.txt" ) ENDIF( UNIX ) +ADD_SUBDIRECTORY( sip/jabber ) + kde4_add_app_icon( tomahawkSources "${CMAKE_CURRENT_SOURCE_DIR}/../data/icons/tomahawk-icon-*.png" ) qt4_add_resources( RC_SRCS "../resources.qrc" ) qt4_wrap_cpp( tomahawkMoc ${tomahawkHeaders} ) diff --git a/src/CMakeLists.unix.txt b/src/CMakeLists.unix.txt index 4de6eff11..3998468e5 100644 --- a/src/CMakeLists.unix.txt +++ b/src/CMakeLists.unix.txt @@ -6,7 +6,7 @@ ADD_DEFINITIONS( -fPIC ) SET( GLOOX_LIBS ${GLOOX_LIBS} resolv gloox ) -SET( OS_SPECIFIC_LINK_LIBRARIES +SET( OS_SPECIFIC_LINK_LIBRARIES ${LIBLASTFM_LIBRARY} ${GLOOX_LIBS} qxtweb-standalone diff --git a/src/database/databasecommand_resolve.cpp b/src/database/databasecommand_resolve.cpp index df09d5bcf..bd28d6f0d 100644 --- a/src/database/databasecommand_resolve.cpp +++ b/src/database/databasecommand_resolve.cpp @@ -120,7 +120,7 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) } else { - source_ptr s = APP->sourcelist().lookup( files_query.value( 13 ).toUInt() ); + source_ptr s = APP->sourcelist().get( files_query.value( 13 ).toUInt() ); if( s.isNull() ) { //qDebug() << "Skipping result for offline sourceid:" << files_query.value(13).toUInt(); diff --git a/src/jabber/jabber.h b/src/jabber/jabber.h deleted file mode 100644 index 0baa9ff8f..000000000 --- a/src/jabber/jabber.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef JABBER_H -#define JABBER_H - -/* - Pimpl of jabber_p, which inherits from a gazillion gloox classes - and it littered with public methods. - */ - -#include "jabber_p.h" - -class Jabber : public QObject -{ -Q_OBJECT - -public: - - Jabber( const QString &jid, const QString password, const QString server = "", const int port=-1 ) - : p( jid, password, server, port ) - { - } - - ~Jabber() - { - // p.disconnect(); - } - - void setProxy( QNetworkProxy* proxy ) - { - p.setProxy( proxy ); - } - -public slots: - - void start() - { - //connect( &p, SIGNAL( finished() ), - // this, SIGNAL( finished() ) ); - - connect( &p, SIGNAL( msgReceived( QString, QString ) ), - this, SIGNAL( msgReceived( QString, QString ) ) ); - - connect( &p, SIGNAL( peerOnline( QString ) ), - this, SIGNAL( peerOnline( QString ) ) ); - - connect( &p, SIGNAL( peerOffline( QString ) ), - this, SIGNAL( peerOffline( QString ) ) ); - - connect( &p, SIGNAL( connected() ), - this, SIGNAL( connected() ) ); - - connect( &p, SIGNAL( disconnected() ), - this, SIGNAL( disconnected() ) ); - - connect( &p, SIGNAL( jidChanged( QString ) ), - this, SIGNAL( jidChanged( QString ) ) ); - - connect( &p, SIGNAL( authError( int, const QString& ) ), - this, SIGNAL( authError( int, const QString& ) ) ); - - p.go(); - } - - void disconnect() - { - QMetaObject::invokeMethod( &p, - "disconnect", - Qt::QueuedConnection - ); - } - - void sendMsg( const QString& to, const QString& msg ) - { - QMetaObject::invokeMethod( &p, - "sendMsg", - Qt::QueuedConnection, - Q_ARG(const QString, to), - Q_ARG(const QString, msg) - ); - } - - void broadcastMsg( const QString &msg ) - { - QMetaObject::invokeMethod( &p, - "broadcastMsg", - Qt::QueuedConnection, - Q_ARG(const QString, msg) - ); - } - - void addContact( const QString &jid, const QString& msg = QString() ) - { - QMetaObject::invokeMethod( &p, - "addContact", - Qt::QueuedConnection, - Q_ARG(const QString, jid), - Q_ARG(const QString, msg) - ); - } - -signals: - //void finished(); - - void msgReceived( const QString&, const QString& ); - void peerOnline( const QString& ); - void peerOffline( const QString& ); - void connected(); - void disconnected(); - void jidChanged( const QString& ); - void authError( int, const QString& ); - -private: - Jabber_p p; -}; - -#endif diff --git a/src/network/servent.cpp b/src/network/servent.cpp index 0854358f5..59480e429 100644 --- a/src/network/servent.cpp +++ b/src/network/servent.cpp @@ -572,7 +572,7 @@ Servent::remoteIODeviceFactory( const result_ptr& result ) QStringList parts = result->url().mid( QString( "servent://" ).length()).split( "\t" ); const QString& sourceName = parts.at( 0 ); const QString& fileId = parts.at( 1 ); - const source_ptr& s = TomahawkApp::instance()->sourcelist().lookup( sourceName ); + const source_ptr& s = TomahawkApp::instance()->sourcelist().get( sourceName ); if ( s.isNull() ) return sp; diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 09c3a9008..938dd021e 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -16,7 +17,7 @@ #include "tomahawk/tomahawkapp.h" #include "musicscanner.h" #include "tomahawksettings.h" -#include +#include "sip/SipHandler.h" static QString @@ -121,7 +122,8 @@ SettingsDialog::~SettingsDialog() if( rejabber ) { - APP->reconnectJabber(); + APP->sipHandler()->disconnect(); + APP->sipHandler()->connect(); } } else diff --git a/src/sip/SipHandler.cpp b/src/sip/SipHandler.cpp new file mode 100644 index 000000000..230a2be83 --- /dev/null +++ b/src/sip/SipHandler.cpp @@ -0,0 +1,198 @@ +#include "SipHandler.h" +#include "sip/SipPlugin.h" + +#include +#include +#include + +#include "tomahawk/tomahawkapp.h" +#include "controlconnection.h" + + +SipHandler::SipHandler( QObject* parent ) + : QObject( parent ) +{ + loadPlugins(); +} + + +SipHandler::~SipHandler() +{ +} + + +void +SipHandler::loadPlugins() +{ + qDebug() << TomahawkApp::instance(); + qDebug() << TomahawkApp::instance()->applicationDirPath(); + QDir pluginsDir( TomahawkApp::instance()->applicationDirPath() ); + + foreach ( QString fileName, pluginsDir.entryList( QDir::Files ) ) + { + QPluginLoader loader( pluginsDir.absoluteFilePath( fileName ) ); + QObject* plugin = loader.instance(); + if ( plugin ) + { + // Connect via that plugin + qDebug() << "Trying to load plugin:" << loader.fileName(); + loadPlugin( plugin ); + } + } +} + + +void +SipHandler::loadPlugin( QObject* plugin ) +{ + SipPlugin* sip = qobject_cast(plugin); + if ( sip ) + { + qDebug() << "Loaded plugin!"; + + QObject::connect( sip, SIGNAL( peerOnline( QString ) ), SLOT( onPeerOnline( QString ) ) ); + QObject::connect( sip, SIGNAL( peerOffline( QString ) ), SLOT( onPeerOffline( QString ) ) ); + QObject::connect( sip, SIGNAL( msgReceived( QString, QString ) ), SLOT( onMessage( QString, QString ) ) ); + + QObject::connect( sip, SIGNAL( connected() ), SIGNAL( connected() ) ); + QObject::connect( sip, SIGNAL( disconnected() ), SIGNAL( disconnected() ) ); + QObject::connect( sip, SIGNAL( error( int, QString ) ), SLOT( onError( int, QString ) ) ); + + m_plugins << sip; + } +} + + +void +SipHandler::connect() +{ + foreach( SipPlugin* sip, m_plugins ) + sip->connect(); +} + + +void +SipHandler::disconnect() +{ + foreach( SipPlugin* sip, m_plugins ) + sip->disconnect(); +} + + +void +SipHandler::onPeerOnline( const QString& jid ) +{ +// qDebug() << Q_FUNC_INFO; + qDebug() << "Jabber online:" << jid; + + SipPlugin* sip = qobject_cast(sender()); + + QVariantMap m; + if( APP->servent().visibleExternally() ) + { + QString key = uuid(); + ControlConnection* conn = new ControlConnection( &APP->servent() ); + + const QString& nodeid = APP->nodeID(); + conn->setName( jid.left( jid.indexOf( "/" ) ) ); + conn->setId( nodeid ); + + // FIXME strip /resource, but we should use a UID per database install + //QString uniqname = jid.left( jid.indexOf("/") ); + //conn->setName( uniqname ); //FIXME + + // FIXME: + //QString ouruniqname = m_settings->value( "jabber/username" ).toString() + // .left( m_settings->value( "jabber/username" ).toString().indexOf("/") ); + + APP->servent().registerOffer( key, conn ); + m["visible"] = true; + m["ip"] = APP->servent().externalAddress().toString(); + m["port"] = APP->servent().externalPort(); + m["key"] = key; + m["uniqname"] = nodeid; + + qDebug() << "Asking them to connect to us:" << m; + } + else + { + m["visible"] = false; + qDebug() << "We are not visible externally:" << m; + } + + QJson::Serializer ser; + QByteArray ba = ser.serialize( m ); + + sip->sendMsg( jid, QString::fromAscii( ba ) ); +} + + +void +SipHandler::onPeerOffline( const QString& jid ) +{ +// qDebug() << Q_FUNC_INFO; + qDebug() << "Jabber offline:" << jid; +} + + +void +SipHandler::onMessage( const QString& from, const QString& msg ) +{ + qDebug() << Q_FUNC_INFO; + qDebug() << "Jabber Message:" << from << msg; + + QJson::Parser parser; + bool ok; + QVariant v = parser.parse( msg.toAscii(), &ok ); + if ( !ok || v.type() != QVariant::Map ) + { + qDebug() << "Invalid JSON in XMPP msg"; + return; + } + + QVariantMap m = v.toMap(); + /* + If only one party is externally visible, connection is obvious + If both are, peer with lowest IP address initiates the connection. + This avoids dupe connections. + */ + if ( m.value( "visible" ).toBool() ) + { + if( !APP->servent().visibleExternally() || + APP->servent().externalAddress().toString() <= m.value( "ip" ).toString() ) + { + qDebug() << "Initiate connection to" << from; + APP->servent().connectToPeer( m.value( "ip" ).toString(), + m.value( "port" ).toInt(), + m.value( "key" ).toString(), + from, + m.value( "uniqname" ).toString() ); + } + else + { + qDebug() << Q_FUNC_INFO << "They should be conecting to us..."; + } + } + else + { + qDebug() << Q_FUNC_INFO << "They are not visible, doing nothing atm"; +// if ( m_servent.visibleExternally() ) +// jabberPeerOnline( from ); // HACK FIXME + } +} + + +void +SipHandler::onError( int code, const QString& msg ) +{ + qWarning() << "Failed to connect to SIP:" << code << msg; + + if ( code == SipPlugin::AuthError ) + { + emit authError(); + } + else + { +// QTimer::singleShot( 10000, this, SLOT( reconnectJabber() ) ); + } +} diff --git a/src/sip/SipHandler.h b/src/sip/SipHandler.h new file mode 100644 index 000000000..f1ea7d3ff --- /dev/null +++ b/src/sip/SipHandler.h @@ -0,0 +1,43 @@ +#ifndef SIPHANDLER_H +#define SIPHANDLER_H + +#include +#include + +class SipPlugin; + +class SipHandler : public QObject +{ + Q_OBJECT + +public: +// static SipHandler* instance() { return s_instance ? s_instance : new SipHandler(); } + + SipHandler( QObject* parent ); + ~SipHandler(); + +public slots: + void addContact( const QString& id ) { qDebug() << Q_FUNC_INFO << id; } + + void connect(); + void disconnect(); + +signals: + void connected(); + void disconnected(); + void authError(); + +private slots: + void onMessage( const QString&, const QString& ); + void onPeerOffline( const QString& ); + void onPeerOnline( const QString& ); + void onError( int code, const QString& msg ); + +private: + void loadPlugins(); + void loadPlugin( QObject* plugin ); + + QList< SipPlugin* > m_plugins; +}; + +#endif diff --git a/src/sip/SipPlugin.cpp b/src/sip/SipPlugin.cpp new file mode 100644 index 000000000..d33fff114 --- /dev/null +++ b/src/sip/SipPlugin.cpp @@ -0,0 +1,2 @@ +#include + diff --git a/src/sip/SipPlugin.h b/src/sip/SipPlugin.h new file mode 100644 index 000000000..e52883cfc --- /dev/null +++ b/src/sip/SipPlugin.h @@ -0,0 +1,34 @@ +#ifndef SIPPLUGIN_H +#define SIPPLUGIN_H + +#include +#include + +class SipPlugin : public QObject +{ + Q_OBJECT + +public: + enum SipErrorCode { AuthError, ConnectionError }; // Placeholder for errors, to be defined + + virtual ~SipPlugin() {} + + virtual bool connect() = 0; + virtual void disconnect() = 0; + + virtual void addContact( const QString &jid, const QString& msg = QString() ) = 0; + virtual void sendMsg( const QString& to, const QString& msg ) = 0; + +signals: + void error( int, const QString& ); + void connected(); + void disconnected(); + + void peerOnline( const QString& ); + void peerOffline( const QString& ); + void msgReceived( const QString&, const QString& ); +}; + +Q_DECLARE_INTERFACE( SipPlugin, "tomahawk.Sip/1.0" ) + +#endif diff --git a/src/sip/jabber/CMakeLists.txt b/src/sip/jabber/CMakeLists.txt new file mode 100644 index 000000000..0f8303f20 --- /dev/null +++ b/src/sip/jabber/CMakeLists.txt @@ -0,0 +1,30 @@ +project( tomahawk ) + +include( ${QT_USE_FILE} ) +add_definitions( ${QT_DEFINITIONS} ) +add_definitions( -DQT_PLUGIN ) +add_definitions( -DQT_SHARED ) + +set( jabberSources + jabber.cpp + jabber_p.cpp +) + +set( jabberHeaders + jabber.h + jabber_p.h +) + +include_directories( . ${CMAKE_CURRENT_BINARY_DIR} .. + ${QT_INCLUDE_DIR} +) + +qt4_wrap_cpp( jabberMoc ${jabberHeaders} ) +add_library( sip_jabber SHARED ${jabberSources} ${jabberMoc} ) + +target_link_libraries( sip_jabber + ${QT_LIBRARIES} + ${GLOOX_LIBS} +) + +install( TARGETS sip_jabber DESTINATION . ) diff --git a/src/sip/jabber/jabber.cpp b/src/sip/jabber/jabber.cpp new file mode 100644 index 000000000..75ec5ae70 --- /dev/null +++ b/src/sip/jabber/jabber.cpp @@ -0,0 +1,63 @@ +#include "jabber.h" + +#include "tomahawk/tomahawkapp.h" +#include "tomahawksettings.h" + + +void +JabberPlugin::setProxy( QNetworkProxy* proxy ) +{ + p->setProxy( proxy ); +} + + +bool +JabberPlugin::connect() +{ + if ( !APP->settings()->value( "jabber/autoconnect", true ).toBool() ) + return false; + + QString jid = APP->settings()->value( "jabber/username" ).toString(); + QString server = APP->settings()->value( "jabber/server" ).toString(); + QString password = APP->settings()->value( "jabber/password" ).toString(); + unsigned int port = APP->settings()->value( "jabber/port", 5222 ).toUInt(); + + // gtalk check + if( server.isEmpty() && ( jid.contains( "@gmail.com" ) || jid.contains( "@googlemail.com" ) ) ) + { + qDebug() << "Setting jabber server to talk.google.com"; + server = "talk.google.com"; + } + + if ( port < 1 || port > 65535 || jid.isEmpty() || password.isEmpty() ) + { + qDebug() << "Jabber credentials look wrong, not connecting"; + return false; + } + + p = new Jabber_p( jid, password, server, port ); + + QObject::connect( p, SIGNAL( peerOnline( QString ) ), SIGNAL( peerOnline( QString ) ) ); + QObject::connect( p, SIGNAL( peerOffline( QString ) ), SIGNAL( peerOffline( QString ) ) ); + QObject::connect( p, SIGNAL( msgReceived( QString, QString ) ), SIGNAL( msgReceived( QString, QString ) ) ); + + QObject::connect( p, SIGNAL( connected() ), SIGNAL( connected() ) ); + QObject::connect( p, SIGNAL( disconnected() ), SIGNAL( disconnected() ) ); + QObject::connect( p, SIGNAL( authError( int, QString ) ), SLOT( onAuthError( int, QString ) ) ); + + p->go(); + + return true; +} + + +void +JabberPlugin::onAuthError( int code, const QString& message ) +{ + if ( code == gloox::ConnAuthenticationFailed ) + emit error( SipPlugin::AuthError, message ); + else + emit error( SipPlugin::ConnectionError, message ); +} + +Q_EXPORT_PLUGIN2( sip, JabberPlugin ) diff --git a/src/sip/jabber/jabber.h b/src/sip/jabber/jabber.h new file mode 100644 index 000000000..cb9187002 --- /dev/null +++ b/src/sip/jabber/jabber.h @@ -0,0 +1,68 @@ +#ifndef JABBER_H +#define JABBER_H + +#include "SipPlugin.h" +#include "jabber_p.h" + +class JabberPlugin : public SipPlugin +{ + Q_OBJECT + Q_INTERFACES( SipPlugin ) + +public: + JabberPlugin() + : p( 0 ) + {} + + virtual ~JabberPlugin() { delete p; } + + void setProxy( QNetworkProxy* proxy ); + + virtual bool connect(); + +public slots: + void disconnect() + { + QMetaObject::invokeMethod( p, + "disconnect", + Qt::QueuedConnection + ); + } + + void sendMsg( const QString& to, const QString& msg ) + { + QMetaObject::invokeMethod( p, + "sendMsg", + Qt::QueuedConnection, + Q_ARG(const QString, to), + Q_ARG(const QString, msg) + ); + } + + void broadcastMsg( const QString &msg ) + { + QMetaObject::invokeMethod( p, + "broadcastMsg", + Qt::QueuedConnection, + Q_ARG(const QString, msg) + ); + } + + void addContact( const QString &jid, const QString& msg = QString() ) + { + QMetaObject::invokeMethod( p, + "addContact", + Qt::QueuedConnection, + Q_ARG(const QString, jid), + Q_ARG(const QString, msg) + ); + } + +private slots: + void onAuthError( int, const QString& ); + +private: + Jabber_p* p; +}; + +#endif diff --git a/src/jabber/jabber_p.cpp b/src/sip/jabber/jabber_p.cpp similarity index 100% rename from src/jabber/jabber_p.cpp rename to src/sip/jabber/jabber_p.cpp diff --git a/src/jabber/jabber_p.h b/src/sip/jabber/jabber_p.h similarity index 100% rename from src/jabber/jabber_p.h rename to src/sip/jabber/jabber_p.h diff --git a/src/sourcelist.cpp b/src/sourcelist.cpp index 45a853640..2999bbaeb 100644 --- a/src/sourcelist.cpp +++ b/src/sourcelist.cpp @@ -79,7 +79,7 @@ SourceList::sources() const source_ptr -SourceList::lookup( unsigned int id ) const +SourceList::get( unsigned int id ) const { QMutexLocker lock( &m_mut ); return m_sources.value( m_sources_id2name.value( id ) ); @@ -87,7 +87,7 @@ SourceList::lookup( unsigned int id ) const source_ptr -SourceList::lookup( const QString& username ) const +SourceList::get( const QString& username ) const { QMutexLocker lock( &m_mut ); return m_sources.value( username ); diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 9efd89721..ee3466ecd 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -14,14 +14,13 @@ #include "database/databasecollection.h" #include "database/databasecommand_collectionstats.h" #include "database/databaseresolver.h" -#include "jabber/jabber.h" +#include "sip/SipHandler.h" #include "utils/tomahawkutils.h" #include "xmppbot/xmppbot.h" #include "web/api_v1.h" #include "scriptresolver.h" #include "audioengine.h" -#include "controlconnection.h" #include "tomahawkzeroconf.h" #ifndef TOMAHAWK_HEADLESS @@ -154,16 +153,6 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) m_nam = new QNetworkAccessManager; #endif -#ifndef TOMAHAWK_HEADLESS - if ( !m_headless ) - { - m_mainwindow = new TomahawkWindow(); - m_mainwindow->setWindowTitle( "Tomahawk" ); - m_mainwindow->show(); - connect( m_mainwindow, SIGNAL( settingsChanged() ), SIGNAL( settingsChanged() ) ); - } -#endif - // Set up proxy if( m_settings->proxyType() != QNetworkProxy::NoProxy && !m_settings->proxyHost().isEmpty() ) { @@ -185,6 +174,22 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) boost::bind( &TomahawkApp::httpIODeviceFactory, this, _1 ); this->registerIODeviceFactory( "http", fac ); + if( !arguments().contains("--nojabber") ) + { + setupSIP(); + m_xmppBot = new XMPPBot( this ); + } + +#ifndef TOMAHAWK_HEADLESS + if ( !m_headless ) + { + m_mainwindow = new TomahawkWindow(); + m_mainwindow->setWindowTitle( "Tomahawk" ); + m_mainwindow->show(); + connect( m_mainwindow, SIGNAL( settingsChanged() ), SIGNAL( settingsChanged() ) ); + } +#endif + setupPipeline(); initLocalCollection(); startServent(); @@ -193,9 +198,6 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) if( arguments().contains( "--http" ) || settings()->value( "network/http", true ).toBool() ) startHTTP(); - if( !arguments().contains("--nojabber") ) setupJabber(); - m_xmppBot = new XMPPBot( this ); - if ( !arguments().contains( "--nozeroconf" ) ) { // advertise our servent on the LAN @@ -205,12 +207,14 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) m_zeroconf->advertise(); } - #ifndef TOMAHAWK_HEADLESS + m_sipHandler->connect(); + +#ifndef TOMAHAWK_HEADLESS if ( !m_settings->hasScannerPath() ) { m_mainwindow->showSettingsDialog(); } - #endif +#endif } @@ -218,10 +222,7 @@ TomahawkApp::~TomahawkApp() { qDebug() << Q_FUNC_INFO; - if ( !m_jabber.isNull() ) - { - m_jabber.clear(); - } + delete m_sipHandler; #ifndef TOMAHAWK_HEADLESS delete m_mainwindow; @@ -432,218 +433,13 @@ TomahawkApp::loadPlugins() void -TomahawkApp::setupJabber() -{ - qDebug() << Q_FUNC_INFO; - if ( !m_jabber.isNull() ) - return; - if ( !m_settings->value( "jabber/autoconnect", true ).toBool() ) - return; - - QString jid = m_settings->value( "jabber/username" ).toString(); - QString server = m_settings->value( "jabber/server" ).toString(); - QString password = m_settings->value( "jabber/password" ).toString(); - unsigned int port = m_settings->value( "jabber/port", 5222 ).toUInt(); - - // gtalk check - if( server.isEmpty() && ( jid.contains("@gmail.com") || jid.contains("@googlemail.com") ) ) - { - qDebug() << "Setting jabber server to talk.google.com"; - server = "talk.google.com"; - } - - if ( port < 1 || port > 65535 || jid.isEmpty() || password.isEmpty() ) - { - qDebug() << "Jabber credentials look wrong, not connecting"; - return; - } - - m_jabber = QSharedPointer( new Jabber( jid, password, server, port ) ); - - connect( m_jabber.data(), SIGNAL( peerOnline( QString ) ), SLOT( jabberPeerOnline( QString ) ) ); - connect( m_jabber.data(), SIGNAL( peerOffline( QString ) ), SLOT( jabberPeerOffline( QString ) ) ); - connect( m_jabber.data(), SIGNAL( msgReceived( QString, QString ) ), SLOT( jabberMessage( QString, QString ) ) ); - - connect( m_jabber.data(), SIGNAL( connected() ), SLOT( jabberConnected() ) ); - connect( m_jabber.data(), SIGNAL( disconnected() ), SLOT( jabberDisconnected() ) ); - connect( m_jabber.data(), SIGNAL( authError( int, QString ) ), SLOT( jabberAuthError( int, QString ) ) ); - - m_jabber->setProxy( m_proxy ); - m_jabber->start(); -} - - -void -TomahawkApp::reconnectJabber() -{ - m_jabber.clear(); - setupJabber(); -} - - -void -TomahawkApp::jabberAddContact( const QString& jid ) -{ - m_jabber->addContact( jid ); -} - - -void -TomahawkApp::jabberAuthError( int code, const QString& msg ) -{ - qWarning() << "Failed to connect to jabber" << code << msg; - -#ifndef TOMAHAWK_HEADLESS - if( m_mainwindow ) - { - m_mainwindow->setWindowTitle( QString("Tomahawk [jabber: %1, portfwd: %2]") - .arg( "AUTH_ERROR" ) - .arg( (servent().externalPort() > 0) ? QString( "YES:%1" ).arg(servent().externalPort()) :"NO" ) ); - - if ( code == gloox::ConnAuthenticationFailed ) - { - QMessageBox::warning( m_mainwindow, - "Jabber Auth Error", - QString("Error connecting to Jabber (%1) %2").arg(code).arg(msg), - QMessageBox::Ok ); - } - } -#endif - - if ( code != gloox::ConnAuthenticationFailed ) - QTimer::singleShot( 10000, this, SLOT( reconnectJabber() ) ); -} - - -void -TomahawkApp::jabberConnected() +TomahawkApp::setupSIP() { qDebug() << Q_FUNC_INFO; -#ifndef TOMAHAWK_HEADLESS - if( m_mainwindow ) - { - m_mainwindow->setWindowTitle( QString("Tomahawk [jabber: %1, portfwd: %2]") - .arg( "CONNECTED" ) - .arg( (servent().externalPort() > 0) ? QString( "YES:%1" ).arg(servent().externalPort()):"NO" ) ); - } -#endif -} + m_sipHandler = new SipHandler( this ); - -void -TomahawkApp::jabberDisconnected() -{ - qDebug() << Q_FUNC_INFO; - -#ifndef TOMAHAWK_HEADLESS - if( m_mainwindow ) - { - m_mainwindow->setWindowTitle( QString("Tomahawk [jabber: %1, portfwd: %2]") - .arg( "DISCONNECTED" ) - .arg( (servent().externalPort() > 0) ? QString( "YES:%1" ).arg(servent().externalPort()):"NO" ) ); - } -#endif -} - - -void -TomahawkApp::jabberPeerOnline( const QString& jid ) -{ -// qDebug() << Q_FUNC_INFO; -// qDebug() << "Jabber Peer online:" << jid; - - QVariantMap m; - if( m_servent.visibleExternally() ) - { - QString key = uuid(); - ControlConnection* conn = new ControlConnection( &m_servent ); - - const QString& nodeid = APP->nodeID(); - conn->setName( jid.left( jid.indexOf( "/" ) ) ); - conn->setId( nodeid ); - - // FIXME strip /resource, but we should use a UID per database install - //QString uniqname = jid.left( jid.indexOf("/") ); - //conn->setName( uniqname ); //FIXME - - // FIXME: - //QString ouruniqname = m_settings->value( "jabber/username" ).toString() - // .left( m_settings->value( "jabber/username" ).toString().indexOf("/") ); - - m_servent.registerOffer( key, conn ); - m["visible"] = true; - m["ip"] = m_servent.externalAddress().toString(); - m["port"] = m_servent.externalPort(); - m["key"] = key; - m["uniqname"] = nodeid; - - qDebug() << "Asking them to connect to us:" << m; - } - else - { - m["visible"] = false; - qDebug() << "We are not visible externally:" << m; - } - - QJson::Serializer ser; - QByteArray ba = ser.serialize( m ); - m_jabber->sendMsg( jid, QString::fromAscii( ba ) ); -} - - -void -TomahawkApp::jabberPeerOffline( const QString& jid ) -{ -// qDebug() << Q_FUNC_INFO; -// qDebug() << "Jabber Peer offline:" << jid; -} - - -void -TomahawkApp::jabberMessage( const QString& from, const QString& msg ) -{ - qDebug() << Q_FUNC_INFO; - qDebug() << "Jabber Message:" << from << msg; - - QJson::Parser parser; - bool ok; - QVariant v = parser.parse( msg.toAscii(), &ok ); - if ( !ok || v.type() != QVariant::Map ) - { - qDebug() << "Invalid JSON in XMPP msg"; - return; - } - - QVariantMap m = v.toMap(); - /* - If only one party is externally visible, connection is obvious - If both are, peer with lowest IP address initiates the connection. - This avoids dupe connections. - */ - if ( m.value( "visible" ).toBool() ) - { - if( !m_servent.visibleExternally() || - m_servent.externalAddress().toString() <= m.value( "ip" ).toString() ) - { - qDebug() << "Initiate connection to" << from; - m_servent.connectToPeer( m.value( "ip" ).toString(), - m.value( "port" ).toInt(), - m.value( "key" ).toString(), - from, - m.value( "uniqname" ).toString() ); - } - else - { - qDebug() << Q_FUNC_INFO << "They should be conecting to us..."; - } - } - else - { - qDebug() << Q_FUNC_INFO << "They are not visible, doing nothing atm"; -// if ( m_servent.visibleExternally() ) -// jabberPeerOnline( from ); // HACK FIXME - } +// m_sipHandler->setProxy( m_proxy ); } diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index 580f0f5c5..56bd9166e 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -20,6 +20,8 @@ #include "database/databasecommand_collectionstats.h" #include "topbar/topbar.h" +#include "sip/SipHandler.h" + #include "audiocontrols.h" #include "controlconnection.h" #include "database.h" @@ -168,6 +170,11 @@ TomahawkWindow::setupSignals() connect( ui->actionCreatePlaylist, SIGNAL( triggered() ), SLOT( createPlaylist() )); connect( ui->actionAboutTomahawk, SIGNAL( triggered() ), SLOT( showAboutTomahawk() ) ); connect( ui->actionExit, SIGNAL( triggered() ), APP, SLOT( quit() ) ); + + // + connect( APP->sipHandler(), SIGNAL( connected() ), SLOT( onSipConnected() ) ); + connect( APP->sipHandler(), SIGNAL( disconnected() ), SLOT( onSipDisconnected() ) ); + connect( APP->sipHandler(), SIGNAL( authError() ), SLOT( onSipError() ) ); } @@ -293,7 +300,7 @@ TomahawkWindow::addFriendManually() return; qDebug() << "Attempting to add jabber contact to roster:" << id; - APP->jabberAddContact( id ); + APP->sipHandler()->addContact( id ); } @@ -338,6 +345,32 @@ TomahawkWindow::onPlaybackLoading( const Tomahawk::result_ptr& result ) } +void +TomahawkWindow::onSipConnected() +{ + ui->statusButton->setText( tr( "Online" ) ); +} + + +void +TomahawkWindow::onSipDisconnected() +{ + ui->statusButton->setText( tr( "Offline" ) ); +} + + +void +TomahawkWindow::onSipError() +{ + onSipDisconnected(); + + QMessageBox::warning( this, + tr( "Authentication Error" ), + QString( "Error connecting to SIP: Authentication failed!" ), + QMessageBox::Ok ); +} + + void TomahawkWindow::setWindowTitle( const QString& title ) { diff --git a/src/tomahawkwindow.h b/src/tomahawkwindow.h index 2649dc1b3..06a574c5b 100644 --- a/src/tomahawkwindow.h +++ b/src/tomahawkwindow.h @@ -50,6 +50,11 @@ public slots: private slots: void scanFinished(); void rescanCollectionManually(); + + void onSipConnected(); + void onSipDisconnected(); + void onSipError(); + void addPeerManually(); void addFriendManually(); diff --git a/src/tomahawkwindow.ui b/src/tomahawkwindow.ui index d91f28a55..bbd71a4ae 100644 --- a/src/tomahawkwindow.ui +++ b/src/tomahawkwindow.ui @@ -23,9 +23,9 @@ - + - PushButton +