~ubuntu-branches/ubuntu/trusty/gcr/trusty-proposed

« back to all changes in this revision

Viewing changes to gck/gck-enumerator.c

  • Committer: Package Import Robot
  • Author(s): Jordi Mallach
  • Date: 2012-05-03 10:18:39 UTC
  • Revision ID: package-import@ubuntu.com-20120503101839-wuvloldm7gmdsnij
Tags: upstream-3.4.1
ImportĀ upstreamĀ versionĀ 3.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
 
2
/* gck-enumerator.c - the GObject PKCS#11 wrapper library
 
3
 
 
4
   Copyright (C) 2010, Stefan Walter
 
5
 
 
6
   The Gnome Keyring Library is free software; you can redistribute it and/or
 
7
   modify it under the terms of the GNU Library General Public License as
 
8
   published by the Free Software Foundation; either version 2 of the
 
9
   License, or (at your option) any later version.
 
10
 
 
11
   The Gnome Keyring Library is distributed in the hope that it will be useful,
 
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
14
   Library General Public License for more details.
 
15
 
 
16
   You should have received a copy of the GNU Library General Public
 
17
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
 
18
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
19
   Boston, MA 02111-1307, USA.
 
20
 
 
21
   Author: Stef Walter <nielsen@memberwebs.com>
 
22
*/
 
23
 
 
24
#include "config.h"
 
25
 
 
26
#include "gck.h"
 
27
#define DEBUG_FLAG GCK_DEBUG_ENUMERATOR
 
28
#include "gck-debug.h"
 
29
#include "gck-private.h"
 
30
 
 
31
#include <string.h>
 
32
 
 
33
/**
 
34
 * SECTION:gck-enumerator
 
35
 * @title: GckEnumerator
 
36
 * @short_description: Enumerates through PKCS\#11 objects.
 
37
 *
 
38
 * A GckEnumerator can be used to enumerate through PKCS\#11 objects. It will
 
39
 * automatically create sessions as necessary.
 
40
 *
 
41
 * Use gck_modules_enumerate_objects() or gck_modules_enumerate_uri() to create
 
42
 * an enumerator. To get the objects use gck_enumerator_next() or
 
43
 * gck_enumerator_next_async() functions.
 
44
 */
 
45
 
 
46
enum {
 
47
        PROP_0,
 
48
        PROP_INTERACTION,
 
49
        PROP_OBJECT_TYPE,
 
50
        PROP_CHAINED
 
51
};
 
52
 
 
53
/**
 
54
 * GckEnumerator:
 
55
 *
 
56
 * An object that allows enumerating of objects across modules, tokens.
 
57
 */
 
58
 
 
59
typedef struct _GckEnumeratorResult {
 
60
        gulong handle;
 
61
        GckSession *session;
 
62
        GckAttributes *attrs;
 
63
} GckEnumeratorResult;
 
64
 
 
65
typedef struct _GckEnumeratorState GckEnumeratorState;
 
66
 
 
67
typedef gpointer (*GckEnumeratorFunc)     (GckEnumeratorState *args,
 
68
                                           gboolean forward);
 
69
 
 
70
struct _GckEnumeratorState {
 
71
        gpointer enumerator;
 
72
        GckEnumeratorState *chained;
 
73
 
 
74
        /* For the current call */
 
75
        gint want_objects;
 
76
 
 
77
        /* The state we're currently in */
 
78
        GckEnumeratorFunc handler;
 
79
 
 
80
        /* Input to enumerator */
 
81
        GList *modules;
 
82
        GckUriData *match;
 
83
        GckSessionOptions session_options;
 
84
        GTlsInteraction *interaction;
 
85
 
 
86
        /* The type of objects to create */
 
87
        GType object_type;
 
88
        gpointer object_class;
 
89
        GckObjectCacheIface *object_iface;
 
90
 
 
91
        /* state_slots */
 
92
        GList *slots;
 
93
 
 
94
        /* state_slot */
 
95
        GckSlot *slot;
 
96
        GckTokenInfo *token_info;
 
97
        CK_FUNCTION_LIST_PTR funcs;
 
98
 
 
99
        /* state_session */
 
100
        GckSession *session;
 
101
 
 
102
        /* state_find */
 
103
        GQueue *found;
 
104
 
 
105
        /* state_results */
 
106
        GQueue *results;
 
107
};
 
108
 
 
109
struct _GckEnumeratorPrivate {
 
110
        GMutex *mutex;
 
111
        GckEnumeratorState *the_state;
 
112
        GTlsInteraction *interaction;
 
113
        GType object_type;
 
114
        GckObjectClass *object_class;
 
115
        GckEnumerator *chained;
 
116
};
 
117
 
 
118
G_DEFINE_TYPE (GckEnumerator, gck_enumerator, G_TYPE_OBJECT);
 
119
 
 
120
static gpointer state_modules        (GckEnumeratorState *args,
 
121
                                      gboolean forward);
 
122
 
 
123
static gpointer state_slots          (GckEnumeratorState *args,
 
124
                                      gboolean forward);
 
125
 
 
126
static gpointer state_slot           (GckEnumeratorState *args,
 
127
                                      gboolean forward);
 
128
 
 
129
static gpointer state_session        (GckEnumeratorState *args,
 
130
                                      gboolean forward);
 
131
 
 
132
static gpointer state_find           (GckEnumeratorState *args,
 
133
                                      gboolean forward);
 
134
 
 
135
static gpointer state_results        (GckEnumeratorState *args,
 
136
                                      gboolean forward);
 
137
 
 
138
 
 
139
static void
 
140
_gck_enumerator_result_free (gpointer data)
 
141
{
 
142
        GckEnumeratorResult *result = data;
 
143
        g_object_unref (result->session);
 
144
        if (result->attrs)
 
145
                gck_attributes_unref (result->attrs);
 
146
        g_slice_free (GckEnumeratorResult, result);
 
147
}
 
148
 
 
149
static gpointer
 
150
rewind_state (GckEnumeratorState *args, GckEnumeratorFunc handler)
 
151
{
 
152
        g_assert (args);
 
153
        g_assert (handler);
 
154
        g_assert (args->handler);
 
155
 
 
156
        while (handler != args->handler) {
 
157
                args->handler = (args->handler) (args, FALSE);
 
158
                g_assert (args->handler);
 
159
        }
 
160
 
 
161
        return handler;
 
162
}
 
163
 
 
164
static void
 
165
cleanup_state (GckEnumeratorState *args)
 
