use std::path::PathBuf;
use std::sync::Arc;

use capnp::capability::Promise;

use sequoia_ipc::capnp_rpc as capnp_rpc;
use capnp_rpc::pry;
use capnp_rpc::rpc_twoparty_capnp::Side;
use capnp_rpc::{RpcSystem, twoparty};

use sequoia_openpgp as openpgp;
use openpgp::Cert;
use openpgp::crypto::mpi::Ciphertext;
use openpgp::crypto::Password;
use openpgp::packet::Key;
use openpgp::packet::PKESK;
use openpgp::packet::key;
use openpgp::parse::Parse;
use openpgp::types::HashAlgorithm;
use openpgp::types::PublicKeyAlgorithm;
use openpgp::Fingerprint;

use sequoia_ipc as ipc;

use crate::keystore_protocol_capnp::keystore;

use crate::Error;
use crate::ImportStatus;
use crate::PasswordSource;
use crate::Protection;
use crate::Result;
use crate::error::ServerError;

mod backend;
use backend::Servers;

type JoinResult<T> = std::result::Result<T, tokio::task::JoinError>;

pub struct Keystore {
    #[allow(unused)]
    descriptor: ipc::Descriptor,
    ks: keystore::Client,
}

impl Keystore {
    /// Instantiates a new `Keystore` server.
    pub fn new(descriptor: ipc::Descriptor,
               _local: &tokio::task::LocalSet)
        -> Result<Self>
    {
        // The application may not use the rust logging framework.
        // Try to initialize it so that the user can get some output.
        let _ = env_logger::Builder::from_default_env().try_init();

        let home = descriptor.context().home().to_path_buf();
        log::debug!("KeystoreServer::new: keystore directory: {}",
                    home.display());
        Ok(Keystore {
            descriptor,
            ks: capnp_rpc::new_client(KeystoreServer::new(home)?),
        })
    }

    /// A generic variant of [`Keystore::new`].
    ///
    /// This is a variant of [`Keystore::new`], which returns a
    /// generic type instead of a [`Keystore`].  This is useful in
    /// conjunction with [`sequoia_ipc::Descriptor::new`].
    pub fn new_descriptor(descriptor: ipc::Descriptor,
                          local: &tokio::task::LocalSet)
        -> Result<Box<dyn ipc::Handler>>
    {
        Self::new(descriptor, local).map(|d| Box::new(d) as Box<dyn ipc::Handler>)
    }
}

impl ipc::Handler for Keystore {
    fn handle(&self,
              network: twoparty::VatNetwork<tokio_util::compat::Compat<tokio::net::tcp::OwnedReadHalf>>)
        -> RpcSystem<Side>
    {
        RpcSystem::new(Box::new(network), Some(self.ks.clone().client))
    }
}

#[derive(Clone, Debug)]
struct KeystoreServer {
    inner: Arc<KeystoreServerInner>,
}

struct KeystoreServerInner {
    home: PathBuf,
    rt: tokio::runtime::Runtime,
}

impl std::fmt::Debug for KeystoreServerInner {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("KeystoreServer")
         .field("home", &self.home)
         .finish()
    }
}

impl KeystoreServer {
    fn new(home: PathBuf) -> Result<Self>
    {
        Ok(Self {
            inner: Arc::new(KeystoreServerInner {
                home,
                rt: tokio::runtime::Runtime::new()?,
            }),
        })
    }
}

// Like try!, but stores the error in `$results`.
macro_rules! ary {
    ($results:expr, $r:expr) => {
        match $r {
            Ok(r) => r,
            Err(err) => {
                pry!($results.get().get_result())
                    .init_err()
                    .from_anyhow(&anyhow::Error::from(err));
                return Promise::ok(());
            }
        }
    }
}

