00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "ktoolinvocation.h"
00022 #include "klauncher_iface.h"
00023 #include "kdebug.h"
00024 #include "kglobal.h"
00025 #include "kstandarddirs.h"
00026 #include "kcomponentdata.h"
00027 #include "kurl.h"
00028 #include "kmessage.h"
00029 #include "kservice.h"
00030 #include <klockfile.h>
00031 #include <klocale.h>
00032
00033 #include <QMutex>
00034 #include <QMutexLocker>
00035 #include <QCoreApplication>
00036 #include <QThread>
00037
00038 #include <errno.h>
00039
00040
00041 KToolInvocation *KToolInvocation::self()
00042 {
00043 K_GLOBAL_STATIC(KToolInvocation, s_self)
00044 return s_self;
00045 }
00046
00047 KToolInvocation::KToolInvocation() : QObject(0), d(0)
00048 {
00049 }
00050
00051 KToolInvocation::~KToolInvocation()
00052 {
00053 }
00054
00055 Q_GLOBAL_STATIC_WITH_ARGS(org::kde::KLauncher, klauncherIface,
00056 ("org.kde.klauncher", "/KLauncher", QDBusConnection::sessionBus()))
00057
00058 org::kde::KLauncher *KToolInvocation::klauncher()
00059 {
00060 if ( !QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.klauncher" ) )
00061 {
00062 kDebug() << "klauncher not running... launching kdeinit";
00063 KToolInvocation::startKdeinit();
00064 }
00065 return ::klauncherIface();
00066 }
00067
00068 static void printError(const QString& text, QString* error)
00069 {
00070 if (error)
00071 *error = text;
00072 else
00073 kError() << text << endl;
00074 }
00075
00076 bool KToolInvocation::isMainThreadActive(QString* error)
00077 {
00078 if (QCoreApplication::instance() && QCoreApplication::instance()->thread() != QThread::currentThread())
00079 {
00080 printError(i18n("Function must be called from the main thread."), error);
00081 return false;
00082 }
00083
00084 return true;
00085 }
00086
00087 int KToolInvocation::startServiceInternal(const char *_function,
00088 const QString& _name, const QStringList &URLs,
00089 QString *error, QString *serviceName, int *pid,
00090 const QByteArray& startup_id, bool noWait,
00091 const QString& workdir)
00092 {
00093 QString function = QLatin1String(_function);
00094 org::kde::KLauncher *launcher = KToolInvocation::klauncher();
00095 QDBusMessage msg = QDBusMessage::createMethodCall(launcher->service(),
00096 launcher->path(),
00097 launcher->interface(),
00098 function);
00099 msg << _name << URLs;
00100 if (function == QLatin1String("kdeinit_exec_with_workdir"))
00101 msg << workdir;
00102 #ifdef Q_WS_X11
00103
00104 QStringList envs;
00105 QByteArray s = startup_id;
00106 emit kapplication_hook(envs, s);
00107 msg << envs;
00108 msg << QString(s);
00109 #else
00110 msg << QStringList();
00111 msg << QString();
00112 #endif
00113 if( !function.startsWith( QLatin1String("kdeinit_exec") ) )
00114 msg << noWait;
00115
00116 QDBusMessage reply = QDBusConnection::sessionBus().call(msg);
00117 if ( reply.type() != QDBusMessage::ReplyMessage )
00118 {
00119 QDBusReply<QString> replyObj(reply);
00120 if (replyObj.error().type() == QDBusError::NoReply) {
00121 printError(i18n("Error launching %1. Either KLauncher is not running anymore, or it failed to start the application.", _name), error);
00122 } else {
00123 const QString rpl = reply.arguments().count() > 0 ? reply.arguments().at(0).toString() : reply.errorMessage();
00124 printError(i18n("KLauncher could not be reached via D-Bus. Error when calling %1:\n%2\n",function, rpl), error);
00125 }
00126
00127 return EINVAL;
00128 }
00129
00130 if (noWait)
00131 return 0;
00132
00133 Q_ASSERT(reply.arguments().count() == 4);
00134 if (serviceName)
00135 *serviceName = reply.arguments().at(1).toString();
00136 if (error)
00137 *error = reply.arguments().at(2).toString();
00138 if (pid)
00139 *pid = reply.arguments().at(3).toInt();
00140 return reply.arguments().at(0).toInt();
00141 }
00142
00143 int
00144 KToolInvocation::startServiceByName( const QString& _name, const QString &URL,
00145 QString *error, QString *serviceName, int *pid,
00146 const QByteArray& startup_id, bool noWait )
00147 {
00148 if (!isMainThreadActive(error))
00149 return EINVAL;
00150
00151 QStringList URLs;
00152 if (!URL.isEmpty())
00153 URLs.append(URL);
00154 return self()->startServiceInternal("start_service_by_name",
00155 _name, URLs, error, serviceName, pid, startup_id, noWait);
00156 }
00157
00158 int
00159 KToolInvocation::startServiceByName( const QString& _name, const QStringList &URLs,
00160 QString *error, QString *serviceName, int *pid,
00161 const QByteArray& startup_id, bool noWait )
00162 {
00163 if (!isMainThreadActive(error))
00164 return EINVAL;
00165
00166 return self()->startServiceInternal("start_service_by_name",
00167 _name, URLs, error, serviceName, pid, startup_id, noWait);
00168 }
00169
00170 int
00171 KToolInvocation::startServiceByDesktopPath( const QString& _name, const QString &URL,
00172 QString *error, QString *serviceName,
00173 int *pid, const QByteArray& startup_id, bool noWait )
00174 {
00175 if (!isMainThreadActive(error))
00176 return EINVAL;
00177
00178 QStringList URLs;
00179 if (!URL.isEmpty())
00180 URLs.append(URL);
00181 return self()->startServiceInternal("start_service_by_desktop_path",
00182 _name, URLs, error, serviceName, pid, startup_id, noWait);
00183 }
00184
00185 int
00186 KToolInvocation::startServiceByDesktopPath( const QString& _name, const QStringList &URLs,
00187 QString *error, QString *serviceName, int *pid,
00188 const QByteArray& startup_id, bool noWait )
00189 {
00190 if (!isMainThreadActive(error))
00191 return EINVAL;
00192
00193 return self()->startServiceInternal("start_service_by_desktop_path",
00194 _name, URLs, error, serviceName, pid, startup_id, noWait);
00195 }
00196
00197 int
00198 KToolInvocation::startServiceByDesktopName( const QString& _name, const QString &URL,
00199 QString *error, QString *serviceName, int *pid,
00200 const QByteArray& startup_id, bool noWait )
00201 {
00202 if (!isMainThreadActive(error))
00203 return EINVAL;
00204
00205 QStringList URLs;
00206 if (!URL.isEmpty())
00207 URLs.append(URL);
00208 return self()->startServiceInternal("start_service_by_desktop_name",
00209 _name, URLs, error, serviceName, pid, startup_id, noWait);
00210 }
00211
00212 int
00213 KToolInvocation::startServiceByDesktopName( const QString& _name, const QStringList &URLs,
00214 QString *error, QString *serviceName, int *pid,
00215 const QByteArray& startup_id, bool noWait )
00216 {
00217 if (!isMainThreadActive(error))
00218 return EINVAL;
00219
00220 return self()->startServiceInternal("start_service_by_desktop_name",
00221 _name, URLs, error, serviceName, pid, startup_id, noWait);
00222 }
00223
00224 int
00225 KToolInvocation::kdeinitExec( const QString& name, const QStringList &args,
00226 QString *error, int *pid, const QByteArray& startup_id )
00227 {
00228 if (!isMainThreadActive(error))
00229 return EINVAL;
00230
00231 return self()->startServiceInternal("kdeinit_exec",
00232 name, args, error, 0, pid, startup_id, false);
00233 }
00234
00235
00236 int
00237 KToolInvocation::kdeinitExecWait( const QString& name, const QStringList &args,
00238 QString *error, int *pid, const QByteArray& startup_id )
00239 {
00240 if (!isMainThreadActive(error))
00241 return EINVAL;
00242
00243 return self()->startServiceInternal("kdeinit_exec_wait",
00244 name, args, error, 0, pid, startup_id, false);
00245 }
00246
00247 void KToolInvocation::invokeHelp( const QString& anchor,
00248 const QString& _appname,
00249 const QByteArray& startup_id )
00250 {
00251 if (!isMainThreadActive())
00252 return;
00253
00254 KUrl url;
00255 QString appname;
00256 QString docPath;
00257 if (_appname.isEmpty()) {
00258 appname = QCoreApplication::instance()->applicationName();
00259 } else
00260 appname = _appname;
00261
00262 KService::Ptr service(KService::serviceByDesktopName(appname));
00263 if (service) {
00264 docPath = service->docPath();
00265 }
00266
00267 if (!docPath.isEmpty()) {
00268 url = KUrl(KUrl("help:/"), docPath);
00269 } else {
00270 url = QString("help:/%1/index.html").arg(appname);
00271 }
00272
00273 if (!anchor.isEmpty()) {
00274 url.addQueryItem("anchor", anchor);
00275 }
00276
00277
00278
00279 if (!(url.protocol() == "help" || url.protocol() == "man" || url.protocol() == "info")) {
00280 invokeBrowser(url.url());
00281 return;
00282 }
00283
00284 QDBusInterface *iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
00285 QLatin1String("/KHelpCenter"),
00286 QLatin1String("org.kde.khelpcenter.khelpcenter"),
00287 QDBusConnection::sessionBus());
00288 if ( !iface->isValid() )
00289 {
00290 QString error;
00291 #ifdef Q_WS_WIN
00292
00293 if (kdeinitExec( "khelpcenter", QStringList() << url.url(), &error, 0, startup_id ))
00294 #else
00295 if (startServiceByDesktopName("khelpcenter", url.url(), &error, 0, 0, startup_id, false))
00296 #endif
00297 {
00298 KMessage::message(KMessage::Error,
00299 i18n("Could not launch the KDE Help Center:\n\n%1", error),
00300 i18n("Could not Launch Help Center"));
00301 return;
00302 }
00303
00304 delete iface;
00305 iface = new QDBusInterface(QLatin1String("org.kde.khelpcenter"),
00306 QLatin1String("/KHelpCenter"),
00307 QLatin1String("org.kde.khelpcenter.khelpcenter"),
00308 QDBusConnection::sessionBus());
00309 }
00310
00311 iface->call("openUrl", url.url(), startup_id );
00312 delete iface;
00313 }
00314
00315 void KToolInvocation::invokeMailer(const QString &address, const QString &subject, const QByteArray& startup_id)
00316 {
00317 if (!isMainThreadActive())
00318 return;
00319
00320 invokeMailer(address, QString(), QString(), subject, QString(), QString(),
00321 QStringList(), startup_id );
00322 }
00323
00324 void KToolInvocation::invokeMailer(const KUrl &mailtoURL, const QByteArray& startup_id, bool allowAttachments )
00325 {
00326 if (!isMainThreadActive())
00327 return;
00328
00329 QString address = KUrl::fromPercentEncoding(mailtoURL.path().toLatin1()), subject, cc, bcc, body;
00330 const QStringList queries = mailtoURL.query().mid(1).split( '&');
00331 QStringList attachURLs;
00332 for (QStringList::ConstIterator it = queries.begin(); it != queries.end(); ++it)
00333 {
00334 QString q = (*it).toLower();
00335 if (q.startsWith("subject="))
00336 subject = KUrl::fromPercentEncoding((*it).mid(8).toLatin1());
00337 else
00338 if (q.startsWith("cc="))
00339 cc = cc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): cc + ',' + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
00340 else
00341 if (q.startsWith("bcc="))
00342 bcc = bcc.isEmpty()? KUrl::fromPercentEncoding((*it).mid(4).toLatin1()): bcc + ',' + KUrl::fromPercentEncoding((*it).mid(4).toLatin1());
00343 else
00344 if (q.startsWith("body="))
00345 body = KUrl::fromPercentEncoding((*it).mid(5).toLatin1());
00346 else
00347 if (allowAttachments && q.startsWith("attach="))
00348 attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(7).toLatin1()));
00349 else
00350 if (allowAttachments && q.startsWith("attachment="))
00351 attachURLs.push_back(KUrl::fromPercentEncoding((*it).mid(11).toLatin1()));
00352 else
00353 if (q.startsWith("to="))
00354 address = address.isEmpty()? KUrl::fromPercentEncoding((*it).mid(3).toLatin1()): address + ',' + KUrl::fromPercentEncoding((*it).mid(3).toLatin1());
00355 }
00356
00357 invokeMailer( address, cc, bcc, subject, body, QString(), attachURLs, startup_id );
00358 }
00359
00360 void KToolInvocation::startKdeinit()
00361 {
00362 KComponentData inst( "startkdeinitlock" );
00363 KLockFile lock( KStandardDirs::locateLocal( "tmp", "startkdeinitlock", inst ));
00364 if( lock.lock( KLockFile::NoBlockFlag ) != KLockFile::LockOK ) {
00365 lock.lock();
00366 if( QDBusConnection::sessionBus().interface()->isServiceRegistered( "org.kde.klauncher" ))
00367 return;
00368 }
00369
00370 QString srv = KStandardDirs::findExe(QLatin1String("kdeinit4"));
00371 if (srv.isEmpty())
00372 return;
00373
00374
00375
00376
00377 QStringList args;
00378 #ifndef Q_WS_WIN
00379 args += "--suicide";
00380 #endif
00381 QProcess::execute(srv, args);
00382
00383
00384 }
00385
00386 #include "ktoolinvocation.moc"