166
{
 
167
        g_assert (args);
 
168
 
 
169
        /* Have each state cleanup */
 
170
        rewind_state (args, state_modules);
 
171
 
 
172
        /* state_slots */
 
173
        g_assert (!args->slots);
 
174
 
 
175
        /* state_slot */
 
176
        g_assert (!args->slot);
 
177
        g_assert (!args->token_info);
 
178
        g_assert (!args->funcs);
 
179
 
 
180
        /* state_session */
 
181
        g_assert (!args->session);
 
182
 
 
183
        /* state_find */
 
184
        if (args->found) {
 
185
                g_queue_foreach (args->found, (GFunc) _gck_enumerator_result_free, NULL);
 
186
                g_queue_free (args->found);
 
187
                args->found = NULL;
 
188
        }
 
189
 
 
190
        /* state_results */
 
191
        if (args->results) {
 
192
                g_queue_foreach (args->results, (GFunc) _gck_enumerator_result_free, NULL);
 
193
                g_queue_free (args->results);
 
194
                args->results = NULL;
 
195
        }
 
196
 
 
197
        gck_list_unref_free (args->modules);
 
198
        args->modules = NULL;
 
199
 
 
200
        g_clear_object (&args->interaction);
 
201
 
 
202
        if (args->object_class)
 
203
                g_type_class_unref (args->object_class);
 
204
        args->object_class = NULL;
 
205
        args->object_type = 0;
 
206
 
 
207
        if (args->match) {
 
208
                gck_uri_data_free (args->match);
 
209
                args->match = NULL;
 
210
        }
 
211
}
 
212
 
 
213
static gpointer
 
214
state_modules (GckEnumeratorState *args, gboolean forward)
 
215
{
 
216
        GckModule *module;
 
217
 
 
218
        g_assert (args->slots == NULL);
 
219
 
 
220
        if (forward) {
 
221
 
 
222
                /* There are no more modules? */
 
223
                if (!args->modules) {
 
224
                        _gck_debug ("no more modules, stopping enumerator");
 
225
                        return NULL;
 
226
                }
 
227
 
 
228
                /* Pop off the current module */
 
229
                module = args->modules->data;
 
230
                g_assert (GCK_IS_MODULE (module));
 
231
                args->modules = g_list_delete_link (args->modules, args->modules);
 
232
 
 
233
                args->slots = gck_module_get_slots (module, TRUE);
 
234
 
 
235
                if (_gck_debugging) {
 
236
                        GckModuleInfo *info = gck_module_get_info (module);
 
237
                        _gck_debug ("enumerating into module: %s", info->library_description);
 
238
                        gck_module_info_free (info);
 
239
                }
 
240
 
 
241
                g_object_unref (module);
 
242
                return state_slots;
 
243
        }
 
244
 
 
245
        /* Should never be asked to go backward from start state */
 
246
        g_assert_not_reached ();
 
247
}
 
248
 
 
249
static gpointer
 
250
state_slots (GckEnumeratorState *args, gboolean forward)
 
251
{
 
252
        GckSlot *slot;
 
253
        GckModule *module;
 
254
        GckTokenInfo *token_info;
 
255
        gboolean matched;
 
256
 
 
257
        g_assert (args->slot == NULL);
 
258
 
 
259
        /* slots to slot state */
 
260
        if (forward) {
 
261
 
 
262
                /* If there are no more slots go back to start state */
 
263
                if (!args->slots) {
 
264
                        _gck_debug ("no more slots, want next module");
 
265
                        return rewind_state (args, state_modules);
 
266
                }
 
267
 
 
268
                /* Pop the next slot off the stack */
 
269
                slot = args->slots->data;
 
270
                args->slots = g_list_delete_link (args->slots, args->slots);
 
271
 
 
272
                token_info = gck_slot_get_token_info (slot);
 
273
                if (!token_info) {
 
274
                        g_message ("couldn't get token info while enumerating");
 
275
                        g_object_unref (slot);
 
276
                        return rewind_state (args, state_modules);
 
277
                }
 
278
 
 
279
                /* Do we have unrecognized matches? */
 
280
                if (args->match->any_unrecognized) {
 
281
                        _gck_debug ("token uri had unrecognized, not matching any tokens");
 
282
                        matched = FALSE;
 
283
 
 
284
                /* Are we trying to match the slot? */
 
285
                } else if (args->match->token_info) {
 
286
                        /* No match? Go to next slot */
 
287
                        matched = _gck_token_info_match (args->match->token_info, token_info);
 
288
 
 
289
                        _gck_debug ("%s token: %s", matched ? "matched" : "did not match",
 
290
                                    token_info->label);
 
291
 
 
292
                } else {
 
293
                        _gck_debug ("matching all tokens: %s", token_info->label);
 
294
                        matched = TRUE;
 
295
                }
 
296
 
 
297
                if (!matched) {
 
298
                        g_object_unref (slot);
 
299
                        gck_token_info_free (token_info);
 
300
                        return state_slots;
 
301
                }
 
302
 
 
303
                module = gck_slot_get_module (slot);
 
304
                args->funcs = gck_module_get_functions (module);
 
305
                g_assert (args->funcs);
 
306
                g_object_unref (module);
 
307
 
 
308
                /* We have a slot */
 
309
                args->slot = slot;
 
310
                args->token_info = token_info;
 
311
                return state_slot;
 
312
 
 
313
        /* slots state to modules state */
 
314
        } else {
 
315
 
 
316
                gck_list_unref_free (args->slots);
 
317
                args->slots = NULL;
 
318
                return state_modules;
 
319
        }
 
320
}
 
321
 
 
322
static gpointer
 
323
state_slot (GckEnumeratorState *args, gboolean forward)
 
324
{
 
325
        CK_SESSION_HANDLE session;
 
326
        CK_FLAGS flags;
 
327
        CK_RV rv;
 
328
 
 
329
        g_assert (args->slot);
 
330
        g_assert (args->funcs);
 
331
        g_assert (args->session == NULL);
 
332
 
 
333
        /* slot to session state */
 
334
        if (forward) {
 
335
                flags = CKF_SERIAL_SESSION;
 
336
                if ((args->session_options & GCK_SESSION_READ_WRITE) == GCK_SESSION_READ_WRITE)
 
337
                        flags |= CKF_RW_SESSION;
 
338
 
 
339
                rv = (args->funcs->C_OpenSession) (gck_slot_get_handle (args->slot),
 
340
                                                   flags, NULL, NULL, &session);
 
341
 
 
342
                if (rv != CKR_OK) {
 
343
                        g_message ("couldn't open session on module while enumerating objects: %s",
 
344
                                   gck_message_from_rv (rv));
 
345
                        return rewind_state (args, state_slots);
 
346
                }
 
347
 
 
348
                _gck_debug ("opened %s session", flags & CKF_RW_SESSION ? "read-write" : "read-only");
 
349
                args->session = gck_session_from_handle (args->slot, session, args->session_options);
 
350
                return state_session;
 
351
 
 
352
        /* slot to slots state */
 
353
        } else {
 
354
                g_object_unref (args->slot);
 
355
                args->slot = NULL;
 
356
                args->funcs = NULL;
 
357
 
 
358
                gck_token_info_free (args->token_info);
 
359
                args->token_info = NULL;
 
360
 
 
361
                return state_slots;
 
362
        }
 
363
}
 