// Server stubs run in three phases:
//
// - Phase 1 extracts the parameters, and copies any required data from
//   self.
//
// - Phase 2 executes the method's body in a separate async task so
//   that tasks that are bound to this thread are not blocked.
//
// - Phase 3 serializes the result in the main thread.
//
// This macro avoids some boilerplate in phase 2 and phase 3.
//
// `phase2` is an async block, which runs the server's body.  It is
// spawned as a separate async task, which, unlike the current task,
// can run on other threads.
//
// `phase3` is a closure, which is fed phase 2's return value, and
// serializes the results.
macro_rules! run {
    ($ks: expr, $results: expr, $phase2: expr, $phase3: expr) => {
        Promise::from_future(async move {
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            let ks: KeystoreServer = $ks;
            let r: JoinResult<Result<_>> = ks.inner.rt.spawn($phase2).await;

            // Convert a join error to an internal server error.
            let r = match r {
                Ok(r) => r,
                Err(err) => {
                    let err = err.to_string();
                    let mut builder = $results.get().get_result()?.init_err()
                        .init_internal_error(err.len() as u32);
                    builder.push_str(&err);

                    return Ok(());
                }
            };

            // Phase 3: Serialize the result in the main thread.
            let r: Result<_> = r.and_then($phase3);

            if let Err(err) = r {
                $results.get().get_result()?
                    .init_err()
                    .from_anyhow(&anyhow::Error::from(err));
            }
            Ok(())
        })
    };
}

