diff --git a/CMakeLists.txt b/CMakeLists.txt index 71c62fdea..7cd00c3c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,10 +8,10 @@ ENDIF( ${CMAKE_VERSION} VERSION_GREATER 2.8.3 ) ### ### Tomahawk application info ### -SET( ORGANIZATION_NAME "Tomahawk" ) -SET( ORGANIZATION_DOMAIN "tomahawk-player.org" ) -SET( APPLICATION_NAME "Tomahawk" ) -SET( VERSION "0.0.3" ) +SET( TOMAHAWK_ORGANIZATION_NAME "Tomahawk" ) +SET( TOMAHAWK_ORGANIZATION_DOMAIN "tomahawk-player.org" ) +SET( TOMAHAWK_APPLICATION_NAME "Tomahawk" ) +SET( TOMAHAWK_VERSION "0.0.3" ) # set paths @@ -50,6 +50,28 @@ macro_log_feature(QJSON_FOUND "QJson" "Qt library that maps JSON data to QVarian macro_optional_find_package(Taglib 1.6.0) macro_log_feature(TAGLIB_FOUND "TagLib" "Audio Meta-Data Library" "http://developer.kde.org/~wheeler/taglib.html" TRUE "" "taglib is needed for reading meta data from audio files") +# this installs headers and such and should really be handled in a separate package by packagers +IF( INTERNAL_JREEN ) + ADD_SUBDIRECTORY( thirdparty/jreen ) + SET( LIBJREEN_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/include ) + + IF( UNIX AND NOT APPLE ) + SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.so ) + ENDIF( UNIX AND NOT APPLE ) + IF( APPLE ) + SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.dylib ) + ENDIF( APPLE ) + IF( WIN32 ) + SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.dll ) + ENDIF( WIN32 ) + + SET( LIBJREEN_FOUND true ) + MESSAGE(STATUS "INTERNAL libjreen: ${LIBJREEN_INCLUDE_DIR}, ${LIBJREEN_LIBRARY}") +ELSE( INTERNAL_JREEN ) + macro_optional_find_package(Jreen) +ENDIF( INTERNAL_JREEN ) +macro_log_feature(LIBJREEN_FOUND "Jreen" "Qt XMPP Library" "http://gitorious.org/jreen/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin. \n\n Use -DINTERNAL_JREEN=ON to build the git submodule inside Tomahawk \n Be aware this installs a full jreen with headers and everything!") + # we need pthreads too find_package(Threads) @@ -65,32 +87,6 @@ ENDIF() include( CheckTagLibFileName ) check_taglib_filename( COMPLEX_TAGLIB_FILENAME ) -# optional -IF( ENABLE_JREEN ) - macro_optional_find_package(Jreen) - IF( LIBJREEN_FOUND ) - macro_log_feature(JREEN_FOUND "Jreen" "Qt XMPP library" "http://gitorious.org/jreen" FALSE "" "Jreen is needed for the alternative/new Jabber SIP plugin. Built automatically inside Tomahawk, if not installed systemwide and ENABLE_JREEN is true") - ELSE( LIBJREEN_FOUND ) - SET( OLD_C_FLAGS ${CMAKE_C_FLAGS} ) - SET( CMAKE_C_FLAGS ${CLEAN_C_FLAGS} ) - ADD_SUBDIRECTORY( thirdparty/jreen ) - SET( LIBJREEN_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/include ) - IF( UNIX AND NOT APPLE ) - SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.so ) - ENDIF( UNIX AND NOT APPLE ) - IF( WIN32 ) - SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.dll ) - ENDIF( WIN32 ) - SET( LIBJREEN_FOUND true ) - MESSAGE(STATUS "Internal libjreen: ${LIBJREEN_INCLUDE_DIR}, ${LIBJREEN_LIBRARY}") - SET( CMAKE_C_FLAGS ${OLD_C_FLAGS} ) - ENDIF( LIBJREEN_FOUND ) -ELSE( LIBJREEN_FOUND ) - macro_optional_find_package(Gloox 1.0) - macro_log_feature(GLOOX_FOUND "Gloox" "A portable high-level Jabber/XMPP library for C++" "http://camaya.net/gloox" FALSE "" "Gloox is needed for the Jabber SIP plugin and the XMPP-Bot") - -ENDIF( ENABLE_JREEN ) - IF( WIN32 ) find_library(QTSPARKLE_LIBRARIES qtsparkle) ENDIF( WIN32 ) diff --git a/CMakeModules/FindJreen.cmake b/CMakeModules/FindJreen.cmake index 301eb24e7..9174ca65a 100644 --- a/CMakeModules/FindJreen.cmake +++ b/CMakeModules/FindJreen.cmake @@ -6,15 +6,15 @@ # LIBJREEN_FOUND, whether libjreen was found -find_path(LIBJREEN_INCLUDE_DIR NAMES jreen.h +find_path(LIBJREEN_INCLUDE_DIR NAMES jreen/jreen.h HINTS ~/usr/include /opt/local/include /usr/include /usr/local/include /opt/kde4/include + ${CMAKE_INSTALL_PREFIX}/include ${KDE4_INCLUDE_DIR} - PATH_SUFFIXES jreen ) find_library( LIBJREEN_LIBRARY NAMES jreen @@ -25,6 +25,8 @@ find_library( LIBJREEN_LIBRARY NAMES jreen /usr/lib64 /usr/local/lib /opt/kde4/lib + ${CMAKE_INSTALL_PREFIX}/lib + ${CMAKE_INSTALL_PREFIX}/lib64 ${KDE4_LIB_DIR} ) @@ -33,7 +35,7 @@ if(LIBJREEN_INCLUDE_DIR AND LIBJREEN_LIBRARY) set(LIBJREEN_FOUND TRUE) message(STATUS "Found libjreen: ${LIBJREEN_INCLUDE_DIR}, ${LIBJREEN_LIBRARY}") else(LIBJREEN_INCLUDE_DIR AND LIBJREEN_LIBRARY) - set(LIBJREEN_FOUND FALSE) + set(LIBJREEN_FOUND FALSE) if (LIBJREEN_FIND_REQUIRED) message(FATAL_ERROR "Could NOT find required package libjreen") endif(LIBJREEN_FIND_REQUIRED) diff --git a/include/tomahawk/tomahawkapp.h b/include/tomahawk/tomahawkapp.h index 2d55f3a1b..1547254dd 100644 --- a/include/tomahawk/tomahawkapp.h +++ b/include/tomahawk/tomahawkapp.h @@ -98,9 +98,6 @@ public: virtual void activate(); virtual bool loadUrl( const QString& url ); - // because QApplication::arguments() is expensive - bool scrubFriendlyName() const { return m_scrubFriendlyName; } - public slots: void instanceStarted( KDSingleApplicationGuard::Instance ); diff --git a/src/CMakeLists.osx.txt b/src/CMakeLists.osx.txt index 0488b2f71..9d43c8e65 100644 --- a/src/CMakeLists.osx.txt +++ b/src/CMakeLists.osx.txt @@ -37,7 +37,7 @@ if (APPLE) # We have to change the URL in the Info.plist file :-/ FILE(READ ${CMAKE_SOURCE_DIR}/admin/mac/Info.plist plist) STRING( REPLACE "TOMAHAWK_VERSION" - ${VERSION} + ${TOMAHAWK_VERSION} edited_plist # save in this variable "${plist}" # from the contents of this var ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f1ac32b61..e339fa9a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,8 +32,6 @@ ENDIF() #ENDFOREACH( moddir ) SET( tomahawkSources ${tomahawkSources} - sip/SipHandler.cpp - web/api_v1.cpp resolvers/scriptresolver.cpp @@ -70,7 +68,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} SET( tomahawkHeaders ${tomahawkHeaders} "${TOMAHAWK_INC_DIR}/tomahawk/tomahawkapp.h" - sip/SipHandler.h web/api_v1.h diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index 8b74784fc..373756f78 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -213,13 +213,13 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result ) onPlaybackLoading( result ); - Tomahawk::InfoSystem::InfoCustomData trackInfo; - trackInfo["artist"] = QVariant::fromValue< QString >( result->artist()->name() ); - trackInfo["album"] = QVariant::fromValue< QString >( result->album()->name() ); + Tomahawk::InfoSystem::InfoCriteriaHash trackInfo; + trackInfo["artist"] = result->artist()->name(); + trackInfo["album"] = result->album()->name(); Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( s_acInfoIdentifier, Tomahawk::InfoSystem::InfoAlbumCoverArt, - QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); + QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); } diff --git a/src/config.h.in b/src/config.h.in index f8246a54d..7ac3931a2 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -1,14 +1,15 @@ #ifndef CONFIG_H_IN #define CONFIG_H_IN -#cmakedefine ORGANIZATION_NAME "${ORGANIZATION_NAME}" -#cmakedefine ORGANIZATION_DOMAIN "${ORGANIZATION_DOMAIN}" -#cmakedefine APPLICATION_NAME "${APPLICATION_NAME}" -#cmakedefine VERSION "${VERSION}" +#cmakedefine TOMAHAWK_ORGANIZATION_NAME "${TOMAHAWK_ORGANIZATION_NAME}" +#cmakedefine TOMAHAWK_ORGANIZATION_DOMAIN "${TOMAHAWK_ORGANIZATION_DOMAIN}" +#cmakedefine TOMAHAWK_APPLICATION_NAME "${TOMAHAWK_APPLICATION_NAME}" +#cmakedefine TOMAHAWK_VERSION "${TOMAHAWK_VERSION}" #cmakedefine DEBUG_BUILD #define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" +#define CMAKE_SYSTEM "${CMAKE_SYSTEM}" #cmakedefine SNOW_LEOPARD #cmakedefine LEOPARD diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 129bb8756..ca48502c7 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -30,6 +30,7 @@ set( libSources viewmanager.cpp sip/SipPlugin.cpp + sip/SipHandler.cpp audio/madtranscode.cpp audio/dummytranscode.cpp @@ -188,6 +189,7 @@ set( libHeaders playlist.h sip/SipPlugin.h + sip/SipHandler.h audio/transcodeinterface.h audio/madtranscode.h diff --git a/src/libtomahawk/audio/flactranscode.cpp b/src/libtomahawk/audio/flactranscode.cpp index c66c5a557..22f339c49 100644 --- a/src/libtomahawk/audio/flactranscode.cpp +++ b/src/libtomahawk/audio/flactranscode.cpp @@ -70,7 +70,7 @@ FLACTranscode::processData( const QByteArray& data, bool finish ) m_buffer.append( data ); m_mutex.unlock(); - while ( m_buffer.size() >= FLAC_BUFFER ) + while ( m_buffer.size() >= FLAC_BUFFER || ( finish && !m_buffer.isEmpty() ) ) { process_single(); } diff --git a/src/libtomahawk/collection.cpp b/src/libtomahawk/collection.cpp index ed186be37..d9f265d12 100644 --- a/src/libtomahawk/collection.cpp +++ b/src/libtomahawk/collection.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -51,7 +51,7 @@ Collection::name() const } -const +const source_ptr& Collection::source() const { return m_source; @@ -64,11 +64,11 @@ Collection::addPlaylist( const Tomahawk::playlist_ptr& p ) qDebug() << Q_FUNC_INFO; QList toadd; toadd << p; - m_playlists.append( toadd ); + m_playlists.insert( p->guid(), p ); qDebug() << Q_FUNC_INFO << "Collection name" << name() << "from source id" << source()->id() - << "numplaylists:" << m_playlists.length(); + << "numplaylists:" << m_playlists.count(); emit playlistsAdded( toadd ); } @@ -79,11 +79,11 @@ Collection::addDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ) qDebug() << Q_FUNC_INFO; QList toadd; toadd << p; - m_dynplaylists.append( toadd ); - + m_dynplaylists.insert( p->guid(), p ); + qDebug() << Q_FUNC_INFO << "Collection name" << name() - << "from source id" << source()->id() - << "numplaylists:" << m_playlists.length(); + << "from source id" << source()->id() + << "numplaylists:" << m_playlists.count(); emit dynamicPlaylistsAdded( toadd ); } @@ -94,11 +94,11 @@ Collection::deletePlaylist( const Tomahawk::playlist_ptr& p ) qDebug() << Q_FUNC_INFO; QList todelete; todelete << p; - m_playlists.removeAll( p ); + m_playlists.remove( p->guid() ); qDebug() << Q_FUNC_INFO << "Collection name" << name() << "from source id" << source()->id() - << "numplaylists:" << m_playlists.length(); + << "numplaylists:" << m_playlists.count(); emit playlistsDeleted( todelete ); } @@ -109,11 +109,11 @@ Collection::deleteDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ) qDebug() << Q_FUNC_INFO; QList todelete; todelete << p; - m_dynplaylists.removeAll( p ); + m_dynplaylists.remove( p->guid() ); qDebug() << Q_FUNC_INFO << "Collection name" << name() << "from source id" << source()->id() - << "numplaylists:" << m_playlists.length(); + << "numplaylists:" << m_playlists.count(); emit dynamicPlaylistsDeleted( todelete ); } @@ -121,33 +121,15 @@ Collection::deleteDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ) playlist_ptr Collection::playlist( const QString& guid ) { - foreach( const playlist_ptr& pp, m_playlists ) - { - if( pp->guid() == guid ) - return pp; - } - - // TODO do we really want to do this? - foreach( const dynplaylist_ptr& pp, m_dynplaylists ) - { - if( pp->guid() == guid ) - return pp.staticCast(); - } - - return playlist_ptr(); + return m_playlists.value( guid, playlist_ptr() ); } dynplaylist_ptr Collection::dynamicPlaylist( const QString& guid ) { - foreach( const dynplaylist_ptr& pp, m_dynplaylists ) - { - if( pp->guid() == guid ) - return pp; - } - return dynplaylist_ptr(); + return m_dynplaylists.value( guid, dynplaylist_ptr() ); } @@ -155,8 +137,9 @@ void Collection::setPlaylists( const QList& plists ) { qDebug() << Q_FUNC_INFO << plists.count(); + foreach ( const playlist_ptr& p, plists ) + m_playlists.insert( p->guid(), p ); - m_playlists.append( plists ); emit playlistsAdded( plists ); } @@ -166,7 +149,8 @@ Collection::setDynamicPlaylists( const QList< Tomahawk::dynplaylist_ptr >& plist { qDebug() << Q_FUNC_INFO << plists.count(); - m_dynplaylists.append( plists ); + foreach ( const dynplaylist_ptr& p, plists ) + m_dynplaylists.insert( p->guid(), p ); // emit dynamicPlaylistsAdded( plists ); } diff --git a/src/libtomahawk/collection.h b/src/libtomahawk/collection.h index 33441b2e0..64f553b6e 100644 --- a/src/libtomahawk/collection.h +++ b/src/libtomahawk/collection.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -68,8 +68,8 @@ public: virtual void addDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ); virtual void deleteDynamicPlaylist( const Tomahawk::dynplaylist_ptr& p ); - virtual QList< Tomahawk::playlist_ptr > playlists() { return m_playlists; } - virtual QList< Tomahawk::dynplaylist_ptr > dynamicPlaylists() { return m_dynplaylists; } + virtual QList< Tomahawk::playlist_ptr > playlists() { return m_playlists.values(); } + virtual QList< Tomahawk::dynplaylist_ptr > dynamicPlaylists() { return m_dynplaylists.values(); } virtual QList< Tomahawk::query_ptr > tracks() { return m_tracks; } const source_ptr& source() const; @@ -107,8 +107,8 @@ private: source_ptr m_source; QList< Tomahawk::query_ptr > m_tracks; - QList< Tomahawk::playlist_ptr > m_playlists; - QList< Tomahawk::dynplaylist_ptr > m_dynplaylists; + QHash< QString, Tomahawk::playlist_ptr > m_playlists; + QHash< QString, Tomahawk::dynplaylist_ptr > m_dynplaylists; }; }; // ns diff --git a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp index 20f09981e..d34367008 100644 --- a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp @@ -134,12 +134,12 @@ LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVarian void LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) { - if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() || !m_scrobbler ) + if ( !data.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() || !m_scrobbler ) { dataError( caller, type, data, customData ); return; } - InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >(); + InfoCriteriaHash hash = data.value< Tomahawk::InfoSystem::InfoCriteriaHash >(); if ( !hash.contains( "title" ) || !hash.contains( "artist" ) || !hash.contains( "album" ) || !hash.contains( "duration" ) ) { dataError( caller, type, data, customData ); @@ -149,10 +149,11 @@ LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVar m_track = lastfm::MutableTrack(); m_track.stamp(); - m_track.setTitle( hash["title"].toString() ); - m_track.setArtist( hash["artist"].toString() ); - m_track.setAlbum( hash["album"].toString() ); - m_track.setDuration( hash["duration"].toUInt() ); + m_track.setTitle( hash["title"] ); + m_track.setArtist( hash["artist"] ); + m_track.setAlbum( hash["album"] ); + bool ok; + m_track.setDuration( hash["duration"].toUInt( &ok ) ); m_track.setSource( lastfm::Track::Player ); m_scrobbler->nowPlaying( m_track ); @@ -183,12 +184,12 @@ void LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) { qDebug() << Q_FUNC_INFO; - if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() ) + if ( !data.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() ) { dataError( caller, type, data, customData ); return; } - InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >(); + InfoCriteriaHash hash = data.value< Tomahawk::InfoSystem::InfoCriteriaHash >(); if ( !hash.contains( "artist" ) || !hash.contains( "album" ) ) { dataError( caller, type, data, customData ); @@ -196,8 +197,8 @@ LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const Q } Tomahawk::InfoSystem::InfoCriteriaHash criteria; - criteria["artist"] = hash["artist"].toString(); - criteria["album"] = hash["album"].toString(); + criteria["artist"] = hash["artist"]; + criteria["album"] = hash["album"]; emit getCachedInfo( criteria, 2419200000, caller, type, data, customData ); } @@ -207,12 +208,12 @@ void LastFmPlugin::fetchArtistImages( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData ) { qDebug() << Q_FUNC_INFO; - if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() ) + if ( !data.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() ) { dataError( caller, type, data, customData ); return; } - InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >(); + InfoCriteriaHash hash = data.value< Tomahawk::InfoSystem::InfoCriteriaHash >(); if ( !hash.contains( "artist" ) ) { dataError( caller, type, data, customData ); @@ -220,7 +221,7 @@ LastFmPlugin::fetchArtistImages( const QString &caller, const InfoType type, con } Tomahawk::InfoSystem::InfoCriteriaHash criteria; - criteria["artist"] = hash["artist"].toString(); + criteria["artist"] = hash["artist"]; emit getCachedInfo( criteria, 2419200000, caller, type, data, customData ); } @@ -301,10 +302,10 @@ LastFmPlugin::coverArtReturned() customData ); - InfoCustomData origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCustomData >(); + InfoCriteriaHash origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCriteriaHash >(); Tomahawk::InfoSystem::InfoCriteriaHash criteria; - criteria["artist"] = origData["artist"].toString(); - criteria["album"] = origData["album"].toString(); + criteria["artist"] = origData["artist"]; + criteria["album"] = origData["album"]; emit updateCache( criteria, 2419200000, type, returnedData ); } else @@ -352,9 +353,9 @@ LastFmPlugin::artistImagesReturned() customData ); - InfoCustomData origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCustomData >(); + InfoCriteriaHash origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCriteriaHash >(); Tomahawk::InfoSystem::InfoCriteriaHash criteria; - criteria["artist"] = origData["artist"].toString(); + criteria["artist"] = origData["artist"]; emit updateCache( criteria, 2419200000, type, returnedData ); } else diff --git a/src/libtomahawk/network/controlconnection.cpp b/src/libtomahawk/network/controlconnection.cpp index b1c7a0b50..1982ee8d7 100644 --- a/src/libtomahawk/network/controlconnection.cpp +++ b/src/libtomahawk/network/controlconnection.cpp @@ -23,6 +23,7 @@ #include "database/databasecommand_collectionstats.h" #include "dbsyncconnection.h" #include "sourcelist.h" +#include #define TCP_TIMEOUT 600 @@ -120,6 +121,10 @@ ControlConnection::registerSource() Source* source = (Source*) sender(); Q_UNUSED( source ) Q_ASSERT( source == m_source.data() ); + + qDebug() << Q_FUNC_INFO << "Setting avatar ... " << name() << !SipHandler::instance()->avatar( name() ).isNull(); + source->setAvatar( SipHandler::instance()->avatar( name() ) ); + // .. but we'll use the shared pointer we've already made: m_registered = true; diff --git a/src/libtomahawk/network/controlconnection.h b/src/libtomahawk/network/controlconnection.h index d23c91f43..f0f2b105b 100644 --- a/src/libtomahawk/network/controlconnection.h +++ b/src/libtomahawk/network/controlconnection.h @@ -44,6 +44,8 @@ public: DBSyncConnection* dbSyncConnection(); + Tomahawk::source_ptr source() const { return m_source; } + protected: virtual void setup(); diff --git a/src/libtomahawk/network/portfwdthread.cpp b/src/libtomahawk/network/portfwdthread.cpp index 36cdd8088..b2af82f17 100644 --- a/src/libtomahawk/network/portfwdthread.cpp +++ b/src/libtomahawk/network/portfwdthread.cpp @@ -41,7 +41,7 @@ PortFwdThread::~PortFwdThread() { qDebug() << Q_FUNC_INFO << "waiting for event loop to finish..."; quit(); - wait( 10000 ); + wait( 1000 ); delete m_portfwd; } diff --git a/src/libtomahawk/playlist/artistview.cpp b/src/libtomahawk/playlist/artistview.cpp index 7a6d94e59..a3ae3232b 100644 --- a/src/libtomahawk/playlist/artistview.cpp +++ b/src/libtomahawk/playlist/artistview.cpp @@ -223,12 +223,12 @@ ArtistView::onScrollTimeout() { TreeModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( m_proxyModel->index( i, 0 ) ) ); - Tomahawk::InfoSystem::InfoCustomData trackInfo; - trackInfo["artist"] = QVariant::fromValue< QString >( item->artist()->name() ); - trackInfo["pptr"] = QVariant::fromValue< qlonglong >( (qlonglong)item ); + Tomahawk::InfoSystem::InfoCriteriaHash trackInfo; + trackInfo["artist"] = item->artist()->name(); + trackInfo["pptr"] = QString::number( (qlonglong)item ); Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( s_tmInfoIdentifier, Tomahawk::InfoSystem::InfoArtistImages, - QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); + QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); } } diff --git a/src/libtomahawk/playlist/treemodel.cpp b/src/libtomahawk/playlist/treemodel.cpp index 7d7974974..8830e0bfe 100644 --- a/src/libtomahawk/playlist/treemodel.cpp +++ b/src/libtomahawk/playlist/treemodel.cpp @@ -476,14 +476,14 @@ TreeModel::onAlbumsAdded( const QList& albums, const QVaria albumitem->index = createIndex( parentItem->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); - Tomahawk::InfoSystem::InfoCustomData trackInfo; - trackInfo["artist"] = QVariant::fromValue< QString >( album->artist()->name() ); - trackInfo["album"] = QVariant::fromValue< QString >( album->name() ); - trackInfo["pptr"] = QVariant::fromValue< qlonglong >( (qlonglong)albumitem ); + Tomahawk::InfoSystem::InfoCriteriaHash trackInfo; + trackInfo["artist"] = album->artist()->name(); + trackInfo["album"] = album->name(); + trackInfo["pptr"] = QString::number( (qlonglong)albumitem ); Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( s_tmInfoIdentifier, Tomahawk::InfoSystem::InfoAlbumCoverArt, - QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); + QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); } if ( crows.second > 0 ) @@ -555,7 +555,7 @@ TreeModel::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, return; } - Tomahawk::InfoSystem::InfoCustomData pptr = input.value< Tomahawk::InfoSystem::InfoCustomData >(); + Tomahawk::InfoSystem::InfoCriteriaHash pptr = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >(); Tomahawk::InfoSystem::InfoCustomData returnedData = output.value< Tomahawk::InfoSystem::InfoCustomData >(); const QByteArray ba = returnedData["imgbytes"].toByteArray(); if ( ba.length() ) @@ -563,7 +563,8 @@ TreeModel::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QPixmap pm; pm.loadFromData( ba ); - qlonglong p = pptr["pptr"].toLongLong(); + bool ok; + qlonglong p = pptr["pptr"].toLongLong( &ok ); TreeModelItem* ai = reinterpret_cast(p); if ( pm.isNull() ) diff --git a/src/sip/SipHandler.cpp b/src/libtomahawk/sip/SipHandler.cpp similarity index 80% rename from src/sip/SipHandler.cpp rename to src/libtomahawk/sip/SipHandler.cpp index 59aa8ea12..a3b7b0375 100644 --- a/src/sip/SipHandler.cpp +++ b/src/libtomahawk/sip/SipHandler.cpp @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -24,19 +24,33 @@ #include #include +#include "functimeout.h" + #include "database/database.h" #include "network/controlconnection.h" #include "sourcelist.h" #include "tomahawksettings.h" -#include "tomahawk/tomahawkapp.h" +//#include "tomahawk/tomahawkapp.h" #include "config.h" +//remove +#include + +SipHandler* SipHandler::s_instance = 0; + +SipHandler* SipHandler::instance() +{ + return s_instance; +} + SipHandler::SipHandler( QObject* parent ) : QObject( parent ) , m_connected( false ) { + s_instance = this; + loadPlugins( findPlugins() ); connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( onSettingsChanged() ) ); @@ -55,6 +69,23 @@ SipHandler::plugins() const return m_plugins; } +const QPixmap SipHandler::avatar( const QString& name ) const +{ + qDebug() << Q_FUNC_INFO << "Getting avatar" << name << m_usernameAvatars.keys(); + if( m_usernameAvatars.keys().contains( name ) ) + { + qDebug() << Q_FUNC_INFO << "Getting avatar and avatar != null "; + Q_ASSERT(!m_usernameAvatars.value( name ).isNull()); + return m_usernameAvatars.value( name ); + } + else + { + qDebug() << Q_FUNC_INFO << "Getting avatar and avatar == null, GAAAAAH "; + return QPixmap(); + } +} + + void SipHandler::onSettingsChanged() @@ -147,6 +178,8 @@ SipHandler::loadPlugin( const QString& path ) QObject::connect( sip, SIGNAL( disconnected() ), SIGNAL( disconnected() ) ); QObject::connect( sip, SIGNAL( error( int, QString ) ), SLOT( onError( int, QString ) ) ); + QObject::connect( sip, SIGNAL( avatarReceived( QString, QPixmap ) ), SLOT( onAvatarReceived( QString, QPixmap ) ) ); + QObject::connect( sip, SIGNAL( avatarReceived( QPixmap ) ), SLOT( onAvatarReceived( QPixmap ) ) ); m_plugins << sip; } } @@ -182,7 +215,8 @@ SipHandler::connectPlugins( bool startup, const QString &pluginName ) if ( !TomahawkSettings::instance()->acceptedLegalWarning() ) { int result = QMessageBox::question( - TomahawkApp::instance()->mainWindow(), tr( "Legal Warning" ), + //TomahawkApp::instance()->mainWindow(), + 0, tr( "Legal Warning" ), tr( "By pressing OK below, you agree that your use of Tomahawk will be in accordance with any applicable laws, including copyright and intellectual property laws, in effect in your country of residence, and indemnify the Tomahawk developers and project from liability should you choose to break those laws.\n\nFor more information, please see http://gettomahawk.com/legal" ), tr( "I Do Not Agree" ), tr( "I Agree" ) ); @@ -346,3 +380,41 @@ SipHandler::onError( int code, const QString& msg ) QTimer::singleShot( 10000, sip, SLOT( connectPlugin() ) ); } } + +void SipHandler::onAvatarReceived( const QString& from, const QPixmap& avatar ) +{ + qDebug() << Q_FUNC_INFO << "Set avatar on source for " << from; + Q_ASSERT(!avatar.isNull()); + + m_usernameAvatars.insert( from, avatar ); + + // + + //Tomahawk::source_ptr source = ->source(); + ControlConnection *conn = Servent::instance()->lookupControlConnection( from ); + if( conn ) + { + qDebug() << Q_FUNC_INFO << from << "got control connection"; + Tomahawk::source_ptr source = conn->source(); + if( source ) + { + + qDebug() << Q_FUNC_INFO << from << "got source, setting avatar"; + source->setAvatar( avatar ); + } + else + { + qDebug() << Q_FUNC_INFO << from << "no source found, not setting avatar"; + } + } + else + { + qDebug() << Q_FUNC_INFO << from << "no control connection setup yet"; + } +} + +void SipHandler::onAvatarReceived( const QPixmap& avatar ) +{ + qDebug() << Q_FUNC_INFO << "Set own avatar on MyCollection"; + SourceList::instance()->getLocal()->setAvatar( avatar ); +} diff --git a/src/sip/SipHandler.h b/src/libtomahawk/sip/SipHandler.h similarity index 79% rename from src/sip/SipHandler.h rename to src/libtomahawk/sip/SipHandler.h index 0d3dcfa63..1c1c6f5bc 100644 --- a/src/sip/SipHandler.h +++ b/src/libtomahawk/sip/SipHandler.h @@ -1,5 +1,5 @@ /* === This file is part of Tomahawk Player - === - * + * * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -20,22 +20,28 @@ #define SIPHANDLER_H #include "sip/SipPlugin.h" +#include "dllmacro.h" #include #include +#include +#include +#include -class SipHandler : public QObject +class DLLEXPORT SipHandler : public QObject { Q_OBJECT public: -// static SipHandler* instance() { return s_instance ? s_instance : new SipHandler(); } + static SipHandler* instance(); SipHandler( QObject* parent ); ~SipHandler(); QList< SipPlugin* > plugins() const; + const QPixmap avatar( const QString& name ) const; + public slots: void addContact( const QString& id ) { qDebug() << Q_FUNC_INFO << id; } @@ -57,7 +63,16 @@ private slots: void onSettingsChanged(); + // set data for local source + void onAvatarReceived( const QPixmap& avatar ); + + // set data for other sources + void onAvatarReceived( const QString& from, const QPixmap& avatar ); + + private: + static SipHandler *s_instance; + QStringList findPlugins(); bool pluginLoaded( const QString& name ) const; @@ -66,6 +81,9 @@ private: QList< SipPlugin* > m_plugins; bool m_connected; + + + QHash m_usernameAvatars; }; #endif diff --git a/src/libtomahawk/sip/SipPlugin.h b/src/libtomahawk/sip/SipPlugin.h index 47af2fcf3..4bd55fc31 100644 --- a/src/libtomahawk/sip/SipPlugin.h +++ b/src/libtomahawk/sip/SipPlugin.h @@ -57,7 +57,14 @@ signals: void peerOnline( const QString& ); void peerOffline( const QString& ); void msgReceived( const QString& from, const QString& msg ); - + + // new data for own source + void avatarReceived ( const QPixmap& avatar ); + + // new data for other sources; + void avatarReceived ( const QString& from, const QPixmap& avatar); + + void addMenu( QMenu* menu ); void removeMenu( QMenu* menu ); }; diff --git a/src/libtomahawk/source.cpp b/src/libtomahawk/source.cpp index d825a7724..48e23dcb6 100644 --- a/src/libtomahawk/source.cpp +++ b/src/libtomahawk/source.cpp @@ -27,6 +27,8 @@ #include "database/databasecommand_logplayback.h" #include "database/database.h" +#include + using namespace Tomahawk; @@ -40,6 +42,8 @@ Source::Source( int id, const QString& username ) { qDebug() << Q_FUNC_INFO << id << username; + m_scrubFriendlyName = qApp->arguments().contains( "--demo" ); + if ( id == 0 ) { m_isLocal = true; @@ -98,8 +102,8 @@ Source::friendlyName() const return m_username; //TODO: this is a terrible assumption, help me clean this up, mighty muesli! - if ( m_friendlyname.contains( "@conference.") ) - return QString(m_friendlyname).remove( 0, m_friendlyname.lastIndexOf( "/" )+1 ).append(" via MUC"); + if ( m_friendlyname.contains( "@conference." ) ) + return QString( m_friendlyname ).remove( 0, m_friendlyname.lastIndexOf( "/" ) + 1 ).append( " via MUC" ); if ( m_friendlyname.contains( "/tomahawk" ) ) return m_friendlyname.left( m_friendlyname.indexOf( "/tomahawk" ) ); @@ -107,6 +111,25 @@ Source::friendlyName() const return m_friendlyname; } +void Source::setAvatar(const QPixmap& avatar) +{ + m_avatar = avatar; +} + +const QPixmap Source::avatar() const +{ + return m_avatar; +} + + +void +Source::setFriendlyName( const QString& fname ) +{ + m_friendlyname = fname; + if ( m_scrubFriendlyName ) + m_friendlyname = m_friendlyname.split( "@" ).first(); +} + void Source::addCollection( const collection_ptr& c ) @@ -164,7 +187,7 @@ Source::dbLoaded( unsigned int id, const QString& fname ) qDebug() << Q_FUNC_INFO << id << fname; m_id = id; - m_friendlyname = fname; + setFriendlyName( fname ); emit syncedWithDatabase(); } @@ -225,10 +248,7 @@ Source::onStateChanged( DBSyncConnection::State newstate, DBSyncConnection::Stat unsigned int Source::trackCount() const { - if ( m_stats.contains( "numfiles" ) ) - return m_stats.value( "numfiles" ).toUInt(); - else - return 0; + return m_stats.value( "numfiles" ).toUInt(); } diff --git a/src/libtomahawk/source.h b/src/libtomahawk/source.h index ed48dfd1b..398e791db 100644 --- a/src/libtomahawk/source.h +++ b/src/libtomahawk/source.h @@ -53,7 +53,9 @@ public: QString userName() const { return m_username; } QString friendlyName() const; - void setFriendlyName( const QString& fname ) { m_friendlyname = fname; } + void setFriendlyName( const QString& fname ); + void setAvatar(const QPixmap &avatar); + const QPixmap avatar() const; collection_ptr collection() const; void addCollection( const Tomahawk::collection_ptr& c ); @@ -111,11 +113,14 @@ private: QList< QSharedPointer > m_collections; QVariantMap m_stats; QString m_lastOpGuid; + bool m_scrubFriendlyName; Tomahawk::query_ptr m_currentTrack; QString m_textStatus; ControlConnection* m_cc; + + QPixmap m_avatar; }; }; diff --git a/src/scrobbler.cpp b/src/scrobbler.cpp index 74ad40ae8..2c5d572b4 100644 --- a/src/scrobbler.cpp +++ b/src/scrobbler.cpp @@ -74,15 +74,15 @@ Scrobbler::trackStarted( const Tomahawk::result_ptr& track ) scrobble(); } - Tomahawk::InfoSystem::InfoCustomData trackInfo; + Tomahawk::InfoSystem::InfoCriteriaHash trackInfo; - trackInfo["title"] = QVariant::fromValue< QString >( track->track() ); - trackInfo["artist"] = QVariant::fromValue< QString >( track->artist()->name() ); - trackInfo["album"] = QVariant::fromValue< QString >( track->album()->name() ); - trackInfo["duration"] = QVariant::fromValue< uint >( track->duration() ); + trackInfo["title"] = track->track(); + trackInfo["artist"] = track->artist()->name(); + trackInfo["album"] = track->album()->name(); + trackInfo["duration"] = QString::number( track->duration() ); Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( s_scInfoIdentifier, Tomahawk::InfoSystem::InfoMiscSubmitNowPlaying, - QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); + QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() ); m_scrobblePoint = ScrobblePoint( track->duration() / 2 ); } diff --git a/src/sip/CMakeLists.txt b/src/sip/CMakeLists.txt index 82aa3ae97..3e547058a 100644 --- a/src/sip/CMakeLists.txt +++ b/src/sip/CMakeLists.txt @@ -1,10 +1,11 @@ # only build one of them, if ENABLE_JREEN is true, GLOOX_FOUND is automatically set to "false" -IF( GLOOX_FOUND ) +IF( GLOOX_FOUND AND NOT LIBJREEN_FOUND ) ADD_SUBDIRECTORY( jabber ) -ENDIF( GLOOX_FOUND ) -IF( ENABLE_JREEN ) +ENDIF( GLOOX_FOUND AND NOT LIBJREEN_FOUND ) + +IF( LIBJREEN_FOUND ) ADD_SUBDIRECTORY( jreen ) -ENDIF( ENABLE_JREEN) +ENDIF( LIBJREEN_FOUND ) ADD_SUBDIRECTORY( twitter ) ADD_SUBDIRECTORY( zeroconf ) diff --git a/src/sip/jreen/CMakeLists.txt b/src/sip/jreen/CMakeLists.txt index b06fac816..e0aa1b0d0 100644 --- a/src/sip/jreen/CMakeLists.txt +++ b/src/sip/jreen/CMakeLists.txt @@ -9,11 +9,17 @@ add_definitions( -DSIPDLLEXPORT_PRO ) set( jabberSources jabber.cpp jabber_p.cpp + tomahawksipmessage.cpp + tomahawksipmessagefactory.cpp + avatarmanager.cpp ) set( jabberHeaders jabber.h jabber_p.h + tomahawksipmessage.h + tomahawksipmessagefactory.h + avatarmanager.h ) include_directories( . ${CMAKE_CURRENT_BINARY_DIR} .. @@ -22,7 +28,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} .. ) qt4_wrap_cpp( jabberMoc ${jabberHeaders} ) -add_library( tomahawk_sipjreen SHARED ${jabberSources} ${jabberMoc} ) +add_library( tomahawk_sipjabber SHARED ${jabberSources} ${jabberMoc} ) IF( WIN32 ) SET( OS_SPECIFIC_LINK_LIBRARIES @@ -33,7 +39,7 @@ SET( OS_SPECIFIC_LINK_LIBRARIES ) ENDIF( WIN32 ) -target_link_libraries( tomahawk_sipjreen +target_link_libraries( tomahawk_sipjabber ${QT_LIBRARIES} ${LIBJREEN_LIBRARY} ${OS_SPECIFIC_LINK_LIBRARIES} @@ -44,4 +50,4 @@ IF( APPLE ) # SET( CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} "-undefined dynamic_lookup" ) ENDIF( APPLE ) -install( TARGETS tomahawk_sipjreen DESTINATION lib${LIB_SUFFIX} ) +install( TARGETS tomahawk_sipjabber DESTINATION lib${LIB_SUFFIX} ) diff --git a/src/sip/jreen/avatarmanager.cpp b/src/sip/jreen/avatarmanager.cpp new file mode 100644 index 000000000..366d805e1 --- /dev/null +++ b/src/sip/jreen/avatarmanager.cpp @@ -0,0 +1,171 @@ +#include "avatarmanager.h" + + +#include "utils/tomahawkutils.h" + +#include +#include +#include + +#include +#include +#include +#include + +AvatarManager::AvatarManager(Jreen::Client *client) : + m_cacheDir(TomahawkUtils::appDataDir().absolutePath().append("/jreen/")) +{ + m_client = client; + + m_cachedAvatars = m_cacheDir.entryList(); + + connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onNewConnection())); + connect(m_client, SIGNAL(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence))); + connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + + connect(this, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString))); +} + +AvatarManager::~AvatarManager() +{ +} + +void AvatarManager::onNewConnection() +{ + fetchVCard( m_client->jid().bare() ); +} + + +void AvatarManager::fetchVCard(const QString &jid) +{ + qDebug() << Q_FUNC_INFO; + + Jreen::IQ iq(Jreen::IQ::Get, jid ); + iq.addExtension(new Jreen::VCard()); + m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), 0 ); +} + +void AvatarManager::onNewPresence(const Jreen::Presence& presence) +{ + Jreen::VCardUpdate::Ptr update = presence.findExtension(); + if(update) + { + qDebug() << "vcard: found update for " << presence.from().full(); + if(!isCached(update->photoHash())) + { + qDebug() << presence.from().full() << "vcard: photo not cached, starting request..." << update->photoHash(); + fetchVCard( presence.from().bare() ); + } + else + { + qDebug() << presence.from().full() << "vcard: photo already cached no request necessary " << update->photoHash(); + m_JidsAvatarHashes.insert( update->photoHash(), presence.from().bare() ); + + Q_ASSERT(!this->avatar(presence.from().bare()).isNull()); + emit newAvatar(presence.from().bare()); + } + } + else + { + qDebug() << Q_FUNC_INFO << presence.from().full() << "got no statusupdateextension"; + + //TODO: do we want this? might fetch avatars for broken clients + fetchVCard( presence.from().bare() ); + } +} + +void AvatarManager::onNewIq(const Jreen::IQ& iq, int context) +{ + Jreen::VCard *vcard = iq.findExtension().data(); + if(vcard) + { + iq.accept(); + + qDebug() << Q_FUNC_INFO << "Got vcard from " << iq.from().full(); + + QString id = iq.from().full(); + QString avatarHash; + + const Jreen::VCard::Photo &photo = vcard->photo(); + if (!photo.data().isEmpty()) { + qDebug() << "vcard: got photo data" << id; + + avatarHash = QCryptographicHash::hash(photo.data(), QCryptographicHash::Sha1).toHex(); + + if (!m_cacheDir.exists()) + m_cacheDir.mkpath( avatarDir( avatarHash ).absolutePath() ); + + + QFile file(avatarPath(avatarHash)); + if (file.open(QIODevice::WriteOnly)) { + file.write(photo.data()); + file.close(); + } + + m_cachedAvatars.append(avatarHash); + m_JidsAvatarHashes.insert( avatarHash, iq.from().bare() ); + + Q_ASSERT(!this->avatar(iq.from().bare()).isNull()); + emit newAvatar(iq.from().bare()); + } + else + { + qDebug() << "vcard: got no photo data" << id; + } + + // got own presence + if ( m_client->jid().bare() == id ) + { + qDebug() << Q_FUNC_INFO << "got own vcard"; + + Jreen::Presence presence = m_client->presence(); + Jreen::VCardUpdate::Ptr update = presence.findExtension(); + if (update->photoHash() != avatarHash) + { + qDebug() << Q_FUNC_INFO << "Updating own presence..."; + + update->setPhotoHash(avatarHash); + m_client->send(presence); + } + } + } +} + +QPixmap AvatarManager::avatar(const QString &jid) const +{ + if( isCached( avatarHash( jid ) ) ) + { + return QPixmap( avatarPath( avatarHash( jid ) ) ); + } + else + { + return QPixmap(); + } +} + +QString AvatarManager::avatarHash(const QString &jid) const +{ + //qDebug() << Q_FUNC_INFO << jid << m_JidsAvatarHashes.key(jid); + return m_JidsAvatarHashes.key(jid); +} + +QDir AvatarManager::avatarDir(const QString &avatarHash) const +{ + return m_cacheDir; +} + +QString AvatarManager::avatarPath(const QString &avatarHash) const +{ + Q_ASSERT(!avatarHash.contains("@")); + return avatarDir(avatarHash).absoluteFilePath(avatarHash); +} + +bool AvatarManager::isCached(const QString &avatarHash) const +{ + return m_cachedAvatars.contains( avatarHash ); +} + +void AvatarManager::onNewAvatar(const QString& jid) +{ + qDebug() << Q_FUNC_INFO << "Found new Avatar..." << jid; +} diff --git a/src/sip/jreen/avatarmanager.h b/src/sip/jreen/avatarmanager.h new file mode 100644 index 000000000..71852285c --- /dev/null +++ b/src/sip/jreen/avatarmanager.h @@ -0,0 +1,43 @@ +#ifndef AVATARMANAGER_H +#define AVATARMANAGER_H + +#include + +#include +#include + + +class AvatarManager : public QObject +{ +Q_OBJECT + +public: + AvatarManager(Jreen::Client *client); + virtual ~AvatarManager(); + + QPixmap avatar(const QString &jid) const; + +signals: + void newAvatar( const QString &jid ); + +private slots: + void onNewPresence( const Jreen::Presence& presence ); + void onNewIq(const Jreen::IQ &iq, int context = 0 ); + void onNewConnection(); + void onNewAvatar( const QString &jid ); + +private: + void fetchVCard( const QString &jid); + QString avatarHash(const QString &jid) const; + QString avatarPath(const QString &avatarHash) const; + + QDir avatarDir(const QString &avatarHash) const; + bool isCached(const QString &avatarHash) const; + + Jreen::Client *m_client; + QStringList m_cachedAvatars; + QDir m_cacheDir; + QMap m_JidsAvatarHashes; +}; + +#endif // AVATARMANAGER_H diff --git a/src/sip/jreen/jabber.cpp b/src/sip/jreen/jabber.cpp index c97067f59..7e0b1235e 100644 --- a/src/sip/jreen/jabber.cpp +++ b/src/sip/jreen/jabber.cpp @@ -1,5 +1,6 @@ /* === This file is part of Tomahawk Player - === - * + * + * Copyright 2010-2011, Dominik Schmidt * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -105,8 +106,12 @@ JabberPlugin::connectPlugin( bool startup ) 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( onConnected() ) ); - QObject::connect( p, SIGNAL( disconnected() ), SIGNAL( onDisconnected() ) ); + QObject::connect( p, SIGNAL( connected() ), SLOT( onConnected() ) ); + QObject::connect( p, SIGNAL( disconnected() ), SLOT( onDisconnected() ) ); + + QObject::connect( p, SIGNAL( authError( int, QString ) ), SLOT( onAuthError( int, QString ) ) ); + QObject::connect( p, SIGNAL( avatarReceived( QString, QPixmap ) ), SIGNAL( avatarReceived( QString, QPixmap ) ) ); + QObject::connect( p, SIGNAL( avatarReceived( QPixmap ) ), SIGNAL( avatarReceived( QPixmap) ) ); return true; } @@ -155,6 +160,33 @@ JabberPlugin::onDisconnected() emit disconnected(); } +void +JabberPlugin::onAuthError( int code, const QString& msg ) +{ + switch( code ) + { + case Jreen::Client::AuthorizationError: + emit error( SipPlugin::AuthError, msg ); + break; + + case Jreen::Client::HostUnknown: + case Jreen::Client::ItemNotFound: + case Jreen::Client::RemoteStreamError: + case Jreen::Client::RemoteConnectionFailed: + case Jreen::Client::InternalServerError: + case Jreen::Client::SystemShutdown: + case Jreen::Client::Conflict: + case Jreen::Client::Unknown: + emit error( SipPlugin::ConnectionError, msg ); + break; + + default: + qDebug() << "Not all Client::DisconnectReasons checked"; + Q_ASSERT(false); + break; + } +} + void JabberPlugin::sendMsg(const QString& to, const QString& msg) { diff --git a/src/sip/jreen/jabber.h b/src/sip/jreen/jabber.h index ccbbafc0e..75996381d 100644 --- a/src/sip/jreen/jabber.h +++ b/src/sip/jreen/jabber.h @@ -1,5 +1,6 @@ /* === This file is part of Tomahawk Player - === - * + * + * Copyright 2010-2011, Dominik Schmidt * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -24,7 +25,7 @@ #include "../sipdllmacro.h" -#define MYNAME "SIPJABBER" +#define MYNAME "SIPJREEN" class SIPDLLEXPORT JabberPlugin : public SipPlugin { @@ -56,6 +57,7 @@ private slots: void showAddFriendDialog(); void onConnected(); void onDisconnected(); + void onAuthError(int code, const QString &msg); private: Jabber_p* p; diff --git a/src/sip/jreen/jabber_p.cpp b/src/sip/jreen/jabber_p.cpp index 9e4aa8798..100ae908c 100644 --- a/src/sip/jreen/jabber_p.cpp +++ b/src/sip/jreen/jabber_p.cpp @@ -1,5 +1,6 @@ /* === This file is part of Tomahawk Player - === - * + * + * Copyright 2010-2011, Dominik Schmidt * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -17,6 +18,18 @@ */ #include "jabber_p.h" +#include "tomahawksipmessage.h" +#include "tomahawksipmessagefactory.h" + +#include "config.h" +#include "utils/tomahawkutils.h" + +#include +#include +#include + +#include +#include #include #include @@ -24,58 +37,69 @@ #include #include #include -#include - -#include -#include - +#include +#include +#include +#include +#include +#include //remove -#include -#include +#include +#include -using namespace std; +#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" ) - -#define TOMAHAWK_CAP_NODE_NAME QLatin1String("http://tomahawk-player.org/") +#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" ) Jabber_p::Jabber_p( const QString& jid, const QString& password, const QString& server, const int port ) : QObject() , m_server() { qDebug() << Q_FUNC_INFO; - //qsrand( QTime( 0, 0, 0 ).secsTo( QTime::currentTime() ) ); qsrand(QDateTime::currentDateTime().toTime_t()); - m_presences[Jreen::Presence::Available] = "available"; - m_presences[Jreen::Presence::Chat] = "chat"; - m_presences[Jreen::Presence::Away] = "away"; - m_presences[Jreen::Presence::DND] = "dnd"; - m_presences[Jreen::Presence::XA] = "xa"; - m_presences[Jreen::Presence::Unavailable] = "unavailable"; - m_presences[Jreen::Presence::Probe] = "probe"; - m_presences[Jreen::Presence::Error] = "error"; - m_presences[Jreen::Presence::Invalid] = "invalid"; - + // setup JID object m_jid = Jreen::JID( jid ); + // general client setup m_client = new Jreen::Client( jid, password ); - m_client->setResource( QString( "tomahawk-jreen%1" ).arg( QString::number( qrand() % 10000 ) ) ); + m_client->registerStanzaExtension(new TomahawkSipMessageFactory); + m_client->setResource( QString( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) ) ); + // add VCardUpdate extension to own presence + m_client->presence().addExtension( new Jreen::VCardUpdate() ); + + // initialize the AvatarManager + m_avatarManager = new AvatarManager(m_client); + + // setup disco + m_client->disco()->setSoftwareVersion( "Tomahawk Player", TOMAHAWK_VERSION, CMAKE_SYSTEM ); + m_client->disco()->addIdentity( Jreen::Disco::Identity( "client", "type", "tomahawk", "en" ) ); + m_client->disco()->addFeature( TOMAHAWK_FEATURE ); + + // setup caps node, legacy peer detection - used before 0.1 Jreen::Capabilities::Ptr caps = m_client->presence().findExtension(); - caps->setNode(TOMAHAWK_CAP_NODE_NAME); + caps->setNode( TOMAHAWK_CAP_NODE_NAME ); + // print connection parameters qDebug() << "Our JID set to:" << m_client->jid().full(); qDebug() << "Our Server set to:" << m_client->server(); qDebug() << "Our Port set to" << m_client->port(); + // setup slots connect(m_client->connection(), SIGNAL(error(SocketError)), SLOT(onError(SocketError))); connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onConnect())); connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason))); connect(m_client, SIGNAL(destroyed(QObject*)), this, SLOT(onDestroy())); connect(m_client, SIGNAL(newMessage(Jreen::Message)), SLOT(onNewMessage(Jreen::Message))); connect(m_client, SIGNAL(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence))); + connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ))); + connect(m_avatarManager, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString))); + + + // connect qDebug() << "Connecting to the XMPP server..."; m_client->connectToServer(); } @@ -105,28 +129,57 @@ Jabber_p::disconnect() void Jabber_p::sendMsg( const QString& to, const QString& msg ) { - qDebug() << Q_FUNC_INFO; - if ( QThread::currentThread() != thread() ) - { - qDebug() << Q_FUNC_INFO << "invoking in correct thread, not" - << QThread::currentThread(); - - QMetaObject::invokeMethod( this, "sendMsg", - Qt::QueuedConnection, - Q_ARG( const QString, to ), - Q_ARG( const QString, msg ) - ); - return; - } + qDebug() << Q_FUNC_INFO << to << msg; if ( !m_client ) { return; } - qDebug() << Q_FUNC_INFO << to << msg; - Jreen::Message m( Jreen::Message::Chat, Jreen::JID(to), msg); + if( m_legacy_peers.contains( to ) ) + { + qDebug() << Q_FUNC_INFO << to << "Send legacy message" << msg; + Jreen::Message m( Jreen::Message::Chat, Jreen::JID(to), msg); + m_client->send( m ); - m_client->send( m ); // assuming this is threadsafe + return; + } + + + /******************************************************* + * Obsolete this by a SipMessage class + */ + 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(); + /*******************************************************/ + + TomahawkSipMessage *sipMessage; + if(m["visible"].toBool()) + { + sipMessage = new TomahawkSipMessage(m["ip"].toString(), + m["port"].toInt(), + m["uniqname"].toString(), + m["key"].toString(), + m["visible"].toBool() + ); + } + else + { + sipMessage = new TomahawkSipMessage(); + } + + + qDebug() << "Send sip messsage to " << to; + Jreen::IQ iq( Jreen::IQ::Set, to ); + iq.addExtension( sipMessage ); + + m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), SipMessageSent ); } @@ -134,23 +187,13 @@ void Jabber_p::broadcastMsg( const QString &msg ) { qDebug() << Q_FUNC_INFO; - if ( QThread::currentThread() != thread() ) - { - QMetaObject::invokeMethod( this, "broadcastMsg", - Qt::QueuedConnection, - Q_ARG(const QString, msg) - ); - return; - } if ( !m_client ) return; foreach( const QString& jidstr, m_peers.keys() ) { - qDebug() << "Broadcasting to" << jidstr <<"..."; - Jreen::Message m(Jreen::Message::Chat, Jreen::JID(jidstr), msg, ""); - m_client->send( m ); + sendMsg( jidstr, msg ); } } @@ -158,16 +201,6 @@ Jabber_p::broadcastMsg( const QString &msg ) void Jabber_p::addContact( const QString& jid, const QString& msg ) { - if ( QThread::currentThread() != thread() ) - { - QMetaObject::invokeMethod( this, "addContact", - Qt::QueuedConnection, - Q_ARG(const QString, jid), - Q_ARG(const QString, msg) - ); - return; - } - // Add contact to the Tomahawk group on the roster m_roster->add( jid, jid, QStringList() << "Tomahawk" ); @@ -183,6 +216,7 @@ Jabber_p::onConnect() // have changed our requested /resource if ( m_client->jid().resource() != m_jid.resource() ) { + // TODO: check if this is still neccessary with jreen m_jid.setResource( m_client->jid().resource() ); QString jidstr( m_jid.full() ); emit jidChanged( jidstr ); @@ -191,22 +225,27 @@ Jabber_p::onConnect() emit connected(); qDebug() << "Connected as:" << m_jid.full(); - m_client->setPresence(Jreen::Presence::Available, "Tomahawk-JREEN available", 1); - m_client->disco()->setSoftwareVersion( "Tomahawk JREEN", "0.0.0.0", "Foobar" ); - m_client->setPingInterval(60000); + // set presence to least valid value + m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127); + + // set ping timeout to 15 secs (TODO: verify if this works) + m_client->setPingInterval(15000); + + // load roster m_roster = new Jreen::SimpleRoster( m_client ); m_roster->load(); + //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P // join MUC with bare jid as nickname //TODO: make the room a list of rooms and make that configurable - QString bare(m_jid.bare()); - m_room = new Jreen::MUCRoom(m_client, Jreen::JID(QString("tomahawk@conference.qutim.org/").append(bare.replace("@", "-")))); + QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_jid.bare() ).replace( "@", "-" ) ); + m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) ); //m_room->setHistorySeconds(0); //m_room->join(); // treat muc participiants like contacts - connect(m_room, SIGNAL(messageReceived(Jreen::Message, bool)), this, SLOT(onNewMessage(Jreen::Message))); - connect(m_room, SIGNAL(presenceReceived(Jreen::Presence,const Jreen::MUCRoom::Participant*)), this, SLOT(onNewPresence(Jreen::Presence))); + connect( m_room, SIGNAL( messageReceived( Jreen::Message, bool ) ), this, SLOT( onNewMessage( Jreen::Message ) ) ); + connect( m_room, SIGNAL( presenceReceived( Jreen::Presence, const Jreen::MUCRoom::Participant* ) ), this, SLOT( onNewPresence( Jreen::Presence ) ) ); } @@ -262,6 +301,10 @@ Jabber_p::onDisconnect( Jreen::Client::DisconnectReason reason ) } qDebug() << "Disconnected from server:" << error; + if( reason != Jreen::Client::User ) + { + emit authError( reason, error ); + } if(reconnect) QTimer::singleShot(reconnectInSeconds*1000, m_client, SLOT(connectToServer())); @@ -278,81 +321,159 @@ Jabber_p::onNewMessage( const Jreen::Message& m ) if ( msg.isEmpty() ) return; - qDebug() << Q_FUNC_INFO << m.from().full() << ":" << m.body(); + QJson::Parser parser; + bool ok; + QVariant v = parser.parse( msg.toAscii(), &ok ); + if ( !ok || v.type() != QVariant::Map ) + { + QString to = from; + QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player" + " (http://gettomahawk.com). If you are getting this message, the person you" + " are trying to reach is probably not signed on, so please try again later!") ); + + // this is not a sip message, so we send it directly through the client + m_client->send( Jreen::Message ( Jreen::Message::Chat, Jreen::JID(to), response) ); + + return; + } + + qDebug() << Q_FUNC_INFO << "From:" << m.from().full() << ":" << m.body(); emit msgReceived( from, msg ); } void Jabber_p::onNewPresence( const Jreen::Presence& presence) { - Jreen::JID jid = presence.from(); QString fulljid( jid.full() ); - qDebug() << Q_FUNC_INFO << "handle presence" << fulljid << presence.subtype(); + + qDebug() << Q_FUNC_INFO << "* New presence: " << fulljid << presence.subtype(); if( jid == m_jid ) return; if ( presence.error() ) { - qDebug() << Q_FUNC_INFO << "presence error: no tomahawk"; + //qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error"; return; } - // ignore anyone not running tomahawk: + // ignore anyone not Running tomahawk: Jreen::Capabilities::Ptr caps = presence.findExtension(); - if ( caps && (caps->node() == TOMAHAWK_CAP_NODE_NAME )) + if ( caps && ( caps->node() == TOMAHAWK_CAP_NODE_NAME ) ) { - qDebug() << Q_FUNC_INFO << presence.from().full() << "tomahawk detected by caps"; + // must be a jreen resource, implementation in gloox was broken + qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: yes" << "caps " << caps->node(); + handlePeerStatus( fulljid, presence.subtype() ); } - // this is a hack actually as long as gloox based libsip_jabber is around - // remove this as soon as everyone is using jreen - else if( presence.from().resource().startsWith( QLatin1String("tomahawk") ) ) + else if( caps ) { - qDebug() << Q_FUNC_INFO << presence.from().full() << "tomahawk detected by resource"; - } - else if( caps && caps->node() != TOMAHAWK_CAP_NODE_NAME ) - { - qDebug() << Q_FUNC_INFO << presence.from().full() << "*no tomahawk* detected by caps!" << caps->node() << presence.from().resource(); - return; + qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node() + << "requesting disco.."; + + // request disco features + QString node = caps->node() + '#' + caps->ver(); + + Jreen::IQ iq( Jreen::IQ::Get, jid ); + iq.addExtension( new Jreen::Disco::Info( node ) ); + + m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestDisco ); } else if( !caps ) { - qDebug() << Q_FUNC_INFO << "no tomahawk detected by resource and !caps"; - return; + qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps"; } +} - qDebug() << Q_FUNC_INFO << fulljid << " is a tomahawk resource."; - - // "going offline" event - if ( !presenceMeansOnline( presence.subtype() ) && - ( !m_peers.contains( fulljid ) || - presenceMeansOnline( m_peers.value( fulljid ) ) - ) - ) +void +Jabber_p::onNewIq( const Jreen::IQ &iq, int context ) +{ + if( context == RequestDisco ) { - m_peers[ fulljid ] = presence.subtype(); - qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid; - emit peerOffline( fulljid ); - return; - } + qDebug() << Q_FUNC_INFO << "Received disco IQ..."; + Jreen::Disco::Info *discoInfo = iq.findExtension().data(); + if(!discoInfo) + return; + iq.accept(); - // "coming online" event - if( presenceMeansOnline( presence.subtype() ) && - ( !m_peers.contains( fulljid ) || - !presenceMeansOnline( m_peers.value( fulljid ) ) - ) - ) + QString fulljid = iq.from().full(); + Jreen::DataForm::Ptr form = discoInfo->form(); + + if(discoInfo->features().contains( TOMAHAWK_FEATURE )) + { + qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk/feature enabled: yes"; + + // the actual presence doesn't matter, it just needs to be "online" + handlePeerStatus( fulljid, Jreen::Presence::Available ); + } + else + { + qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk/feature enabled: no"; + + //LEGACY: accept resources starting with tomahawk too + if( iq.from().resource().startsWith("tomahawk") ) + { + qDebug() << Q_FUNC_INFO << fulljid << "Detected legacy tomahawk.."; + + // add to legacy peers, so we can send text messages instead of iqs + m_legacy_peers.append( fulljid ); + + handlePeerStatus( fulljid, Jreen::Presence::Available ); + } + } + } + else if(context == RequestedDisco) { - m_peers[ fulljid ] = presence.subtype(); - qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid; - emit peerOnline( fulljid ); - return; + qDebug() << "Sent IQ(Set), what should be happening here?"; } + else if(context == SipMessageSent ) + { + qDebug() << "Sent SipMessage... what now?!"; + } + /*else if(context == RequestedVCard ) + { + qDebug() << "Requested VCard... what now?!"; + }*/ + else + { - //qDebug() << "Updating presence data for" << fulljid; - m_peers[ fulljid ] = presence.subtype(); + TomahawkSipMessage *sipMessage = iq.findExtension().data(); + if(sipMessage) + { + iq.accept(); + qDebug() << Q_FUNC_INFO << "Got SipMessage ..."; + qDebug() << "ip" << sipMessage->ip(); + qDebug() << "port" << sipMessage->port(); + qDebug() << "uniqname" << sipMessage->uniqname(); + qDebug() << "key" << sipMessage->key(); + qDebug() << "visible" << sipMessage->visible(); + + + QVariantMap m; + if( sipMessage->visible() ) + { + m["visible"] = true; + m["ip"] = sipMessage->ip(); + m["port"] = sipMessage->port(); + m["key"] = sipMessage->key(); + m["uniqname"] = sipMessage->uniqname(); + } + else + { + m["visible"] = false; + } + + + QJson::Serializer ser; + QByteArray ba = ser.serialize( m ); + QString msg = QString::fromAscii( ba ); + + QString from = iq.from().full(); + qDebug() << Q_FUNC_INFO << "From:" << from << ":" << msg; + emit msgReceived( from, msg ); + } + } } bool @@ -369,3 +490,73 @@ Jabber_p::presenceMeansOnline( Jreen::Presence::Type p ) return true; } } + +void +Jabber_p::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType ) +{ + QString fulljid = jid.full(); + + // "going offline" event + if ( !presenceMeansOnline( presenceType ) && + ( !m_peers.contains( fulljid ) || + presenceMeansOnline( m_peers.value( fulljid ) ) + ) + ) + { + m_peers[ fulljid ] = presenceType; + qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid; + + // remove peer from legacy peers + if( m_legacy_peers.contains( fulljid ) ) + { + m_legacy_peers.removeAll( fulljid ); + } + + emit peerOffline( fulljid ); + return; + } + + // "coming online" event + if( presenceMeansOnline( presenceType ) && + ( !m_peers.contains( fulljid ) || + !presenceMeansOnline( m_peers.value( fulljid ) ) + ) + ) + { + m_peers[ fulljid ] = presenceType; + qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid; + + emit peerOnline( fulljid ); + + if(!m_avatarManager->avatar(jid.bare()).isNull()) + onNewAvatar( jid.bare() ); + + return; + } + + //qDebug() << "Updating presence data for" << fulljid; + m_peers[ fulljid ] = presenceType; +} + +void Jabber_p::onNewAvatar(const QString& jid) +{ + qDebug() << Q_FUNC_INFO << jid; + Q_ASSERT(!m_avatarManager->avatar( jid ).isNull()); + + // find peers for the jid + QStringList peers = m_peers.keys(); + foreach(const QString &peer, peers) + { + if( peer.startsWith(jid) ) + { + emit avatarReceived ( peer, m_avatarManager->avatar( jid ) ); + } + } + + if( jid == m_client->jid().bare() ) + // own avatar + emit avatarReceived ( m_avatarManager->avatar( jid ) ); + else + // someone else's avatar + emit avatarReceived ( jid, m_avatarManager->avatar( jid ) ); +} diff --git a/src/sip/jreen/jabber_p.h b/src/sip/jreen/jabber_p.h index ab0826f20..243e255a9 100644 --- a/src/sip/jreen/jabber_p.h +++ b/src/sip/jreen/jabber_p.h @@ -1,5 +1,6 @@ /* === This file is part of Tomahawk Player - === - * + * + * Copyright 2010-2011, Dominik Schmidt * Copyright 2010-2011, Christian Muehlhaeuser * * Tomahawk is free software: you can redistribute it and/or modify @@ -16,20 +17,12 @@ * along with Tomahawk. If not, see . */ -/* - This is the Jabber client that the rest of the app sees - Gloox stuff should NOT leak outside this class. - We may replace jreen later, this interface should remain the same. -*/ #ifndef JABBER_P_H #define JABBER_P_H -#include -#include -#include -#include +#include "../sipdllmacro.h" -#include +#include "avatarmanager.h" #include #include @@ -41,16 +34,19 @@ #include #include #include +#include +#include + +#include +#include +#include +#include #if defined( WIN32 ) || defined( _WIN32 ) -# include +#include #endif -#include "../sipdllmacro.h" -#include -#include - class SIPDLLEXPORT Jabber_p : public QObject { @@ -69,6 +65,8 @@ signals: void connected(); void disconnected(); void jidChanged( const QString& ); + void avatarReceived( const QPixmap& avatar ); + void avatarReceived( const QString&, const QPixmap& avatar ); void authError( int, const QString& ); public slots: @@ -87,9 +85,13 @@ private slots: { qDebug() << e; } + virtual void onNewIq( const Jreen::IQ &iq, int context = NoContext ); + virtual void onNewAvatar( const QString &jid ); private: bool presenceMeansOnline( Jreen::Presence::Type p ); + void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType ); + Jreen::Client *m_client; Jreen::MUCRoom *m_room; Jreen::SimpleRoster *m_roster; @@ -97,6 +99,12 @@ private: QMap m_presences; QMap m_peers; QString m_server; + + enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent, RequestedVCard }; + + QStringList m_legacy_peers; + + AvatarManager *m_avatarManager; }; #endif // JABBER_H diff --git a/src/sip/jreen/tomahawksipmessage.cpp b/src/sip/jreen/tomahawksipmessage.cpp new file mode 100644 index 000000000..0dce37b0b --- /dev/null +++ b/src/sip/jreen/tomahawksipmessage.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** + * + * This file is part of qutIM + * + * Copyright (c) 2011 by Nigmatullin Ruslan + * + *************************************************************************** + * * + * This file is part of free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * * + *************************************************************************** + ****************************************************************************/ + +#include "tomahawksipmessage.h" + +class TomahawkSipMessagePrivate +{ +public: + QString ip; + int port; + QString uniqname; + QString key; + bool visible; +}; + +TomahawkSipMessage::TomahawkSipMessage(QString ip, unsigned int port, QString uniqname, QString key, bool visible) : d_ptr(new TomahawkSipMessagePrivate) +{ + Q_D(TomahawkSipMessage); + d->ip = ip; + d->port = port; + d->uniqname = uniqname; + d->key = key; + d->visible = visible; +} + +TomahawkSipMessage::TomahawkSipMessage() : d_ptr(new TomahawkSipMessagePrivate) +{ + Q_D(TomahawkSipMessage); + d->visible = false; + d->port = -1; +} + + +TomahawkSipMessage::~TomahawkSipMessage() +{ +} + +const QString TomahawkSipMessage::ip() const +{ + return d_func()->ip; +} + +unsigned int TomahawkSipMessage::port() const +{ + return d_func()->port; +} + +QString TomahawkSipMessage::uniqname() const +{ + return d_func()->uniqname; +} + +QString TomahawkSipMessage::key() const +{ + return d_func()->key; +} + +bool TomahawkSipMessage::visible() const +{ + return d_func()->visible; +} diff --git a/src/sip/jreen/tomahawksipmessage.h b/src/sip/jreen/tomahawksipmessage.h new file mode 100644 index 000000000..da1c376c5 --- /dev/null +++ b/src/sip/jreen/tomahawksipmessage.h @@ -0,0 +1,28 @@ +#ifndef ENTITYTIME_H +#define ENTITYTIME_H + +#include + +#define TOMAHAWK_SIP_MESSAGE_NS QLatin1String("http://www.tomhawk-player.org/sip/transports") + +class TomahawkSipMessagePrivate; +class TomahawkSipMessage : public Jreen::StanzaExtension +{ + J_EXTENSION(TomahawkSipMessage, "") + Q_DECLARE_PRIVATE(TomahawkSipMessage) + public: + TomahawkSipMessage(QString ip, unsigned int port, QString uniqname, QString key, bool visible); + // sets visible to false as we dont have any extra information + TomahawkSipMessage(); + ~TomahawkSipMessage(); + + const QString ip() const; + unsigned int port() const; + QString uniqname() const; + QString key() const; + bool visible() const; + private: + QScopedPointer d_ptr; +}; + +#endif // ENTITYTIME_H diff --git a/src/sip/jreen/tomahawksipmessagefactory.cpp b/src/sip/jreen/tomahawksipmessagefactory.cpp new file mode 100644 index 000000000..20a0a9ba8 --- /dev/null +++ b/src/sip/jreen/tomahawksipmessagefactory.cpp @@ -0,0 +1,124 @@ +#include "tomahawksipmessagefactory.h" +//#include "util.h" +#include +#include +#include +#include + +using namespace Jreen; + +TomahawkSipMessageFactory::TomahawkSipMessageFactory() +{ + m_depth = 0; + m_state = AtNowhere; +} + +TomahawkSipMessageFactory::~TomahawkSipMessageFactory() +{ +} + +QStringList TomahawkSipMessageFactory::features() const +{ + return QStringList(TOMAHAWK_SIP_MESSAGE_NS); +} + +bool TomahawkSipMessageFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes) +{ + Q_UNUSED(uri); + Q_UNUSED(attributes); + return name == QLatin1String("tomahawk") && uri == TOMAHAWK_SIP_MESSAGE_NS; +} + +void TomahawkSipMessageFactory::handleStartElement(const QStringRef &name, const QStringRef &uri, + const QXmlStreamAttributes &attributes) +{ + m_depth++; + if (m_depth == 1) { + m_state = AtNowhere; + m_ip = QString(); + m_port = -1; + m_uniqname = QString(); + m_key = QString(); + m_visible = false; + } else if (m_depth == 2) { + if (name == QLatin1String("transport")) + { + qDebug() << "Found Transport"; + m_state = AtTransport; + + m_uniqname = attributes.value(QLatin1String("uniqname")).toString(); + m_key = attributes.value(QLatin1String("pwd")).toString(); + m_visible = true; + } + } else if(m_depth == 3) { + if (name == QLatin1String("candidate")) + { + m_state = AtCandidate; + qDebug() << "Found candidate"; + m_ip = attributes.value(QLatin1String("ip")).toString(); + m_port = attributes.value(QLatin1String("port")).toString().toInt(); + + } + } + Q_UNUSED(uri); + Q_UNUSED(attributes); +} + +void TomahawkSipMessageFactory::handleEndElement(const QStringRef &name, const QStringRef &uri) +{ + if (m_depth == 3) + m_state = AtNowhere; + Q_UNUSED(name); + Q_UNUSED(uri); + m_depth--; +} + +void TomahawkSipMessageFactory::handleCharacterData(const QStringRef &text) +{ + /*if (m_state == AtUtc) { + //m_utc = Util::fromStamp(text.toString()); + } else if (m_state == AtTzo) { + QString str = text.toString(); + int multiple = str.startsWith('-') ? -1 : 1; + //QTime delta = QTime::fromString(str.mid(1), QLatin1String("hh:mm")); + //m_tzo = multiple * (delta.hour() * 60 + delta.minute()); + }*/ + Q_UNUSED(text); +} + +void TomahawkSipMessageFactory::serialize(StanzaExtension *extension, QXmlStreamWriter *writer) +{ + TomahawkSipMessage *sipMessage = se_cast(extension); + + writer->writeStartElement(QLatin1String("tomahawk")); + writer->writeDefaultNamespace(TOMAHAWK_SIP_MESSAGE_NS); + + if(sipMessage->visible()) + { + // add transport tag + writer->writeStartElement(QLatin1String("transport")); + writer->writeAttribute(QLatin1String("pwd"), sipMessage->key()); + writer->writeAttribute(QLatin1String("uniqname"), sipMessage->uniqname()); + + writer->writeEmptyElement(QLatin1String("candidate")); + writer->writeAttribute(QLatin1String("component"), "1"); + writer->writeAttribute(QLatin1String("id"), "el0747fg11"); // FIXME + writer->writeAttribute(QLatin1String("ip"), sipMessage->ip()); + writer->writeAttribute(QLatin1String("network"), "1"); + writer->writeAttribute(QLatin1String("port"), QVariant(sipMessage->port()).toString()); + writer->writeAttribute(QLatin1String("priority"), "1"); //TODO + writer->writeAttribute(QLatin1String("protocol"), "tcp"); + writer->writeAttribute(QLatin1String("type"), "host"); //FIXME: correct?! + writer->writeEndElement(); + } + else + { + writer->writeEmptyElement(QLatin1String("transport")); + } + writer->writeEndElement(); +} + +StanzaExtension::Ptr TomahawkSipMessageFactory::createExtension() +{ + return StanzaExtension::Ptr(new TomahawkSipMessage(m_ip, m_port, m_uniqname, m_key, m_visible)); +} diff --git a/src/sip/jreen/tomahawksipmessagefactory.h b/src/sip/jreen/tomahawksipmessagefactory.h new file mode 100644 index 000000000..318208710 --- /dev/null +++ b/src/sip/jreen/tomahawksipmessagefactory.h @@ -0,0 +1,46 @@ +/**************************************************************************** + * + * This file is part of qutIM + * + * Copyright (c) 2011 by Nigmatullin Ruslan + * + *************************************************************************** + * * + * This file is part of free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of the * + * License, or (at your option) any later version. * + * * + *************************************************************************** + ****************************************************************************/ + +#ifndef ENTITYTIMEFACTORY_P_H +#define ENTITYTIMEFACTORY_P_H + +#include "tomahawksipmessage.h" + +#include + +class TomahawkSipMessageFactory : public Jreen::StanzaExtensionFactory +{ +public: + TomahawkSipMessageFactory(); + virtual ~TomahawkSipMessageFactory(); + QStringList features() const; + bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes); + void handleEndElement(const QStringRef &name, const QStringRef &uri); + void handleCharacterData(const QStringRef &text); + void serialize(Jreen::StanzaExtension *extension, QXmlStreamWriter *writer); + Jreen::StanzaExtension::Ptr createExtension(); +private: + enum State { AtNowhere, AtTransport, AtCandidate } m_state; + int m_depth; + QString m_ip; + int m_port; + QString m_uniqname; + QString m_key; + bool m_visible; +}; + +#endif // ENTITYTIMEFACTORY_P_H diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index 49e6369a4..5a3688894 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -465,20 +465,23 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co CollectionItem* colItem = qobject_cast< CollectionItem* >( item ); Q_ASSERT( colItem ); - bool status = !( !colItem || colItem->source().isNull() || !colItem->source()->isOnline() ); + QPixmap avatar( RESPATH "images/user-avatar.png" ); QString tracks; int figWidth = 0; - if ( status ) + if ( status && colItem && !colItem->source().isNull() ) { tracks = QString::number( colItem->source()->trackCount() ); figWidth = painter->fontMetrics().width( tracks ); + if ( !colItem->source()->avatar().isNull() ) + avatar = colItem->source()->avatar(); } QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 ); - painter->drawPixmap( iconRect, item->icon().pixmap( iconRect.size() ) ); + + painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) ); if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected ) { diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index ea5311844..194e5be73 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -150,14 +150,14 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] ) , m_sipHandler( 0 ) , m_servent( 0 ) , m_shortcutHandler( 0 ) - , m_scrubFriendlyName( false ) , m_mainwindow( 0 ) { qDebug() << "TomahawkApp thread:" << this->thread(); - setOrganizationName( QLatin1String( ORGANIZATION_NAME ) ); - setOrganizationDomain( QLatin1String( ORGANIZATION_DOMAIN ) ); - setApplicationName( QLatin1String( APPLICATION_NAME ) ); - setApplicationVersion( QLatin1String( VERSION ) ); + setOrganizationName( QLatin1String( TOMAHAWK_ORGANIZATION_NAME ) ); + setOrganizationDomain( QLatin1String( TOMAHAWK_ORGANIZATION_DOMAIN ) ); + setApplicationName( QLatin1String( TOMAHAWK_APPLICATION_NAME ) ); + setApplicationVersion( QLatin1String( TOMAHAWK_VERSION ) ); + registerMetaTypes(); setupLogfile(); } @@ -192,7 +192,6 @@ TomahawkApp::init() qDebug() << "Init Echonest Factory."; GeneratorFactory::registerFactory( "echonest", new EchonestFactory ); - m_scrubFriendlyName = arguments().contains( "--demo" ); // Register shortcut handler for this platform #ifdef Q_WS_MAC m_shortcutHandler = new MacShortcutHandler( this ); diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index f28fdff43..dc734eac2 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,5 +1,5 @@ -add_subdirectory( jdns ) -add_subdirectory( qtweetlib ) +ADD_SUBDIRECTORY( jdns ) +ADD_SUBDIRECTORY( qtweetlib ) ADD_SUBDIRECTORY( libportfwd ) ADD_SUBDIRECTORY( qxt ) ADD_SUBDIRECTORY( liblastfm2 )