Improvde #include order consistency
[glib.git] / gio / gtlsinteraction.c
blob75d4bab47162e4c1660efff580426508cf6e9008
1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2011 Collabora, Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library 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 GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Stef Walter <stefw@collabora.co.uk>
23 #include "config.h"
25 #include <string.h>
27 #include "gtlsinteraction.h"
28 #include "gtlspassword.h"
29 #include "gasyncresult.h"
30 #include "gcancellable.h"
31 #include "gtask.h"
32 #include "gioenumtypes.h"
33 #include "glibintl.h"
36 /**
37 * SECTION:gtlsinteraction
38 * @short_description: Interaction with the user during TLS operations.
39 * @include: gio/gio.h
41 * #GTlsInteraction provides a mechanism for the TLS connection and database
42 * code to interact with the user. It can be used to ask the user for passwords.
44 * To use a #GTlsInteraction with a TLS connection use
45 * g_tls_connection_set_interaction().
47 * Callers should instantiate a derived class that implements the various
48 * interaction methods to show the required dialogs.
50 * Callers should use the 'invoke' functions like
51 * g_tls_interaction_invoke_ask_password() to run interaction methods. These
52 * functions make sure that the interaction is invoked in the main loop
53 * and not in the current thread, if the current thread is not running the
54 * main loop.
56 * Derived classes can choose to implement whichever interactions methods they'd
57 * like to support by overriding those virtual methods in their class
58 * initialization function. Any interactions not implemented will return
59 * %G_TLS_INTERACTION_UNHANDLED. If a derived class implements an async method,
60 * it must also implement the corresponding finish method.
63 /**
64 * GTlsInteraction:
66 * An object representing interaction that the TLS connection and database
67 * might have with the user.
69 * Since: 2.30
72 /**
73 * GTlsInteractionClass:
74 * @ask_password: ask for a password synchronously. If the implementation
75 * returns %G_TLS_INTERACTION_HANDLED, then the password argument should
76 * have been filled in by using g_tls_password_set_value() or a similar
77 * function.
78 * @ask_password_async: ask for a password asynchronously.
79 * @ask_password_finish: complete operation to ask for a password asynchronously.
80 * If the implementation returns %G_TLS_INTERACTION_HANDLED, then the
81 * password argument of the async method should have been filled in by using
82 * g_tls_password_set_value() or a similar function.
84 * The class for #GTlsInteraction. Derived classes implement the various
85 * virtual interaction methods to handle TLS interactions.
87 * Derived classes can choose to implement whichever interactions methods they'd
88 * like to support by overriding those virtual methods in their class
89 * initialization function. If a derived class implements an async method,
90 * it must also implement the corresponding finish method.
92 * The synchronous interaction methods should implement to display modal dialogs,
93 * and the asynchronous methods to display modeless dialogs.
95 * If the user cancels an interaction, then the result should be
96 * %G_TLS_INTERACTION_FAILED and the error should be set with a domain of
97 * %G_IO_ERROR and code of %G_IO_ERROR_CANCELLED.
99 * Since: 2.30
102 struct _GTlsInteractionPrivate {
103 GMainContext *context;
106 G_DEFINE_TYPE (GTlsInteraction, g_tls_interaction, G_TYPE_OBJECT);
108 typedef struct {
109 GMutex mutex;
111 /* Input arguments */
112 GTlsInteraction *interaction;
113 GObject *argument;
114 GCancellable *cancellable;
116 /* Used when we're invoking async interactions */
117 GAsyncReadyCallback callback;
118 gpointer user_data;
120 /* Used when we expect results */
121 GTlsInteractionResult result;
122 GError *error;
123 gboolean complete;
124 GCond cond;
125 } InvokeClosure;
127 static void
128 invoke_closure_free (gpointer data)
130 InvokeClosure *closure = data;
131 g_assert (closure);
132 g_object_unref (closure->interaction);
133 g_clear_object (&closure->argument);
134 g_clear_object (&closure->cancellable);
135 g_cond_clear (&closure->cond);
136 g_mutex_clear (&closure->mutex);
137 g_clear_error (&closure->error);
139 /* Insurance that we've actually used these before freeing */
140 g_assert (closure->callback == NULL);
141 g_assert (closure->user_data == NULL);
143 g_free (closure);
146 static InvokeClosure *
147 invoke_closure_new (GTlsInteraction *interaction,
148 GObject *argument,
149 GCancellable *cancellable)
151 InvokeClosure *closure = g_new0 (InvokeClosure, 1);
152 closure->interaction = g_object_ref (interaction);
153 closure->argument = argument ? g_object_ref (argument) : NULL;
154 closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
155 g_mutex_init (&closure->mutex);
156 g_cond_init (&closure->cond);
157 closure->result = G_TLS_INTERACTION_UNHANDLED;
158 return closure;
161 static GTlsInteractionResult
162 invoke_closure_wait_and_free (InvokeClosure *closure,
163 GError **error)
165 GTlsInteractionResult result;
167 g_mutex_lock (&closure->mutex);
169 while (!closure->complete)
170 g_cond_wait (&closure->cond, &closure->mutex);
172 g_mutex_unlock (&closure->mutex);
174 if (closure->error)
176 g_propagate_error (error, closure->error);
177 closure->error = NULL;
179 result = closure->result;
181 invoke_closure_free (closure);
182 return result;
185 static void
186 g_tls_interaction_init (GTlsInteraction *interaction)
188 interaction->priv = G_TYPE_INSTANCE_GET_PRIVATE (interaction, G_TYPE_TLS_INTERACTION,
189 GTlsInteractionPrivate);
190 interaction->priv->context = g_main_context_ref_thread_default ();
193 static void
194 g_tls_interaction_finalize (GObject *object)
196 GTlsInteraction *interaction = G_TLS_INTERACTION (object);
198 g_main_context_unref (interaction->priv->context);
200 G_OBJECT_CLASS (g_tls_interaction_parent_class)->finalize (object);
203 static void
204 g_tls_interaction_class_init (GTlsInteractionClass *klass)
206 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
208 gobject_class->finalize = g_tls_interaction_finalize;
210 g_type_class_add_private (klass, sizeof (GTlsInteractionPrivate));
213 static gboolean
214 on_invoke_ask_password_sync (gpointer user_data)
216 InvokeClosure *closure = user_data;
217 GTlsInteractionClass *klass;
219 g_mutex_lock (&closure->mutex);
221 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
222 g_assert (klass->ask_password);
224 closure->result = klass->ask_password (closure->interaction,
225 G_TLS_PASSWORD (closure->argument),
226 closure->cancellable,
227 &closure->error);
229 closure->complete = TRUE;
230 g_cond_signal (&closure->cond);
231 g_mutex_unlock (&closure->mutex);
233 return FALSE; /* don't call again */
236 static void
237 on_async_as_sync_complete (GObject *source,
238 GAsyncResult *result,
239 gpointer user_data)
241 InvokeClosure *closure = user_data;
242 GTlsInteractionClass *klass;
244 g_mutex_lock (&closure->mutex);
246 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
247 g_assert (klass->ask_password_finish);
249 closure->result = klass->ask_password_finish (closure->interaction,
250 result,
251 &closure->error);
253 closure->complete = TRUE;
254 g_cond_signal (&closure->cond);
255 g_mutex_unlock (&closure->mutex);
258 static gboolean
259 on_invoke_ask_password_async_as_sync (gpointer user_data)
261 InvokeClosure *closure = user_data;
262 GTlsInteractionClass *klass;
264 g_mutex_lock (&closure->mutex);
266 klass = G_TLS_INTERACTION_GET_CLASS (closure->interaction);
267 g_assert (klass->ask_password_async);
269 klass->ask_password_async (closure->interaction,
270 G_TLS_PASSWORD (closure->argument),
271 closure->cancellable,
272 on_async_as_sync_complete,
273 closure);
275 /* Note that we've used these */
276 closure->callback = NULL;
277 closure->user_data = NULL;
279 g_mutex_unlock (&closure->mutex);
281 return FALSE; /* don't call again */
285 * g_tls_interaction_invoke_ask_password:
286 * @interaction: a #GTlsInteraction object
287 * @password: a #GTlsPassword object
288 * @cancellable: an optional #GCancellable cancellation object
289 * @error: an optional location to place an error on failure
291 * Invoke the interaction to ask the user for a password. It invokes this
292 * interaction in the main loop, specifically the #GMainContext returned by
293 * g_main_context_get_thread_default() when the interaction is created. This
294 * is called by called by #GTlsConnection or #GTlsDatabase to ask the user
295 * for a password.
297 * Derived subclasses usually implement a password prompt, although they may
298 * also choose to provide a password from elsewhere. The @password value will
299 * be filled in and then @callback will be called. Alternatively the user may
300 * abort this password request, which will usually abort the TLS connection.
302 * The implementation can either be a synchronous (eg: modal dialog) or an
303 * asynchronous one (eg: modeless dialog). This function will take care of
304 * calling which ever one correctly.
306 * If the interaction is cancelled by the cancellation object, or by the
307 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
308 * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
309 * not support immediate cancellation.
311 * Returns: The status of the ask password interaction.
313 * Since: 2.30
315 GTlsInteractionResult
316 g_tls_interaction_invoke_ask_password (GTlsInteraction *interaction,
317 GTlsPassword *password,
318 GCancellable *cancellable,
319 GError **error)
321 GTlsInteractionResult result;
322 InvokeClosure *closure;
323 GTlsInteractionClass *klass;
324 gboolean complete;
326 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
327 g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED);
328 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
330 closure = invoke_closure_new (interaction, G_OBJECT (password), cancellable);
332 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
333 if (klass->ask_password)
335 g_main_context_invoke (interaction->priv->context,
336 on_invoke_ask_password_sync, closure);
337 result = invoke_closure_wait_and_free (closure, error);
339 else if (klass->ask_password_async)
341 g_return_val_if_fail (klass->ask_password_finish, G_TLS_INTERACTION_UNHANDLED);
342 g_main_context_invoke (interaction->priv->context,
343 on_invoke_ask_password_async_as_sync, closure);
346 * Handle the case where we've been called from within the main context
347 * or in the case where the main context is not running. This approximates
348 * the behavior of a modal dialog.
350 if (g_main_context_acquire (interaction->priv->context))
352 for (;;)
354 g_mutex_lock (&closure->mutex);
355 complete = closure->complete;
356 g_mutex_unlock (&closure->mutex);
357 if (complete)
358 break;
359 g_main_context_iteration (interaction->priv->context, TRUE);
362 g_main_context_release (interaction->priv->context);
364 if (closure->error)
366 g_propagate_error (error, closure->error);
367 closure->error = NULL;
370 result = closure->result;
371 invoke_closure_free (closure);
375 * Handle the case where we're in a different thread than the main
376 * context and a main loop is running.
378 else
380 result = invoke_closure_wait_and_free (closure, error);
383 else
385 result = G_TLS_INTERACTION_UNHANDLED;
386 invoke_closure_free (closure);
389 return result;
394 * g_tls_interaction_ask_password:
395 * @interaction: a #GTlsInteraction object
396 * @password: a #GTlsPassword object
397 * @cancellable: an optional #GCancellable cancellation object
398 * @error: an optional location to place an error on failure
400 * Run synchronous interaction to ask the user for a password. In general,
401 * g_tls_interaction_invoke_ask_password() should be used instead of this
402 * function.
404 * Derived subclasses usually implement a password prompt, although they may
405 * also choose to provide a password from elsewhere. The @password value will
406 * be filled in and then @callback will be called. Alternatively the user may
407 * abort this password request, which will usually abort the TLS connection.
409 * If the interaction is cancelled by the cancellation object, or by the
410 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
411 * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
412 * not support immediate cancellation.
414 * Returns: The status of the ask password interaction.
416 * Since: 2.30
418 GTlsInteractionResult
419 g_tls_interaction_ask_password (GTlsInteraction *interaction,
420 GTlsPassword *password,
421 GCancellable *cancellable,
422 GError **error)
424 GTlsInteractionClass *klass;
426 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
427 g_return_val_if_fail (G_IS_TLS_PASSWORD (password), G_TLS_INTERACTION_UNHANDLED);
428 g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), G_TLS_INTERACTION_UNHANDLED);
430 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
431 if (klass->ask_password)
432 return (klass->ask_password) (interaction, password, cancellable, error);
433 else
434 return G_TLS_INTERACTION_UNHANDLED;
438 * g_tls_interaction_ask_password_async:
439 * @interaction: a #GTlsInteraction object
440 * @password: a #GTlsPassword object
441 * @cancellable: an optional #GCancellable cancellation object
442 * @callback: (allow-none): will be called when the interaction completes
443 * @user_data: (allow-none): data to pass to the @callback
445 * Run asynchronous interaction to ask the user for a password. In general,
446 * g_tls_interaction_invoke_ask_password() should be used instead of this
447 * function.
449 * Derived subclasses usually implement a password prompt, although they may
450 * also choose to provide a password from elsewhere. The @password value will
451 * be filled in and then @callback will be called. Alternatively the user may
452 * abort this password request, which will usually abort the TLS connection.
454 * If the interaction is cancelled by the cancellation object, or by the
455 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
456 * contains a %G_IO_ERROR_CANCELLED error code. Certain implementations may
457 * not support immediate cancellation.
459 * Certain implementations may not support immediate cancellation.
461 * Since: 2.30
463 void
464 g_tls_interaction_ask_password_async (GTlsInteraction *interaction,
465 GTlsPassword *password,
466 GCancellable *cancellable,
467 GAsyncReadyCallback callback,
468 gpointer user_data)
470 GTlsInteractionClass *klass;
471 GTask *task;
473 g_return_if_fail (G_IS_TLS_INTERACTION (interaction));
474 g_return_if_fail (G_IS_TLS_PASSWORD (password));
475 g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
477 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
478 if (klass->ask_password_async)
480 g_return_if_fail (klass->ask_password_finish);
481 (klass->ask_password_async) (interaction, password, cancellable,
482 callback, user_data);
484 else
486 task = g_task_new (interaction, cancellable, callback, user_data);
487 g_task_set_source_tag (task, g_tls_interaction_ask_password_async);
488 g_task_return_int (task, G_TLS_INTERACTION_UNHANDLED);
489 g_object_unref (task);
494 * g_tls_interaction_ask_password_finish:
495 * @interaction: a #GTlsInteraction object
496 * @result: the result passed to the callback
497 * @error: an optional location to place an error on failure
499 * Complete an ask password user interaction request. This should be once
500 * the g_tls_interaction_ask_password_async() completion callback is called.
502 * If %G_TLS_INTERACTION_HANDLED is returned, then the #GTlsPassword passed
503 * to g_tls_interaction_ask_password() will have its password filled in.
505 * If the interaction is cancelled by the cancellation object, or by the
506 * user then %G_TLS_INTERACTION_FAILED will be returned with an error that
507 * contains a %G_IO_ERROR_CANCELLED error code.
509 * Returns: The status of the ask password interaction.
511 * Since: 2.30
513 GTlsInteractionResult
514 g_tls_interaction_ask_password_finish (GTlsInteraction *interaction,
515 GAsyncResult *result,
516 GError **error)
518 GTlsInteractionClass *klass;
520 g_return_val_if_fail (G_IS_TLS_INTERACTION (interaction), G_TLS_INTERACTION_UNHANDLED);
521 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), G_TLS_INTERACTION_UNHANDLED);
523 klass = G_TLS_INTERACTION_GET_CLASS (interaction);
524 if (klass->ask_password_finish)
526 g_return_val_if_fail (klass->ask_password_async != NULL, G_TLS_INTERACTION_UNHANDLED);
528 return (klass->ask_password_finish) (interaction, result, error);
530 else
532 g_return_val_if_fail (g_async_result_is_tagged (result, g_tls_interaction_ask_password_async), G_TLS_INTERACTION_UNHANDLED);
534 return g_task_propagate_int (G_TASK (result), error);