diff --git a/CMakeLists.txt b/CMakeLists.txt index 89ad426d1..0958f1d9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,8 +60,8 @@ pkg_check_modules(PLIST libplist) pkg_check_modules(USBMUXD libusbmuxd) pkg_check_modules(LIBMTP libmtp>=1.0) pkg_check_modules(INDICATEQT indicate-qt) -pkg_check_modules(QJSON QJson) pkg_check_modules(ARCHIVE libarchive) +pkg_check_modules(GLOOX gloox>=1.0) if (WIN32) find_package(ZLIB REQUIRED) @@ -235,9 +235,9 @@ endif(ENABLE_VISUALISATIONS) # need from it are private. option(STATIC_SQLITE "Compile and use a static sqlite3 library" ON) -if(ENABLE_REMOTE AND QJSON_LIBRARIES AND QJSON_INCLUDE_DIRS) +if(ENABLE_REMOTE AND GLOOX_LIBRARIES) set(HAVE_REMOTE ON) -endif(ENABLE_REMOTE AND QJSON_LIBRARIES AND QJSON_INCLUDE_DIRS) +endif(ENABLE_REMOTE AND GLOOX_LIBRARIES) set(HAVE_STATIC_SQLITE ${STATIC_SQLITE}) if(STATIC_SQLITE) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5ad91e0fc..5f2a14389 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -788,12 +788,10 @@ if(HAVE_SCRIPTING_PYTHON) endif(HAVE_SCRIPTING_PYTHON) if(HAVE_REMOTE) - include_directories(${QJSON_INCLUDE_DIRS}) - link_directories(${QJSON_LIBRARY_DIRS}) - list(APPEND HEADERS remote/httpserver.h) - list(APPEND HEADERS remote/httpconnection.h) - list(APPEND SOURCES remote/httpserver.cpp) - list(APPEND SOURCES remote/httpconnection.cpp) + include_directories(${GLOOX_INCLUDE_DIRS}) + link_directories(${GLOOX_LIBRARY_DIRS}) + list(APPEND HEADERS remote/xmpp.h) + list(APPEND SOURCES remote/xmpp.cpp) list(APPEND SOURCES remote/zeroconf.cpp) if(APPLE) @@ -965,7 +963,7 @@ if(HAVE_SCRIPTING_PYTHON) endif(HAVE_SCRIPTING_PYTHON) if(HAVE_REMOTE) - target_link_libraries(clementine_lib ${QJSON_LIBRARIES}) + target_link_libraries(clementine_lib ${GLOOX_LIBRARIES}) endif(HAVE_REMOTE) if (APPLE) diff --git a/src/main.cpp b/src/main.cpp index bae9ce8e9..0f6a1c4d7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -93,7 +93,7 @@ using boost::scoped_ptr; #endif #ifdef HAVE_REMOTE -#include "remote/httpserver.h" +#include "remote/xmpp.h" #include "remote/zeroconf.h" #endif @@ -333,12 +333,10 @@ int main(int argc, char *argv[]) { #ifdef HAVE_REMOTE Zeroconf* zeroconf = Zeroconf::GetZeroconf(); if (zeroconf) { - HttpServer* server = new HttpServer(&player); - int port = 12345; - while (!server->Listen(QHostAddress::Any, port)) { ++port; } - - zeroconf->Publish("local", "_clementine._tcp", "Clementine", port); + zeroconf->Publish("local", "_clementine._tcp", "Clementine", 12345); } + XMPP xmpp; + xmpp.Connect("timetabletest2@googlemail.com", "timetabletestpassword"); #endif // Window diff --git a/src/remote/httpconnection.cpp b/src/remote/httpconnection.cpp deleted file mode 100644 index 5ef61131f..000000000 --- a/src/remote/httpconnection.cpp +++ /dev/null @@ -1,142 +0,0 @@ -#include "httpconnection.h" - -#include -#include -#include - -#include - -#include "core/player.h" -#include "playlist/playlistitem.h" - -HttpConnection::HttpConnection(Player* player, QTcpSocket* socket) - : QObject(socket), - socket_(socket), - state_(WaitingForRequest), - player_(player), - cover_loader_(new AlbumCoverLoader(this)) { - connect(socket_, SIGNAL(readyRead()), SLOT(ReadyRead())); - connect(cover_loader_, SIGNAL(ImageLoaded(quint64, const QImage&)), - SLOT(ImageReady(quint64, const QImage&))); - connect(socket_, SIGNAL(disconnected()), socket_, SLOT(deleteLater())); - - cover_loader_->SetDesiredHeight(400); - cover_loader_->SetScaleOutputImage(true); -} - -void HttpConnection::ReadyRead() { - switch (state_) { - case WaitingForRequest: - if (socket_->canReadLine()) { - QString line = socket_->readLine(); - if (ParseRequest(line)) { - state_ = WaitingForHeaders; - } else { - state_ = Error; - } - } - break; - case WaitingForHeaders: - while (socket_->canReadLine()) { - QByteArray line = socket_->readLine(); - if (line == "\r\n") { - DoRequest(); - state_ = Finished; - } else { - // TODO: Parse headers. - } - } - break; - - default: - break; - } - - if (state_ == Error) { - socket_->close(); - socket_->deleteLater(); - return; - } - - if (socket_->canReadLine()) { - ReadyRead(); - } -} - -bool HttpConnection::ParseRequest(const QString& line) { - QStringList tokens = line.split(' ', QString::SkipEmptyParts); - if (tokens.length() != 3) { - return false; - } - const QString& method = tokens[0]; - if (method != "GET") { - return false; - } - - method_ = QNetworkAccessManager::GetOperation; - path_ = tokens[1]; - return true; -} - -void HttpConnection::DoRequest() { - PlaylistItemPtr current_item = player_->GetCurrentItem(); - if (current_item) { - quint64 id = cover_loader_->LoadImageAsync(current_item->Metadata()); - pending_tasks_[id] = current_item->Metadata(); - return; - } - - SendHeaders(); - - QVariantMap state = GetState(); - - QJson::Serializer serializer; - QString output = serializer.serialize(state); - socket_->write(output.toUtf8()); - - socket_->disconnectFromHost(); -} - -void HttpConnection::ImageReady(quint64 id, const QImage& image) { - Song song = pending_tasks_.take(id); - SendSongInfo(song, image); -} - -void HttpConnection::SendHeaders() { - socket_->write("HTTP/1.0 200 OK\r\n"); - socket_->write("Content-type: application/json\r\n"); - socket_->write("\r\n"); -} - -QVariantMap HttpConnection::GetState() { - QVariantMap json; - json.insert("state", player_->GetState()); - json.insert("volume", player_->GetVolume()); - return json; -} - -void HttpConnection::SendSongInfo(Song song, const QImage& cover) { - SendHeaders(); - - QVariantMap metadata; - metadata.insert("title", song.title()); - metadata.insert("album", song.album()); - metadata.insert("artist", song.artist()); - if (!cover.isNull()) { - QByteArray cover_data; - { - QBuffer cover_buffer(&cover_data); - cover_buffer.open(QIODevice::WriteOnly); - cover.save(&cover_buffer, "PNG"); - } - metadata.insert("cover", cover_data.toBase64()); - } - - QVariantMap state = GetState(); - state.insert("song", metadata); - - QJson::Serializer serializer; - QString output = serializer.serialize(state); - socket_->write(output.toUtf8()); - socket_->disconnectFromHost(); -} diff --git a/src/remote/httpconnection.h b/src/remote/httpconnection.h deleted file mode 100644 index 44dd91c2f..000000000 --- a/src/remote/httpconnection.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef HTTPCONNECTION_H -#define HTTPCONNECTION_H - -#include -#include -#include - -#include "core/song.h" - -class QTcpSocket; - -class AlbumCoverLoader; -class Player; - -class HttpConnection : public QObject { - Q_OBJECT - public: - HttpConnection(Player* player, QTcpSocket* sock); - - private slots: - void ReadyRead(); - void ImageReady(quint64 id, const QImage& image); - - private: - void DoRequest(); - bool ParseRequest(const QString& line); - void SendHeaders(); - QVariantMap GetState(); - void SendSongInfo(Song song, const QImage& cover); - - QTcpSocket* socket_; - - enum State { - WaitingForRequest, - WaitingForHeaders, - WaitingForRequestFinish, - Finished, - Error, - } state_; - - QNetworkAccessManager::Operation method_; - QString path_; - - Player* player_; - AlbumCoverLoader* cover_loader_; - - QMap pending_tasks_; -}; - -#endif diff --git a/src/remote/httpserver.cpp b/src/remote/httpserver.cpp deleted file mode 100644 index 15fa8a2f1..000000000 --- a/src/remote/httpserver.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "httpserver.h" - -#include -#include - -#include "httpconnection.h" - -HttpServer::HttpServer(Player* player, QObject* parent) - : QObject(parent), - player_(player) { - connect(&server_, SIGNAL(newConnection()), SLOT(NewConnection())); -} - -bool HttpServer::Listen(const QHostAddress& addr, quint16 port) { - return server_.listen(addr, port); -} - -void HttpServer::NewConnection() { - qDebug() << Q_FUNC_INFO; - QTcpSocket* socket = server_.nextPendingConnection(); - new HttpConnection(player_, socket); -} diff --git a/src/remote/httpserver.h b/src/remote/httpserver.h deleted file mode 100644 index 4d53a84b9..000000000 --- a/src/remote/httpserver.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef HTTPSERVER_H -#define HTTPSERVER_H - -#include - -class Player; - -class HttpServer : public QObject { - Q_OBJECT - public: - HttpServer(Player* player, QObject* parent = 0); - bool Listen(const QHostAddress& addr, quint16 port); - - private slots: - void NewConnection(); - - private: - QTcpServer server_; - - Player* player_; -}; - -#endif diff --git a/src/remote/xmpp.cpp b/src/remote/xmpp.cpp new file mode 100644 index 000000000..c70452b2e --- /dev/null +++ b/src/remote/xmpp.cpp @@ -0,0 +1,52 @@ +#include "xmpp.h" + +#include +#include + +#include + +using gloox::Client; +using gloox::ConnectionTCPClient; +using gloox::JID; +using gloox::Message; +using gloox::MessageSession; + +XMPP::XMPP() { + +} + +XMPP::~XMPP() { + +} + +bool XMPP::Connect(const QString& jid, const QString& password) { + qDebug() << Q_FUNC_INFO; + // TODO: Generate <256 char resource. + JID j(jid.toUtf8().constData()); + qDebug() << "Resource:" << j.resource().c_str(); + client_.reset(new Client(j, password.toUtf8().constData())); + client_->registerMessageHandler(this); + client_->setServer("talk.google.com"); + client_->connect(false); + qDebug() << Q_FUNC_INFO; + int fd = static_cast(client_->connectionImpl())->socket(); + + notifier_.reset(new QSocketNotifier(fd, QSocketNotifier::Read)); + connect(notifier_.get(), SIGNAL(activated(int)), SLOT(Receive())); + + qDebug() << Q_FUNC_INFO; + return true; +} + +void XMPP::handleMessage(const Message& stanza, MessageSession* session) { + qDebug() << Q_FUNC_INFO; + qDebug() << stanza.tag()->xml().c_str(); + qDebug() << "resource:" << client_->resource().c_str(); + Message reply(Message::Chat, stanza.from(), "Hello World!"); + client_->send(reply); +} + +void XMPP::Receive() { + qDebug() << Q_FUNC_INFO; + client_->recv(); +} diff --git a/src/remote/xmpp.h b/src/remote/xmpp.h new file mode 100644 index 000000000..02bc87202 --- /dev/null +++ b/src/remote/xmpp.h @@ -0,0 +1,32 @@ +#ifndef XMPP_H +#define XMPP_H + +#include +#include + +#include + +#include +#include + +class XMPP : public QObject, public gloox::MessageHandler { + Q_OBJECT + public: + XMPP(); + virtual ~XMPP(); + + bool Connect(const QString& jid, const QString& password); + + private slots: + void Receive(); + + private: + // gloox::MessageHandler + virtual void handleMessage(const gloox::Message& stanza, + gloox::MessageSession* session = 0); + + boost::scoped_ptr client_; + boost::scoped_ptr notifier_; +}; + +#endif // XMPP_H