1use pcsc::*;
2use std::thread::{ self, JoinHandle };
3use std::collections::HashMap;
4use std::ffi::CStr;
5
6mod badge;
7mod ndef;
8pub use badge::NFCBadge;
9
10pub fn handle_cards<F, G>(card_handler: F, reader_handler: G) -> JoinHandle<()>
11 where F: Fn(&Card, &CStr, usize),
12 F: Send + 'static,
13 G: Fn(&CStr, bool),
14 G: Send + 'static,
15{
16 thread::spawn(move || {
17 let mut ctx = Context::establish(Scope::User).expect("Failed to establish context");
18
19 let mut readers_buf = [0; 2048];
20 let mut reader_states = vec![
21 ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE),
23 ];
24 let mut readers = HashMap::new();
26 loop {
27 fn is_invalid(rs: &ReaderState) -> bool {
29 rs.event_state().intersects(State::UNKNOWN | State::IGNORE)
30 }
31 reader_states.retain(|rs| {
32 let should_keep = !is_invalid(rs);
33 if !should_keep {
34 reader_handler(rs.name(), false);
36 }
37 should_keep
38 });
39
40 let names = match ctx.list_readers(&mut readers_buf) {
42 Ok(names) => names,
43 Err(pcsc::Error::ServiceStopped) | Err(pcsc::Error::NoService) => {
44 ctx = Context::establish(Scope::User).expect("Failed to establish context");
47 continue;
48 }
49 Err(err) => { panic!("Failed to list readers: {:?}", err) }
50 };
51
52 for name in names {
53 if !reader_states.iter().any(|rs| rs.name() == name) && !name.to_str().unwrap().contains("Windows Hello") {
55 reader_handler(name, true);
56 reader_states.push(ReaderState::new(name, State::UNAWARE));
57 }
58 }
59
60 for rs in &mut reader_states {
62 rs.sync_current_state();
63 }
64
65 match ctx.get_status_change(None, &mut reader_states) {
67 Ok(()) => {},
68 Err(pcsc::Error::ServiceStopped) | Err(pcsc::Error::NoService) => {
69 ctx = Context::establish(Scope::User).expect("Failed to establish context");
72 continue;
73 }
74 Err(err) => { panic!("Failed to get status change: {:?}", err) }
75 };
76
77 for (reader_index, rs) in reader_states.iter().enumerate() {
78 if rs.name() == PNP_NOTIFICATION() { continue; }
79
80 let name = rs.name().to_owned();
81 if rs.event_state().intersects(State::PRESENT) {
83 if !readers.get(&name).unwrap_or(&false) {
84 match ctx.connect(rs.name(), ShareMode::Shared, Protocols::ANY) {
87 Ok(card) => card_handler(&card, rs.name(), reader_index),
88 Err(Error::NoSmartcard) => {
89 eprintln!("A smartcard is not present in the reader");
90 }
91 Err(err) => {
92 eprintln!("Failed to connect to card: {}", err);
93 }
94 };
95 }
96 readers.insert(name, true);
97 }
98 else if rs.event_state().intersects(State::EMPTY) {
99 readers.insert(name, false);
100 }
101 }
102 }
103 })
104}