1 /*
2 * activeprofiles_dbus.cpp - Class for interacting with other psi instances
3 * Copyright (C) 2006-2007 Martin Hostettler
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 */
20
21 #include "activeprofiles.h"
22
23 #include <QCoreApplication>
24 #include <QString>
25 #include <QStringList>
26 #include <QByteArray>
27 #include <QDBusConnection>
28 #include <QDBusConnectionInterface>
29 #include <QDBusInterface>
30
31
32 #include <QLabel>
33 #include <QTimer>
34
35
36 #include "applicationinfo.h"
37 #include "dbus.h"
38
39
40
41
42
43 /** \brief encodes a string to "[A-Z][a-z][0-9]_-" ascii subset
44 * [A-Z][a-z][0-9] -> [A-Z][a-z][0-9]
45 * / -> _
46 * everything else to "-XX" with XX hex code of char
47 * (slow)
48 */
encodeAlNumD(QString in)49 static QString encodeAlNumD(QString in)
50 {
51 QString out;
52 QByteArray chars = in.toUtf8();
53 bool first = true;
54 foreach(char c, chars) {
55 if (('A' <= c) && (c <= 'z')) {
56 out += (char)c;
57 } else if (('0' <= c) && (c <= '9') && !first) {
58 out += (char)c;
59 } else if ('/' == c) {
60 out += "_";
61 } else {
62 out += QString("-%1").arg(c, 2, 16, QChar('0'));
63 }
64 first = false;
65 }
66 return out;
67 }
68
69
70 /** \brief DBus busname registration helper
71 * \param dbusIface interface of bus
72 * \param name busname to register
73 * \param queue try queueing?
74 * \return got dbus name?
75 */
registerBusname(QDBusConnectionInterface * dbusIface,QString name,bool queue)76 static bool registerBusname(QDBusConnectionInterface *dbusIface, QString name, bool queue)
77 {
78 bool ok = false;
79 QDBusReply<QDBusConnectionInterface::RegisterServiceReply> reply;
80 reply = dbusIface->registerService(name,
81 queue ? QDBusConnectionInterface::QueueService : QDBusConnectionInterface::DontQueueService,
82 QDBusConnectionInterface::AllowReplacement);
83 if (reply.isValid()) {
84 switch (reply.value()) {
85 case QDBusConnectionInterface::ServiceNotRegistered:
86 qWarning("failed to register dbus name %s:", qPrintable(name));
87 break;
88 case QDBusConnectionInterface::ServiceQueued:
89 qDebug("dbus name %s already taken, queueing", qPrintable(name));
90 break;
91 case QDBusConnectionInterface::ServiceRegistered:
92 ok = true;
93 }
94 } else {
95 qWarning("failed to register dbus name %s: %s", qPrintable(name), qPrintable(reply.error().message()));
96 }
97 return ok;
98 }
99
100
101 class ActiveProfiles::Private {
102 public:
103 QString profile;
104 QStringList busNames;
105 bool registerBusnames(QString prof);
106
107 QString dbusName(QString prof);
108 };
109
110
dbusName(QString prof)111 QString ActiveProfiles::Private::dbusName(QString prof)
112 {
113 QString name = PSIDBUSNAME;
114 name += ".";
115 name += encodeAlNumD(ApplicationInfo::homeDir(ApplicationInfo::ConfigLocation)).right(qMax(0,200-name.size()));
116 if (!prof.isEmpty()) {
117 name += ".";
118 name += encodeAlNumD(prof).right(qMax(0,250-name.size()));
119 }
120 return name;
121 }
122
123
124
registerBusnames(QString prof)125 bool ActiveProfiles::Private::registerBusnames(QString prof)
126 {
127 // FIXME move where?
128 if (!QDBusConnection::sessionBus().isConnected()) {
129 qWarning("can't connect to dbus");
130 return true;
131 }
132
133
134 QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface ();
135
136 QString name = PSIDBUSNAME;
137 registerBusname(dbusIface, name, true);
138 busNames << name;
139 name = dbusName(QString());
140 registerBusname(dbusIface, name, true);
141 busNames << name;
142 name = dbusName(prof);
143 busNames << name;
144 return registerBusname(dbusIface, name, false);
145
146 }
147
148
isActive(const QString & profile) const149 bool ActiveProfiles::isActive(const QString &profile) const
150 {
151 if (!QDBusConnection::sessionBus().isConnected()) {
152 qWarning("can't connect to dbus");
153 return false;
154 }
155
156 QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface ();
157 return dbusIface->isServiceRegistered(d->dbusName(profile));
158 }
159
isAnyActive() const160 bool ActiveProfiles::isAnyActive() const
161 {
162 return isActive("");
163 }
164
165
setThisProfile(const QString & profile)166 bool ActiveProfiles::setThisProfile(const QString &profile)
167 {
168 if (profile == d->profile)
169 return true;
170
171 if (profile.isEmpty()) {
172 unsetThisProfile();
173 return true;
174 }
175 bool ok = d->registerBusnames(profile);
176 if (ok) {
177 d->profile = profile;
178 } else {
179 unsetThisProfile();
180 }
181 return ok;
182 }
183
unsetThisProfile()184 void ActiveProfiles::unsetThisProfile()
185 {
186 QDBusConnectionInterface *dbusIface = QDBusConnection::sessionBus().interface ();
187 foreach(QString name, d->busNames) {
188 dbusIface->unregisterService(name);
189 }
190 d->busNames.clear();
191 d->profile = QString();
192 }
193
thisProfile() const194 QString ActiveProfiles::thisProfile() const
195 {
196 return d->profile;
197 }
198
ActiveProfiles()199 ActiveProfiles::ActiveProfiles()
200 : QObject(QCoreApplication::instance())
201 {
202 d = new ActiveProfiles::Private;
203 }
204
~ActiveProfiles()205 ActiveProfiles::~ActiveProfiles()
206 {
207 delete d;
208 d = 0;
209 }
210
setStatus(const QString & profile,const QString & status,const QString & message) const211 bool ActiveProfiles::setStatus(const QString &profile, const QString &status, const QString &message) const
212 {
213 QDBusInterface(d->dbusName(profile), "/Main", PSIDBUSMAINIF).call(QDBus::NoBlock,
214 "setStatus", status, message);
215 return true;
216 }
217
openUri(const QString & profile,const QString & uri) const218 bool ActiveProfiles::openUri(const QString &profile, const QString &uri) const
219 {
220 QDBusInterface(d->dbusName(profile), "/Main", PSIDBUSMAINIF).call(QDBus::NoBlock,
221 "openURI", uri);
222 return true;
223 }
224
raise(const QString & profile,bool withUI) const225 bool ActiveProfiles::raise(const QString &profile, bool withUI) const
226 {
227 QLabel *lab=0;
228 QDBusMessage msg = QDBusMessage::createMethodCall ( d->dbusName(profile), "/Main", PSIDBUSMAINIF, "raise" );
229 if (withUI) {
230 lab = new QLabel(tr("This psi profile is already running...<br>please wait..."));
231 QTimer::singleShot(250, lab, SLOT(show()));
232 }
233 QDBusMessage rmsg = QDBusConnection::sessionBus().call(msg, QDBus::BlockWithGui, 10000);
234 if (withUI) {
235 lab->hide();
236 delete lab;
237 }
238 if (rmsg.type() == QDBusMessage::ReplyMessage) {
239 return true;
240 } else return false;
241 }
242