3 Copyright (C) 2008 jlh (jlh at gmx dot ch)
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2 of the License, version 3 of
8 the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 The GNU General Public License version 2 is included with the source of
20 this program under the file name COPYING. You can also get a copy on
27 #include <QMessageBox>
34 const QString
skypeServiceName("com.Skype.API");
35 const QString
skypeInterfaceName("com.Skype.API");
38 Skype::Skype(QObject
*parent
) : QObject(parent
), dbus("SkypeRecorder"), connectionState(0) {
39 timer
= new QTimer(this);
40 timer
->setInterval(5000);
41 connect(timer
, SIGNAL(timeout()), this, SLOT(poll()));
43 dbus
= QDBusConnection::connectToBus(QDBusConnection::SessionBus
, "SkypeRecorder");
45 if (!dbus
.isConnected()) {
46 debug("Error: Cannot connect to DBus");
47 QMessageBox::critical(NULL
, PROGRAM_NAME
" - Error",
48 QString("The connection to DBus failed! This is a fatal error."));
53 exported
= new SkypeExport(this);
54 if (!dbus
.registerObject("/com/Skype/Client", this)) {
55 debug("Error: Cannot register object /com/Skype/Client");
56 QMessageBox::critical(NULL
, PROGRAM_NAME
" - Error",
57 QString("Cannot register object on DBus! This is a fatal error."));
61 connect(dbus
.interface(), SIGNAL(serviceOwnerChanged(const QString
&, const QString
&, const QString
&)),
62 this, SLOT(serviceOwnerChanged(const QString
&, const QString
&, const QString
&)));
63 QTimer::singleShot(0, this, SLOT(connectToSkype()));
66 void Skype::connectToSkype() {
70 QDBusReply
<bool> exists
= dbus
.interface()->isServiceRegistered(skypeServiceName
);
72 if (!exists
.isValid() || !exists
.value()) {
75 debug(QString("Service %1 not found on DBus").arg(skypeServiceName
));
79 if (!timer
->isActive())
82 sendWithAsyncReply("NAME SkypeCallRecorder");
86 void Skype::serviceOwnerChanged(const QString
&name
, const QString
&oldOwner
, const QString
&newOwner
) {
87 if (name
!= skypeServiceName
)
90 if (oldOwner
.isEmpty()) {
91 debug(QString("DBUS: Skype API service appeared as %1").arg(newOwner
));
92 if (connectionState
!= 3)
94 } else if (newOwner
.isEmpty()) {
95 debug("DBUS: Skype API service disappeared");
96 if (connectionState
== 3)
97 emit
connected(false);
103 void Skype::sendWithAsyncReply(const QString
&s
) {
104 debug(QString("SKYPE --> %1 (async reply)").arg(s
));
106 QDBusMessage msg
= QDBusMessage::createMethodCall(skypeServiceName
, "/com/Skype", skypeInterfaceName
, "Invoke");
107 QList
<QVariant
> args
;
109 msg
.setArguments(args
);
111 dbus
.callWithCallback(msg
, this, SLOT(methodCallback(const QDBusMessage
&)), SLOT(methodError(const QDBusError
&, const QDBusMessage
&)), 3600000);
114 QString
Skype::sendWithReply(const QString
&s
, int timeout
) {
115 debug(QString("SKYPE --> %1 (sync reply)").arg(s
));
117 QDBusMessage msg
= QDBusMessage::createMethodCall(skypeServiceName
, "/com/Skype", skypeInterfaceName
, "Invoke");
118 QList
<QVariant
> args
;
120 msg
.setArguments(args
);
122 msg
= dbus
.call(msg
, QDBus::Block
, timeout
);
124 if (msg
.type() != QDBusMessage::ReplyMessage
) {
125 debug(QString("SKYPE <R- (failed)"));
129 QString ret
= msg
.arguments().value(0).toString();
130 debug(QString("SKYPE <R- %1").arg(ret
));
134 void Skype::send(const QString
&s
) {
135 debug(QString("SKYPE --> %1 (no reply)").arg(s
));
137 QDBusMessage msg
= QDBusMessage::createMethodCall(skypeServiceName
, "/com/Skype", skypeInterfaceName
, "Invoke");
138 QList
<QVariant
> args
;
140 msg
.setArguments(args
);
142 dbus
.call(msg
, QDBus::NoBlock
);
145 QString
Skype::getObject(const QString
&object
) {
146 QString ret
= sendWithReply("GET " + object
);
147 if (!ret
.startsWith(object
))
149 return ret
.mid(object
.size() + 1);
152 void Skype::methodCallback(const QDBusMessage
&msg
) {
153 if (msg
.type() != QDBusMessage::ReplyMessage
) {
155 emit
connectionFailed("Cannot communicate with Skype");
159 QString s
= msg
.arguments().value(0).toString();
160 debug(QString("SKYPE <R- %1").arg(s
));
162 if (connectionState
== 1) {
165 sendWithAsyncReply("PROTOCOL 5");
166 } else if (s
== "CONNSTATUS OFFLINE") {
167 // no user logged in, cannot connect now. from now on,
168 // we have no way of knowing when the user has logged
169 // in and we may again try to connect. this is an
170 // annoying limitation of the Skype API which we work
175 emit
connectionFailed("Skype denied access");
177 } else if (connectionState
== 2) {
178 if (s
== "PROTOCOL 5") {
180 emit
connected(true);
183 emit
connectionFailed("Skype handshake error");
188 void Skype::methodError(const QDBusError
&error
, const QDBusMessage
&) {
190 emit
connectionFailed(error
.message());
193 void Skype::doNotify(const QString
&s
) {
194 if (connectionState
!= 3)
197 debug(QString("SKYPE <-- %1").arg(s
));
199 if (s
.startsWith("CURRENTUSERHANDLE "))
200 skypeName
= s
.mid(18);
206 if (connectionState
== 0) {
208 } else if (connectionState
== 3) {
209 if (sendWithReply("PING", 2000) != "PONG") {
210 debug("Skype didn't reply with PONG to our PING");
212 emit
connected(false);
217 // ---- SkypeExport ----
219 SkypeExport::SkypeExport(Skype
*p
) : QDBusAbstractAdaptor(p
), parent(p
) {
222 void SkypeExport::Notify(const QString
&s
) {