device.c 19.8 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"
Daniel Drake's avatar
Daniel Drake committed
34

35 36
extern DBusGConnection *fprintd_dbus_conn;

Bastien Nocera's avatar
Bastien Nocera committed
37
static void fprint_device_claim(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
38
	DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
39
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
40
	DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
41
static void fprint_device_unload_print_data(FprintDevice *rdev,
42
	guint32 print_id, DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
43
static void fprint_device_verify_start(FprintDevice *rdev,
44
	guint32 print_id, DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
45
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
46
	DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
47
static void fprint_device_enroll_start(FprintDevice *rdev,
48
	guint32 finger_num, DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
49
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
50
	DBusGMethodInvocation *context);
51 52
static gboolean fprint_device_set_storage_type(FprintDevice *rdev,
	gint type);
53 54
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev, 
	DBusGMethodInvocation *context);
Bastien Nocera's avatar
Bastien Nocera committed
55 56
static void fprint_device_load_print_data(FprintDevice *rdev,
	guint32 finger_num, DBusGMethodInvocation *context);
Daniel Drake's avatar
Daniel Drake committed
57 58 59 60

#include "device-dbus-glue.h"

struct session_data {
Daniel Drake's avatar
Daniel Drake committed
61 62 63
	/* finger being enrolled */
	int enroll_finger;

Daniel Drake's avatar
Daniel Drake committed
64 65 66 67 68 69 70 71
	/* method invocation for async ClaimDevice() */
	DBusGMethodInvocation *context_claim_device;

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

	/* a list of loaded prints */
	GSList *loaded_prints;
72

Daniel Drake's avatar
Daniel Drake committed
73 74 75 76 77 78 79 80 81 82 83 84
};

struct loaded_print {
	guint32 id;
	struct fp_print_data *data;
};

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

Bastien Nocera's avatar
Bastien Nocera committed
86 87
	PolKitContext *pol_ctx;

88 89 90
	/* The current user of the device, if claimed */
	char *sender;

91 92 93 94 95
	/* Either the current user of the device, or if allowed,
	 * what was set using SetCurrentUid */
	char *username;
	uid_t uid;

96 97
	/* type of storage */
	int storage_type;
Daniel Drake's avatar
Daniel Drake committed
98 99 100 101 102 103 104 105 106 107
};

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,
};

108
enum fprint_device_signals {
Daniel Drake's avatar
Daniel Drake committed
109 110
	SIGNAL_VERIFY_STATUS,
	SIGNAL_ENROLL_STATUS,
111 112 113
	NUM_SIGNALS,
};

Daniel Drake's avatar
Daniel Drake committed
114 115
static GObjectClass *parent_class = NULL;
static guint32 last_id = ~0;
116
static guint signals[NUM_SIGNALS] = { 0, };
Daniel Drake's avatar
Daniel Drake committed
117

118
static void fprint_device_finalize(GObject *object)
Daniel Drake's avatar
Daniel Drake committed
119 120 121 122
{
	/* FIXME close and stuff */
}

123
static void fprint_device_set_property(GObject *object, guint property_id,
Daniel Drake's avatar
Daniel Drake committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
	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;
	}
}

139
static void fprint_device_class_init(FprintDeviceClass *klass)
Daniel Drake's avatar
Daniel Drake committed
140 141 142 143 144 145 146 147
{
	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);

148 149
	gobject_class->finalize = fprint_device_finalize;
	gobject_class->set_property = fprint_device_set_property;
150
	g_type_class_add_private(klass, sizeof(FprintDevicePrivate));
Daniel Drake's avatar
Daniel Drake committed
151 152 153 154 155 156 157

	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);

Daniel Drake's avatar
Daniel Drake committed
158 159 160 161
	signals[SIGNAL_VERIFY_STATUS] = g_signal_new("verify-status",
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
		g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
	signals[SIGNAL_ENROLL_STATUS] = g_signal_new("enroll-status",
162 163
		G_TYPE_FROM_CLASS(gobject_class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
		g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
Daniel Drake's avatar
Daniel Drake committed
164 165
}

Bastien Nocera's avatar
Bastien Nocera committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
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);
}

