use std::ffi::CString;
use crate::card::Card;
use crate::error::{Error, Result};
use crate::transport::Transmit;
pub fn list_readers() -> Result<Vec<String>> {
let context = ::pcsc::Context::establish(::pcsc::Scope::User)?;
Ok(context
.list_readers_owned()?
.iter()
.map(|name| name.to_string_lossy().into_owned())
.collect())
}
pub fn connect_any() -> Result<Card<PcscTransport>> {
let context = ::pcsc::Context::establish(::pcsc::Scope::User)?;
let reader = context
.list_readers_owned()?
.into_iter()
.next()
.ok_or(Error::NoReader)?;
connect_with(context, &reader)
}
pub fn connect(reader: &str) -> Result<Card<PcscTransport>> {
let context = ::pcsc::Context::establish(::pcsc::Scope::User)?;
let name = context
.list_readers_owned()?
.into_iter()
.find(|name| name.to_string_lossy() == reader)
.ok_or_else(|| Error::ReaderNotFound(reader.to_owned()))?;
connect_with(context, &name)
}
fn connect_with(context: ::pcsc::Context, reader: &CString) -> Result<Card<PcscTransport>> {
let card = context.connect(reader, ::pcsc::ShareMode::Shared, ::pcsc::Protocols::ANY)?;
Ok(Card::new(PcscTransport::new(card)))
}
pub struct PcscTransport {
card: ::pcsc::Card,
buffer: Vec<u8>,
}
impl PcscTransport {
pub fn new(card: ::pcsc::Card) -> Self {
PcscTransport {
card,
buffer: vec![0; ::pcsc::MAX_BUFFER_SIZE_EXTENDED],
}
}
pub fn card(&self) -> &::pcsc::Card {
&self.card
}
pub fn power_cycle(&mut self) -> Result<()> {
self.card.reconnect(
::pcsc::ShareMode::Shared,
::pcsc::Protocols::ANY,
::pcsc::Disposition::UnpowerCard,
)?;
let _ = self.transmit(&[0x00, 0xA4, 0x00, 0x00]);
Ok(())
}
pub fn into_inner(self) -> ::pcsc::Card {
self.card
}
}
impl Transmit for PcscTransport {
fn transmit(&mut self, command: &[u8]) -> Result<Vec<u8>> {
Ok(self.card.transmit(command, &mut self.buffer)?.to_vec())
}
}
impl std::fmt::Debug for PcscTransport {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PcscTransport").finish_non_exhaustive()
}
}