device.c 32.1 KB
Newer Older
Daniel Drake's avatar
Daniel Drake committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * /net/reactivated/Fprint/Device/foo object implementation
 * Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 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 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.
 */

20
21
#include "config.h"

Daniel Drake's avatar
Daniel Drake committed
22
#include <dbus/dbus-glib-bindings.h>
23
24
#include <dbus/dbus-glib-lowlevel.h>
#include <glib/gi18n.h>
Bastien Nocera's avatar
Bastien Nocera committed
25
26
#include <polkit/polkit.h>
#include <polkit-dbus/polkit-dbus.h>
Daniel Drake's avatar
Daniel Drake committed
27
28
#include <libfprint/fprint.h>

29
30
31
#include <sys/types.h>
#include <pwd.h>

Daniel Drake's avatar
Daniel Drake committed
32
#include "fprintd.h"
33
#include "storage.h"
34
#include "egg-dbus-monitor.h"
Daniel Drake's avatar
Daniel Drake committed
35

36
37
38
39
40
41
42
43
44
45
46
47
48
static char *fingers[] = {
	"left-thumb",
	"left-index-finger",
	"left-middle-finger",
	"left-ring-finger",
	"left-little-finger",
	"right-thumb",
	"right-index-finger",
	"right-middle-finger",
	"right-ring-finger",
	"right-little-finger"
};

49
50
extern DBusGConnection *fprintd_dbus_conn;

