<commit_before>#[link(name = "nss", vers = "0.0-pre")];

#[feature(struct_variant)];
#[feature(globs)];

extern mod nspr;

extern mod extra;

use std::rt::io::fs::{File};
use std::{os, ptr, vec, str};
use std::rt::io::{Reader, Writer, io_error};
use std::rt::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr};

use std::path::Path;
use std::libc::{c_void};
use std::unstable::atomics::{AtomicBool, Acquire, Release, INIT_ATOMIC_BOOL};

pub use raw::nss::*;
use nspr::raw::nspr::*;

#[cfg(test)]
mod tests;

pub mod raw { pub mod nss; }

static mut NSS_INIT_START: AtomicBool = INIT_ATOMIC_BOOL;
static mut NSS_INIT_END: AtomicBool = INIT_ATOMIC_BOOL;

static mut NSS_UNINIT_START: AtomicBool = INIT_ATOMIC_BOOL;
static mut NSS_UNINIT_END: AtomicBool = INIT_ATOMIC_BOOL;



pub struct NSS { 

    priv nss_ctx: Option<*c_void>,
    priv nss_cert_mod: Option<SECMODModule>,
    cfg_dir: Option<~str>,
}

impl NSS {

pub fn new() -> NSS {
 NSS { nss_ctx: None, nss_cert_mod: None, cfg_dir: None,  }
}

pub fn set_cfg_dir(&mut self, cfg_dir: &str)
{
  self.cfg_dir = Some(cfg_dir.to_owned());
}

pub fn init(&mut self) -> SECStatus {
unsafe {
  if(NSS_IsInitialized() == PRTrue ) { return SECSuccess; }
  if NSS_INIT_START.swap(true, Acquire) { while !NSS_INIT_END.load(Release) { std::task::deschedule(); } }

  self.cfg_dir = match self.cfg_dir { 
            None => Some(os::getenv("SSL_DIR").unwrap_or(format!("{}/.pki/nssdb", os::getenv("HOME").unwrap_or(~"")).to_owned())),
            Some(ref s) => Some(s.to_owned()), };
  let cfg_dir = match self.cfg_dir { 
            Some(ref s) => s.to_owned(),
            None => ~"", };
  let cfg_path = &Path::new(cfg_dir.clone());                              
  let nss_path = format!("sql:{}", cfg_dir);

  if(!cfg_path.exists()) {
          if(NSS_NoDB_Init(ptr::null()) == SECFailure){
                 fail!("NSS is borked!");
          }
     }
     else {
     nss_path.with_c_str(|nssdb| self.nss_ctx = Some(NSS_InitContext(nssdb, ptr::null(), ptr::null(), ptr::null(), ptr::null(), NSS_INIT_READONLY | NSS_INIT_PK11RELOAD)));
     }
 
  do nss_cmd { NSS_SetDomesticPolicy() };
  self.nss_cert_mod = Some(*SECMOD_LoadUserModule("library=libnssckbi.so name=\"Root Certs\"".to_c_str().unwrap(),  ptr::null(), PRFalse));
  if(self.nss_cert_mod.unwrap().loaded != PRTrue)
  {
     return SECFailure;
  }
  NSS_INIT_END.store(true, Release);
 
  if(NSS_IsInitialized() == PRTrue) {
    SECSuccess
  }
  else {
    SECFailure
  } 

 }
}

pub fn uninit(&mut self) -> SECStatus {
    unsafe {
    if(NSS_IsInitialized() == PRFalse) { return SECSuccess; }
    if NSS_UNINIT_START.swap(true, Acquire) { while !NSS_UNINIT_END.load(Release) { std::task::deschedule(); } }
    SECMOD_DestroyModule(&self.nss_cert_mod.unwrap());
    if(!self.nss_ctx.is_none()) { NSS_ShutdownContext(self.nss_ctx.unwrap()) };
    self.nss_ctx = None;
    NSS_UNINIT_END.store(true, Release);
    }
    SECSuccess
}

pub fn trust_cert(file: ~str) -> SECStatus
{
    let path = &Path::new(file);
    let mut retStatus = SECFailure;
    if(!path.exists()){ return retStatus; }
    do io_error::cond.trap(|_| { retStatus = SECFailure; }).inside
    {
      unsafe
      {
        let pemdata = str::from_utf8_owned(File::open(path).read_to_end());
        let cert = CERT_DecodeCertFromPackage(pemdata.to_c_str().unwrap(), pemdata.to_c_str().len() as i32) ;
        let trust = CERTCertTrust { sslFlags: 0, emailFlags: 0, objectSigningFlags: 0 };
        CERT_DecodeTrustString(&trust, "TCu,Cu,Tu".to_c_str().unwrap());
        retStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
      }
    }
    retStatus
}

}
pub fn nss_cmd(blk: &fn() -> SECStatus) {
    let result = blk();
    if(result == SECFailure) {
      fail!("NSS Failed with {}", get_nss_error());
    }
}

pub fn get_nss_error() -> ~str {
    unsafe { std::str::raw::from_c_str(PR_ErrorToName(PR_GetError())) }
}

pub struct SSLStream {
    sslfd: *c_void,
    is_eof: bool,
}

impl SSLStream {

pub fn connect(addr: SocketAddr, hostname: ~str) -> SSLStream<commit_msg>More robust nss database handling<commit_after>#[link(name = "nss", vers = "0.0-pre")];

#[feature(struct_variant)];
#[feature(globs)];

extern mod nspr;

extern mod extra;

use std::rt::io::fs::{File, mkdir_recursive};
use std::{os, ptr, vec, str};
use std::rt::io::{Reader, Writer, io_error};
use std::rt::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr};

