From c0b4cfc97dc727cfa3a8d34456637860a5856c8a Mon Sep 17 00:00:00 2001 From: "B. Stack" Date: Sun, 22 Sep 2024 21:58:19 -0400 Subject: progress for day --- fprintd_tk.py | 44 +++++++++++++++++++------------ fprintd_tk_lib.py | 77 +++++++++++++++++++++++++++++++------------------------ 2 files changed, 71 insertions(+), 50 deletions(-) diff --git a/fprintd_tk.py b/fprintd_tk.py index 8fe0ab6..3e815a6 100755 --- a/fprintd_tk.py +++ b/fprintd_tk.py @@ -6,17 +6,13 @@ # References: # stackrpms_tk.py # Improve: -# implement delete -# implement enroll -# +# flash the newly enrolled finger, and/or the failed verify on a finger. -import tkinter as tk, os, tkinter.filedialog, sys, threading +import tkinter as tk, os, tkinter.simpledialog, sys, threading, time import tkstackrpms as stk import fprintd_tk_lib as lib from PIL import Image, ImageTk -# todo: load images array? - ABOUT_TEXT = """ fprintd_tk \"Gui for fprintd\" (C) 2024 bgstack15 @@ -102,6 +98,8 @@ class App(tk.Frame): self.action.set(a) def load_data_into_form(self): + time.sleep(0.05) + # WORKHERE: if the fprintd-list fails because the device is open, we will want to keep the old enrolled_fingers list. maybe check if statustext contains "failed to open" or whatever the message is. if it does, do not update the self.enrolled_fingers? self.enrolled_fingers = lib.get_enrolled_fingers() print(f"DEBUG (load_data_into_form): got enrolled fingers {self.enrolled_fingers}") for i in self.fingers: @@ -123,25 +121,39 @@ class App(tk.Frame): def func_finger_button(self, finger): print(f"DEBUG: func_finger_button finger {finger}, action {self.action.get()}") action = self.action.get() - if 1 == action: # enroll + # position in array is same as the value coming from radio button for actions. + available_actions = ["none","enroll","verify"] + try: + action_str = available_actions[action] + except ValueError: + action_str = "OFF" + if action_str in available_actions: try: - # WORKHERE: pass a tk text var to set for intermediate operations? - self.statustext.set(lib.enroll_finger(finger, self.func_update_status)) + t1 = threading.Thread(target=lib.fprintd_action, args=(action_str, finger, self.func_update_status)) + t1.start() except Exception as e: self.statustext.set(e) - elif 2 == action: # verify - #print(f"stub action: verify, finger {finger}") - t1 = threading.Thread(target=lib.verify_finger,args=(finger, self.func_update_status)) - t1.run() - self.load_data_into_form() + else: + self.statustext.set(f"Invalid action {action}, string {action_str}.") + # This blocks everything! Do not use this. + #t1.join() + # unfortunately useless here, because of the threading. + #self.load_data_into_form() def func_update_status(self, msg): msg = msg.strip() - print(f"DEBUG: func_update_status called with msg {msg}",file=sys.stderr) + print(f"DEBUG (func_update_status: msg {msg}",file=sys.stderr) self.statustext.set(msg) + self.load_data_into_form() def func_delete(self): - print(f"stub, please ask user if he is certain to delete all enrolled fingerprints") + print(f"please ask user if he is certain to delete all enrolled fingerprints") + sure = tkinter.messagebox.askokcancel(title="Delete all enrolled fingerprints",message="Are you sure you want to delete all enrolled fingerprints?") + if sure: + t1 = threading.Thread(target=lib.fprintd_action, args=("delete", "none", self.func_update_status)) + t1.start() + else: + self.statustext.set("Cancelled the delete action.") # main root = tk.Tk() diff --git a/fprintd_tk_lib.py b/fprintd_tk_lib.py index 1f1b022..f4947ec 100644 --- a/fprintd_tk_lib.py +++ b/fprintd_tk_lib.py @@ -9,8 +9,12 @@ import os, subprocess, re _user = os.getenv("USER") -#fre = re.compile("^.* . #[0-9]: \w+$") fre = re.compile ("^.* - #[0-9]+: ([^ ]+)$") +prevent_success_messages = [ + "no-match", + "failed to claim", + "not enrolled for user" +] def get_enrolled_fingers(user = None): # return list of full strings of fingers that are enrolled. @@ -35,47 +39,52 @@ def get_enrolled_fingers(user = None): pass return enrolled_fingers -def enroll_finger(finger, status_function = None, user = None): +# WORKHERE: count duplicate lines as before, and also save last line, so we can prepend "succeeded"? +def fprintd_action(action, finger, status_function = None, user = None): if user is None: user = _user + if action == "enroll": + command = ["fprintd-enroll","-f",finger,user] + elif action == "verify": + command = ["fprintd-verify","-f",finger,user] + elif action == "delete": + command = ["fprintd-delete",user] + else: + if status_function: + status_function(f"Invalid action {action}") + return False proc = subprocess.Popen( - ["fprintd-enroll","-f",finger,user], + command, stdout = subprocess.PIPE, universal_newlines = True ) + old_line = "INITIAL_LINE" + dupe_count = 0 while True: line = proc.stdout.readline() if not line: break - if re.match("^.*enroll-duplicate.*",line): - # Using the same finger as any other finger enrolled by any user already is considered an error by fprintd, and there is nothing we can do about it. It is an error and we must raise an error here. - return "enroll-duplicate" - elif re.match("^.*enroll-completed.*",line): - return "enroll-completed" - elif re.match("^.*enroll-stage-passed.*",line): - if status_function: - #print(f"Will use function {status_function}(\"enroll-stage-passed\")") - status_function("enroll-stage-passed") - print(f"Great, keep going!") - # so the process has ended, now what? - return f"Last line was: {line}" - -def verify_finger(finger, status_function = None, user = None): - if user is None: - user = _user - proc = subprocess.Popen( - ["fprintd-verify","-f",finger,user], - stdout = subprocess.PIPE, - universal_newlines = True - ) - while True: - line = proc.stdout.readline() - if not line: - break - if re.match("^.*verify-match (done).*",line): - return "verify-match" + display_line = line + if line == old_line: + dupe_count = dupe_count + 1 + display_line = line.strip() + str(f" (x{dupe_count})") else: - if status_function: - #print(f"Will use function {status_function}(\"enroll-stage-passed\")") - status_function(line) - return line + dupe_count = 1 + old_line = line + if status_function: + status_function(display_line) + # If you want to react to any lines. + #if re.match("^.*verify-match (done).*",line): + # proc.kill() + # return "verify-match" + # so the process has ended, now what? + proc.kill() + if status_function: + if display_line: + display = True + for i in prevent_success_messages: + if i in display_line: + display = False + break + if display: + status_function(f"Succeeded! {display_line}") -- cgit