//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2013 Vincent Richard <vincent@vmime.org>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// Linking this library statically or dynamically with other modules is making
// a combined work based on this library.  Thus, the terms and conditions of
// the GNU General Public License cover the whole combination.
//

#include "vmime/config.hpp"


#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT


#include "vmime/security/sasl/XOAuth2SASLMechanism.hpp"

#include "vmime/security/sasl/SASLContext.hpp"
#include "vmime/security/sasl/SASLSession.hpp"

#include "vmime/exception.hpp"

#include <sstream>


namespace vmime {
namespace security {
namespace sasl {


XOAuth2SASLMechanism::XOAuth2SASLMechanism(shared_ptr <SASLContext> ctx, const string& /* name */)
	: m_context(ctx), m_complete(false)
{
}


XOAuth2SASLMechanism::~XOAuth2SASLMechanism()
{
}


const string XOAuth2SASLMechanism::getName() const
{
	return "XOAUTH2";
}


bool XOAuth2SASLMechanism::step
	(shared_ptr <SASLSession> sess,
	 const byte_t* /* challenge */, const size_t /* challengeLen */,
	 byte_t** response, size_t* responseLen)
{
	// Build initial response
	//
	// The SASL XOAUTH2 initial client response has the following format:
	//    base64("user=" {User} "^Aauth=Bearer " {Access Token} "^A^A")

	const std::string user(sess->getAuthenticator()->getUsername());
	const std::string accessToken(sess->getAuthenticator()->getAccessToken());

	std::ostringstream initRespBytes;
	initRespBytes.write("user=", 5);
	initRespBytes.write(user.c_str(), user.length());
	initRespBytes.write("\x01", 1);
	initRespBytes.write("auth=Bearer ", 12);
	initRespBytes.write(accessToken.c_str(), accessToken.length());
	initRespBytes.write("\x01\x01", 2);

	const std::string initResp = initRespBytes.str();

	// Set initial response
	byte_t* res = new byte_t[initResp.length()];
	std::copy(initResp.c_str(), initResp.c_str() + initResp.length(), res);

	*response = res;
	*responseLen = initResp.length();
	m_complete = true;

	return true;
}


bool XOAuth2SASLMechanism::isComplete() const
{
	return m_complete;
}


bool XOAuth2SASLMechanism::hasInitialResponse() const
{
	return true;
}


void XOAuth2SASLMechanism::encode
	(shared_ptr <SASLSession> /* sess */,
	 const byte_t* input, const size_t inputLen,
	 byte_t** output, size_t* outputLen)
{
	// No encoding performed, just copy input bytes
	byte_t* res = new byte_t[inputLen];
	std::copy(input, input + inputLen, res);

	*outputLen = inputLen;
	*output = res;
}


void XOAuth2SASLMechanism::decode
	(shared_ptr <SASLSession> /* sess */,
	 const byte_t* input, const size_t inputLen,
	 byte_t** output, size_t* outputLen)
{
	// No decoding performed, just copy input bytes
	byte_t* res = new byte_t[inputLen];
	std::copy(input, input + inputLen, res);

	*outputLen = inputLen;
	*output = res;
}


} // sasl
} // security
} // vmime


#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