Bastien Nocera's avatar
Bastien Nocera committed
51
static void fprint_device_claim(FprintDevice *rdev,
52
53
				const char *username,
				DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
54
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
55
	DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
56
static void fprint_device_verify_start(FprintDevice *rdev,
57
	const char *finger_name, DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
58
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
59
	DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
60
static void fprint_device_enroll_start(FprintDevice *rdev,
61
	const char *finger_name, DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
62
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
63
	DBusGMethodInvocation *context);
64
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, 
65
66
						const char *username,
						DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
67
static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
68
69
						  const char *username,
						  DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
70
71
static void fprint_device_get_properties (FprintDevice *rdev,
					  DBusGMethodInvocation *context);
Daniel Drake's avatar
Daniel Drake committed
72
73
74

#include "device-dbus-glue.h"

Bastien Nocera's avatar
Bastien Nocera committed
75
76
77
typedef enum {
	ACTION_NONE = 0,
	ACTION_IDENTIFY,
Bastien Nocera's avatar
Bastien Nocera committed
78
79
	ACTION_VERIFY,
	ACTION_ENROLL
Bastien Nocera's avatar
Bastien Nocera committed
80
81
} FprintDeviceAction;

Daniel Drake's avatar
Daniel Drake committed
82
struct session_data {
Daniel Drake's avatar
Daniel Drake committed
83
84
85
	/* finger being enrolled */
	int enroll_finger;

Daniel Drake's avatar
Daniel Drake committed
86
87
88
89
90
91
92
93
94
95
96
97
	/* method invocation for async ClaimDevice() */
	DBusGMethodInvocation *context_claim_device;

	/* method invocation for async ReleaseDevice() */
	DBusGMethodInvocation *context_release_device;
};

struct FprintDevicePrivate {
	guint32 id;
	struct fp_dscv_dev *ddev;
	struct fp_dev *dev;
	struct session_data *session;
98

Bastien Nocera's avatar
Bastien Nocera committed
99
100
	PolKitContext *pol_ctx;

101
102
103
	/* The current user of the device, if claimed */
	char *sender;

Bastien Nocera's avatar
Bastien Nocera committed
104
105
	/* The current user of the device, or if allowed,
	 * what was passed as a username argument */
106
107
	char *username;

108
109
	/* type of storage */
	int storage_type;
Bastien Nocera's avatar
Bastien Nocera committed
110

111
112
113
	/* Hashtable of connected clients */
	GHashTable *clients;

Bastien Nocera's avatar
Bastien Nocera committed
114
	/* whether we're running an identify, or a verify */
Bastien Nocera's avatar
Bastien Nocera committed
115
	FprintDeviceAction current_action;
Daniel Drake's avatar
Daniel Drake committed
116
117
118
119
120
121
122
123
};

typedef struct FprintDevicePrivate FprintDevicePrivate;

#define DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), FPRINT_TYPE_DEVICE, FprintDevicePrivate))

enum fprint_device_properties {
	FPRINT_DEVICE_CONSTRUCT_DDEV = 1,
124
	FPRINT_DEVICE_IN_USE,
Daniel Drake's avatar
Daniel Drake committed
125
126
};

127
enum fprint_device_signals {
Daniel Drake's avatar
Daniel Drake committed
128
	SIGNAL_VERIFY_STATUS,
Bastien Nocera's avatar
Bastien Nocera committed
129
	SIGNAL_VERIFY_FINGER_SELECTED,
Daniel Drake's avatar
Daniel Drake committed
130
	SIGNAL_ENROLL_STATUS,
131
132
133
	NUM_SIGNALS,
};

Daniel Drake's avatar
Daniel Drake committed
134
135
static GObjectClass *parent_class = NULL;
static guint32 last_id = ~0;
136
static guint signals[NUM_SIGNALS] = { 0, };
Daniel Drake's avatar
Daniel Drake committed
137

138
static void fprint_device_finalize(GObject *object)
Daniel Drake's avatar
Daniel Drake committed
139
{
140
141
142
143
	FprintDevice *self = (FprintDevice *) object;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self);

	g_hash_table_destroy (priv->clients);
Daniel Drake's avatar
Daniel Drake committed
144
145
146
	/* FIXME close and stuff */
}

147
static void fprint_device_set_property(GObject *object, guint property_id,
Daniel Drake's avatar
Daniel Drake committed
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
	const GValue *value, GParamSpec *pspec)
{
	FprintDevice *self = (FprintDevice *) object;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self);

	switch (property_id) {
	case FPRINT_DEVICE_CONSTRUCT_DDEV:
		priv->ddev = g_value_get_pointer(value);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

Bastien Nocera's avatar
Bastien Nocera committed
163
164
165
166
167
168
169
static void fprint_device_get_property(GObject *object, guint property_id,
				       GValue *value, GParamSpec *pspec)
{
	FprintDevice *self = (FprintDevice *) object;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(self);

	switch (property_id) {
170
171
	case FPRINT_DEVICE_IN_USE:
		g_value_set_boolean(value, g_hash_table_size (priv->clients) != 0);
Bastien Nocera's avatar
Bastien Nocera committed
172
173
174
175
176
177
178
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
		break;
	}
}

179
static void fprint_device_class_init(FprintDeviceClass *klass)
Daniel Drake's avatar
Daniel Drake committed
180
181
182
183
184
185
186
187
{
	GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
	GParamSpec *pspec;

	dbus_g_object_type_install_info(FPRINT_TYPE_DEVICE,
		&dbus_glib_fprint_device_object_info);
	parent_class = g_type_class_peek_parent(klass);

188
189
	gobject_class->finalize = fprint_device_finalize;
	gobject_class->set_property = fprint_device_set_property;
Bastien Nocera's avatar
Bastien Nocera committed
190
	gobject_class->get_property = fprint_device_get_property;
191
	g_type_class_add_private(klass, sizeof(FprintDevicePrivate));
Daniel Drake's avatar
Daniel Drake committed
192
193
194
195
196
197

	pspec = g_param_spec_pointer("discovered-dev", "Discovered device",
		"Set discovered device construction property",
		G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE);
	g_object_class_install_property(gobject_class,
		FPRINT_DEVICE_CONSTRUCT_DDEV, pspec);
198
199
200
	pspec = g_param_spec_boolean("in-use", "In use",
				 "Whether the device is currently in use", FALSE,
				 G_PARAM_READABLE);
Bastien Nocera's avatar
Bastien Nocera committed
201
	g_object_class_install_property(gobject_class,
202
					FPRINT_DEVICE_IN_USE, pspec);
Daniel Drake's avatar
Daniel Drake committed
203

Daniel Drake's avatar
Daniel Drake committed
204
205
	signals[SIGNAL_VERIFY_STATUS] = g_signal_new("verify-status",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
206
		g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
Daniel Drake's avatar
Daniel Drake committed
207
	signals[SIGNAL_ENROLL_STATUS] = g_signal_new("enroll-status",
208
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
209
		g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
Bastien Nocera's avatar
Bastien Nocera committed
210
211
	signals[SIGNAL_VERIFY_FINGER_SELECTED] = g_signal_new("verify-finger-selected",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
212
		g_cclosure_marshal_VOID__STRING, G_TYPE_NONE, 1, G_TYPE_STRING);
Daniel Drake's avatar
Daniel Drake committed
213
214
}

Bastien Nocera's avatar
Bastien Nocera committed
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
static gboolean
pk_io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data)
{
	int fd;
	PolKitContext *pk_context = user_data;
	fd = g_io_channel_unix_get_fd (channel);
	polkit_context_io_func (pk_context, fd);
	return TRUE;
}

static int 
pk_io_add_watch (PolKitContext *pk_context, int fd)
{
	guint id = 0;
	GIOChannel *channel;
	channel = g_io_channel_unix_new (fd);
	if (channel == NULL)
		goto out;
	id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context);
	if (id == 0) {
		g_io_channel_unref (channel);
		goto out;
	}
	g_io_channel_unref (channel);
out:
	return id;
}

static void 
pk_io_remove_watch (PolKitContext *pk_context, int watch_id)
{
	g_source_remove (watch_id);
}

249
static void fprint_device_init(FprintDevice *device)
Daniel Drake's avatar
Daniel Drake committed
250
{
251
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device);
Daniel Drake's avatar
Daniel Drake committed
252
	priv->id = ++last_id;
Bastien Nocera's avatar
Bastien Nocera committed
253
254
255
256
257
258
259
260
261

	/* Setup PolicyKit */
	priv->pol_ctx = polkit_context_new ();
	polkit_context_set_io_watch_functions (priv->pol_ctx, pk_io_add_watch, pk_io_remove_watch);
	if (!polkit_context_init (priv->pol_ctx, NULL)) {
		g_critical ("cannot initialize libpolkit");
		polkit_context_unref (priv->pol_ctx);
		priv->pol_ctx = NULL;
	}
262
263
264
265
	priv->clients = g_hash_table_new_full (g_str_hash,
					       g_str_equal,
					       g_free,
					       g_object_unref);
Daniel Drake's avatar
Daniel Drake committed
266
267
}

268
G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT);
Daniel Drake's avatar
Daniel Drake committed
269
270
271
272
273
274
275
276
277
278
279

FprintDevice *fprint_device_new(struct fp_dscv_dev *ddev)
{
	return g_object_new(FPRINT_TYPE_DEVICE, "discovered-dev", ddev, NULL);	
}

