diff --git a/src/kauthexecutejob.cpp b/src/kauthexecutejob.cpp index 0310fe0..345c8eb 100644 --- a/src/kauthexecutejob.cpp +++ b/src/kauthexecutejob.cpp @@ -1,234 +1,241 @@ /* * Copyright (C) 2009-2012 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #include "kauthexecutejob.h" #include "BackendsManager.h" #include #include #include #include "kauthdebug.h" namespace KAuth { class Q_DECL_HIDDEN ExecuteJob::Private { public: Private(ExecuteJob *parent) : q(parent) {} ExecuteJob *q; Action action; Action::ExecutionMode mode; QVariantMap data; void doExecuteAction(); void doAuthorizeAction(); void actionPerformedSlot(const QString &action, const ActionReply &reply); void progressStepSlot(const QString &action, int i); void progressStepSlot(const QString &action, const QVariantMap &data); void statusChangedSlot(const QString &action, KAuth::Action::AuthStatus status); }; static QHash s_watchers; ExecuteJob::ExecuteJob(const Action &action, Action::ExecutionMode mode, QObject *parent) : KJob(parent) , d(new Private(this)) { d->action = action; d->mode = mode; HelperProxy *helper = BackendsManager::helperProxy(); connect(helper, SIGNAL(actionPerformed(QString,KAuth::ActionReply)), this, SLOT(actionPerformedSlot(QString,KAuth::ActionReply))); connect(helper, SIGNAL(progressStep(QString,int)), this, SLOT(progressStepSlot(QString,int))); connect(helper, SIGNAL(progressStep(QString,QVariantMap)), this, SLOT(progressStepSlot(QString,QVariantMap))); connect(BackendsManager::authBackend(), SIGNAL(actionStatusChanged(QString,KAuth::Action::AuthStatus)), this, SLOT(statusChangedSlot(QString,KAuth::Action::AuthStatus))); } ExecuteJob::~ExecuteJob() { delete d; } Action ExecuteJob::action() const { return d->action; } QVariantMap ExecuteJob::data() const { return d->data; } void ExecuteJob::start() { if (!d->action.isValid()) { qCWarning(KAUTH) << "Tried to start an invalid action"; ActionReply reply(ActionReply::InvalidActionError); reply.setErrorDescription(tr("Tried to start an invalid action")); d->actionPerformedSlot(d->action.name(), reply); return; } switch (d->mode) { case Action::ExecuteMode: QTimer::singleShot(0, this, SLOT(doExecuteAction())); break; case Action::AuthorizeOnlyMode: QTimer::singleShot(0, this, SLOT(doAuthorizeAction())); break; default: { ActionReply reply(ActionReply::InvalidActionError); reply.setErrorDescription(tr("Unknown execution mode chosen")); d->actionPerformedSlot(d->action.name(), reply); } break; } } +bool ExecuteJob::kill(KillVerbosity verbosity) +{ + BackendsManager::helperProxy()->stopAction(d->action.name(), d->action.helperId()); + KJob::kill(verbosity); + return true; +} + void ExecuteJob::Private::doExecuteAction() { // If this action authorizes from the client, let's do it now if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) { if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget()); } Action::AuthStatus s = BackendsManager::authBackend()->authorizeAction(action.name()); if (s == Action::AuthorizedStatus) { if (action.hasHelper()) { BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.arguments(), action.timeout()); } else { // Done actionPerformedSlot(action.name(), ActionReply::SuccessReply()); } } else { // Abort if authorization fails switch (s) { case Action::DeniedStatus: actionPerformedSlot(action.name(), ActionReply::AuthorizationDeniedReply()); break; case Action::InvalidStatus: actionPerformedSlot(action.name(), ActionReply::InvalidActionReply()); break; case Action::UserCancelledStatus: actionPerformedSlot(action.name(), ActionReply::UserCancelledReply()); break; default: { ActionReply r(ActionReply::BackendError); r.setErrorDescription(tr("Unknown status for the authentication procedure")); actionPerformedSlot(action.name(), r); } break; } } } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) { if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget()); } if (!action.hasHelper()) { ActionReply r(ActionReply::InvalidActionReply()); r.setErrorDescription(tr("The current backend only allows helper authorization, but this action does not have a helper.")); actionPerformedSlot(action.name(), r); return; } BackendsManager::helperProxy()->executeAction(action.name(), action.helperId(), action.arguments(), action.timeout()); } else { // There's something totally wrong here ActionReply r(ActionReply::BackendError); r.setErrorDescription(tr("The backend does not specify how to authorize")); actionPerformedSlot(action.name(), r); } } void ExecuteJob::Private::doAuthorizeAction() { // Check the status first Action::AuthStatus s = action.status(); if (s == Action::AuthRequiredStatus) { // Let's check what to do if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromClientCapability) { // In this case we can actually try an authorization if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::PreAuthActionCapability) { BackendsManager::authBackend()->preAuthAction(action.name(), action.parentWidget()); } s = BackendsManager::authBackend()->authorizeAction(action.name()); } else if (BackendsManager::authBackend()->capabilities() & KAuth::AuthBackend::AuthorizeFromHelperCapability) { // In this case, just throw out success, as the auth will take place later s = Action::AuthorizedStatus; } else { // This should never, never happen ActionReply r(ActionReply::BackendError); r.setErrorDescription(tr("The backend does not specify how to authorize")); actionPerformedSlot(action.name(), r); } } // Return based on the current status if (s == Action::AuthorizedStatus) { actionPerformedSlot(action.name(), ActionReply::SuccessReply()); } else { actionPerformedSlot(action.name(), ActionReply::AuthorizationDeniedReply()); } } void ExecuteJob::Private::actionPerformedSlot(const QString &taction, const ActionReply &reply) { if (taction == action.name()) { if (reply.failed()) { q->setError(reply.errorCode()); q->setErrorText(reply.errorDescription()); } else { data = reply.data(); } q->emitResult(); } } void ExecuteJob::Private::progressStepSlot(const QString &taction, int i) { if (taction == action.name()) { q->setPercent(i); } } void ExecuteJob::Private::progressStepSlot(const QString &taction, const QVariantMap &data) { if (taction == action.name()) { emit q->newData(data); } } void ExecuteJob::Private::statusChangedSlot(const QString &taction, Action::AuthStatus status) { if (taction == action.name()) { emit q->statusChanged(status); } } } // namespace Auth #include "moc_kauthexecutejob.cpp" diff --git a/src/kauthexecutejob.h b/src/kauthexecutejob.h index 0ae728d..691c1c2 100644 --- a/src/kauthexecutejob.h +++ b/src/kauthexecutejob.h @@ -1,105 +1,118 @@ /* * Copyright (C) 2012 Dario Freddi * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef ASYNC_ACTION_H #define ASYNC_ACTION_H #include #include #include "kauthaction.h" #include "kauthactionreply.h" namespace KAuth { /** * @brief Job executing an Action * @since 5.0 */ class KAUTH_EXPORT ExecuteJob : public KJob { Q_OBJECT ExecuteJob(const KAuth::Action &action, KAuth::Action::ExecutionMode mode, QObject *parent); friend class Action; class Private; Private *const d; Q_PRIVATE_SLOT(d, void doExecuteAction()) Q_PRIVATE_SLOT(d, void doAuthorizeAction()) Q_PRIVATE_SLOT(d, void actionPerformedSlot(const QString &action, const KAuth::ActionReply &reply)) Q_PRIVATE_SLOT(d, void progressStepSlot(const QString &action, int i)) Q_PRIVATE_SLOT(d, void progressStepSlot(const QString &action, const QVariantMap &data)) Q_PRIVATE_SLOT(d, void statusChangedSlot(const QString &action, KAuth::Action::AuthStatus status)) public: /// Virtual destructor virtual ~ExecuteJob(); /** * Starts the job asynchronously. * @see KJob::result * @see newData * @see statusChanged */ void start() Q_DECL_OVERRIDE; /** * @returns the action associated with this job */ Action action() const; /** * @returns the data sent by the helper */ QVariantMap data() const; +public Q_SLOTS: + /** + * Attempts to halt the execution of the action associated with this job. + * You should listen to the finished and result signals to work out whether + * halting was successful (as long running operations can also take time + * to shut down cleanly). + * @see HelperSupport::isStopped() + * @see KJob::result + * @see KJob::finished + * @return Always returns true + */ + bool kill(KillVerbosity verbosity = Quietly); + Q_SIGNALS: /** * @brief Signal emitted by the helper to notify the action's progress * * This signal is emitted every time the helper's code calls the * HelperSupport::progressStep(QVariantMap) method. This is useful to let the * helper notify the execution status of a long action, also providing * some data, for example if you want to achieve some sort of progressive loading. * The meaning of the data passed here is totally application-dependent. * If you only need to pass some percentage, you can use the other signal that * pass an int. * * @param data The progress data from the helper */ void newData(const QVariantMap &data); /** * @brief Signal emitted when the authentication status changes * @param status the the new authentication status */ void statusChanged(KAuth::Action::AuthStatus status); private: Q_DISABLE_COPY(ExecuteJob) }; } // namespace Auth #endif diff --git a/src/kauthhelpersupport.h b/src/kauthhelpersupport.h index 2828ec2..dfcd153 100644 --- a/src/kauthhelpersupport.h +++ b/src/kauthhelpersupport.h @@ -1,105 +1,106 @@ /* * Copyright (C) 2008 Nicola Gigante * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . */ #ifndef HELPER_SUPPORT_H #define HELPER_SUPPORT_H #include #include #include #define KAUTH_HELPER_MAIN(ID, HelperClass) \ int main(int argc, char **argv) { return KAuth::HelperSupport::helperMain(argc, argv, ID, new HelperClass()); } namespace KAuth { /** * @brief Support class with some KAUTH_EXPORT methods useful to the helper's code * * This class provides the API to write the helper tool that executes your actions. * You don't create instances of HelperSupport. Instead, you use its KAUTH_EXPORT methods. * * This them you can notify the application of progress in your action's execution * and you can check if the application asked you to terminate it. * * @since 4.4 */ namespace HelperSupport { /** * @brief Send a progressStep signal to the caller application * * You can use this method to notify progress information about the * action execution. When you call this method, the ActionWatcher * object associated with the current action will emit the progressStep(int) * signal. The meaning of the integer passed here is totally application dependent, * but you'll want to use it as a sort of percentage. * If you need to be more expressive, use the other overload which takes a QVariantMap * * @param step The progress indicator */ KAUTH_EXPORT void progressStep(int step); /** * @brief Send a progressStep signal to the caller application * * You can use this method to notify progress information about the * action execution. When you call this method, the ActionWatcher * object associated with the current action will emit the progressStep(QVariantMap) * signal. The meaning of the data passed here is totally application dependent. * If you only need a simple percentage value, use the other overload which takes an int. * * @param data The progress data */ KAUTH_EXPORT void progressStep(const QVariantMap &data); /** * @brief Check if the caller asked the helper to stop the execution * * This method will return true if the helper has been asked to stop the * execution of the current action. If this happens, your helper should * return (NOT exit). The meaning of the data you return in this case is * application-dependent. * It's good practice to check it regularly if you have a long-running action * + * @see ExecuteJob::kill * @return true if the helper has been asked to stop, false otherwise */ KAUTH_EXPORT bool isStopped(); /** * @brief Method that implements the main function of the helper tool. Do not call directly * * This method is called in the proper way by the code generated by the KAUTH_HELPER_MAIN(), * which creates a main() function for the helper tool. * macro. You shouldn't call this method directly. * * @param argc The argc parameter from the main() function. * @param argv The argv parameter from the main() function. * @param id The helper ID as passed to the macro * @param responder The responder object for the helper. The macro passes a default-constructed, * heap-allocated object of the class specified as the last macro parameter */ KAUTH_EXPORT int helperMain(int argc, char **argv, const char *id, QObject *responder); } // namespace HelperSupport } // namespace Auth #endif