Пример #1
0
// Make sure Server Nym is set on this cron object before loading or saving, since it's
// used for signing and verifying..
bool OTCron::LoadCron()
{
	static const char * szCronFile = "OT-CRON.crn"; // todo stop hardcoding filenames.
	
	OT_ASSERT(NULL != GetServerNym());
	
	// ------------------------------------------------------------------------
	
	bool bFolderExists = OTLog::ConfirmOrCreateFolder(OTLog::CronFolder()); // <path>/cron is where all cronlogs go.
	
	if (!bFolderExists)
	{
		OTLog::vError("Unable to create or confirm folder \"%s\" in order to load Cron file.\n",
					  OTLog::CronFolder());
		return false;
	}
	
	// ------------------------------------------------------------------------
	
	OTString strCronfileLocalPath;
	strCronfileLocalPath.Format("%s%s%s", OTLog::CronFolder(), OTLog::PathSeparator(), szCronFile);
	
	// ------------------------------------------------------------------------
	
	OTString strCronfilePath;
	strCronfilePath.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), strCronfileLocalPath.Get());
	
	std::ifstream in(strCronfilePath.Get(), std::ios::binary);
	
	if (in.fail())
	{
		OTLog::vError("Error opening file in OTCron::LoadCron: %s\n",
					  strCronfilePath.Get());
		return false;
	}
	
	std::stringstream buffer;
	buffer << in.rdbuf();
	
	std::string contents(buffer.str());
	
	OTString strRawFile = contents.c_str();
	
	bool bSuccess = false;

	if (strRawFile.GetLength())
	{
		bSuccess = LoadContractFromString(strRawFile);
		
		if (bSuccess)
		{
			bSuccess = VerifySignature(*GetServerNym());
		}
	}
	
	return bSuccess;
	
	// ------------------------------------------------------------------------
}
Пример #2
0
OTCronItem * OTCronItem::LoadCronReceipt(const long & lTransactionNum)
{
	
	// ------------------------------------------------------------------------
	
	bool bFolderExists = OTLog::ConfirmOrCreateFolder(OTLog::CronFolder()); // <path>/cron is where all cronlogs go.
	
	if (!bFolderExists)
	{
		OTLog::vError("Unable to create or confirm folder \"%s\"\n in order to load Cron Receipt %ld.\n",
					  OTLog::CronFolder(), lTransactionNum);
		return NULL;
	}
	
	// ------------------------------------------------------------------------
	
	OTString strCronItemLocalPath;
	strCronItemLocalPath.Format("%s%s%ld.crn", OTLog::CronFolder(), 
								OTLog::PathSeparator(), lTransactionNum);
	
	bool bFileExists = OTLog::ConfirmFile(strCronItemLocalPath.Get());
	
	if (!bFileExists)
	{
		OTLog::vError("Attempted to load non-existent Cron Record for transaction %ld in folder %s.\n",
					  lTransactionNum, strCronItemLocalPath.Get());
		return NULL;
	}
	
	// ------------------------------------------------------------------------
	
	OTString strCronItemPath;
	strCronItemPath.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), 
						   strCronItemLocalPath.Get());
	
	std::ifstream in(strCronItemPath.Get(), std::ios::binary);
	
	if (in.fail())
	{
		OTLog::vError("Error opening file in OTCronItem::LoadCronReceipt: %s\n",
					  strCronItemPath.Get());
		return NULL;
	}
	
	std::stringstream buffer;
	buffer << in.rdbuf();
	
	std::string contents(buffer.str());
	
	OTString strRawFile = contents.c_str();
	
	if (strRawFile.GetLength())
		return OTCronItem::NewCronItem(strRawFile);
	
	return NULL;
	
	// ------------------------------------------------------------------------
}
bool OTSocket_ZMQ_4::Listen(const OTString & strBindingPath)
{
    if (!strBindingPath.Exists())		{ OTLog::vError("%s: Error: %s dosn't exist!\n", __FUNCTION__, "strBindingPath");	OT_FAIL; }
    if (5 > strBindingPath.GetLength()) { OTLog::vError("%s: Error: %s is too short!\n", __FUNCTION__, "strBindingPath");	OT_FAIL; }

    m_strBindingPath = strBindingPath;

    return (this->Listen());
}
bool OTSocket_ZMQ_4::Connect(const OTString & strConnectPath)
{
    if (!strConnectPath.Exists())		{ OTLog::vError("%s: Error: %s dosn't exist!\n", __FUNCTION__, "strConnectPath");	OT_FAIL; }
    if (5 > strConnectPath.GetLength()) { OTLog::vError("%s: Error: %s is too short!\n", __FUNCTION__, "strConnectPath");	OT_FAIL; }

    m_strConnectPath = strConnectPath;  // set the connection path.

    return (this->Connect());
}
Пример #5
0
// append a string at the end of the current buffer.
void OTString::Concatenate(const OTString & strBuf)
{
    std::string str_output;

    if ((m_lLength > 0) && (NULL != m_strBuffer))
        str_output += m_strBuffer;

    if (strBuf.Exists() && (strBuf.GetLength() > 0))
        str_output += strBuf.Get();

    Set(str_output.c_str());
}
Пример #6
0
const bool OTPaths::LoadSetScriptsFolder  // ie. PrefixFolder() + lib/opentxs/
	(
	OTSettings * pConfig, //optional
	const OTString & strScriptsFolder,	//optional
	const bool & bIsRelative			//optional
	)
{
	if (NULL == pConfig)  { OT_ASSERT(false); return false; }

	const bool bPreLoaded(pConfig->IsLoaded());

	if (!bPreLoaded)
	{
		pConfig->Reset();
		if(!pConfig->Load()) { OT_ASSERT(false); return false; }
	}

	OTString strRelativeKey = "";
	strRelativeKey.Format("%s%s","scripts",OT_CONFIG_ISRELATIVE);

	// local vairables.
	bool bConfigIsRelative = false;
	OTString strConfigFolder = "";

	bool bKeyIsNew = false;

	if (!pConfig->CheckSet_bool("paths",strRelativeKey,true,bConfigIsRelative,bKeyIsNew)) { return false; }
	if (!pConfig->CheckSet_str("paths","scripts",OT_SCRIPTS_DIR,strConfigFolder,bKeyIsNew)) { return false; }

	if (!strConfigFolder.Compare(strScriptsFolder))  // only if we need to.
	{
		if(strScriptsFolder.Exists() && (3 < strScriptsFolder.GetLength()))
		{
			// update the local vairables.
			bConfigIsRelative = bIsRelative;
			strConfigFolder = strScriptsFolder;

			bool bNewOrUpdated = false;

			if (!pConfig->Set_bool("paths","scripts_is_",bConfigIsRelative,bNewOrUpdated)) { return false; }
			if (!pConfig->Set_str( "paths","scripts",strConfigFolder,bNewOrUpdated)) {return false; }
		}
	}

	if(bIsRelative)
	{
		if(!FixPath(strConfigFolder,strConfigFolder,true)) { OT_ASSERT(false); return false; }

		OTString strScriptPath = "";
		if(AppendFolder(strScriptPath,PrefixFolder(),strConfigFolder)); else { OT_ASSERT(false); return false; }

		m_strScriptsFolder = strScriptPath; // set
	}
	else
	{
		if(!ToReal(strConfigFolder,strConfigFolder)) { OT_ASSERT(false); return false; }
		if(!FixPath(strConfigFolder,strConfigFolder,true)) { OT_ASSERT(false); return false; }
		m_strScriptsFolder = strConfigFolder; // set
	}

	if (!bPreLoaded)
	{
		if(!pConfig->Save()) { OT_ASSERT(false); return false; }
		pConfig->Reset();
	}
	return true;  // success
}
Пример #7
0
/// This function first Packs the incoming string, using whatever is the default packer. (MsgPack or Protobuf).
/// Then it Compresses the packed binary data using zlib. (ezcompress.)
/// Then it Base64-Encodes the compressed binary and sets it as a string on THIS OBJECT.
/// 
/// I added these pieces 1-by-1 over time. At first the messages were too long, so I started compressing them.
/// Then they were not binary compatible across various platforms, so I added the packing.
//
bool OTASCIIArmor::SetAndPackString(const OTString & strData, bool bLineBreaks) //=true
{	
	Release();
	
	if (strData.GetLength() < 1)
		return true;
	// --------------------------------------------------------
	OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either.
	
	// Here I use the default storage context to create the object (the blob.)
	// I also originally created OTASCIIArmor::GetPacker() using OTDB_DEFAULT_PACKER,
	// so I know everything is compatible.
	//
	OTDB::OTDBString * pOTDBString = dynamic_cast<OTDB::OTDBString *>(OTDB::CreateObject(OTDB::STORED_OBJ_STRING));
	
	OT_ASSERT(NULL != pOTDBString); // Beyond this point, responsible to delete pString.
	OTCleanup<OTDB::OTDBString> theStringAngel(*pOTDBString); // make sure memory is cleaned up.
	// -----------------------------
	const uint32_t	theStringSize32	= strData.GetLength();
	const size_t	theStringSize	= theStringSize32; // might need a cast here. // todo make sure this will handle sizes as big as I need.
	
	pOTDBString->m_string.assign(strData.Get(), // const char * 
								 theStringSize);
	
	OTDB::PackedBuffer * pBuffer = pPacker->Pack(*pOTDBString); // Now we PACK our string before compressing/encoding it.
	
	if (NULL == pBuffer)
	{
		OTLog::Error("Failed packing string in OTASCIIArmor::SetAndPackString. \n");
		return false;
	}
	
	OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // make sure memory is cleaned up.
	// --------------------------------------------------------	
	const uint8_t* pUint = static_cast<const uint8_t*>(pBuffer->GetData());
	const size_t theSize = pBuffer->GetSize();
	// --------------------------------------------------------
	char *	pString	= NULL;
	
	// Set up source buffer and destination buffer
	long nDestLen	= DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.)
	const long lSourcelen	= static_cast<long> (theSize);
	
	unsigned char* pSource	= new unsigned char[lSourcelen+10]; // for safety
	unsigned char* pDest	= new unsigned char[nDestLen  +10]; // for safety
	
	OT_ASSERT(NULL != pSource);
	OT_ASSERT(NULL != pDest);
	
    OTPassword::zeroMemory(pSource, lSourcelen+10);
    OTPassword::zeroMemory(pDest,   nDestLen  +10);
    