guint32 _fprint_device_get_id(FprintDevice *rdev)
{
	return DEVICE_GET_PRIVATE(rdev)->id;
}

280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
static const char *
finger_num_to_name (int finger_num)
{
	if (finger_num == -1)
		return "any";
	if (finger_num < LEFT_THUMB || finger_num > RIGHT_LITTLE)
		return NULL;
	return fingers[finger_num - 1];
}

static int
finger_name_to_num (const char *finger_name)
{
	guint i;

	if (finger_name == NULL || *finger_name == '\0' || g_str_equal (finger_name, "any"))
		return -1;

	for (i = 0; i < G_N_ELEMENTS (fingers); i++) {
		if (g_str_equal (finger_name, fingers[i]))
			return i + 1;
	}

	/* Invalid, let's try that */
	return -1;
}

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
static const char *
verify_result_to_name (int result)
{
	switch (result) {
	case FP_VERIFY_NO_MATCH:
		return "verify-no-match";
	case FP_VERIFY_MATCH:
		return "verify-match";
	case FP_VERIFY_RETRY:
		return "verify-retry-scan";
	case FP_VERIFY_RETRY_TOO_SHORT:
		return "verify-swipe-too-short";
	case FP_VERIFY_RETRY_CENTER_FINGER:
		return "verify-finger-not-centered";
	case FP_VERIFY_RETRY_REMOVE_FINGER:
		return "verify-remove-and-retry";
	default:
		return "verify-unknown-error";
	}
}

static const char *
enroll_result_to_name (int result)
{
	switch (result) {
	case FP_ENROLL_COMPLETE:
		return "enroll-completed";
	case FP_ENROLL_FAIL:
		return "enroll-failed";
	case FP_ENROLL_PASS:
		return "enroll-stage-passed";
	case FP_ENROLL_RETRY:
		return "enroll-retry-scan";
	case FP_ENROLL_RETRY_TOO_SHORT:
		return "enroll-swipe-too-short";
	case FP_ENROLL_RETRY_CENTER_FINGER:
		return "enroll-finger-not-centered";
	case FP_ENROLL_RETRY_REMOVE_FINGER:
		return "enroll-remove-and-retry";
	default:
		return "enroll-unknown-error";
	}
}

351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
static gboolean
_fprint_device_check_claimed (FprintDevice *rdev,
			      DBusGMethodInvocation *context,
			      GError **error)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	DBusConnection *conn;
	char *sender;
	gboolean retval;

	/* The device wasn't claimed, exit */
	if (priv->sender == NULL) {
		g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			     _("Device was not claimed before use"));
		return FALSE;
	}

	conn = dbus_g_connection_get_connection (fprintd_dbus_conn);
	sender = dbus_g_method_get_sender (context);
	retval = g_str_equal (sender, priv->sender);
	g_free (sender);

	if (retval == FALSE) {
		g_set_error (error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
			     _("Device already in use by another user"));
	}

	return retval;
}

Bastien Nocera's avatar
Bastien Nocera committed
381
static gboolean
Bastien Nocera's avatar
Bastien Nocera committed
382
_fprint_device_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action, GError **error)
Bastien Nocera's avatar
Bastien Nocera committed
383
384
385
386
387
388
389
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	const char *sender;
	DBusError dbus_error;
	PolKitCaller *pk_caller;
	PolKitAction *pk_action;
	PolKitResult pk_result;
390
	uid_t uid;
Bastien Nocera's avatar
Bastien Nocera committed
391
392
393
394
395
396
397
398
399

	/* Check that caller is privileged */
	sender = dbus_g_method_get_sender (context);
	dbus_error_init (&dbus_error);
	pk_caller = polkit_caller_new_from_dbus_name (
	    dbus_g_connection_get_connection (fprintd_dbus_conn),
	    sender, 
	    &dbus_error);
	if (pk_caller == NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
400
401
402
403
		g_set_error (error, FPRINT_ERROR,
			     FPRINT_ERROR_INTERNAL,
			     "Error getting information about caller: %s: %s",
			     dbus_error.name, dbus_error.message);
Bastien Nocera's avatar
Bastien Nocera committed
404
405
406
407
		dbus_error_free (&dbus_error);
		return FALSE;
	}

408
409
410
411
412
413
414
415
416
417
418
	/* XXX Hack?
	 * We'd like to allow root to set the username by default, so
	 * it can authenticate users through PAM
	 * https://bugzilla.redhat.com/show_bug.cgi?id=447266 */
	if ((polkit_caller_get_uid (pk_caller, &uid) && uid == 0) &&
	    (g_str_equal (action, "net.reactivated.fprint.device.setusername") ||
	     g_str_equal (action, "net.reactivated.fprint.device.verify"))) {
		polkit_caller_unref (pk_caller);
		return TRUE;
	}

Bastien Nocera's avatar
Bastien Nocera committed
419
420
421
	pk_action = polkit_action_new ();
	polkit_action_set_action_id (pk_action, action);
	pk_result = polkit_context_is_caller_authorized (priv->pol_ctx, pk_action, pk_caller,
Bastien Nocera's avatar
Bastien Nocera committed
422
							 TRUE, NULL);