200
static void fprint_device_init(FprintDevice *device)
Daniel Drake's avatar
Daniel Drake committed
201
{
202
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(device);
Daniel Drake's avatar
Daniel Drake committed
203
	priv->id = ++last_id;
204 205
	priv->storage_type = FP_FILE_STORAGE;
	storages[priv->storage_type].init();
Bastien Nocera's avatar
Bastien Nocera committed
206 207 208 209 210 211 212 213 214

	/* 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;
	}
Daniel Drake's avatar
Daniel Drake committed
215 216
}

217
G_DEFINE_TYPE(FprintDevice, fprint_device, G_TYPE_OBJECT);
Daniel Drake's avatar
Daniel Drake committed
218 219 220 221 222 223 224 225 226 227 228

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;
}

229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
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
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 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 307 308 309 310 311
static gboolean
_check_polkit_for_action (FprintDevice *rdev, DBusGMethodInvocation *context, const char *action)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	const char *sender;
	GError *error;
	DBusError dbus_error;
	PolKitCaller *pk_caller;
	PolKitAction *pk_action;
	PolKitResult pk_result;

	error = NULL;

	/* 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) {
		error = g_error_new (FPRINT_ERROR,
				     FPRINT_ERROR_INTERNAL,
				     "Error getting information about caller: %s: %s",
				     dbus_error.name, dbus_error.message);
		dbus_error_free (&dbus_error);
		dbus_g_method_return_error (context, error);
		g_error_free (error);
		return FALSE;
	}

	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,
							 FALSE, NULL);
	polkit_caller_unref (pk_caller);
	polkit_action_unref (pk_action);

	if (pk_result != POLKIT_RESULT_YES) {
		error = g_error_new (FPRINT_ERROR,
				     FPRINT_ERROR_INTERNAL,
				     "%s %s <-- (action, result)",
				     action,
				     polkit_result_to_string_representation (pk_result));
		dbus_error_free (&dbus_error);
		dbus_g_method_return_error (context, error);
		g_error_free (error);
		return FALSE;
	}

	return TRUE;
}

Daniel Drake's avatar
Daniel Drake committed
312 313 314 315 316 317 318 319 320 321
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;
322 323 324 325

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

Daniel Drake's avatar
Daniel Drake committed
326 327 328 329 330 331 332 333 334 335
		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
336
static void fprint_device_claim(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
337 338 339 340
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	GError *error = NULL;
341 342 343 344
	DBusConnection *conn;
	DBusError dbus_error;
	char *sender;
	unsigned long uid;
345
	struct passwd *user;
Daniel Drake's avatar
Daniel Drake committed
346 347
	int r;

348
	/* Is it already claimed? */
349 350 351 352
	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
353
		return;
354 355
	}

356
	/* Get details about the current sender, and username/uid */
357 358 359 360 361 362 363 364 365 366
	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);

	if (dbus_error_is_set(&dbus_error)) {
		g_free (sender);
		dbus_set_g_error (&error, &dbus_error);
		dbus_g_method_return_error(context, error);
		g_error_free (error);
Bastien Nocera's avatar
Bastien Nocera committed
367
		return;
368 369
	}

370 371 372 373 374 375 376 377 378 379
	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);
		dbus_g_method_return_error(context, error);
		return;
	}

	priv->username = g_strdup (user->pw_name);
380 381
	priv->sender = sender;

382
	g_message ("user claiming the device: %s (%ld)", priv->username, uid);
383 384
	/* FIXME call polkit to check whether allowed */

Daniel Drake's avatar
Daniel Drake committed
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
	g_message("claiming device %d", priv->id);
	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;
		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;

410 411 412
	g_free (priv->sender);
	priv->sender = NULL;

413 414 415
	g_free (priv->username);
	priv->username = NULL;

Daniel Drake's avatar
Daniel Drake committed
416 417 418 419
	g_message("released device %d", priv->id);
	dbus_g_method_return(context);
}

Bastien Nocera's avatar
Bastien Nocera committed
420
static void fprint_device_release(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
421 422 423 424 425
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
	GSList *elem = session->loaded_prints;
426 427 428 429
	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
430
		return;
431
	}
Daniel Drake's avatar
Daniel Drake committed
432 433 434 435 436 437 438 439 440 441 442 443 444

	/* Unload any loaded prints */
	if (elem) {
		do
			g_slice_free(struct loaded_print, elem->data);
		while ((elem = g_slist_next(elem)) != NULL);
		g_slist_free(session->loaded_prints);
	}

	session->context_release_device = context;
	fp_async_dev_close(priv->dev, dev_close_cb, rdev);
}