364
 
 
365
static gpointer
 
366
state_session (GckEnumeratorState *args, gboolean forward)
 
367
{
 
368
        GTlsInteraction *interaction;
 
369
        CK_RV rv;
 
370
 
 
371
        g_assert (args->funcs);
 
372
        g_assert (args->session);
 
373
        g_assert (args->token_info);
 
374
 
 
375
        /* session to authenticated state */
 
376
        if (forward) {
 
377
 
 
378
                /* Don't want to authenticate? */
 
379
                if ((args->session_options & GCK_SESSION_LOGIN_USER) == 0) {
 
380
                        _gck_debug ("no authentication necessary, skipping");
 
381
                        return state_find;
 
382
                }
 
383
 
 
384
                /* Compatibility, hook into GckModule signals if no interaction set */
 
385
                if (args->interaction)
 
386
                        interaction = g_object_ref (args->interaction);
 
387
                else
 
388
                        interaction = _gck_interaction_new (args->slot);
 
389
 
 
390
                rv = _gck_session_authenticate_token (args->funcs,
 
391
                                                      gck_session_get_handle (args->session),
 
392
                                                      args->slot, interaction, NULL);
 
393
 
 
394
                g_object_unref (interaction);
 
395
 
 
396
                if (rv != CKR_OK)
 
397
                        g_message ("couldn't authenticate when enumerating: %s", gck_message_from_rv (rv));
 
398
 
 
399
                /* We try to proceed anyway with the enumeration */
 
400
                return state_find;
 
401
 
 
402
        /* Session to slot state */
 
403
        } else {
 
404
                g_object_unref (args->session);
 
405
                args->session = NULL;
 
406
                return state_slot;
 
407
        }
 
408
}
 
409
 
 
410
static gpointer
 
411
state_find (GckEnumeratorState *args,
 
412
            gboolean forward)
 
413
{
 
414
        CK_OBJECT_HANDLE objects[128];
 
415
        CK_SESSION_HANDLE session;
 
416
        CK_ATTRIBUTE_PTR attrs;
 
417
        CK_ULONG n_attrs, i,count;
 
418
        GckEnumeratorResult *result;
 
419
        CK_RV rv;
 
420
 
 
421
        /* Just go back, no logout */
 
422
        if (!forward)
 
423
                return state_session;
 
424
 
 
425
        /* This is where we do the actual searching */
 
426
 
 
427
        g_assert (args->session != NULL);
 
428
        g_assert (args->want_objects > 0);
 
429
        g_assert (args->funcs != NULL);
 
430
 
 
431
        if (!args->found)
 
432
                args->found = g_queue_new ();
 
433
 
 
434
        if (args->match->attributes) {
 
435
                attrs = _gck_attributes_commit_out (args->match->attributes, &n_attrs);
 
436
                if (_gck_debugging) {
 
437
                        gchar *string = gck_attributes_to_string (args->match->attributes);
 
438
                        _gck_debug ("finding objects matching: %s", string);
 
439
                        g_free (string);
 
440
                }
 
441
        } else {
 
442
                attrs = NULL;
 
443
                n_attrs = 0;
 
444
                _gck_debug ("finding all objects");
 
445
        }
 
446
 
 
447
        session = gck_session_get_handle (args->session);
 
448
        g_return_val_if_fail (session, NULL);
 
449
 
 
450
        /* Get all the objects */
 
451
        rv = (args->funcs->C_FindObjectsInit) (session, attrs, n_attrs);
 
452
 
 
453
        if (rv == CKR_OK) {
 
454
                for(;;) {
 
455
                        rv = (args->funcs->C_FindObjects) (session, objects, G_N_ELEMENTS (objects), &count);
 
456
                        if (rv != CKR_OK || count == 0)
 
457
                                break;
 
458
 
 
459
                        _gck_debug ("matched %lu objects", count);
 
460
 
 
461
                        for (i = 0; i < count; i++) {
 
462
                                result = g_slice_new0 (GckEnumeratorResult);
 
463
                                result->handle = objects[i];
 
464
                                result->session = g_object_ref (args->session);
 
465
                                g_queue_push_tail (args->found, result);
 
466
                        }
 
467
                }
 
468
 
 
469
                (args->funcs->C_FindObjectsFinal) (session);
 
470
        }
 
471
 
 
472
        _gck_debug ("finding objects completed with: %s", _gck_stringize_rv (rv));
 
473
        return state_results;
 
474
}
 
475
 
 
476
static gpointer
 
477
state_results (GckEnumeratorState *args,
 
478
               gboolean forward)
 