//    void * OTPassword::safe_memcpy(void   * dest,
//                                   uint32_t dest_size,
//                                   const
//                                   void   * src,
//                                   uint32_t src_length,
//                                   bool     bZeroSource/*=false*/) // if true, sets the source buffer to zero after copying is done.

    OTPassword::safe_memcpy(pSource, lSourcelen, pUint, static_cast<uint32_t>(theSize));
	
	// Now we are compressing first before base64-encoding (for strings, anyway)	
	int nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen );
	
	// If the destination buffer wasn't the right size the first time around,
	// then we re-allocate it to the right size (which we now know) and try again...
	if ( nErr == EZ_BUF_ERROR )
	{
		delete [] pDest;
		pDest = new unsigned char [nDestLen+10]; // enough room now
		OT_ASSERT(NULL != pDest);
        
        OTPassword::zeroMemory(pDest, nDestLen+10);
		
		nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen );
	}
	
	// Clean this up...
	delete [] pSource;
	pSource = NULL;
	
	// Still errors?
	if ( nErr == EZ_BUF_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_FAIL_MSG("Error allocating memory in OTASCIIArmor::SetAndPackString\n");
	}
	else if ( nErr == EZ_STREAM_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_FAIL_MSG( "pDest is NULL in OTASCIIArmor::SetAndPackString\n");
	}
	else if ( nErr == EZ_DATA_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_FAIL_MSG("corrupted pSrc passed to ezuncompress OTASCIIArmor::SetAndPackString\n");
	}
	else if ( nErr == EZ_MEM_ERROR )
	{
		delete [] pDest;	
		pDest = NULL;
		
		OT_FAIL_MSG("Out of memory in OTASCIIArmor::SetAndPackString\n");
	}
	
	OT_ASSERT_MSG(pDest != NULL, "pDest NULL in OTASCIIArmor::SetAndPackString\n");
	
	// Success
	if (0 < nDestLen)
	{
		// Now let's base-64 encode it...
        pString = OTCrypto::It()->Base64Encode((const uint8_t*)pDest, nDestLen, bLineBreaks);
//		pString = OT_base64_encode((const uint8_t*)pDest, nDestLen, (bLineBreaks ? 1 : 0));
		
		delete [] pDest;
		pDest = NULL;
		
		if (pString)
		{
			Set(pString);
			delete [] pString; pString=NULL; 
			return true;
		}
		else 
		{
			OTLog::Error("pString NULL in OTASCIIArmor::SetAndPackString\n");
		}
	}
	else 
	{
		OTLog::Error("nDestLen 0 in OTASCIIArmor::SetAndPackString\n");
	}
	
	if (pDest)
		delete [] pDest;
	
	pDest = NULL;
	
	return false;	
}
Пример #8
0
// static
const bool OTDataFolder::Init(const OTString & strThreadContext)
{
	if (NULL != pDataFolder) return false; // we already have a data dir setup.

	if (!strThreadContext.Exists())	   { OTLog::sError("%s: Null: %s passed in!\n", __FUNCTION__, "strThreadContext"	); OT_ASSERT(false); }
	if (3 > strThreadContext.GetLength())	   { OTLog::sError("%s: Too Short: %s !\n", __FUNCTION__, "strThreadContext"	); OT_ASSERT(false); }

	pDataFolder = new OTDataFolder;  // make the new instance

	pDataFolder->m_bInitialized = false;

	// setup the config instance.
	OTSettings * pSettings(new OTSettings(OTPaths::GlobalConfigFile()));
	pSettings->Reset();
	if (!pSettings->Load()) return false;

	// setup the RelativeKey
	OTString l_strRelativeKey("");
	l_strRelativeKey.Format("%s%s",strThreadContext.Get(),OT_CONFIG_ISRELATIVE);

	bool l_IsRelative(false), l_Exist(false);
	OTString l_strFolderName(""), l_strDataConifgFilename("");

	// check the config for an existing configuration.
	if(!pSettings->Check_bool("data_path",l_strRelativeKey,l_IsRelative,l_Exist)) { return false; }			// is data folder relative

	if (l_Exist)
	{
		if(!pSettings->Check_str("data_path",strThreadContext,l_strFolderName,l_Exist)) { return false; }	// what is the data folder

		if (l_Exist)
		{
			if(!pSettings->Check_str("data_config",strThreadContext,l_strDataConifgFilename,l_Exist)) { return false; }	// what is config file name

			if (l_Exist)
			{
				if (l_IsRelative) // data folder path
				{
					if(!OTPaths::AppendFolder(pDataFolder->m_strDataFolderPath, OTPaths::AppDataFolder(), l_strFolderName)) { return false; }
				}
				else
				{
					pDataFolder->m_strDataFolderPath = l_strFolderName;
				}

				// data config file path.
				if(!OTPaths::AppendFile(pDataFolder->m_strDataConifgFilePath, OTPaths::AppDataFolder(), l_strDataConifgFilename)) { return false; }

				pDataFolder->m_bInitialized = true;
				return true;
			}
		}
	}

	// if we get here we do not have a valid config, lets set one.

	// setup the default conifg file-name;
	l_strFolderName.Format("%s%s",strThreadContext.Get(), DATA_FOLDER_EXT);
	l_strDataConifgFilename.Format("%s%s",strThreadContext.Get(), CONFIG_FILE_EXT);

	if(!pSettings->Set_bool("data_path", l_strRelativeKey, true, l_Exist)) { return false; }
	if(!pSettings->Set_str("data_path", strThreadContext, l_strFolderName,l_Exist)) { return false; }
	if(!pSettings->Set_str("data_config", strThreadContext, l_strDataConifgFilename, l_Exist)) { return false; }

	if(!OTPaths::AppendFolder(pDataFolder->m_strDataFolderPath,OTPaths::AppDataFolder(),l_strFolderName)) { return false; }
	if(!OTPaths::AppendFile(pDataFolder->m_strDataConifgFilePath, OTPaths::AppDataFolder(), l_strDataConifgFilename)) { return false; }

	// save config
	if (!pSettings->Save()) return false;
	pSettings->Reset();

	if (NULL != pSettings) delete pSettings;
	pSettings = NULL;

	// have set the default dir, now returning true;

	pDataFolder->m_bInitialized = true;
	return true;
}
Пример #9
0
// The LoadSet Functions will update the static values.
const bool OTPaths::LoadSetPrefixFolder	// eg. /usr/local/  
	(	
	OTSettings * pConfig,	//optional
	const OTString & strPrefixFolder				//optional
	//const bool & bIsRelative (cannot be relative);
	)
{
	/*
	The prefix path is special.

	This path is tested if it is different to the
	one that would be automatically selected by this program
	(aka either compiled into, or from the registry, or the default user data directory).

	If the set path is different to what would be supplied and the ‘override path’ value is set.
	Then we will use that path.

	Otherwise, we will update the path in the configuration to link against the updated path.

	Users will need to set the ‘override path’ flag in the configuration,
	if they want to manually set the prefix path.
	*/

	if (NULL == pConfig)  { OT_ASSERT(false); return false; }

	const bool bPreLoaded(pConfig->IsLoaded());

	if (!bPreLoaded)
	{
		pConfig->Reset();
		if(!pConfig->Load()) { OT_ASSERT(false); return false; }
	}

	// get default path
	OTString strDefaultPrefixPath(OT_PREFIX_PATH);

#ifdef _WIN32
	OTString strTemp;
	if (OTPaths::Win_GetInstallFolderFromRegistry(strTemp))
	{
		strDefaultPrefixPath = strTemp;
	}
#endif

	// now check the configuration to see what values we have:
	OTString strConfigPath = "";
	bool bNewPath = false;
	bool bHaveRelativePath = false; // should always be false.
	bool bPrefixPathOverride = false;
	bool bNoOverrideFlagWasSet = false;

	if(!pConfig->CheckSet_str("paths","prefix_path",strDefaultPrefixPath,strConfigPath,bNewPath)) { return false; }

	OTString strPrefixPathOverride("prefix_path_override");
	if(!pConfig->CheckSet_bool("paths",strPrefixPathOverride,false,bPrefixPathOverride,bNoOverrideFlagWasSet,"; Set this if you don't want this path to change")) {return false; }

	OTString strLocalPrefixPath = "";

	// if the caller has supplied a prefix folder, lets set that.
	if(strPrefixFolder.Exists() && (3 < strPrefixFolder.GetLength()))
	{
		if (!strConfigPath.Compare(strPrefixFolder))
		{
			// we set the new path (from this function caller)
			bool bNewOrUpdate = false;
			if(!pConfig->Set_str("paths","prefix_path",strPrefixFolder,bNewOrUpdate)) { return false; }
		}
		strLocalPrefixPath = strPrefixFolder; // set
	}
	else
	{
		// we should update the path
		if (!bPrefixPathOverride)
		{
			if (!strConfigPath.Compare(strDefaultPrefixPath))
			{
				// we set the new default path (since we have no overide set)
				bool bNewOrUpdate = false;
				if(!pConfig->Set_str("paths","prefix_path",strDefaultPrefixPath,bNewOrUpdate)) { return false; }
			}
			strLocalPrefixPath = strDefaultPrefixPath; // set
		}
		else
		{
			strLocalPrefixPath = strConfigPath; // set
		}
	}

	if (!strLocalPrefixPath.Exists()) { OT_ASSERT(false); }

	if(!ToReal(strLocalPrefixPath,strLocalPrefixPath)) { OT_ASSERT(false); return false; }
	if(!FixPath(strLocalPrefixPath,strLocalPrefixPath,true)) { OT_ASSERT(false); return false; }

	m_strPrefixFolder = strLocalPrefixPath;

	if (!bPreLoaded)
	{
		if(!pConfig->Save()) { OT_ASSERT(false); return false; }
		pConfig->Reset();
	}
	return true;
}
Пример #10
0
int main (int argc, char **argv) 
{
	OTLog::vOutput(0, "\n\nWelcome to Open Transactions... Test Client -- version %s\n"
				   "(transport build: OTMessage -> TCP -> SSL)\n"
				   "IF YOU PREFER TO USE ZMQ (message based), then rebuild from main folder like this:\n"
				   "cd ..; make clean; make\n\n", 
				   OTLog::Version());

	OT_API::InitOTAPI();

	// -----------------------------------------------------------------------
	// The beginnings of an INI file!!

	OTString strPath;

	{
		CSimpleIniA ini; // We're assuming this file is on the path.
		SI_Error rc = ini.LoadFile("./.ot_ini"); // todo: stop hardcoding. 

		if (rc >=0)
		{
			const char * pVal = ini.GetValue("paths", "client_path", SERVER_PATH_DEFAULT); // todo stop hardcoding.

			if (NULL != pVal)
				strPath.Set(pVal);
			else
				strPath.Set(SERVER_PATH_DEFAULT);
		}
		else 
		{
			strPath.Set(SERVER_PATH_DEFAULT);
		}
	}
	// -----------------------------------------------------------------------

	OTString strCAFile, strKeyFile, strSSLPassword;

	if (argc < 2)
	{
		OTLog::vOutput(0, "\n==> USAGE:    %s   <SSL-password>  <absolute_path_to_data_folder>\n\n"
#if defined (FELLOW_TRAVELER)					   
				"(Password defaults to '%s' if left blank.)\n"
				"(Folder defaults to '%s' if left blank.)\n"
#else
				"(The test password is always 'test'.\n'cd data_folder' then 'pwd' to see the absolute path.)\n"
#endif
					   "\n\n", argv[0]
#if defined (FELLOW_TRAVELER)					   
					   , KEY_PASSWORD, 
					   strPath.Get()
#endif					   
					   );
	
#if defined (FELLOW_TRAVELER)
		strSSLPassword.Set(KEY_PASSWORD);

		OTString strClientPath(strPath.Get());
        g_OT_API.Init(strClientPath);  // SSL gets initialized in here, before any keys are loaded.
#else
		exit(1);
#endif
	}
	else if (argc < 3)
	{
		OTLog::vOutput(0, "\n==> USAGE:    %s   <SSL-password>  <absolute_path_to_data_folder>\n\n"
#if defined (FELLOW_TRAVELER)					      
				"(Folder defaults to '%s' if left blank.)\n"
#endif
					   "\n\n", argv[0]
#if defined (FELLOW_TRAVELER)
					   , strPath.Get()
#endif
					   );
		
#if defined (FELLOW_TRAVELER)					   
		strSSLPassword.Set(argv[1]);

		OTString strClientPath(strPath.Get());
        g_OT_API.Init(strClientPath);  // SSL gets initialized in here, before any keys are loaded.
#else
		exit(1);
#endif
	}
	else 
	{
		strSSLPassword.Set(argv[1]);

		OTString strClientPath(argv[2]);
        g_OT_API.Init(strClientPath);  // SSL gets initialized in here, before any keys are loaded.
	}	

	OTLog::vOutput::(0, "Using as path to data folder:  %s\n", OTLog::Path());

	strCAFile. Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), CA_FILE);
	strKeyFile.Format("%s%s%s", OTLog::Path(), OTLog::PathSeparator(), KEY_FILE);


	// ------------------------------------------------------------------------------

	//
	// Basically, loop:
	//
	//	1) Present a prompt, and get a user string of input. Wait for that.
	//
	//	2) Process it out as an OTMessage to the server. It goes down the pipe.
	//
	//	3) Sleep for 1 second.
	//
	//	4) Awake and check for messages to be read in response from the server.
	//	   Loop. As long as there are any responses there, then process and handle
	//	   them all.
	//	   Then continue back up to the prompt at step (1).

    char buf[200] = "";
 	int retVal = 0;

	int nExpectResponse = 0;

	OTLog::Output(0, "You may wish to 'load' then 'connect' then 'stat'.\n");
	OTLog::vOutput(4, "Starting client loop. u_header size in C code is %d.\n", OT_CMD_HEADER_SIZE);


	for(;;)
	{
		buf[0] = 0; // Making it fresh again.

		nExpectResponse = 0;

		// 1) Present a prompt, and get a user string of input. Wait for that.
		OTLog::Output(0, "\nWallet> ");

		if (NULL == fgets(buf, sizeof(buf)-10, stdin)) // Leaving myself 10 extra bytes at the end for safety's sake.
            break;

		OTLog::Output(0, ".\n..\n...\n....\n.....\n......\n.......\n........\n.........\n..........\n"
				"...........\n............\n.............\n");

		// so we can process the user input
		std::string strLine = buf;

		// 1.5 The one command that doesn't involve a message to the server (so far)
		//     is the command to load the wallet from disk (which we do before we can
		//     do anything else.)  That and maybe the message to CONNECT to the server.
		// Load wallet.xml
		if (strLine.compare(0,4,"load") == 0)
		{
			OTLog::Output(0, "User has instructed to load wallet.xml...\n");
			g_OT_API.GetWallet()->LoadWallet("wallet.xml");
 
//			g_OT_API.GetWallet()->SaveWallet("NEWwallet.xml"); // todo remove this test code.

			continue;
		}

		else if (strLine.compare(0,5,"clear") == 0)
		{
			if (NULL == g_pTemporaryNym)
			{
				OTLog::Output(0, "No Nym yet available. Try 'load'.\n");
				continue;
			}

			g_pTemporaryNym->RemoveAllNumbers();

			g_pTemporaryNym->SaveSignedNymfile(*g_pTemporaryNym);

			OTLog::Output(0, "Successfully removed all issued and transaction numbers. Saving nym...\n");

			continue;
		}			

		else if (strLine.compare(0,7,"payment") == 0)
		{
			if (NULL == g_pTemporaryNym)
			{
				OTLog::Output(0, "No Nym yet available to sign the payment plan with. Try 'load'.\n");
				continue;
			}

			OTLog::Output(0, "Enter your Asset Account ID that the payments will come from: ");
			OTString strTemp;
			strTemp.OTfgets(std::cin);

			const OTIdentifier ACCOUNT_ID(strTemp), USER_ID(*g_pTemporaryNym);
			OTAccount * pAccount = g_OT_API.GetWallet()->GetAccount(ACCOUNT_ID);

			if (NULL == pAccount)
			{
				OTLog::Output(0, "That account isn't loaded right now. Try 'load'.\n");
				continue;
			}

			// To write a payment plan, like a cheque, we need to burn one of our transaction numbers. (Presumably
			// the wallet is also storing a couple of these, since they are needed to perform any transaction.)
			//
			// I don't have to contact the server to write a payment plan -- as long as I already have a transaction
			// number I can use to write it. Otherwise I'd have to ask the server to send me one first.
			OTString strServerID(pAccount->GetRealServerID());
			long lTransactionNumber=0;

			if (false == g_pTemporaryNym->GetNextTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber))
			{
				OTLog::Output(0, "Payment Plans are written offline, but you still need a transaction number\n"
							  "(and you have none, currently.) Try using 'n' to request another transaction number.\n");
				continue;
			}

			// -----------------------------------------------------------------------

			OTString str_RECIPIENT_USER_ID, str_RECIPIENT_ACCT_ID, strConsideration;

			// Get the Recipient Nym ID
			OTLog::Output(0, "Enter the Recipient's User ID (NymID): ");
			str_RECIPIENT_USER_ID.OTfgets(std::cin);		


			// THEN GET AN ACCOUNT ID in that same asset type
			OTLog::Output(0, "Enter the Recipient's ACCOUNT ID (of the same asset type as your account): ");
			str_RECIPIENT_ACCT_ID.OTfgets(std::cin);		

			OTLog::Output(0, "Enter a memo describing consideration for the payment plan: ");
			strConsideration.OTfgets(std::cin);		

			const OTIdentifier	RECIPIENT_USER_ID(str_RECIPIENT_USER_ID), 
								RECIPIENT_ACCT_ID(str_RECIPIENT_ACCT_ID);


			OTPaymentPlan thePlan(pAccount->GetRealServerID(), pAccount->GetAssetTypeID(),
								  pAccount->GetRealAccountID(),	pAccount->GetUserID(),
								  RECIPIENT_ACCT_ID, RECIPIENT_USER_ID);

			// -----------------------------------------------------------------------

			// Valid date range (in seconds)
			OTLog::Output(0, 
						  " 6 minutes	==      360 Seconds\n"
						  "10 minutes	==      600 Seconds\n"
						  "1 hour		==     3600 Seconds\n"
						  "1 day		==    86400 Seconds\n"
						  "30 days			==  2592000 Seconds\n"
						  "3 months		==  7776000 Seconds\n"
						  "6 months		== 15552000 Seconds\n\n"
						  );

			long lExpirationInSeconds = 86400;
			OTLog::vOutput(0, "How many seconds before payment plan expires? (defaults to 1 day: %ld): ", lExpirationInSeconds);
			strTemp.Release();
			strTemp.OTfgets(std::cin);

			if (strTemp.GetLength() > 1)
				lExpirationInSeconds = atol(strTemp.Get());


			// -----------------------------------------------------------------------

			time_t	VALID_FROM	= time(NULL); // This time is set to TODAY NOW

			OTLog::vOutput(0, "Payment plan becomes valid for processing STARTING date\n"
						   "(defaults to now, in seconds) [%ld]: ", VALID_FROM);
			strTemp.Release();
			strTemp.OTfgets(std::cin);

			if (strTemp.GetLength() > 2)
				VALID_FROM = atol(strTemp.Get());

			const time_t VALID_TO = VALID_FROM + lExpirationInSeconds; // now + 86400

			// -----------------------------------------------------------------------

			bool bSuccessSetAgreement = thePlan.SetAgreement(lTransactionNumber, strConsideration, VALID_FROM,	VALID_TO);

			if (!bSuccessSetAgreement)
			{
				OTLog::Output(0, "Failed trying to set the agreement!\n");

				// IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS.
				g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true								

				continue;
			}

			bool bSuccessSetInitialPayment	= true; // the default, in case user chooses not to even have this payment.
			bool bSuccessSetPaymentPlan		= true; // the default, in case user chooses not to have a payment plan
			// -----------------------------------------------------------------------

			OTLog::Output(0, "What is the Initial Payment Amount, if any? [0]: ");
			strTemp.Release(); strTemp.OTfgets(std::cin);
			long lInitialPayment = atol(strTemp.Get());

			if (lInitialPayment > 0)
			{
				time_t	PAYMENT_DELAY = 60; // 60 seconds.

				OTLog::vOutput(0, "From the Start Date forward, how long until the Initial Payment should charge?\n"
							   "(defaults to one minute, in seconds) [%d]: ", PAYMENT_DELAY);
				strTemp.Release();
				strTemp.OTfgets(std::cin);

				if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0)
					PAYMENT_DELAY = atol(strTemp.Get());

				// -----------------------------------------------------------------------

				 bSuccessSetInitialPayment = thePlan.SetInitialPayment(lInitialPayment, PAYMENT_DELAY);
			}

			if (!bSuccessSetInitialPayment)
			{
				OTLog::Output(0, "Failed trying to set the initial payment!\n");

				// IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS.
				g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true								

				continue;
			}

			// -----------------------------------------------------------------------

			OTLog::Output(0, "What is the regular payment amount, if any? [0]: ");
			strTemp.Release(); strTemp.OTfgets(std::cin);
			long lRegularPayment = atol(strTemp.Get());

			if (lRegularPayment > 0) // If there are regular payments.
			{
				// -----------------------------------------------------------------------

				time_t	PAYMENT_DELAY = 120; // 120 seconds.

				OTLog::vOutput(0, "From the Start Date forward, how long until the Regular Payments start?\n"
							   "(defaults to two minutes, in seconds) [%d]: ", PAYMENT_DELAY);
				strTemp.Release();
				strTemp.OTfgets(std::cin);

				if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0)
					PAYMENT_DELAY = atol(strTemp.Get());

				// -----------------------------------------------------------------------

				time_t	PAYMENT_PERIOD = 30; // 30 seconds.

				OTLog::vOutput(0, "Once payments begin, how much time should elapse between each payment?\n"
							   "(defaults to thirty seconds) [%d]: ", PAYMENT_PERIOD);
				strTemp.Release();
				strTemp.OTfgets(std::cin);

				if ((strTemp.GetLength() > 1) && atol(strTemp.Get())>0)
					PAYMENT_PERIOD = atol(strTemp.Get());

				// -----------------------------------------------------------------------

				time_t	PLAN_LENGTH = 0; // 0 seconds (for no max length).

				OTLog::vOutput(0, "From start date, do you want the plan to expire after a certain maximum time?\n"
							   "(defaults to 0 for no) [%d]: ", PLAN_LENGTH);
				strTemp.Release();
				strTemp.OTfgets(std::cin);

				if (strTemp.GetLength() > 1)
					PLAN_LENGTH = atol(strTemp.Get());

				// -----------------------------------------------------------------------

				OTLog::Output(0, "Should there be some maximum number of payments? (Zero for no maximum.) [0]: ");
				strTemp.Release(); strTemp.OTfgets(std::cin);
				int nMaxPayments = atoi(strTemp.Get());

				bSuccessSetPaymentPlan = thePlan.SetPaymentPlan(lRegularPayment, PAYMENT_DELAY, PAYMENT_PERIOD, PLAN_LENGTH, nMaxPayments);
			}

			if (!bSuccessSetPaymentPlan)
			{
				OTLog::Output(0, "Failed trying to set the payment plan!\n");

				// IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS.
				g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true								

				continue;
			}

			thePlan.SignContract(*g_pTemporaryNym);
			thePlan.SaveContract();

			OTString strPlan(thePlan);

			OTLog::vOutput(0, "\n\n(Make sure Both Parties sign the payment plan before submitting to server):\n\n\n%s\n", 
						   strPlan.Get());

			continue;			
		}


		else if (strLine.compare(0,6,"cheque") == 0)
		{
			if (NULL == g_pTemporaryNym)
			{
				OTLog::Output(0, "No Nym yet available to sign the cheque with. Try 'load'.\n");
				continue;
			}


			OTLog::Output(0, "Enter the ID for your Asset Account that the cheque will be drawn on: ");
			OTString strTemp;
			strTemp.OTfgets(std::cin);

			const OTIdentifier ACCOUNT_ID(strTemp), USER_ID(*g_pTemporaryNym);
			OTAccount * pAccount = g_OT_API.GetWallet()->GetAccount(ACCOUNT_ID);

			if (NULL == pAccount)
			{
				OTLog::Output(0, "That account isn't loaded right now. Try 'load'.\n");
				continue;
			}

			// To write a cheque, we need to burn one of our transaction numbers. (Presumably the wallet
			// is also storing a couple of these, since they are needed to perform any transaction.)
			//
			// I don't have to contact the server to write a cheque -- as long as I already have a transaction
			// number I can use to write it. Otherwise I'd have to ask the server to send me one first.
			OTString strServerID(pAccount->GetRealServerID());
			long lTransactionNumber=0;

			if (false == g_pTemporaryNym->GetNextTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber))
			{
				OTLog::Output(0, "Cheques are written offline, but you still need a transaction number\n"
						"(and you have none, currently.) Try using 'n' to request another transaction number.\n");
				continue;
			}


			OTCheque theCheque(pAccount->GetRealServerID(), pAccount->GetAssetTypeID());

			// Recipient
			OTLog::Output(0, "Enter a User ID for the recipient of this cheque (defaults to blank): ");
			OTString strRecipientUserID;
			strRecipientUserID.OTfgets(std::cin);
			const OTIdentifier RECIPIENT_USER_ID(strRecipientUserID.Get());

			// Amount
			OTLog::Output(0, "Enter an amount: ");
			strTemp.Release();
			strTemp.OTfgets(std::cin);
			const long lAmount = atol(strTemp.Get());

			// -----------------------------------------------------------------------

			// Memo
			OTLog::Output(0, "Enter a memo for your check: ");
			OTString strChequeMemo;
			strChequeMemo.OTfgets(std::cin);

			// -----------------------------------------------------------------------

			// Valid date range (in seconds)
			OTLog::Output(0, 
					" 6 minutes	==      360 Seconds\n"
					"10 minutes	==      600 Seconds\n"
					"1 hour		==     3600 Seconds\n"
					"1 day		==    86400 Seconds\n"
					"30 days	==  2592000 Seconds\n"
					"3 months	==  7776000 Seconds\n"
					"6 months	== 15552000 Seconds\n\n"
					);

			long lExpirationInSeconds = 3600;
			OTLog::vOutput(0, "How many seconds before cheque expires? (defaults to 1 hour: %ld): ", lExpirationInSeconds);
			strTemp.Release();
			strTemp.OTfgets(std::cin);

			if (strTemp.GetLength() > 1)
				lExpirationInSeconds = atol(strTemp.Get());


			// -----------------------------------------------------------------------

			time_t	VALID_FROM	= time(NULL); // This time is set to TODAY NOW

			OTLog::vOutput(0, "Cheque may be cashed STARTING date (defaults to now, in seconds) [%ld]: ", VALID_FROM);
			strTemp.Release();
			strTemp.OTfgets(std::cin);

			if (strTemp.GetLength() > 2)
				VALID_FROM = atol(strTemp.Get());


			const time_t VALID_TO = VALID_FROM + lExpirationInSeconds; // now + 3600

			// -----------------------------------------------------------------------

			bool bIssueCheque = theCheque.IssueCheque(lAmount, lTransactionNumber, VALID_FROM, VALID_TO, 
													  ACCOUNT_ID, USER_ID, strChequeMemo,
													  (strRecipientUserID.GetLength() > 2) ? &(RECIPIENT_USER_ID) : NULL);

			if (bIssueCheque)
			{
				theCheque.SignContract(*g_pTemporaryNym);
				theCheque.SaveContract();

				OTString strCheque(theCheque);

				OTLog::vOutput(0, "\n\nOUTPUT:\n\n\n%s\n", strCheque.Get());
			}
			else 
			{
				OTLog::Output(0, "Failed trying to issue the cheque!\n");

				// IF FAILED, ADD TRANSACTION NUMBER BACK TO LIST OF AVAILABLE NUMBERS.
				g_pTemporaryNym->AddTransactionNum(*g_pTemporaryNym, strServerID, lTransactionNumber, true); // bSave=true								
			}

			continue;
		}

		else if (strLine.compare(0,7,"decrypt") == 0)
		{
			if (NULL == g_pTemporaryNym)
			{
				OTLog::Output(0, "No Nym yet available to decrypt with.\n");
				continue;
			}

			OTLog::Output(0, "Enter text to be decrypted:\n> ");

			OTASCIIArmor theArmoredText;
			char decode_buffer[200]; // Safe since we only read sizeof - 1

			do {
				decode_buffer[0] = 0;
				if (NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin))
				{
					theArmoredText.Concatenate("%s\n", decode_buffer);
					OTLog::Output(0, "> ");
				}
				else 
				{
					break;
				}
			} while (strlen(decode_buffer)>1);


			OTEnvelope	theEnvelope(theArmoredText);
			OTString	strDecodedText;

			theEnvelope.Open(*g_pTemporaryNym, strDecodedText);

			OTLog::vOutput(0, "\n\nDECRYPTED TEXT:\n\n%s\n\n", strDecodedText.Get());

			continue;
		}

		else if (strLine.compare(0,6,"decode") == 0)
		{
			OTLog::Output(0, "Enter text to be decoded:\n> ");

			OTASCIIArmor theArmoredText;
			char decode_buffer[200]; // Safe since we only read sizeof - 1.

			do {
				decode_buffer[0] = 0;
				if (NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin))
				{
					theArmoredText.Concatenate("%s\n", decode_buffer);
					OTLog::Output(0, "> ");
				}
				else 
				{
					break;
				}

			} while (strlen(decode_buffer)>1);

			OTString strDecodedText(theArmoredText);

			OTLog::vOutput(0, "\n\nDECODED TEXT:\n\n%s\n\n", strDecodedText.Get());

			continue;
		}

		else if (strLine.compare(0,6,"encode") == 0)
		{
			OTLog::Output(0, "Enter text to be ascii-encoded (terminate with ~ on a new line):\n> ");

			OTString strDecodedText;
			char decode_buffer[200]; // Safe since we only read sizeof - 1.

			do {
				decode_buffer[0] = 0;

				if ((NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) &&
					(decode_buffer[0] != '~'))
				{
					strDecodedText.Concatenate("%s", decode_buffer);
					OTLog::Output(0, "> ");
				}
				else 
				{
					break;
				}

			} while (decode_buffer[0] != '~');

			OTASCIIArmor theArmoredText(strDecodedText);

			OTLog::vOutput(0, "\n\nENCODED TEXT:\n\n%s\n\n", theArmoredText.Get());

			continue;
		}

		else if (strLine.compare(0,4,"hash") == 0)
		{
			OTLog::Output(0, "Enter text to be hashed (terminate with ~ on a new line):\n> ");

			OTString strDecodedText;
			char decode_buffer[200]; // Safe since we only read sizeof - 1.

			do {
				decode_buffer[0] = 0;

				if ((NULL != fgets(decode_buffer, sizeof(decode_buffer)-1, stdin)) &&
					(decode_buffer[0] != '~'))
				{
					strDecodedText.Concatenate("%s\n", decode_buffer);
					OTLog::Output(0, "> ");
				}
				else 
				{
					break;
				}

			} while (decode_buffer[0] != '~');

			OTIdentifier theIdentifier;
			theIdentifier.CalculateDigest(strDecodedText);

			OTString strHash(theIdentifier);

			OTLog::vOutput(0, "\n\nMESSAGE DIGEST:\n\n%s\n\n", strHash.Get());

			continue;
		}

		else if (strLine.compare(0,4,"stat") == 0)
		{
			OTLog::Output(0, "User has instructed to display wallet contents...\n");

			OTString strStat;
			g_OT_API.GetWallet()->DisplayStatistics(strStat);
			OTLog::vOutput(0, "%s\n", strStat.Get());

			continue;
		}

		else if (strLine.compare(0,4,"help") == 0)
		{
			OTLog::Output(0, "User has instructed to display the help file...\n");

			system("more ../docs/CLIENT-COMMANDS.txt");

			continue;
		}

		else if (strLine.compare(0,4,"quit") == 0)
		{
			OTLog::Output(0, "User has instructed to exit the wallet...\n");

			break;
		}

		// 1.6 Connect to the first server in the wallet. (assuming it loaded a server contract.)
		else if (strLine.compare(0,7,"connect") == 0)
		{
			OTLog::Output(0, "User has instructed to connect to the first server available in the wallet.\n");

			if (NULL == g_pTemporaryNym)
			{
				OTLog::Output(0, "No Nym yet available to connect with. Try 'load'.\n");
				continue;
			}

			// Wallet, after loading, should contain a list of server
			// contracts. Let's pull the hostname and port out of
			// the first contract, and connect to that server.
			bool bConnected = g_OT_API.GetClient()->ConnectToTheFirstServerOnList(*g_pTemporaryNym, strCAFile, strKeyFile, strSSLPassword); 

			if (bConnected)
				OTLog::Output(0, "Success. (Connected to the first notary server on your wallet's list.)\n");
			else {
				OTLog::Output(0, "Either the wallet is not loaded, or there was an error connecting to server.\n");
			}

			continue;
		}

		if (!g_OT_API.GetClient()->IsConnected())
		{
			OTLog::Output(0, "(You are not connected to a notary server--you cannot send commands.)\n");
			continue;
		}

		// 2) Process it out as an OTMessage to the server. It goes down the pipe.
		g_OT_API.GetClient()->ProcessMessageOut(buf, &nExpectResponse);
		
		// 3) Sleep for 1 second.