Bastien Nocera's avatar
Bastien Nocera committed
423
424
425
426
	polkit_caller_unref (pk_caller);
	polkit_action_unref (pk_action);

	if (pk_result != POLKIT_RESULT_YES) {
Bastien Nocera's avatar
Bastien Nocera committed
427
428
429
430
431
		g_set_error (error, FPRINT_ERROR,
			     FPRINT_ERROR_INTERNAL,
			     "%s %s <-- (action, result)",
			     action,
			     polkit_result_to_string_representation (pk_result));
Bastien Nocera's avatar
Bastien Nocera committed
432
433
434
435
436
437
438
		dbus_error_free (&dbus_error);
		return FALSE;
	}

	return TRUE;
}

Bastien Nocera's avatar
Bastien Nocera committed
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
static gboolean
_fprint_device_check_polkit_for_actions (FprintDevice *rdev,
					 DBusGMethodInvocation *context,
					 const char *action1,
					 const char *action2,
					 GError **error)
{
	if (_fprint_device_check_polkit_for_action (rdev, context, action1, error) != FALSE)
		return TRUE;

	g_error_free (*error);
	*error = NULL;

	return _fprint_device_check_polkit_for_action (rdev, context, action2, error);
}

455
456
457
458
459
460
static char *
_fprint_device_check_for_username (FprintDevice *rdev,
				   DBusGMethodInvocation *context,
				   const char *username,
				   char **ret_sender,
				   GError **error)
Bastien Nocera's avatar
Bastien Nocera committed
461
{
462
463
464
465
466
467
	DBusConnection *conn;
	DBusError dbus_error;
	char *sender;
	unsigned long uid;
	struct passwd *user;
	char *client_username;
Bastien Nocera's avatar
Bastien Nocera committed
468

469
470
471
472
473
	/* Get details about the current sender, and username/uid */
	conn = dbus_g_connection_get_connection (fprintd_dbus_conn);
	sender = dbus_g_method_get_sender (context);
	dbus_error_init (&dbus_error);
	uid = dbus_bus_get_unix_user (conn, sender, &dbus_error);
Bastien Nocera's avatar
Bastien Nocera committed
474

475
476
477
478
	if (dbus_error_is_set(&dbus_error)) {
		g_free (sender);
		dbus_set_g_error (error, &dbus_error);
		return NULL;
Bastien Nocera's avatar
Bastien Nocera committed
479
480
	}

481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
	user = getpwuid (uid);
	if (user == NULL) {
		g_free (sender);
		g_set_error(error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			    "Failed to get information about user UID %lu", uid);
		return NULL;
	}
	client_username = g_strdup (user->pw_name);

	/* The current user is usually allowed to access their
	 * own data, this should be followed by PolicyKit checks
	 * anyway */
	if (username == NULL || *username == '\0' || g_str_equal (username, client_username)) {
		if (ret_sender != NULL)
			*ret_sender = sender;
		else
			g_free (sender);
		return client_username;
	}

	/* If we're not allowed to set a different username,
	 * then fail */
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.setusername", error) == FALSE) {
		g_free (sender);
		return NULL;
Bastien Nocera's avatar
Bastien Nocera committed
506
507
	}

508
509
510
511
	if (ret_sender != NULL)
		*ret_sender = sender;
	else
		g_free (sender);
Bastien Nocera's avatar
Bastien Nocera committed
512

513
	return g_strdup (username);
Bastien Nocera's avatar
Bastien Nocera committed
514
515
}

516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
static void action_stop_cb(struct fp_dev *dev, void *user_data)
{
	gboolean *done = (gboolean *) user_data;
	*done = TRUE;
}

static void
_fprint_device_client_disconnected (EggDbusMonitor *monitor, gboolean connected, FprintDevice *rdev)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);

	if (connected == FALSE) {
		const char *sender;
		sender = egg_dbus_monitor_get_service (monitor);

		/* Was that the client that claimed the device? */
		if (priv->sender != NULL) {
			gboolean done = FALSE;
			switch (priv->current_action) {
			case ACTION_NONE:
				break;
			case ACTION_IDENTIFY:
				fp_async_identify_stop(priv->dev, action_stop_cb, &done);
				while (done == FALSE)
					g_main_context_iteration (NULL, TRUE);
				break;
			case ACTION_VERIFY:
				fp_async_verify_stop(priv->dev, action_stop_cb, &done);
				while (done == FALSE)
					g_main_context_iteration (NULL, TRUE);
				break;
			case ACTION_ENROLL:
				fp_async_enroll_stop(priv->dev, action_stop_cb, &done);
				while (done == FALSE)
					g_main_context_iteration (NULL, TRUE);
				break;
			}
			priv->current_action = ACTION_NONE;
			done = FALSE;

			/* Close the claimed device as well */
			fp_async_dev_close (priv->dev, action_stop_cb, &done);
			while (done == FALSE)
				g_main_context_iteration (NULL, TRUE);

			g_free (priv->sender);
			priv->sender = NULL;
			g_free (priv->username);
			priv->username = NULL;
		}
		g_hash_table_remove (priv->clients, sender);
	}

	if (g_hash_table_size (priv->clients) == 0) {
		g_object_notify (G_OBJECT (rdev), "in-use");
	}
}

