2019-11-19 19:21:03 +00:00
|
|
|
/*
|
|
|
|
* Example fingerprint device prints listing and deletion
|
|
|
|
* Enrolls your right index finger and saves the print to disk
|
|
|
|
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <libfprint/fprint.h>
|
2019-11-20 13:29:46 +00:00
|
|
|
#include "utilities.h"
|
2019-11-19 19:21:03 +00:00
|
|
|
|
|
|
|
typedef struct _ListData
|
|
|
|
{
|
|
|
|
GMainLoop *loop;
|
|
|
|
int ret_value;
|
|
|
|
GList *to_delete;
|
|
|
|
gboolean any_failed;
|
|
|
|
} ListData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
list_data_free (ListData *list_data)
|
|
|
|
{
|
|
|
|
g_list_free_full (list_data->to_delete, g_object_unref);
|
|
|
|
g_main_loop_unref (list_data->loop);
|
|
|
|
g_free (list_data);
|
|
|
|
}
|
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ListData, list_data_free)
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_device_closed (FpDevice *dev,
|
|
|
|
GAsyncResult *res,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
ListData *list_data = user_data;
|
|
|
|
|
|
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
|
|
|
|
fp_device_close_finish (dev, res, &error);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
g_warning ("Failed closing device %s\n", error->message);
|
|
|
|
|
|
|
|
g_main_loop_quit (list_data->loop);
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct _DeleteData
|
|
|
|
{
|
|
|
|
ListData *list_data;
|
|
|
|
FpPrint *print;
|
|
|
|
} DeleteData;
|
|
|
|
|
|
|
|
static void
|
|
|
|
delete_data_free (DeleteData *delete_data)
|
|
|
|
{
|
|
|
|
g_object_unref (delete_data->print);
|
|
|
|
g_free (delete_data);
|
|
|
|
}
|
|
|
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (DeleteData, delete_data_free);
|
|
|
|
|
2019-11-19 20:13:11 +00:00
|
|
|
static void on_print_deleted (FpDevice *dev,
|
|
|
|
GAsyncResult *res,
|
|
|
|
gpointer user_data);
|
2019-11-19 19:21:03 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
delete_next_print (FpDevice *dev,
|
|
|
|
ListData *list_data)
|
|
|
|
{
|
|
|
|
FpPrint *print;
|
|
|
|
|
|
|
|
g_assert_nonnull (list_data->to_delete);
|
|
|
|
print = list_data->to_delete->data;
|
|
|
|
|
|
|
|
g_debug ("Deleting print %s\n", fp_print_get_description (print));
|
|
|
|
fp_device_delete_print (dev, print, NULL,
|
|
|
|
(GAsyncReadyCallback) on_print_deleted, list_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_print_deleted (FpDevice *dev,
|
|
|
|
GAsyncResult *res,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
ListData *list_data = user_data;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:21:03 +00:00
|
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
g_autoptr(FpPrint) print = NULL;
|
|
|
|
GList *deleted_link;
|
|
|
|
|
|
|
|
fp_device_delete_print_finish (dev, res, &error);
|
|
|
|
|
|
|
|
deleted_link = list_data->to_delete;
|
|
|
|
print = g_steal_pointer (&deleted_link->data);
|
|
|
|
list_data->to_delete = g_list_delete_link (list_data->to_delete, deleted_link);
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
g_warning ("Failed to remove print %s: %s",
|
|
|
|
fp_print_get_description (print), error->message);
|
2019-11-19 19:21:03 +00:00
|
|
|
list_data->any_failed = TRUE;
|
|
|
|
}
|
|
|
|
else
|
2019-11-19 20:13:11 +00:00
|
|
|
{
|
|
|
|
g_debug ("Deleted print %s from device", fp_print_get_description (print));
|
|
|
|
}
|
2019-11-19 19:21:03 +00:00
|
|
|
|
|
|
|
if (list_data->to_delete != NULL)
|
|
|
|
{
|
|
|
|
delete_next_print (dev, list_data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!list_data->any_failed)
|
|
|
|
list_data->ret_value = EXIT_SUCCESS;
|
|
|
|
|
|
|
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
|
|
|
list_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_list_completed (FpDevice *dev,
|
|
|
|
GAsyncResult *res,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
ListData *list_data = user_data;
|
2019-11-19 20:13:11 +00:00
|
|
|
|
2019-11-19 19:21:03 +00:00
|
|
|
g_autoptr(GPtrArray) prints = NULL;
|
|
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
|
|
|
|
prints = fp_device_list_prints_finish (dev, res, &error);
|
|
|
|
|
|
|
|
if (!error)
|
|
|
|
{
|
|
|
|
guint i;
|
|
|
|
char buf[128];
|
|
|
|
|
|
|
|
g_print ("Device contains %u prints\n", prints->len);
|
|
|
|
|
|
|
|
for (i = 0; i < prints->len; ++i)
|
|
|
|
{
|
2019-11-19 20:13:11 +00:00
|
|
|
FpPrint * print = prints->pdata[i];
|
2019-11-19 19:21:03 +00:00
|
|
|
|
|
|
|
g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d",
|
|
|
|
fp_print_get_enroll_date (print));
|
|
|
|
g_print ("[%d] Print of %s finger for username %s, enrolled "
|
|
|
|
"on %s. Description: %s\n", i + 1,
|
|
|
|
finger_to_string (fp_print_get_finger (print)),
|
|
|
|
fp_print_get_username (print), buf,
|
|
|
|
fp_print_get_description (print));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prints->len)
|
|
|
|
{
|
|
|
|
gint64 idx = 0;
|
|
|
|
|
2019-11-20 13:29:46 +00:00
|
|
|
g_print ("Want to delete saved print? [<number>/A/n]\n> ");
|
2019-11-19 19:21:03 +00:00
|
|
|
if (fgets (buf, 3, stdin))
|
|
|
|
idx = g_ascii_strtoll (buf, NULL, 10);
|
|
|
|
|
|
|
|
if (idx > 0 && idx <= prints->len)
|
|
|
|
{
|
|
|
|
FpPrint *print = prints->pdata[idx - 1];
|
|
|
|
list_data->to_delete = g_list_prepend (list_data->to_delete,
|
|
|
|
g_object_ref (print));
|
|
|
|
}
|
|
|
|
else if (buf[0] == 'A')
|
|
|
|
{
|
|
|
|
for (i = 0; i < prints->len; ++i)
|
|
|
|
{
|
|
|
|
FpPrint *print = prints->pdata[i];
|
|
|
|
list_data->to_delete = g_list_prepend (list_data->to_delete,
|
|
|
|
g_object_ref (print));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (buf[0] == 'n' || buf[0] == 'N')
|
|
|
|
list_data->ret_value = EXIT_SUCCESS;
|
|
|
|
else
|
|
|
|
g_warning ("Invalid finger selected");
|
|
|
|
|
|
|
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
|
|
|
list_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list_data->to_delete)
|
|
|
|
delete_next_print (dev, list_data);
|
|
|
|
else
|
2019-11-19 20:13:11 +00:00
|
|
|
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
|
|
|
|
list_data);
|
2019-11-19 19:21:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_warning ("Getting prints failed with error %s", error->message);
|
|
|
|
g_main_loop_quit (list_data->loop);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
on_device_opened (FpDevice *dev,
|
|
|
|
GAsyncResult *res,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
ListData *list_data = user_data;
|
|
|
|
|
|
|
|
g_autoptr(GError) error = NULL;
|
|
|
|
|
|
|
|
if (!fp_device_open_finish (dev, res, &error))
|
|
|
|
{
|
|
|
|
g_warning ("Failed to open device: %s", error->message);
|
|
|
|
g_main_loop_quit (list_data->loop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!fp_device_has_storage (dev))
|
|
|
|
{
|
|
|
|
g_warning ("Device %s doesn't support storage", fp_device_get_name (dev));
|
|
|
|
g_main_loop_quit (list_data->loop);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fp_device_list_prints (dev, NULL,
|
|
|
|
(GAsyncReadyCallback) on_list_completed, list_data);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main (void)
|
|
|
|
{
|
|
|
|
g_autoptr(FpContext) ctx = NULL;
|
|
|
|
g_autoptr(ListData) list_data = NULL;
|
|
|
|
GPtrArray *devices;
|
|
|
|
FpDevice *dev;
|
|
|
|
|
|
|
|
g_print ("This program will report the prints saved in device\n");
|
|
|
|
|
|
|
|
setenv ("G_MESSAGES_DEBUG", "all", 0);
|
|
|
|
|
|
|
|
ctx = fp_context_new ();
|
|
|
|
|
|
|
|
devices = fp_context_get_devices (ctx);
|
|
|
|
if (!devices)
|
|
|
|
{
|
|
|
|
g_warning ("Impossible to get devices");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev = discover_device (devices);
|
|
|
|
if (!dev)
|
|
|
|
{
|
|
|
|
g_warning ("No devices detected.");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_data = g_new0 (ListData, 1);
|
|
|
|
list_data->ret_value = EXIT_FAILURE;
|
|
|
|
list_data->loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
|
|
|
|
fp_device_open (dev, NULL, (GAsyncReadyCallback) on_device_opened, list_data);
|
|
|
|
|
|
|
|
g_main_loop_run (list_data->loop);
|
|
|
|
|
|
|
|
return list_data->ret_value;
|
|
|
|
}
|