2014-04-01 02:12:31 +01:00
/*
2015-02-05 07:52:07 +00:00
* Copyright 2015 Aleix Pol Gonzalez < aleixpol @ kde . org >
2014-04-01 02:12:31 +01:00
*
* 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 < http : //www.gnu.org/licenses/>.
*/
2015-07-19 15:55:28 +01:00
# include <QCryptographicHash>
2015-09-11 12:35:16 +01:00
# include <QIODevice>
2014-06-14 14:22:40 +01:00
# include <QDBusMessage>
# include <QDBusConnection>
2015-03-10 04:59:36 +00:00
# include <QCoreApplication>
# include <QTextStream>
2017-01-23 08:08:27 +00:00
# include <QFile>
2015-03-10 04:59:36 +00:00
2014-09-22 01:26:06 +01:00
# include <KAboutData>
2014-04-01 02:12:31 +01:00
2015-03-10 04:59:36 +00:00
# include "interfaces/devicesmodel.h"
# include "interfaces/notificationsmodel.h"
# include "interfaces/dbusinterfaces.h"
2017-06-06 16:48:30 +01:00
# include "interfaces/dbushelpers.h"
2015-03-10 04:59:36 +00:00
# include "kdeconnect-version.h"
2015-02-05 07:52:07 +00:00
2014-04-01 02:12:31 +01:00
int main ( int argc , char * * argv )
{
2014-11-28 16:42:53 +00:00
QCoreApplication app ( argc , argv ) ;
2016-11-26 14:38:08 +00:00
KAboutData about ( QStringLiteral ( " kdeconnect-cli " ) ,
QStringLiteral ( " kdeconnect-cli " ) ,
QStringLiteral ( KDECONNECT_VERSION_STRING ) ,
2015-02-05 07:52:07 +00:00
i18n ( " KDE Connect CLI tool " ) ,
KAboutLicense : : GPL ,
i18n ( " (C) 2015 Aleix Pol Gonzalez " ) ) ;
2014-09-22 01:26:06 +01:00
KAboutData : : setApplicationData ( about ) ;
2014-07-01 22:59:38 +01:00
2016-11-26 14:38:08 +00:00
about . addAuthor ( i18n ( " Aleix Pol Gonzalez " ) , QString ( ) , QStringLiteral ( " aleixpol@kde.org " ) ) ;
about . addAuthor ( i18n ( " Albert Vaca Cintora " ) , QString ( ) , QStringLiteral ( " albertvaka@gmail.com " ) ) ;
2014-09-22 01:26:06 +01:00
QCommandLineParser parser ;
2016-11-26 14:38:08 +00:00
parser . addOption ( QCommandLineOption ( QStringList ( QStringLiteral ( " l " ) ) < < QStringLiteral ( " list-devices " ) , i18n ( " List all devices " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringList ( QStringLiteral ( " a " ) ) < < QStringLiteral ( " list-available " ) , i18n ( " List available (paired and reachable) devices " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " id-only " ) , i18n ( " Make --list-devices or --list-available print only the devices id, to ease scripting " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " refresh " ) , i18n ( " Search for devices in the network and re-establish connections " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " pair " ) , i18n ( " Request pairing to a said device " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " ring " ) , i18n ( " Find the said device by ringing it. " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " unpair " ) , i18n ( " Stop pairing to a said device " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " ping " ) , i18n ( " Sends a ping to said device " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " ping-msg " ) , i18n ( " Same as ping but you can set the message to display " ) , i18n ( " message " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " share " ) , i18n ( " Share a file to a said device " ) , QStringLiteral ( " path " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " list-notifications " ) , i18n ( " Display the notifications on a said device " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " lock " ) , i18n ( " Lock the specified device " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " send-sms " ) , i18n ( " Sends an SMS. Requires destination " ) , i18n ( " message " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " destination " ) , i18n ( " Phone number to send the message " ) , i18n ( " phone number " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringList ( QStringLiteral ( " device " ) ) < < QStringLiteral ( " d " ) , i18n ( " Device ID " ) , QStringLiteral ( " dev " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringList ( QStringLiteral ( " name " ) ) < < QStringLiteral ( " n " ) , i18n ( " Device Name " ) , QStringLiteral ( " name " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " encryption-info " ) , i18n ( " Get encryption info about said device " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " list-commands " ) , i18n ( " Lists remote commands and their ids " ) ) ) ;
parser . addOption ( QCommandLineOption ( QStringLiteral ( " execute-command " ) , i18n ( " Executes a remote command by id " ) , QStringLiteral ( " id " ) ) ) ;
2017-01-23 08:08:27 +00:00
parser . addOption ( QCommandLineOption ( QStringList { QStringLiteral ( " k " ) , QStringLiteral ( " send-keys " ) } , i18n ( " Sends keys to a said device " ) ) ) ;
2017-02-24 21:37:00 +00:00
parser . addOption ( QCommandLineOption ( QStringLiteral ( " my-id " ) , i18n ( " Display this device's id and exit " ) ) ) ;
2014-09-22 01:26:06 +01:00
about . setupCommandLine ( & parser ) ;
parser . addHelpOption ( ) ;
parser . process ( app ) ;
about . processCommandLine ( & parser ) ;
2015-09-12 21:07:05 +01:00
const QString id = " kdeconnect-cli- " + QString : : number ( QCoreApplication : : applicationPid ( ) ) ;
DaemonDbusInterface iface ;
2017-02-24 21:37:00 +00:00
if ( parser . isSet ( QStringLiteral ( " my-id " ) ) ) {
QTextStream ( stdout ) < < iface . selfId ( ) < < endl ;
} else if ( parser . isSet ( QStringLiteral ( " l " ) ) | | parser . isSet ( QStringLiteral ( " a " ) ) ) {
2015-03-16 01:58:22 +00:00
bool paired = true , reachable = false ;
2016-11-26 14:38:08 +00:00
if ( parser . isSet ( QStringLiteral ( " a " ) ) ) {
2015-03-16 01:58:22 +00:00
reachable = true ;
2015-09-09 22:22:59 +01:00
} else {
2017-01-19 19:01:11 +00:00
blockOnReply ( iface . acquireDiscoveryMode ( id ) ) ;
2015-09-09 22:22:59 +01:00
QThread : : sleep ( 2 ) ;
2015-02-25 06:13:30 +00:00
}
2017-01-19 19:01:11 +00:00
const QStringList devices = blockOnReply < QStringList > ( iface . devices ( paired , reachable ) ) ;
2015-03-16 01:58:22 +00:00
2017-07-20 15:14:07 +01:00
for ( const QString & id : devices ) {
2016-11-26 14:38:08 +00:00
if ( parser . isSet ( QStringLiteral ( " id-only " ) ) ) {
2015-03-16 01:58:22 +00:00
QTextStream ( stdout ) < < id < < endl ;
2015-02-25 06:13:30 +00:00
} else {
2015-03-16 01:58:22 +00:00
DeviceDbusInterface deviceIface ( id ) ;
2015-02-25 06:13:30 +00:00
QString statusInfo ;
2016-11-23 16:20:59 +00:00
const bool isReachable = deviceIface . isReachable ( ) ;
const bool isTrusted = deviceIface . isTrusted ( ) ;
if ( isReachable & & isTrusted ) {
2015-03-16 01:58:22 +00:00
statusInfo = i18n ( " (paired and reachable) " ) ;
} else if ( isReachable ) {
statusInfo = i18n ( " (reachable) " ) ;
2016-11-23 16:20:59 +00:00
} else if ( isTrusted ) {
2015-03-16 01:58:22 +00:00
statusInfo = i18n ( " (paired) " ) ;
2016-11-23 16:20:59 +00:00
}
2015-03-16 01:58:22 +00:00
QTextStream ( stdout ) < < " - " < < deviceIface . name ( )
< < " : " < < deviceIface . id ( ) < < ' ' < < statusInfo < < endl ;
2014-06-27 15:18:43 +01:00
}
2014-04-01 02:12:31 +01:00
}
2016-11-26 14:38:08 +00:00
if ( ! parser . isSet ( QStringLiteral ( " id-only " ) ) ) {
2015-03-16 01:58:22 +00:00
QTextStream ( stdout ) < < i18np ( " 1 device found " , " %1 devices found " , devices . size ( ) ) < < endl ;
} else if ( devices . isEmpty ( ) ) {
2015-02-25 06:13:30 +00:00
QTextStream ( stderr ) < < i18n ( " No devices found " ) < < endl ;
}
2015-09-09 22:22:59 +01:00
2017-01-19 19:01:11 +00:00
blockOnReply ( iface . releaseDiscoveryMode ( id ) ) ;
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " refresh " ) ) ) {
QDBusMessage msg = QDBusMessage : : createMethodCall ( QStringLiteral ( " org.kde.kdeconnect " ) , QStringLiteral ( " /modules/kdeconnect " ) , QStringLiteral ( " org.kde.kdeconnect.daemon " ) , QStringLiteral ( " forceOnNetworkChange " ) ) ;
2017-01-19 19:01:11 +00:00
blockOnReply ( QDBusConnection : : sessionBus ( ) . asyncCall ( msg ) ) ;
2014-04-01 02:12:31 +01:00
} else {
2016-10-24 11:42:20 +01:00
2016-11-26 14:38:08 +00:00
QString device = parser . value ( QStringLiteral ( " device " ) ) ;
if ( device . isEmpty ( ) & & parser . isSet ( QStringLiteral ( " name " ) ) ) {
2017-01-19 19:01:11 +00:00
device = blockOnReply ( iface . deviceIdByName ( parser . value ( QStringLiteral ( " name " ) ) ) ) ;
2016-06-05 22:31:13 +01:00
if ( device . isEmpty ( ) ) {
2016-11-26 14:38:08 +00:00
QTextStream ( stderr ) < < " Couldn't find device: " < < parser . value ( QStringLiteral ( " name " ) ) < < endl ;
2016-06-05 22:31:13 +01:00
return 1 ;
}
}
if ( device . isEmpty ( ) ) {
2015-02-25 06:13:30 +00:00
QTextStream ( stderr ) < < i18n ( " No device specified " ) < < endl ;
2016-11-30 14:40:30 +00:00
parser . showHelp ( 1 ) ;
2014-04-01 02:12:31 +01:00
}
2016-10-24 11:42:20 +01:00
2016-11-26 14:38:08 +00:00
if ( parser . isSet ( QStringLiteral ( " share " ) ) ) {
QUrl url = QUrl : : fromUserInput ( parser . value ( QStringLiteral ( " share " ) ) , QDir : : currentPath ( ) ) ;
2014-09-22 01:26:06 +01:00
parser . clearPositionalArguments ( ) ;
2014-06-23 17:15:10 +01:00
if ( ! url . isEmpty ( ) & & ! device . isEmpty ( ) ) {
2016-11-26 14:38:08 +00:00
QDBusMessage msg = QDBusMessage : : createMethodCall ( QStringLiteral ( " org.kde.kdeconnect " ) , " /modules/kdeconnect/devices/ " + device + " /share " , QStringLiteral ( " org.kde.kdeconnect.device.share " ) , QStringLiteral ( " shareUrl " ) ) ;
2014-06-23 17:15:10 +01:00
msg . setArguments ( QVariantList ( ) < < url . toString ( ) ) ;
2017-01-19 19:01:11 +00:00
blockOnReply ( QDBusConnection : : sessionBus ( ) . asyncCall ( msg ) ) ;
2015-02-25 06:13:30 +00:00
} else {
QTextStream ( stderr ) < < ( i18n ( " Couldn't share %1 " , url . toString ( ) ) ) < < endl ;
}
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " pair " ) ) ) {
2014-06-23 17:15:10 +01:00
DeviceDbusInterface dev ( device ) ;
2015-09-12 21:07:05 +01:00
if ( ! dev . isReachable ( ) ) {
//Device doesn't exist, go into discovery mode and wait up to 30 seconds for the device to appear
QEventLoop wait ;
QTextStream ( stderr ) < < i18n ( " waiting for device... " ) < < endl ;
2017-01-19 19:01:11 +00:00
blockOnReply ( iface . acquireDiscoveryMode ( id ) ) ;
2015-09-12 21:07:05 +01:00
QObject : : connect ( & iface , & DaemonDbusInterface : : deviceAdded , [ & ] ( const QString & deviceAddedId ) {
if ( device = = deviceAddedId ) {
wait . quit ( ) ;
}
} ) ;
QTimer : : singleShot ( 30 * 1000 , & wait , & QEventLoop : : quit ) ;
wait . exec ( ) ;
}
if ( ! dev . isReachable ( ) ) {
QTextStream ( stderr ) < < i18n ( " Device not found " ) < < endl ;
2017-01-19 19:01:11 +00:00
} else if ( blockOnReply < bool > ( dev . isTrusted ( ) ) ) {
2015-02-25 06:13:30 +00:00
QTextStream ( stderr ) < < i18n ( " Already paired " ) < < endl ;
2015-09-12 21:07:05 +01:00
} else {
QTextStream ( stderr ) < < i18n ( " Pair requested " ) < < endl ;
2017-01-19 19:01:11 +00:00
blockOnReply ( dev . requestPair ( ) ) ;
2014-06-23 17:15:10 +01:00
}
2017-01-19 19:01:11 +00:00
blockOnReply ( iface . releaseDiscoveryMode ( id ) ) ;
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " unpair " ) ) ) {
2014-06-23 17:15:10 +01:00
DeviceDbusInterface dev ( device ) ;
2015-09-12 21:07:05 +01:00
if ( ! dev . isReachable ( ) ) {
QTextStream ( stderr ) < < i18n ( " Device does not exist " ) < < endl ;
2017-01-19 19:01:11 +00:00
} else if ( ! dev . isTrusted ( ) ) {
2015-02-25 06:13:30 +00:00
QTextStream ( stderr ) < < i18n ( " Already not paired " ) < < endl ;
2015-09-12 21:07:05 +01:00
} else {
QTextStream ( stderr ) < < i18n ( " Unpaired " ) < < endl ;
2017-01-19 19:01:11 +00:00
blockOnReply ( dev . unpair ( ) ) ;
2014-06-23 17:15:10 +01:00
}
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " ping " ) ) | | parser . isSet ( QStringLiteral ( " ping-msg " ) ) ) {
QDBusMessage msg = QDBusMessage : : createMethodCall ( QStringLiteral ( " org.kde.kdeconnect " ) , " /modules/kdeconnect/devices/ " + device + " /ping " , QStringLiteral ( " org.kde.kdeconnect.device.ping " ) , QStringLiteral ( " sendPing " ) ) ;
if ( parser . isSet ( QStringLiteral ( " ping-msg " ) ) ) {
QString message = parser . value ( QStringLiteral ( " ping-msg " ) ) ;
2014-09-27 04:39:38 +01:00
msg . setArguments ( QVariantList ( ) < < message ) ;
}
2017-01-19 19:01:11 +00:00
blockOnReply ( QDBusConnection : : sessionBus ( ) . asyncCall ( msg ) ) ;
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " send-sms " ) ) ) {
if ( parser . isSet ( QStringLiteral ( " destination " ) ) ) {
QDBusMessage msg = QDBusMessage : : createMethodCall ( QStringLiteral ( " org.kde.kdeconnect " ) , " /modules/kdeconnect/devices/ " + device + " /telephony " , QStringLiteral ( " org.kde.kdeconnect.device.telephony " ) , QStringLiteral ( " sendSms " ) ) ;
2016-11-03 18:15:23 +00:00
msg . setArguments ( { parser . value ( " destination " ) , parser . value ( " send-sms " ) } ) ;
2017-01-19 19:01:11 +00:00
blockOnReply ( QDBusConnection : : sessionBus ( ) . asyncCall ( msg ) ) ;
2016-11-03 18:15:23 +00:00
} else {
QTextStream ( stderr ) < < i18n ( " error: should specify the SMS's recipient by passing --destination <phone number> " ) ;
return 1 ;
}
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " ring " ) ) ) {
QDBusMessage msg = QDBusMessage : : createMethodCall ( QStringLiteral ( " org.kde.kdeconnect " ) , " /modules/kdeconnect/devices/ " + device + " /findmyphone " , QStringLiteral ( " org.kde.kdeconnect.device.findmyphone " ) , QStringLiteral ( " ring " ) ) ;
2017-01-19 19:01:11 +00:00
blockOnReply ( QDBusConnection : : sessionBus ( ) . asyncCall ( msg ) ) ;
2017-01-23 08:08:27 +00:00
} else if ( parser . isSet ( " send-keys " ) ) {
QString seq = parser . value ( " send-keys " ) ;
QDBusMessage msg = QDBusMessage : : createMethodCall ( " org.kde.kdeconnect " , " /modules/kdeconnect/devices/ " + device + " /remotekeyboard " , " org.kde.kdeconnect.device.remotekeyboard " , " sendKeyPress " ) ;
if ( seq . trimmed ( ) = = QLatin1String ( " - " ) ) {
// from file
QFile in ;
if ( in . open ( stdin , QIODevice : : ReadOnly | QIODevice : : Unbuffered ) ) {
while ( ! in . atEnd ( ) ) {
QByteArray line = in . readLine ( ) ; // sanitize to ASCII-codes > 31?
msg . setArguments ( { QString ( line ) , - 1 , false , false , false } ) ;
2017-01-19 19:01:11 +00:00
blockOnReply ( QDBusConnection : : sessionBus ( ) . asyncCall ( msg ) ) ;
2017-01-23 08:08:27 +00:00
}
in . close ( ) ;
}
} else {
msg . setArguments ( { seq , - 1 , false , false , false } ) ;
2017-01-19 19:01:11 +00:00
blockOnReply ( QDBusConnection : : sessionBus ( ) . asyncCall ( msg ) ) ;
2017-01-23 08:08:27 +00:00
}
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " list-notifications " ) ) ) {
2014-07-01 00:15:23 +01:00
NotificationsModel notifications ;
notifications . setDeviceId ( device ) ;
for ( int i = 0 , rows = notifications . rowCount ( ) ; i < rows ; + + i ) {
QModelIndex idx = notifications . index ( i ) ;
2014-11-10 01:14:53 +00:00
QTextStream ( stdout ) < < " - " < < idx . data ( NotificationsModel : : AppNameModelRole ) . toString ( )
2015-02-25 06:13:30 +00:00
< < " : " < < idx . data ( NotificationsModel : : NameModelRole ) . toString ( ) < < endl ;
2014-07-01 00:15:23 +01:00
}
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " list-commands " ) ) ) {
2016-06-12 19:15:40 +01:00
RemoteCommandsDbusInterface iface ( device ) ;
const auto cmds = QJsonDocument : : fromJson ( iface . commands ( ) ) . object ( ) ;
for ( auto it = cmds . constBegin ( ) , itEnd = cmds . constEnd ( ) ; it ! = itEnd ; + + it ) {
const QJsonObject cont = it - > toObject ( ) ;
2016-11-26 14:38:08 +00:00
QTextStream ( stdout ) < < it . key ( ) < < " : " < < cont . value ( QStringLiteral ( " name " ) ) . toString ( ) < < " : " < < cont . value ( QStringLiteral ( " command " ) ) . toString ( ) < < endl ;
2016-06-12 19:15:40 +01:00
}
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " execute-command " ) ) ) {
2016-06-12 19:15:40 +01:00
RemoteCommandsDbusInterface iface ( device ) ;
2017-01-19 19:01:11 +00:00
blockOnReply ( iface . triggerCommand ( parser . value ( QStringLiteral ( " execute-command " ) ) ) ) ;
2016-11-26 14:38:08 +00:00
} else if ( parser . isSet ( QStringLiteral ( " encryption-info " ) ) ) {
2015-09-11 16:25:23 +01:00
DeviceDbusInterface dev ( device ) ;
2017-01-19 19:01:11 +00:00
QString info = blockOnReply < QString > ( dev . encryptionInfo ( ) ) ; // QSsl::Der = 1
QTextStream ( stdout ) < < info < < endl ;
2014-07-01 00:15:23 +01:00
} else {
2015-02-25 06:13:30 +00:00
QTextStream ( stderr ) < < i18n ( " Nothing to be done " ) < < endl ;
2014-07-01 00:15:23 +01:00
}
2014-04-01 02:12:31 +01:00
}
QMetaObject : : invokeMethod ( & app , " quit " , Qt : : QueuedConnection ) ;
return app . exec ( ) ;
}