impl keystore::Server for KeystoreServer {
    fn backends(&mut self,
                _params: keystore::BackendsParams,
                mut results: keystore::BackendsResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.clone();
        let ks = self.clone();
        let ks2 = self.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let server = server.lock().await;

                let ids = server.iter()
                    .map(|backend| backend.id())
                    .collect::<Vec<String>>();

                Ok(ids)
            },
            // Phase 3: Serialize the result in the main thread.
            |ids: Vec<String>| {
                let mut ok = results.get().get_result()?
                    .initn_ok(ids.len() as u32);
                for (i, id) in ids.into_iter().enumerate() {
                    let server: BackendServer = BackendServer::new(
                        ks2.clone(), id);
                    let cap: keystore::backend::Client
                        = capnp_rpc::new_client(server);
                    ok.set(i as u32, cap.client.hook);
                }

                Ok(())
            })
    }

    fn decrypt(&mut self,
                params: keystore::DecryptParams,
                mut results: keystore::DecryptResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let mut pkesks = Vec::new();
        for (i, pkesk) in pry!(pry!(params.get()).get_pkesks()).iter().enumerate() {
            pkesks.push((i, ary!(results, PKESK::from_bytes(pry!(pkesk)))));
        }

        let ks0 = self.clone();
        let ks = self.clone();

        log::trace!("KeystoreServer::decrypt({})",
                    pkesks.iter()
                    .map(|(_i, pkesk)| {
                        pkesk.recipient()
                            .map(|r| r.to_string())
                            .unwrap_or_else(
                                || "anonymous".into())
                    })
                    .collect::<Vec<String>>()
                    .join(", "));

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let (wildcard, known): (Vec<&(usize, PKESK)>, Vec<&(usize, PKESK)>)
                    = pkesks
                    .iter()
                    .partition(|(_i, pkesk)| pkesk.recipient().is_none());

                // Keys that are inaccessible, but that could become available
                // with a little help from the user (e.g., unlock a password,
                // insert a device, etc.)
                let mut inaccessible: Vec<InaccessibleDecryptionKey> = Vec::new();

                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if ! known.is_empty() {
                    log::trace!("Considering PKESKs with known recipients");
                    for backend in server.backends.iter_mut() {
                        for device in backend.list().await {
                            for mut key in device.list().await {
                                for (i, pkesk) in known.iter() {
                                    let keyid = key.key_handle();
                                    if ! pkesk.recipient()
                                        .map(|h| h.aliases(&keyid))
                                        .unwrap_or(false)
                                    {
                                        log::trace!("PKESK for {:?}, key: {}, skipping",
                                                    pkesk.recipient(), keyid);
                                        continue;
                                    }

                                    if ! key.decryption_capable().await {
                                        log::trace!("{} cannot be used for decryption",
                                                    key.fingerprint());
                                        continue;
                                    }

                                    let mut abort = false;
                                    let protection = key.locked().await;
                                    log::trace!("{}'s protection: {:?}",
                                                keyid, protection);
                                    match protection {
                                        // An unlocked key should work.
                                        Protection::Unlocked => (),
                                        // External protection may
                                        // succeed, but it may block.
                                        Protection::UnknownProtection(_) => (),
                                        Protection::ExternalPassword(_) => (),
                                        Protection::ExternalTouch(_) => (),
                                        Protection::ExternalOther(_) => (),
                                        protection @ Protection::Password(_) => {
                                            log::trace!("{} is locked: {:?}",
                                                        keyid, protection);
                                            abort = true;
                                        }
                                    }
                                    if ! key.available().await {
                                        log::trace!("{} is unavailable",
                                                    key.fingerprint());
                                        abort = true;
                                    }
                                    if abort {
                                        log::trace!("{} is inaccessible",
                                                    keyid);
                                        inaccessible.push(InaccessibleDecryptionKey {
                                            key: KeyDescriptor {
                                                server: KeyServer::new(
                                                    ks.clone(),
                                                    backend.id(),
                                                    device.id(), key.id()),
                                                key: key.public_key().await.clone(),
                                            },
                                            pkesk: pkesk.clone(),
                                        });
                                        continue;
                                    }

                                    if let Some((sym_algo, sk))
                                        = key.decrypt_pkesk(pkesk).await
                                    {
                                        let fpr = key.fingerprint();
                                        return Ok((*i, fpr, sym_algo, sk));
                                    } else {
                                        log::trace!("PKESK for {:?} matches key {}, \
                                                     but failed to decrypt it!",
                                                    pkesk.recipient(), keyid);
                                    }
                                }
                            }
                        }
                    }
                }

                if ! wildcard.is_empty() {
                    log::trace!("Considering PKESKs with anonymous recipients");
                    for backend in server.backends.iter_mut() {
                        for device in backend.list().await {
                            for mut key in device.list().await {
                                for (i, pkesk) in wildcard.iter() {
                                    let keyid = key.key_handle();
                                    let public_key = key.public_key().await;
                                    if pkesk.pk_algo() != public_key.pk_algo() {
                                        log::trace!("skipping PKESK: \
                                                     algorithm mismatch");
                                        continue;
                                    }

                                    if ! key.decryption_capable().await {
                                        log::trace!("{} cannot be used for decryption",
                                                    key.fingerprint());
                                        continue;
                                    }

                                    let mut abort = false;
                                    let protection = key.locked().await;
                                    log::trace!("{}'s protection: {:?}",
                                                keyid, protection);
                                    match protection {
                                        // An unlocked key should work.
                                        Protection::Unlocked => (),
                                        // External protection may
                                        // succeed, but it may block.
                                        Protection::UnknownProtection(_) => (),
                                        Protection::ExternalPassword(_) => (),
                                        Protection::ExternalTouch(_) => (),
                                        Protection::ExternalOther(_) => (),
                                        protection @ Protection::Password(_) => {
                                            log::trace!("{} is locked: {:?}",
                                                        keyid, protection);
                                            abort = true;
                                        }
                                    }
                                    if ! key.available().await {
                                        log::trace!("{} is unavailable",
                                                    key.fingerprint());
                                        abort = true;
                                    }
                                    if abort {
                                        log::trace!("{} is inaccessible",
                                                    keyid);
                                        inaccessible.push(InaccessibleDecryptionKey {
                                            key: KeyDescriptor {
                                                server: KeyServer::new(
                                                    ks.clone(),
                                                    backend.id(),
                                                    device.id(), key.id()),
                                                key: key.public_key().await.clone(),
                                            },
                                            pkesk: pkesk.clone(),
                                        });
                                        continue;
                                    }

                                    if let Some((sym_algo, sk))
                                        = key.decrypt_pkesk(pkesk).await
                                    {
                                        let fpr = key.fingerprint();
                                        return Ok((*i, fpr, sym_algo, sk));
                                    } else {
                                        log::trace!("PKESK failed to decrypt \
                                                     with {}", keyid);
                                    }
                                }
                            }
                        }
                    }
                }

                if ! inaccessible.is_empty() {
                    log::debug!("Failed to decrypt, but have {} candidate keys \
                                 that are inaccessible",
                                inaccessible.len());
                    Err(ServerError::InaccessibleDecryptionKey(inaccessible).into())
                } else {
                    // XXX: The right error is: no known secret key can decrypt
                    // it.
                    Err(Error::EOF.into())
                }
            },
            // Phase 3: Serialize the result.
            |(i, fingerprint, sym_algo, sk)| {
                let mut ok = results.get().get_result()?.init_ok();

                ok.set_index(i as u32);
                ok.set_fingerprint(fingerprint.as_bytes());
                ok.set_fingerprint_version(match fingerprint {
                    Fingerprint::V4(_) => 4,
                    Fingerprint::V6(_) => 6,
                    Fingerprint::Unknown { version, .. } =>
                        version.unwrap_or(0),
                    _ => 0,
                });
                ok.set_algo(sym_algo.map(u8::from).unwrap_or(0));
                ok.set_session_key(&sk);

                Ok::<_, anyhow::Error>(())
            })
    }
}