479
{
 
480
        GckEnumeratorResult *result;
 
481
        GckBuilder builder;
 
482
        GckAttributes *attrs;
 
483
        CK_ATTRIBUTE_PTR template;
 
484
        CK_ULONG n_template;
 
485
        CK_SESSION_HANDLE session;
 
486
        gint count;
 
487
        CK_RV rv;
 
488
        gint i;
 
489
 
 
490
        g_assert (args->funcs != NULL);
 
491
        g_assert (args->object_class != NULL);
 
492
        g_assert (args->found != NULL);
 
493
 
 
494
        /* No cleanup, just unwind */
 
495
        if (!forward)
 
496
                return state_find;
 
497
 
 
498
        if (!args->results)
 
499
                args->results = g_queue_new ();
 
500
 
 
501
        session = gck_session_get_handle (args->session);
 
502
        g_return_val_if_fail (session, NULL);
 
503
 
 
504
        /* Get the attributes for want_objects */
 
505
        for (count = 0; count < args->want_objects; count++) {
 
506
                result = g_queue_pop_head (args->found);
 
507
                if (result == NULL) {
 
508
                        _gck_debug ("wanted %d objects, have %d, looking for more",
 
509
                                    args->want_objects, g_queue_get_length (args->results));
 
510
                        return rewind_state (args, state_slots);
 
511
                }
 
512
 
 
513
                /* If no request for attributes, just go forward */
 
514
                if (args->object_iface == NULL || args->object_iface->n_default_types == 0) {
 
515
                        g_queue_push_tail (args->results, result);
 
516
                        continue;
 
517
                }
 
518
 
 
519
                gck_builder_init (&builder);
 
520
 
 
521
                for (i = 0; i < args->object_iface->n_default_types; ++i)
 
522
                        gck_builder_add_empty (&builder, args->object_iface->default_types[i]);
 
523
 
 
524
                /* Ask for attribute sizes */
 
525
                template = _gck_builder_prepare_in (&builder, &n_template);
 
526
 
 
527
                rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
 
528
                if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
 
529
 
 
530
                        /* Allocate memory for each value */
 
531
                        template = _gck_builder_commit_in (&builder, &n_template);
 
532
 
 
533
                        /* Now get the actual values */
 
534
                        rv = (args->funcs->C_GetAttributeValue) (session, result->handle, template, n_template);
 
535
                }
 
536
 
 
537
                attrs = gck_attributes_ref_sink (gck_builder_end (&builder));
 
538
 
 
539
                if (GCK_IS_GET_ATTRIBUTE_RV_OK (rv)) {
 
540
                        if (_gck_debugging) {
 
541
                                gchar *string = gck_attributes_to_string (attrs);
 
542
                                _gck_debug ("retrieved attributes for object %lu: %s",
 
543
                                            result->handle, string);
 
544
                                g_free (string);
 
545
                        }
 
546
                        result->attrs = attrs;
 
547
                        g_queue_push_tail (args->results, result);
 
548
 
 
549
                } else {
 
550
                        g_message ("couldn't retrieve attributes when enumerating: %s",
 
551
                                   gck_message_from_rv (rv));
 
552
                        gck_attributes_unref (attrs);
 
553
                        _gck_enumerator_result_free (result);
 
554
                }
 
555
        }
 
556
 
 
557
        _gck_debug ("wanted %d objects, returned %d objects",
 
558
                    args->want_objects, g_queue_get_length (args->results));
 
559
 
 
560
        /* We got all the results we wanted */
 
561
        return NULL;
 
562
}
 
563
 
 
564
static void
 
565
gck_enumerator_init (GckEnumerator *self)
 
566
{
 
567
        self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_ENUMERATOR, GckEnumeratorPrivate);
 
568
#if GLIB_CHECK_VERSION(2,31,2)
 
569
        self->pv->mutex = g_new0 (GMutex, 1);
 
570
        g_mutex_init (self->pv->mutex);
 
571
#else
 
572
        self->pv->mutex = g_mutex_new ();
 
573
#endif
 
574
        self->pv->the_state = g_new0 (GckEnumeratorState, 1);
 
575
        self->pv->object_type = GCK_TYPE_OBJECT;
 
576
        self->pv->object_class = g_type_class_ref (self->pv->object_type);
 
577
        g_assert (self->pv->object_class);
 
578
}
 
579
 
 
580
static void
 
581
gck_enumerator_get_property (GObject *obj,
 
582
                             guint prop_id,
 
583
                             GValue *value,
 
584
                             GParamSpec *pspec)
 
585
{
 
586
        GckEnumerator *self = GCK_ENUMERATOR (obj);
 
587
 
 
588
        switch (prop_id) {
 
589
        case PROP_INTERACTION:
 
590
                g_value_take_object (value, gck_enumerator_get_interaction (self));
 
591
                break;
 
592
        case PROP_OBJECT_TYPE:
 
593
                g_value_set_gtype (value, gck_enumerator_get_object_type (self));
 
594
                break;
 
595
        case PROP_CHAINED:
 
596
                g_value_set_object (value, gck_enumerator_get_chained (self));
 
597
                break;
 
598
        default:
 
599
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 
600
                break;
 
601
        }
 
602
}
 
603
 
 
604
static void
 
605
gck_enumerator_set_property (GObject *obj,
 
606
                             guint prop_id,
 
607
                             const GValue *value,
 
608
                             GParamSpec *pspec)
 
609
{
 
610
        GckEnumerator *self = GCK_ENUMERATOR (obj);
 
611
 
 
612
        switch (prop_id) {
 
613
        case PROP_INTERACTION:
 
614
                gck_enumerator_set_interaction (self, g_value_get_object (value));
 
615
                break;
 
616
        case PROP_OBJECT_TYPE:
 
617
                gck_enumerator_set_object_type (self, g_value_get_gtype (value));
 
618
                break;
 
619
        case PROP_CHAINED:
 
620
                gck_enumerator_set_chained (self, g_value_get_object (value));
 
621
                break;
 
622
        default:
 
623
                G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
 
624
                break;
 
625
        }
 
626
}
 
627
 
 
628
static void
 
629
gck_enumerator_dispose (GObject *obj)
 
630
{
 
631
        GckEnumerator *self = GCK_ENUMERATOR (obj);
 
632
 
 
633
        gck_enumerator_set_interaction (self, NULL);
 
634
        gck_enumerator_set_chained (self, NULL);
 
635
 
 
636
        G_OBJECT_CLASS (gck_enumerator_parent_class)->dispose (obj);
 
637
}
 
638
 
 
639
static void
 
640
gck_enumerator_finalize (GObject *obj)
 
641
{
 
642
        GckEnumerator *self = GCK_ENUMERATOR (obj);
 
643
 
 
644
        g_assert (self->pv->interaction == NULL);
 
645
 
 
646
        g_assert (self->pv->the_state != NULL);
 
647
        cleanup_state (self->pv->the_state);
 
648
        g_free (self->pv->the_state);
 
649
 
 
650
#if GLIB_CHECK_VERSION(2,31,2)
 
651
        g_mutex_clear (self->pv->mutex);
 
652
        g_free (self->pv->mutex);
 
653
#else
 
654
        g_mutex_free (self->pv->mutex);
 
655
#endif
 
656
        g_type_class_unref (self->pv->object_class);
 
657
 
 
658
        G_OBJECT_CLASS (gck_enumerator_parent_class)->finalize (obj);
 
659
}
 
660
 
 
661
static void
 
662
gck_enumerator_class_init (GckEnumeratorClass *klass)
 
