From 27138c4b799248d2d39e9681337a620c89636557 Mon Sep 17 00:00:00 2001
From: Robin Krahl <robin.krahl@ireas.org>
Date: Thu, 17 Jan 2019 13:10:01 +0000
Subject: Add the CommunicationError enum

Communication errors returned by libnitrokey were previously not mapped
to an error type in the nitrokey crate.  We introduce the
CommunicationError enum to represent these errors.
---
 CHANGELOG.md |  2 ++
 src/error.rs | 59 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 51 insertions(+), 10 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c34175e..413c626 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,8 @@
   - Add the `Error` enum and the `Result` typedef.
   - Add the `LibraryError` enum and move the library error variants from
     `CommandError` to `LibraryError`.
+  - Add the `CommunicationError` enum and move the communication error variants
+    from `CommandError` to `CommunicationError`.
   - Return `Error` instead of `CommandError` in all public functions.
   - Move the `CommandError::RngError` variant to `Error::RandError` and the
     `CommandError::Unknown` variant to `Error::Unknown`.
diff --git a/src/error.rs b/src/error.rs
index f40d07f..a2b3848 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -9,7 +9,7 @@ use std::result;
 pub enum Error {
     /// An error reported by the Nitrokey device in the response packet.
     CommandError(CommandError),
-    /// Placeholder for testing.
+    /// A device communication.
     CommunicationError(CommunicationError),
     /// A library usage error.
     LibraryError(LibraryError),
@@ -23,6 +23,8 @@ impl From<raw::c_int> for Error {
     fn from(code: raw::c_int) -> Self {
         if let Some(err) = CommandError::try_from(code) {
             Error::CommandError(err)
+        } else if let Some(err) = CommunicationError::try_from(256 - code) {
+            Error::CommunicationError(err)
         } else if let Some(err) = LibraryError::try_from(code) {
             Error::LibraryError(err)
         } else {
@@ -37,6 +39,12 @@ impl From<CommandError> for Error {
     }
 }
 
+impl From<CommunicationError> for Error {
+    fn from(err: CommunicationError) -> Self {
+        Error::CommunicationError(err)
+    }
+}
+
 impl From<LibraryError> for Error {
     fn from(err: LibraryError) -> Self {
         Error::LibraryError(err)
@@ -53,7 +61,7 @@ impl error::Error for Error {
     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
         match *self {
             Error::CommandError(ref err) => Some(err),
-            Error::CommunicationError(_) => None,
+            Error::CommunicationError(ref err) => Some(err),
             Error::LibraryError(ref err) => Some(err),
             Error::RandError(ref err) => Some(err),
             Error::Unknown(_) => None,
@@ -65,7 +73,7 @@ impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match *self {
             Error::CommandError(ref err) => write!(f, "Command error: {}", err),
-            Error::CommunicationError(_) => write!(f, "Placeholder"),
+            Error::CommunicationError(ref err) => write!(f, "Communication error: {}", err),
             Error::LibraryError(ref err) => write!(f, "Library error: {}", err),
             Error::RandError(ref err) => write!(f, "RNG error: {}", err),
             Error::Unknown(ref err) => write!(f, "Unknown error: {}", err),
@@ -104,13 +112,6 @@ pub enum CommandError {
     Undefined,
 }
 
-/// Placeholder for testing.
-#[derive(Debug)]
-pub enum CommunicationError {
-    /// Placeholder for testing.
-    NotConnected,
-}
-
 impl CommandError {
     fn try_from(value: raw::c_int) -> Option<Self> {
         match value {
@@ -159,6 +160,44 @@ impl fmt::Display for CommandError {
     }
 }
 
+/// A device communication error.
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub enum CommunicationError {
+    /// Could not connect to a Nitrokey device.
+    NotConnected,
+    /// Sending a packet failed.
+    SendingFailure,
+    /// Receiving a packet failed.
+    ReceivingFailure,
+    /// A packet with a wrong checksum was received.
+    InvalidCrc,
+}
+
+impl CommunicationError {
+    fn try_from(value: raw::c_int) -> Option<Self> {
+        match value {
+            2 => Some(CommunicationError::NotConnected),
+            3 => Some(CommunicationError::SendingFailure),
+            4 => Some(CommunicationError::ReceivingFailure),
+            5 => Some(CommunicationError::InvalidCrc),
+            _ => None,
+        }
+    }
+}
+
+impl error::Error for CommunicationError {}
+
+impl fmt::Display for CommunicationError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str(match *self {
+            CommunicationError::NotConnected => "Could not connect to a Nitrokey device",
+            CommunicationError::SendingFailure => "Sending a packet failed",
+            CommunicationError::ReceivingFailure => "Receiving a packet failed",
+            CommunicationError::InvalidCrc => "A packet with a wrong checksum was received",
+        })
+    }
+}
+
 /// A library usage error.
 #[derive(Clone, Copy, Debug, PartialEq)]
 pub enum LibraryError {
-- 
cgit v1.2.3