fix logic
[personal-kdelibs.git] / kdecore / kernel / ktoolinvocation.cpp
blob1824f8d65952d847682bd5a1a1101de2df9361d9
1 /* This file is part of the KDE libraries
2 Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
3 Copyright (C) 2006 Thiago Macieira <thiago@kde.org>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library 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 GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include "ktoolinvocation.h"
22 #include "klauncher_iface.h"
23 #include "kdebug.h"
24 #include "kglobal.h"
25 #include "kstandarddirs.h"
26 #include "kcomponentdata.h"
27 #include "kurl.h"
28 #include "kmessage.h"
29 #include "kservice.h"
30 #include <klockfile.h>
31 #include <klocale.h>
33 #include <QMutex>
34 #include <QMutexLocker>
35 #include <QCoreApplication>
36 #include <QThread>
38 #include <errno.h>
41 KToolInvocation *KToolInvocation::self()
43 K_GLOBAL_STATIC(KToolInvocation, s_self)
44 return s_self;
47 KToolInvocation::KToolInvocation() : QObject(0), d(0)
51 KToolInvocation::~KToolInvocation()
55 Q_GLOBAL_STATIC_WITH_ARGS(org::kde::KLauncher, klauncherIface,
56 ("org.kde.klauncher", "/KLauncher", QDBusConnection::sessionBus()))
58 org::kde::KLauncher *KToolInvocation::klauncher()
60 if ( !QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.klauncher" ) )
62 kDebug() << "klauncher not running... launching kdeinit";
63 KToolInvocation::startKdeinit();
65 return ::klauncherIface();
68 static void printError(const QString& text, QString* error)
70 if (error)
71 *error = text;
72 else
73 kError() << text << endl;
76 bool KToolInvocation::isMainThreadActive(QString* error)
78 if (QCoreApplication::instance() && QCoreApplication::instance()->thread() != QThread::currentThread())
80 printError(i18n("Function must be called from the main thread."), error);
81 return false;
84 return true;
87 int KToolInvocation::startServiceInternal(const char *_function,
88 const QString& _name, const QStringList &URLs,
89 QString *error, QString *serviceName, int *pid,
90 const QByteArray& startup_id, bool noWait,
91 const QString& workdir)
93 QString function = QLatin1String(_function);
94 org::kde::KLauncher *launcher = KToolInvocation::klauncher();
95 QDBusMessage msg = QDBusMessage::createMethodCall(launcher->service(),
96 launcher->path(),
97 launcher->interface(),
98 function);
99 msg << _name << URLs;
100 if (function == QLatin1String("kdeinit_exec_with_workdir"))
101 msg << workdir;
102 #ifdef Q_WS_X11
103 // make sure there is id, so that user timestamp exists
104 QStringList envs;
105 QByteArray s = startup_id;
106 emit kapplication_hook(envs, s);
107 msg << envs;
108 msg << QString(s);
109 #else
110 msg << QStringList();
111 msg << QString();
112 #endif
113 if( !function.startsWith( QLatin1String("kdeinit_exec") ) )
114 msg << noWait;
116 QDBusMessage reply = QDBusConnection::sessionBus().call(msg);
117 if ( reply.type() != QDBusMessage::ReplyMessage )
119 QDBusReply<QString> replyObj(reply);
120 if (replyObj.error().type() == QDBusError::NoReply) {
121 printError(i18n("Error launching %1. Either KLauncher is not running anymore, or it failed to start the application.", _name), error);
122 } else {
123 const QString rpl = reply.arguments().count() > 0 ? reply.arguments().at(0).toString() : reply.errorMessage();
124 printError(i18n("KLauncher could not be reached via D-Bus. Error when calling %1:\n%2\n",function, rpl), error);
126 //qDebug() << reply;
127 return EINVAL;
130 if (noWait)
131 return 0;
133 Q_ASSERT(reply.arguments().count() == 4);
134 if (serviceName)
135 *serviceName = reply.arguments().at(1).toString();
136 if (error)
137 *error = reply.arguments().at(2).toString();
138 if (pid)
139 *pid = reply.arguments().at(3).toInt();
140 return reply.arguments().at(0).toInt();
144 KToolInvocation::startServiceByName( const QString& _name, const QString &URL,
145 QString *error, QString *serviceName, int *pid,
146 const QByteArray& startup_id, bool noWait )
148 if (!isMainThreadActive(error))
149 return EINVAL;
151 QStringList URLs;
152 if (!URL.isEmpty())
153 URLs.append(URL);
154 return self()->startServiceInternal("start_service_by_name",
155 _name, URLs, error, serviceName, pid, startup_id, noWait);
159 KToolInvocation::startServiceByName( const QString& _name, const QStringList &URLs,
160 QString *error, QString *serviceName, int *pid,
161 const QByteArray& startup_id, bool noWait )
163 if (!isMainThreadActive(error))
164 return EINVAL;
166 return self()->startServiceInternal("start_service_by_name",
167 _name, URLs, error, serviceName, pid, startup_id, noWait);
171 KToolInvocation::startServiceByDesktopPath( const QString& _name, const QString &URL,
172 QString *error, QString *serviceName,
173 int *pid, const QByteArray& startup_id, bool noWait )
175 if (!isMainThreadActive(error))
176 return EINVAL;
178 QStringList URLs;
179 if (!URL.isEmpty())
180 URLs.append(URL);
181 return self()->startServiceInternal("start_service_by_desktop_path",
182 _name, URLs, error, serviceName, pid, startup_id, noWait);
186 KToolInvocation::startServiceByDesktopPath( const QString& _name, const QStringList &URLs,
187 QString *error, QString *serviceName, int *pid,
188 const QByteArray& startup_id, bool noWait )
190 if (!isMainThreadActive(error))
191 return EINVAL;
193 return self()->startServiceInternal("start_service_by_desktop_path",
194 _name, URLs, error, serviceName, pid, startup_id, noWait);
198 KToolInvocation::startServiceByDesktopName( const QString& _name, const QString &URL,
199 QString *error, QString *serviceName, int *pid,
200 const QByteArray& startup_id, bool noWait )
202 if (!isMainThreadActive(error))
203 return EINVAL;
205 QStringList URLs;
206 if (!URL.isEmpty())
207 URLs.append(URL);
208 return self()->startServiceInternal("start_service_by_desktop_name",
209 _name, URLs, error, serviceName, pid, startup_id, noWait);
213 KToolInvocation::startServiceByDesktopName( const QString& _name, const QStringList &URLs,
214 QString *error, QString *serviceName, int *pid,
215 const QByteArray& startup_id, bool noWait )
217 if (!isMainThreadActive(error))
218 return EINVAL;
220 return self()->startServiceInternal("start_service_by_desktop_name",
221 _name, URLs, error, serviceName, pid, startup_id, noWait);
225 KToolInvocation::kdeinitExec( const QString& name, const QStringList &args,
226 QString *error, int *pid, const QByteArray& startup_id )
228 if (!isMainThreadActive(error))
229 return EINVAL;
231 return self()->startServiceInternal("kdeinit_exec",
232 name, args, error, 0, pid, startup_id, false);
237 KToolInvocation::kdeinitExecWait( const QString& name, const QStringList &args,
238 QString *error, int *pid, const QByteArray& startup_id )
240 if (!isMainThreadActive(error))
241 return EINVAL;
243 return self()->startServiceInternal("kdeinit_exec_wait",
244 name, args, error, 0, pid, startup_id, false);
247 void KToolInvocation::invokeHelp( const QString& anchor,
248 const QString& _appname,
249 const QByteArray& startup_id )
251 if (!isMainThreadActive())
252 return;
254 KUrl url;
255 QString appname;
256 QString docPath;
257 if (_appname.isEmpty()) {
258 appname = QCoreApplication::instance()->applicationName();
259 } else
260 appname = _appname;
262 KService::Ptr service(KService::serviceByDesktopName(appname));
263 if (service) {
264 docPath = service->docPath();
267 if (!docPath.isEmpty()) {
268 url = KUrl(KUrl("help:/"), docPath);
269 } else {
270 url = QString("help:/%1/index.html").arg(appname);
273 if (!anchor.isEmpty()) {
274 url.addQueryItem("anchor", anchor);
277 // launch a browser for URIs not handled by khelpcenter
278 // (following KCMultiDialog::slotHelpClicked())
279 if (!(url.protocol() == "help" || url.protocol() == "man" || url.protocol() == "info")) {
280 invokeBrowser(url.url());
281 return;
284 QDBusInterface *iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
285 QLatin1String("/KHelpCenter"),
286 QLatin1String("org.kde.khelpcenter.khelpcenter"),
287 QDBusConnection::sessionBus());
288 if ( !iface->isValid() )
290 QString error;
291 #ifdef Q_WS_WIN
292 // startServiceByDesktopName() does not work yet; KRun:processDesktopExec returned 'KRun: syntax error in command "khelpcenter %u" , service "KHelpCenter" '
293 if (kdeinitExec( "khelpcenter", QStringList() << url.url(), &error, 0, startup_id ))
294 #else
295 if (startServiceByDesktopName("khelpcenter", url.url(), &error, 0, 0, startup_id, false))
296 #endif
298 KMessage::message(KMessage::Error,
299 i18n("Could not launch the KDE Help Center:\n\n%1", error),
300 i18n("Could not Launch Help Center"));
301 return;
304 delete iface;
305 iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
306 QLatin1String("/KHelpCenter"),
307 QLatin1String("org.kde.khelpcenter.khelpcenter"),
308 QDBusConnection::sessionBus());
311 iface->call("openUrl", url.url(), startup_id );
312 delete iface;
315 void KToolInvocation::invokeMailer(const QString &address, const QString &subject, const QByteArray& startup_id)
317 if (!isMainThreadActive())
318 return;
320 invokeMailer(address, QString(), QString(), subject, QString(), QString(),
321 QStringList(), startup_id );
324 void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray& startup_id, bool allowAttachments )
326 if (!isMainThreadActive())
327 return;
329 QString address = KUrl::fromPercentEncoding(mailtoURL.path().toLatin1()), subject, cc, bcc, body;
330 const QStringList queries = mailtoURL.query().mid(1).split( '&');
331 QStringList attachURLs;
332 for (QStringList::ConstIterator it = queries.begin(); it != queries.end(); ++it)
334 QString q = (*it).toLower();
335 if (q.startsWith("subject="))
336 subject = KUrl::fromPercentEncoding((*it).mid(8).toLatin1());
337 else
338 if (q.startsWith("cc="))
339 cc = cc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): cc + ',' + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
340 else
341 if (q.startsWith("bcc="))
342 bcc = bcc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(4).toLatin1()): bcc + ',' + KUrl::fromPercentEncoding((*it).mid(4).toLatin1());
343 else
344 if (q.startsWith("body="))
345 body = KUrl::fromPercentEncoding((*it).mid(5).toLatin1());
346 else
347 if (allowAttachments && q.startsWith("attach="))
348 attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(7).toLatin1()));
349 else
350 if (allowAttachments && q.startsWith("attachment="))
351 attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(11).toLatin1()));
352 else
353 if (q.startsWith("to="))
354 address = address.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): address + ',' + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
357 invokeMailer( address, cc, bcc, subject, body, QString(), attachURLs, startup_id );
360 void KToolInvocation::startKdeinit()
362 KComponentData inst( "startkdeinitlock" );
363 KLockFile lock( KStandardDirs::locateLocal( "tmp", "startkdeinitlock", inst ));
364 if( lock.lock( KLockFile::NoBlockFlag ) != KLockFile::LockOK ) {
365 lock.lock();
366 if( QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.klauncher" ))
367 return; // whoever held the lock has already started it
369 // Try to launch kdeinit.
370 QString srv = KStandardDirs::findExe(QLatin1String("kdeinit4"));
371 if (srv.isEmpty())
372 return;
373 // this is disabled because we are in kdecore
374 // const bool gui = qApp && qApp->type() != QApplication::Tty;
375 // if ( gui )
376 // qApp->setOverrideCursor( Qt::WaitCursor );
377 QStringList args;
378 #ifndef Q_WS_WIN
379 args += "--suicide";
380 #endif
381 QProcess::execute(srv, args);
382 // if ( gui )
383 // qApp->restoreOverrideCursor();
386 #include "ktoolinvocation.moc"