// Copyright 2016 Pierre-Étienne Meunier
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! Server and client SSH asynchronous library, based on tokio/futures.
//!
//! The normal way to use this library, both for clients and for
//! servers, is by creating *handlers*, i.e. types that implement
//! `client::Handler` for clients and `server::Handler` for
//! servers.
//!
//! # Writing servers
//!
//! In the specific case of servers, a server must implement
//! `server::Server`, a trait for creating new `server::Handler`.  The
//! main type to look at in the `server` module is `Session` (and
//! `Config`, of course).
//!
//! Here is an example server, which forwards input from each client
//! to all other clients:
//!
//! ```
//! extern crate thrussh;
//! extern crate thrussh_keys;
//! extern crate futures;
//! extern crate tokio;
//! use std::sync::{Mutex, Arc};
//! use thrussh::*;
//! use thrussh::server::{Auth, Session};
//! use thrussh_keys::*;
//! use std::collections::HashMap;
//! use futures::Future;
//!
//! #[tokio::main]
//! async fn main() {
//!     let client_key = thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
//!     let client_pubkey = Arc::new(client_key.clone_public_key());
//!     let mut config = thrussh::server::Config::default();
//!     config.connection_timeout = Some(std::time::Duration::from_secs(3));
//!     config.auth_rejection_time = std::time::Duration::from_secs(3);
//!     config.keys.push(thrussh_keys::key::KeyPair::generate_ed25519().unwrap());
//!     let config = Arc::new(config);
//!     let sh = Server{
//!         client_pubkey,
//!         clients: Arc::new(Mutex::new(HashMap::new())),
//!         id: 0
//!     };
//!     tokio::time::timeout(
//!        std::time::Duration::from_secs(1),
//!        thrussh::server::run(config, "0.0.0.0:2222", sh)
//!     ).await.unwrap_or(Ok(()));
//! }
//!
//! #[derive(Clone)]
//! struct Server {
//!     client_pubkey: Arc<thrussh_keys::key::PublicKey>,
//!     clients: Arc<Mutex<HashMap<(usize, ChannelId), thrussh::server::Handle>>>,
//!     id: usize,
//! }
//!
//! impl server::Server for Server {
//!     type Handler = Self;
//!     fn new(&mut self, _: Option<std::net::SocketAddr>) -> Self {
//!         let s = self.clone();
//!         self.id += 1;
//!         s
//!     }
//! }
//!
//! impl server::Handler for Server {
//!     type FutureAuth = futures::future::Ready<Result<(Self, server::Auth), anyhow::Error>>;
//!     type FutureUnit = futures::future::Ready<Result<(Self, Session), anyhow::Error>>;
//!     type FutureBool = futures::future::Ready<Result<(Self, Session, bool), anyhow::Error>>;
//!
//!     fn finished_auth(mut self, auth: Auth) -> Self::FutureAuth {
//!         futures::future::ready(Ok((self, auth)))
//!     }
//!     fn finished_bool(self, b: bool, s: Session) -> Self::FutureBool {
//!         futures::future::ready(Ok((self, s, b)))
//!     }
//!     fn finished(self, s: Session) -> Self::FutureUnit {
//!         futures::future::ready(Ok((self, s)))
//!     }
//!     fn channel_open_session(self, channel: ChannelId, session: Session) -> Self::FutureUnit {
//!         {
//!             let mut clients = self.clients.lock().unwrap();
//!             clients.insert((self.id, channel), session.handle());
//!         }
//!         self.finished(session)
//!     }
//!     fn auth_publickey(self, _: &str, _: &key::PublicKey) -> Self::FutureAuth {
//!         self.finished_auth(server::Auth::Accept)
//!     }
//!     fn data(self, channel: ChannelId, data: &[u8], mut session: Session) -> Self::FutureUnit {
//!         {
//!             let mut clients = self.clients.lock().unwrap();
//!             for ((id, channel), ref mut s) in clients.iter_mut() {
//!                 if *id != self.id {
//!                     s.data(*channel, CryptoVec::from_slice(data));
//!                 }
//!             }
//!         }
//!         session.data(channel, CryptoVec::from_slice(data));
//!         self.finished(session)
//!     }
//! }
//! ```
//!
//! Note the call to `session.handle()`, which allows to keep a handle
//! to a client outside the event loop. This feature is internally
//! implemented using `futures::sync::mpsc` channels.
//!
//! Note that this is just a toy server. In particular:
//!
//! - It doesn't handle errors when `s.data` returns an error,
//!   i.e. when the client has disappeared
//!
//! - Each new connection increments the `id` field. Even though we
//! would need a lot of connections per second for a very long time to
//! saturate it, there are probably better ways to handle this to
//! avoid collisions.
//!
//!
//! # Implementing clients
//!
//! Maybe surprisingly, the data types used by Thrussh to implement
//! clients are relatively more complicated than for servers. This is
//! mostly related to the fact that clients are generally used both in
//! a synchronous way (in the case of SSH, we can think of sending a
//! shell command), and asynchronously (because the server may send
//! unsollicited messages), and hence need to handle multiple
//! interfaces.
//!
//! The important types in the `client` module are `Session` and
//! `Connection`. A `Connection` is typically used to send commands to
//! the server and wait for responses, and contains a `Session`. The
//! `Session` is passed to the `Handler` when the client receives
//! data.
//!
//! ```
//!extern crate thrussh;
//!extern crate thrussh_keys;
//!extern crate futures;
//!extern crate tokio;
//!extern crate env_logger;
//!use std::sync::Arc;
//!use thrussh::*;
//!use thrussh::server::{Auth, Session};
//!use thrussh_keys::*;
//!use futures::Future;
//!use std::io::Read;
//!
//!
//!struct Client {
//!}
//!
//!impl client::Handler for Client {
//!    type FutureUnit = futures::future::Ready<Result<(Self, client::Session), anyhow::Error>>;
//!    type FutureBool = futures::future::Ready<Result<(Self, bool), anyhow::Error>>;
//!
//!    fn finished_bool(self, b: bool) -> Self::FutureBool {
//!        futures::future::ready(Ok((self, b)))
//!    }
//!    fn finished(self, session: client::Session) -> Self::FutureUnit {
//!        futures::future::ready(Ok((self, session)))
//!    }
//!    fn check_server_key(self, server_public_key: &key::PublicKey) -> Self::FutureBool {
//!        println!("check_server_key: {:?}", server_public_key);
//!        self.finished_bool(true)
//!    }
//!    fn channel_open_confirmation(self, channel: ChannelId, max_packet_size: u32, window_size: u32, session: client::Session) -> Self::FutureUnit {
//!        println!("channel_open_confirmation: {:?}", channel);
//!        self.finished(session)
//!    }
//!    fn data(self, channel: ChannelId, data: &[u8], session: client::Session) -> Self::FutureUnit {
//!        println!("data on channel {:?}: {:?}", channel, std::str::from_utf8(data));
//!        self.finished(session)
//!    }
//!}
//!
//! #[tokio::main]
//! async fn main() {
//!   let config = thrussh::client::Config::COMPRESSED;
//!   let config = Arc::new(config);
//!   let sh = Client{};
//!
//!   let key = thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
//!   let mut agent = thrussh_keys::agent::client::AgentClient::connect_env().await.unwrap();
//!   agent.add_identity(&key, &[]).await.unwrap();
//!   let mut session = thrussh::client::connect(config, "localhost:22", sh).await.unwrap();
//!   if session.authenticate_future(std::env::var("USER").unwrap(), key.clone_public_key(), agent).await.unwrap().1 {
//!     let mut channel = session.channel_open_session().await.unwrap();
//!     channel.data(b"Hello, world!").await.unwrap();
//!     if let Some(msg) = channel.wait().await {
//!         println!("{:?}", msg)
//!     }
//!   }
//! }
//! ```
//! # Using non-socket IO / writing tunnels
//!
//! The easy way to implement SSH tunnels, like `ProxyCommand` for
//! OpenSSH, is to use the `thrussh-config` crate, and use the
//! `Stream::tcp_connect` or `Stream::proxy_command` methods of that
//! crate. That crate is a very lightweight layer above Thrussh, only
//! implementing for external commands the traits used for sockets.
//!
//! # The SSH protocol
//!
//! If we exclude the key exchange and authentication phases, handled
//! by Thrussh behind the scenes, the rest of the SSH protocol is
//! relatively simple: clients and servers open *channels*, which are
//! just integers used to handle multiple requests in parallel in a
//! single connection. Once a client has obtained a `ChannelId` by
//! calling one the many `channel_open_…` methods of
//! `client::Connection`, the client may send exec requests and data
//! to the server.
//!
//! A simple client just asking the server to run one command will
//! usually start by calling
//! `client::Connection::channel_open_session`, then
//! `client::Connection::exec`, then possibly
//! `client::Connection::data` a number of times to send data to the
//! command's standard input, and finally `Connection::channel_eof`
//! and `Connection::channel_close`.
//!
//! # Design principles
//!
//! The main goal of this library is conciseness, and reduced size and
//! readability of the library's code. Moreover, this library is split
//! between Thrussh, which implements the main logic of SSH clients
//! and servers, and Thrussh-keys, which implements calls to
//! cryptographic primitives.
//!
//! One non-goal is to implement all possible cryptographic algorithms
//! published since the initial release of SSH. Technical debt is
//! easily acquired, and we would need a very strong reason to go
//! against this principle. If you are designing a system from
//! scratch, we urge you to consider recent cryptographic primitives
//! such as Ed25519 for public key cryptography, and Chacha20-Poly1305
//! for symmetric cryptography and MAC.
//!
//! # Internal details of the event loop
//!
//! It might seem a little odd that the read/write methods for server
//! or client sessions often return neither `Result` nor
//! `Future`. This is because the data sent to the remote side is
//! buffered, because it needs to be encrypted first, and encryption
//! works on buffers, and for many algorithms, not in place.
//!
//! Hence, the event loop keeps waiting for incoming packets, reacts
//! to them by calling the provided `Handler`, which fills some
//! buffers. If the buffers are non-empty, the event loop then sends
//! them to the socket, flushes the socket, empties the buffers and
//! starts again. In the special case of the server, unsollicited
//! messages sent through a `server::Handle` are processed when there
//! is no incoming packet to read.
//!
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate log;
extern crate thrussh_libsodium as sodium;
#[macro_use]
extern crate thiserror;