static void
_fprint_device_add_client (FprintDevice *rdev, const char *sender)
{
	EggDbusMonitor *monitor;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);

	monitor = g_hash_table_lookup (priv->clients, sender);
	if (monitor == NULL) {
		monitor = egg_dbus_monitor_new ();
		egg_dbus_monitor_assign (monitor, fprintd_dbus_conn, sender);
		//FIXME handle replaced
		g_signal_connect (G_OBJECT (monitor), "connection-changed",
					 G_CALLBACK (_fprint_device_client_disconnected), rdev);
		g_hash_table_insert (priv->clients, g_strdup (sender), monitor);
		g_object_notify (G_OBJECT (rdev), "in-use");
	}
}

Daniel Drake's avatar
Daniel Drake committed
592
593
594
595
596
597
598
599
600
601
static void dev_open_cb(struct fp_dev *dev, int status, void *user_data)
{
	FprintDevice *rdev = user_data;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;

	g_message("device %d claim status %d", priv->id, status);

	if (status != 0) {
		GError *error;
602
603
604
605

		g_free (priv->sender);
		priv->sender = NULL;

Daniel Drake's avatar
Daniel Drake committed
606
607
608
609
610
611
612
613
614
615
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			"Open failed with error %d", status);
		dbus_g_method_return_error(session->context_claim_device, error);
		return;
	}

	priv->dev = dev;
	dbus_g_method_return(session->context_claim_device);
}

Bastien Nocera's avatar
Bastien Nocera committed
616
static void fprint_device_claim(FprintDevice *rdev,
617
618
				const char *username,
				DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
619
620
621
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
622
	char *sender, *user;
Daniel Drake's avatar
Daniel Drake committed
623
624
	int r;

625
	/* Is it already claimed? */
626
627
628
629
	if (priv->sender != NULL) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			    "Device was already claimed");
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
630
		return;
631
632
	}

633
634
	g_assert (priv->username == NULL);
	g_assert (priv->sender == NULL);
Bastien Nocera's avatar
Bastien Nocera committed
635

636
637
638
639
640
641
642
	sender = NULL;
	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  &sender,
						  &error);
	if (user == NULL) {
643
		g_free (sender);
644
		dbus_g_method_return_error (context, error);
645
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
646
		return;
647
648
	}

649
650
651
652
	if (_fprint_device_check_polkit_for_actions (rdev, context,
						     "net.reactivated.fprint.device.verify",
						     "net.reactivated.fprint.device.enroll",
						     &error) == FALSE) {
653
		g_free (sender);
654
655
		g_free (user);
		dbus_g_method_return_error (context, error);
656
657
658
		return;
	}

659
660
	_fprint_device_add_client (rdev, sender);

661
	priv->username = user;
662
663
	priv->sender = sender;

Bastien Nocera's avatar
Bastien Nocera committed
664
	g_message ("user '%s' claiming the device: %d", priv->username, priv->id);
665

Daniel Drake's avatar
Daniel Drake committed
666
667
668
669
670
671
672
	priv->session = g_slice_new0(struct session_data);
	priv->session->context_claim_device = context;

	r = fp_async_dev_open(priv->ddev, dev_open_cb, rdev);
	if (r < 0) {
		g_slice_free(struct session_data, priv->session);
		priv->session = NULL;
673
674
675
676
677
678

		g_free (priv->username);
		priv->username = NULL;
		g_free (priv->sender);
		priv->sender = NULL;

Daniel Drake's avatar
Daniel Drake committed
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_CLAIM_DEVICE,
			"Could not attempt device open, error %d", r);
		dbus_g_method_return_error(context, error);
	}
}

static void dev_close_cb(struct fp_dev *dev, void *user_data)
{
	FprintDevice *rdev = user_data;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
	DBusGMethodInvocation *context = session->context_release_device;

	priv->dev = NULL;
	g_slice_free(struct session_data, session);
	priv->session = NULL;

696
697
698
	g_free (priv->sender);
	priv->sender = NULL;

699
700
701
	g_free (priv->username);
	priv->username = NULL;

Daniel Drake's avatar
Daniel Drake committed
702
703
704
705
	g_message("released device %d", priv->id);
	dbus_g_method_return(context);
}

Bastien Nocera's avatar
Bastien Nocera committed
706
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
707
708
709
710
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
711
712
713
714
	GError *error = NULL;

	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
715
		return;
716
	}
Daniel Drake's avatar
Daniel Drake committed
717

Bastien Nocera's avatar
Bastien Nocera committed
718
719
720
721
722
723
724
725
726
	/* People that can claim can also release */
	if (_fprint_device_check_polkit_for_actions (rdev, context,
						     "net.reactivated.fprint.device.verify",
						     "net.reactivated.fprint.device.enroll",
						     &error) == FALSE) {
		dbus_g_method_return_error (context, error);
		return;
	}

Daniel Drake's avatar
Daniel Drake committed
727
728
729
730
731
	session->context_release_device = context;
	fp_async_dev_close(priv->dev, dev_close_cb, rdev);
}

static void verify_cb(struct fp_dev *dev, int r, struct fp_img *img,
Bastien Nocera's avatar
Bastien Nocera committed
732
733
734
		      void *user_data)
{
	struct FprintDevice *rdev = user_data;
735
736
	const char *name = verify_result_to_name (r);
	g_message("verify_cb: result %s (%d)", name, r);
Bastien Nocera's avatar
Bastien Nocera committed
737

738
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name);
Bastien Nocera's avatar
Bastien Nocera committed
739
740
741
742
743
	fp_img_free(img);
}

static void identify_cb(struct fp_dev *dev, int r,
			 size_t match_offset, struct fp_img *img, void *user_data)