663
{
 
664
        GObjectClass *gobject_class = (GObjectClass*)klass;
 
665
 
 
666
        gobject_class->get_property = gck_enumerator_get_property;
 
667
        gobject_class->set_property = gck_enumerator_set_property;
 
668
        gobject_class->dispose = gck_enumerator_dispose;
 
669
        gobject_class->finalize = gck_enumerator_finalize;
 
670
 
 
671
        g_type_class_add_private (klass, sizeof (GckEnumeratorPrivate));
 
672
 
 
673
        /**
 
674
         * GckEnumerator:interaction:
 
675
         *
 
676
         * Interaction object used to ask the user for pins when opening
 
677
         * sessions. Used if the session_options of the enumerator have
 
678
         * %GCK_SESSION_LOGIN_USER
 
679
         */
 
680
        g_object_class_install_property (gobject_class, PROP_INTERACTION,
 
681
                g_param_spec_object ("interaction", "Interaction", "Interaction asking for pins",
 
682
                                     G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE));
 
683
 
 
684
        /**
 
685
         * GckEnumerator:object-type:
 
686
         *
 
687
         * The type of objects that are created by the enumerator. Must be
 
688
         * GckObject or derived from it.
 
689
         */
 
690
        g_object_class_install_property (gobject_class, PROP_OBJECT_TYPE,
 
691
                g_param_spec_gtype ("object-type", "Object Type", "Type of objects created",
 
692
                                    GCK_TYPE_OBJECT, G_PARAM_READWRITE));
 
693
 
 
694
        /**
 
695
         * GckEnumerator:chained:
 
696
         *
 
697
         * Chained enumerator, which will be enumerated when this enumerator
 
698
         * has enumerated all its objects.
 
699
         */
 
700
        g_object_class_install_property (gobject_class, PROP_CHAINED,
 
701
                    g_param_spec_object ("chained", "Chained", "Chained enumerator",
 
702
                                         GCK_TYPE_ENUMERATOR, G_PARAM_READWRITE));
 
703
}
 
704
 
 
705
static void
 
706
created_enumerator (GckUriData *uri_data,
 
707
                    const gchar *type)
 
708
{
 
709
        if (_gck_debugging) {
 
710
                gchar *attrs, *uri;
 
711
                attrs = uri_data->attributes ? gck_attributes_to_string (uri_data->attributes) : NULL;
 
712
                uri = uri_data ? gck_uri_build (uri_data, GCK_URI_FOR_TOKEN | GCK_URI_FOR_MODULE) : NULL;
 
713
                _gck_debug ("for = %s, tokens = %s, objects = %s", type, uri, attrs);
 
714
                g_free (attrs);
 
715
                g_free (uri);
 
716
        }
 
717
}
 
718
 
 
719
GckEnumerator *
 
720
_gck_enumerator_new_for_modules (GList *modules,
 
721
                                 GckSessionOptions session_options,
 
722
                                 GckUriData *uri_data)
 
723
{
 
724
        GckEnumerator *self;
 
725
        GckEnumeratorState *state;
 
726
 
 
727
        self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
 
728
        state = self->pv->the_state;
 
729
 
 
730
        state->session_options = session_options;
 
731
 
 
732
        state->modules = gck_list_ref_copy (modules);
 
733
        state->slots = NULL;
 
734
        state->handler = state_modules;
 
735
        state->match = uri_data;
 
736
 
 
737
        created_enumerator (uri_data, "modules");
 
738
        return self;
 
739
}
 
740
 
 
741
GckEnumerator *
 
742
_gck_enumerator_new_for_slots (GList *slots,
 
743
                               GckSessionOptions session_options,
 
744
                               GckUriData *uri_data)
 
745
{
 
746
        GckEnumerator *self;
 
747
        GckEnumeratorState *state;
 
748
 
 
749
        self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
 
750
        state = self->pv->the_state;
 
751
 
 
752
        state->session_options = session_options;
 
753
 
 
754
        state->slots = gck_list_ref_copy (slots);
 
755
        state->modules = NULL;
 
756
        state->handler = state_slots;
 
757
        state->match = uri_data;
 
758
 
 
759
        created_enumerator (uri_data, "slots");
 
760
        return self;
 
761
}
 
762
 
 
763
GckEnumerator *
 
764
_gck_enumerator_new_for_session (GckSession *session,
 
765
                                 GckUriData *uri_data)
 
766
{
 
767
        GckEnumerator *self;
 
768
        GckEnumeratorState *state;
 
769
        GckModule *module;
 
770
 
 
771
        self = g_object_new (GCK_TYPE_ENUMERATOR, NULL);
 
772
        state = self->pv->the_state;
 
773
 
 
774
        state->session = g_object_ref (session);
 
775
        state->modules = NULL;
 
776
        state->slots = NULL;
 
777
        state->handler = state_session;
 
778
        state->match = uri_data;
 
779
 
 
780
        state->slot = gck_session_get_slot (session);
 
781
        state->token_info = gck_slot_get_token_info (state->slot);
 
782
 
 
783
        module = gck_session_get_module (session);
 
784
        state->funcs = gck_module_get_functions (module);
 
785
        g_object_unref (module);
 
786
 
 
787
        created_enumerator (uri_data, "session");
 
788
        return self;
 
789
}
 
790
 
 
791
typedef struct _EnumerateNext {
 
792
        GckArguments base;
 
793
        GckEnumeratorState *state;
 
794
        gint want_objects;
 
795
} EnumerateNext;
 
796
 
 
797
static CK_RV
 
798
perform_enumerate_next (EnumerateNext *args)
 
799
{
 
800
        GckEnumeratorFunc handler;
 
801
        GckEnumeratorState *state;
 
802
        gint count = 0;
 
803
 
 
804
        g_assert (args->state);
 
805
 
 
806
        for (state = args->state; state != NULL; state = state->chained) {
 
807
                g_assert (state->handler);
 
808
                state->want_objects = args->want_objects - count;
 
809
                for (;;) {
 
810
                        handler = (state->handler) (state, TRUE);
 
811
                        if (!handler)
 
812
                                break;
 
813
                        state->handler = handler;
 
814
                }
 
815
 
 
816
                count += state->results ? g_queue_get_length (state->results) : 0;
 
817
                if (count >= args->want_objects)
 
818
                        break;
 
819
        }
 
820
 
 
821
        /* TODO: In some modes, errors */
 
822
        return CKR_OK;
 
823
}
 
824
 
 
825
static void
 
826
free_enumerate_next (EnumerateNext *args)
 
827
{
 
828
        /* Should have been assigned back to enumerator */
 
829
        g_assert (!args->state);
 
830
 
 
831
        g_free (args);
 
832
}
 
