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