Daniel Drake's avatar
Daniel Drake committed
744
745
{
	struct FprintDevice *rdev = user_data;
746
747
	const char *name = verify_result_to_name (r);
	g_message("identify_cb: result %s (%d)", name, r);
Daniel Drake's avatar
Daniel Drake committed
748

749
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, name);
750
	fp_img_free(img);
Daniel Drake's avatar
Daniel Drake committed
751
752
}

Bastien Nocera's avatar
Bastien Nocera committed
753
static void fprint_device_verify_start(FprintDevice *rdev,
754
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
755
756
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
Bastien Nocera's avatar
Bastien Nocera committed
757
	struct fp_print_data **gallery = NULL;
Daniel Drake's avatar
Daniel Drake committed
758
	struct fp_print_data *data = NULL;
759
	GError *error = NULL;
760
	guint finger_num = finger_name_to_num (finger_name);
Daniel Drake's avatar
Daniel Drake committed
761
762
	int r;

763
764
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
765
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
766
		return;
767
768
	}

Bastien Nocera's avatar
Bastien Nocera committed
769
770
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
771
772
773
774
775
		g_error_free (error);
		return;
	}

	if (priv->current_action != ACTION_NONE) {
Bastien Nocera's avatar
Bastien Nocera committed
776
777
778
779
780
781
782
		if (priv->current_action == ACTION_ENROLL) {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
				    "Enrollment in progress");
		} else {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
				    "Verification already in progress");
		}
Bastien Nocera's avatar
Bastien Nocera committed
783
784
		dbus_g_method_return_error(context, error);
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
785
786
787
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
788
789
790
791
792
	if (finger_num == -1) {
		GSList *prints;

		prints = store.discover_prints(priv->ddev, priv->username);
		if (prints == NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
793
794
795
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
				    "No fingerprints enrolled");
			dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
796
797
798
799
800
801
802
803
804
			return;
		}
		if (fp_dev_supports_identification(priv->dev)) {
			GSList *l;
			GPtrArray *array;

			array = g_ptr_array_new ();

			for (l = prints; l != NULL; l = l->next) {
Bastien Nocera's avatar
Bastien Nocera committed
805
806
				g_message ("adding finger %d to the gallery", GPOINTER_TO_INT (l->data));
				r = store.print_data_load(priv->dev, GPOINTER_TO_INT (l->data),
Bastien Nocera's avatar
Bastien Nocera committed
807
808
809
810
811
							  &data, priv->username);
				//FIXME r < 0 ?
				g_ptr_array_add (array, data);
			}
			data = NULL;
Bastien Nocera's avatar
Bastien Nocera committed
812
813
814
815
816
817
818

			if (array->len > 0) {
				g_ptr_array_add (array,  NULL);
				gallery = (struct fp_print_data **) g_ptr_array_free (array, FALSE);
			} else {
				gallery = NULL;
			}
Bastien Nocera's avatar
Bastien Nocera committed
819
		} else {
Bastien Nocera's avatar
Bastien Nocera committed
820
			finger_num = GPOINTER_TO_INT (prints->data);
Bastien Nocera's avatar
Bastien Nocera committed
821
822
		}
		g_slist_free(prints);
Daniel Drake's avatar
Daniel Drake committed
823
	}
Bastien Nocera's avatar
Bastien Nocera committed
824

Bastien Nocera's avatar
Bastien Nocera committed
825
	if (fp_dev_supports_identification(priv->dev) && finger_num == -1) {
Bastien Nocera's avatar
Bastien Nocera committed
826
		if (gallery == NULL) {
827
828
829
830
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
				    "No fingerprints on that device");
			dbus_g_method_return_error(context, error);
			g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
831
832
			return;
		}
833
		priv->current_action = ACTION_IDENTIFY;
Bastien Nocera's avatar
Bastien Nocera committed
834
835
836
837
838

		g_message ("start identification device %d", priv->id);
		//FIXME we're supposed to free the gallery here?
		r = fp_async_identify_start (priv->dev, gallery, identify_cb, rdev);
	} else {
839
		priv->current_action = ACTION_VERIFY;
Bastien Nocera's avatar
Bastien Nocera committed
840
841
842
843
844
845
846
847
848
849
850
851

		g_message("start verification device %d finger %d", priv->id, finger_num);

		r = store.print_data_load(priv->dev, (enum fp_finger)finger_num, 
					  &data, priv->username);

		if (r < 0 || !data) {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
				    "No such print %d", finger_num);
			dbus_g_method_return_error(context, error);
			return;
		}
Bastien Nocera's avatar
Bastien Nocera committed
852

Bastien Nocera's avatar
Bastien Nocera committed
853
854
855
856
		/* FIXME fp_async_verify_start should copy the fp_print_data */
		r = fp_async_verify_start(priv->dev, data, verify_cb, rdev);
	}

857
858
	/* Emit VerifyFingerSelected telling the front-end which finger
	 * we selected for auth */
859
860
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_FINGER_SELECTED],
		      0, finger_num_to_name (finger_num));
861
862


Daniel Drake's avatar
Daniel Drake committed
863
	if (r < 0) {
Bastien Nocera's avatar
Bastien Nocera committed
864
865
866
867
868
869
870
871
		if (data != NULL) {
			fp_print_data_free (data);
		} else if (gallery != NULL) {
			guint i;
			for (i = 0; gallery[i] != NULL; i++)
				fp_print_data_free(gallery[i]);
			g_free (gallery);
		}
872
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_START,
Daniel Drake's avatar
Daniel Drake committed
873
			"Verify start failed with error %d", r);