833
 
 
834
/**
 
835
 * gck_enumerator_get_object_type:
 
836
 * @self: an enumerator
 
837
 *
 
838
 * Get the type of objects created by this enumerator. The type will always
 
839
 * either be #GckObject or derived from it.
 
840
 *
 
841
 * Returns: (transfer none): the type of objects created
 
842
 */
 
843
GType
 
844
gck_enumerator_get_object_type (GckEnumerator *self)
 
845
{
 
846
        GType result;
 
847
 
 
848
        g_return_val_if_fail (GCK_IS_ENUMERATOR (self), 0);
 
849
 
 
850
        g_mutex_lock (self->pv->mutex);
 
851
 
 
852
                result = self->pv->object_type;
 
853
 
 
854
        g_mutex_unlock (self->pv->mutex);
 
855
 
 
856
        return result;
 
857
}
 
858
 
 
859
/**
 
860
 * gck_enumerator_set_object_type:
 
861
 * @self: an enumerator
 
862
 * @object_type: the type of objects to create
 
863
 *
 
864
 * Set the type of objects to be created by this enumerator. The type must
 
865
 * always be either #GckObject or derived from it.
 
866
 *
 
867
 * If the #GckObjectCache interface is implemented on the derived class
 
868
 * and the attribute_types field is set, then the enumerator will retrieve
 
869
 * attributes for each object.
 
870
 */
 
871
void
 
872
gck_enumerator_set_object_type (GckEnumerator *self,
 
873
                                GType object_type)
 
874
{
 
875
        gpointer klass;
 
876
 
 
877
        g_return_if_fail (GCK_IS_ENUMERATOR (self));
 
878
 
 
879
        if (!g_type_is_a (object_type, GCK_TYPE_OBJECT)) {
 
880
                g_warning ("the object_type '%s' is not a derived type of GckObject",
 
881
                           g_type_name (object_type));
 
882
                return;
 
883
        }
 
884
 
 
885
        klass = g_type_class_ref (object_type);
 
886
 
 
887
        g_mutex_lock (self->pv->mutex);
 
888
 
 
889
                if (self->pv->object_type)
 
890
                        g_type_class_unref (self->pv->object_class);
 
891
                self->pv->object_type = object_type;
 
892
                self->pv->object_class = klass;
 
893
 
 
894
        g_mutex_unlock (self->pv->mutex);
 
895
}
 
896
 
 
897
/**
 
898
 * gck_enumerator_get_chained:
 
899
 * @self: the enumerator
 
900
 *
 
901
 * Get the enumerator that will be run after all objects from this one
 
902
 * are seen.
 
903
 *
 
904
 * Returns: (transfer full) (allow-none): the chained enumerator or %NULL
 
905
 */
 
906
GckEnumerator *
 
907
gck_enumerator_get_chained (GckEnumerator *self)
 
908
{
 
909
        GckEnumerator *chained = NULL;
 
910
 
 
911
        g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
 
912
 
 
913
        g_mutex_lock (self->pv->mutex);
 
914
 
 
915
                if (self->pv->chained)
 
916
                        chained = g_object_ref (self->pv->chained);
 
917
 
 
918
        g_mutex_unlock (self->pv->mutex);
 
919
 
 
920
        return chained;
 
921
}
 
922
 
 
923
/**
 
924
 * gck_enumerator_set_interaction:
 
925
 * @self: the enumerator
 
926
 * @chained: (allow-none): the chained enumerator or %NULL
 
927
 *
 
928
 * Set a chained enumerator that will be run after all objects from this one
 
929
 * are seen.
 
930
 */
 
931
void
 
932
gck_enumerator_set_chained (GckEnumerator *self,
 
933
                            GckEnumerator *chained)
 
934
{
 
935
        GckEnumerator *old_chained = NULL;
 
936
 
 
937
        g_return_if_fail (GCK_IS_ENUMERATOR (self));
 
938
        g_return_if_fail (chained == NULL || GCK_IS_ENUMERATOR (chained));
 
939
 
 
940
        g_mutex_lock (self->pv->mutex);
 
941
 
 
942
                old_chained = self->pv->chained;
 
943
                if (chained)
 
944
                        g_object_ref (chained);
 
945
                self->pv->chained = chained;
 
946
 
 
947
        g_mutex_unlock (self->pv->mutex);
 
948
 
 
949
        if (old_chained)
 
950
                g_object_unref (old_chained);
 
951
 
 
952
        g_object_notify (G_OBJECT (self), "chained");
 
953
}
 
954
 
 
955
/**
 
956
 * gck_enumerator_get_interaction:
 
957
 * @self: the enumerator
 
958
 *
 
959
 * Get the interaction used when a pin is needed
 
960
 *
 
961
 * Returns: (transfer full) (allow-none): the interaction or %NULL
 
962
 */
 
963
GTlsInteraction *
 
964
gck_enumerator_get_interaction (GckEnumerator *self)
 
965
{
 
966
        GTlsInteraction *result = NULL;
 
967
 
 
968
        g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
 
969
 
 
970
        g_mutex_lock (self->pv->mutex);
 
971
 
 
972
                if (self->pv->interaction)
 
973
                        result = g_object_ref (self->pv->interaction);
 
974
 
 
975
        g_mutex_unlock (self->pv->mutex);
 
976
 
 
977
        return result;
 
978
}
 
979
 
 
980
/**
 
981
 * gck_enumerator_set_interaction:
 
982
 * @self: the enumerator
 
983
 * @interaction: (allow-none): the interaction or %NULL
 
984
 *
 
985
 * Set the interaction used when a pin is needed
 
986
 */
 
987
void
 
988
gck_enumerator_set_interaction (GckEnumerator *self,
 
989
                                GTlsInteraction *interaction)
 
990
{
 
991
        GTlsInteraction *previous = NULL;
 
992
 
 
993
        g_return_if_fail (GCK_IS_ENUMERATOR (self));
 
994
        g_return_if_fail (interaction == NULL || G_IS_TLS_INTERACTION (interaction));
 
995
 
 
996
        g_mutex_lock (self->pv->mutex);
 
997
 
 
998
                if (interaction != self->pv->interaction) {
 
999
                        previous = self->pv->interaction;
 
1000
                        self->pv->interaction = interaction;
 
1001
                        if (interaction)
 
1002
                                g_object_ref (interaction);
 
1003
                }
 
1004
 
 
1005
        g_mutex_unlock (self->pv->mutex);
 
1006
 
 
1007
        g_clear_object (&previous);
 
1008
        g_object_notify (G_OBJECT (self), "interaction");
 
1009
}
 
1010
 
 
1011
static GckEnumeratorState *
 
