diff --git a/retroshare-android-service/src/retroshare-android-service.pro b/retroshare-android-service/src/retroshare-android-service.pro index d327ace4f..bede07450 100644 --- a/retroshare-android-service/src/retroshare-android-service.pro +++ b/retroshare-android-service/src/retroshare-android-service.pro @@ -2,7 +2,7 @@ TARGET = retroshare-android-service -QT += core network androidextras +QT += core network QT -= gui CONFIG += c++11 diff --git a/retroshare-android-service/src/service.cpp b/retroshare-android-service/src/service.cpp index 5cea31e5f..9359af904 100644 --- a/retroshare-android-service/src/service.cpp +++ b/retroshare-android-service/src/service.cpp @@ -18,7 +18,10 @@ #include #include -#include + +#ifdef __ANDROID__ +# include +#endif #include "retroshare/rsinit.h" #include "api/ApiServer.h" @@ -39,8 +42,10 @@ int main(int argc, char *argv[]) qDebug() << "Listening on:" << sockPath; ApiServerLocal apiServerLocal(&api, sockPath); (void) apiServerLocal; +#ifdef __ANDROID__ qDebug() << "Is service.cpp running as a service?" << QtAndroid::androidService().isValid(); qDebug() << "Is service.cpp running as an activity?" << QtAndroid::androidActivity().isValid(); +#endif while (!ctrl_mod.processShouldExit()) { diff --git a/retroshare-qml-app/src/libresapilocalclient.cpp b/retroshare-qml-app/src/libresapilocalclient.cpp index 6b7e1d1f1..aa74feab7 100644 --- a/retroshare-qml-app/src/libresapilocalclient.cpp +++ b/retroshare-qml-app/src/libresapilocalclient.cpp @@ -1,35 +1,39 @@ +/* + * RetroShare Android QML App + * Copyright (C) 2016 Gioacchino Mazzurco + * Copyright (C) 2016 Manu Pineda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + #include "libresapilocalclient.h" #include "debugutils.h" #include -/* Constructor de còpia per proves, no s'ha d'usar. -LibresapiLocalClient::LibresapiLocalClient(const LibresapiLocalClient & l) -{ - //mLocalSocket = l.mLocalSocket; - receivedBytes = l.receivedBytes; - json = l.json; -}*/ -LibresapiLocalClient::LibresapiLocalClient(const QString & socketPath) : - mLocalSocket(this) +void LibresapiLocalClient::openConnection(QString socketPath) { - myDebug(this); - mSocketPath = socketPath; - connect(& mLocalSocket, SIGNAL(error(QLocalSocket::LocalSocketError)), - this, SLOT(socketError(QLocalSocket::LocalSocketError))); - connect(& mLocalSocket, SIGNAL(readyRead()), - this, SLOT(read())); - //openConnection(); -} - - -void LibresapiLocalClient::openConnection() -{ - mLocalSocket.connectToServer(mSocketPath); + connect(& mLocalSocket, SIGNAL(error(QLocalSocket::LocalSocketError)), + this, SLOT(socketError(QLocalSocket::LocalSocketError))); + connect(& mLocalSocket, SIGNAL(readyRead()), + this, SLOT(read())); + mLocalSocket.connectToServer(socketPath); } int LibresapiLocalClient::request(const QString & path, const QString & jsonData) { + qDebug() << "LibresapiLocalClient::request()" << path << jsonData; QByteArray data; data.append(path); data.append('\n'); data.append(jsonData); data.append('\n'); @@ -38,25 +42,24 @@ int LibresapiLocalClient::request(const QString & path, const QString & jsonData return 1; } -void LibresapiLocalClient::socketError(QLocalSocket::LocalSocketError error) +void LibresapiLocalClient::socketError(QLocalSocket::LocalSocketError) { - myDebug("error!!!!\n" + mLocalSocket.errorString());//error.errorString()); + myDebug("error!!!!\n" + mLocalSocket.errorString()); } void LibresapiLocalClient::read() { - receivedBytes = mLocalSocket.readAll(); - - if(parseResponse()){ // pensar en fer un buffer per parsejar, per evitar errors. - emit goodResponseReceived(QString(receivedBytes)); - return; - } - - QString errMess = "The message was not understood!\n" - "It should be a JSON formatted text file\n" - "Its contents were:\n" + receivedBytes; - myDebug(errMess.replace(QChar('\n'), QChar::LineSeparator)); + receivedBytes = mLocalSocket.readLine(); + if(parseResponse()) // pensar en fer un buffer per parsejar, per evitar errors. + emit goodResponseReceived(QString(receivedBytes)); + else + { + QString errMess = "The message was not understood!\n" + "It should be a JSON formatted text file\n" + "Its contents were:\n" + receivedBytes; + myDebug(errMess.replace(QChar('\n'), QChar::LineSeparator)); + } } bool LibresapiLocalClient::parseResponse() diff --git a/retroshare-qml-app/src/libresapilocalclient.h b/retroshare-qml-app/src/libresapilocalclient.h index da2917359..cfbfb6dec 100644 --- a/retroshare-qml-app/src/libresapilocalclient.h +++ b/retroshare-qml-app/src/libresapilocalclient.h @@ -1,5 +1,6 @@ /* * libresapi local socket client + * Copyright (C) 2016 Gioacchino Mazzurco * Copyright (C) 2016 Manu Pineda * * This program is free software: you can redistribute it and/or modify @@ -26,39 +27,30 @@ class LibresapiLocalClient : public QObject { - Q_OBJECT + Q_OBJECT - public: +public: + LibresapiLocalClient() : mLocalSocket(this) {} - LibresapiLocalClient() {} - // LibresapiLocalClient(const LibresapiLocalClient & l); - LibresapiLocalClient(const QString & socketPath); - // potser abstreure el següent amb QUrl urlPath (path) i amb QJson jsonData. - Q_INVOKABLE int request(const QString & path, const QString & jsonData); - const QJsonDocument & getJson(); - Q_INVOKABLE void openConnection(); + // potser abstreure el següent amb QUrl urlPath (path) i amb QJson jsonData. + Q_INVOKABLE int request(const QString & path, const QString & jsonData); + const QJsonDocument & getJson(); + Q_INVOKABLE void openConnection(QString socketPath); - private: +private: + QLocalSocket mLocalSocket; + QByteArray receivedBytes; + QJsonDocument json; + //QVector responses; - QString mSocketPath; - QLocalSocket mLocalSocket; - QByteArray receivedBytes; - QJsonDocument json; - //QVector responses; + bool parseResponse(); //std::string msg); - bool parseResponse(); //std::string msg); - - private slots: - - void socketError(QLocalSocket::LocalSocketError error); - void read(); - - signals: - - void goodResponseReceived(const QString & msg);//, int requestId); - - public slots: +private slots: + void socketError(QLocalSocket::LocalSocketError error); + void read(); +signals: + void goodResponseReceived(const QString & msg);//, int requestId); }; #endif // LIBRESAPILOCALCLIENT_H diff --git a/retroshare-qml-app/src/main.cpp b/retroshare-qml-app/src/main.cpp index 05ada4369..1418ec3fb 100644 --- a/retroshare-qml-app/src/main.cpp +++ b/retroshare-qml-app/src/main.cpp @@ -22,7 +22,10 @@ #include #include -#include +#ifdef __ANDROID__ +# include +#endif + #include #include @@ -35,20 +38,28 @@ int main(int argc, char *argv[]) QGuiApplication app(argc, argv); QQmlApplicationEngine engine; + qmlRegisterType( + "org.retroshare.qml_components.LibresapiLocalClient", 1, 0, + "LibresapiLocalClient"); QString sockPath = QString::fromStdString(RsAccounts::ConfigDirectory()); sockPath.append("/libresapi.sock"); - LibresapiLocalClient llc(sockPath); - qmlRegisterType("LibresapiLocalClientQml", 1, 0, "LibresapiLocalClientComm"); - engine.rootContext()->setContextProperty("llc", &llc); - engine.load(QUrl(QLatin1String("qrc:/qml/main.qml"))); +#ifndef __ANDROID__ + sockPath = "/home/gio/.retroshare/LOC06_8730499b55bb946424d537b180bee10a/libresapi.sock"; +#endif - QFileInfo fileInfo(sockPath); + engine.rootContext()->setContextProperty("apiSocketPath", sockPath); + engine.load(QUrl(QLatin1String("qrc:/qml/main.qml"))); + QFileInfo fileInfo(sockPath); + +#ifdef __ANDROID__ qDebug() << "Is main.cpp running as a service?" << QtAndroid::androidService().isValid(); qDebug() << "Is main.cpp running as an activity?" << QtAndroid::androidActivity().isValid(); - qDebug() << "QML APP:" << sockPath << fileInfo.exists() << fileInfo.lastModified().toString(); +#endif + + qDebug() << "QML APP:" << sockPath << fileInfo.exists() << fileInfo.lastModified().toString(); return app.exec(); } diff --git a/retroshare-qml-app/src/qml.qrc b/retroshare-qml-app/src/qml.qrc index a0211e789..4bb111bc1 100644 --- a/retroshare-qml-app/src/qml.qrc +++ b/retroshare-qml-app/src/qml.qrc @@ -15,6 +15,10 @@ qml/ChannelGroupDelegate.qml qml/ApplicationBar.qml qml/AppButton.qml - qml/LibresapiLocalClientComm.qml + qml/Locations.qml + qml/jsonpath.js + qml/JSONListModel.qml + qml/Contacts.qml + qml/AddTrustedNode.qml diff --git a/retroshare-qml-app/src/qml/AddTrustedNode.qml b/retroshare-qml-app/src/qml/AddTrustedNode.qml new file mode 100644 index 000000000..80a0e094f --- /dev/null +++ b/retroshare-qml-app/src/qml/AddTrustedNode.qml @@ -0,0 +1,39 @@ +import QtQuick 2.0 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 +import org.retroshare.qml_components.LibresapiLocalClient 1.0 + +Item +{ + Component.onCompleted: + { + rsApi.openConnection(apiSocketPath) + rsApi.request("/peers/self/certificate/", "") + } + + LibresapiLocalClient + { + id: rsApi + onGoodResponseReceived: myKeyField.text = JSON.parse(msg).data.cert_string + } + + ColumnLayout + { + anchors.top: parent.top + anchors.bottom: bottomButton.top + + TextField { id: myKeyField } + TextField { id: otherKeyField } + } + + Button + { + id: bottomButton + text: "Add trusted node" + anchors.bottom: parent.bottom + onClicked: + { + rsApi.request("/peers/examine_cert/", JSON.stringify({ cert_string: otherKeyField.text })) + } + } +} diff --git a/retroshare-qml-app/src/qml/Contacts.qml b/retroshare-qml-app/src/qml/Contacts.qml new file mode 100644 index 000000000..ef4fe3a13 --- /dev/null +++ b/retroshare-qml-app/src/qml/Contacts.qml @@ -0,0 +1,56 @@ +/* + * RetroShare Android QML App + * Copyright (C) 2016 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.0 +import QtQuick.Controls 1.4 +import org.retroshare.qml_components.LibresapiLocalClient 1.0 + +Item +{ + function refreshData() + { + rsApi.openConnection(apiSocketPath) + rsApi.request("/identity/*/", "") + } + + Component.onCompleted: refreshData() + onFocusChanged: focus && refreshData() + + LibresapiLocalClient + { + id: rsApi + onGoodResponseReceived: locationsModel.json = msg + } + + JSONListModel + { + id: locationsModel + query: "$.data[*]" + } + + ListView + { + id: locationsListView + width: parent.width + height: 300 + model: locationsModel.model + delegate: Text { text: model.name } + } + + Text { text: "Contacts View"; anchors.bottom: parent.bottom } +} diff --git a/retroshare-qml-app/src/qml/JSONListModel.qml b/retroshare-qml-app/src/qml/JSONListModel.qml new file mode 100644 index 000000000..cee905d75 --- /dev/null +++ b/retroshare-qml-app/src/qml/JSONListModel.qml @@ -0,0 +1,51 @@ +/* JSONListModel - a QML ListModel with JSON and JSONPath support + * + * Copyright (c) 2012 Romain Pokrzywka (KDAB) (romain@kdab.com) + * Licensed under the MIT licence (http://opensource.org/licenses/mit-license.php) + */ + +import QtQuick 2.0 +import "jsonpath.js" as JSONPath + +Item { + property string source: "" + property string json: "" + property string query: "" + + property ListModel model : ListModel { id: jsonModel } + property alias count: jsonModel.count + + onSourceChanged: { + var xhr = new XMLHttpRequest; + xhr.open("GET", source); + xhr.onreadystatechange = function() { + if (xhr.readyState == XMLHttpRequest.DONE) + json = xhr.responseText; + } + xhr.send(); + } + + onJsonChanged: updateJSONModel() + onQueryChanged: updateJSONModel() + + function updateJSONModel() { + jsonModel.clear(); + + if ( json === "" ) + return; + + var objectArray = parseJSONString(json, query); + for ( var key in objectArray ) { + var jo = objectArray[key]; + jsonModel.append( jo ); + } + } + + function parseJSONString(jsonString, jsonPathQuery) { + var objectArray = JSON.parse(jsonString); + if ( jsonPathQuery !== "" ) + objectArray = JSONPath.jsonPath(objectArray, jsonPathQuery); + + return objectArray; + } +} diff --git a/retroshare-qml-app/src/qml/LibresapiLocalClientComm.qml b/retroshare-qml-app/src/qml/LibresapiLocalClientComm.qml deleted file mode 100644 index 75233c4ab..000000000 --- a/retroshare-qml-app/src/qml/LibresapiLocalClientComm.qml +++ /dev/null @@ -1,5 +0,0 @@ -import LibresapiLocalClientQml 1.0 - -LibresapiLocalClientComm { - id: llc -} diff --git a/retroshare-qml-app/src/qml/Locations.qml b/retroshare-qml-app/src/qml/Locations.qml new file mode 100644 index 000000000..3e3c5e62e --- /dev/null +++ b/retroshare-qml-app/src/qml/Locations.qml @@ -0,0 +1,152 @@ +/* + * RetroShare Android QML App + * Copyright (C) 2016 Gioacchino Mazzurco + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.0 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.3 +import org.retroshare.qml_components.LibresapiLocalClient 1.0 + +Item +{ + id: locationView + state: "selectLocation" + + states: + [ + State + { + name: "selectLocation" + PropertyChanges { target: locationsListView; visible: true } + PropertyChanges { target: createLocationView; visible: false } + PropertyChanges + { + target: bottomButton + text: "Create new location" + onClicked: locationView.state = "createLocation" + } + }, + State + { + name: "createLocation" + PropertyChanges { target: locationsListView; visible: false } + PropertyChanges { target: createLocationView; visible: true } + PropertyChanges + { + target: bottomButton + text: "Save" + onClicked: + { + var jsonData = { pgp_name: nameField.text, ssl_name: nameField.text, pgp_password: passwordField.text } + rsApi.request("/control/create_location/", JSON.stringify(jsonData)) + onClicked: locationView.state = "savingLocation" + } + } + }, + State + { + name: "savingLocation" + PropertyChanges { target: locationsListView; visible: false } + PropertyChanges { target: createLocationView; color: "grey" } + PropertyChanges + { + target: bottomButton + text: "Saving..." + enabled: false + } + }, + State + { + name: "loggingIn" + PropertyChanges { target: locationsListView; visible: false } + PropertyChanges { target: createLocationView; visible: true } + PropertyChanges { target: nameField; enabled: false} + PropertyChanges + { + target: bottomButton + text: "Login" + enabled: true + onClicked: + { + var jsonData = { id: nameField.sslid, autologin: false } + rsApi.request("/control/login/", JSON.stringify(jsonData)) + jsonData = { password: passwordField.text } + rsApi.request("/control/password/", JSON.stringify(jsonData)) + } + } + } + ] + + Component.onCompleted: + { + rsApi.openConnection(apiSocketPath) + rsApi.request("/control/locations/", "") + } + + LibresapiLocalClient + { + id: rsApi + onGoodResponseReceived: locationsModel.json = msg + } + + JSONListModel + { + id: locationsModel + query: "$.data[*]" + } + + ListView + { + id: locationsListView + width: parent.width + anchors.top: parent.top + anchors.bottom: bottomButton.top + model: locationsModel.model + delegate: Button + { + text: model.name + property string sslid: model.id + onClicked: + { + locationView.state = "loggingIn" + nameField.text = text + } + } + visible: false + } + + ColumnLayout + { + id: createLocationView + width: parent.width + anchors.top: parent.top + anchors.bottom: bottomButton.top + visible: false + + Row { Text {text: "Name:" } TextField { id: nameField; property string sslid } } + Row { Text {text: "Password:" } TextField { id: passwordField; echoMode: PasswordEchoOnEdit } } + } + + Text { text: "Locations View"; anchors.bottom: bottomButton.top } + + Button + { + id: bottomButton + text: "Create new location" + anchors.bottom: parent.bottom + } +} diff --git a/retroshare-qml-app/src/qml/jsonpath.js b/retroshare-qml-app/src/qml/jsonpath.js new file mode 100644 index 000000000..2cb6bb07e --- /dev/null +++ b/retroshare-qml-app/src/qml/jsonpath.js @@ -0,0 +1,88 @@ +/* JSONPath 0.8.5 - XPath for JSON + * + * Copyright (c) 2007 Stefan Goessner (goessner.net) + * Licensed under the MIT (MIT-LICENSE.txt) licence. + * + */ +function jsonPath(obj, expr, arg) { + var P = { + resultType: arg && arg.resultType || "VALUE", + result: [], + normalize: function(expr) { + var subx = []; + return expr.replace(/[\['](\??\(.*?\))[\]']|\['(.*?)'\]/g, function($0,$1,$2){return "[#"+(subx.push($1||$2)-1)+"]";}) /* http://code.google.com/p/jsonpath/issues/detail?id=4 */ + .replace(/'?\.'?|\['?/g, ";") + .replace(/;;;|;;/g, ";..;") + .replace(/;$|'?\]|'$/g, "") + .replace(/#([0-9]+)/g, function($0,$1){return subx[$1];}); + }, + asPath: function(path) { + var x = path.split(";"), p = "$"; + for (var i=1,n=x.length; i + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ import QtQuick 2.2 -import QtQuick.Layouts 1.1 -import QtQuick.Controls 1.1 // millor fer servir 2.0 o més -import LibresapiLocalClientQml 1.0 +import QtQuick.Controls 2.0 +import org.retroshare.qml_components.LibresapiLocalClient 1.0 -ApplicationWindow { - visible: true - width: 640 - height: 480 - title: qsTr("RSChat") +ApplicationWindow +{ + id: mainWindow + visible: true + title: qsTr("RSChat") + Rectangle + { + id: mainView + anchors.fill: parent; + + states: + [ + State + { + name: "waiting_account_select"; + PropertyChanges { target: swipeView; currentIndex: 1 } + }, + State + { + name: "running_ok" + PropertyChanges { target: swipeView; currentIndex: 2 } + }, + State + { + name: "running_ok_no_full_control" + PropertyChanges { target: swipeView; currentIndex: 2 } + } + ] + + LibresapiLocalClient + { + onGoodResponseReceived: + { + var jsonReponse = JSON.parse(msg) + mainView.state = jsonReponse.data.runstate + } + Component.onCompleted: + { + openConnection(apiSocketPath) + request("/control/runstate/", "") + } + } + + SwipeView + { + id: swipeView + anchors.fill: parent + visible: true + currentIndex: 1 + + Locations + { + id: locationsView + visible: true + } + + AddTrustedNode + { + id: addTrustedNodeView + visible: true + } + + Contacts + { + id: contactsView + visible: true + } + } + } /* - LibresapiLocalClientComm{ - id: llc - onGoodResponseReceived: gxss.title = msg - - }*/ - onSceneGraphInitialized: llc.openConnection() + onSceneGraphInitialized: llc.openConnection() Rectangle { id: page @@ -154,7 +225,5 @@ ApplicationWindow { } } } + */ } - - - diff --git a/retroshare-qml-app/src/retroshare-qml-app.pro b/retroshare-qml-app/src/retroshare-qml-app.pro index b9c79f8ec..63e34a404 100644 --- a/retroshare-qml-app/src/retroshare-qml-app.pro +++ b/retroshare-qml-app/src/retroshare-qml-app.pro @@ -1,6 +1,6 @@ !include("../../retroshare.pri"): error("Could not include file ../../retroshare.pri") -QT += qml quick androidextras +QT += qml quick CONFIG += c++11 diff --git a/retroshare.pri b/retroshare.pri index 08bb84a7d..aaee2e406 100644 --- a/retroshare.pri +++ b/retroshare.pri @@ -52,6 +52,7 @@ unix { android-g++ { CONFIG *= no_libresapihttpserver no_sqlcipher upnp_libupnp CONFIG -= libresapihttpserver sqlcipher upnp_miniupnpc + QT *= androidextras DEFINES *= "fopen64=fopen" DEFINES *= "fseeko64=fseeko" DEFINES *= "ftello64=ftello"