1 | /* |
2 | * Copyright (C) 2008 Nicola Gigante <nicola.gigante@gmail.com> |
3 | * Copyright (C) 2009 Dario Freddi <drf@kde.org> |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU Lesser General Public License as published by |
7 | * the Free Software Foundation; either version 2.1 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Lesser General Public License |
16 | * along with this program; if not, write to the |
17 | * Free Software Foundation, Inc., |
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . |
19 | */ |
20 | |
21 | #ifndef ACTION_H |
22 | #define ACTION_H |
23 | |
24 | #include <QtCore/QString> |
25 | #include <QtCore/QVariant> |
26 | #include <QtCore/QHash> |
27 | |
28 | #include <kdecore_export.h> |
29 | |
30 | #include "kauthactionreply.h" |
31 | |
32 | namespace KAuth |
33 | { |
34 | |
35 | class ActionWatcher; |
36 | |
37 | /** |
38 | * @brief Class to access, authorize and execute actions. |
39 | * |
40 | * This is the main class of the kauth API. It provides the interface to |
41 | * manipulate actions. Every action is identified by its name. Every instance |
42 | * of the Action class with the same name refers to the same action. |
43 | * |
44 | * Once you have an action object you can tell the helper to execute it |
45 | * (asking the user to authenticate if needed) with one of the execute*() methods. |
46 | * The simplest thing to do is to execute a single action synchronously |
47 | * blocking for the reply, using the execute() method. |
48 | * |
49 | * For asynchronous calls, use the executeAsync() method. It sends the request |
50 | * to the helper and returns immediately. You can optionally provide an object |
51 | * and a slot. This will be connected to the actionPerformed() signal of the |
52 | * action's ActionWatcher object. |
53 | * By calling the watcher() method, you obtain an object that emits some useful |
54 | * signals that you can receive while the action is in progress. Those signals |
55 | * are emitted also with the synchronous calls. |
56 | * To execute a bunch of actions with a single call, you can use the executeActions() |
57 | * static method. This is not the same as calling executeAsync() for each action, |
58 | * because the actions are execute with a single request to the helper. |
59 | * To use any of the execute*() methods you have to set the default helper's ID using |
60 | * the setHelperID() static method. Alternatively, you can specify the helperID using |
61 | * the overloaded version of the methods that takes it as a parameter. |
62 | * |
63 | * Each action object contains a QVariantMap object that is passed directly to the |
64 | * helper when the action is executed. You can access this map using the arguments() |
65 | * method. You can insert into it any kind of custom data you need to pass to the helper. |
66 | * |
67 | * @since 4.4 |
68 | */ |
69 | class KDECORE_EXPORT Action |
70 | { |
71 | class Private; |
72 | Private * const d; |
73 | |
74 | public: |
75 | /** |
76 | * The three values returned by authorization methods |
77 | */ |
78 | enum AuthStatus { |
79 | Denied, ///< The authorization has been denied by the authorization backend |
80 | Error, ///< An error occurred |
81 | Invalid, ///< An invalid action cannot be authorized |
82 | Authorized, ///< The authorization has been granted by the authorization backend |
83 | AuthRequired, ///< The user could obtain the authorization after authentication |
84 | UserCancelled ///< The user pressed Cancel the authentication dialog. Currently used only on the mac |
85 | }; |
86 | |
87 | /** |
88 | * @brief Default constructor |
89 | * |
90 | * This constructor sets the name to the empty string. |
91 | * Such an action is invalid and cannot be authorized nor executed, so |
92 | * you need to call setName() before you can use the object. |
93 | */ |
94 | Action(); |
95 | |
96 | /** Copy constructor */ |
97 | Action(const Action &action); |
98 | |
99 | /** |
100 | * This creates a new action object with this name |
101 | * @param name The name of the new action |
102 | */ |
103 | Action(const QString &name); |
104 | |
105 | /** |
106 | * This creates a new action object with this name and details |
107 | * @param name The name of the new action |
108 | * @param details The details of the action |
109 | * |
110 | * @see setDetails |
111 | */ |
112 | Action(const QString &name, const QString &details); |
113 | |
114 | /// Virtual destructor |
115 | ~Action(); |
116 | |
117 | /// Assignment operator |
118 | Action &operator=(const Action &action); |
119 | |
120 | /** |
121 | * @brief Comparison operator |
122 | * |
123 | * This comparison operator compares the <b>names</b> of two |
124 | * actions and returns whether they are the same. It does not |
125 | * care about the arguments stored in the actions. However, |
126 | * if two actions are invalid they'll match as equal, even |
127 | * if the invalid names are different. |
128 | * |
129 | * @returns true if the two actions are the same or both invalid |
130 | */ |
131 | bool operator==(const Action &action) const; |
132 | |
133 | /** |
134 | * @brief Negated comparison operator |
135 | * |
136 | * Returns the negation of operator== |
137 | * |
138 | * @returns true if the two actions are different and not both invalid |
139 | */ |
140 | bool operator!=(const Action &action) const; |
141 | |
142 | /** |
143 | * @brief Gets the action's name. |
144 | * |
145 | * This is the unique attribute that identifies |
146 | * an action object. Two action objects with the same |
147 | * name always refer to the same action. |
148 | * |
149 | * @return The action name |
150 | */ |
151 | QString name() const; |
152 | |
153 | /** |
154 | * @brief Sets the action's name. |
155 | * |
156 | * It's not common to change the action name |
157 | * after its creation. Usually you set the name |
158 | * with the constructor (and you have to, because |
159 | * there's no default constructor) |
160 | */ |
161 | void setName(const QString &name); |
162 | |
163 | /** |
164 | * @brief Sets the action's details |
165 | * |
166 | * You can use this function to provide the user more details |
167 | * (if the backend supports it) on the action being authorized in |
168 | * the authorization dialog |
169 | */ |
170 | void setDetails(const QString &details); |
171 | |
172 | /** |
173 | * @brief Gets the action's details |
174 | * |
175 | * The details that will be shown in the authorization dialog, if the |
176 | * backend supports it. |
177 | * |
178 | * @return The action's details |
179 | */ |
180 | QString details() const; |
181 | |
182 | /** |
183 | * @brief Returns if the object represents a valid action |
184 | * |
185 | * Action names have to respect a simple syntax. |
186 | * They have to be all in lowercase characters, separated |
187 | * by dots. Dots can't appear at the beginning and at the end of |
188 | * the name. |
189 | * |
190 | * In other words, the action name has to match this perl-like |
191 | * regular expression: |
192 | * @verbatim |
193 | * /^[a-z]+(\.[a-z]+)*$/ |
194 | * @endverbatim |
195 | * |
196 | * This method returns false if the action name doesn't match the |
197 | * valid syntax. |
198 | * |
199 | * If the backend supports it, this method also checks if the action is |
200 | * valid and recognized by the backend itself. |
201 | * |
202 | * Invalid actions cannot be authorized nor executed. |
203 | * The empty string is not a valid action name, so the default |
204 | * constructor returns an invalid action. |
205 | */ |
206 | bool isValid() const; |
207 | |
208 | /** |
209 | * @brief Gets the default helper ID used for actions execution |
210 | * |
211 | * The helper ID is the string that uniquely identifies the helper in |
212 | * the system. It is the string passed to the KDE4_AUTH_HELPER() macro |
213 | * in the helper source. Because one could have different helpers, |
214 | * you need to specify an helper ID for each execution, or set a default |
215 | * ID by calling setHelperID(). This method returns the current default |
216 | * value. |
217 | * |
218 | * @return The default helper ID. |
219 | */ |
220 | QString helperID() const; |
221 | |
222 | /** |
223 | * @brief Sets the default helper ID used for actions execution |
224 | * |
225 | * This method sets the helper ID which contains the body of this action. |
226 | * If the string is non-empty, the corresponding helper will be fired and |
227 | * the action executed inside the helper. Otherwise, the action will be just |
228 | * authorized. |
229 | * |
230 | * @note To unset a previously set helper, just pass an empty string |
231 | * |
232 | * @param id The default helper ID. |
233 | * |
234 | * @see hasHelper |
235 | * @see helperID |
236 | */ |
237 | void setHelperID(const QString &id); |
238 | |
239 | /** |
240 | * @brief Checks if the action has an helper |
241 | * |
242 | * This function can be used to check if an helper will be called upon the |
243 | * execution of an action. Such an helper can be set through setHelperID. If |
244 | * this function returns false, upon execution the action will be just authorized. |
245 | * |
246 | * @since 4.5 |
247 | * |
248 | * @return Whether the action has an helper or not |
249 | * |
250 | * @see setHelperID |
251 | */ |
252 | bool hasHelper() const; |
253 | |
254 | /** |
255 | * @brief Gets the ActionWatcher object for this action |
256 | * |
257 | * ActionWatcher objects are used to get notifications about the action |
258 | * execution status. Every action watcher is tied to an action and |
259 | * every action has a watcher. This means that if you call this method |
260 | * on two different Action objects with the same name, you'll get the |
261 | * same watcher object. |
262 | * |
263 | * @return The action watcher for this action |
264 | */ |
265 | ActionWatcher *watcher(); |
266 | |
267 | /** |
268 | * @brief Sets the map object used to pass arguments to the helper. |
269 | * |
270 | * This method sets the variant map that the application |
271 | * can use to pass arbitrary data to the helper when executing the action. |
272 | * |
273 | * @param arguments The new arguments map |
274 | */ |
275 | void setArguments(const QVariantMap &arguments); |
276 | |
277 | /** |
278 | * @brief Returns map object used to pass arguments to the helper. |
279 | * |
280 | * This method returns the variant map that the application |
281 | * can use to pass arbitrary data to the helper when executing the action. |
282 | * |
283 | * @return The arguments map that will be passed to the helper. |
284 | */ |
285 | QVariantMap arguments() const; |
286 | |
287 | /** |
288 | * @brief Convenience method to add an argument. |
289 | * |
290 | * This method adds the pair @c key/value to the QVariantMap used to |
291 | * send custom data to the helper. |
292 | * |
293 | * Use this method if you don't want to create a new QVariantMap only to |
294 | * add a new entry. |
295 | * |
296 | * @param key The new entry's key |
297 | * @param value The value of the new entry |
298 | */ |
299 | void addArgument(const QString &key, const QVariant &value); |
300 | |
301 | /** |
302 | * @brief Acquires authorization for an action without excuting it. |
303 | * |
304 | * @note Please use this method if you really know what you are doing. If you are |
305 | * implementing a GUI, you probably should look into earlyAuthorize instead. |
306 | * |
307 | * @note Please remember that calling this method is not required for a successful action |
308 | * execution: it is safe and advised to call execute() only, without a previous call |
309 | * to authorize or earlyAuthorize. |
310 | * |
311 | * This method acquires the authorization rights for the action, asking |
312 | * the user to authenticate if needed. It tries very hard to resolve a possible |
313 | * challenge (AuthRequired); for this reason, it is meant only for advanced usages. |
314 | * If you are unsure, always use earlyAuthorize or execute the action directly. |
315 | * |
316 | * @return The result of the authorization process |
317 | * |
318 | * @see earlyAuthorize |
319 | */ |
320 | AuthStatus authorize() const; |
321 | |
322 | /** |
323 | * @brief Tries to resolve authorization status in the best possible way without executing the action |
324 | * |
325 | * This method checks for the status of the action, and tries to acquire authorization |
326 | * (if needed) if the backend being used supports client-side authorization. |
327 | * |
328 | * This means this method is not reliable - its purpose is to provide user interfaces with |
329 | * an efficient means to acquire authorization as early as possible, without interrupting |
330 | * the user's workflow. If the backend's authentication phase happens in the helper and the |
331 | * action requires authentication, \c Authorized will be returned. |
332 | * |
333 | * The main difference with authorize is that this method does not try to acquire authorization |
334 | * if the backend's authentication phase happens in the helper: using authorize in such a case |
335 | * might lead to ask the user its password twice, as the helper might time out, or in the case |
336 | * of a one shot authorization, the scope of the authorization would end with the authorization |
337 | * check itself. For this reason, you should @b always use this method instead of authorize, which |
338 | * is meant only for very advanced usages. |
339 | * |
340 | * This method is always safe to be called and used before an execution, even if not needed. |
341 | * |
342 | * @since 4.5 |
343 | * |
344 | * @return The result of the early authorization process, with the caveats described above. |
345 | */ |
346 | AuthStatus earlyAuthorize() const; |
347 | |
348 | /** |
349 | * @brief Gets information about the authorization status of an action |
350 | * |
351 | * This methods query the authorization backend to know if the user can try |
352 | * to acquire the authorization for this action. If the result is Action::AuthRequired, |
353 | * the user can try to acquire the authorization by authenticating. |
354 | * |
355 | * It should not be needed to call this method directly, because the execution methods |
356 | * already take care of all the authorization stuff. |
357 | * |
358 | * @return @c Action::Denied if the user doesn't have the authorization to execute the action, |
359 | * @c Action::Authorized if the action can be executed, |
360 | * @c Action::AuthRequired if the user could acquire the authorization after authentication, |
361 | * @c Action::UserCancelled if the user cancels the authentication dialog. Not currently supported by the Polkit backend |
362 | */ |
363 | AuthStatus status() const; |
364 | |
365 | /** |
366 | * @brief Synchronously executes the action |
367 | * |
368 | * This is the simpler of all the action execution methods. It sends an execution request to the |
369 | * caller, and returns the reply directly to the caller. The ActionReply object will contain the |
370 | * custom data coming from the helper. |
371 | * |
372 | * The method blocks the execution, and will |
373 | * return only when the action has been completed (or failed). Take note, however, that with the D-Bus |
374 | * helper proxy (currently the only one implemented on all the supported platforms), the request is |
375 | * sent using the QDBus::BlockWithGui flag. |
376 | * |
377 | * This means the method will enter a local eventloop to wait |
378 | * for the reply. This allows the application GUI to stay responsive, but you have to be prepared to |
379 | * receive other events in the meantime. |
380 | * |
381 | * All the signals from the ActionWatcher class are emitted also with this method (although they're more |
382 | * useful with the asynchronous calls) |
383 | * |
384 | * The method checks for authorization before to execute the action. If the user is not authorized, the |
385 | * return value will be ActionReply::AuthorizationDeniedReply. |
386 | * If the user cancels the authentication, the return value should be ActionReply::UserCancelledReply. |
387 | * Due to policykit limitations, this currently only with the Mac OS X backend. |
388 | * |
389 | * If the helper is busy executing another action (or action group) the reply will be ActionReply::HelperBusyReply |
390 | * |
391 | * If the request cannot be sent for bus errors, the method returns ActionReply::DBusErrorReply. |
392 | * |
393 | * @return The reply from the helper, or an error reply if something's wrong. |
394 | */ |
395 | ActionReply execute() const; |
396 | |
397 | /** |
398 | * @brief Synchronously executes the action with a specific helperID |
399 | * |
400 | * This method does the exact same thing as execute(), but it takes a specific helperID, useful |
401 | * if you don't want to use the default one without changing it with setHelperID() |
402 | * |
403 | * @param helperID The helper ID to use for the execution of this action |
404 | * @return The reply from the helper, or an error if something's wrong. |
405 | */ |
406 | ActionReply execute(const QString &helperID) const; |
407 | |
408 | void setExecutesAsync(bool async); |
409 | bool executesAsync() const; |
410 | |
411 | /** |
412 | * @brief Asynchronously executes a group of actions with a single request |
413 | * |
414 | * This method executes each action in the list. It checks for authorization of each action, and put the |
415 | * denied actions, if any, in the list pointed by the deniedActions parameter, if not NULL. |
416 | * |
417 | * Please note that with the D-Bus helper proxy (currently the only one implemented), the execution of a group |
418 | * of actions is very different from executing in sequence each action using, for example, executeAsync(). |
419 | * Currently, the helper can execute only one request at the time. For this reason, if you have to call |
420 | * different actions in sequence, you can't call executeAsync() like this: |
421 | * @code |
422 | * action1.executeAsync(); |
423 | * action2.executeAsync(); |
424 | * @endcode |
425 | * because the second call will almost certainly return ActionReply::HelperBusy. You would have to execute the second |
426 | * action in the slot connected to the first action's actionPerformed() signal. This is not so good. This method |
427 | * allows the application to send a request with a list of actions. With this method, the code above becomes: |
428 | * @code |
429 | * QList<Action> list; |
430 | * list << action1 << action2; |
431 | * Action::executeActions(list); |
432 | * @endcode |
433 | * The return value will be false if communication errors occur. It will also be false if <b>all</b> the actions |
434 | * in the list are denied. |
435 | * |
436 | * @param actions The list of actions to execute |
437 | * @param deniedActions A pointer to a list to fill with the denied actions. Pass NULL if you don't need them. |
438 | * @param helperId The helper ID to execute the actions on. |
439 | */ |
440 | static bool executeActions(const QList<Action> &actions, QList<Action> *deniedActions, const QString &helperId); |
441 | |
442 | /** |
443 | * Convenience overload. This overload lets you specify, in addition, a QWidget which will be used as the |
444 | * authentication dialog's parent. |
445 | * |
446 | * @since 4.6 |
447 | * |
448 | * @see executeActions |
449 | * @see setParentWidget |
450 | */ |
451 | static bool executeActions(const QList<Action> &actions, QList<Action> *deniedActions, const QString &helperId, |
452 | QWidget *parent); |
453 | |
454 | /** |
455 | * @brief Ask the helper to stop executing an action |
456 | * |
457 | * This method sends a request to the helper asking to stop the execution of an action. It is only |
458 | * useful for long-running actions, because short and fast actions won't obbey to this request most of the times. |
459 | * Calling this method will make the HelperSupport::isStopped() method to return true the next time it's called. |
460 | * |
461 | * It's the helper's responsibility to regularly call it and exit if requested |
462 | * The actionPerformed() signal is emitted normally because, actually, the helper exists regularly. The return data |
463 | * in this case is application-dependent. |
464 | */ |
465 | void stop(); |
466 | |
467 | /** |
468 | * @brief Ask the helper to stop executing an action, using a specific helper ID |
469 | * |
470 | * This method works exactly as the stop() method, but it lets you specify an helper ID different from the |
471 | * default one. |
472 | * |
473 | * To stop an action you need to send the stop request to the helper that is executing that action. This of course means you have to |
474 | * use the same helperID used for the execution call (either passed as a parameter or set as default with setHelperID() ) |
475 | */ |
476 | void stop(const QString &helperID); |
477 | |
478 | /** |
479 | * @brief Sets a parent widget for the authentication dialog |
480 | * |
481 | * This function is used for explicitly setting a parent window for an eventual authentication dialog required when |
482 | * authorization is triggered. Some backends, in fact, (like polkit-1) need to have a parent explicitly set for displaying |
483 | * the dialog correctly. |
484 | * |
485 | * @note If you are using KAuth through one of KDE's GUI components (KPushButton, KCModule...) you do not need and should not |
486 | * call this function, as it is already done by the component itself. |
487 | * |
488 | * @since 4.6 |
489 | * |
490 | * @param parent A QWidget which will be used as the dialog's parent |
491 | */ |
492 | void setParentWidget(QWidget *parent); |
493 | |
494 | /** |
495 | * @brief Returns the parent widget for the authentication dialog for this action |
496 | * |
497 | * @since 4.6 |
498 | * |
499 | * @returns A QWidget which will is being used as the dialog's parent |
500 | */ |
501 | QWidget *parentWidget() const; |
502 | }; |
503 | |
504 | } // namespace Auth |
505 | |
506 | #endif |
507 | |