File indexing completed on 2024-04-28 15:29:48
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2005 Brad Hards <bradh@frogmouth.net> 0004 SPDX-FileCopyrightText: 2006 Thiago Macieira <thiago@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "ktoolinvocation.h" 0010 #ifdef QT_DBUS_LIB 0011 #include "klauncher_iface.h" 0012 #include <KDEInitInterface> 0013 #endif 0014 #include "kservice.h" 0015 #include <KLocalizedString> 0016 0017 #include <QCoreApplication> 0018 #include <QDebug> 0019 #include <QStandardPaths> 0020 #include <QThread> 0021 #include <QUrl> 0022 #include <QUrlQuery> 0023 0024 #include <errno.h> // for EINVAL 0025 0026 class KToolInvocationSingleton 0027 { 0028 public: 0029 KToolInvocation instance; 0030 }; 0031 0032 Q_GLOBAL_STATIC(KToolInvocationSingleton, s_self) 0033 0034 KToolInvocation *KToolInvocation::self() 0035 { 0036 return &s_self()->instance; 0037 } 0038 0039 KToolInvocation::KToolInvocation() 0040 : QObject(nullptr) 0041 , d(nullptr) 0042 { 0043 } 0044 0045 KToolInvocation::~KToolInvocation() 0046 { 0047 } 0048 0049 static void printError(const QString &text, QString *error) 0050 { 0051 if (error) { 0052 *error = text; 0053 } else { 0054 qWarning() << text; 0055 } 0056 } 0057 0058 bool KToolInvocation::isMainThreadActive(QString *error) 0059 { 0060 if (QCoreApplication::instance() && QCoreApplication::instance()->thread() != QThread::currentThread()) { 0061 printError(i18n("Function must be called from the main thread."), error); 0062 return false; 0063 } 0064 0065 return true; 0066 } 0067 0068 int KToolInvocation::startServiceInternal(const char *_function, 0069 const QString &_name, 0070 const QStringList &URLs, 0071 QString *error, 0072 QString *serviceName, 0073 int *pid, 0074 const QByteArray &startup_id, 0075 bool noWait, 0076 const QString &workdir, 0077 const QStringList &envs) 0078 { 0079 #ifdef QT_DBUS_LIB 0080 QString function = QLatin1String(_function); 0081 KToolInvocation::ensureKdeinitRunning(); 0082 QDBusMessage msg = 0083 QDBusMessage::createMethodCall(QStringLiteral("org.kde.klauncher5"), QStringLiteral("/KLauncher"), QStringLiteral("org.kde.KLauncher"), function); 0084 msg << _name << URLs; 0085 if (function == QLatin1String("kdeinit_exec_with_workdir")) { 0086 msg << workdir; 0087 } 0088 // make sure there is id, so that user timestamp exists 0089 QByteArray s = startup_id; 0090 QStringList envCopy(envs); 0091 Q_EMIT kapplication_hook(envCopy, s); 0092 msg << envCopy; 0093 msg << QString::fromLatin1(s); 0094 if (!function.startsWith(QLatin1String("kdeinit_exec"))) { 0095 msg << noWait; 0096 } 0097 0098 QDBusMessage reply = QDBusConnection::sessionBus().call(msg, QDBus::Block, INT_MAX); 0099 if (reply.type() != QDBusMessage::ReplyMessage) { 0100 QDBusReply<QString> replyObj(reply); 0101 if (replyObj.error().type() == QDBusError::NoReply) { 0102 printError(i18n("Error launching %1. Either KLauncher is not running anymore, or it failed to start the application.", _name), error); 0103 } else { 0104 const QString rpl = reply.arguments().count() > 0 ? reply.arguments().at(0).toString() : reply.errorMessage(); 0105 printError(i18n("KLauncher could not be reached via D-Bus. Error when calling %1:\n%2\n", function, rpl), error); 0106 } 0107 // qDebug() << reply; 0108 return EINVAL; 0109 } 0110 0111 if (noWait) { 0112 return 0; 0113 } 0114 0115 Q_ASSERT(reply.arguments().count() == 4); 0116 if (serviceName) { 0117 *serviceName = reply.arguments().at(1).toString(); 0118 } 0119 if (error) { 0120 *error = reply.arguments().at(2).toString(); 0121 } 0122 if (pid) { 0123 *pid = reply.arguments().at(3).toInt(); 0124 } 0125 return reply.arguments().at(0).toInt(); 0126 #else 0127 return ENOTSUP; 0128 #endif 0129 } 0130 0131 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0132 int KToolInvocation::startServiceByName(const QString &_name, 0133 const QString &URL, 0134 QString *error, 0135 QString *serviceName, 0136 int *pid, 0137 const QByteArray &startup_id, 0138 bool noWait) 0139 { 0140 if (!isMainThreadActive(error)) { 0141 return EINVAL; 0142 } 0143 0144 QStringList URLs; 0145 if (!URL.isEmpty()) { 0146 URLs.append(URL); 0147 } 0148 return self()->startServiceInternal("start_service_by_name", _name, URLs, error, serviceName, pid, startup_id, noWait); 0149 } 0150 #endif 0151 0152 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0153 int KToolInvocation::startServiceByName(const QString &_name, 0154 const QStringList &URLs, 0155 QString *error, 0156 QString *serviceName, 0157 int *pid, 0158 const QByteArray &startup_id, 0159 bool noWait) 0160 { 0161 if (!isMainThreadActive(error)) { 0162 return EINVAL; 0163 } 0164 0165 return self()->startServiceInternal("start_service_by_name", _name, URLs, error, serviceName, pid, startup_id, noWait); 0166 } 0167 #endif 0168 0169 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 82) 0170 int KToolInvocation::startServiceByDesktopPath(const QString &_name, 0171 const QString &URL, 0172 QString *error, 0173 QString *serviceName, 0174 int *pid, 0175 const QByteArray &startup_id, 0176 bool noWait) 0177 { 0178 if (!isMainThreadActive(error)) { 0179 return EINVAL; 0180 } 0181 0182 QStringList URLs; 0183 if (!URL.isEmpty()) { 0184 URLs.append(URL); 0185 } 0186 return self()->startServiceInternal("start_service_by_desktop_path", _name, URLs, error, serviceName, pid, startup_id, noWait); 0187 } 0188 #endif 0189 0190 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 82) 0191 int KToolInvocation::startServiceByDesktopPath(const QString &_name, 0192 const QStringList &URLs, 0193 QString *error, 0194 QString *serviceName, 0195 int *pid, 0196 const QByteArray &startup_id, 0197 bool noWait) 0198 { 0199 if (!isMainThreadActive(error)) { 0200 return EINVAL; 0201 } 0202 0203 return self()->startServiceInternal("start_service_by_desktop_path", _name, URLs, error, serviceName, pid, startup_id, noWait); 0204 } 0205 #endif 0206 0207 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 82) 0208 int KToolInvocation::startServiceByDesktopName(const QString &_name, 0209 const QString &URL, 0210 QString *error, 0211 QString *serviceName, 0212 int *pid, 0213 const QByteArray &startup_id, 0214 bool noWait) 0215 { 0216 if (!isMainThreadActive(error)) { 0217 return EINVAL; 0218 } 0219 0220 QStringList URLs; 0221 if (!URL.isEmpty()) { 0222 URLs.append(URL); 0223 } 0224 return self()->startServiceInternal("start_service_by_desktop_name", _name, URLs, error, serviceName, pid, startup_id, noWait); 0225 } 0226 #endif 0227 0228 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 82) 0229 int KToolInvocation::startServiceByDesktopName(const QString &_name, 0230 const QStringList &URLs, 0231 QString *error, 0232 QString *serviceName, 0233 int *pid, 0234 const QByteArray &startup_id, 0235 bool noWait) 0236 { 0237 if (!isMainThreadActive(error)) { 0238 return EINVAL; 0239 } 0240 0241 return self()->startServiceInternal("start_service_by_desktop_name", _name, URLs, error, serviceName, pid, startup_id, noWait); 0242 } 0243 #endif 0244 0245 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 83) 0246 int KToolInvocation::kdeinitExec(const QString &name, const QStringList &args, QString *error, int *pid, const QByteArray &startup_id) 0247 { 0248 if (!isMainThreadActive(error)) { 0249 return EINVAL; 0250 } 0251 0252 return self()->startServiceInternal("kdeinit_exec", name, args, error, nullptr, pid, startup_id, false); 0253 } 0254 #endif 0255 0256 int KToolInvocation::kdeinitExecWait(const QString &name, const QStringList &args, QString *error, int *pid, const QByteArray &startup_id) 0257 { 0258 if (!isMainThreadActive(error)) { 0259 return EINVAL; 0260 } 0261 0262 return self()->startServiceInternal("kdeinit_exec_wait", name, args, error, nullptr, pid, startup_id, false); 0263 } 0264 0265 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0266 void KToolInvocation::invokeMailer(const QString &address, const QString &subject, const QByteArray &startup_id) 0267 { 0268 if (!isMainThreadActive()) { 0269 return; 0270 } 0271 0272 invokeMailer(address, QString(), QString(), subject, QString(), QString(), QStringList(), startup_id); 0273 } 0274 #endif 0275 0276 #if KSERVICE_BUILD_DEPRECATED_SINCE(5, 0) 0277 void KToolInvocation::invokeMailer(const QUrl &mailtoURL, const QByteArray &startup_id, bool allowAttachments) 0278 { 0279 if (!isMainThreadActive()) { 0280 return; 0281 } 0282 0283 QString address = mailtoURL.path(); 0284 QString subject; 0285 QString cc; 0286 QString bcc; 0287 QString body; 0288 0289 QList<QPair<QString, QString>> queryItems = QUrlQuery(mailtoURL).queryItems(); 0290 const QChar comma = QChar::fromLatin1(','); 0291 QStringList attachURLs; 0292 for (int i = 0; i < queryItems.count(); ++i) { 0293 const QString q = queryItems.at(i).first.toLower(); 0294 const QString value = queryItems.at(i).second; 0295 if (q == QLatin1String("subject")) { 0296 subject = value; 0297 } else if (q == QLatin1String("cc")) { 0298 cc = cc.isEmpty() ? value : cc + comma + value; 0299 } else if (q == QLatin1String("bcc")) { 0300 bcc = bcc.isEmpty() ? value : bcc + comma + value; 0301 } else if (q == QLatin1String("body")) { 0302 body = value; 0303 } else if (allowAttachments && q == QLatin1String("attach")) { 0304 attachURLs.push_back(value); 0305 } else if (allowAttachments && q == QLatin1String("attachment")) { 0306 attachURLs.push_back(value); 0307 } else if (q == QLatin1String("to")) { 0308 address = address.isEmpty() ? value : address + comma + value; 0309 } 0310 } 0311 0312 invokeMailer(address, cc, bcc, subject, body, QString(), attachURLs, startup_id); 0313 } 0314 #endif 0315 0316 void KToolInvocation::ensureKdeinitRunning() 0317 { 0318 #ifdef QT_DBUS_LIB 0319 KDEInitInterface::ensureKdeinitRunning(); 0320 #endif 0321 } 0322 0323 #include "moc_ktoolinvocation.cpp"