#[derive(Clone, Debug)]
struct BackendServer {
    ks: KeystoreServer,
    id: String,
}

impl BackendServer {
    fn new<S: AsRef<str>>(ks: KeystoreServer, id: S) -> Self {
        let server = Self {
            ks,
            id: id.as_ref().into(),
        };

        server
    }
}

impl keystore::backend::Server for BackendServer {
    fn id(&mut self,
          _params: keystore::backend::IdParams,
          mut results: keystore::backend::IdResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        let mut ok = pry!(results.get().get_result());
        pry!(ok.set_ok(&self.id));

        Promise::ok(())
    }

    fn devices(&mut self, _params: keystore::backend::DevicesParams,
            mut results: keystore::backend::DevicesResults)
            -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let ks2 = self.ks.clone();
        let backend_id = self.id.clone();
        let backend_id2 = self.id.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    let devices: Vec<_> = backend.list().await.collect();
                    let ids = devices.into_iter()
                        .map(|d| d.id())
                        .collect::<Vec<String>>();

                    Ok(ids)
                } else {
                    Err(Error::EOF.into())
                }
            },
            // Phase 3: Serialize the result.
            |ids: Vec<String>| {
                let mut ok = results.get().get_result()?
                    .initn_ok(ids.len() as u32);
                for (i, device_id) in ids.into_iter().enumerate() {
                    let server = DeviceServer::new(
                        ks2.clone(), &backend_id2, device_id);
                    let cap: keystore::device::Client
                        = capnp_rpc::new_client(server);
                    ok.set(i as u32, cap.client.hook);
                }

                Ok::<(), anyhow::Error>(())
            })
    }

    fn import<'a>(&mut self, params: keystore::backend::ImportParams,
                  mut results: keystore::backend::ImportResults)
            -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let bytes = pry!(pry!(params.get()).get_cert());
        let cert = ary!(results, Cert::from_bytes(bytes));

        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let ks2 = self.ks.clone();
        let backend_id = self.id.clone();
        let backend_id2 = self.id.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    let mut results = Vec::new();
                    for (import_status, key) in backend.import(cert).await? {
                        use openpgp::serialize::MarshalInto;
                        let key_bytes = key.public_key().await.to_vec()
                            .expect("serializing to a vec is infallible");

                        results.push(
                            (import_status, key.device().await.id(), key.id(),
                             key_bytes))
                    }
                    Ok(results)
                } else {
                    Err(Error::EOF.into())
                }
            },
            // Phase 3: Serialize the result.
            |imports: Vec<(ImportStatus, String, String, Vec<u8>)>| {
                let mut ok = results.get().get_result()?
                    .initn_ok(imports.len() as u32);
                for (i, (import_status, device_id, key_id, key_bytes))
                    in imports.into_iter().enumerate()
                {
                    let mut r = ok.reborrow().get(i as u32);

                    r.reborrow().init_status().set_import_status(import_status)?;

                    let mut key_descriptor = r.init_key();

                    let server = KeyServer::new(
                        ks2.clone(), &backend_id2, device_id, key_id);
                    let cap: keystore::key::Client
                        = capnp_rpc::new_client(server);
                    key_descriptor.set_handle(cap);

                    key_descriptor.set_public_key(&key_bytes[..]);
                }

                Ok::<(), anyhow::Error>(())
            })
    }
}