874
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
875
		return;
Daniel Drake's avatar
Daniel Drake committed
876
877
	}

878
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
879
880
881
882
883
884
885
}

static void verify_stop_cb(struct fp_dev *dev, void *user_data)
{
	dbus_g_method_return((DBusGMethodInvocation *) user_data);
}

Bastien Nocera's avatar
Bastien Nocera committed
886
887
888
889
890
static void identify_stop_cb(struct fp_dev *dev, void *user_data)
{
	dbus_g_method_return((DBusGMethodInvocation *) user_data);
}

Bastien Nocera's avatar
Bastien Nocera committed
891
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
892
893
894
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
895
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
896
897
	int r;

898
899
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
900
		return;
901
902
	}

Bastien Nocera's avatar
Bastien Nocera committed
903
904
905
906
907
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
		dbus_g_method_return_error (context, error);
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
908
	if (priv->current_action == ACTION_VERIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
909
		r = fp_async_verify_stop(priv->dev, verify_stop_cb, context);
Bastien Nocera's avatar
Bastien Nocera committed
910
	} else if (priv->current_action == ACTION_IDENTIFY) {
Bastien Nocera's avatar
Bastien Nocera committed
911
		r = fp_async_identify_stop(priv->dev, identify_stop_cb, context);
Bastien Nocera's avatar
Bastien Nocera committed
912
913
914
915
916
917
	} else {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_STOP,
			    "No verification in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
Bastien Nocera's avatar
Bastien Nocera committed
918
	}
Bastien Nocera's avatar
Bastien Nocera committed
919

Daniel Drake's avatar
Daniel Drake committed
920
921
922
923
	if (r < 0) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_STOP,
			"Verify stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
924
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
925
	}
Bastien Nocera's avatar
Bastien Nocera committed
926

927
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
928
929
}

Daniel Drake's avatar
Daniel Drake committed
930
931
932
933
934
935
static void enroll_stage_cb(struct fp_dev *dev, int result,
	struct fp_print_data *print, struct fp_img *img, void *user_data)
{
	struct FprintDevice *rdev = user_data;
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
Bastien Nocera's avatar
Bastien Nocera committed
936
	int r;
Daniel Drake's avatar
Daniel Drake committed
937
938

	g_message("enroll_stage_cb: result %d", result);
Bastien Nocera's avatar
Bastien Nocera committed
939
	if (result == FP_ENROLL_COMPLETE) {
940
		r = store.print_data_save(print, session->enroll_finger, priv->username);
Bastien Nocera's avatar
Bastien Nocera committed
941
942
943
		if (r < 0)
			result = FP_ENROLL_FAIL;
	}
Daniel Drake's avatar
Daniel Drake committed
944

945
	g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, enroll_result_to_name (result));
Daniel Drake's avatar
Daniel Drake committed
946
947
948
949
	fp_img_free(img);
	fp_print_data_free(print);
}

Bastien Nocera's avatar
Bastien Nocera committed
950
static void fprint_device_enroll_start(FprintDevice *rdev,
951
	const char *finger_name, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
952
953
954
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
955
	int finger_num = finger_name_to_num (finger_name);
956
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
957
958
	int r;

959
960
961
962
963
964
965
966
	if (finger_num == -1) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
			    "Invalid print name");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

967
968
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
969
		return;
970
971
	}

Bastien Nocera's avatar
Bastien Nocera committed
972
973
974
975
976
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
		dbus_g_method_return_error (context, error);
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
977
978
979
980
981
982
983
984
985
986
987
988
989
	if (priv->current_action != ACTION_NONE) {
		if (priv->current_action == ACTION_ENROLL) {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
				    "Enrollment already in progress");
		} else {
			g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ALREADY_IN_USE,
				    "Verification in progress");
		}
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

Daniel Drake's avatar
Daniel Drake committed
990
991
992
993
994
	g_message("start enrollment device %d finger %d", priv->id, finger_num);
	session->enroll_finger = finger_num;
	
	r = fp_async_enroll_start(priv->dev, enroll_stage_cb, rdev);
	if (r < 0) {
995
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_START,
Daniel Drake's avatar
Daniel Drake committed
996
			"Enroll start failed with error %d", r);
997
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
998
		return;
Daniel Drake's avatar
Daniel Drake committed
999
1000
	}

1001
	priv->current_action = ACTION_ENROLL;
Bastien Nocera's avatar
Bastien Nocera committed
1002

1003
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
1004
1005
1006
1007
1008
1009
1010
}

static void enroll_stop_cb(struct fp_dev *dev, void *user_data)
{
	dbus_g_method_return((DBusGMethodInvocation *) user_data);
}

Bastien Nocera's avatar
Bastien Nocera committed
1011
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
1012
1013
1014
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1015
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
1016
1017
	int r;

1018
1019
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1020
		return;
1021
1022
	}

Bastien Nocera's avatar
Bastien Nocera committed
1023
1024
1025
1026
1027
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
		dbus_g_method_return_error (context, error);
		return;
	}

Bastien Nocera's avatar
Bastien Nocera committed
1028
1029
1030
1031
1032
1033
1034
1035
	if (priv->current_action != ACTION_ENROLL) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_STOP,
			    "No enrollment in progress");
		dbus_g_method_return_error(context, error);
		g_error_free (error);
		return;
	}

