diff --git a/cli/kdeconnect-cli.cpp b/cli/kdeconnect-cli.cpp index d899968cf..8d6d6987c 100644 --- a/cli/kdeconnect-cli.cpp +++ b/cli/kdeconnect-cli.cpp @@ -43,6 +43,7 @@ int main(int argc, char** argv) parser.addOption(QCommandLineOption("unpair", i18n("Stop pairing to a said device"))); parser.addOption(QCommandLineOption("ping", i18n("Sends a ping to said device"))); parser.addOption(QCommandLineOption("list-notifications", i18n("Display the notifications on a said device"))); + parser.addOption(QCommandLineOption("ping-msg ", i18n("Same as ping but you can customize the shown message."), i18n("message"))); parser.addOption(QCommandLineOption("device", i18n("Device ID"), "dev")); about.setupCommandLine(&parser); @@ -70,6 +71,9 @@ int main(int argc, char** argv) << ": " << idx.data(DevicesModel::IdModelRole).toString().toStdString() << ' ' << statusInfo.toStdString() << std::endl; } std::cout << devices.rowCount() << " devices found" << std::endl; + } else if(parser.isSet("refresh")) { + QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.kdeconnect", "/modules/kdeconnect", "org.kde.kdeconnect.daemon", "forceOnNetworkChange"); + QDBusConnection::sessionBus().call(msg); } else { QString device; if(!parser.isSet("device")) { @@ -102,8 +106,12 @@ int main(int argc, char** argv) QDBusPendingReply req = dev.unpair(); req.waitForFinished(); } - } else if(parser.isSet("ping")) { + } else if(parser.isSet("ping") || parser.isSet("ping-msg")) { QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.kdeconnect", "/modules/kdeconnect/devices/"+device+"/ping", "org.kde.kdeconnect.device.ping", "sendPing"); + if (parser.isSet("ping-msg")) { + QString message = parser.value("ping-msg"); + msg.setArguments(QVariantList() << message); + } QDBusConnection::sessionBus().call(msg); } else if(parser.isSet("list-notifications")) { NotificationsModel notifications; diff --git a/cmake/FindLibFakeKey.cmake b/cmake/FindLibFakeKey.cmake new file mode 100644 index 000000000..d2413d867 --- /dev/null +++ b/cmake/FindLibFakeKey.cmake @@ -0,0 +1,59 @@ +# +# - Try to find the fakekey library +# Once done this will define +# +# LibFakeKey_FOUND - system has LibFakeKey +# LibFakeKey_INCLUDE_DIRS - the LibFakeKey include directory +# LibFakeKey_LIBRARIES - The libraries needed to use LibFakeKey +# LibFakeKey_VERSION - The LibFakeKey version + +# Copyright (c) 2014 Christophe Giboudeaux +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +find_package(PkgConfig QUIET REQUIRED) +pkg_check_modules(PC_LibFakeKey libfakekey) + +find_path(LibFakeKey_INCLUDE_DIRS + NAMES fakekey/fakekey.h + HINTS ${PC_LibFakeKey_LIBRARY_DIRS} +) + +find_library(LibFakeKey_LIBRARIES + NAMES fakekey + HINTS ${PC_LibFakeKey_LIBRARY_DIRS} +) + +set(LibFakeKey_VERSION ${PC_LibFakeKey_VERSION}) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(LibFakeKey + FOUND_VAR LibFakeKey_FOUND + REQUIRED_VARS LibFakeKey_LIBRARIES LibFakeKey_INCLUDE_DIRS + VERSION_VAR LibFakeKey_VERSION +) + +mark_as_advanced(LibFakeKey_LIBRARIES LibFakeKey_INCLUDE_DIRS LibFakeKey_VERSION) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 5caeedcb9..aba295459 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -23,6 +23,7 @@ set(kded_kdeconnect_SRCS kdeconnectplugin.cpp pluginloader.cpp + dbushelper.cpp networkpackage.cpp filetransferjob.cpp daemon.cpp diff --git a/core/backends/devicelink.cpp b/core/backends/devicelink.cpp index 1a61a3103..4f90754d8 100644 --- a/core/backends/devicelink.cpp +++ b/core/backends/devicelink.cpp @@ -29,6 +29,5 @@ DeviceLink::DeviceLink(const QString& deviceId, LinkProvider* parent) Q_ASSERT(!deviceId.isEmpty()); setProperty("deviceId", deviceId); - //gcc complains if we don't add something to compile on a class with virtual functions } diff --git a/core/backends/lan/lanlinkprovider.cpp b/core/backends/lan/lanlinkprovider.cpp index f352aeaf1..b77101ff1 100644 --- a/core/backends/lan/lanlinkprovider.cpp +++ b/core/backends/lan/lanlinkprovider.cpp @@ -30,6 +30,9 @@ #include #include +#include +#include + #include "landevicelink.h" void LanLinkProvider::configureSocket(QTcpSocket* socket) @@ -44,13 +47,17 @@ void LanLinkProvider::configureSocket(QTcpSocket* socket) #endif #ifdef TCP_KEEPCNT - int count = 3; // send up to 3 keepalive packets out, then disconnect if no response - setsockopt(fd, getprotobyname("TCP")->p_proto, TCP_KEEPCNT, &count, sizeof(count)); + if (getprotobyname("TCP")) { + int count = 3; // send up to 3 keepalive packets out, then disconnect if no response + setsockopt(fd, getprotobyname("TCP")->p_proto, TCP_KEEPCNT, &count, sizeof(count)); + } #endif #ifdef TCP_KEEPINTVL - int interval = 5; // send a keepalive packet out every 2 seconds (after the 5 second idle period) - setsockopt(fd, getprotobyname("TCP")->p_proto, TCP_KEEPINTVL, &interval, sizeof(interval)); + if (getprotobyname("TCP")) { + int interval = 5; // send a keepalive packet out every 2 seconds (after the 5 second idle period) + setsockopt(fd, getprotobyname("TCP")->p_proto, TCP_KEEPINTVL, &interval, sizeof(interval)); + } #endif } @@ -98,6 +105,8 @@ void LanLinkProvider::onNetworkChange(QNetworkSession::State state) NetworkPackage::createIdentityPackage(&np); np.set("tcpPort", mTcpPort); mUdpSocket.writeDatagram(np.serialize(), QHostAddress("255.255.255.255"), port); + + //TODO: Ping active connections to see if they are still reachable } //I'm the existing device, a new device is kindly introducing itself (I will create a TcpSocket) @@ -123,17 +132,17 @@ void LanLinkProvider::newUdpConnection() delete receivedPackage; } - NetworkPackage np2(""); - NetworkPackage::createIdentityPackage(&np2); + KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc"); + const QString myId = config->group("myself").readEntry("id",""); - if (receivedPackage->get("deviceId") == np2.get("deviceId")) { - //kDebug(kdeconnect_kded()) << "Ignoring my own broadcast"; + //kDebug(debugArea()) << "Ignoring my own broadcast"; + if (receivedPackage->get("deviceId") == myId) { return; } int tcpPort = receivedPackage->get("tcpPort", port); - //kDebug(kdeconnect_kded()) << "Received Udp presentation from" << sender << "asking for a tcp connection on port " << tcpPort; + //kDebug(debugArea()) << "Received Udp presentation from" << sender << "asking for a tcp connection on port " << tcpPort; QTcpSocket* socket = new QTcpSocket(this); receivedIdentityPackages[socket].np = receivedPackage; @@ -165,6 +174,8 @@ void LanLinkProvider::connected() QTcpSocket* socket = qobject_cast(sender()); + if (!socket) return; + disconnect(socket, SIGNAL(connected()), this, SLOT(connected())); disconnect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(connectError())); @@ -181,7 +192,6 @@ void LanLinkProvider::connected() bool success = deviceLink->sendPackage(np2); - //TODO: Use reverse connection too to preffer connecting a unstable device (a phone) to a stable device (a computer) if (success) { //qCDebug(KDECONNECT_CORE) << "Handshaking done (i'm the existing device)"; diff --git a/core/backends/linkprovider.h b/core/backends/linkprovider.h index 6bcdd939c..bb89d1c42 100644 --- a/core/backends/linkprovider.h +++ b/core/backends/linkprovider.h @@ -36,7 +36,7 @@ class LinkProvider public: - const static int PRIORITY_LOW = 0; //eg: 3g + const static int PRIORITY_LOW = 0; //eg: 3g internet const static int PRIORITY_MEDIUM = 50; //eg: internet const static int PRIORITY_HIGH = 100; //eg: lan diff --git a/core/daemon.cpp b/core/daemon.cpp index 20afff2bd..3bf4d1ce9 100644 --- a/core/daemon.cpp +++ b/core/daemon.cpp @@ -28,12 +28,14 @@ #include #include #include +#include #include #include #include #include "core_debug.h" +#include "dbushelper.h" #include "networkpackage.h" #include "backends/lan/lanlinkprovider.h" #include "backends/loopback/loopbacklinkprovider.h" @@ -60,12 +62,13 @@ Daemon::Daemon(QObject *parent) : QObject(parent) , d(new DaemonPrivate) { + qCDebug(KDECONNECT_CORE) << "KdeConnect daemon starting"; + KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc"); if (!config->group("myself").hasKey("id")) { QString uuid = QUuid::createUuid().toString(); - //uuids contain charcaters that are not exportable in dbus paths - uuid = uuid.mid(1, uuid.length() - 2).replace("-", "_"); + DbusHelper::filterNonExportableCharacters(uuid); config->group("myself").writeEntry("id", uuid); config->sync(); qCDebug(KDECONNECT_CORE) << "My id:" << uuid; @@ -73,7 +76,7 @@ Daemon::Daemon(QObject *parent) //qCDebug(KDECONNECT_CORE) << "QCA supported capabilities:" << QCA::supportedFeatures().join(","); if(!QCA::isSupported("rsa")) { - //TODO: Maybe display this in a more visible way? + //TODO: Display this in a notification or another visible way qCDebug(KDECONNECT_CORE) << "Error: KDE Connect could not find support for RSA in your QCA installation, if your distribution provides" << "separate packages for QCA-ossl and QCA-gnupg plugins, make sure you have them installed and try again"; return; @@ -106,6 +109,7 @@ Daemon::Daemon(QObject *parent) } privKey.close(); + //TODO: This should not store an absolute path: it will cause problems if the home folder changes, .kde4 becomes .kde (debian?), or similar... config->group("myself").writeEntry("privateKeyPath", privateKeyPath); config->sync(); } @@ -115,8 +119,9 @@ Daemon::Daemon(QObject *parent) qCDebug(KDECONNECT_CORE) << "Error: KDE Connect detects wrong permissions for private file " << config->group("myself").readEntry("privateKeyPath"); } - //Debugging - qCDebug(KDECONNECT_CORE) << "Starting KdeConnect daemon"; + //Register on DBus + QDBusConnection::sessionBus().registerService("org.kde.kdeconnect"); + QDBusConnection::sessionBus().registerObject("/modules/kdeconnect", this, QDBusConnection::ExportScriptableContents); //Load backends (hardcoded by now, should be plugins in a future) d->mLinkProviders.insert(new LanLinkProvider()); @@ -133,25 +138,28 @@ Daemon::Daemon(QObject *parent) Q_EMIT deviceAdded(id); } - //Listen to connectivity changes - QNetworkSession* network = new QNetworkSession(QNetworkConfigurationManager().defaultConfiguration()); + //Listen to new devices Q_FOREACH (LinkProvider* a, d->mLinkProviders) { - connect(network, SIGNAL(stateChanged(QNetworkSession::State)), - a, SLOT(onNetworkChange(QNetworkSession::State))); connect(a, SIGNAL(onConnectionReceived(NetworkPackage, DeviceLink*)), this, SLOT(onNewDeviceLink(NetworkPackage, DeviceLink*))); } - - QDBusConnection::sessionBus().registerService("org.kde.kdeconnect"); - QDBusConnection::sessionBus().registerObject("/modules/kdeconnect", this, QDBusConnection::ExportScriptableContents); - setDiscoveryEnabled(true); + //Listen to connectivity changes + QNetworkConfigurationManager* manager = new QNetworkConfigurationManager(); + QNetworkSession* network = new QNetworkSession(manager->defaultConfiguration()); + connect(manager, SIGNAL(configurationAdded(QNetworkConfiguration)), + this, SLOT(forceOnNetworkChange())); + Q_FOREACH (LinkProvider* a, d->mLinkProviders) { + connect(network, SIGNAL(stateChanged(QNetworkSession::State)), + a, SLOT(onNetworkChange(QNetworkSession::State))); + } + + qCDebug(KDECONNECT_CORE) << "KdeConnect daemon started"; } void Daemon::setDiscoveryEnabled(bool b) { - //Listen to incomming connections Q_FOREACH (LinkProvider* a, d->mLinkProviders) { if (b) a->onStart(); diff --git a/core/dbushelper.cpp b/core/dbushelper.cpp new file mode 100644 index 000000000..e188126d0 --- /dev/null +++ b/core/dbushelper.cpp @@ -0,0 +1,33 @@ +/** + * Copyright 2014 Albert Vaca + * + * This program is 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "dbushelper.h" + +#include + +namespace DbusHelper { + +void filterNonExportableCharacters(QString& s) +{ + static QRegExp regexp("[^A-Za-z0-9_]", Qt::CaseSensitive, QRegExp::Wildcard); + s.replace(regexp,"_"); +} + +} \ No newline at end of file diff --git a/core/dbushelper.h b/core/dbushelper.h new file mode 100644 index 000000000..43b22860c --- /dev/null +++ b/core/dbushelper.h @@ -0,0 +1,29 @@ +/** + * Copyright 2014 Albert Vaca + * + * This program is 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) version 3 or any later version + * accepted by the membership of KDE e.V. (or its successor approved + * by the membership of KDE e.V.), which shall act as a proxy + * defined in Section 14 of version 3 of the license. + * + * 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KDECONNECT_DBUSHELPER_H +#define KDECONNECT_DBUSHELPER_H +#include + +namespace DbusHelper { + void filterNonExportableCharacters(QString& s); +} + +#endif \ No newline at end of file diff --git a/core/default_args.h b/core/default_args.h index ff1b7f7ff..d198c6f44 100644 --- a/core/default_args.h +++ b/core/default_args.h @@ -40,14 +40,6 @@ struct default_arg { static int get() { return -1; } }; -//Pointer types -> NULL (partial specialization) -//NOTE: Comented because it doesn't makeno sense to send a pointer over the network, but I just left it here for reference --albertvaka -/*template -struct default_arg { - static T* get() { NULL; } -}; -*/ - //QByteArray-> empty qbytearray template<> struct default_arg { diff --git a/core/device.cpp b/core/device.cpp index 1d1fdb29a..0a5c94cac 100644 --- a/core/device.cpp +++ b/core/device.cpp @@ -71,6 +71,8 @@ Device::Device(QObject* parent, const NetworkPackage& identityPackage, DeviceLin , m_deviceType(str2type(identityPackage.get("deviceType"))) , m_pairStatus(Device::NotPaired) , m_protocolVersion(identityPackage.get("protocolVersion")) + , m_incomingCapabilities(identityPackage.get("SupportedIncomingInterfaces", QStringList()).toSet()) + , m_outgoingCapabilities(identityPackage.get("SupportedOutgoingInterfaces", QStringList()).toSet()) { initPrivateKey(); @@ -137,11 +139,27 @@ void Device::reloadPlugins() incomingInterfaces = m_pluginsByIncomingInterface.keys(plugin); outgoingInterfaces = m_pluginsByOutgoingInterface.keys(plugin); } else { - PluginData data = loader->instantiatePluginForDevice(pluginName, this); - plugin = data.plugin; - incomingInterfaces = data.incomingInterfaces; - outgoingInterfaces = data.outgoingInterfaces; + KService::Ptr service = loader->pluginService(pluginName); + incomingInterfaces = service->property("X-KdeConnect-SupportedPackageType", QVariant::StringList).toStringList(); + outgoingInterfaces = service->property("X-KdeConnect-OutgoingPackageType", QVariant::StringList).toStringList(); } + + //If we don't find intersection with the received on one end and the sent on the other, we don't + //let the plugin stay + //Also, if no capabilities are specified on the other end, we don't apply this optimizaton, as + //we asume that the other client doesn't know about capabilities. + if (!m_incomingCapabilities.isEmpty() && !m_outgoingCapabilities.isEmpty() + && m_incomingCapabilities.intersect(outgoingInterfaces.toSet()).isEmpty() + && m_outgoingCapabilities.intersect(incomingInterfaces.toSet()).isEmpty() + ) { + delete plugin; + continue; + } + + if (!plugin) { + plugin = loader->instantiatePluginForDevice(pluginName, this); + } + foreach(const QString& interface, incomingInterfaces) { newPluginsByIncomingInterface.insert(interface, plugin); } diff --git a/core/device.h b/core/device.h index d15430078..2ebb40349 100644 --- a/core/device.h +++ b/core/device.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -135,6 +136,8 @@ private: QMultiMap m_pluginsByOutgoingInterface; QTimer m_pairingTimeut; + QSet m_incomingCapabilities; + QSet m_outgoingCapabilities; void setAsPaired(); void storeAsTrusted(); diff --git a/core/filetransferjob.cpp b/core/filetransferjob.cpp index acb7d452e..7e0b2a86c 100644 --- a/core/filetransferjob.cpp +++ b/core/filetransferjob.cpp @@ -190,7 +190,7 @@ void FileTransferJob::sourceFinished() //Make sure we do not enter this function again disconnect(mOrigin.data(), SIGNAL(aboutToClose()),this, SLOT(sourceFinished())); - //TODO: MD5 check the file + //TODO: MD5-check the file if (mSize > -1 && mWritten != mSize) { qCDebug(KDECONNECT_CORE) << "Received incomplete file (" << mWritten << " of " << mSize << " bytes)"; setError(1); diff --git a/core/networkpackage.cpp b/core/networkpackage.cpp index bea3eaa4d..02a1945eb 100644 --- a/core/networkpackage.cpp +++ b/core/networkpackage.cpp @@ -35,7 +35,9 @@ #include #include +#include "dbushelper.h" #include "filetransferjob.h" +#include "pluginloader.h" const QCA::EncryptionAlgorithm NetworkPackage::EncryptionAlgorithm = QCA::EME_PKCS1v15; const int NetworkPackage::ProtocolVersion = 5; @@ -59,8 +61,10 @@ void NetworkPackage::createIdentityPackage(NetworkPackage* np) np->mPayloadSize = 0; np->set("deviceId", id); np->set("deviceName", qgetenv("USER") + "@" + QHostInfo::localHostName()); - np->set("protocolType", "desktop"); //TODO: Detect laptop, tablet, phone... + np->set("deviceType", "desktop"); //TODO: Detect laptop, tablet, phone... np->set("protocolVersion", NetworkPackage::ProtocolVersion); + np->set("SupportedIncomingInterfaces", PluginLoader::instance()->incomingInterfaces().join(",")); + np->set("SupportedOutgoingInterfaces", PluginLoader::instance()->outgoingInterfaces().join(",")); //kDebug(kdeconnect_kded()) << "createIdentityPackage" << np->serialize(); } @@ -151,6 +155,14 @@ bool NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np) } np->mPayloadTransferInfo = variant["payloadTransferInfo"].toMap(); //Will return an empty qvariantmap if was not present, which is ok + //Ids containing characters that are not allowed as dbus paths would make app crash + if (np->mBody.contains("deviceId")) + { + QString deviceId = np->get("deviceId"); + DbusHelper::filterNonExportableCharacters(deviceId); + np->set("deviceId", deviceId); + } + return true; } diff --git a/core/networkpackage.h b/core/networkpackage.h index dec011156..cb8b4a85b 100644 --- a/core/networkpackage.h +++ b/core/networkpackage.h @@ -93,7 +93,7 @@ private: QString mId; QString mType; QVariantMap mBody; - + QSharedPointer mPayload; int mPayloadSize; QVariantMap mPayloadTransferInfo; diff --git a/core/pluginloader.cpp b/core/pluginloader.cpp index b374ac726..37bd4baac 100644 --- a/core/pluginloader.cpp +++ b/core/pluginloader.cpp @@ -57,9 +57,9 @@ KPluginInfo PluginLoader::getPluginInfo(const QString& name) const return KPluginInfo(service); } -PluginData PluginLoader::instantiatePluginForDevice(const QString& name, Device* device) const +KdeConnectPlugin* PluginLoader::instantiatePluginForDevice(const QString& name, Device* device) const { - PluginData ret; + KdeConnectPlugin* ret = 0; KService::Ptr service = plugins[name]; if (!service) { @@ -73,14 +73,12 @@ PluginData PluginLoader::instantiatePluginForDevice(const QString& name, Device* return ret; } - ret.incomingInterfaces = service->property("X-KdeConnect-SupportedPackageType", QVariant::StringList).toStringList(); - ret.outgoingInterfaces = service->property("X-KdeConnect-OutgoingPackageType", QVariant::StringList).toStringList(); + QStringList outgoingInterfaces = service->property("X-KdeConnect-OutgoingPackageType", QVariant::StringList).toStringList(); QVariant deviceVariant = QVariant::fromValue(device); - //FIXME any reason to use QObject in template param instead KdeConnectPlugin? - ret.plugin = factory->create(device, QVariantList() << deviceVariant << ret.outgoingInterfaces); - if (!ret.plugin) { + ret = factory->create(device, QVariantList() << deviceVariant << outgoingInterfaces); + if (!ret) { qCDebug(KDECONNECT_CORE) << "Error loading plugin"; return ret; } @@ -89,3 +87,25 @@ PluginData PluginLoader::instantiatePluginForDevice(const QString& name, Device* return ret; } +KService::Ptr PluginLoader::pluginService(const QString& pluginName) const +{ + return plugins[pluginName]; +} + +QStringList PluginLoader::incomingInterfaces() const +{ + QSet ret; + foreach(const KService::Ptr& service, plugins) { + ret += service->property("X-KdeConnect-SupportedPackageType", QVariant::StringList).toStringList().toSet(); + } + return ret.toList(); +} + +QStringList PluginLoader::outgoingInterfaces() const +{ + QSet ret; + foreach(const KService::Ptr& service, plugins) { + ret += service->property("X-KdeConnect-OutgoingPackageType", QVariant::StringList).toStringList().toSet(); + } + return ret.toList(); +} diff --git a/core/pluginloader.h b/core/pluginloader.h index 4983730c7..e92b73e29 100644 --- a/core/pluginloader.h +++ b/core/pluginloader.h @@ -32,23 +32,18 @@ class Device; class KdeConnectPlugin; -struct PluginData -{ - PluginData() : plugin(0) {} - KdeConnectPlugin* plugin; - QStringList incomingInterfaces; - QStringList outgoingInterfaces; -}; - class PluginLoader { public: static PluginLoader* instance(); + QStringList incomingInterfaces() const; + QStringList outgoingInterfaces() const; QStringList getPluginList() const; KPluginInfo getPluginInfo(const QString& name) const; - PluginData instantiatePluginForDevice(const QString& name, Device* device) const; + KService::Ptr pluginService(const QString& pluginName) const; + KdeConnectPlugin* instantiatePluginForDevice(const QString& name, Device* device) const; private: PluginLoader(); diff --git a/fileitemactionplugin/kdeconnectsendfile.desktop b/fileitemactionplugin/kdeconnectsendfile.desktop index 9f20b51a7..ac0d01b26 100644 --- a/fileitemactionplugin/kdeconnectsendfile.desktop +++ b/fileitemactionplugin/kdeconnectsendfile.desktop @@ -4,7 +4,10 @@ Name=Send file via KDE Connect service Name[ca]=Envia un fitxer a través del servei KDE Connect Name[cs]=Poslat soubor přes službu KDE Connect Name[da]=Send fil via KDE Connect-tjeneste +Name[de]=Datei mit KDE-Connect -Dienst versenden Name[es]=Enviar archivo usando el servicio KDE Connect +Name[fi]=Lähetä tiedosto KDE-Connect-palvelulla +Name[fr]=Envoyer un fichier via le service KDE Connect Name[hu]=Fájl küldése a KDE csatlakozás szolgáltatáson keresztül Name[nl]=Bestand via de service KDE Connect versturen Name[pl]=Wyślij plik przez usługę KDE Connect @@ -19,7 +22,10 @@ X-KDE-Submenu=Connect X-KDE-Submenu[ca]=Connecta X-KDE-Submenu[cs]=Připojit X-KDE-Submenu[da]=Forbind +X-KDE-Submenu[de]=Verbinden X-KDE-Submenu[es]=Conectar +X-KDE-Submenu[fi]=Yhdistä +X-KDE-Submenu[fr]=Connecter X-KDE-Submenu[hu]=Csatlakozás X-KDE-Submenu[nl]=Verbinden X-KDE-Submenu[pl]=Połącz diff --git a/interfaces/CMakeLists.txt b/interfaces/CMakeLists.txt index bf2662f2e..9a3dd713b 100644 --- a/interfaces/CMakeLists.txt +++ b/interfaces/CMakeLists.txt @@ -69,9 +69,10 @@ add_dependencies(kdeconnectinterfaces ) target_link_libraries(kdeconnectinterfaces - Qt5::Core - Qt5::DBus +LINK_PUBLIC Qt5::Gui + Qt5::DBus +LINK_PRIVATE KF5::ConfigCore ) diff --git a/kcm/devicessortproxymodel.h b/kcm/devicessortproxymodel.h index 3862eeba5..1b6249b3a 100644 --- a/kcm/devicessortproxymodel.h +++ b/kcm/devicessortproxymodel.h @@ -33,7 +33,7 @@ public: virtual bool lessThan(const QModelIndex& left, const QModelIndex& right) const; virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; -public slots: +public Q_SLOTS: void sourceDataChanged(QModelIndex,QModelIndex); }; diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp index 1aa793fbe..f358d2cc4 100644 --- a/kcm/kcm.cpp +++ b/kcm/kcm.cpp @@ -74,7 +74,8 @@ KdeConnectKcm::KdeConnectKcm(QWidget *parent, const QVariantList&) this, SLOT(unpair())); connect(kcmUi->ping_button, SIGNAL(pressed()), this, SLOT(sendPing())); - + connect(kcmUi->refresh_button,SIGNAL(pressed()), + this, SLOT(refresh())); } KdeConnectKcm::~KdeConnectKcm() @@ -82,6 +83,12 @@ KdeConnectKcm::~KdeConnectKcm() } +void KdeConnectKcm::refresh() +{ + QDBusMessage msg = QDBusMessage::createMethodCall("org.kde.kdeconnect", "/modules/kdeconnect", "org.kde.kdeconnect.daemon", "forceOnNetworkChange"); + QDBusConnection::sessionBus().call(msg); +} + void KdeConnectKcm::resetSelection() { kcmUi->deviceList->selectionModel()->setCurrentIndex(sortProxyModel->mapFromSource(currentIndex), QItemSelectionModel::ClearAndSelect); diff --git a/kcm/kcm.h b/kcm/kcm.h index 91ecdc718..92f123de8 100644 --- a/kcm/kcm.h +++ b/kcm/kcm.h @@ -61,6 +61,7 @@ private Q_SLOTS: void pairingSuccesful(); void pairingFailed(const QString& error); void unpaired(); + void refresh(); private: Ui::KdeConnectKcmUi* kcmUi; diff --git a/kcm/kcm.ui b/kcm/kcm.ui index a92d283f8..63ca38795 100644 --- a/kcm/kcm.ui +++ b/kcm/kcm.ui @@ -32,12 +32,16 @@ - - 0 - + + + + Refresh + + + diff --git a/kcm/kcm_kdeconnect.desktop b/kcm/kcm_kdeconnect.desktop index c1e29981d..2296175b4 100755 --- a/kcm/kcm_kdeconnect.desktop +++ b/kcm/kcm_kdeconnect.desktop @@ -18,6 +18,7 @@ Name[cs]=KDE Connect Name[da]=KDE Connect Name[de]=KDE-Connect Name[es]=KDE Connect +Name[fi]=KDE-Connect Name[fr]=KDE Connect Name[hu]=KDE csatlakozás Name[it]=KDE Connect @@ -42,6 +43,7 @@ Comment[cs]=Připojte a synchronizujte svá zařízení s KDE Comment[da]=Forbind og synkronisér dine enheder med KDE Comment[de]=Verbinden und Abgleichen Ihrer Geräte mit KDE Comment[es]=Conectar y sincronizar dispositivos con KDE +Comment[fi]=Yhdistä ja synkronoi laitteitasi KDE:ssa Comment[fr]=Connectez et synchronisez vos périphériques avec KDE Comment[hu]=Eszközök csatlakoztatása és szinkronizálása a KDE-vel Comment[it]=Connetti e sincronizza i tuoi dispositivi con KDE @@ -65,6 +67,7 @@ X-KDE-Keywords[cs]=Síť,Android,Zařízení X-KDE-Keywords[da]=Netværk,Android,Enheder X-KDE-Keywords[de]=Netzwerk,Android,Geräte X-KDE-Keywords[es]=Red,Android,Dispositivos +X-KDE-Keywords[fi]=Verkko,Android,Laitteet X-KDE-Keywords[fr]=Réseau,Android,Périphériques X-KDE-Keywords[hu]=Hálózat,Android,Eszközök X-KDE-Keywords[it]=Rete,Android,Dispositivi diff --git a/kcm/kdeconnect.desktop b/kcm/kdeconnect.desktop index 2c0a31922..819dbf15b 100755 --- a/kcm/kdeconnect.desktop +++ b/kcm/kdeconnect.desktop @@ -11,6 +11,7 @@ Name[cs]=KDE Connect Name[da]=KDE Connect Name[de]=KDE-Connect Name[es]=KDE Connect +Name[fi]=KDE-Connect Name[fr]=KDE Connect Name[hu]=KDE csatlakozás Name[it]=KDE Connect @@ -33,6 +34,7 @@ GenericName[cs]=Připojte své telefony k Pracovní ploše Plasma GenericName[da]=Forbind smartphones med din KDE Plasma Workspace GenericName[de]=Verbindung von Smartphones mit demKDE-Plasma-Arbeitsbereich GenericName[es]=Conectar teléfono inteligente al área de trabajo Plasma de KDE +GenericName[fi]=Yhdistä älypuhelimesi KDE Plasma -työtilaan GenericName[fr]=Connectez votre smartphone à votre espace de travail KDE Plasma GenericName[hu]=Okostelefonok csatlakoztatása a KDE Plasma munkaterülethez GenericName[ko]=KDE Plasma 작업 공간으로 스마트폰 연결 diff --git a/kded/kdeconnect.desktop b/kded/kdeconnect.desktop index 1ed76f325..ad509b064 100644 --- a/kded/kdeconnect.desktop +++ b/kded/kdeconnect.desktop @@ -17,6 +17,7 @@ Name[cs]=KDE Connect Name[da]=KDE Connect Name[de]=KDE-Connect Name[es]=KDE Connect +Name[fi]=KDE-Connect Name[fr]=KDE Connect Name[hu]=KDE csatlakozás Name[it]=KDE Connect @@ -41,6 +42,7 @@ Comment[cs]=Propojte KDE s vaším telefonem Comment[da]=Forbind KDE med din smartphone Comment[de]=KDE mit Ihren Smartphone verbinden Comment[es]=Conecte KDE con su teléfono móvil +Comment[fi]=Yhdistä KDE älypuhelimeesi Comment[fr]=Connectez KDE avec votre smartphone Comment[hu]=A KDE csatlakoztatása az okostelefonnal Comment[it]=Connetti KDE con il tuo smartphone diff --git a/kded/kdeconnect.notifyrc b/kded/kdeconnect.notifyrc index 794136c09..37d5fa2b0 100644 --- a/kded/kdeconnect.notifyrc +++ b/kded/kdeconnect.notifyrc @@ -8,6 +8,7 @@ Name[cs]=KDE Connect Name[da]=KDE Connect Name[de]=KDE-Connect Name[es]=KDE Connect +Name[fi]=KDE-Connect Name[fr]=KDE Connect Name[hu]=KDE csatlakozás Name[it]=KDE Connect @@ -31,6 +32,7 @@ Comment[cs]=Oznamování z vašich zařízení Comment[da]=Bekendtgørelser fra dine enheder Comment[de]=Benachrichtigungen von Ihren Geräten Comment[es]=Notificaciones de sus dispositivos +Comment[fi]=Laitteesi ilmoitukset Comment[fr]=Notifications provenant de vos périphériques Comment[hu]=Az eszközökről származó értesítések Comment[it]=Notifiche dai tuoi dispositivi @@ -56,6 +58,7 @@ Name[cs]=Volám Name[da]=Ringer Name[de]=Anruf Name[es]=Llamando +Name[fi]=Soitetaan Name[fr]=Appel Name[hu]=Hívás Name[it]=Chiamata @@ -79,6 +82,7 @@ Comment[cs]=Někdo vám volá Comment[da]=Nogen ringer til dig Comment[de]=Sie werden angerufen Comment[es]=Alguien le está llamando +Comment[fi]=Sinulle soitetaan Comment[fr]=Quelqu'un vous appelle Comment[hu]=Valaki hívja önt Comment[it]=Chiamata in arrivo @@ -105,6 +109,7 @@ Name[cs]=Zmeškané Name[da]=Ubesvaret Name[de]=Verpasst Name[es]=Perdida +Name[fi]=Ei vastattu Name[fr]=Pas de réponse Name[hu]=Nem fogadott Name[it]=Chiamata persa @@ -128,6 +133,7 @@ Comment[cs]=Máte zmeškaný hovor Comment[da]=Du har et ubesvaret opkald Comment[de]=Sie haben einen Anruf verpasst Comment[es]=Tiene una llamada perdida +Comment[fi]=Sinulla on vastaamaton puhelu Comment[fr]=Vous avez un appel manqué Comment[hu]=Nem fogadott hívása van Comment[it]=Hai una chiamata persa @@ -154,6 +160,7 @@ Name[cs]=SMS Name[da]=SMS Name[de]=SMS Name[es]=SMS +Name[fi]=Tekstiviesti Name[fr]=SMS Name[hu]=SMS Name[it]=SMS @@ -177,6 +184,7 @@ Comment[cs]=Někdo vám poslal SMS Comment[da]=Nogen sendte dig en SMS Comment[de]=Jemand hat Ihnen eine SMS gesendet Comment[es]=Alguien le ha enviado un SMS +Comment[fi]=Sinulle lähetettiin tekstiviesti Comment[fr]=Quelqu'un vous a envoyé un SMS Comment[hu]=Valaki SMS-t küldött önnek Comment[it]=Hai ricevuto un SMS @@ -203,6 +211,7 @@ Name[cs]=Baterie Name[da]=Batteri Name[de]=Akku Name[es]=Batería +Name[fi]=Akku Name[fr]=Batterie Name[hu]=Akkumulátor Name[it]=Batteria @@ -226,6 +235,7 @@ Comment[cs]=Máte slabou baterii Comment[da]=Dit batteri er på lavt niveau Comment[de]=Der Ladestand Ihres Akkus ist niedrig Comment[es]=La batería está en nivel bajo +Comment[fi]=Akkusi virta on vähissä Comment[fr]=Votre batterie est faible Comment[hu]=Az akkumulátora feszültsége alacsony Comment[it]=La tua batteria è al livello basso @@ -252,6 +262,7 @@ Name[cs]=Ping Name[da]=Ping Name[de]=Ping Name[es]=Ping +Name[fi]=Ping Name[fr]=Commande « Ping » Name[hu]=Ping Name[it]=Ping @@ -275,6 +286,7 @@ Comment[cs]=Ping přijat Comment[da]=Ping modtaget Comment[de]=Ping empfangen Comment[es]=Ping recibido +Comment[fi]=Vastaanotettiin ping Comment[fr]=Commande « Ping » reçue Comment[hu]=Ping érkezett Comment[it]=Hai ricevuto un ping @@ -301,6 +313,7 @@ Name[cs]=Upozornění Name[da]=Bekendtgørelse Name[de]=Benachrichtigung Name[es]=Notificación +Name[fi]=Ilmoitus Name[fr]=Notification Name[hu]=Értesítés Name[it]=Notifica @@ -324,6 +337,7 @@ Comment[cs]=Bylo přijato upozornění Comment[da]=Bekendtgørelse modtaget Comment[de]=Benachrichtigung eingegangen Comment[es]=Notificación recibida +Comment[fi]=Vastaanotettiin ilmoitus Comment[fr]=Notification reçue Comment[hu]=Értesítés érkezett Comment[it]=Hai ricevuto una notifica @@ -350,6 +364,7 @@ Name[cs]=Neznámý Name[da]=Ukendt Name[de]=Unbekannt Name[es]=Desconocido +Name[fi]=Tuntematon Name[fr]=Inconnu Name[hu]=Ismeretlen Name[it]=Sconsciuto @@ -373,6 +388,7 @@ Comment[cs]=Stalo se něco neznámého Comment[da]=Der skete noget ukendt Comment[de]=Etwas unbekanntes ist aufgetreten Comment[es]=Ha ocurrido algo desconocido +Comment[fi]=Jotakin outoa sattui Comment[fr]=Un évènement inconnu est survenu Comment[hu]=Valami ismeretlen történt Comment[it]=Errore imprevisto diff --git a/kio/kiokdeconnect.cpp b/kio/kiokdeconnect.cpp index 0d393ca37..707d19d92 100644 --- a/kio/kiokdeconnect.cpp +++ b/kio/kiokdeconnect.cpp @@ -83,7 +83,8 @@ void KioKdeconnect::listAllDevices() { infoMessage(i18n("Listing devices...")); - QStringList devices = m_dbusInterface->devices(true, true); //TODO: Change to all devices and show different icons for connected and disconnected? + //TODO: Change to all devices and show different icons for connected and disconnected? + QStringList devices = m_dbusInterface->devices(true, true); totalSize(devices.length()); @@ -125,44 +126,38 @@ void KioKdeconnect::listDevice() QDBusReply mountreply = interface.mountAndWait(); - if (handleDBusError(mountreply, this)) - { + if (handleDBusError(mountreply, this)) { return; } - if (!mountreply.value()) - { + if (!mountreply.value()) { error(KIO::ERR_COULD_NOT_MOUNT, i18n("Could not mount device filesystem")); return; } - QDBusReply urlreply = interface.mountPoint(); + QDBusReply< QVariantMap > urlreply = interface.getDirectories(); - if (handleDBusError(urlreply, this)) - { + if (handleDBusError(urlreply, this)) { return; } - QString url = urlreply.value(); + QVariantMap urls = urlreply.value(); - KIO::UDSEntry entry; - entry.insert(KIO::UDSEntry::UDS_NAME, "files"); - entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("Camera pictures")); - entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "folder"); - entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); - entry.insert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH); - entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, ""); - entry.insert(KIO::UDSEntry::UDS_URL, url + "/DCIM/Camera"); - listEntry(entry); + for (QVariantMap::iterator it = urls.begin(); it != urls.end(); it++) { - entry.insert(KIO::UDSEntry::UDS_NAME, "files"); - entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, i18n("All files")); - entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "folder"); - entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); - entry.insert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH); - entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, ""); - entry.insert(KIO::UDSEntry::UDS_URL, url); - listEntry(entry); + QString path = it.key(); + QString name = it.value().toString(); + + KIO::UDSEntry entry; + entry.insert(KIO::UDSEntry::UDS_NAME, "files"); + entry.insert(KIO::UDSEntry::UDS_DISPLAY_NAME, name); + entry.insert(KIO::UDSEntry::UDS_ICON_NAME, "folder"); + entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR); + entry.insert(KIO::UDSEntry::UDS_ACCESS, S_IRUSR | S_IRGRP | S_IROTH); + entry.insert(KIO::UDSEntry::UDS_MIME_TYPE, ""); + entry.insert(KIO::UDSEntry::UDS_URL, path); + listEntry(entry, false); + } infoMessage(""); finished(); diff --git a/plasmoid/package/metadata.desktop b/plasmoid/package/metadata.desktop index 02ff68281..df63128ee 100644 --- a/plasmoid/package/metadata.desktop +++ b/plasmoid/package/metadata.desktop @@ -7,6 +7,7 @@ Name[cs]=KDE Connect Name[da]=KDE Connect Name[de]=KDE-Connect Name[es]=KDE Connect +Name[fi]=KDE-Connect Name[fr]=KDE Connect Name[hu]=KDE csatlakozás Name[it]=KDE Connect @@ -30,6 +31,7 @@ Comment[cs]=Zobrazit upozornění z vašich zařízení pomocí KDE Connect Comment[da]=Vis bekendtgørelser fra dine enheder med KDE Connect Comment[de]=Zeigt Benachrichtigungen von Ihren Geräten mit KDE-Connect Comment[es]=Mostrar notificaciones de sus dispositivos usando KDE Connect +Comment[fi]=Näytä laitteidesi ilmoitukset KDE-Connectilla Comment[fr]=Afficher les notifications provenant de vos périphériques à l'aide de KDE Connect Comment[hu]=Az eszközökről származó értesítések megjelenítése a KDE csatlakozás használatával Comment[it]=Mostra le notifiche dei tuoi dispositivi tramite KDE Connect diff --git a/plugins/battery/kdeconnect_battery.desktop b/plugins/battery/kdeconnect_battery.desktop index 06f4aabbc..9601e045a 100644 --- a/plugins/battery/kdeconnect_battery.desktop +++ b/plugins/battery/kdeconnect_battery.desktop @@ -19,6 +19,7 @@ Name[cs]=Monitor baterie Name[da]=Batteriovervågning Name[de]=Akkuüberwachung Name[es]=Monitor de la batería +Name[fi]=Akkuvalvonta Name[fr]=Moniteur de batterie Name[hu]=Akkumulátorfigyelő Name[it]=Monitor batteria @@ -42,7 +43,8 @@ Comment[cs]=Zobrazit baterku vašeho telefonu vedle baterie vašeho notebooku Comment[da]=Vis dit telefonbatteri ved siden af din computers batteri Comment[de]=Zeigt den Akku Ihres Telefons neben dem Akku des Rechners Comment[es]=Muestra la batería de su teléfono junto a la batería de su equipo -Comment[fr]=Affichez la batterie de votre téléphone près de la batterie de votre téléphone +Comment[fi]=Näytä puhelimesi akku tietokoneen akun rinnalla +Comment[fr]=Affichez la batterie de votre téléphone près de la batterie de votre ordinateur Comment[hu]=A telefon akkumulátorának megjelenítése a számítógép akkumulátora mellett Comment[it]=Mostra il livello batteria del tuo telefono accanto a quella del computer Comment[ko]=폰 배터리와 컴퓨터 배터리 동시 확인 diff --git a/plugins/clipboard/kdeconnect_clipboard.desktop b/plugins/clipboard/kdeconnect_clipboard.desktop index 4f3330618..94faa7830 100644 --- a/plugins/clipboard/kdeconnect_clipboard.desktop +++ b/plugins/clipboard/kdeconnect_clipboard.desktop @@ -19,6 +19,7 @@ Name[cs]=Schránka Name[da]=Udklipsholder Name[de]=Zwischenablage Name[es]=Portapapeles +Name[fi]=Leikepöytä Name[fr]=Presse-papiers Name[hu]=Vágólap Name[it]=Appunti @@ -42,6 +43,7 @@ Comment[cs]=Sdílejte schránku mezi zařízeními Comment[da]=Del indholdet af udklipsholderen mellem enheder Comment[de]=Die Zwischenablage mit Geräten teilen Comment[es]=Compartir el portapapeles entre dispositivos +Comment[fi]=Jaa leikepöytä laitteiden välillä Comment[fr]=Partagez le presse-papiers entre périphériques Comment[hu]=Vágólap megosztása az eszközök között Comment[it]=Condividi gli appunti tra i dispositivi diff --git a/plugins/kdeconnect_plugin.desktop b/plugins/kdeconnect_plugin.desktop index ec21bb543..02bdde62e 100644 --- a/plugins/kdeconnect_plugin.desktop +++ b/plugins/kdeconnect_plugin.desktop @@ -5,11 +5,12 @@ X-KDE-Derived=KPluginInfo Name=KDEConnect Plugin Name[bg]=Приставка на KDEConnect Name[bs]=Priključak za KDE konekciju -Name[ca]=Connector del KDEConnect +Name[ca]=Connector del KDE Connect Name[cs]=Modul KDEConnect Name[da]=KDEConnect-plugin Name[de]=KDEConnect-Modul Name[es]=Complemento de KDEConnect +Name[fi]=KDE-Connect-liitännäinen Name[fr]=Module externe KDEConnect Name[hu]=KDEConnect bővítmény Name[it]=Estensione KDEConnect diff --git a/plugins/mousepad/CMakeLists.txt b/plugins/mousepad/CMakeLists.txt index abba697a3..a0994fbbe 100644 --- a/plugins/mousepad/CMakeLists.txt +++ b/plugins/mousepad/CMakeLists.txt @@ -4,12 +4,13 @@ set(kdeconnect_mousepad_SRCS find_package(XTest REQUIRED) find_package(X11 REQUIRED) +find_package(LibFakeKey REQUIRED) add_library(kdeconnect_mousepad MODULE ${kdeconnect_mousepad_SRCS}) -include_directories(${XTEST_INCLUDE_DIRS} ${X11_INCLUDE_DIR}) +include_directories(${XTEST_INCLUDE_DIRS} ${X11_INCLUDE_DIR} ${LibFakeKey_INCLUDE_DIRS}) -target_link_libraries(kdeconnect_mousepad KF5::Service kdeconnectcore Qt5::Gui ${X11_LIBRARIES} ${XTEST_LIBRARIES}) +target_link_libraries(kdeconnect_mousepad KF5::Service kdeconnectcore Qt5::Gui ${X11_LIBRARIES} ${XTEST_LIBRARIES} ${LibFakeKey_LIBRARIES}) install(TARGETS kdeconnect_mousepad DESTINATION ${PLUGIN_INSTALL_DIR} ) install(FILES kdeconnect_mousepad.desktop DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/plugins/mousepad/kdeconnect_mousepad.desktop b/plugins/mousepad/kdeconnect_mousepad.desktop index d91647873..1c3204af5 100644 --- a/plugins/mousepad/kdeconnect_mousepad.desktop +++ b/plugins/mousepad/kdeconnect_mousepad.desktop @@ -11,7 +11,39 @@ X-KDE-PluginInfo-License=GPL X-KDE-PluginInfo-EnabledByDefault=true Icon=input-mouse Name=Touchpad +Name[ca]=Plafó tàctil +Name[cs]=Touchpad +Name[da]=Touchpad +Name[de]=Touchpad +Name[es]=Cursor del ratón +Name[fi]=Kosketuslevy +Name[fr]=Pavé tactile +Name[hu]=Érintőtábla +Name[nl]=Touchpad +Name[pl]=Gładzik +Name[pt]=Rato por Toque +Name[pt_BR]=Touchpad +Name[sk]=Touchpad +Name[sv]=Tryckplatta +Name[uk]=Сенсорна панель +Name[x-test]=xxTouchpadxx Comment=Use your phone as a touchpad +Comment[ca]=Usa el vostre telèfon com un plafó tàctil +Comment[cs]=Používejte svůj telefon jako touchpad +Comment[da]=Brug din telefon som touchpad +Comment[de]=Verwendet Ihr Handy als Touchpad +Comment[es]=Usar su teléfono como cursor del ratón +Comment[fi]=Käytä puhelinta kosketuslevynä +Comment[fr]=Utilisez votre téléphone comme un pavé tactile +Comment[hu]=A telefon használata érintőtáblaként +Comment[nl]=Uw telefoon gebruiken als touchpad +Comment[pl]=Użyj swojego telefonu jako gładzika +Comment[pt]=Usar o seu telemóvel como painel de rato +Comment[pt_BR]=Use seu celular como touchpad +Comment[sk]=Použiť váš mobil ako touchpad +Comment[sv]=Använd telefonen som en tryckplatta +Comment[uk]=Використання телефону як сенсорної панелі +Comment[x-test]=xxUse your phone as a touchpadxx X-KdeConnect-SupportedPackageType=kdeconnect.mousepad X-KdeConnect-OutgoingPackageType=kdeconnect.mousepad diff --git a/plugins/mousepad/mousepadplugin.cpp b/plugins/mousepad/mousepadplugin.cpp index 507522d3b..fea207856 100644 --- a/plugins/mousepad/mousepadplugin.cpp +++ b/plugins/mousepad/mousepadplugin.cpp @@ -19,16 +19,46 @@ */ #include "mousepadplugin.h" -#include - #include +#include +#include +#include +#include K_PLUGIN_FACTORY( KdeConnectPluginFactory, registerPlugin< MousepadPlugin >(); ) -// Source: http://bharathisubramanian.wordpress.com/2010/04/01/x11-fake-mouse-events-generation-using-xtest/ +enum MouseButtons { + LeftMouseButton = 1, + MiddleMouseButton = 2, + RightMouseButton = 3, + MouseWheelUp = 4, + MouseWheelDown = 5 +}; + +//Translation table to keep in sync within all the implementations +int SpecialKeysMap[] = { + 0, // Invalid + XK_BackSpace, // 1 + XK_Tab, // 2 + XK_Linefeed, // 3 + XK_Left, // 4 + XK_Up, // 5 + XK_Right, // 6 + XK_Down, // 7 + XK_Page_Up, // 8 + XK_Page_Down, // 9 + XK_Home, // 10 + XK_End, // 11 + XK_Return, // 12 + XK_Delete, // 13 + XK_Escape, // 14 +}; + +template +size_t arraySize(T(&arr)[N]) { (void)arr; return N; } MousepadPlugin::MousepadPlugin(QObject* parent, const QVariantList& args) - : KdeConnectPlugin(parent, args), m_display(0) + : KdeConnectPlugin(parent, args), m_display(0), m_fakekey(0) { } @@ -39,10 +69,16 @@ MousepadPlugin::~MousepadPlugin() XCloseDisplay(m_display); m_display = 0; } + if (m_fakekey) { + free(m_fakekey); + m_fakekey = 0; + } } bool MousepadPlugin::receivePackage(const NetworkPackage& np) { + //TODO: Split mouse/keyboard in two different plugins to avoid big if statements + float dx = np.get("dx", 0); float dy = np.get("dy", 0); @@ -51,39 +87,74 @@ bool MousepadPlugin::receivePackage(const NetworkPackage& np) bool isMiddleClick = np.get("middleclick", false); bool isRightClick = np.get("rightclick", false); bool isScroll = np.get("scroll", false); + QString key = np.get("key", ""); + int specialKey = np.get("specialKey", 0); + + if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isScroll || !key.isEmpty() || specialKey) { - if (isSingleClick || isDoubleClick || isMiddleClick || isRightClick || isScroll) { if(!m_display) { m_display = XOpenDisplay(NULL); + if(!m_display) { + qWarning() << "Failed to open X11 display"; + return false; + } } - if(m_display) { - if (isSingleClick) { - XTestFakeButtonEvent(m_display, LeftMouseButton, true, CurrentTime); - XTestFakeButtonEvent(m_display, LeftMouseButton, false, CurrentTime); - } else if (isDoubleClick) { - XTestFakeButtonEvent(m_display, LeftMouseButton, true, CurrentTime); - XTestFakeButtonEvent(m_display, LeftMouseButton, false, CurrentTime); - XTestFakeButtonEvent(m_display, LeftMouseButton, true, CurrentTime); - XTestFakeButtonEvent(m_display, LeftMouseButton, false, CurrentTime); - } else if (isMiddleClick) { - XTestFakeButtonEvent(m_display, MiddleMouseButton, true, CurrentTime); - XTestFakeButtonEvent(m_display, MiddleMouseButton, false, CurrentTime); - } else if (isRightClick) { - XTestFakeButtonEvent(m_display, RightMouseButton, true, CurrentTime); - XTestFakeButtonEvent(m_display, RightMouseButton, false, CurrentTime); - } else if( isScroll ) { - if (dy < 0) { - XTestFakeButtonEvent(m_display, MouseWheelDown, true, CurrentTime); - XTestFakeButtonEvent(m_display, MouseWheelDown, false, CurrentTime); - } else if (dy > 0) { - XTestFakeButtonEvent(m_display, MouseWheelUp, true, CurrentTime); - XTestFakeButtonEvent(m_display, MouseWheelUp, false, CurrentTime); - } + if (isSingleClick) { + XTestFakeButtonEvent(m_display, LeftMouseButton, True, 0); + XTestFakeButtonEvent(m_display, LeftMouseButton, False, 0); + } else if (isDoubleClick) { + XTestFakeButtonEvent(m_display, LeftMouseButton, True, 0); + XTestFakeButtonEvent(m_display, LeftMouseButton, False, 0); + XTestFakeButtonEvent(m_display, LeftMouseButton, True, 0); + XTestFakeButtonEvent(m_display, LeftMouseButton, False, 0); + } else if (isMiddleClick) { + XTestFakeButtonEvent(m_display, MiddleMouseButton, True, 0); + XTestFakeButtonEvent(m_display, MiddleMouseButton, False, 0); + } else if (isRightClick) { + XTestFakeButtonEvent(m_display, RightMouseButton, True, 0); + XTestFakeButtonEvent(m_display, RightMouseButton, False, 0); + } else if( isScroll ) { + if (dy < 0) { + XTestFakeButtonEvent(m_display, MouseWheelDown, True, 0); + XTestFakeButtonEvent(m_display, MouseWheelDown, False, 0); + } else if (dy > 0) { + XTestFakeButtonEvent(m_display, MouseWheelUp, True, 0); + XTestFakeButtonEvent(m_display, MouseWheelUp, False, 0); } - XFlush(m_display); + } else if (!key.isEmpty() || specialKey) { + + if (specialKey) + { + if (specialKey > (int)arraySize(SpecialKeysMap)) { + qWarning() << "Unsupported special key identifier"; + return false; + } + + int keycode = XKeysymToKeycode(m_display, SpecialKeysMap[specialKey]); + XTestFakeKeyEvent (m_display, keycode, True, 0); + XTestFakeKeyEvent (m_display, keycode, False, 0); + + } else { + + if (!m_fakekey) { + m_fakekey = fakekey_init(m_display); + if (!m_fakekey) { + qWarning() << "Failed to initialize libfakekey"; + return false; + } + } + + //We use fakekey here instead of XTest (above) because it can handle utf characters instead of keycodes. + fakekey_press(m_fakekey, (const unsigned char*)key.toUtf8().constData(), -1, 0); + fakekey_release(m_fakekey); + } + } - } else { + + XFlush(m_display); + + } else { //Is a mouse move event QPoint point = QCursor::pos(); QCursor::setPos(point.x() + (int)dx, point.y() + (int)dy); } diff --git a/plugins/mousepad/mousepadplugin.h b/plugins/mousepad/mousepadplugin.h index b6f418e11..e8ce48028 100644 --- a/plugins/mousepad/mousepadplugin.h +++ b/plugins/mousepad/mousepadplugin.h @@ -28,19 +28,13 @@ #define PACKAGE_TYPE_MOUSEPAD QLatin1String("kdeconnect.mousepad") +struct FakeKey; + class MousepadPlugin : public KdeConnectPlugin { Q_OBJECT - enum MouseButtons { - LeftMouseButton = 1, - MiddleMouseButton = 2, - RightMouseButton = 3, - MouseWheelUp = 4, - MouseWheelDown = 5 - }; - public: explicit MousepadPlugin(QObject *parent, const QVariantList &args); virtual ~MousepadPlugin(); @@ -50,6 +44,8 @@ public: private: Display *m_display; + FakeKey* m_fakekey; + }; #endif diff --git a/plugins/mpriscontrol/kdeconnect_mpriscontrol.desktop b/plugins/mpriscontrol/kdeconnect_mpriscontrol.desktop index f7d3c24a1..e9d4e3ca7 100644 --- a/plugins/mpriscontrol/kdeconnect_mpriscontrol.desktop +++ b/plugins/mpriscontrol/kdeconnect_mpriscontrol.desktop @@ -19,6 +19,7 @@ Name[cs]=Přijímač ovládání multimédií Name[da]=Modtager til multimediebetjening Name[de]=Steuerung für Multimedia-Empfänger Name[es]=Receptor de control multimedia +Name[fi]=Multimediakaukosäädin Name[fr]=Receveur de contrôle multimédia Name[hu]=Multimédia vezérlés vevő Name[it]=Ricevitore telecomando multimediale @@ -41,6 +42,7 @@ Comment[cs]=Vzdálené ovládání pro vaši hudbu a videa Comment[da]=Fjernbetjening til din musik og dine videoer Comment[de]=Fernbedienung für Musik und Videos Comment[es]=Controle a distancia su música y sus vídeos +Comment[fi]=Kaukosäädin musiikkiisi ja videoihisi Comment[fr]=Contrôlez à distance votre musique et vos vidéos Comment[hu]=Távirányító a zenékhez és videókhoz Comment[it]=Controlla la riproduzione audio/video del pc dal telefono diff --git a/plugins/mpriscontrol/mpriscontrolplugin.cpp b/plugins/mpriscontrol/mpriscontrolplugin.cpp index 104c65a3e..65b44b198 100644 --- a/plugins/mpriscontrol/mpriscontrolplugin.cpp +++ b/plugins/mpriscontrol/mpriscontrolplugin.cpp @@ -20,7 +20,6 @@ #include "mpriscontrolplugin.h" - #include #include #include @@ -160,7 +159,7 @@ bool MprisControlPlugin::receivePackage (const NetworkPackage& np) if (np.has("action")) { const QString& action = np.get("action"); qCDebug(KDECONNECT_PLUGIN_MPRIS) << "Calling action" << action << "in" << playerList[player]; - //TODO: Check for valid actions + //TODO: Check for valid actions, currently we trust anything the other end sends us mprisInterface.call(action); } if (np.has("setVolume")) { diff --git a/plugins/notifications/kdeconnect_notifications.desktop b/plugins/notifications/kdeconnect_notifications.desktop index 3c11a2866..040f5fef5 100644 --- a/plugins/notifications/kdeconnect_notifications.desktop +++ b/plugins/notifications/kdeconnect_notifications.desktop @@ -19,6 +19,7 @@ Name[cs]=Synchronizace hlášení Name[da]=Synk. af bekendtgørelser Name[de]=Benachrichtigungs-Abgleich Name[es]=Sincronizar notificaciones +Name[fi]=Ilmoitusten synkronointi Name[fr]=Synchronisation de notifications Name[hu]=Értesítés szinkronizáció Name[it]=Sincronizzazione notifiche @@ -42,6 +43,7 @@ Comment[cs]=Zobrazit upozornění z telefonu v KDE a udržovat je synchronizovan Comment[da]=Vis telefonbekendtgørelser i KDE og hold dem synkroniseret Comment[de]=Benachrichtigungen in KDE anzeigen und abgleichen Comment[es]=Mostrar las notificaciones del teléfono en KDE y mantenerlas sincronizadas +Comment[fi]=Näytä puhelimen ilmoitukset KDE:ssa ja pidä ne ajan tasalla Comment[fr]=Affichez les notifications du téléphone dans KDE et conservez-les lors de la synchronisation Comment[hu]=Telefonértesítések megjelenítése a KDE-ben és szinkronizálva tartása Comment[it]=Mostra e sincronizza le notifiche del telefono in KDE diff --git a/plugins/pausemusic/kdeconnect_pausemusic.desktop b/plugins/pausemusic/kdeconnect_pausemusic.desktop index b6ddcdde8..2aeeca21f 100644 --- a/plugins/pausemusic/kdeconnect_pausemusic.desktop +++ b/plugins/pausemusic/kdeconnect_pausemusic.desktop @@ -19,6 +19,7 @@ Name[cs]=Pozastavit média během hovoru Name[da]=Sæt medier på pause under opkald Name[de]=Medium bei Anrufen anhalten Name[es]=Pausar multimedia durante las llamadas +Name[fi]=Keskeytä toisto puhelujen aikana Name[fr]=Mettre en pause le média pendant les appels Name[hu]=Média szüneteltetése hívások közben Name[it]=Pausa durante le chiamate @@ -41,6 +42,7 @@ Comment[cs]=Pozastavit hudbu/videa během hovoru Comment[da]=Sæt musik/video på pause under telefonopkald Comment[de]=Hält Musik oder Videos währen eines Anrufs an Comment[es]=Pausar la música y los vídeos durante una llamada telefónica +Comment[fi]=Keskeytä musiikki ja videot puhelun aikana Comment[fr]=Mettre en pause la musique / les vidéos pendant un appel téléphonique Comment[hu]=Zenék vagy videók szüneteltetése telefonhívás közben Comment[it]=Mette in pausa la riproduzione audio/video durante una chiamata diff --git a/plugins/pausemusic/kdeconnect_pausemusic_config.desktop b/plugins/pausemusic/kdeconnect_pausemusic_config.desktop index 98b3c0b36..0d9a30914 100644 --- a/plugins/pausemusic/kdeconnect_pausemusic_config.desktop +++ b/plugins/pausemusic/kdeconnect_pausemusic_config.desktop @@ -12,6 +12,7 @@ Name[cs]=Nastavení modulu Pozastavení hudby Name[da]=Indstilling af plugin til at sætte musik på pause Name[de]=Modul-Einstellungen für das Anhalten der Musikwiedergabe Name[es]=Ajustes del complemento PauseMusic +Name[fi]=Keskeytä musiikki -liitännäisen asetukset Name[fr]=Paramètres du module de mise en pause Name[hu]=Zene szüneteltetése bővítmény beállításai Name[ko]=음악 일시 정지 플러그인 설정 diff --git a/plugins/pausemusic/pausemusic_config.cpp b/plugins/pausemusic/pausemusic_config.cpp index e77468fdc..03dacf9ab 100644 --- a/plugins/pausemusic/pausemusic_config.cpp +++ b/plugins/pausemusic/pausemusic_config.cpp @@ -51,6 +51,7 @@ void PauseMusicConfig::defaults() KCModule::defaults(); m_ui->rad_talking->setChecked(false); m_ui->rad_ringing->setChecked(true); + m_ui->check_pause->setChecked(true); m_ui->check_mute->setChecked(false); Q_EMIT changed(true); } @@ -59,19 +60,23 @@ void PauseMusicConfig::defaults() void PauseMusicConfig::load() { KCModule::load(); - bool talking = m_cfg->group("pause_condition").readEntry("talking_only", false); + bool talking = m_cfg->group("condition").readEntry("talking_only", false); m_ui->rad_talking->setChecked(talking); m_ui->rad_ringing->setChecked(!talking); - bool use_mute = m_cfg->group("use_mute").readEntry("use_mute", false); - m_ui->check_mute->setChecked(use_mute); + + bool pause = m_cfg->group("actions").readEntry("pause", true); + bool mute = m_cfg->group("actions").readEntry("mute", false); + m_ui->check_pause->setChecked(pause); + m_ui->check_mute->setChecked(mute); Q_EMIT changed(false); } void PauseMusicConfig::save() { - m_cfg->group("pause_condition").writeEntry("talking_only", m_ui->rad_talking->isChecked()); - m_cfg->group("use_mute").writeEntry("use_mute", m_ui->check_mute->isChecked()); + m_cfg->group("condition").writeEntry("talking_only", m_ui->rad_talking->isChecked()); + m_cfg->group("actions").writeEntry("pause", m_ui->check_pause->isChecked()); + m_cfg->group("actions").writeEntry("mute", m_ui->check_mute->isChecked()); KCModule::save(); Q_EMIT changed(false); diff --git a/plugins/pausemusic/pausemusic_config.ui b/plugins/pausemusic/pausemusic_config.ui index 8b0507301..04d870bb4 100644 --- a/plugins/pausemusic/pausemusic_config.ui +++ b/plugins/pausemusic/pausemusic_config.ui @@ -9,14 +9,17 @@ 0 0 - 406 - 155 + 368 + 241 Pause music plugin - + + + 20 + @@ -26,7 +29,7 @@ - Pause condition + Condition @@ -47,23 +50,32 @@ - - - Qt::Vertical + + + + 0 + 0 + - - - 20 - 40 - - - - - - - - Mute system instead of pause + + Actions + + + + + Pause media players + + + + + + + Mute system sound + + + + diff --git a/plugins/pausemusic/pausemusicplugin.cpp b/plugins/pausemusic/pausemusicplugin.cpp index de093545f..a9cdc6811 100644 --- a/plugins/pausemusic/pausemusicplugin.cpp +++ b/plugins/pausemusic/pausemusicplugin.cpp @@ -58,6 +58,7 @@ int PauseMusicPlugin::isKMixMuted() { PauseMusicPlugin::PauseMusicPlugin(QObject* parent, const QVariantList& args) : KdeConnectPlugin(parent, args) + , muted(false) { QDBusInterface kmixInterface("org.kde.kmix", "/kmix/KMixWindow/actions/mute", "org.qtproject.Qt.QAction"); } @@ -66,7 +67,7 @@ bool PauseMusicPlugin::receivePackage(const NetworkPackage& np) { //FIXME: There should be a better way to listen to changes in the config file instead of reading the value each time KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnect/plugins/pausemusic"); - bool pauseOnlyWhenTalking = config->group("pause_condition").readEntry("talking_only", false); + bool pauseOnlyWhenTalking = config->group("condition").readEntry("talking_only", false); if (pauseOnlyWhenTalking) { if (np.get("event") != "talking") { @@ -79,16 +80,21 @@ bool PauseMusicPlugin::receivePackage(const NetworkPackage& np) } bool pauseConditionFulfilled = !np.get("isCancel"); - bool use_mute = config->group("use_mute").readEntry("use_mute", false); + + bool pause = config->group("actions").readEntry("pause", true); + bool mute = config->group("actions").readEntry("mute", false); if (pauseConditionFulfilled) { - if (use_mute) { + + if (mute) { QDBusInterface kmixInterface("org.kde.kmix", "/kmix/KMixWindow/actions/mute", "org.qtproject.Qt.QAction"); if (isKMixMuted() == 0) { - pausedSources.insert("mute"); //Fake source + muted = true; kmixInterface.call("trigger"); } - } else { + } + + if (pause) { //Search for interfaces currently playing QStringList interfaces = QDBusConnection::sessionBus().interface()->registeredServiceNames().value(); Q_FOREACH (const QString& iface, interfaces) { @@ -108,14 +114,18 @@ bool PauseMusicPlugin::receivePackage(const NetworkPackage& np) } } } + } else { - if (pausedSources.empty()) return false; - if (use_mute) { + + if (mute && muted) { QDBusInterface kmixInterface("org.kde.kmix", "/kmix/KMixWindow/actions/mute", "org.qtproject.Qt.QAction"); if (isKMixMuted() > 0) { kmixInterface.call("trigger"); } - } else { + muted = false; + } + + if (pause && !pausedSources.empty()) { Q_FOREACH (const QString& iface, pausedSources) { QDBusInterface mprisInterface(iface, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player"); //Calling play does not work for Spotify @@ -125,8 +135,8 @@ bool PauseMusicPlugin::receivePackage(const NetworkPackage& np) mprisInterface.asyncCall("PlayPause"); //End of workaround } + pausedSources.clear(); } - pausedSources.clear(); } diff --git a/plugins/pausemusic/pausemusicplugin.h b/plugins/pausemusic/pausemusicplugin.h index 8bfa09c54..aba9eb5ce 100644 --- a/plugins/pausemusic/pausemusicplugin.h +++ b/plugins/pausemusic/pausemusicplugin.h @@ -46,6 +46,7 @@ public Q_SLOTS: private: QSet pausedSources; + bool muted; }; diff --git a/plugins/ping/README b/plugins/ping/README index b793c1e73..7f93c6c6a 100644 --- a/plugins/ping/README +++ b/plugins/ping/README @@ -1,3 +1,4 @@ This plugin displays a notification to the user each time a package with type -"kdeconnect.ping" is received, regardless of the content. +"kdeconnect.ping" is received. If the package has something in the "message" +field, that will be displayed in the notification body. diff --git a/plugins/ping/kdeconnect_ping.desktop b/plugins/ping/kdeconnect_ping.desktop index aa6c7a545..7757bf67b 100644 --- a/plugins/ping/kdeconnect_ping.desktop +++ b/plugins/ping/kdeconnect_ping.desktop @@ -19,6 +19,7 @@ Name[cs]=Ping Name[da]=Ping Name[de]=Ping Name[es]=Ping +Name[fi]=Ping Name[fr]=Commande « Ping » Name[hu]=Ping Name[it]=Ping @@ -42,6 +43,7 @@ Comment[cs]=Posílat a přijímat ping Comment[da]=Send og modtag ping Comment[de]=Senden und Empfangen von Pings Comment[es]=Enviar y recibir pings +Comment[fi]=Lähetä ja vastaanota pingejä Comment[fr]=Envoyez et recevez des « ping » Comment[hu]=Pingek küldése és fogadása Comment[it]=Invia e ricevi ping diff --git a/plugins/ping/pingplugin.cpp b/plugins/ping/pingplugin.cpp index 54214796e..d1de1358b 100644 --- a/plugins/ping/pingplugin.cpp +++ b/plugins/ping/pingplugin.cpp @@ -54,7 +54,6 @@ bool PingPlugin::receivePackage(const NetworkPackage& np) notification->sendEvent(); return true; - } void PingPlugin::sendPing() @@ -64,6 +63,16 @@ void PingPlugin::sendPing() qCDebug(KDECONNECT_PLUGIN_PING) << "sendPing:" << success; } +void PingPlugin::sendPing(const QString& customMessage) +{ + NetworkPackage np(PACKAGE_TYPE_PING); + if (!customMessage.isEmpty()) { + np.set("message", customMessage); + } + bool success = sendPackage(np); + qCDebug(KDECONNECT_PLUGIN_PING) << "sendPing:" << success; +} + void PingPlugin::connected() { QDBusConnection::sessionBus().registerObject(dbusPath(), this, QDBusConnection::ExportAllContents); diff --git a/plugins/ping/pingplugin.h b/plugins/ping/pingplugin.h index 54b17d66c..146db57b0 100644 --- a/plugins/ping/pingplugin.h +++ b/plugins/ping/pingplugin.h @@ -39,6 +39,7 @@ public: virtual ~PingPlugin(); Q_SCRIPTABLE void sendPing(); + Q_SCRIPTABLE void sendPing(const QString& customMessage); public Q_SLOTS: virtual bool receivePackage(const NetworkPackage& np); diff --git a/plugins/sftp/kdeconnect_sftp.desktop b/plugins/sftp/kdeconnect_sftp.desktop index ff7e0472d..72c44b0f5 100644 --- a/plugins/sftp/kdeconnect_sftp.desktop +++ b/plugins/sftp/kdeconnect_sftp.desktop @@ -13,11 +13,12 @@ X-KDE-PluginInfo-EnabledByDefault=true Icon=system-file-manager Name=Remote filesystem browser Name[bg]=Достъп до отдалечена файлова система -Name[ca]=Navegador per al sistema de fitxers remot +Name[ca]=Navegador pel sistema de fitxers remot Name[cs]=Prohlížeč vzdáleného souborového systému Name[da]=Gennemse eksternt filsystem Name[de]=Datei-Browser für entferne Systeme Name[es]=Navegador de sistemas de archivos remoto +Name[fi]=Etätiedostojärjestelmäselain Name[fr]=Contrôlez à distance le navigateur du système de fichiers Name[hu]=Távoli fájlrendszer böngésző Name[ko]=원격 파일 시스템 탐색기 @@ -37,6 +38,7 @@ Comment[cs]=Prohlížení souborového systému na zařízení pomocí SFTP Comment[da]=Gennemse filsystemet på den eksterne enhed med SFTP Comment[de]=Browsen im Dateisystem des entfernten Geräts mit SFTP Comment[es]=Navegar en el sistema de archivos del dispositivo remoto usando SFTP +Comment[fi]=Selaa etälaitteiden tiedostojärjestelmiä SFTP:llä Comment[fr]=Visualiser le système de fichiers de l'appareil distant en utilisant SFTP Comment[hu]=A távoli eszköz fájlrendszerének böngészése SFTP használatával Comment[ko]=SFTP로 원격 파일 시스템 탐색 diff --git a/plugins/sftp/kdeconnect_sftp_config.desktop b/plugins/sftp/kdeconnect_sftp_config.desktop index 4c0fb301f..17477c551 100644 --- a/plugins/sftp/kdeconnect_sftp_config.desktop +++ b/plugins/sftp/kdeconnect_sftp_config.desktop @@ -12,6 +12,7 @@ Name[cs]=Nastavení modulu pro prohlížení souborů přes SFTP Name[da]=Indstilling af filhåndteringens SFTP-plugin Name[de]=Modul-Einstellungen für SFTP-Dateibrowser Name[es]=Ajustes del complemento navegador de archivos SFTP +Name[fi]=SFTP-tiedostoselainliitännäisen asetukset Name[fr]=Paramètres du module du navigateur de fichiers SFTP Name[hu]=SFTP fájlböngésző bővítmény beállításai Name[ko]=SFTP 파일 탐색기 플러그인 설정 diff --git a/plugins/sftp/mounter.cpp b/plugins/sftp/mounter.cpp index f60cefa37..9ced0ed7c 100644 --- a/plugins/sftp/mounter.cpp +++ b/plugins/sftp/mounter.cpp @@ -93,7 +93,6 @@ void Mounter::onPakcageReceived(const NetworkPackage& np) //TODO implement on android side //if (np.get("id") != m_id) return; - //This is the previous code, to access sftp server using KIO. Now we are //using the external binary sshfs, and accessing it as a local filesystem. @@ -120,11 +119,16 @@ void Mounter::onPakcageReceived(const NetworkPackage& np) QDir().mkpath(mpoint); const QString program = "sshfs"; + + QString path; + if (np.has("multiPaths")) path = "/"; + else path = np.get("path"); + const QStringList arguments = QStringList() << QString("%1@%2:%3") .arg(np.get("user")) .arg(np.get("ip")) - .arg(np.get("path")) + .arg(path) << mpoint << "-p" << np.get("port") << "-d" diff --git a/plugins/sftp/sftp_config.cpp b/plugins/sftp/sftp_config.cpp index ca168728e..31a068990 100644 --- a/plugins/sftp/sftp_config.cpp +++ b/plugins/sftp/sftp_config.cpp @@ -69,7 +69,6 @@ void SftpConfig::defaults() Q_EMIT changed(true); } - void SftpConfig::load() { KCModule::load(); diff --git a/plugins/sftp/sftpplugin.cpp b/plugins/sftp/sftpplugin.cpp index 20273c179..9564ad208 100644 --- a/plugins/sftp/sftpplugin.cpp +++ b/plugins/sftp/sftpplugin.cpp @@ -55,7 +55,7 @@ struct SftpPlugin::Pimpl SftpPlugin::SftpPlugin(QObject *parent, const QVariantList &args) : KdeConnectPlugin(parent, args) - , m_d(new Pimpl) + , m_d(new Pimpl()) { addToDolphin(); qCDebug(KDECONNECT_PLUGIN_SFTP) << "Created device:" << device()->name(); @@ -66,7 +66,6 @@ SftpPlugin::~SftpPlugin() QDBusConnection::sessionBus().unregisterObject(dbusPath(), QDBusConnection::UnregisterTree); removeFromDolphin(); unmount(); - qCDebug(KDECONNECT_PLUGIN_SFTP) << "Destroyed device:" << device()->name(); } void SftpPlugin::addToDolphin() @@ -143,14 +142,26 @@ bool SftpPlugin::startBrowsing() bool SftpPlugin::receivePackage(const NetworkPackage& np) { - if (!(fields_c - np.body().keys().toSet()).isEmpty()) - { + if (!(fields_c - np.body().keys().toSet()).isEmpty()) { // package is invalid return false; } Q_EMIT packageReceived(np); + remoteDirectories.clear(); + if (np.has("multiPaths")) { + QStringList paths = np.get("multiPaths",QStringList()); + QStringList names = np.get("pathNames",QStringList()); + int size = qMin(names.size(), paths.size()); + for (int i = 0; i < size; i++) { + remoteDirectories.insert(mountPoint() + paths.at(i), names.at(i)); + } + } else { + remoteDirectories.insert(mountPoint(), i18n("All files")); + remoteDirectories.insert(mountPoint() + "/DCIM/Camera", i18n("Camera pictures")); + } + return true; } @@ -199,4 +210,9 @@ void SftpPlugin::knotify(int type, const QString& text, const QPixmap& icon) con , KNotification::CloseOnTimeout); } +QVariantMap SftpPlugin::getDirectories() +{ + return remoteDirectories; +} + #include "sftpplugin.moc" diff --git a/plugins/sftp/sftpplugin.h b/plugins/sftp/sftpplugin.h index 9517d8e71..8c77d621c 100644 --- a/plugins/sftp/sftpplugin.h +++ b/plugins/sftp/sftpplugin.h @@ -35,12 +35,10 @@ class SftpPlugin Q_CLASSINFO("D-Bus Interface", "org.kde.kdeconnect.device.sftp") public: - explicit SftpPlugin(QObject *parent, const QVariantList &args); virtual ~SftpPlugin(); Q_SIGNALS: - void packageReceived(const NetworkPackage& np); Q_SCRIPTABLE void mounted(); Q_SCRIPTABLE void unmounted(); @@ -53,11 +51,10 @@ public Q_SLOTS: Q_SCRIPTABLE void unmount(); Q_SCRIPTABLE bool mountAndWait(); Q_SCRIPTABLE bool isMounted() const; - + Q_SCRIPTABLE bool startBrowsing(); Q_SCRIPTABLE QString mountPoint(); - - + Q_SCRIPTABLE QVariantMap getDirectories(); //Actually a QMap, but QDBus preffers this private Q_SLOTS: void onMounted(); @@ -73,6 +70,8 @@ private: private: struct Pimpl; QScopedPointer m_d; + + QVariantMap remoteDirectories; //Actually a QMap, but QDBus preffers this }; diff --git a/plugins/share/kdeconnect_share.desktop b/plugins/share/kdeconnect_share.desktop index 8cb65d6e2..79271c88b 100644 --- a/plugins/share/kdeconnect_share.desktop +++ b/plugins/share/kdeconnect_share.desktop @@ -18,6 +18,7 @@ Name[cs]=Sdílet a přijímat Name[da]=Del og modtag Name[de]=Veröffentlichen und Empfangen Name[es]=Compartir y recibir +Name[fi]=Jaa ja vastaanota Name[fr]=Partager et recevoir Name[hu]=Megosztás és fogadás Name[ko]=공유하고 받기 @@ -38,6 +39,7 @@ Comment[cs]=Jednoduše přijímejte a posílejte soubory, URL nebo čistý text Comment[da]=Modtag og send filer, URL'er eller klartekst på nem måde Comment[de]=Empfang und Senden von Dateien, URLs oder einfacher Text Comment[es]=Recibir y enviar archivos, URLs o texto plano fácilmente +Comment[fi]=Vastaanota ja lähetä tiedostoja, verkko-osoitteita tai tekstiä helposti Comment[fr]=Recevoir et envoyer des fichiers, des URLs ou du texte brut facilement Comment[hu]=Fájlok, URL-ek vagy egyszerű szövegek könnyű fogadása és küldése Comment[ko]=파일, URL, 일반 텍스트를 주고받기 diff --git a/plugins/share/kdeconnect_share_config.desktop b/plugins/share/kdeconnect_share_config.desktop index 377c651ff..5e5cefaed 100644 --- a/plugins/share/kdeconnect_share_config.desktop +++ b/plugins/share/kdeconnect_share_config.desktop @@ -12,6 +12,7 @@ Name[cs]=Nastavení modulu sdílení Name[da]=Indstilling af deling-plugin Name[de]=Modul-Einstellungen für Veröffentlichung Name[es]=Ajustes del complemento para compartir +Name[fi]=Jakoliitännäisen asetukset Name[fr]=Paramètres du module de partage Name[hu]=Megosztás bővítmény beállításai Name[ko]=공유 플러그인 설정 diff --git a/plugins/share/shareplugin.cpp b/plugins/share/shareplugin.cpp index c6a55ed14..906bf1ba7 100644 --- a/plugins/share/shareplugin.cpp +++ b/plugins/share/shareplugin.cpp @@ -73,7 +73,7 @@ QUrl SharePlugin::destinationDir() const bool SharePlugin::receivePackage(const NetworkPackage& np) { /* - //TODO: Use this code to write a test + //TODO: Write a test like this if (np.type() == PACKAGE_TYPE_PING) { qCDebug(KDECONNECT_PLUGIN_SHARE) << "sending file" << (QDesktopServices::storageLocation(QDesktopServices::HomeLocation) + "/.bashrc"); diff --git a/plugins/telephony/kdeconnect_telephony.desktop b/plugins/telephony/kdeconnect_telephony.desktop index 5df0cd398..2a7224849 100644 --- a/plugins/telephony/kdeconnect_telephony.desktop +++ b/plugins/telephony/kdeconnect_telephony.desktop @@ -19,6 +19,7 @@ Name[cs]=Integrace telefonie Name[da]=Telefoni-integration Name[de]=Telefon-Integration Name[es]=Integración de telefonía +Name[fi]=Puhelinintegrointi Name[fr]=Intégration de la téléphonie Name[hu]=Telefon integráció Name[it]=Integrazione telefono @@ -42,6 +43,7 @@ Comment[cs]=Zobrazit upozornění na volání a SMS (odpovídání bude brzy k d Comment[da]=Vis bekendtgørelser af opkald og SMS (at svare kommer snart) Comment[de]=Zeigt Benachrichtigungen für Anrufe und SMS Comment[es]=Mostrar notificaciones de llamadas y SMS (en breve se podrá responder) +Comment[fi]=Näytä puhelujen ja tekstiviestien ilmoitukset (vastaaminen tulossa pian) Comment[fr]=Affichez les notifications pour les appels et les SMS (la réponse arrive bientôt) Comment[hu]=Értesítések megjelenítése hívásokhoz és SMS-ekhez (a fogadásuk hamarosan) Comment[it]=Mostra le notifiche di chiamate ed SMS (a breve anche per rispondere) diff --git a/plugins/telephony/telephonyplugin.cpp b/plugins/telephony/telephonyplugin.cpp index d12274044..0c51e633d 100644 --- a/plugins/telephony/telephonyplugin.cpp +++ b/plugins/telephony/telephonyplugin.cpp @@ -62,10 +62,13 @@ KNotification* TelephonyPlugin::createNotification(const NetworkPackage& np) } else if (event == "talking") { return NULL; } else { - //TODO: return NULL if !debug +#ifdef NDEBUG + return NULL; +#else type = "unknownEvent"; icon = "pda"; content = i18n("Unknown telephony event: %2", event); +#endif } qCDebug(KDECONNECT_PLUGIN_TELEPHONY) << "Creating notification with type:" << type; diff --git a/tests/testsocketlinereader.cpp b/tests/testsocketlinereader.cpp index 797f60a9f..185816d14 100644 --- a/tests/testsocketlinereader.cpp +++ b/tests/testsocketlinereader.cpp @@ -79,6 +79,9 @@ void TestSocketLineReader::socketLineReader() } QTcpSocket *sock = mServer->nextPendingConnection(); + + QVERIFY2(sock != 0, "Could not open a connection to the client"); + mReader = new SocketLineReader(sock, this); connect(mReader, SIGNAL(readyRead()), SLOT(newPackage())); mTimer.start();