Bastien Nocera's avatar
Bastien Nocera committed
445
static void fprint_device_unload_print_data(FprintDevice *rdev,
446
	guint32 print_id, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
447 448 449 450
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
	GSList *elem = session->loaded_prints;
451 452 453 454
	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
455
		return;
456
	}
Daniel Drake's avatar
Daniel Drake committed
457 458 459

	g_message("unload print data %d for device %d", print_id, priv->id);
	if (!elem) {
460
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
Daniel Drake's avatar
Daniel Drake committed
461
			"No such loaded print %d", print_id);
462
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
463
		return;
Daniel Drake's avatar
Daniel Drake committed
464 465 466 467 468 469 470 471 472 473
	}

	do {
		struct loaded_print *print = elem->data;
		if (print->id != print_id)
			continue;

		session->loaded_prints = g_slist_delete_link(session->loaded_prints,
			elem);
		g_slice_free(struct loaded_print, print);
474
		dbus_g_method_return(context);
Bastien Nocera's avatar
Bastien Nocera committed
475
		return;
Daniel Drake's avatar
Daniel Drake committed
476 477
	} while ((elem = g_slist_next(elem)) != NULL);

478
	g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
Daniel Drake's avatar
Daniel Drake committed
479
		"No such loaded print %d", print_id);
480
	dbus_g_method_return_error(context, error);
Daniel Drake's avatar
Daniel Drake committed
481 482 483 484 485 486 487 488
}

static void verify_cb(struct fp_dev *dev, int r, struct fp_img *img,
	void *user_data)
{
	struct FprintDevice *rdev = user_data;
	g_message("verify_cb: result %d", r);

Daniel Drake's avatar
Daniel Drake committed
489
	g_signal_emit(rdev, signals[SIGNAL_VERIFY_STATUS], 0, r);
490
	fp_img_free(img);
Daniel Drake's avatar
Daniel Drake committed
491 492
}

Bastien Nocera's avatar
Bastien Nocera committed
493
static void fprint_device_verify_start(FprintDevice *rdev,
494
	guint32 print_id, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
495 496 497 498 499
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
	GSList *elem = session->loaded_prints;
	struct fp_print_data *data = NULL;
500
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
501 502
	int r;

503 504
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
505
		return;
506 507
	}

Daniel Drake's avatar
Daniel Drake committed
508 509
	g_message("start verification device %d print %d", priv->id, print_id);
	if (!elem) {
510
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
Daniel Drake's avatar
Daniel Drake committed
511
			"No such loaded print %d", print_id);
512
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
513
		return;
Daniel Drake's avatar
Daniel Drake committed
514 515 516 517 518 519 520 521 522 523 524
	}
	
	do {
		struct loaded_print *print = elem->data;
		if (print->id == print_id) {
			data = print->data;
			break;
		}
	} while ((elem = g_slist_next(elem)) != NULL);

	if (!data) {
525
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_NO_SUCH_LOADED_PRINT,
Daniel Drake's avatar
Daniel Drake committed
526
			"No such loaded print %d", print_id);
527
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
528
		return;
Daniel Drake's avatar
Daniel Drake committed
529 530 531 532 533
	}

	/* FIXME check freeing/copying of data */
	r = fp_async_verify_start(priv->dev, data, verify_cb, rdev);
	if (r < 0) {
534
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_VERIFY_START,
Daniel Drake's avatar
Daniel Drake committed
535
			"Verify start failed with error %d", r);
536
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
537
		return;
Daniel Drake's avatar
Daniel Drake committed
538 539
	}

540
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
541 542 543 544 545 546 547
}

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
548
static void fprint_device_verify_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
549 550 551
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
552
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
553 554
	int r;

555 556
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
557
		return;
558 559
	}

Daniel Drake's avatar
Daniel Drake committed
560 561 562 563 564 565 566 567
	r = fp_async_verify_stop(priv->dev, verify_stop_cb, context);
	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);
	}
}

Daniel Drake's avatar
Daniel Drake committed
568 569 570 571 572 573
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
574
	int r;
Daniel Drake's avatar
Daniel Drake committed
575 576

	g_message("enroll_stage_cb: result %d", result);
Bastien Nocera's avatar
Bastien Nocera committed
577
	if (result == FP_ENROLL_COMPLETE) {
578
		r = storages[priv->storage_type].print_data_save(print, session->enroll_finger, priv->username);
Bastien Nocera's avatar
Bastien Nocera committed
579 580 581
		if (r < 0)
			result = FP_ENROLL_FAIL;
	}