pub use cryptovec::CryptoVec;
mod auth;
mod cipher;
mod compression;
mod kex;
mod key;
mod msg;
mod negotiation;
mod ssh_read;
mod sshbuffer;

pub use negotiation::{Named, Preferred};
mod pty;
pub use pty::Pty;

macro_rules! push_packet {
    ( $buffer:expr, $x:expr ) => {{
        use byteorder::{BigEndian, ByteOrder};
        let i0 = $buffer.len();
        $buffer.extend(b"\0\0\0\0");
        let x = $x;
        let i1 = $buffer.len();
        use std::ops::DerefMut;
        let buf = $buffer.deref_mut();
        BigEndian::write_u32(&mut buf[i0..], (i1 - i0 - 4) as u32);
        x
    }};
}
mod session;

/// Server side of this library.
pub mod server;

/// Client side of this library.
pub mod client;

#[derive(Debug, Error)]
pub enum Error {
    /// The key file could not be parsed.
    #[error("Could not read key")]
    CouldNotReadKey,

    /// Unspecified problem with the beginning of key exchange.
    #[error("Key exchange init failed")]
    KexInit,

    /// No common key exchange algorithm.
    #[error("No common key exchange algorithm")]
    NoCommonKexAlgo,

    /// No common signature algorithm.
    #[error("No common key algorithm")]
    NoCommonKeyAlgo,

