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())
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Sharing {
Shared,
Exclusive,
}
impl Sharing {
fn mode(self) -> ::pcsc::ShareMode {
match self {
Sharing::Shared => ::pcsc::ShareMode::Shared,
Sharing::Exclusive => ::pcsc::ShareMode::Exclusive,
}
}
}
pub fn connect_any(sharing: Sharing) -> Result<Card<PcscTransport>> {
let context = ::pcsc::Context::establish(::pcsc::Scope::User)?;
let reader = context
.list_readers_owned()?
.into_iter()
.next()
.ok_or(Error::NoReader)?;
open(&context, &reader, sharing)
}
pub fn connect(reader: &str, sharing: Sharing) -> 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()))?;
open(&context, &name, sharing)
}
fn open(
context: &::pcsc::Context,
reader: &CString,
sharing: Sharing,
) -> Result<Card<PcscTransport>> {
let card = context.connect(reader, sharing.mode(), ::pcsc::Protocols::ANY)?;
Ok(Card::new(PcscTransport::new(card, sharing)))
}
pub struct PcscTransport {
card: ::pcsc::Card,
buffer: Vec<u8>,
sharing: Sharing,
}
impl PcscTransport {
pub fn new(card: ::pcsc::Card, sharing: Sharing) -> Self {
PcscTransport {
card,
buffer: vec![0; ::pcsc::MAX_BUFFER_SIZE_EXTENDED],
sharing,
}
}
pub fn sharing(&self) -> Sharing {
self.sharing
}
pub fn card(&self) -> &::pcsc::Card {
&self.card
}
pub fn power_cycle(&mut self) -> Result<()> {
self.card.reconnect(
self.sharing.mode(),
::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()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sharing_maps_to_the_pcsc_mode_of_the_same_name() {
assert_eq!(Sharing::Shared.mode(), ::pcsc::ShareMode::Shared);
assert_eq!(Sharing::Exclusive.mode(), ::pcsc::ShareMode::Exclusive);
}
}