From d91ec2d044f3d10227c08b21ba92d1b059cd78bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Tue, 19 Nov 2019 20:21:03 +0100 Subject: [PATCH] examples: Add manage-prints test to list and delete prints Simple example program to list prints in a device with own storage and that allow to delete them (by manual selection or full deletion). --- examples/manage-prints.c | 327 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 examples/manage-prints.c diff --git a/examples/manage-prints.c b/examples/manage-prints.c new file mode 100644 index 0000000..9e6696a --- /dev/null +++ b/examples/manage-prints.c @@ -0,0 +1,327 @@ +/* + * Example fingerprint device prints listing and deletion + * Enrolls your right index finger and saves the print to disk + * Copyright (C) 2019 Marco Trevisan + * + * 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 + +#include + +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) + +FpDevice *discover_device (GPtrArray * devices) +{ + FpDevice *dev; + + if (!devices->len) + return NULL; + + dev = g_ptr_array_index (devices, 0); + g_print ("Found device claimed by %s driver\n", fp_device_get_driver (dev)); + return dev; +} + +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); +} + +const char * +finger_to_string (FpFinger finger) +{ + switch (finger) + { + case FP_FINGER_LEFT_THUMB: + return "left thumb"; + + case FP_FINGER_LEFT_INDEX: + return "left index"; + + case FP_FINGER_LEFT_MIDDLE: + return "left middle"; + + case FP_FINGER_LEFT_RING: + return "left ring"; + + case FP_FINGER_LEFT_LITTLE: + return "left little"; + + case FP_FINGER_RIGHT_THUMB: + return "right thumb"; + + case FP_FINGER_RIGHT_INDEX: + return "right index"; + + case FP_FINGER_RIGHT_MIDDLE: + return "right middle"; + + case FP_FINGER_RIGHT_RING: + return "right ring"; + + case FP_FINGER_RIGHT_LITTLE: + return "right little"; + + default: + return "unknown"; + } +} + +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); + +static void +on_print_deleted (FpDevice *dev, GAsyncResult *res, gpointer user_data); + +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; + 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) + { + g_warning("Failed to remove print %s: %s", + fp_print_get_description (print), error->message); + list_data->any_failed = TRUE; + } + else + g_debug ("Deleted print %s from device", fp_print_get_description (print)); + + 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; + 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) + { + FpPrint* print = prints->pdata[i]; + + 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; + + g_print ("Want to delete saved print? [/A/n]\n"); + 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 + { + fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, + list_data); + } + } + 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; +}