    /// No common cipher.
    #[error("No common key cipher")]
    NoCommonCipher,

    /// No common compression algorithm.
    #[error("No common compression algorithm")]
    NoCommonCompression,

    /// Invalid SSH version string.
    #[error("invalid SSH version string")]
    Version,

    /// Error during key exchange.
    #[error("Key exchange failed")]
    Kex,

    /// Invalid packet authentication code.
    #[error("Wrong packet authentication code")]
    PacketAuth,

    /// The protocol is in an inconsistent state.
    #[error("Inconsistent state of the protocol")]
    Inconsistent,

    /// The client is not yet authenticated.
    #[error("Not yet authenticated")]
    NotAuthenticated,

    /// Index out of bounds.
    #[error("Index out of bounds")]
    IndexOutOfBounds,

    /// Unknown server key.
    #[error("Unknown server key")]
    UnknownKey,

    /// The server provided a wrong signature.
    #[error("Wrong server signature")]
    WrongServerSig,

    /// Message received/sent on unopened channel.
    #[error("Channel not open")]
    WrongChannel,

    /// Disconnected
    #[error("Disconnected")]
    Disconnect,

    /// No home directory found when trying to learn new host key.
    #[error("No home directory when saving host key")]
    NoHomeDir,

    /// Remote key changed, this could mean a man-in-the-middle attack
    /// is being performed on the connection.
    #[error("Key changed, line {}", line)]
    KeyChanged { line: usize },

