1use pcsc::*;
4use std::error::Error;
5use std::ffi::CString;
6use std::fmt;
7use std::time::Duration;
8
9#[derive(Debug)]
11pub enum CardError {
12 NoReaders,
13 CardNotFound,
14 Transmit(String),
15 Context(String),
16 Connect(String),
17}
18
19impl fmt::Display for CardError {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 Self::NoReaders => write!(f, "no smart card readers available"),
23 Self::CardNotFound => write!(f, "no card present"),
24 Self::Transmit(msg) => write!(f, "transmit: {msg}"),
25 Self::Context(msg) => write!(f, "context: {msg}"),
26 Self::Connect(msg) => write!(f, "connect: {msg}"),
27 }
28 }
29}
30
31impl Error for CardError {}
32
33pub fn establish_context() -> Result<Context, CardError> {
35 Context::establish(Scope::User).map_err(|e| CardError::Context(e.to_string()))
36}
37
38pub fn list_readers(ctx: &Context) -> Result<Vec<String>, CardError> {
40 let mut buf = [0u8; 2048];
41 let readers = ctx
42 .list_readers(&mut buf)
43 .map_err(|e| CardError::Context(e.to_string()))?;
44 let result: Vec<String> = readers
45 .filter_map(|r| r.to_str().ok())
46 .map(|s| s.to_string())
47 .collect();
48 if result.is_empty() {
49 return Err(CardError::NoReaders);
50 }
51 Ok(result)
52}
53
54fn to_c_str(s: &str) -> CString {
56 CString::new(s).unwrap_or_else(|_| CString::new("").unwrap())
57}
58
59pub fn wait_for_card(ctx: &Context, readers: &[String]) -> Result<usize, CardError> {
61 let mut states: Vec<ReaderState> = readers
62 .iter()
63 .map(|r| ReaderState::new(to_c_str(r), State::UNAWARE))
64 .collect();
65
66 loop {
67 ctx.get_status_change(Duration::from_secs(u64::MAX), &mut states)
68 .map_err(|e| CardError::Context(e.to_string()))?;
69
70 for (i, state) in states.iter().enumerate() {
71 if state.event_state().intersects(State::PRESENT) {
72 return Ok(i);
73 }
74 }
75 for state in &mut states {
76 state.sync_current_state();
77 }
78 }
79}
80
81pub fn wait_for_card_removal(
83 ctx: &Context,
84 reader_idx: usize,
85 readers: &[String],
86) -> Result<(), CardError> {
87 let mut states = vec![ReaderState::new(
88 to_c_str(&readers[reader_idx]),
89 State::UNAWARE,
90 )];
91
92 loop {
93 ctx.get_status_change(Duration::from_secs(u64::MAX), &mut states)
94 .map_err(|e| CardError::Context(e.to_string()))?;
95
96 if states[0].event_state().intersects(State::EMPTY) {
97 return Ok(());
98 }
99 states[0].sync_current_state();
100 }
101}
102
103pub fn connect_card(ctx: &Context, reader: &str) -> Result<Card, CardError> {
105 let c_reader = to_c_str(reader);
106 ctx.connect(c_reader.as_c_str(), ShareMode::Exclusive, Protocols::ANY)
107 .map_err(|e| CardError::Connect(e.to_string()))
108}
109
110pub fn get_response_command(atr: &[u8]) -> Vec<u8> {
112 if atr.len() >= 2 && atr[0] == 0x3B && atr[1] == 0x67 {
113 vec![0x00, 0xC0, 0x00, 0x01]
114 } else {
115 vec![0x00, 0xC0, 0x00, 0x00]
116 }
117}
118
119const BUF_SIZE: usize = 264;
121
122pub fn transmit_read(
126 card: &Card,
127 cmd: &[u8],
128 get_resp_prefix: &[u8],
129 is_tis620: bool,
130) -> Result<String, CardError> {
131 let _ = transmit_raw(card, cmd)?;
132
133 let mut get_resp = get_resp_prefix.to_vec();
134 get_resp.push(cmd[cmd.len() - 1]);
135 let rsp = transmit_raw(card, &get_resp)?;
136
137 let mut payload = strip_status(&rsp);
138 if is_tis620 {
139 let (decoded, _, _) = encoding_rs::WINDOWS_874.decode(&payload);
140 payload = decoded.as_bytes().to_vec();
141 }
142 Ok(String::from_utf8_lossy(&payload).trim().to_string())
143}
144
145pub fn transmit_read_laser_id(
147 card: &Card,
148 cmd: &[u8],
149 get_resp_prefix: &[u8],
150) -> Result<String, CardError> {
151 let _ = transmit_raw(card, cmd)?;
152
153 let mut get_resp = get_resp_prefix.to_vec();
154 get_resp.push(0x10);
155 let rsp = transmit_raw(card, &get_resp)?;
156
157 let payload: Vec<u8> = strip_status(&rsp)
158 .into_iter()
159 .filter(|&b| b != 0x00)
160 .collect();
161 Ok(String::from_utf8_lossy(&payload).trim().to_string())
162}
163
164pub fn transmit_read_bytes(
167 card: &Card,
168 cmd: &[u8],
169 get_resp_prefix: &[u8],
170) -> Result<Vec<u8>, CardError> {
171 let _ = transmit_raw(card, cmd)?;
172 let mut get_resp = get_resp_prefix.to_vec();
173 get_resp.push(cmd[cmd.len() - 1]);
174 let rsp = transmit_raw(card, &get_resp)?;
175 Ok(strip_status(&rsp))
176}
177
178pub fn transmit_select(card: &Card, cmd: &[u8]) -> Result<(), CardError> {
180 transmit_raw(card, cmd).map(|_| ())
181}
182
183fn transmit_raw(card: &Card, cmd: &[u8]) -> Result<Vec<u8>, CardError> {
184 let mut buf = [0u8; BUF_SIZE];
185 let rsp = card
186 .transmit(cmd, &mut buf)
187 .map_err(|e| CardError::Transmit(e.to_string()))?;
188 Ok(rsp.to_vec())
189}
190
191fn strip_status(data: &[u8]) -> Vec<u8> {
192 if data.len() < 2 {
193 Vec::new()
194 } else {
195 data[..data.len() - 2].to_vec()
196 }
197}