Make scripts exit early on errors
[skype-call-recorder.git] / skype.cpp
blobfad660741bd17add6b7891a8cd8a8a6eccae515e
1 /*
2 Skype Call Recorder
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
21 http://www.fsf.org/
24 #include <QList>
25 #include <QVariant>
26 #include <QTimer>
27 #include <QMessageBox>
28 #include <QtDBus>
30 #include "skype.h"
31 #include "common.h"
33 namespace {
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."));
49 return;
52 // export our object
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."));
58 return;
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() {
67 if (connectionState)
68 return;
70 QDBusReply<bool> exists = dbus.interface()->isServiceRegistered(skypeServiceName);
72 if (!exists.isValid() || !exists.value()) {
73 timer->stop();
75 debug(QString("Service %1 not found on DBus").arg(skypeServiceName));
76 return;
79 if (!timer->isActive())
80 timer->start();
82 sendWithAsyncReply("NAME SkypeCallRecorder");
83 connectionState = 1;
86 void Skype::serviceOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner) {
87 if (name != skypeServiceName)
88 return;
90 if (oldOwner.isEmpty()) {
91 debug(QString("DBUS: Skype API service appeared as %1").arg(newOwner));
92 if (connectionState != 3)
93 connectToSkype();
94 } else if (newOwner.isEmpty()) {
95 debug("DBUS: Skype API service disappeared");
96 if (connectionState == 3)
97 emit connected(false);
98 timer->stop();
99 connectionState = 0;
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;
108 args.append(s);
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;
119 args.append(s);
120 msg.setArguments(args);
122 msg = dbus.call(msg, QDBus::Block, timeout);
124 if (msg.type() != QDBusMessage::ReplyMessage) {
125 debug(QString("SKYPE <R- (failed)"));
126 return QString();
129 QString ret = msg.arguments().value(0).toString();
130 debug(QString("SKYPE <R- %1").arg(ret));
131 return 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;
139 args.append(s);
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))
148 return QString();
149 return ret.mid(object.size() + 1);
152 void Skype::methodCallback(const QDBusMessage &msg) {
153 if (msg.type() != QDBusMessage::ReplyMessage) {
154 connectionState = 0;
155 emit connectionFailed("Cannot communicate with Skype");
156 return;
159 QString s = msg.arguments().value(0).toString();
160 debug(QString("SKYPE <R- %1").arg(s));
162 if (connectionState == 1) {
163 if (s == "OK") {
164 connectionState = 2;
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
171 // around be polling
172 connectionState = 0;
173 } else {
174 connectionState = 0;
175 emit connectionFailed("Skype denied access");
177 } else if (connectionState == 2) {
178 if (s == "PROTOCOL 5") {
179 connectionState = 3;
180 emit connected(true);
181 } else {
182 connectionState = 0;
183 emit connectionFailed("Skype handshake error");
188 void Skype::methodError(const QDBusError &error, const QDBusMessage &) {
189 connectionState = 0;
190 emit connectionFailed(error.message());
193 void Skype::doNotify(const QString &s) {
194 if (connectionState != 3)
195 return;
197 debug(QString("SKYPE <-- %1").arg(s));
199 if (s.startsWith("CURRENTUSERHANDLE "))
200 skypeName = s.mid(18);
202 emit notify(s);
205 void Skype::poll() {
206 if (connectionState == 0) {
207 connectToSkype();
208 } else if (connectionState == 3) {
209 if (sendWithReply("PING", 2000) != "PONG") {
210 debug("Skype didn't reply with PONG to our PING");
211 connectionState = 0;
212 emit connected(false);
217 // ---- SkypeExport ----
219 SkypeExport::SkypeExport(Skype *p) : QDBusAbstractAdaptor(p), parent(p) {
222 void SkypeExport::Notify(const QString &s) {
223 parent->doNotify(s);