1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
use std::marker::PhantomData;
use std::ptr;
use std::sync::RwLockReadGuard;

use ffi;

use {Protocol, TOKEN, Token};
use error::Result;
use utils::{self, StrResult};

#[derive(Debug, Copy, Clone)]
pub struct EngineInfo<'a, T: 'a> {
    raw: ffi::gpgme_engine_info_t,
    phantom: PhantomData<&'a T>,
}

impl<'a, T> EngineInfo<'a, T> {
    pub unsafe fn from_raw<'b>(raw: ffi::gpgme_engine_info_t) -> EngineInfo<'b, T> {
        debug_assert!(!raw.is_null());
        EngineInfo {
            raw: raw,
            phantom: PhantomData,
        }
    }

    pub fn raw(&self) -> ffi::gpgme_engine_info_t {
        self.raw
    }

    /// Returns the `Protocol` implemented by the engine.
    pub fn protocol(&self) -> Protocol {
        unsafe { Protocol::from_raw((*self.raw).protocol) }
    }

    pub fn filename(&self) -> StrResult<'a> {
        unsafe { utils::from_cstr((*self.raw).file_name) }
    }

    pub fn home_dir(&self) -> StrResult<'a> {
        unsafe { utils::from_cstr((*self.raw).file_name) }
    }

    pub fn version(&self) -> StrResult<'a> {
        unsafe { utils::from_cstr((*self.raw).version) }
    }

    pub fn required_version(&self) -> StrResult<'a> {
        unsafe { utils::from_cstr((*self.raw).req_version) }
    }
}

#[derive(Debug, Copy, Clone)]
pub struct EngineInfoIter<'a, T: 'a> {
    current: ffi::gpgme_engine_info_t,
    phantom: PhantomData<&'a T>,
}

impl<'a, T> EngineInfoIter<'a, T> {
    pub unsafe fn from_list<'b>(raw: ffi::gpgme_engine_info_t) -> EngineInfoIter<'b, T> {
        EngineInfoIter {
            current: raw,
            phantom: PhantomData,
        }
    }
}

impl<'a, T> Iterator for EngineInfoIter<'a, T> {
    list_iterator!(EngineInfo<'a, T>, EngineInfo::from_raw);
}

pub struct EngineInfoGuard(RwLockReadGuard<'static, ()>);

impl EngineInfoGuard {
    pub fn new(_token: &Token) -> Result<EngineInfoGuard> {
        let lock = TOKEN.0.engine_info.read().expect("Engine info lock could not be acquired");
        unsafe {
            let mut info = ptr::null_mut();
            return_err!(ffi::gpgme_get_engine_info(&mut info));
        }
        Ok(EngineInfoGuard(lock))
    }

    pub fn get(&self, proto: Protocol) -> Option<EngineInfo<()>> {
        self.iter().find(|info| info.protocol() == proto)
    }

    pub fn iter(&self) -> EngineInfoIter<()> {
        unsafe {
            let mut first = ptr::null_mut();
            assert_eq!(ffi::gpgme_get_engine_info(&mut first), 0);
            EngineInfoIter::from_list(first)
        }
    }
}

impl<'a> IntoIterator for &'a EngineInfoGuard {
    type Item = EngineInfo<'a, ()>;
    type IntoIter = EngineInfoIter<'a, ()>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}