#[derive(Clone, Debug)]
struct DeviceServer {
    ks: KeystoreServer,
    backend: String,
    id: String,
}

impl DeviceServer {
    fn new<B, I>(ks: KeystoreServer, backend: B, id: I) -> Self
        where B: AsRef<str>, I: AsRef<str>
    {
        let device = Self {
            ks,
            backend: backend.as_ref().into(),
            id: id.as_ref().into(),
        };

        device
    }
}

impl keystore::device::Server for DeviceServer {
    fn id(&mut self,
          _params: keystore::device::IdParams,
          mut results: keystore::device::IdResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        let mut ok = pry!(results.get().get_result());
        pry!(ok.set_ok(&self.id));

        Promise::ok(())
    }

    fn keys(&mut self, _params: keystore::device::KeysParams,
            mut results: keystore::device::KeysResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let ks2 = self.ks.clone();
        let backend_id = self.backend.clone();
        let backend_id2 = self.backend.clone();
        let device_id = self.id.clone();
        let device_id2 = self.id.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        let mut info = Vec::new();
                        let keys: Vec<_> = device.list().await.collect();
                        for key in keys.into_iter() {
                            let key_id = key.id();

                            use openpgp::serialize::MarshalInto;
                            let key_bytes = key.public_key().await.to_vec()
                                .expect("serializing to a vec is infallible");

                            info.push((key_id, key_bytes));
                        }
                        Ok(info)
                    } else {
                        Err(Error::EOF.into())
                    }
                } else {
                    Err(Error::EOF.into())
                }
            },
            // Phase 3: Serialize the result.
            |info: Vec<(String, Vec<u8>)>| {
                let mut ok = results.get().get_result()?
                    .initn_ok(info.len() as u32);
                for (i, (key_id, key_bytes)) in info.into_iter().enumerate() {
                    let server = KeyServer::new(
                        ks2.clone(), &backend_id2, &device_id2, key_id);
                    let cap: keystore::key::Client
                        = capnp_rpc::new_client(server);

                    let mut r = ok.reborrow().get(i as u32);
                    r.set_handle(cap);
                    r.set_public_key(&key_bytes[..]);
                }

                Ok::<(), anyhow::Error>(())
            })
    }
}

#[derive(Clone, Debug)]
struct KeyServer {
    ks: KeystoreServer,
    backend: String,
    device: String,
    key: String,
}

impl KeyServer {
    fn new<B, D, K>(ks: KeystoreServer, backend: B, device: D, key: K)
        -> Self
        where B: AsRef<str>, D: AsRef<str>, K: AsRef<str>
    {
        let key = Self {
            ks,
            backend: backend.as_ref().into(),
            device: device.as_ref().into(),
            key: key.as_ref().into(),
        };

        key
    }
}

impl keystore::key::Server for KeyServer {
    fn id(&mut self,
          _params: keystore::key::IdParams,
          mut results: keystore::key::IdResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        let mut ok = pry!(results.get().get_result());
        pry!(ok.set_ok(&self.key));

        Promise::ok(())
    }

    fn unlock(&mut self,
              params: keystore::key::UnlockParams,
              mut results: keystore::key::UnlockResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let p = pry!(params.get());
        let password: Vec<u8> = pry!(p.get_password()).to_vec();

        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(mut key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            match key.unlock(Some(&password.into())).await {
                                Ok(()) => return Ok(()),
                                Err(err) => return Err(err.into()),
                            }
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |()| {
                let _ok = results.get().get_result()?.set_ok(());
                Ok(())
            })
    }