#ifdef _WIN32
		OT_Sleep(1000);
#else
		sleep (1);
#endif

		bool bFoundMessage = false;

		// 4) While there are messages to be read in response from the server,
		//	  then process and handle them all.
		do 
		{
			OTMessage * pMsg = new OTMessage;

			OT_ASSERT(NULL != pMsg);

			// If this returns true, that means a Message was
			// received and processed into an OTMessage object (theMsg)
			bFoundMessage = g_OT_API.GetClient()->ProcessInBuffer(*pMsg);

			if (true == bFoundMessage)
			{
//				OTString strReply;
//				theMsg.SaveContract(strReply);
//				OTLog::vOutput(0, "\n\n**********************************************\n"
//						"Successfully in-processed server response.\n\n%s\n", strReply.Get());
				g_OT_API.GetClient()->ProcessServerReply(*pMsg); // the Client takes ownership and will handle cleanup.
			}
			else 
			{
				delete pMsg;
				pMsg = NULL;
			}


		} while (true == bFoundMessage);
	} // for

	OTLog::Output(0, "Finished running client.\n");

#ifdef _WIN32
	WSACleanup();
#endif

	return retVal;
}
// This version is fully functional, and performs compression in addition to base64-encoding.
//
bool OTASCIIArmor::SetString(const OTString & theData, bool bLineBreaks) //=true
{
	
	return SetAndPackString(theData, bLineBreaks);
	
	
	// ---------------------------------------------------------------
	
//	OTLog::vError("DEBUGGING OTASCIIARMOR::SETSTRING, INPUT:  --------->%s<---------", theData.Get());
	
	Release();
	
	if (theData.GetLength() < 1)
		return true;
	
	char *	pString	= NULL;
	
	// Set up source buffer and destination buffer
	long nDestLen	= DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.)
	const	long lSourcelen	= sizeof(unsigned char)*theData.GetLength()+1;// for null terminator
	
	unsigned char* pSource	= new unsigned char[lSourcelen+10]; // for safety
	unsigned char* pDest	= new unsigned char[nDestLen+10]; // for safety
	
	OT_ASSERT(NULL != pSource);
	OT_ASSERT(NULL != pDest);
	
	memcpy(pSource, (const unsigned char*)theData.Get(), lSourcelen );
	
	// Now we are compressing first before base64-encoding (for strings, anyway)	
	int nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen );
	
	// If the destination buffer wasn't the right size the first time around,
	// then we re-allocate it to the right size (which we now know) and try again...
	if ( nErr == EZ_BUF_ERROR )
	{
		delete [] pDest;
		pDest = new unsigned char [nDestLen]; // enough room now
		
		OT_ASSERT(NULL != pDest);
		
		nErr = ezcompress( pDest, &nDestLen, pSource, lSourcelen );
	}
	
	// Clean this up...
	delete [] pSource;
	pSource = NULL;
	
	// Still errors?
	if ( nErr == EZ_BUF_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_ASSERT_MSG(false, "Error allocating memory in OTASCIIArmor::SetString\n");
		return false; // not really necessary but just making sure.
	}
	else if ( nErr == EZ_STREAM_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_ASSERT_MSG(false, "pDest is NULL in OTASCIIArmor::SetString\n");
		return false; // not really necessary but just making sure.
	}
	else if ( nErr == EZ_DATA_ERROR )
	{
		delete [] pDest;
		pDest = NULL;	
		
		OT_ASSERT_MSG(false, "corrupted pSrc passed to ezuncompress OTASCIIArmor::SetString\n");
		return false; // not really necessary but just making sure.
	}
	else if ( nErr == EZ_MEM_ERROR )
	{
		delete [] pDest;	
		pDest = NULL;
		
		OT_ASSERT_MSG(false, "Out of memory in OTASCIIArmor::SetString\n");
		return false; // not really necessary but just making sure.
	}
	
	
	OT_ASSERT_MSG(pDest != NULL, "pDest NULL in OTASCIIArmor::SetString\n");
	
	// Success
	if (0 < nDestLen)
	{
		// Now let's base-64 encode it...
		pString = OT_base64_encode((const uint8_t*)pDest, nDestLen, (bLineBreaks ? 1 : 0));
		//	pString = OT_base64_encode((const uint8_t*)theData.Get(), theData.GetLength()+1, (bLineBreaks ? 1 : 0)); // this was before we used compression.
		
		delete [] pDest;
		pDest = NULL;
		
		if (pString)
		{
			Set(pString);
			delete [] pString; pString=NULL; 
			return true;
		}
		else 
		{
			OTLog::Error("pString NULL in OTASCIIArmor::SetString\n");
		}
	}
	else 
	{
		OTLog::Error("nDestLen 0 in OTASCIIArmor::SetString\n");
	}
	
	if (pDest)
		delete [] pDest;
	
	pDest = NULL;
	
	return false;
}
Пример #12
0
bool OTEnvelope::Encrypt(const OTString & theInput, OTSymmetricKey & theKey, const OTPassword & thePassword)
{
    OT_ASSERT((thePassword.isPassword() && (thePassword.getPasswordSize() > 0)) || (thePassword.isMemory() && (thePassword.getMemorySize() > 0)));
    OT_ASSERT(theInput.Exists());
    // -----------------------------------------------
    // Generate a random initialization vector.
    //
    OTPayload theIV;

    if (false == theIV.Randomize(OTCryptoConfig::SymmetricIvSize()))
    {
		OTLog::vError("%s: Failed trying to randomly generate IV.\n", __FUNCTION__);
		return false;	
    }
    // -----------------------------------------------
    // If the symmetric key hasn't already been generated, we'll just do that now...
    // (The passphrase is used to derive another key that is used to encrypt the
    // actual symmetric key, and to access it later.)
    //
    if ((false == theKey.IsGenerated()) && (false == theKey.GenerateKey(thePassword)))
    {
		OTLog::vError("%s: Failed trying to generate symmetric key using password.\n", __FUNCTION__);
		return false;	
    }
    // -----------------------------------------------

	if (!theKey.HasHashCheck())
	{
		if(!theKey.GenerateHashCheck(thePassword))
		{
		OTLog::vError("%s: Failed trying to generate hash check using password.\n", __FUNCTION__);
		return false;
		}
	}

	OT_ASSERT(theKey.HasHashCheck());

    OTPassword  theRawSymmetricKey;
    
    if (false == theKey.GetRawKeyFromPassphrase(thePassword, theRawSymmetricKey))
    {
		OTLog::vError("%s: Failed trying to retrieve raw symmetric key using password.\n", __FUNCTION__);
		return false;	
    }
    // -----------------------------------------------
    //
    OTPayload theCipherText;
    
    const bool bEncrypted = OTCrypto::It()->Encrypt(theRawSymmetricKey, // The symmetric key, in clear form.
                                                    // -------------------------------
                                                    theInput.Get(),     // This is the Plaintext.
                                                    theInput.GetLength() + 1, // for null terminator
                                                    // -------------------------------
                                                    theIV,              // Initialization vector.
                                                    // -------------------------------
                                                    theCipherText);     // OUTPUT. (Ciphertext.)
    // -----------------------------------------------
    //
    // Success?
    //
    if (!bEncrypted)
    {
        OTLog::vError("%s: (static) call failed to encrypt. Wrong key? (Returning false.)\n", __FUNCTION__);
		return false;
    }
    // -----------------------------------------------
    //
	// This is where the envelope final contents will be placed,
    // including the envelope type, the size of the IV, the IV
    // itself, and the ciphertext.
    //
	m_dataContents.Release();

    // -----------------------------------------------
    // Write the ENVELOPE TYPE (network order version.)
    //
    // 0 == Error
    // 1 == Asymmetric Key  (other functions -- Seal / Open.)
    // 2 == Symmetric Key   (this function -- Encrypt / Decrypt.)
    // Anything else: error.
    
    uint16_t   env_type_n = static_cast<uint16_t>(htons(static_cast<uint16_t>(2))); // Calculate "network-order" version of envelope type 2.
    
    m_dataContents.Concatenate(reinterpret_cast<void *>(&env_type_n),   
                               // (uint32_t here is the 2nd parameter to Concatenate, and has nothing to do with env_type_n being uint16_t)
                               static_cast<uint32_t>(sizeof(env_type_n)));  
    // ------------------------------------------------------------
    //
    // Write IV size (in network-order)
    //
    uint32_t  ivlen   = OTCryptoConfig::SymmetricIvSize(); // Length of IV for this cipher...
    OT_ASSERT(ivlen >= theIV.GetSize());
    uint32_t  ivlen_n = htonl(theIV.GetSize()); // Calculate "network-order" version of iv length.
    
	m_dataContents.Concatenate(reinterpret_cast<void *>(&ivlen_n),   
                               static_cast<uint32_t>(sizeof(ivlen_n)));
	
    // Write the IV itself.
    //
	m_dataContents.Concatenate(theIV.GetPayloadPointer(), 
                               static_cast<uint32_t>(theIV.GetSize()));
    // ------------------------------------------------------------
    
    // Write the Ciphertext.
    //
    m_dataContents.Concatenate(theCipherText.GetPayloadPointer(), 
                               static_cast<uint32_t>(theCipherText.GetSize()));
    
    // We don't write the size of the ciphertext before the ciphertext itself,
    // since the decryption is able to deduce the size based on the total envelope
    // size minus the other pieces. We might still want to add that size here, however.
    // (for security / safety reasons.)
    
    // -----------------------------------------------
    return true;
}
Пример #13
0
// The LoadSet Functions will update the static values.
const bool OTPaths::LoadSetPrefixFolder	// eg. /usr/local/  
	(	
	OTSettings * pConfig,	//optional
	const OTString & strPrefixFolder				//optional
	//const bool & bIsRelative (cannot be relative);
	)
{
	/*
	The prefix path is special.

	This path is tested if it is different to the
	one that would be automatically selected by this program
	(aka either compiled into, or from the registry, or the default user data directory).

	If the set path is different to what would be supplied and the ‘override path’ value is set.
	Then we will use that path.

	Otherwise, we will update the path in the configuration to link against the updated path.

	Users will need to set the ‘override path’ flag in the configuration,
	if they want to manually set the prefix path.
	*/

	if (NULL == pConfig)  { OT_ASSERT(false); return false; }

	const bool bPreLoaded(pConfig->IsLoaded());

	if (!bPreLoaded)
	{
		pConfig->Reset();
		if(!pConfig->Load()) { OT_ASSERT(false); return false; }
	}

	{
		// get default path
		OTString strDefaultPrefixPath(OT_PREFIX_PATH);
		{
			if (!strDefaultPrefixPath.Exists()) { OTLog::sError("%s: Error: OT_PREFIX_PATH is not set!",__FUNCTION__); OT_ASSERT(false); }

#ifdef _WIN32
			OTString strTemp;
			if (OTPaths::Win_GetInstallFolderFromRegistry(strTemp))
			{
				strDefaultPrefixPath = strTemp;
			}
#endif

			if(!ToReal(strDefaultPrefixPath,strDefaultPrefixPath)) { OT_ASSERT(false); return false; }
			if(!FixPath(strDefaultPrefixPath,strDefaultPrefixPath,true)) { OT_ASSERT(false); return false; }
		}

		OTString strLocalPrefixPath = "";
		bool bPrefixPathOverride = false;

		{
			// now check the configuration to see what values we have:
			OTString strConfigPath = "";

			bool bIsNew = false;
			OTString strPrefixPathOverride("prefix_path_override");

			if(!pConfig->CheckSet_str("paths","prefix_path",strDefaultPrefixPath,strConfigPath,bIsNew)) { return false; }
			if(!pConfig->CheckSet_bool("paths",strPrefixPathOverride,false,bPrefixPathOverride,bIsNew,"; This will force the prefix not to change")) {return false; }

			// if the config dosn't have a prefix path set. Lets set the default.
			// if a prefix path was passed in, we will override with that later.
			if (!strConfigPath.Exists() || (3 > strConfigPath.GetLength())) {
				OTLog::sError("%s: Error: Bad %s in config, will reset!",__FUNCTION__,"prefix_path");

				strConfigPath = strDefaultPrefixPath; // set
				bPrefixPathOverride = false;

				// lets set the default path, and reset override
				bool bNewOrUpdate = false;
				if(!pConfig->Set_str("paths","prefix_path",strDefaultPrefixPath,bNewOrUpdate)) { return false; }
				if(!pConfig->Set_bool("paths",strPrefixPathOverride,false,bNewOrUpdate)) { return false; }
			}

			strLocalPrefixPath = strConfigPath;
		}

		{
			if (!bPrefixPathOverride)
			{
				bool bUpdate = false;

				// default
				if (!strLocalPrefixPath.Compare(strDefaultPrefixPath)) {
					strLocalPrefixPath = strDefaultPrefixPath;
					bUpdate = true;
				}

				// passed in
				if (strPrefixFolder.Exists() && (3 < strPrefixFolder.GetLength())) {
					// a prefix folder was passed in... lets use it, and update the config if the override isn't set
					OTString strTmp = strPrefixFolder;

					if(!ToReal(strTmp,strTmp)) { OT_ASSERT(false); return false; }
					if(!FixPath(strTmp,strTmp,true)) { OT_ASSERT(false); return false; }

					if (!strLocalPrefixPath.Compare(strTmp)) {
						strLocalPrefixPath = strTmp;
						bUpdate = true;
					}
				}

				// we need to update the path in the config
				if (bUpdate) {
					bool bNewOrUpdate = false;
					if(!pConfig->Set_str("paths","prefix_path",strLocalPrefixPath,bNewOrUpdate)) { return false; }
				}
			}
		}

		{
			if (!strLocalPrefixPath.Exists()) { OT_ASSERT(false); }

			if(!ToReal(strLocalPrefixPath,strLocalPrefixPath)) { OT_ASSERT(false); return false; }
			if(!FixPath(strLocalPrefixPath,strLocalPrefixPath,true)) { OT_ASSERT(false); return false; }
			m_strPrefixFolder = strLocalPrefixPath;
		}

	}

	if (!bPreLoaded)
	{
		if(!pConfig->Save()) { OT_ASSERT(false); return false; }
		pConfig->Reset();
	}
	return true;
}
Пример #14
0
//static
std::string OTAssetContract::formatLongAmount(int64_t & lOriginalValue, int32_t nFactor/*=100*/, int32_t nPower/*=2*/, const char * szSymbol/*=""*/,
                                              const char * szSeparator/*=","*/, const char * szDecimalPoint/*="."*/)
{
    std::stringstream sss;
    OTString strRemainder;
    // --------------------------------------------------
    // If the original value is 0, we still want to format the
    // string properly for a 0 value. (And then return.)
    //
    if (0 == lOriginalValue)
    {
        sss << szSymbol << " "; // Currency symbol
        
        if (!(nFactor < 2))
        {
            sss << szDecimalPoint;
            
            strRemainder.Format("%0*ld", nPower, 0);
        }
        else
            strRemainder.Format("%lld", 0);
        
        sss << strRemainder.Get();
        return sss.str();
    }
    // --------------------------------------------------
    int64_t lAbsoluteValue = (lOriginalValue > 0) ? lOriginalValue : (lOriginalValue * (-1));
    // --------------------------------------------------    
    int64_t lValue     = lAbsoluteValue / nFactor; // For example, if 506 is supposed to be $5.06, then dividing 506 by factor of 100 results in 5 dollars.
    int64_t lRemainder = lAbsoluteValue % nFactor; // For example, if 506 is supposed to be $5.06, then 506 mod 100 results in 6 cents.
    
    if (nFactor < 2) // Basically, if nFactor is 1.
        strRemainder.Set("");
    else
        strRemainder.Format("%0*ld", nPower, lRemainder); // If remainder is 6 (cents) and nPower is 2, strRemainder gets set here to 06.    
    // ------------------------------------------------------
    // Here we add the negative sign, if the value itself is negative.
    //
    if (lOriginalValue < 0)
    {
//        const std::moneypunct<char, false> &mp = std::use_facet< std::moneypunct<char, false> >(std::locale ());
//        sss << mp.negative_sign();
     
        // For some reason the above code isn't working, so I've got the negative sign
        // hardcoded here to '-'.
        //
        sss << "-";
    }
    // ------------------------------------------------------    
    // Here we add the currency symbol.
    //
    sss << szSymbol << " "; // Currency symbol
    // ------------------------------------------------------
    OTString strValue;
    strValue.Format("%lld", lValue);
    // ---------------------------------
    char     cTemp = '\0';
    uint32_t uValueStrLength = strValue.GetLength();
    // ---------------------------------
    // Here we add the main body of the amount, including separators (commas.)
    //
    while (uValueStrLength > 0)
    {
        cTemp = strValue.sgetc();
        
        sss << cTemp;
        
        --uValueStrLength;
        
        if ((uValueStrLength > 0) && (0 == (uValueStrLength % 3)))
            sss << szSeparator;
    }
    // ------------------------------------------------------
    // Here we deal with the decimal point, etc.
    //
    if (!(nFactor < 2))
    {
        sss << szDecimalPoint;
        // -----------------------------
        sss << strRemainder.Get();
    }
    // -----------------------------
    return sss.str();
}
Пример #15
0
bool OTEnvelope::Seal(const OTAsymmetricKey & RecipPubKey, const OTString & theContents)
{
	bool retval = false;
    
	EVP_CIPHER_CTX	ctx;
    
	unsigned char	buffer[4096];
    unsigned char	buffer_out[4096 + EVP_MAX_IV_LENGTH];
    unsigned char	iv[EVP_MAX_IV_LENGTH];
    
	size_t			len = 0;
    int				len_out = 0;

    unsigned char *	ek = NULL;
    int				eklen = 0;
    uint32_t		eklen_n = 0;
	
	
	memset(buffer, 0, 4096);
	memset(buffer_out, 0, 4096 + EVP_MAX_IV_LENGTH);
	memset(iv, 0, EVP_MAX_IV_LENGTH);

	
	OTAsymmetricKey &	publicKey	= (OTAsymmetricKey &)RecipPubKey;
	EVP_PKEY *			pkey		= (EVP_PKEY *)publicKey.GetKey();
	
	if (NULL == pkey)
	{
		OTLog::Error("Null public key in OTEnvelope::Seal\n");
		return false;
	}
	
	// This is where the envelope final contents will be placed.
	m_dataContents.Release();
	
	
	EVP_CIPHER_CTX_init(&ctx);
    ek = (unsigned char*)malloc(EVP_PKEY_size(pkey));
	
	OT_ASSERT(NULL != ek);
	
	memset(ek, 0, EVP_PKEY_size(pkey));
	
    if (!EVP_SealInit(&ctx, EVP_aes_128_cbc(), &ek, &eklen, iv, &pkey, 1))
    {
        OTLog::Error("EVP_SealInit: failed.\n");
		free(ek); ek = NULL;
		return false;
    }
	
    // First we write out the encrypted key length, then the encrypted key,
	// then the iv (the IV length is fixed by the cipher we have chosen).
	
    eklen_n = htonl(eklen);
	
	OTData dataEKSize(&eklen_n, sizeof(eklen_n)); // Encrypted Key size. (EK). Bytes are in network order.
	OTData dataEK(ek, eklen); // Encrypted Key
	OTData dataIV(iv, EVP_CIPHER_iv_length(EVP_aes_128_cbc())); // Initialization Vector
	
	// Concatenate (to the envelope result buffer) the three pieces of final data we have so far.
	m_dataContents += dataEKSize;
	m_dataContents += dataEK;
	m_dataContents += dataIV;
	
	// Next we put the plaintext into a data object so we can process it.
	OTData plaintext((const void*)theContents.Get(), theContents.GetLength()+1); // +1 for null terminator
	
    // Now we process the input and write the encrypted data to the
	// output.
	
    while (0 < (len = plaintext.OTfread((char*)buffer, sizeof(buffer))))
    {
        if (!EVP_SealUpdate(&ctx, buffer_out, &len_out, buffer, len))
        {
            OTLog::Error("EVP_SealUpdate: failed.\n");
			free(ek); ek = NULL;
			return false;
        }
		
		OTData dataSealUpdate(buffer_out, len_out);
		m_dataContents += dataSealUpdate;
	}
	
    if (!EVP_SealFinal(&ctx, buffer_out, &len_out))
    {
        OTLog::Error("EVP_SealFinal: failed.\n");
		free(ek); ek = NULL;
		return false;
    }
	
	OTData dataSealFinal(buffer_out, len_out);
	m_dataContents += dataSealFinal;
	
	retval = true;
	
    free(ek); ek = NULL;
	
    return retval;
}
Пример #16
0
bool OTPayment::SetPayment(const OTString & strPayment)
{
    if (!strPayment.Exists())
		return false;
    // --------------------------------------------------------------------
	//
    // To support legacy data, we check here to see if it's armored or not.
    // If it's not, we support it. But if it IS, we ALSO support it (we de-armor it here.)
    //
    bool bArmoredAndALSOescaped = false;    // "- -----BEGIN OT ARMORED"
    bool bArmoredButNOTescaped  = false;    // "-----BEGIN OT ARMORED"
    
    if (strPayment.Contains(OT_BEGIN_ARMORED_escaped)) // check this one first...
    {
        bArmoredAndALSOescaped = true;
        
        OTLog::Error("OTPayment::SetPayment: Armored and escaped value passed in, but escaped are forbidden here. (Returning false.)\n");
		return false;
    }
    else if (strPayment.Contains(OT_BEGIN_ARMORED))
    {
        bArmoredButNOTescaped = true;
    }
    // ----------------------------------------
    const bool bArmored = (bArmoredAndALSOescaped || bArmoredButNOTescaped);
    // ----------------------------------------
    
    // Whether the string is armored or not, (-----BEGIN OT ARMORED)
    // either way, we'll end up with the decoded version in this variable:
    //
    std::string str_Trim;
    
    // ------------------------------------------------
    if (bArmored) // it's armored, we have to decode it first.
    {
        OTASCIIArmor ascTemp;
        OTString strPaymentTemp(strPayment);
        
        if (false == (ascTemp.LoadFromString(strPaymentTemp, 
                                             bArmoredAndALSOescaped, // if it IS escaped or not, this variable will be true or false to show it.
                                             // The below szOverride sub-string determines where the content starts, when loading.
                                             OT_BEGIN_ARMORED)))     // Default is:       "-----BEGIN" 
                                                                     // We're doing this: "-----BEGIN OT ARMORED" (Should worked for escaped as well, here.)
        {
            OTLog::vError("OTPayment::SetPayment: Error loading string contents from ascii-armored encoding. Contents: \n%s\n", 
                          strPayment.Get());
            return false;
        }
        else // success loading the actual contents out of the ascii-armored version.
        {
            OTString strTemp(ascTemp); // <=== ascii-decoded here.
            
            std::string str_temp(strTemp.Get(), strTemp.GetLength());
            
            str_Trim = OTString::trim(str_temp); // This is the std::string for the trim process.
        } 
    }
    else
    {
        std::string str_temp(strPayment.Get(), strPayment.GetLength());
        str_Trim = OTString::trim(str_temp); // This is the std::string for the trim process. (Wasn't armored, so here we use it as passed in.)
    }
    // ------------------------------------------------
    
    // At this point, str_Trim contains the actual contents, whether they
    // were originally ascii-armored OR NOT. (And they are also now trimmed, either way.)
    // ------------------------------------------
    
    OTString strContract(str_Trim.c_str());
    
    m_strPayment.Release();
    // ----------------------
    // todo: should be "starts with" and perhaps with a trim first
    //
    if (strContract.Contains("-----BEGIN SIGNED CHEQUE-----"))
        m_Type  = OTPayment::CHEQUE;
    else if (strContract.Contains("-----BEGIN SIGNED VOUCHER-----"))
        m_Type  = OTPayment::VOUCHER;
    else if (strContract.Contains("-----BEGIN SIGNED INVOICE-----"))
        m_Type  = OTPayment::INVOICE;
    // -------------------
    else if (strContract.Contains("-----BEGIN SIGNED PAYMENT PLAN-----"))
        m_Type  = OTPayment::PAYMENT_PLAN;
    else if (strContract.Contains("-----BEGIN SIGNED SMART CONTRACT-----"))
        m_Type  = OTPayment::SMART_CONTRACT;
    // -------------------
    else if (strContract.Contains("-----BEGIN SIGNED PURSE-----"))
        m_Type  = OTPayment::PURSE;
    else
        m_Type  = OTPayment::ERROR_STATE;
    // ----------------------
    if (OTPayment::ERROR_STATE == m_Type)
        return false;

    // *********************************
    
    m_strPayment.Set(strContract);
    
    // *********************************
    
    return true;
}
Пример #17
0
/// This function first Packs the incoming string, using whatever is the default packer. (MsgPack or Protobuf).
/// Then it Compresses the packed binary data using zlib. (ezcompress.)
/// Then it Base64-Encodes the compressed binary and sets it as a string on THIS OBJECT.
/// 
/// I added these pieces 1-by-1 over time. At first the messages were too int64_t, so I started compressing them.
/// Then they were not binary compatible across various platforms, so I added the packing.
//
bool OTASCIIArmor::SetAndPackString(const OTString & strData, bool bLineBreaks) //=true
{	
	Release();
	
	if (strData.GetLength() < 1)
		return true;
	// --------------------------------------------------------
	OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either.
	
	// Here I use the default storage context to create the object (the blob.)
	// I also originally created OTASCIIArmor::GetPacker() using OTDB_DEFAULT_PACKER,
	// so I know everything is compatible.
	//
	OTDB::OTDBString * pOTDBString = dynamic_cast<OTDB::OTDBString *>(OTDB::CreateObject(OTDB::STORED_OBJ_STRING));
	
	OT_ASSERT(NULL != pOTDBString); // Beyond this point, responsible to delete pString.
	OTCleanup<OTDB::OTDBString> theStringAngel(*pOTDBString); // make sure memory is cleaned up.
	// -----------------------------
	const uint32_t	theStringSize32	= strData.GetLength();
	const size_t	theStringSize	= theStringSize32; // might need a cast here. // todo make sure this will handle sizes as big as I need.
	
	pOTDBString->m_string.assign(strData.Get(), // const char * 
								 theStringSize);
	
	OTDB::PackedBuffer * pBuffer = pPacker->Pack(*pOTDBString); // Now we PACK our string before compressing/encoding it.
	
	if (NULL == pBuffer)
	{
		OTLog::Error("Failed packing string in OTASCIIArmor::SetAndPackString. \n");
		return false;
	}
	
	OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // make sure memory is cleaned up.
	// --------------------------------------------------------
    std::string str_packed(reinterpret_cast<const char *>(pBuffer->GetData()), pBuffer->GetSize());
    
    std::string str_compressed = compress_string( str_packed );
    
	// Success
    if (str_compressed.size())
	{
		// Now let's base-64 encode it...
        // TODO: remove static cast, add check for longer than 'int32_t' length? (da2ce7)
        char * pString = OTCrypto::It()->Base64Encode((const uint8_t*)(str_compressed.data()), static_cast<int32_t>(str_compressed.size()), bLineBreaks);
		
		if (pString)
		{
			Set(pString);
			delete [] pString; pString=NULL; 
			return true;
		}
		else 
		{
			OTLog::vError("OTASCIIArmor::%s: pString NULL.\n", __FUNCTION__);
		}
	}
	else 
	{
		OTLog::vError("OTASCIIArmor::%s: nDestLen 0.\n", __FUNCTION__);
	}
		
	return false;	
}
Пример #18
0
const bool OTPaths::LoadSetScriptsFolder  // ie. PrefixFolder() + lib/opentxs/
	(
	OTSettings * pConfig, //optional
	const OTString & strScriptsFolder,	//optional
	const bool & bIsRelative			//optional
	)
{
	if (NULL == pConfig)  { OT_ASSERT(false); return false; }

	const bool bPreLoaded(pConfig->IsLoaded());

	if (!bPreLoaded)
	{
		pConfig->Reset();
		if(!pConfig->Load()) { OT_ASSERT(false); return false; }
	}

	OTString strRelativeKey = "";
	strRelativeKey.Format("%s%s","scripts",OT_CONFIG_ISRELATIVE);


	// local vairables.
	bool bConfigIsRelative = false;
	OTString strConfigFolder = "";


	// lets first check what we have in the configuration:
	{
	bool bKeyIsNew = false;

	if (!pConfig->CheckSet_bool("paths",strRelativeKey,true,bConfigIsRelative,bKeyIsNew)) { return false; }
	if (!pConfig->CheckSet_str("paths","scripts",OT_SCRIPTS_DIR,strConfigFolder,bKeyIsNew)) { return false; }
	}

	// lets first test if there was a folder passed in

	if ((strScriptsFolder.Exists()) && (3 < strScriptsFolder.GetLength())) {

		// we have a folder passed in, lets now check if we need to update anything:

		if (bConfigIsRelative != bIsRelative) {

			bConfigIsRelative = bIsRelative;
			bool bNewOrUpdated = false;

			if (!pConfig->Set_bool("paths", strRelativeKey, bConfigIsRelative, bNewOrUpdated)) { return false; }

		}

		if (!strConfigFolder.Compare(strScriptsFolder)) {

			strConfigFolder = strScriptsFolder; // update folder
			bool bNewOrUpdated = false;

			if (!pConfig->Set_str( "paths", "scripts", strConfigFolder, bNewOrUpdated)) { return false; }
		}
	}


	if(bConfigIsRelative)
	{
		if(!FixPath(strConfigFolder,strConfigFolder,true)) { OT_ASSERT(false); return false; }

		OTString strScriptPath = "";
		if(!AppendFolder(strScriptPath, PrefixFolder(), strConfigFolder)) { OT_ASSERT(false); return false; }

		m_strScriptsFolder = strScriptPath; // set
	}
	else
	{
		if(!ToReal(strConfigFolder, strConfigFolder)) { OT_ASSERT(false); return false; }
		if(!FixPath(strConfigFolder, strConfigFolder, true)) { OT_ASSERT(false); return false; }
		m_strScriptsFolder = strConfigFolder; // set
	}
		
	if (!bPreLoaded)
	{
		if(!pConfig->Save()) { OT_ASSERT(false); return false; }
		pConfig->Reset();
	}
	return true;  // success
}