/*
 * The Cryptonit security software suite is developped by IDEALX
 * Cryptonit Team (http://IDEALX.org/ and http://cryptonit.org).
 *
 * Copyright 2003-2006 IDEALX
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301, USA. 
 *
 * In addition, as two special exceptions:
 *
 * 1) IDEALX S.A.S gives permission to:
 *  * link the code of portions of his program with the OpenSSL library under
 *    certain conditions described in each source file
 *  * distribute linked combinations including the two, with respect to the
 *    OpenSSL license and with the GPL
 *
 * You must obey the GNU General Public License in all respects for all of the
 * code used other than OpenSSL. If you modify file(s) with this exception,
 * you may extend this exception to your version of the file(s), but you are
 * not obligated to do so. If you do not wish to do so, delete this exception
 * statement from your version, in all files (this very one along with all
 * source files).

 * 2) IDEALX S.A.S acknowledges that portions of his sourcecode uses (by the
 * way of headers inclusion) some work published by 'RSA Security Inc.'. Those
 * portions are "derived from the RSA Security Inc. PKCS #11Cryptographic
 * Token Interface (Cryptoki)" as described in each individual source file.
 */

#include "CertificateStore.hh"

#include "Utils.hh"

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>

namespace Cryptonit
{

    CertificateStore::CertificateStore()
    {
	certificatePath = "";
	certificates = std::vector<Certificate>(0);
    }


    CertificateStore::CertificateStore( const std::string path )
    {
	certificates = std::vector<Certificate>(0);
	certificatePath = appendDir( path, CERTIFICATE_STORE_DEFAULT_PATH );

	/* load all certs */
	DIR* dir;
	if( (dir = opendir( certificatePath.c_str() )) != NULL ) {
	    struct dirent* entry;
	    entry = readdir( dir );

	    while( entry != NULL ) {
		Certificate certificate;

		std::string filename;
		filename = appendDir( certificatePath, entry->d_name );

		// Skip . and .. entries
		std::string buffer;
		buffer = filename.substr( filename.size() - 2 );

		if( buffer != ".." && buffer != "/." && buffer != "\\." ) {
#ifdef DEBUG
 		    std::cerr << "Loading certificate " << filename;
#endif 

		    if( certificate.load( filename.c_str() ) != SUCCESS ) {
#ifdef DEBUG
 			std::cerr << ": failed" << std::endl; 
#endif 
		    }
		    else {
#ifdef DEBUG
 			std::cerr << ": success" << std::endl;
#endif 
			certificates.push_back( certificate );
		    }
		}
		entry = readdir( dir );
	    }
	    
	    closedir( dir );

#ifdef DEBUG
 	    std::cerr << certificates.size() << " certificate(s) added." << std::endl;
#endif 

	}
	else {
#ifdef DEBUG
 	    std::cerr << "Cannot open dir '" << certificatePath << "' for reading." << std::endl;
#endif 
	}
    }


    CertificateStore::CertificateStore( const CertificateStore &src )
    {
	certificatePath = src.certificatePath;
	certificates = std::vector<Certificate>( src.certificates );
    }


    CertificateStore::~CertificateStore()
    {
    }


    bool CertificateStore::add( Certificate &certificate, const bool write )
    {
	if( write ) {

	    std::string filename;
	    filename += certificate.getHash();
	    filename += ".";
	    filename += CERTIFICATE_DEFAULT_EXTENSION;

	    std::string fullPath;
	    fullPath = appendDir( certificatePath, filename );

#ifdef DEBUG
 	    std::cerr << "Add file '" << fullPath << "' into the certificate store." << std::cerr;
#endif 
	    
	    if( certificate.save( fullPath.c_str() ) != SUCCESS ) {
#ifdef DEBUG
 		std::cerr << "Cannot write certificate on disk !" << std::cerr;
#endif 
		return false;
	    }
	}

	certificates.push_back( Certificate(certificate) );

	return true;
    }

	
    bool CertificateStore::remove( const size_t index )
    {
	if( index < certificates.size() ) {

	    std::vector<Certificate>::iterator it = certificates.begin();
	    unsigned int i = 0;

	    while( it != certificates.end() && i != index ) {
		it++;
		i++;
	    }

	    /* We have the corresponding certificate */
	    if( i == index ) {

		std::string filename;
		filename += it->getHash();
		filename += ".";
		filename += CERTIFICATE_DEFAULT_EXTENSION;

		std::string fullPath;
		fullPath = appendDir( certificatePath, filename );

		if( std::remove( fullPath.c_str() ) != 0 )
#ifdef DEBUG
 		    std::cerr << "Warning, cannot remove certificate file '" << fullPath 
			      << "'from the store." << std::endl;
#endif 

		certificates.erase( it );
		
		return true;
	    }
	    else {
#ifdef DEBUG
 		std::cerr << "There is no certificate associated with this index (" 
			  << index << ")." << std::endl;
#endif 
		return false;
	    }
	}

#ifdef DEBUG
 	std::cerr << "The provided index is invalid (" << index << ")." << std::endl;
#endif 
	return false;
    }


    const std::vector<Certificate> CertificateStore::getCertificates() const
    {
	return std::vector<Certificate>( certificates );
    }


    size_t CertificateStore::getNbCertificates() const
    {
	return certificates.size();
    }


    std::string CertificateStore::getCertificatePath() const
    {
	return certificatePath;
    }
    
}