    fn decrypt_ciphertext(&mut self,
                          params: keystore::key::DecryptCiphertextParams,
                          mut results: keystore::key::DecryptCiphertextResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let algo = PublicKeyAlgorithm::from(pry!(params.get()).get_algo());
        let ciphertext = pry!(pry!(params.get()).get_ciphertext());
        let ciphertext = ary!(results, Ciphertext::parse(algo, ciphertext));

        let plaintext_len = match pry!(params.get()).get_plaintext_len() {
            0 => None,
            n => Some(n as usize),
        };

        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(mut key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            if ! key.decryption_capable().await {
                                log::trace!("{} is not for decryption",
                                            key.fingerprint());
                                return Err(Error::NotDecryptionCapable(
                                    key.fingerprint().to_string()).into());
                            }

                            match key.decrypt_ciphertext(
                                &ciphertext, plaintext_len).await
                            {
                                Ok(sk) => return Ok(sk),
                                Err(err) => return Err(err.into()),
                            }
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |sk| {
                let ok = results.get().get_result()?
                    .initn_ok(sk.len() as u32);
                ok.copy_from_slice(&sk);

                Ok(())
            })
    }

    fn sign_message(&mut self,
                    params: keystore::key::SignMessageParams,
                    mut results: keystore::key::SignMessageResults)
            -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let p = pry!(params.get());
        let hash_algo = HashAlgorithm::from(p.get_hash_algo());
        let digest: Vec<u8> = pry!(p.get_digest()).to_vec();

        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(mut key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            log::trace!("Signing digest with {} (hash: {})",
                                        key.keyid(), hash_algo);

                            if ! key.signing_capable().await {
                                log::trace!("{} is not for signing",
                                            key.fingerprint());
                                return Err(Error::NotSigningCapable(
                                    key.fingerprint().to_string()).into());
                            }
                            match key.sign(hash_algo, &digest).await {
                                Ok((pk_algo, sig)) => {

                                    use openpgp::serialize::MarshalInto;
                                    let bytes = sig.to_vec()
                                        .expect("serializing to a vec is infallible");
                                    return Ok((pk_algo, bytes));
                                }
                                Err(err) => {
                                    log::info!("Failed to sign {} digest with {}: {}",
                                               hash_algo, key.keyid(), err);
                                    return Err(err.into());
                                }
                            }
                        }
                    }
                }

                log::debug!("Invalid key capability: {}/{}/{} not found",
                            backend_id, device_id, key_id);

                return Err(Error::EOF.into());
            },
            // Phase 3: Serialize the result in the main thread.
            |(pk_algo, bytes)| {
                let mut ok = results.get().get_result()?.init_ok();
                ok.set_pk_algo(u8::from(pk_algo));

                let mpis = ok.init_mpis(bytes.len() as u32);
                mpis.copy_from_slice(&bytes);

                Ok(())
            })
    }

    fn available(&mut self,
                 _params: keystore::key::AvailableParams,
                 mut results: keystore::key::AvailableResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            return Ok(key.available().await);
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |available: bool| {
                let _ok = results.get().get_result()?.set_ok(available);
                Ok(())
            })
    }

    fn locked(&mut self,
              _params: keystore::key::LockedParams,
              mut results: keystore::key::LockedResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            return Ok(key.locked().await);
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |protection: Protection| {
                let mut result = results.get().get_result()?.init_ok();
                result.set_protection(protection)?;
                Ok(())
            })
    }

    fn password_source(&mut self,
                       _params: keystore::key::PasswordSourceParams,
                       mut results: keystore::key::PasswordSourceResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            return Ok(key.password_source().await);
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |password_source: PasswordSource| {
                let mut result = results.get().get_result()?.init_ok();
                result.set_password_source(password_source)?;
                Ok(())
            })
    }

    fn decryption_capable(&mut self,
                          _params: keystore::key::DecryptionCapableParams,
                          mut results: keystore::key::DecryptionCapableResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            return Ok(key.decryption_capable().await);
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |decryption_capable: bool| {
                let _ok = results.get().get_result()?.set_ok(decryption_capable);
                Ok(())
            })
    }

    fn signing_capable(&mut self,
                       _params: keystore::key::SigningCapableParams,
                       mut results: keystore::key::SigningCapableResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            return Ok(key.signing_capable().await);
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |signing_capable: bool| {
                let _ok = results.get().get_result()?.set_ok(signing_capable);
                Ok(())
            })
    }

    fn export(&mut self,
              _params: keystore::key::ExportParams,
              mut results: keystore::key::ExportResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(mut key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            use openpgp::serialize::MarshalInto;

                            let key = key.export().await?;
                            return Ok(key.to_vec()?);
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |sk: Vec<u8>| {
                let ok = results.get().get_result()?
                    .initn_ok(sk.len() as u32);
                ok.copy_from_slice(&sk);

                Ok(())
            })
    }

    fn change_password(&mut self,
                       params: keystore::key::ChangePasswordParams,
                       mut results: keystore::key::ChangePasswordResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let p = pry!(params.get());

        use keystore::change_password_action::Which;
        let new_password = match pry!(pry!(p.get_password()).which()) {
            Which::Ask(()) => None,
            Which::Password(password) => {
                Some(Password::from(pry!(password)))
            }
        };

        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(mut key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            key.change_password(new_password.as_ref()).await?;
                            return Ok(());
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |()| {
                let _ok = results.get().get_result()?.set_ok(());
                Ok(())
            })
    }

    fn delete_secret_key_material(&mut self,
                                  _params: keystore::key::DeleteSecretKeyMaterialParams,
                                  mut results: keystore::key::DeleteSecretKeyMaterialResults)
        -> ::capnp::capability::Promise<(), ::capnp::Error>
    {
        // Phase 1: Extract the parameters, and copy any required data
        // from self.
        let ks0 = self.ks.clone();
        let ks = self.ks.clone();
        let backend_id = self.backend.clone();
        let device_id = self.device.clone();
        let key_id = self.key.clone();

        run!(
            ks0,
            results,
            // Phase 2: Execute the method's body in a separate task
            // so that tasks that are bound to this thread are not
            // blocked.
            async move {
                let server = Servers::get(ks.inner.home.as_path()).await?;
                let mut server = server.lock().await;

                if let Some(backend) = server.backends.iter_mut()
                    .find(|b| b.id() == backend_id)
                {
                    if let Some(device) = backend.list().await
                        .find(|d| d.id() == device_id)
                    {
                        if let Some(mut key) = device.list().await
                            .find(|k| k.id() == key_id)
                        {
                            key.delete_secret_key_material().await?;
                            return Ok(());
                        }
                    }
                }

                Err(Error::EOF.into())
            },
            // Phase 3: Serialize the result in the main thread.
            |()| {
                let _ok = results.get().get_result()?.set_ok(());
                Ok(())
            })
    }
}

