1#![allow(clippy::large_enum_variant)]
15
16pub mod apdu;
17pub mod ffi;
18pub mod model;
19pub mod options;
20pub mod reader;
21
22mod laser;
23mod nhso;
24mod personal;
25
26pub use options::Options;
27
28use std::sync::mpsc;
29use std::thread;
30use std::time::Duration;
31
32use pcsc::*;
33
34use crate::reader::CardError;
35
36#[derive(Debug)]
38pub enum Event {
39 CardInserted { reader: String },
40 CardData(model::CardData),
41 CardRemoved { reader: String },
42 Error(String),
43}
44
45pub struct SmartCard;
47
48impl SmartCard {
49 pub fn new() -> Self {
51 Self
52 }
53
54 pub fn list_readers() -> Result<Vec<String>, CardError> {
56 let ctx = reader::establish_context()?;
57 reader::list_readers(&ctx)
58 }
59
60 pub fn read(
63 &self,
64 reader_name: Option<&str>,
65 opts: &Options,
66 ) -> Result<model::CardData, CardError> {
67 let ctx = reader::establish_context()?;
68
69 let readers = match reader_name {
70 Some(name) => vec![name.to_string()],
71 None => reader::list_readers(&ctx)?,
72 };
73
74 let idx = reader::wait_for_card(&ctx, &readers)?;
75 let reader = &readers[idx];
76
77 self.read_card(&ctx, reader, opts)
78 }
79
80 pub fn start_daemon(opts: Options) -> mpsc::Receiver<Event> {
83 let (tx, rx) = mpsc::channel();
84 let card = Self;
85
86 thread::spawn(move || loop {
87 let ctx = match reader::establish_context() {
88 Ok(c) => c,
89 Err(e) => {
90 let _ = tx.send(Event::Error(e.to_string()));
91 thread::sleep(Duration::from_secs(2));
92 continue;
93 }
94 };
95
96 let readers = match reader::list_readers(&ctx) {
97 Ok(r) => r,
98 Err(_) => {
99 thread::sleep(Duration::from_secs(2));
100 continue;
101 }
102 };
103
104 let idx = match reader::wait_for_card(&ctx, &readers) {
105 Ok(i) => i,
106 Err(e) => {
107 let _ = tx.send(Event::Error(e.to_string()));
108 continue;
109 }
110 };
111
112 let reader_name = readers[idx].clone();
113 let _ = tx.send(Event::CardInserted {
114 reader: reader_name.clone(),
115 });
116
117 match card.read_card(&ctx, &reader_name, &opts) {
118 Ok(data) => {
119 let _ = tx.send(Event::CardData(data));
120 }
121 Err(e) => {
122 let _ = tx.send(Event::Error(e.to_string()));
123 }
124 }
125
126 let _ = reader::wait_for_card_removal(&ctx, idx, &readers);
127 let _ = tx.send(Event::CardRemoved {
128 reader: reader_name,
129 });
130 });
131
132 rx
133 }
134
135 fn read_card(
136 &self,
137 ctx: &Context,
138 reader: &str,
139 opts: &Options,
140 ) -> Result<model::CardData, CardError> {
141 let card = reader::connect_card(ctx, reader)?;
142
143 let status = card
144 .status2_owned()
145 .map_err(|e| CardError::Context(e.to_string()))?;
146 let resp_cmd = reader::get_response_command(status.atr());
147
148 let personal = personal::read_personal(&card, &resp_cmd, opts.show_face_image);
149
150 let card_info = if opts.show_laser_data {
151 Some(laser::read_laser_id(&card, &resp_cmd))
152 } else {
153 None
154 };
155
156 let nhso_data = if opts.show_nhso_data {
157 Some(nhso::read_nhso(&card, &resp_cmd))
158 } else {
159 None
160 };
161
162 drop(card);
163
164 Ok(model::CardData {
165 personal: Some(personal),
166 card: card_info,
167 nhso: nhso_data,
168 })
169 }
170}
171
172impl Default for SmartCard {
173 fn default() -> Self {
174 Self::new()
175 }
176}