File indexing completed on 2024-11-10 04:40:28

0001 /*
0002     SPDX-FileCopyrightText: 2008 Volker Krause <vkrause@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "agentinstancecreatejob.h"
0008 
0009 #include "agentinstance.h"
0010 #include "agentmanager.h"
0011 #include "agentmanager_p.h"
0012 #include "controlinterface.h"
0013 #include "kjobprivatebase_p.h"
0014 #include <QDBusConnection>
0015 
0016 #include <KLocalizedString>
0017 
0018 #include <QTimer>
0019 
0020 #ifdef Q_OS_UNIX
0021 #include <signal.h>
0022 #include <sys/types.h>
0023 #endif
0024 
0025 using namespace Akonadi;
0026 
0027 static const int safetyTimeout = 10000; // ms
0028 
0029 namespace Akonadi
0030 {
0031 /**
0032  * @internal
0033  */
0034 class AgentInstanceCreateJobPrivate : public KJobPrivateBase
0035 {
0036     Q_OBJECT
0037 public:
0038     explicit AgentInstanceCreateJobPrivate(AgentInstanceCreateJob *parent)
0039         : q(parent)
0040         , safetyTimer(new QTimer(parent))
0041     {
0042         connect(AgentManager::self(), &AgentManager::instanceAdded, this, &AgentInstanceCreateJobPrivate::agentInstanceAdded);
0043         connect(safetyTimer, &QTimer::timeout, this, &AgentInstanceCreateJobPrivate::timeout);
0044     }
0045 
0046     void agentInstanceAdded(const AgentInstance &instance) const
0047     {
0048         if (agentInstance == instance && !tooLate) {
0049             safetyTimer->stop();
0050             if (doConfig) {
0051                 // return from dbus call first before doing the next one
0052                 QTimer::singleShot(0, this, &AgentInstanceCreateJobPrivate::doConfigure);
0053             } else {
0054                 q->emitResult();
0055             }
0056         }
0057     }
0058 
0059     void doConfigure()
0060     {
0061         auto agentControlIface =
0062             new org::freedesktop::Akonadi::Agent::Control(ServerManager::agentServiceName(ServerManager::Agent, agentInstance.identifier()),
0063                                                           QStringLiteral("/"),
0064                                                           QDBusConnection::sessionBus(),
0065                                                           q);
0066         if (!agentControlIface || !agentControlIface->isValid()) {
0067             delete agentControlIface;
0068 
0069             q->setError(KJob::UserDefinedError);
0070             q->setErrorText(i18n("Unable to access D-Bus interface of created agent."));
0071             q->emitResult();
0072             return;
0073         }
0074 
0075         connect(agentControlIface, &org::freedesktop::Akonadi::Agent::Control::configurationDialogAccepted, this, [agentControlIface, this]() {
0076             agentControlIface->deleteLater();
0077             q->emitResult();
0078         });
0079         connect(agentControlIface, &org::freedesktop::Akonadi::Agent::Control::configurationDialogRejected, this, [agentControlIface, this]() {
0080             agentControlIface->deleteLater();
0081             AgentManager::self()->removeInstance(agentInstance);
0082             q->emitResult();
0083         });
0084 
0085         agentInstance.configure(parentWidget);
0086     }
0087 
0088     void timeout()
0089     {
0090         tooLate = true;
0091         q->setError(KJob::UserDefinedError);
0092         q->setErrorText(i18n("Agent instance creation timed out."));
0093         q->emitResult();
0094     }
0095 
0096     void doStart() override;
0097 
0098     AgentInstanceCreateJob *const q;
0099     AgentType agentType;
0100     QString agentTypeId;
0101     AgentInstance agentInstance;
0102     QWidget *parentWidget = nullptr;
0103     QTimer *const safetyTimer;
0104     bool doConfig = false;
0105     bool tooLate = false;
0106 };
0107 
0108 } // namespace Akonadi
0109 
0110 AgentInstanceCreateJob::AgentInstanceCreateJob(const AgentType &agentType, QObject *parent)
0111     : KJob(parent)
0112     , d(new AgentInstanceCreateJobPrivate(this))
0113 {
0114     d->agentType = agentType;
0115 }
0116 
0117 AgentInstanceCreateJob::AgentInstanceCreateJob(const QString &typeId, QObject *parent)
0118     : KJob(parent)
0119     , d(new AgentInstanceCreateJobPrivate(this))
0120 {
0121     d->agentTypeId = typeId;
0122 }
0123 
0124 AgentInstanceCreateJob::~AgentInstanceCreateJob() = default;
0125 
0126 void AgentInstanceCreateJob::configure(QWidget *parent)
0127 {
0128     d->parentWidget = parent;
0129     d->doConfig = true;
0130 }
0131 
0132 AgentInstance AgentInstanceCreateJob::instance() const
0133 {
0134     return d->agentInstance;
0135 }
0136 
0137 void AgentInstanceCreateJob::start()
0138 {
0139     d->start();
0140 }
0141 
0142 void AgentInstanceCreateJobPrivate::doStart()
0143 {
0144     if (!agentType.isValid() && !agentTypeId.isEmpty()) {
0145         agentType = AgentManager::self()->type(agentTypeId);
0146     }
0147 
0148     if (!agentType.isValid()) {
0149         q->setError(KJob::UserDefinedError);
0150         q->setErrorText(i18n("Unable to obtain agent type '%1'.", agentTypeId));
0151         QTimer::singleShot(0, q, &AgentInstanceCreateJob::emitResult);
0152         return;
0153     }
0154 
0155     agentInstance = AgentManager::self()->d->createInstance(agentType);
0156     if (!agentInstance.isValid()) {
0157         q->setError(KJob::UserDefinedError);
0158         q->setErrorText(i18n("Unable to create agent instance."));
0159         QTimer::singleShot(0, q, &AgentInstanceCreateJob::emitResult);
0160     } else {
0161         int timeout = safetyTimeout;
0162 #ifdef Q_OS_UNIX
0163         // Increate the timeout when valgrinding the agent, because that slows down things a log.
0164         const QString agentValgrind = QString::fromLocal8Bit(qgetenv("AKONADI_VALGRIND"));
0165         if (!agentValgrind.isEmpty() && agentType.identifier().contains(agentValgrind)) {
0166             timeout *= 15;
0167         }
0168 #endif
0169         // change the timeout when debugging the agent, because we need time to start the debugger
0170         const QString agentDebugging = QString::fromLocal8Bit(qgetenv("AKONADI_DEBUG_WAIT"));
0171         if (!agentDebugging.isEmpty()) {
0172             // we are debugging
0173             const QString agentDebuggingTimeout = QString::fromLocal8Bit(qgetenv("AKONADI_DEBUG_TIMEOUT"));
0174             if (agentDebuggingTimeout.isEmpty()) {
0175                 // use default value of 150 seconds (the same as "valgrinding", this has to be checked)
0176                 timeout = 15 * safetyTimeout;
0177             } else {
0178                 // use own value
0179                 timeout = agentDebuggingTimeout.toInt();
0180             }
0181         }
0182         safetyTimer->start(timeout);
0183     }
0184 }
0185 
0186 #include "agentinstancecreatejob.moc"
0187 
0188 #include "moc_agentinstancecreatejob.cpp"