// Basically, a wrapper around a KeyHandle that we want to return
// later.  This isn't just a wrapper around a `dyn
// sequoia_keystore_backend::KeyHandle` due to lifetimes.
#[derive(Clone)]
pub(crate) struct KeyDescriptor {
    server: KeyServer,
    key: Key<key::PublicParts, key::UnspecifiedRole>,
}

impl std::fmt::Debug for KeyDescriptor {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "server::KeyDescriptor {{ {} }}",
               self.key.fingerprint())
    }
}

impl KeyDescriptor {
    /// Returns a capability.
    pub fn cap(&self) -> keystore::key::Client {
        capnp_rpc::new_client(self.server.clone())
    }

    /// Returns the key handle.
    pub fn public_key(&self) -> &Key<key::PublicParts, key::UnspecifiedRole> {
        &self.key
    }

    pub fn serialize(&self, mut builder: keystore::key_descriptor::Builder) {
        use openpgp::serialize::MarshalInto;

        builder.set_handle(self.cap());

        let bytes = self.public_key().to_vec()
            .expect("serializing to a vec is infallible");
        builder.set_public_key(&bytes[..]);
    }
}

#[derive(Clone)]
pub(crate) struct InaccessibleDecryptionKey {
    key: KeyDescriptor,
    pkesk: PKESK,
}

impl std::fmt::Debug for InaccessibleDecryptionKey {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "server::InaccessibleDecryptionKey {{ {} }}",
               self.key.key.fingerprint())
    }
}

impl InaccessibleDecryptionKey {
    pub fn serialize(&self, mut builder: keystore::inaccessible_decryption_key::Builder) {
        use openpgp::serialize::MarshalInto;

        self.key.serialize(builder.reborrow().init_key_descriptor());

        let bytes = self.pkesk.to_vec()
            .expect("serializing to a vec is infallible");
        builder.set_pkesk(&bytes[..]);
    }
}