    /// Connection closed by the remote side.
    #[error("Connection closed by the remote side")]
    HUP,

    /// Connection timeout.
    #[error("Connection timeout")]
    ConnectionTimeout,

    /// Missing authentication method.
    #[error("No authentication method")]
    NoAuthMethod,

    #[error("Channel send error")]
    SendError,

    #[error(transparent)]
    Keys(#[from] thrussh_keys::Error),

    #[error(transparent)]
    IO(#[from] std::io::Error),

    #[error(transparent)]
    Utf8(#[from] std::str::Utf8Error),

    #[error(transparent)]
    Compress(#[from] flate2::CompressError),

    #[error(transparent)]
    Decompress(#[from] flate2::DecompressError),

    #[error(transparent)]
    Join(#[from] tokio::task::JoinError),

    #[error(transparent)]
    Openssl(#[from] openssl::error::ErrorStack),

    #[error(transparent)]
    Elapsed(#[from] tokio::time::error::Elapsed),
}

#[derive(Debug, Error)]
#[error("Could not reach the event loop")]
pub struct SendError {}

/// Since handlers are large, their associated future types must implement this trait to provide reasonable default implementations (basically, rejecting all requests).
pub trait FromFinished<T>: futures::Future<Output = Result<T, Error>> {
    /// Turns type `T` into `Self`, a future yielding `T`.
    fn finished(t: T) -> Self;
}

impl<T> FromFinished<T> for futures::future::Ready<Result<T, Error>> {
    fn finished(t: T) -> Self {
        futures::future::ready(Ok(t))
    }
}

impl<T: 'static> FromFinished<T> for Box<dyn futures::Future<Output = Result<T, Error>> + Unpin> {
    fn finished(t: T) -> Self {
        Box::new(futures::future::ready(Ok(t)))
    }
}

// mod mac;
// use mac::*;
// mod compression;

/// The number of bytes read/written, and the number of seconds before a key re-exchange is requested.
#[derive(Debug, Clone)]
pub struct Limits {
    pub rekey_write_limit: usize,
    pub rekey_read_limit: usize,
    pub rekey_time_limit: std::time::Duration,
}

impl Limits {
    /// Create a new `Limits`, checking that the given bounds cannot lead to nonce reuse.
    pub fn new(write_limit: usize, read_limit: usize, time_limit: std::time::Duration) -> Limits {
        assert!(write_limit <= 1 << 30 && read_limit <= 1 << 30);
        Limits {
            rekey_write_limit: write_limit,
            rekey_read_limit: read_limit,
            rekey_time_limit: time_limit,
        }
    }
}

impl Default for Limits {
    fn default() -> Self {
        // Following the recommendations of
        // https://tools.ietf.org/html/rfc4253#section-9
        Limits {
            rekey_write_limit: 1 << 30, // 1 Gb
            rekey_read_limit: 1 << 30,  // 1 Gb
            rekey_time_limit: std::time::Duration::from_secs(3600),
        }
    }
}

pub use auth::{AgentAuthError, MethodSet, Signer};

/// A reason for disconnection.
#[allow(missing_docs)] // This should be relatively self-explanatory.
#[derive(Debug)]
pub enum Disconnect {
    HostNotAllowedToConnect = 1,
    ProtocolError = 2,
    KeyExchangeFailed = 3,
    #[doc(hidden)]
    Reserved = 4,
    MACError = 5,
    CompressionError = 6,
    ServiceNotAvailable = 7,
    ProtocolVersionNotSupported = 8,
    HostKeyNotVerifiable = 9,
    ConnectionLost = 10,
    ByApplication = 11,
    TooManyConnections = 12,
    AuthCancelledByUser = 13,
    NoMoreAuthMethodsAvailable = 14,
    IllegalUserName = 15,
}

/// The type of signals that can be sent to a remote process. If you
/// plan to use custom signals, read [the
/// RFC](https://tools.ietf.org/html/rfc4254#section-6.10) to
/// understand the encoding.
#[allow(missing_docs)]
// This should be relatively self-explanatory.
#[derive(Debug, Clone)]
pub enum Sig {
    ABRT,
    ALRM,
    FPE,
    HUP,
    ILL,
    INT,
    KILL,
    PIPE,
    QUIT,
    SEGV,
    TERM,
    USR1,
    Custom(String),
}

impl Sig {
    fn name(&self) -> &str {
        match *self {
            Sig::ABRT => "ABRT",
            Sig::ALRM => "ALRM",
            Sig::FPE => "FPE",
            Sig::HUP => "HUP",
            Sig::ILL => "ILL",
            Sig::INT => "INT",
            Sig::KILL => "KILL",
            Sig::PIPE => "PIPE",
            Sig::QUIT => "QUIT",
            Sig::SEGV => "SEGV",
            Sig::TERM => "TERM",
            Sig::USR1 => "USR1",
            Sig::Custom(ref c) => c,
        }
    }
    fn from_name(name: &[u8]) -> Result<Sig, Error> {
        match name {
            b"ABRT" => Ok(Sig::ABRT),
            b"ALRM" => Ok(Sig::ALRM),
            b"FPE" => Ok(Sig::FPE),
            b"HUP" => Ok(Sig::HUP),
            b"ILL" => Ok(Sig::ILL),
            b"INT" => Ok(Sig::INT),
            b"KILL" => Ok(Sig::KILL),
            b"PIPE" => Ok(Sig::PIPE),
            b"QUIT" => Ok(Sig::QUIT),
            b"SEGV" => Ok(Sig::SEGV),
            b"TERM" => Ok(Sig::TERM),
            b"USR1" => Ok(Sig::USR1),
            x => Ok(Sig::Custom(std::str::from_utf8(x)?.to_string())),
        }
    }
}

/// Reason for not being able to open a channel.
#[derive(Debug, Copy, Clone, PartialEq)]
#[allow(missing_docs)]
pub enum ChannelOpenFailure {
    AdministrativelyProhibited = 1,
    ConnectFailed = 2,
    UnknownChannelType = 3,
    ResourceShortage = 4,
}

impl ChannelOpenFailure {
    fn from_u32(x: u32) -> Option<ChannelOpenFailure> {
        match x {
            1 => Some(ChannelOpenFailure::AdministrativelyProhibited),
            2 => Some(ChannelOpenFailure::ConnectFailed),
            3 => Some(ChannelOpenFailure::UnknownChannelType),
            4 => Some(ChannelOpenFailure::ResourceShortage),
            _ => None,
        }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
/// The identifier of a channel.
pub struct ChannelId(u32);

/// The parameters of a channel.
#[derive(Debug)]
pub(crate) struct Channel {
    recipient_channel: u32,
    sender_channel: ChannelId,
    recipient_window_size: u32,
    sender_window_size: u32,
    recipient_maximum_packet_size: u32,
    sender_maximum_packet_size: u32,
    /// Has the other side confirmed the channel?
    pub confirmed: bool,
    wants_reply: bool,
    pending_data: std::collections::VecDeque<(CryptoVec, Option<u32>, usize)>,
}

#[derive(Debug)]
pub enum ChannelMsg {
    Data {
        data: CryptoVec,
    },
    ExtendedData {
        data: CryptoVec,
        ext: u32,
    },
    Eof,
    Close,
    XonXoff {
        client_can_do: bool,
    },
    ExitStatus {
        exit_status: u32,
    },
    ExitSignal {
        signal_name: Sig,
        core_dumped: bool,
        error_message: String,
        lang_tag: String,
    },
    WindowAdjusted {
        new_size: u32,
    },
    Success,
}

#[cfg(test)]
mod test_compress {
    use super::server::{Auth, Session};
    use super::*;
    use std::collections::HashMap;
    use std::sync::{Arc, Mutex};

    #[tokio::test]
    async fn compress_local_test() {
        test_compress(true).await
    }

    async fn test_compress(local: bool) {
        env_logger::try_init().unwrap_or(());
        let (client_key, addr) = if local {
            let client_key = thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
            let client_pubkey = Arc::new(client_key.clone_public_key());
            let mut config = super::server::Config::default();
            config.preferred = super::Preferred::COMPRESSED;
            config.auth_rejection_time = std::time::Duration::from_secs(0);
            config.connection_timeout = None; // Some(std::time::Duration::from_secs(3));
            config.auth_rejection_time = std::time::Duration::from_secs(3);
            config
                .keys
                .push(thrussh_keys::key::KeyPair::generate_ed25519().unwrap());
            let config = Arc::new(config);
            let sh = Server {
                client_pubkey,
                clients: Arc::new(Mutex::new(HashMap::new())),
                id: 0,
            };
            tokio::spawn(super::server::run(config, "0.0.0.0:2222", sh));
            std::thread::sleep(std::time::Duration::from_millis(100));
            (client_key, "127.0.0.1:2222")
        } else {
            let client_key = thrussh_keys::load_secret_key("id_ed25519", None).unwrap();
            (client_key, "127.0.0.1:2222")
        };

        let mut config = super::client::Config::default();
        config.preferred = super::Preferred::COMPRESSED;
        let config = Arc::new(config);
        let sh = Client {};

        let mut session = super::client::connect(config, addr, sh).await.unwrap();
        debug!("connected");
        if session
            .authenticate_publickey(std::env::var("USER").unwrap(), Arc::new(client_key))
            .await
            .unwrap()
        {
            debug!("authenticated");
            if let Ok(mut channel) = session.channel_open_session().await {
                channel.data(&b"Hello, world!"[..]).await.unwrap();
                if let Some(msg) = channel.wait().await {
                    println!("{:?}", msg)
                }
            }
        }
        if local {
            std::thread::sleep(std::time::Duration::from_secs(40));
        }
    }

    #[derive(Clone)]
    struct Server {
        client_pubkey: Arc<thrussh_keys::key::PublicKey>,
        clients: Arc<Mutex<HashMap<(usize, ChannelId), super::server::Handle>>>,
        id: usize,
    }

    impl server::Server for Server {
        type Handler = Self;
        fn new(&mut self, _: Option<std::net::SocketAddr>) -> Self {
            let s = self.clone();
            self.id += 1;
            s
        }
    }

    impl server::Handler for Server {
        type Error = super::Error;
        type FutureAuth = futures::future::Ready<Result<(Self, server::Auth), Self::Error>>;
        type FutureUnit = futures::future::Ready<Result<(Self, Session), Self::Error>>;
        type FutureBool = futures::future::Ready<Result<(Self, Session, bool), Self::Error>>;

        fn finished_auth(self, auth: Auth) -> Self::FutureAuth {
            futures::future::ready(Ok((self, auth)))
        }
        fn finished_bool(self, b: bool, s: Session) -> Self::FutureBool {
            futures::future::ready(Ok((self, s, b)))
        }
        fn finished(self, s: Session) -> Self::FutureUnit {
            futures::future::ready(Ok((self, s)))
        }
        fn channel_open_session(self, channel: ChannelId, session: Session) -> Self::FutureUnit {
            {
                let mut clients = self.clients.lock().unwrap();
                clients.insert((self.id, channel), session.handle());
            }
            self.finished(session)
        }
        fn auth_publickey(self, _: &str, _: &thrussh_keys::key::PublicKey) -> Self::FutureAuth {
            debug!("auth_publickey");
            self.finished_auth(server::Auth::Accept)
        }
        fn data(self, _channel: ChannelId, data: &[u8], session: Session) -> Self::FutureUnit {
            debug!("server data = {:?}", std::str::from_utf8(data));
            self.finished(session)
        }
    }

    struct Client {}

    impl client::Handler for Client {
        type Error = super::Error;
        type FutureUnit = futures::future::Ready<Result<(Self, client::Session), Self::Error>>;
        type FutureBool = futures::future::Ready<Result<(Self, bool), Self::Error>>;

        fn finished_bool(self, b: bool) -> Self::FutureBool {
            futures::future::ready(Ok((self, b)))
        }
        fn finished(self, session: client::Session) -> Self::FutureUnit {
            futures::future::ready(Ok((self, session)))
        }
        fn check_server_key(
            self,
            server_public_key: &thrussh_keys::key::PublicKey,
        ) -> Self::FutureBool {
            println!("check_server_key: {:?}", server_public_key);
            self.finished_bool(true)
        }
        fn channel_open_confirmation(
            self,
            channel: ChannelId,
            _: u32,
            _: u32,
            session: client::Session,
        ) -> Self::FutureUnit {
            println!("channel_open_confirmation: {:?}", channel);
            self.finished(session)
        }
        fn data(
            self,
            channel: ChannelId,
            data: &[u8],
            session: client::Session,
        ) -> Self::FutureUnit {
            debug!(
                "client data on channel {:?}: {:?}",
                channel,
                std::str::from_utf8(data)
            );
            self.finished(session)
        }
    }
}