1012
check_out_enumerator_state (GckEnumerator *self)
 
1013
{
 
1014
        GckEnumeratorState *state = NULL;
 
1015
        GTlsInteraction *old_interaction = NULL;
 
1016
        gpointer old_object_class = NULL;
 
1017
        GckEnumeratorState *chained_state = NULL;
 
1018
        GckEnumerator *chained;
 
1019
 
 
1020
        chained = gck_enumerator_get_chained (self);
 
1021
        if (chained) {
 
1022
                chained_state = check_out_enumerator_state (chained);
 
1023
                g_object_unref (chained);
 
1024
        }
 
1025
 
 
1026
        g_mutex_lock (self->pv->mutex);
 
1027
 
 
1028
                if (self->pv->the_state) {
 
1029
                        state = self->pv->the_state;
 
1030
                        self->pv->the_state = NULL;
 
1031
 
 
1032
                        state->enumerator = g_object_ref (self);
 
1033
                        g_assert (state->chained == NULL);
 
1034
                        state->chained = chained_state;
 
1035
 
 
1036
                        old_interaction = state->interaction;
 
1037
                        if (self->pv->interaction)
 
1038
                                state->interaction = g_object_ref (self->pv->interaction);
 
1039
                        else
 
1040
                                state->interaction = NULL;
 
1041
 
 
1042
                        old_object_class = state->object_class;
 
1043
 
 
1044
                        /* Must already be holding a reference, state also holds a ref */
 
1045
                        state->object_type = self->pv->object_type;
 
1046
                        state->object_class = g_type_class_peek (state->object_type);
 
1047
                        g_assert (state->object_class == self->pv->object_class);
 
1048
                        state->object_iface = g_type_interface_peek (state->object_class,
 
1049
                                                                     GCK_TYPE_OBJECT_CACHE);
 
1050
                        g_type_class_ref (state->object_type);
 
1051
                }
 
1052
 
 
1053
        g_mutex_unlock (self->pv->mutex);
 
1054
 
 
1055
        if (state == NULL)
 
1056
                g_warning ("this enumerator is already running a next operation");
 
1057
 
 
1058
        /* Free these outside the lock */
 
1059
        if (old_interaction)
 
1060
                g_object_unref (old_interaction);
 
1061
        if (old_object_class)
 
1062
                g_type_class_unref (old_object_class);
 
1063
 
 
1064
        return state;
 
1065
}
 
1066
 
 
1067
static void
 
1068
check_in_enumerator_state (GckEnumeratorState *state)
 
1069
{
 
1070
        GckEnumeratorState *chained = NULL;
 
1071
        GckEnumerator *self;
 
1072
 
 
1073
        g_assert (GCK_IS_ENUMERATOR (state->enumerator));
 
1074
        self = state->enumerator;
 
1075
 
 
1076
        g_mutex_lock (self->pv->mutex);
 
1077
 
 
1078
                state->enumerator = NULL;
 
1079
                g_assert (self->pv->the_state == NULL);
 
1080
                self->pv->the_state = state;
 
1081
                chained = state->chained;
 
1082
                state->chained = NULL;
 
1083
 
 
1084
        g_mutex_unlock (self->pv->mutex);
 
1085
 
 
1086
        /* matches ref in check_in */
 
1087
        g_object_unref (self);
 
1088
 
 
1089
        if (chained)
 
1090
                check_in_enumerator_state (chained);
 
1091
}
 
1092
 
 
1093
static GckObject *
 
1094
extract_result (GckEnumeratorState *state)
 
1095
{
 
1096
        GckEnumeratorResult *result = NULL;
 
1097
        GckModule *module;
 
1098
        GckObject *object;
 
1099
 
 
1100
        g_assert (state != NULL);
 
1101
 
 
1102
        if (state->results != NULL)
 
1103
                result = g_queue_pop_head (state->results);
 
1104
        if (result == NULL) {
 
1105
                if (state->chained)
 
1106
                        return extract_result (state->chained);
 
1107
                return NULL;
 
1108
        }
 
1109
 
 
1110
        module = gck_session_get_module (result->session);
 
1111
        object = g_object_new (state->object_type,
 
1112
                               "module", module,
 
1113
                               "handle", result->handle,
 
1114
                               "session", result->session,
 
1115
                               result->attrs ? "attributes" : NULL, result->attrs,
 
1116
                               NULL);
 
1117
        g_object_unref (module);
 
1118
 
 
1119
        _gck_enumerator_result_free (result);
 
1120
        return object;
 
1121
}
 
1122
 
 
1123
static GList *
 
1124
extract_results (GckEnumeratorState *state,
 
1125
                 gint *want_objects)
 
1126
{
 
1127
        GList *objects = NULL;
 
1128
        GckObject *object;
 
1129
        gint i;
 
1130
 
 
1131
        g_assert (state != NULL);
 
1132
        g_assert (want_objects != NULL);
 
1133
 
 
1134
        for (i = 0; i < *want_objects; i++) {
 
1135
                object = extract_result (state);
 
1136
                if (object == NULL)
 
1137
                        break;
 
1138
                objects = g_list_prepend (objects, object);
 
1139
        }
 
1140
 
 
1141
        *want_objects -= i;
 
1142
        return g_list_reverse (objects);
 
1143
}
 
1144
 
 
1145
/**
 
1146
 * gck_enumerator_next:
 
1147
 * @self: The enumerator
 
1148
 * @cancellable: A #GCancellable or %NULL
 
1149
 * @error: A location to store an error on failure
 
1150
 *
 
1151
 * Get the next object in the enumerator, or %NULL if there are no more objects.
 
1152
 *
 
1153
 * %NULL is also returned if the function fails. Use the @error to determine
 
1154
 * whether a failure occurred or not.
 
1155
 *
 
1156
 * Returns: (transfer full) (allow-none): The next object, which must be released
 
1157
 * using g_object_unref, or %NULL.
 
1158
 */
 
1159
GckObject *
 
1160
gck_enumerator_next (GckEnumerator *self,
 
1161
                     GCancellable *cancellable,
 
1162
                     GError **error)
 
1163
{
 
1164
        EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, 0, };
 
1165
        GckObject *result = NULL;
 
1166
 
 
1167
        g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
 
1168
        g_return_val_if_fail (!error || !*error, NULL);
 
1169
 
 
1170
        args.state = check_out_enumerator_state (self);
 
1171
        g_return_val_if_fail (args.state != NULL, NULL);
 
1172
 
 
1173
        /* A result from a previous run? */
 
1174
        result = extract_result (args.state);
 
