1 /*
2 This file is part of Akonadi Contact.
3
4 SPDX-FileCopyrightText: 2009 Tobias Koenig <tokoe@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8
9 #include "qskypedialer.h"
10
11 #include <KLocalizedString>
12 #include <QDBusConnection>
13 #include <QDBusConnectionInterface>
14 #include <QDBusInterface>
15 #include <QDBusReply>
16 #include <QProcess>
17 #include <QStandardPaths>
18
19 #if !defined(Q_OS_WIN)
20 #include <unistd.h>
21 #else
22 #include <windows.h>
23 #endif
24
isSkypeServiceRegistered()25 static bool isSkypeServiceRegistered()
26 {
27 const QString service(QStringLiteral("com.Skype.API"));
28
29 QDBusConnectionInterface *interface = QDBusConnection::sessionBus().interface();
30 if (interface->isServiceRegistered(service)) {
31 return true;
32 }
33
34 interface = QDBusConnection::sessionBus().interface();
35 if (interface->isServiceRegistered(service)) {
36 return true;
37 }
38
39 return false;
40 }
41
searchSkypeDBusInterface()42 static QDBusInterface *searchSkypeDBusInterface()
43 {
44 const QString service(QStringLiteral("com.Skype.API"));
45 const QString path(QStringLiteral("/com/Skype"));
46
47 auto interface = new QDBusInterface(service, path, QString(), QDBusConnection::sessionBus());
48 if (!interface->isValid()) {
49 delete interface;
50 interface = new QDBusInterface(service, path, QString(), QDBusConnection::sessionBus());
51 }
52
53 return interface;
54 }
55
QSkypeDialer(const QString & applicationName)56 QSkypeDialer::QSkypeDialer(const QString &applicationName)
57 : QDialer(applicationName)
58 {
59 }
60
~QSkypeDialer()61 QSkypeDialer::~QSkypeDialer()
62 {
63 delete mInterface;
64 }
65
initializeSkype()66 bool QSkypeDialer::initializeSkype()
67 {
68 if (mInterface && mInterface->isValid()) {
69 return true;
70 }
71
72 // first check whether dbus interface is available yet
73 if (!isSkypeServiceRegistered()) {
74 // it could be skype is not running yet, so start it now
75 const QString progFullPath = QStandardPaths::findExecutable(QStringLiteral("skype"));
76 if (progFullPath.isEmpty() || !QProcess::startDetached(QStringLiteral("skype"), QStringList())) {
77 mErrorMessage = i18n("Unable to start skype process, check that skype executable is in your PATH variable.");
78 return false;
79 }
80
81 const int runs = 100;
82 for (int i = 0; i < runs; ++i) {
83 if (!isSkypeServiceRegistered()) {
84 #if !defined(Q_OS_WIN)
85 ::sleep(2);
86 #else
87 Sleep(2000);
88 #endif
89 } else {
90 break;
91 }
92 }
93 }
94
95 // check again for the dbus interface
96 mInterface = searchSkypeDBusInterface();
97
98 if (!mInterface->isValid()) {
99 delete mInterface;
100 mInterface = nullptr;
101
102 mErrorMessage = i18n("Skype Public API (D-Bus) seems to be disabled.");
103 return false;
104 }
105
106 QDBusReply<QString> reply = mInterface->call(QStringLiteral("Invoke"), QStringLiteral("NAME %1").arg(mApplicationName));
107 if (reply.value() != QLatin1String("OK")) {
108 delete mInterface;
109 mInterface = nullptr;
110
111 mErrorMessage = i18n("Skype registration failed.");
112 return false;
113 }
114
115 reply = mInterface->call(QStringLiteral("Invoke"), QStringLiteral("PROTOCOL 1"));
116 if (reply.value() != QLatin1String("PROTOCOL 1")) {
117 delete mInterface;
118 mInterface = nullptr;
119
120 mErrorMessage = i18n("Protocol mismatch.");
121 return false;
122 }
123
124 return true;
125 }
126
dialNumber(const QString & number)127 bool QSkypeDialer::dialNumber(const QString &number)
128 {
129 if (!initializeSkype()) {
130 return false;
131 }
132
133 QDBusReply<QString> reply = mInterface->call(QStringLiteral("Invoke"), QStringLiteral("CALL %1").arg(number));
134
135 return true;
136 }
137
sendSms(const QString & number,const QString & text)138 bool QSkypeDialer::sendSms(const QString &number, const QString &text)
139 {
140 if (!initializeSkype()) {
141 return false;
142 }
143
144 // First we create a new SMS object that gets an ID. We need that ID later...
145 QDBusReply<QString> reply = mInterface->call(QStringLiteral("Invoke"), QStringLiteral("CREATE SMS OUTGOING %1").arg(number));
146 const QString messageId = reply.value().section(QLatin1Char(' '), 1, 1);
147
148 // Set the SMS text
149 reply = mInterface->call(QStringLiteral("Invoke"), QStringLiteral("SET SMS %1 BODY %2").arg(messageId, text));
150
151 // Send the SMS
152 reply = mInterface->call(QStringLiteral("Invoke"), QStringLiteral("ALTER SMS %1 SEND").arg(messageId));
153 if (reply.value().contains(QLatin1String("ERROR"))) {
154 mErrorMessage = reply.value();
155 // As sending the message failed (not enough Skype credit), lets delete the message
156 reply = mInterface->call(QStringLiteral("Invoke"), QStringLiteral("DELETE SMS %1").arg(messageId));
157 return false;
158 }
159
160 return true;
161 }
162