use std::path::Path;
use std::libc::{c_void};
use std::unstable::atomics::{AtomicBool, Acquire, Release, INIT_ATOMIC_BOOL};

pub use raw::nss::*;
use nspr::raw::nspr::*;

#[cfg(test)]
mod tests;

pub mod raw { pub mod nss; }

static mut NSS_INIT_START: AtomicBool = INIT_ATOMIC_BOOL;
static mut NSS_INIT_END: AtomicBool = INIT_ATOMIC_BOOL;

static mut NSS_UNINIT_START: AtomicBool = INIT_ATOMIC_BOOL;
static mut NSS_UNINIT_END: AtomicBool = INIT_ATOMIC_BOOL;



pub struct NSS { 

    priv nss_ctx: Option<*c_void>,
    priv nss_cert_mod: Option<SECMODModule>,
    cfg_dir: Option<~str>,
}

impl NSS {

pub fn new() -> NSS {
 NSS { nss_ctx: None, nss_cert_mod: None, cfg_dir: None,  }
}

pub fn set_cfg_dir(&mut self, cfg_dir: &str)
{
  self.cfg_dir = Some(cfg_dir.to_owned());
}

pub fn init(&mut self) -> SECStatus {
unsafe {
  if(NSS_IsInitialized() == PRTrue ) { return SECSuccess; }
  if NSS_INIT_START.swap(true, Acquire) { while !NSS_INIT_END.load(Release) { std::task::deschedule(); } }

  self.cfg_dir = match self.cfg_dir { 
            None => Some(os::getenv("SSL_DIR").unwrap_or(format!("{}/.pki/nssdb", os::getenv("HOME").unwrap_or(~".")).to_owned())),
            Some(ref s) => Some(s.to_owned()), };
  let cfg_dir = match self.cfg_dir { 
            Some(ref s) => s.to_owned(),
            None => ~"", };
  let mut cfg_path = Path::new(cfg_dir.clone());                              
  let mut nss_path = format!("sql:{}", cfg_dir);

  if(!cfg_path.exists()) {
          let system_path = &Path::new("/etc/pki/nssdb");
          if(!system_path.exists()) {
             do io_error::cond.trap(|_|{}).inside { mkdir_recursive(&cfg_path, 0b111_111_111); }
          }
          else {
            cfg_path = Path::new("/etc/pki/nssdb");
            nss_path = format!("sql:{}", system_path.as_str().unwrap());
          }
     }

     if(cfg_path.exists()) {
        nss_path.with_c_str(|nssdb| self.nss_ctx = Some(NSS_InitContext(nssdb, ptr::null(), ptr::null(), ptr::null(), ptr::null(), NSS_INIT_PK11RELOAD)));
     }

     if(NSS_IsInitialized() == PRFalse) {
                if(NSS_NoDB_Init(ptr::null()) == SECFailure){
                    fail!("NSS is borked!");
                }
     }
 
  do nss_cmd { NSS_SetDomesticPolicy() };
  self.nss_cert_mod = Some(*SECMOD_LoadUserModule("library=libnssckbi.so name=\"Root Certs\"".to_c_str().unwrap(),  ptr::null(), PRFalse));
  if(self.nss_cert_mod.unwrap().loaded != PRTrue) {
     return SECFailure;
  }
  NSS_INIT_END.store(true, Release);
 
  if(NSS_IsInitialized() == PRTrue) {
    SECSuccess
  }
  else {
    SECFailure
  } 

 }
}

pub fn uninit(&mut self) -> SECStatus {
    unsafe {
    if(NSS_IsInitialized() == PRFalse) { return SECSuccess; }
    if NSS_UNINIT_START.swap(true, Acquire) { while !NSS_UNINIT_END.load(Release) { std::task::deschedule(); } }
    SECMOD_DestroyModule(&self.nss_cert_mod.unwrap());
    if(!self.nss_ctx.is_none()) { NSS_ShutdownContext(self.nss_ctx.unwrap()) };
    self.nss_ctx = None;
    NSS_UNINIT_END.store(true, Release);
    }
    SECSuccess
}

pub fn trust_cert(file: ~str) -> SECStatus
{
    let path = &Path::new(file);
    let mut retStatus = SECFailure;
    if(!path.exists()){ return retStatus; }
    do io_error::cond.trap(|_| { retStatus = SECFailure; }).inside
    {
      unsafe
      {
        let pemdata = str::from_utf8_owned(File::open(path).read_to_end());
        let cert = CERT_DecodeCertFromPackage(pemdata.to_c_str().unwrap(), pemdata.to_c_str().len() as i32);
        let trust = CERTCertTrust { sslFlags: 0, emailFlags: 0, objectSigningFlags: 0 };
        CERT_DecodeTrustString(&trust, "TCu,Cu,Tu".to_c_str().unwrap());
        retStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
      }
    }
    retStatus
}

}
pub fn nss_cmd(blk: &fn() -> SECStatus) {
    let result = blk();
    if(result == SECFailure) {
      fail!("NSS Failed with {}", get_nss_error());
    }
}

pub fn get_nss_error() -> ~str {
    unsafe { std::str::raw::from_c_str(PR_ErrorToName(PR_GetError())) }
}

pub struct SSLStream {
    sslfd: *c_void,
    is_eof: bool,
}

impl SSLStream {

pub fn connect(addr: SocketAddr, hostname: ~str) -> SSLStream
{'fraction_non_alphanumeric': 0.1679637588570101, 'fraction_numerical': 0.0037170403066558253, 'mean_word_length': 3.651539708265802, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2710812', 'n_tokens_mistral': 3335, 'n_tokens_neox': 3283, 'n_words': 589}