Daniel Drake's avatar
Daniel Drake committed
1036
1037
1038
1039
1040
	r = fp_async_enroll_stop(priv->dev, enroll_stop_cb, context);
	if (r < 0) {
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_STOP,
			"Enroll stop failed with error %d", r);
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1041
		g_error_free (error);
Daniel Drake's avatar
Daniel Drake committed
1042
	}
Bastien Nocera's avatar
Bastien Nocera committed
1043

1044
	priv->current_action = ACTION_NONE;
Daniel Drake's avatar
Daniel Drake committed
1045
1046
}

1047
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
1048
1049
						const char *username,
						DBusGMethodInvocation *context)
1050
1051
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
1052
	GError *error = NULL;
1053
1054
	GSList *prints;
	GSList *item;
1055
	GPtrArray *ret;
1056
	char *user, *sender;
1057
1058
1059
1060
1061
1062
1063

	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  NULL,
						  &error);
	if (user == NULL) {
1064
		dbus_g_method_return_error (context, error);
1065
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
1066
		return;
1067
1068
	}

Bastien Nocera's avatar
Bastien Nocera committed
1069
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.verify", &error) == FALSE) {
1070
		g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1071
1072
1073
1074
		dbus_g_method_return_error (context, error);
		return;
	}

1075
1076
1077
1078
	sender = dbus_g_method_get_sender (context);
	_fprint_device_add_client (rdev, sender);
	g_free (sender);

1079
1080
	prints = store.discover_prints(priv->ddev, user);
	g_free (user);
1081
	if (!prints) {
1082
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_DISCOVER_PRINTS,
1083
			"Failed to discover prints");
1084
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
1085
		return;
1086
1087
	}

1088
	ret = g_ptr_array_new ();
1089
	for (item = prints; item; item = item->next) {
1090
1091
		int finger_num = GPOINTER_TO_INT (item->data);
		g_ptr_array_add (ret, g_strdup (finger_num_to_name (finger_num)));
1092
	}
1093
	g_ptr_array_add (ret, NULL);
1094
1095

	g_slist_free(prints);
1096

1097
	dbus_g_method_return(context, g_ptr_array_free (ret, FALSE));
1098
1099
}

Bastien Nocera's avatar
Bastien Nocera committed
1100
static void fprint_device_delete_enrolled_fingers(FprintDevice *rdev,
1101
						  const char *username,
Bastien Nocera's avatar
Bastien Nocera committed
1102
1103
1104
1105
1106
						  DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
	guint i;
1107
	char *user, *sender;
Bastien Nocera's avatar
Bastien Nocera committed
1108

1109
1110
1111
1112
1113
1114
	user = _fprint_device_check_for_username (rdev,
						  context,
						  username,
						  NULL,
						  &error);
	if (user == NULL) {
Bastien Nocera's avatar
Bastien Nocera committed
1115
		dbus_g_method_return_error (context, error);
1116
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
1117
1118
1119
		return;
	}

1120
	if (_fprint_device_check_polkit_for_action (rdev, context, "net.reactivated.fprint.device.enroll", &error) == FALSE) {
1121
		g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1122
1123
1124
1125
		dbus_g_method_return_error (context, error);
		return;
	}

1126
1127
1128
1129
	sender = dbus_g_method_get_sender (context);
	_fprint_device_add_client (rdev, sender);
	g_free (sender);

Bastien Nocera's avatar
Bastien Nocera committed
1130
	for (i = LEFT_THUMB; i <= RIGHT_LITTLE; i++) {
1131
		store.print_data_delete(priv->ddev, i, user);
Bastien Nocera's avatar
Bastien Nocera committed
1132
	}
1133
	g_free (user);
Bastien Nocera's avatar
Bastien Nocera committed
1134
1135
1136
1137

	dbus_g_method_return(context);
}

Bastien Nocera's avatar
Bastien Nocera committed
1138
1139
static void fprint_device_get_properties (FprintDevice *rdev,
					  DBusGMethodInvocation *context)
Bastien Nocera's avatar
Bastien Nocera committed
1140
1141
1142
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GHashTable *table;
1143
	GValue *value;
Bastien Nocera's avatar
Bastien Nocera committed
1144
1145
1146

	table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);

1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
	value = g_new0 (GValue, 1);
	g_value_init (value, G_TYPE_STRING);
	g_value_set_string (value, fp_driver_get_full_name (fp_dscv_dev_get_driver (priv->ddev)));
	g_hash_table_insert (table, "Name", value);

	value = g_new0 (GValue, 1);
	g_value_init (value, G_TYPE_STRING);
	g_value_set_static_string (value,
				   fp_driver_get_scan_type (fp_dscv_dev_get_driver (priv->ddev)) == FP_SCAN_TYPE_PRESS ? "press" : "swipe");
	g_hash_table_insert (table, "ScanType", value);

	if (priv->dev != NULL) {
		value = g_new0 (GValue, 1);
		g_value_init (value, G_TYPE_INT);
		g_value_set_int (value, fp_dev_get_nr_enroll_stages (priv->dev));
		g_hash_table_insert (table, "NumberEnrollStages", value);
	}
Bastien Nocera's avatar
Bastien Nocera committed
1164

Bastien Nocera's avatar
Bastien Nocera committed
1165
	dbus_g_method_return (context, table);
1166
1167

	g_hash_table_destroy (table);
Bastien Nocera's avatar
Bastien Nocera committed
1168
1169
}