Daniel Drake's avatar
Daniel Drake committed
582 583 584 585 586 587

	g_signal_emit(rdev, signals[SIGNAL_ENROLL_STATUS], 0, result);
	fp_img_free(img);
	fp_print_data_free(print);
}

Bastien Nocera's avatar
Bastien Nocera committed
588
static void fprint_device_enroll_start(FprintDevice *rdev,
589
	guint32 finger_num, DBusGMethodInvocation *context)
Daniel Drake's avatar
Daniel Drake committed
590 591 592
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
593
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
594 595
	int r;

596 597
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
598
		return;
599 600
	}

Daniel Drake's avatar
Daniel Drake committed
601 602 603 604 605
	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) {
606
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_ENROLL_START,
Daniel Drake's avatar
Daniel Drake committed
607
			"Enroll start failed with error %d", r);
608
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
609
		return;
Daniel Drake's avatar
Daniel Drake committed
610 611
	}

612
	dbus_g_method_return(context);
Daniel Drake's avatar
Daniel Drake committed
613 614 615 616 617 618 619
}

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
620
static void fprint_device_enroll_stop(FprintDevice *rdev,
Daniel Drake's avatar
Daniel Drake committed
621 622 623
	DBusGMethodInvocation *context)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
624
	GError *error = NULL;
Daniel Drake's avatar
Daniel Drake committed
625 626
	int r;

627 628
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
629
		return;
630 631
	}

Daniel Drake's avatar
Daniel Drake committed
632 633 634 635 636
	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
637
		return;
Daniel Drake's avatar
Daniel Drake committed
638 639 640
	}
}

641 642 643 644 645 646 647 648 649 650 651 652 653 654
static gboolean fprint_device_set_storage_type(FprintDevice *rdev,
	gint type)
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);

	if (type >= FP_STORAGES_COUNT) return FALSE;

	storages[priv->storage_type].deinit();
	priv->storage_type = type;
	storages[priv->storage_type].init();

	return TRUE;
}

655 656
static void fprint_device_list_enrolled_fingers(FprintDevice *rdev,
	DBusGMethodInvocation *context)
657 658
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
659
	GError *error = NULL;
660 661 662 663
	GSList *prints;
	GSList *item;
	GArray *ret;

664 665
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
666
		return;
667 668
	}

669
	prints = storages[priv->storage_type].discover_prints(priv->dev, priv->username);
670
	if (!prints) {
671
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_DISCOVER_PRINTS,
672
			"Failed to discover prints");
673
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
674
		return;
675 676 677 678 679 680 681 682 683
	}

	ret = g_array_new(FALSE, FALSE, sizeof(int));
	for (item = prints; item; item = item->next) {
		int *fingerptr = (int *)item->data;
		ret = g_array_append_val(ret, *fingerptr);
	}

	g_slist_free(prints);
684

685
	dbus_g_method_return(context, ret);
686 687
}

Bastien Nocera's avatar
Bastien Nocera committed
688 689
static void fprint_device_load_print_data(FprintDevice *rdev,
	guint32 finger_num, DBusGMethodInvocation *context)
690 691 692 693 694
{
	FprintDevicePrivate *priv = DEVICE_GET_PRIVATE(rdev);
	struct session_data *session = priv->session;
	struct loaded_print *lprint;
	struct fp_print_data *data;
695
	GError *error = NULL;
696 697
	int r;

698 699
	if (_fprint_device_check_claimed(rdev, context, &error) == FALSE) {
		dbus_g_method_return_error (context, error);
Bastien Nocera's avatar
Bastien Nocera committed
700
		return;
701 702
	}

703
	r = storages[priv->storage_type].print_data_load(priv->dev, (enum fp_finger)finger_num, 
704
		&data, priv->username);
705 706

	if (r < 0) {
707
		g_set_error(&error, FPRINT_ERROR, FPRINT_ERROR_PRINT_LOAD,
708
			"Print load failed with error %d", r);
709
		dbus_g_method_return_error(context, error);
Bastien Nocera's avatar
Bastien Nocera committed
710
		return;
711 712 713 714 715 716 717 718 719
	}

	lprint = g_slice_new(struct loaded_print);
	lprint->data = data;
	lprint->id = ++last_id;
	session->loaded_prints = g_slist_prepend(session->loaded_prints, lprint);

	g_message("load print data finger %d for device %d = %d",
		finger_num, priv->id, lprint->id);
720

721
	dbus_g_method_return(context, lprint->id);
722 723
}