1175
        if (result == NULL) {
 
1176
                args.want_objects = 1;
 
1177
 
 
1178
                /* Run the operation and steal away the results */
 
1179
                if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error))
 
1180
                        result = extract_result (args.state);
 
1181
 
 
1182
                args.want_objects = 0;
 
1183
        }
 
1184
 
 
1185
        /* Put the state back */
 
1186
        check_in_enumerator_state (args.state);
 
1187
 
 
1188
        return result;
 
1189
}
 
1190
 
 
1191
/**
 
1192
 * gck_enumerator_next_n:
 
1193
 * @self: An enumerator
 
1194
 * @max_objects: The maximum amount of objects to enumerate
 
1195
 * @cancellable: A #GCancellable or %NULL
 
1196
 * @error: A location to store an error on failure
 
1197
 *
 
1198
 * Get the next set of objects from the enumerator. The maximum number of
 
1199
 * objects can be specified with @max_objects. If -1 is specified, then all
 
1200
 * the remaining objects will be returned.
 
1201
 *
 
1202
 * %NULL is also returned if the function fails. Use the @error to determine
 
1203
 * whether a failure occurred or not.
 
1204
 *
 
1205
 * Returns: (transfer full) (element-type Gck.Object): A list of objects, which
 
1206
 * should be freed using gck_list_unref_free().
 
1207
 */
 
1208
GList *
 
1209
gck_enumerator_next_n (GckEnumerator *self,
 
1210
                       gint max_objects,
 
1211
                       GCancellable *cancellable,
 
1212
                       GError **error)
 
1213
{
 
1214
        EnumerateNext args = { GCK_ARGUMENTS_INIT, NULL, 0, };
 
1215
        GList *results = NULL;
 
1216
        gint want_objects;
 
1217
 
 
1218
        g_return_val_if_fail (GCK_IS_ENUMERATOR (self), NULL);
 
1219
        g_return_val_if_fail (max_objects == -1 || max_objects > 0, NULL);
 
1220
        g_return_val_if_fail (!error || !*error, NULL);
 
1221
 
 
1222
        /* Remove the state and own it ourselves */
 
1223
        args.state = check_out_enumerator_state (self);
 
1224
        g_return_val_if_fail (args.state != NULL, NULL);
 
1225
 
 
1226
        want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
 
1227
 
 
1228
        /* A result from a previous run? */
 
1229
        results = extract_results (args.state, &want_objects);
 
1230
        if (want_objects > 0) {
 
1231
                args.want_objects = want_objects;
 
1232
 
 
1233
                /* Run the operation and steal away the results */
 
1234
                if (_gck_call_sync (NULL, perform_enumerate_next, NULL, &args, cancellable, error))
 
1235
                        results = g_list_concat (results, extract_results (args.state, &want_objects));
 
1236
 
 
1237
                args.want_objects = 0;
 
1238
        }
 
1239
 
 
1240
        /* Put the state back */
 
1241
        check_in_enumerator_state (args.state);
 
1242
 
 
1243
        if (results)
 
1244
                g_clear_error (error);
 
1245
 
 
1246
        return results;
 
1247
}
 
1248
 
 
1249
/**
 
1250
 * gck_enumerator_next_async:
 
1251
 * @self: An enumerator
 
1252
 * @max_objects: The maximum number of objects to get
 
1253
 * @cancellable: A #GCancellable or %NULL
 
1254
 * @callback: Called when the result is ready
 
1255
 * @user_data: Data to pass to the callback
 
1256
 *
 
1257
 * Get the next set of objects from the enumerator. This operation completes
 
1258
 * asynchronously.The maximum number of objects can be specified with
 
1259
 * @max_objects. If -1 is specified, then all the remaining objects will be
 
1260
 * enumerated.
 
1261
 */
 
1262
void
 
1263
gck_enumerator_next_async (GckEnumerator *self, gint max_objects, GCancellable *cancellable,
 
1264
                           GAsyncReadyCallback callback, gpointer user_data)
 
1265
{
 
1266
        GckEnumeratorState *state;
 
1267
        EnumerateNext *args;
 
1268
 
 
1269
        g_return_if_fail (GCK_IS_ENUMERATOR (self));
 
1270
        g_return_if_fail (max_objects == -1 || max_objects > 0);
 
1271
 
 
1272
        g_object_ref (self);
 
1273
 
 
1274
        /* Remove the state and own it ourselves */
 
1275
        state = check_out_enumerator_state (self);
 
1276
        g_return_if_fail (state != NULL);
 
1277
 
 
1278
        args =  _gck_call_async_prep (NULL, self, perform_enumerate_next, NULL,
 
1279
                                       sizeof (*args), free_enumerate_next);
 
1280
        args->want_objects = max_objects <= 0 ? G_MAXINT : max_objects;
 
1281
 
 
1282
        args->state = state;
 
1283
        _gck_call_async_ready_go (args, cancellable, callback, user_data);
 
1284
        g_object_unref (self);
 
1285
}
 
1286
 
 
1287
/**
 
1288
 * gck_enumerator_next_finish:
 
1289
 * @self: An enumerator
 
1290
 * @result: The result passed to the callback
 
1291
 * @error: A location to raise an error on failure.
 
1292
 *
 
1293
 * Complete an operation to enumerate next objects.
 
1294
 *
 
1295
 * %NULL is also returned if the function fails. Use the @error to determine
 
1296
 * whether a failure occurred or not.
 
1297
 *
 
1298
 * Returns: (element-type Gck.Module) (transfer full): The list of objects, which
 
1299
 * should be freed with gck_list_unref_free()
 
1300
 */
 
1301
GList*
 
1302
gck_enumerator_next_finish (GckEnumerator *self, GAsyncResult *result, GError **error)
 
1303
{
 
1304
        EnumerateNext *args;
 
1305
        GckEnumeratorState *state;
 
1306
        GList *results = NULL;
 
1307
        gint want_objects;
 
1308
 
 
1309
        g_object_ref (self);
 
1310
 
 
1311
        args = _gck_call_arguments (result, EnumerateNext);
 
1312
        state = args->state;
 
1313
        args->state = NULL;
 
1314
        want_objects = args->want_objects;
 
1315
        args->want_objects = 0;
 
1316
 
 
1317
        if (_gck_call_basic_finish (result, error))
 
1318
                results = extract_results (state, &want_objects);
 
1319
 
 
1320
        /* Put the state back */
 
1321
        check_in_enumerator_state (state);
 
1322
 
 
1323
        g_object_unref (self);
 
1324
 
 
1325
        return results;
 
1326
}