Example #1
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();
}
Example #2
0
void OTLog::Error(OTString & strError)
{
	if (strError.Exists())
		OTLog::Error(strError.Get());
}
// A certain number of bytes are expected in the payload, according to the header.
// This function tries to read that many bytes, and inserts them into an OTPayload object.
// From there, a simple method call extracts the message, we return true, and the message
// gets added to our internal list for processing.
bool OTClientConnection::ProcessType1Cmd(u_header & theCMD, OTMessage & theMessage)
{
	// At this point, the checksum has already validated. 
	// Might as well get the PAYLOAD next.
//	int  err;
	uint32_t nread, lSize = theCMD.fields.size;
	
	// Make sure our byte-order is correct here.
//	theCMD.fields.size = ntohl(theCMD.fields.size); // I was doing this twice!! This is already done when the header is first read.

	// setup the buffer we are reading into
	OTPayload thePayload;
	nread = thePayload.ReadBytesFrom(m_Buffer, lSize);
	
	/*
	// actually read the payload from the socket into the buffer.
	for (nread = 0;  nread < theCMD.fields.size;  nread += err)
	{
		err = SFSocketRead(m_pSocket, 
						   (unsigned char *)thePayload.GetPayloadPointer() + nread,
						   theCMD.fields.size - nread);
		
		// if we don't read anything more, stop reading and move on
		if (err <= 0)
			break;
	}
	*/
	// TODO fix the buffering so that if a complete command has not yet been received, it saves the other
	// bytes instead of discarding them.  For now I'll just sleep for a second to make sure the entire command
	// was received.
//	sleep(1);
	
	// ------------------------------------------------------------
	
	// Try to interpret the command number.
	// Right now we support signed messages and encrypted envelopes containing
	// signed messages.
	switch (theCMD.fields.command_id) {
		case TYPE_1_CMD_1:
			OTLog::Output(2, "Received Type 1 CMD 1:\nThere is a signed OTMessage in the payload.\n");
			break;
		case TYPE_1_CMD_2:
			OTLog::Output(2, "Received Type 1 CMD 2:\n"
					"There is an encrypted OTEnvelope (containing signed OTMessage) in the payload.\n");
			break;
		default:
			OTLog::vError("Received unexpected command number %d in OTClientConnection::ProcessType1Cmd\n", 
					theCMD.fields.command_id);
			break;
	}
	
	// ------------------------------------------------------------
	// Hm, that's weird. It was a 0 size payload message. DoS?
	if (theCMD.fields.size == 0)
	{
		OTLog::Output(2, "(The payload was a 0 size.)\n");
		return true;
	}
	// Uh-oh, somehow the number of bytes read was less than what we expected...
	else if (nread < theCMD.fields.size)
	{
		// TODO: Verify that the amount read matched the amount expected
		// if not, we have a problem that needs to be handled.
		
		// Long term solution is to buffer the data as a comes in and just
		// add it to the buffer.
		
		// Then if we don't have the complete message yet, we just come around next
		// time some data is read, and we add that to the buffer, THEN we check to see
		// if there are enough bytes yet read to match the amount expected according to
		// the header.
		//
		// Until I can do that, I'm not yet TRULY asynchronous. TODO: lookup a good buffer class.

		OTLog::Error("Number of bytes read did NOT match size in header.\n");
		return false;
	}
	else
		OTLog::vOutput(2, "Loaded a payload, size: %d\n", theCMD.fields.size);
	
	// ------------------------------------------------------------
	
	// Okay so now we've received the expected size from the socket. Let's transfer it
	// into an object type that we can manipulate here in code. (Message or Envelope.)
	
	// a signed OTMessage
	if (TYPE_1_CMD_1 == theCMD.fields.command_id) 
	{
#ifdef _WIN32
		if (OTPAYLOAD_GetMessage(thePayload, theMessage))
#else
		if (thePayload.GetMessage(theMessage))
#endif
		{
			OTLog::Output(2, "Successfully retrieved payload message...\n");
			
			if (theMessage.ParseRawFile())
			{
				OTLog::Output(2, "Successfully parsed payload message.\n");
				
				return true;
			}
			else {
				OTLog::Error("Error parsing message.\n");
				return false;
			}
			
		}
		else {
			OTLog::Error("Error retrieving message from payload.\n");
			return false;
		}
		
	}
	
	// A base64-encoded envelope, encrypted, and containing a signed message.
	else if (TYPE_1_CMD_2 == theCMD.fields.command_id) 
	{
		OTEnvelope theEnvelope;
		if (thePayload.GetEnvelope(theEnvelope))
		{
			OTLog::Output(2, "Successfully retrieved envelope from payload...\n");
			
			OTString strEnvelopeContents;
			
			// Decrypt the Envelope.    
			if (m_pServer && theEnvelope.Open(m_pServer->GetServerNym(), strEnvelopeContents))
			{
				// All decrypted, now let's load the results into an OTMessage.
				// No need to call theMessage.ParseRawFile() after, since
				// LoadContractFromString handles it.
				//
				if (strEnvelopeContents.Exists() && theMessage.LoadContractFromString(strEnvelopeContents))
				{
					OTLog::Output(2, "Success loading message out of the envelope contents and parsing it.\n");
					return true;
				}
				else 
				{
					OTLog::Error("Error loading message from envelope contents.\n");
					return false;		
				}
			}
			else 
			{
				OTLog::Error("Unable to open envelope.\n");
				return false;
			}			
		}
		else 
		{
			OTLog::Error("Error retrieving message from payload.\n");
			return false;
		}
	}
	
	return true;
}
Example #4
0
const bool OTPaths::ToReal(const OTString & strExactPath, OTString & out_strCanonicalPath)
{
	if (!strExactPath.Exists())		{ OTLog::sError("%s: Null: %s passed in!\n", __FUNCTION__, "strExactPath"); OT_ASSERT(false); }

#ifdef _WIN32
#ifdef _UNICODE	

	const char * szPath = strExactPath.Get();
	size_t newsize = strlen(szPath) + 1;
	wchar_t * wzPath = new wchar_t[newsize];

	size_t convertedChars = 0;
	mbstowcs_s(&convertedChars, wzPath, newsize, szPath,4096);

	wchar_t szBuf[4096]= L"";

	if(GetFullPathName(wzPath,4096,szBuf,NULL))
	{
		out_strCanonicalPath.Set(utf8util::UTF8FromUTF16(szBuf));
		return true;
	}
	else 
	{
		out_strCanonicalPath.Set("");
		return false;
	}

#else
	char_t szBuf[4096]="";
	char_t const * szPath = strRealPath.Get();

	if(GetFullPathName(szPath,4096,szBuf,NULL))
	{
		out_strCanonicalPath.Set(szBuf);
		return true;
	}
	else
	{
		out_strCanonicalPath.Set("");
		return false;
	}

#endif
#else

	long path_max=0;
#ifdef PATH_MAX
	path_max = PATH_MAX;
#else
	path_max = pathconf("/", _PC_PATH_MAX);
	if (path_max <= 0)  path_max = 4096;
#endif

	char actualpath [path_max+1];
    actualpath[0] = '\0';
	char *ptr=NULL;

	if (NULL ==  realpath(strExactPath.Get(), actualpath)) {

		if (errno == ENOTDIR) {
			OTLog::vOutput(1,"Input value to RealPath is not a directory: (Realpath: skipping)\n");
			out_strCanonicalPath.Set(strExactPath);
			return true;
		}

		if (errno == ENOENT) {
			OTLog::vOutput(1,"File doesn't exist: (Realpath: skipping)\n");
			out_strCanonicalPath.Set(strExactPath);
			return true;
		}

		OT_ASSERT_MSG((errno != EACCES),"Error (Realpath: EACCES): Unable to build RealPath: access denied");
		OT_ASSERT_MSG((errno != EINVAL),"Error (RealPath: EINVAL): Input value into RealPath was NULL");
		OT_ASSERT_MSG((errno != ELOOP),"Error (RealPath: ELOOP): Resloving links resulted in a loop.");
		OT_ASSERT_MSG((errno != ENAMETOOLONG),"Error (RealPath: ENAMETOOLONG): Name too long.");
		OT_ASSERT_MSG((errno != ERANGE),"Error (RealPath: ERANGE): Resulting path is too long for the buffer");
		OT_ASSERT_MSG((errno != EIO),"Error (RealPath: EIO): Unable to access path.");

		OT_ASSERT_MSG((false),"Error (RealPath: OTHER): Something bad Happend with 'realpath'.");
	}
	out_strCanonicalPath.Set(actualpath);
	return true;
#endif
}
Example #5
0
// return -1 if error, 0 if nothing, and 1 if the node was processed.
int OTOffer::ProcessXMLNode(irr::io::IrrXMLReader*& xml)
{
	int nReturnVal = 0;
	
	// Here we call the parent class first.
	// If the node is found there, or there is some error,
	// then we just return either way.  But if it comes back
	// as '0', then nothing happened, and we'll continue executing.
	//
	// -- Note you can choose not to call the parent if
	// you don't want to use any of those xml tags.
	// As I do below, in the case of OTAccount.
	//if (nReturnVal = OTContract::ProcessXMLNode(xml))
	//	return nReturnVal;
	
	if (!strcmp("marketOffer", xml->getNodeName())) 
	{		
		m_strVersion		= xml->getAttributeValue("version");					

		OTString strIsSelling;
		strIsSelling		= xml->getAttributeValue("isSelling");
		if (strIsSelling.Compare("true"))
			m_bSelling = true;
		else
			m_bSelling = false;
				
		m_strContractType.Set((m_bSelling ? "ASK" : "BID"));

		const OTString	strServerID(xml->getAttributeValue("serverID")),
						strAssetTypeID(xml->getAttributeValue("assetTypeID")),
						strCurrencyTypeID(xml->getAttributeValue("currencyTypeID"));
		
		const OTIdentifier	SERVER_ID(strServerID),	ASSET_ID(strAssetTypeID),		
							CURRENCY_TYPE_ID(strCurrencyTypeID);
		
		SetServerID(SERVER_ID);
		SetAssetID(ASSET_ID);
		SetCurrencyID(CURRENCY_TYPE_ID);
		// ------------------------------------
		const OTString strScale	= xml->getAttributeValue("marketScale");
		const long lScale		= strScale.Exists() ? atol(strScale.Get()) : 0; // if it doesn't exist, the 0 here causes the below error to fire.
				
		if (false == isPowerOfTen( lScale ))
		{
			OTLog::vOutput(0, "OTOffer::ProcessXMLNode: Failure: marketScale *must* be 1, or a power of 10. Instead I got: %ld.\n",
						   lScale);
			return (-1);
		}
		else
			SetScale(lScale);
		// ------------------------------------
		const OTString strPriceLimit	= xml->getAttributeValue("priceLimit");
		const long lPriceLimit			= strPriceLimit.Exists() ? atol(strPriceLimit.Get()) : 0; // if it doesn't exist, the 0 here causes the below error to fire.
		if (lPriceLimit < 1)
		{
			OTLog::vOutput(0, "OTOffer::ProcessXMLNode: Failure: priceLimit *must* be larger than 0. Instead I got: %ld.\n",
						   lPriceLimit);
			return (-1);
		}
		else
			SetPriceLimit(lPriceLimit);
		// ------------------------------------
		const OTString strTotal	= xml->getAttributeValue("totalAssetsOnOffer");
		const long lTotal		= strTotal.Exists() ? atol(strTotal.Get()) : 0; // if it doesn't exist, the 0 here causes the below error to fire.
		if (lTotal < 1)
		{
			OTLog::vOutput(0, "OTOffer::ProcessXMLNode: Failure: totalAssetsOnOffer *must* be larger than 0. Instead I got: %ld.\n",
						   lTotal);
			return (-1);
		}
		else
			SetTotalAssetsOnOffer(lTotal);
		// ------------------------------------
		const OTString strFinished	= xml->getAttributeValue("finishedSoFar");
		const long lFinished		= strFinished.Exists() ? atol(strFinished.Get()) : 0; // if it doesn't exist, the 0 here causes the below error to fire.
		if (lFinished < 0)
		{
			OTLog::vOutput(0, "OTOffer::ProcessXMLNode: Failure: finishedSoFar *must* be 0 or larger. Instead I got: %ld.\n",
						   lFinished);
			return (-1);
		}
		else
			SetFinishedSoFar(lFinished);
		// ------------------------------------
		const OTString	strMinInc	= xml->getAttributeValue("minimumIncrement");
		const long		lMinInc		= strMinInc.Exists() ? atol(strMinInc.Get()) : 0; // if it doesn't exist, the 0 here causes the below error to fire.
		if ((lMinInc < 1) || (lMinInc > lTotal)) // Minimum increment cannot logically be higher than the total assets on offer...
		{
			OTLog::vOutput(0, "OTOffer::ProcessXMLNode: Failure: minimumIncrement *must* be 1 or larger, \n"
						   "and must also be less than the total assets on offer. Instead I got: %ld.\n",
						   lMinInc);
			return (-1);
		}
		else
			SetMinimumIncrement(lMinInc);
		// -----------------------------------
		const OTString strTransNum = xml->getAttributeValue("transactionNum");
		const long lTransNum = strTransNum.Exists() ? atol(strTransNum.Get()) : 0;
		
		SetTransactionNum(lTransNum);
		// ----------------------------------------------------------------
		const OTString strValidFrom	= xml->getAttributeValue("validFrom");
		const OTString strValidTo	= xml->getAttributeValue("validTo");
		
		time_t tValidFrom	=	strValidFrom.Exists() ? atoi(strValidFrom.Get()) : 0;
		time_t tValidTo		=	strValidTo.Exists() ? atoi(strValidTo.Get()) : 0;

		if ((tValidTo < tValidFrom) && (tValidTo != 0))
		{
			long nFrom= static_cast<long> (tValidFrom), nTo= static_cast<long> (tValidTo);
			OTLog::vOutput(0, "OTOffer::ProcessXMLNode: Failure: validTo date (%ld) cannot be earlier than validFrom date (%ld).\n",
						   nFrom, nTo);
			return (-1);
		}
		
		SetValidFrom(tValidFrom);
		SetValidTo(tValidTo);
		
		// ---------------------
		
		OTLog::vOutput(4,
					   "\n\nOffer. Transaction Number: %ld\n Valid From: %d\n Valid To: %d\n"
					   " AssetTypeID: %s\n  CurrencyTypeID: %s\n ServerID: %s\n"
					   " Price Limit: %ld,  Total Assets on Offer: %ld,  %s so far: %ld\n "
					   " Scale: %ld.   Minimum Increment: %ld.  This offer is a%s.\n", 
					   m_lTransactionNum, m_VALID_FROM, m_VALID_TO,
					   strAssetTypeID.Get(), strCurrencyTypeID.Get(), strServerID.Get(),
					   GetPriceLimit(), GetTotalAssetsOnOffer(),  (m_bSelling ? "sold" : "bought"), 
					   GetFinishedSoFar(), GetScale(), GetMinimumIncrement(), 
					   (m_bSelling ? "n ASK" : " BID"));
		
		nReturnVal = 1;
	}
		
	return nReturnVal;	
}
Example #6
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;
}
Example #7
0
const bool OTPaths::Get(
	OTSettings * pConfig,
	const				  OTString	  & strSection,
	const				  OTString	  & strKey,
	OTString	  & out_strVar,
	bool		  & out_bIsRelative,
	bool		  & out_bKeyExist
	)
{
	if (!strSection.Exists())		{ OTLog::sError("%s: Null: %s passed in!\n", __FUNCTION__, "strSection"	); OT_ASSERT(false); }
	if (!strKey.Exists())			{ OTLog::sError("%s: Null: %s passed in!\n", __FUNCTION__, "strKey"		); OT_ASSERT(false); }

	out_strVar = "";
	out_bIsRelative = false;
	out_bKeyExist = false;

	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; }
	}

	bool bBoolExists(false), bStringExists(false), bIsRelative(false);
	OTString  strRelativeKey(""), strOutFolder("");

	strRelativeKey.Format("%s%s",strKey.Get(),OT_CONFIG_ISRELATIVE);

	if(pConfig->Check_bool(strSection,strRelativeKey,bIsRelative,bBoolExists))
	{
		if(pConfig->Check_str(strSection,strKey,strOutFolder,bStringExists))
		{
			if (bBoolExists && bStringExists)
			{
				if (!bIsRelative) // lets fix the path, so it dosn't matter how people write it in the config.
				{
					if(!ToReal(strOutFolder,strOutFolder)) { OT_ASSERT(false); return false; }
					if(!FixPath(strOutFolder,strOutFolder,true)) { OT_ASSERT(false); return false; }
				}

				out_strVar = strOutFolder;
				out_bIsRelative = bIsRelative;
				out_bKeyExist = true;
			}
			else
			{
				out_strVar = "";
				out_bIsRelative = false;
				out_bKeyExist = false;
			}

			if (!bPreLoaded)
			{
				pConfig->Reset();
			}

			return true;
		}
	}
	// if we get here, there has been a error!
	OT_ASSERT(false);
	pConfig->Reset();
	return false;
}
_SharedPtr<OTAccount> OTAcctList::GetOrCreateAccount(OTPseudonym			& theServerNym,
        const OTIdentifier	& ACCOUNT_OWNER_ID,
        const OTIdentifier	& ASSET_TYPE_ID,
        const OTIdentifier	& SERVER_ID,
        bool					& bWasAcctCreated, // this will be set to true if the acct is created here. Otherwise set to false;
        const int64_t             lStashTransNum/*=0*/)
{
    _SharedPtr<OTAccount> pRetVal;
    bWasAcctCreated = false;
    // ------------------------------------------------
    if (OTAccount::stash == m_AcctType)
    {
        if (lStashTransNum <= 0)
        {
            OTLog::Error("OTAcctList::GetOrCreateAccount: Failed attempt to create stash account without cron item #.\n");
            return pRetVal;
        }
    }

    // ------------------------------------------------
    // First, we'll see if there's already an account ID available for the requested asset type ID.
    //
    const OTString strAssetTypeID(ASSET_TYPE_ID);
    const std::string str_asset_type_id = strAssetTypeID.Get();

    // ------------------------------------
    OTString strAcctType;
    TranslateAccountTypeToString(m_AcctType, strAcctType);
    // ----------------------------------------------------------------

    mapOfStrings::iterator it_acct_ids = m_mapAcctIDs.find(str_asset_type_id);
    if (m_mapAcctIDs.end() != it_acct_ids) // Account ID *IS* already there for this asset type...
    {
        const std::string			str_account_id	= (*it_acct_ids).second; // grab account ID
        mapOfWeakAccounts::iterator	it_weak			= m_mapWeakAccts.find(str_account_id); // Try to find account pointer...

        if (m_mapWeakAccts.end() != it_weak)  // FOUND the weak ptr to the account! Maybe it's already loaded
        {
//			bool bSuccess = true;

            _WeakPtr<OTAccount>	pWeak	= (*it_weak).second; // first is acct ID, second is weak_ptr to account.

            try
            {
                _SharedPtr<OTAccount>	pShared(pWeak);

                // If success, then we have a shared pointer. But it's worrying (TODO) because this should have
                // gone out of scope and been destroyed by whoever ELSE was using it. The fact that it's still here...
                // well I'm glad not to double-load it, but I wonder why it's still here? And we aren't walking on anyone's
                // toes, right? If this were multi-threaded, then I'd explicitly lock a mutex here, honestly. But since things
                // happen one at a time on OT, I'll settle for a warning for now. I'm assuming that if the account's loaded
                // already somewhere, it's just a pointer sitting there, and we're not walking on each other's toes.
                //
                if (pShared)
                {
                    OTLog::vOutput(0, "OTAcctList::GetOrCreateAccount: Warning: account (%s) was already in memory so I gave you a "
                                   "pointer to the existing one. (But who else has a copy of it?) \n", str_account_id.c_str());
                    return pShared;
                }

            }
            catch (...)
            {

            }


            // Though the weak pointer was there, the resource must have since been destroyed,
            // because I cannot lock a new shared ptr onto it.   :-(
            //
            // Therefore remove it from the map, and RE-LOAD IT.
            //
            m_mapWeakAccts.erase(it_weak);
        }

        // DIDN'T find the acct pointer, even though we had the ID.
        // (Or it was there, but we couldn't lock a shared_ptr onto it, so we erased it...)
        //
        // So let's load it now. After all, the Account ID *does* exist...
        //
        const OTString strAcctID(str_account_id.c_str());
        const OTIdentifier theAccountID(strAcctID);

        // The Account ID exists, but we don't have the pointer to a loaded account for it.
        // Soo.... let's load it.
        //
        OTAccount * pAccount = OTAccount::LoadExistingAccount(theAccountID, SERVER_ID);

        if (NULL == pAccount)
            OTLog::vError("OTAcctList::GetOrCreateAccount: Failed trying to load %s account with account ID: %s\n",
                          strAcctType.Get(),strAcctID.Get());
        else if (!pAccount->VerifySignature(theServerNym))
            OTLog::vError("OTAcctList::GetOrCreateAccount: Failed verifying server's signature on %s account with account ID: %s\n",
                          strAcctType.Get(),strAcctID.Get());
        else if (!pAccount->VerifyOwnerByID(ACCOUNT_OWNER_ID))
        {
            const OTString strOwnerID(ACCOUNT_OWNER_ID);
            OTLog::vError("OTAcctList::GetOrCreateAccount: Failed verifying owner ID (%s) on %s account ID: %s\n",
                          strOwnerID.Get(), strAcctType.Get(),strAcctID.Get());
        }
        else // SUCCESS loading the account...
        {
            OTLog::vOutput(3, "Successfully loaded %s account ID: %s Asset Type ID: %s\n",
                           strAcctType.Get(), strAcctID.Get(), str_asset_type_id.c_str());

            pRetVal								= _SharedPtr<OTAccount>(pAccount); // Create a shared pointer to the account, so it will be cleaned up automatically.
            m_mapWeakAccts [strAcctID.Get()]	= _WeakPtr<OTAccount>(pRetVal); // save a weak pointer to the acct, so we'll never load it twice, but we'll also know if it's been deleted.
        }
        return pRetVal;
        //
    } // (Asset Type ID was found on the AcctID Map -- a corresponding Account ID is already there for that asset type.)

    // ******************************************************************************

    // Not found... There's no account ID yet for that asset type ID.
    // That means we can create it...
    //
    OTMessage theMessage; // Here we set up theMessage
    ACCOUNT_OWNER_ID.GetString(theMessage.m_strNymID);
    ASSET_TYPE_ID.GetString(theMessage.m_strAssetID);
    SERVER_ID.GetString(theMessage.m_strServerID);

    OTAccount * pAccount = OTAccount::GenerateNewAccount(ACCOUNT_OWNER_ID,	// theUserID
                           SERVER_ID,			// theServerID
                           theServerNym,		// theServerNym
                           theMessage,
                           m_AcctType,		// OTAccount::voucher is default.
                           lStashTransNum);
    // ------------------------------------------------------------------------------------------

    if (NULL == pAccount)
        OTLog::vError(" OTAcctList::GetOrCreateAccount: Failed trying to generate %s account with asset type ID: %s\n",
                      strAcctType.Get(), str_asset_type_id.c_str());
    else // SUCCESS creating the account...
    {
        OTString strAcctID;
        pAccount->GetIdentifier(strAcctID);

        OTLog::vOutput(0, "Successfully created %s account ID: %s Asset Type ID: %s\n",
                       strAcctType.Get(), strAcctID.Get(), str_asset_type_id.c_str());

        pRetVal = _SharedPtr<OTAccount>(pAccount); // Create a shared pointer to the account, so it will be cleaned up automatically.

        m_mapWeakAccts	[strAcctID.Get()]				= _WeakPtr<OTAccount>(pRetVal); // save a weak pointer to the acct, so we'll never load it twice, but we'll also know if it's been deleted.
        m_mapAcctIDs	[theMessage.m_strAssetID.Get()]	= strAcctID.Get(); // Save the new acct ID in a map, keyed by asset type ID.

        bWasAcctCreated = true;
    }

    return pRetVal;
}
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;
}
Example #10
0
// Lucre step 4: client unblinds token -- now it's ready for use.
bool OTToken::ProcessToken(const OTPseudonym & theNym, OTMint & theMint, OTToken & theRequest)
{
//		OTLog::vError("%s <bank public info> <private coin request> <signed coin request> <coin>\n",
	bool bReturnValue = false;
	
	// When the Mint has signed a token and sent it back to the client,
	// the client must unblind the token and set it as spendable. Thus,
	// this function is only performed on tokens in the signedToken state.
	if (OTToken::signedToken != m_State)
	{
		OTLog::Error("Signed token expected in OTToken::ProcessToken\n");
		return false;
	}
	
	// Lucre
    SetDumper(stderr);
    BIO *bioBank			= BIO_new(BIO_s_mem()); // input
    BIO *bioSignature		= BIO_new(BIO_s_mem()); // input
    BIO *bioPrivateRequest	= BIO_new(BIO_s_mem()); // input
    BIO *bioCoin			= BIO_new(BIO_s_mem()); // output
	
	// Get the bank's public key (decoded into strPublicMint)
	// and put it into bioBank so we can use it with Lucre.
	OTASCIIArmor ascPublicMint;
	theMint.GetPublic(ascPublicMint, GetDenomination());
	OTString strPublicMint(ascPublicMint);
	BIO_puts(bioBank, strPublicMint.Get());

	// Get the existing signature into a bio.
//	OTLog::vError("DEBUGGING, m_Signature: -------------%s--------------\n", m_Signature.Get());
	OTString strSignature(m_Signature);
	BIO_puts(bioSignature, strSignature.Get());
	
	// I need the Private coin request also. (Only the client has this private coin request data.)
	OTASCIIArmor thePrototoken;		// The server sets m_nChosenIndex when it signs the token.
	bool bFoundToken = theRequest.GetPrivatePrototoken(thePrototoken, m_nChosenIndex);
	
	if (bFoundToken)
	{
//		OTLog::vError("THE PRIVATE REQUEST ARMORED CONTENTS:\n------------------>%s<-----------------------\n",
//				thePrototoken.Get());
		
		// Decrypt the prototoken
		OTString strPrototoken;
		OTEnvelope theEnvelope(thePrototoken);
		theEnvelope.Open(theNym, strPrototoken); // todo check return value.
		
//		OTLog::vError("THE PRIVATE REQUEST CONTENTS:\n------------------>%s<-----------------------\n",
//				strPrototoken.Get());
		
		// copy strPrototoken to a BIO
		BIO_puts(bioPrivateRequest, strPrototoken.Get());
		
		// ------- Okay, the BIOs are all loaded.... let's process...
		
		PublicBank	bank(bioBank);
		CoinRequest	req(bioPrivateRequest);
		
		// TODO make sure I'm not leaking memory with these ReadNumbers
		// Probably need to be calling some free function for each one.
		
		// Apparently reading the request id here and then just discarding it...
		ReadNumber(bioSignature,"request=");
		
		// Versus the signature data, which is read into bnSignature apparently.
		BIGNUM * bnSignature	= ReadNumber(bioSignature,"signature=");
		DumpNumber("signature=", bnSignature);
		
		// Produce the final unblinded token in Coin coin, and write it to bioCoin...
		Coin coin; // Coin Request, processes into Coin, with Bank and Signature passed in.
		req.ProcessResponse(&coin, bank, bnSignature); // Notice still apparently "request" info is discarded.
		coin.WriteBIO(bioCoin);
		
		// convert bioCoin to a C-style string...
		char CoinBuffer[1024];   // todo stop hardcoding these string lengths
		int coinLen	= BIO_read(bioCoin, CoinBuffer, 1000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason.
		
		if (coinLen)
		{
			// ...to OTString...
			OTString strCoin;	
			strCoin.Set(CoinBuffer, coinLen);
			
//			OTLog::vError("Processing token...\n%s\n", strCoin.Get());
			
			// ...to Envelope stored in m_ascSpendable (encrypted and base64-encoded)
			OTEnvelope theEnvelope;
			theEnvelope.Seal(theNym, strCoin);	// Todo check the return values on these two functions
			theEnvelope.GetAsciiArmoredData(m_ascSpendable); // Here's the final product.
			
//			OTLog::vError("NEW SPENDABLE token...\n--------->%s<----------------\n", m_ascSpendable.Get());

			// Now the coin is encrypted from here on out, and otherwise ready-to-spend.
			m_State			= OTToken::spendableToken;
			bReturnValue	= true;
			
			// Lastly, we free the signature data, which is no longer needed, and which could be
			// otherwise used to trace the token. (Which we don't want.)
			m_Signature.Release();
		}
		
	}
	// Todo log error here if the private prototoken is not found. (Very strange if so!!)
	//  else {}
	
	// Cleanup openssl resources.
	BIO_free_all(bioBank);	
	BIO_free_all(bioSignature);	
	BIO_free_all(bioPrivateRequest);	
	BIO_free_all(bioCoin);	

	return bReturnValue;	
}
int32_t OTAcctList::ReadFromXMLNode(irr::io::IrrXMLReader*& xml, const OTString & strAcctType, const OTString & strAcctCount)
{
    if (!strAcctType.Exists())
    {
        OTLog::Error("OTAcctList::ReadFromXMLNode: Failed: Empty accountList 'type' attribute.\n");
        return (-1);
    }

    m_AcctType = TranslateAccountTypeStringToEnum(strAcctType);

    if (OTAccount::err_acct == m_AcctType)
    {
        OTLog::Error("OTAcctList::ReadFromXMLNode: Failed: accountList 'type' attribute contains unknown value.\n");
        return (-1);
    }

    // -----------------------------------------------
    //
    // Load up the account IDs.
    //
    int32_t nCount	= strAcctCount.Exists() ? atoi(strAcctCount.Get()) : 0;
    if (nCount > 0)
    {
        while (nCount-- > 0)
        {
//			xml->read();
            if (false == OTContract::SkipToElement(xml))
            {
                OTLog::Output(0, "OTAcctList::ReadFromXMLNode: Failure: Unable to find expected element.\n");
                return (-1);
            }
            // --------------------------------------

            if ((xml->getNodeType() == EXN_ELEMENT) && (!strcmp("accountEntry", xml->getNodeName())))
            {
                OTString strAssetTypeID	= xml->getAttributeValue("assetTypeID"); // Asset Type ID of this account.
                OTString strAccountID	= xml->getAttributeValue("accountID"); // Account ID for this account.

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

                if (!strAssetTypeID.Exists() || !strAccountID.Exists())
                {
                    OTLog::vError("OTAcctList::ReadFromXMLNode: Error loading accountEntry: Either the assetTypeID (%s), "
                                  "or the accountID (%s) was EMPTY.\n", strAssetTypeID.Get(), strAccountID.Get());
                    return (-1);
                }

                // Success
                m_mapAcctIDs.insert(std::pair<std::string, std::string>(strAssetTypeID.Get(), strAccountID.Get())); // <=============
            }
            else
            {
                OTLog::Error("OTAcctList::ReadFromXMLNode: Expected accountEntry element in accountList.\n");
                return (-1); // error condition
            }
        } // while
    }
    // --------------------------------

    if (false == OTContract::SkipAfterLoadingField(xml))	// </accountList>
    {   OTLog::Output(0, "*** OTAcctList::ReadFromXMLNode: Bad data? Expected EXN_ELEMENT_END here, but "
                      "didn't get it. Returning false.\n");
        return (-1);
    }

    return 1;
}
Example #12
0
// Lucre step 2 (client generates coin request)
// nDenomination must be one of the denominations supported by the mint.
// sets m_nTokenCount and populates the maps with prototokens (in ASCII-armored format.)
bool OTToken::GenerateTokenRequest(const OTPseudonym & theNym, OTMint & theMint, 
								   long lDenomination, int nTokenCount/*=OTToken::nMinimumPrototokenCount*/)
{		
	//	OTLog::vError("%s <bank public info> <coin request private output file> <coin request public output file>\n", argv[0]);

	if (OTToken::blankToken != m_State)
	{
		OTLog::Error("Blank token expected in OTToken::GenerateTokenRequest\n");
		return false;
	}
	
	// We are supposed to set these values here.
	// The server actually sets them again, for security reasons.
	// But we should still set them since server may choose to reject the request.
	SetSeriesAndExpiration(theMint.GetSeries(), theMint.GetValidFrom(), theMint.GetValidTo());
	
    SetDumper(stderr);
	
    BIO *bioBank		=	BIO_new(BIO_s_mem()); // Input. We must supply the bank's public lucre info
    BIO *bioCoin		=	BIO_new(BIO_s_mem()); // These two are output. We must write these bios, after
    BIO *bioPublicCoin	=	BIO_new(BIO_s_mem()); // the operation, back into some form we can use
	
	// This version base64-DECODES the ascii-armored string passed in,
	// and then sets the decoded plaintext string onto the string.
	//OTString::OTString(const OTASCIIArmor & strValue)
	OTASCIIArmor ascPublicMint;
	
	theMint.GetPublic(ascPublicMint, lDenomination);
	
//	OTLog::vError("DEBUG: OTToken  public asc: \n%s\n", ascPublicMint.Get());

	
	OTString strPublicMint(ascPublicMint);

//	OTLog::vError("DEBUG: OTToken  public str: \n%s\n", strPublicMint.Get());
	

	// Get the bank's public key (now decoded in strPublicMint)
	// and put it into bioBank so we can use it with Lucre.
	BIO_puts(bioBank, strPublicMint.Get());
	
	// Instantiate a PublicBank (Lucre) object.
	// We will use it to generate all the prototokens in the loop below.
    PublicBank bank;
    bank.ReadBIO(bioBank);
	
	Release();

	const int nFinalTokenCount = (nTokenCount < OTToken::nMinimumPrototokenCount) ? 
					OTToken::nMinimumPrototokenCount : nTokenCount; 
	
	// Token count is actually 1 (always) with Lucre, although this lib has potential to work with 
	// multiple proto-tokens, you can see this loop as though it always executes just once.
	for (int i = 0; i < nFinalTokenCount; i++)
	{
		CoinRequest req(bank);

		// write the private coin request to BIO
		req.WriteBIO(bioCoin);
		
		// write the public coin request to BIO
		((PublicCoinRequest *)&req)->WriteBIO(bioPublicCoin);
		
		// Convert the two bios to our format
		char privateCoinBuffer[4096], publicCoinBuffer[4096];   // todo stop hardcoding these string lengths
		int privatecoinLen	= BIO_read(bioCoin, privateCoinBuffer, 4000); // cutting it a little short on purpose, with the buffer. Just makes me feel more comfortable for some reason.
		int publiccoinLen	= BIO_read(bioPublicCoin, publicCoinBuffer, 4000); 
		
		if (privatecoinLen && publiccoinLen)
		{
			// With this, we have the Lucre public and private bank info converted to OTStrings
			OTString strPublicCoin;		strPublicCoin.Set(publicCoinBuffer, publiccoinLen);
			OTString strPrivateCoin;	strPrivateCoin.Set(privateCoinBuffer, privatecoinLen);
			
			OTASCIIArmor * pArmoredPublic	= new OTASCIIArmor(strPublicCoin);
			OTASCIIArmor * pArmoredPrivate	= new OTASCIIArmor();
			
			OT_ASSERT_MSG(((NULL != pArmoredPublic) && (NULL != pArmoredPrivate)), "ERROR: Unable to allocate memory in OTToken::GenerateTokenRequest\n");
			
			// Change the state. It's no longer a blank token, but a prototoken.
			m_State = OTToken::protoToken;

			// Seal the private coin info up into an encrypted Envelope 
			// and set it onto pArmoredPrivate (which was just added to our internal map, above.)
			OTEnvelope theEnvelope;
			theEnvelope.Seal(theNym, strPrivateCoin);	// Todo check the return values on these two functions
			theEnvelope.GetAsciiArmoredData(*pArmoredPrivate);
			
			m_mapPublic[i]	= pArmoredPublic;
			m_mapPrivate[i]	= pArmoredPrivate;

			m_nTokenCount = nFinalTokenCount;
			SetDenomination(lDenomination);
		}
		else {
			// Error condition
		}

		// Free the Private and Public coins and allocate them fresh, for the next iteration of the loop.
		BIO_free_all(bioCoin);	
		BIO_free_all(bioPublicCoin);

		bioCoin			=	BIO_new(BIO_s_mem());
		bioPublicCoin	=	BIO_new(BIO_s_mem());
	}
	
	
	// Cleanup openssl resources.
	BIO_free_all(bioBank);	
    BIO_free_all(bioCoin);	
    BIO_free_all(bioPublicCoin);
	
	return true;
}
Example #13
0
// return -1 if error, 0 if nothing, and 1 if the node was processed.
int OTToken::ProcessXMLNode(IrrXMLReader*& xml)
{
	static int nPublicTokenCount = 0;
	static int nPrivateTokenCount = 0;
	
	int nReturnVal = 0;
	
	// Here we call the parent class first.
	// If the node is found there, or there is some error,
	// then we just return either way.  But if it comes back
	// as '0', then nothing happened, and we'll continue executing.
	//
	// -- Note you can choose not to call the parent if
	// you don't want to use any of those xml tags.
	// As I do below, in the case of OTAccount.
	//if (nReturnVal = OTContract::ProcessXMLNode(xml))
	//	return nReturnVal;
	
	if (!strcmp("token", xml->getNodeName())) 
	{
		OTString strState;

		m_strVersion	= xml->getAttributeValue("version");					
		strState		= xml->getAttributeValue("state");

		m_nSeries		= atoi(xml->getAttributeValue("series"));
		m_VALID_FROM	= atol(xml->getAttributeValue("validFrom"));
		m_VALID_TO		= atol(xml->getAttributeValue("validTo"));
		
		SetDenomination(atol(xml->getAttributeValue("denomination")));

		if (strState.Compare("blankToken"))
			m_State = OTToken::blankToken;
		else if (strState.Compare("protoToken"))
			m_State = OTToken::protoToken;
		else if (strState.Compare("signedToken"))
			m_State = OTToken::signedToken;
		else if (strState.Compare("spendableToken"))
			m_State = OTToken::spendableToken;
		else if (strState.Compare("verifiedToken"))
			m_State = OTToken::verifiedToken;
		else
			m_State = OTToken::errorToken;
		
        if (m_State == OTToken::spendableToken)
            m_strContractType.Set("CASH");

		OTString	strAssetTypeID(xml->getAttributeValue("assetTypeID")),
					strServerID(xml->getAttributeValue("serverID"));
		
		m_AssetTypeID.SetString(strAssetTypeID);
		m_ServerID.SetString(strServerID);

		OTLog::vOutput(4,
				//	"\n===> Loading XML for token into memory structures..."
				"\n\nToken State: %s\n Denomination: %ld\n"
				" AssetTypeID: %s\nServerID: %s\n", 
				strState.Get(), GetDenomination(), strAssetTypeID.Get(), strServerID.Get());
		
		nReturnVal = 1;
	}
	
	else if (!strcmp("tokenID", xml->getNodeName())) 
	{		
		if (false == LoadEncodedTextField(xml, m_ascSpendable))
		{
			OTLog::Error("Error in OTToken::ProcessXMLNode: token ID without value.\n");
			return (-1); // error condition
		}
		
		return 1;
	}
	
	else if (!strcmp("tokenSignature", xml->getNodeName())) 
	{		
		if (false == LoadEncodedTextField(xml, m_Signature))
		{
			OTLog::Error("Error in OTToken::ProcessXMLNode: token Signature without value.\n");
			return (-1); // error condition
		}
		
		return 1;
	}
	
	else if (!strcmp("protopurse", xml->getNodeName())) 
	{	// TODO for security, if the count here doesn't match what's loaded up, that should be part of
		// what is verified in each token when it's verified..
		m_nTokenCount	= atoi(xml->getAttributeValue("count"));
		m_nChosenIndex	= atoi(xml->getAttributeValue("chosenIndex"));

		nPublicTokenCount = 0;
		
		return 1;
	}
	
	else if (!strcmp("prototoken", xml->getNodeName())) 
	{		
		OTASCIIArmor * pArmoredPrototoken = new OTASCIIArmor;
		
		OT_ASSERT(NULL != pArmoredPrototoken);
		
		if (!LoadEncodedTextField(xml, *pArmoredPrototoken) || !pArmoredPrototoken->Exists())
		{
			OTLog::Error("Error in OTToken::ProcessXMLNode: prototoken field without value.\n");
			
			delete pArmoredPrototoken;
			pArmoredPrototoken = NULL;
			
			return (-1); // error condition
		}
		else 
		{			
			m_mapPublic[nPublicTokenCount] = pArmoredPrototoken;
			nPublicTokenCount++;
		}
		
		return 1;
	}
		
	else if (!strcmp("privateProtopurse", xml->getNodeName())) 
	{	
		nPrivateTokenCount = 0;
		
		return 1;
	}
	
	else if (!strcmp("privatePrototoken", xml->getNodeName())) 
	{		
		OTASCIIArmor * pArmoredPrototoken = new OTASCIIArmor;
		
		OT_ASSERT(NULL != pArmoredPrototoken);
		
		if (!LoadEncodedTextField(xml, *pArmoredPrototoken) || !pArmoredPrototoken->Exists())
		{
			OTLog::Error("Error in OTToken::ProcessXMLNode: privatePrototoken field without value.\n");
			
			delete pArmoredPrototoken;
			pArmoredPrototoken = NULL;
			
			return (-1); // error condition
		}
		else 
		{			
			m_mapPrivate[nPrivateTokenCount] = pArmoredPrototoken;
			nPrivateTokenCount++;
			
			OTLog::vOutput(4, "Loaded prototoken and adding to m_mapPrivate at index: %d\n", nPrivateTokenCount-1);
		}
		
		return 1;
	}
		
	return nReturnVal;
}
Example #14
0
void OTToken::UpdateContents()
{
	if (m_State == OTToken::spendableToken)
		m_strContractType.Set("CASH");
	
	OTString ASSET_TYPE_ID(m_AssetTypeID), SERVER_ID(m_ServerID);
	
	OTString strState;
	switch (m_State) {
		case OTToken::blankToken:
			strState.Set("blankToken");
			break;
		case OTToken::protoToken:
			strState.Set("protoToken");
			break;
		case OTToken::signedToken:
			strState.Set("signedToken");
			break;
		case OTToken::spendableToken:
			strState.Set("spendableToken");
			break;
		case OTToken::verifiedToken:
			strState.Set("verifiedToken");
			break;
		default:
			strState.Set("errorToken");
			break;
	}

	long lFrom = m_VALID_FROM, lTo = m_VALID_TO;

	
	// I release this because I'm about to repopulate it.
	m_xmlUnsigned.Release();
	
	m_xmlUnsigned.Concatenate("<?xml version=\"%s\"?>\n\n", "1.0");		
	
	m_xmlUnsigned.Concatenate("<token\n version=\"%s\"\n state=\"%s\"\n denomination=\"%ld\"\n"
							  " assetTypeID=\"%s\"\n"
							  " serverID=\"%s\"\n"
							  " series=\"%d\"\n"
							  " validFrom=\"%ld\"\n"
							  " validTo=\"%ld\""							  
							  " >\n\n", 
							  m_strVersion.Get(), strState.Get(), GetDenomination(), 
							  ASSET_TYPE_ID.Get(), 
							  SERVER_ID.Get(),
							  m_nSeries, lFrom, lTo );		

	// signed tokens, as well as spendable tokens, both carry a TokenID
	// (The spendable token contains the unblinded version.)
	if (OTToken::signedToken	== m_State || 
		OTToken::spendableToken	== m_State)
	{
		m_xmlUnsigned.Concatenate("<tokenID>\n%s</tokenID>\n\n", m_ascSpendable.Get());
	}
	
	// Only signedTokens carry the signature, which is discarded in spendable tokens.
	// (Because it is not used past the unblinding stage anyway, and because it could
	// be used to track the token.)
	if (OTToken::signedToken == m_State)
	{
		m_xmlUnsigned.Concatenate("<tokenSignature>\n%s</tokenSignature>\n\n", m_Signature.Get());
	}
	
	if ((OTToken::protoToken == m_State || 
		 OTToken::signedToken == m_State)	&& m_nTokenCount)
	{
		m_xmlUnsigned.Concatenate("<protopurse count=\"%d\" chosenIndex=\"%d\">\n\n", m_nTokenCount, m_nChosenIndex);
		
		OTASCIIArmor * pPrototoken = NULL;
		for (mapOfPrototokens::iterator ii = m_mapPublic.begin(); ii != m_mapPublic.end(); ++ii)
		{
			pPrototoken = (*ii).second;
			
			OT_ASSERT(NULL != pPrototoken);
			
			m_xmlUnsigned.Concatenate("<prototoken>\n%s</prototoken>\n\n", pPrototoken->Get());
		}		
		m_xmlUnsigned.Concatenate("</protopurse>\n\n");
	}
	
	if (m_bSavePrivateKeys)
	{
		m_bSavePrivateKeys = false; // set it back to false;
		
		m_xmlUnsigned.Concatenate("<privateProtopurse>\n\n");
		
		OTASCIIArmor * pPrototoken = NULL;
		for (mapOfPrototokens::iterator ii = m_mapPrivate.begin(); ii != m_mapPrivate.end(); ++ii)
		{
			pPrototoken = (*ii).second;
			
			OT_ASSERT(NULL != pPrototoken);
			
			m_xmlUnsigned.Concatenate("<privatePrototoken>\n%s</privatePrototoken>\n\n", pPrototoken->Get());
		}		
		m_xmlUnsigned.Concatenate("</privateProtopurse>\n\n");
	}
	
	m_xmlUnsigned.Concatenate("</token>\n");			
}
Example #15
0
int main (int argc, char * const argv[])
{
	if (argc < 3)
	{
		printf("Usage:  createmint server_user_id asset_type_id\n\n"
			   "For now, expiration dates are automatically set:\n"
			   "FROM: Today, Now.\n"
			   "TO: 6 months from now.\n\n"
			   "It is recommended that you issue a new series (create a new mint) every 3 months for each\n"
			   "asset type, so that there is a 3-month overlap. In the future, this will be configured inside\n"
			   "the contracts themselves.\n\n"
			   "Server user ID needs to match the Server User ID from notaryServer.xml\n"
			   "Asset Type ID needs to match the Asset ID (aka Hashed Contract ID) of the currency contract.\n\n");
		exit(1);
	}
	
	SSL_library_init();
	SSL_load_error_strings();

	OTString strServerID(argv[1]), strAssetTypeID(argv[2]);
	OTIdentifier ASSET_TYPE_ID(strAssetTypeID);
	
	
	OTString strMintPath;
	bool bFileIsPresent = false;		
	int nSeries = 0;
	
	for (nSeries = 0; nSeries < 1000; nSeries++)
	{
		struct stat st;

		strMintPath.Format("%s%smints%s%s.%d", 
									 OTLog::Path(), OTLog::PathSeparator(),
									 OTLog::PathSeparator(),
									 strAssetTypeID.Get(), nSeries);
		
		bFileIsPresent = (stat(strMintPath.Get(), &st) == 0);
		
		if (!bFileIsPresent)
			break;
	}
	
	// if bFileIsPresent is STILL true, that means we got all the way up to 1000 and the 
	// file was present every time.
	// Geez, there must be 1000 mints on this computer.  At one new Mint per 3 months,
	// that's 4 per year, that's 250 years already!!
	if (bFileIsPresent)
	{
		fprintf(stdout, "This program automatically finds the next series, up to 1000. You\n"
				"have reached 1000. You will have to change the source code of this\n"
				"program in order to continue. Sorry.\n");
		exit(1);
	}
	
	
	// nSeries now contains the number we need to use for the next series.
	// and strMintPath now contains the correct file path.
	
	OTMint * pMint = new OTMint(strAssetTypeID, strMintPath, strAssetTypeID);
	
	if (pMint && pMint->LoadContract())
	{
		printf("The mint already exists. Delete it first if you wish to re-create it.\n");
	}
	else 
	{
		fprintf(stderr, "Mint file does not yet exist, for series %d and asset type:\n%s\nCreating......\n", 
				nSeries, strAssetTypeID.Get());
		
		if (pMint)
		{	
			// TODO: read the denominations out of the asset contract itself, instead of hardcoding them here.
			
			
			// Calculate FROM as Today, Now, 
			// then calculate TO as 6 months from now, 
			// and EXPIRATION as 3 months from now.
			//
			// TODO: Let these numbers be configured either in server operator contract, or issuer contract.
			// In the meantime, 3 and 6 months are good enough.
			
			OTPseudonym theNym;
			theNym.SetIdentifier(strServerID);
			
			// 1 hour	==     3600 Seconds
			// 1 day	==    86400 Seconds
			// 30 days	==  2592000 Seconds
			// 3 months ==  7776000 Seconds
			// 6 months == 15552000 Seconds
			
			
			// This part requires the server operator to enter his passphrase.
			// Which is why the server can't just fire it off automatically and
			// make a mint available to the client.  The client has to wait a day or
			// until the operator is able to run this script and type the passphrase.
			if (theNym.Loadx509CertAndPrivateKey())
			{								
				const time_t	CURRENT_TIME	= time(NULL), 
								VALID_TO		= CURRENT_TIME + 15552000,	// Tokens generated by this mint are valid from today until 6 months from today
								MINT_EXPIRATION	= CURRENT_TIME + 7776000;	// The mint itself will expire in 3 months from today, and be replaced with a new one.
				
				pMint->GenerateNewMint(nSeries, CURRENT_TIME, VALID_TO, MINT_EXPIRATION,
														// penny, nickel, dime, quarter, $1, $5, $10, $20, $100, $1000
									   ASSET_TYPE_ID, theNym, 1, 5, 10, 25, 100, 500, 1000, 2000, 10000, 100000);
												// should be: 1, 2, 4,   8,  16,  32,   64,  128,   256,    512, 1024, 2048, 4096, 8192, 16384, 32768, 65536
				
				pMint->SetSavePrivateKeys(); // This causes the next serialization to save the private, not just public, keys.
				pMint->SignContract(theNym);
				pMint->SaveContract(strMintPath.Get());  // save the mint file.
				
				// Now I sign it again, to get the private keys out of there.
				pMint->ReleaseSignatures();
				pMint->SignContract(theNym);
				strMintPath.Format("%s%smints%s%s.PUBLIC", OTLog::Path(), OTLog::PathSeparator(),
								   OTLog::PathSeparator(), strAssetTypeID.Get());
				pMint->SaveContract(strMintPath.Get());
				printf("Done.\n");
			}
			else {
				printf("Error calling theNym.Loadx509CertAndPrivateKey()\n");
			}
		}
		else 
		{
			fprintf(stdout, "Error allocating memory for new OTMint.\n");
		}
	}
	
	return 0;
}
bool OTEnvelope::Decrypt(OTString & theOutput, const OTSymmetricKey & theKey, const OTPassword & thePassword)
{
    const char * szFunc = "OTEnvelope::Decrypt";
    // ------------------------------------------------
    OT_ASSERT((thePassword.isPassword() && (thePassword.getPasswordSize() > 0)) || (thePassword.isMemory() && (thePassword.getMemorySize() > 0)));
    OT_ASSERT(theKey.IsGenerated());
    // -----------------------------------------------
    OTPassword  theRawSymmetricKey;
    
    if (false == theKey.GetRawKeyFromPassphrase(thePassword, theRawSymmetricKey))
    {
		OTLog::vError("%s: Failed trying to retrieve raw symmetric key using password. (Wrong password?)\n", 
                      szFunc);
		return false;	
    }
    // -----------------------------------------------
    //
    uint32_t    nRead         = 0;
    uint32_t    nRunningTotal = 0;
    
    m_dataContents.reset(); // Reset the fread position on this object to 0.

    // ****************************************************************************
    //
    // Read the ENVELOPE TYPE (as network order version -- and convert to host version.)
    //
    // 0 == Error
    // 1 == Asymmetric Key  (this function -- Seal / Open)
    // 2 == Symmetric Key   (other functions -- Encrypt / Decrypt use this.)
    // Anything else: error.
    //
    uint16_t  env_type_n = 0;
    
    if (0 == (nRead = m_dataContents.OTfread(reinterpret_cast<uint8_t*>(&env_type_n),
                                             static_cast<uint32_t>(sizeof(env_type_n)))))
	{
		OTLog::vError("%s: Error reading Envelope Type. Expected asymmetric(1) or symmetric (2).\n", szFunc);
		return false;
	}
    nRunningTotal += nRead;
    OT_ASSERT(nRead == static_cast<uint32_t>(sizeof(env_type_n)));
    // ----------------------------------------------------------------------------
	// convert that envelope type from network to HOST endian.
    //
    const uint16_t env_type = static_cast<uint16_t>(ntohs(static_cast<uint16_t>(env_type_n)));
//  nRunningTotal += env_type;    // NOPE! Just because envelope type is 1 or 2, doesn't mean we add 1 or 2 extra bytes to the length here. Nope!
    
    if (2 != env_type)
	{
        const uint32_t l_env_type = static_cast<uint32_t>(env_type);
		OTLog::vError("%s: Error: Expected Envelope for Symmetric key (type 2) but instead found type: %ld.\n", 
                      szFunc, l_env_type);
		return false;
	}
    // ****************************************************************************
    //
    // Read network-order IV size (and convert to host version) 
    //    
    const uint32_t max_iv_length   = OTCryptoConfig::SymmetricIvSize(); // I believe this is a max length, so it may not match the actual length of the IV.
    
    // Read the IV SIZE (network order version -- convert to host version.)
    //
    uint32_t	iv_size_n   = 0;
    
    if (0 == (nRead = m_dataContents.OTfread(reinterpret_cast<uint8_t*>(&iv_size_n),
                                             static_cast<uint32_t>(sizeof(iv_size_n)))))
	{
		OTLog::vError("%s: Error reading IV Size.\n", szFunc);
		return false;
	}
    nRunningTotal += nRead;
    OT_ASSERT(nRead == static_cast<uint32_t>(sizeof(iv_size_n)));
    // ----------------------------------------------------------------------------
	// convert that iv size from network to HOST endian.
    //
    const uint32_t iv_size_host_order = ntohl(iv_size_n);
    
    if (iv_size_host_order > max_iv_length)
    {
        OTLog::vError("%s: Error: iv_size (%ld) is larger than max_iv_length (%ld).\n",
                      szFunc, static_cast<long>(iv_size_host_order), static_cast<long>(max_iv_length));
        return false;
    }
//  nRunningTotal += iv_size_host_order; // Nope!
    // ****************************************************************************
    //
    // Then read the IV (initialization vector) itself.
    //
    OTPayload theIV;
    theIV.SetPayloadSize(iv_size_host_order);
    
    if (0 == (nRead = m_dataContents.OTfread(static_cast<uint8_t*>(const_cast<void *>(theIV.GetPayloadPointer())), 
                                             static_cast<uint32_t>(iv_size_host_order))))
    {
        OTLog::vError("%s: Error reading initialization vector.\n", szFunc);
        return false;
    }
    nRunningTotal += nRead;
    OT_ASSERT(nRead == static_cast<uint32_t>(iv_size_host_order));
    
    OT_ASSERT(nRead <= max_iv_length);
    
	// ----------------------------------------------------------------------------    
    // We create an OTPayload object to store the ciphertext itself, which begins AFTER the end of the IV.
    // So we see pointer + nRunningTotal as the starting point for the ciphertext.
    // the size of the ciphertext, meanwhile, is the size of the entire thing, MINUS nRunningTotal.
    //
	OTPayload theCipherText(static_cast<const void*>( 
                                               static_cast<const uint8_t *>(m_dataContents.GetPointer()) + nRunningTotal
                                               ), 
					  m_dataContents.GetSize() - nRunningTotal);
    // ----------------------------------------------------------------------------
    // Now we've got all the pieces together, let's try to decrypt it...
    //
    OTPayload thePlaintext; // for output.
    
    const bool bDecrypted = OTCrypto::It()->Decrypt(theRawSymmetricKey, // The symmetric key, in clear form.
                                                    // -------------------------------
                                                    static_cast<const char *>(theCipherText.GetPayloadPointer()),  // This is the Ciphertext.
                                                    theCipherText.GetSize(),
                                                    // -------------------------------
                                                    theIV,
                                                    // -------------------------------
                                                    thePlaintext); // OUTPUT. (Recovered plaintext.) You can pass OTPassword& OR OTPayload& here (either will work.)
    // -----------------------------------------------
    // theOutput is where we'll put the decrypted data.
    //
    theOutput.Release();
    
    if (bDecrypted)
    {
        // -----------------------------------------------------
        // Make sure it's null-terminated...
        //
        uint32_t nIndex = thePlaintext.GetSize()-1;
        (static_cast<uint8_t*>(const_cast<void *>(thePlaintext.GetPointer())))[nIndex] = '\0';
        
        // -----------------------------------------------------
        // Set it into theOutput (to return the plaintext to the caller)
        //
        theOutput.Set(static_cast<const char *>(thePlaintext.GetPointer()));
        // ----------------
    }
    
    return bDecrypted;
}
Example #17
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;
}
Example #18
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;
}
Example #19
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
}
/// 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 & theData, bool bLineBreaks) //=true
{
//	OTLog::vError("DEBUGGING OTASCIIARMOR::SETSTRING, INPUT:  --------->%s<---------", theData.Get());
	
	Release();
	
	if (theData.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	= theData.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(theData.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	= 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);
	
	memcpy(pSource, static_cast<const unsigned char*>(pUint), 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]; // 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::SetAndPackString\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::SetAndPackString\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::SetAndPackString\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::SetAndPackString\n");
		return false; // not really necessary but just making sure.
	}
	
	
	OT_ASSERT_MSG(pDest != NULL, "pDest NULL in OTASCIIArmor::SetAndPackString\n");
	
	// Success
	if (0 < nDestLen)
	{
		// Now let's base-64 encode it...
		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;	
}
Example #21
0
const bool OTPaths::ConfirmCreateFolder(const OTString & strExactPath, bool & out_Exists, bool & out_IsNew)
{
	const bool bExists = (strExactPath.Exists() && !strExactPath.Compare(""));
	OT_ASSERT_MSG(bExists,"OTPaths::ConfirmCreateFolder: Assert failed: no strFolderName\n");

	std::string l_strExactPath(strExactPath.Get());

	if ('/' != *l_strExactPath.rbegin()) return false; // not a directory.

	// Confirm If Directory Exists Already
	out_Exists = PathExists(strExactPath);

	if (out_Exists)
	{
		out_IsNew = false;
		return true;  // Already Have Folder, lets retun true!
	}
	else 
	{
		// It dosn't exist: lets create it.

#ifdef _WIN32
		bool bCreateDirSuccess = (_mkdir(strExactPath.Get()) == 0);
#else
		bool bCreateDirSuccess = (mkdir(strExactPath.Get(), 0700) == 0);
#endif

		if (!bCreateDirSuccess) 
		{
			OTLog::vError("OTPaths::ConfirmCreateFolder: Unable To Confirm "
				"Created Directory %s.\n", strExactPath.Get());
			out_IsNew = false;
			out_Exists = false;
			return false;
		}

		// At this point if the folder still doesn't exist, nothing we can do. We
		// already tried to create the folder, and SUCCEEDED, and then STILL failed 
		// to find it (if this is still false.)

		else 
		{
			bool bCheckDirExist = PathExists(strExactPath);

			if (!bCheckDirExist) 
			{
				OTLog::vError("OTPaths::ConfirmCreateFolder: "
					"Unable To Confirm Created Directory %s.\n", 
					strExactPath.Get());
				out_IsNew = false;
				out_Exists = false;
				return false;
			}
			else
			{
				out_IsNew = true;
				out_Exists = false;
				return true;  // We have Created and checked the Folder
			}
		}
		return false; // should never happen.
	}
}
// 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;
}
bool OTIdentifier::operator!=(const OTIdentifier &s2) const
{
	const OTString ots1(*this), ots2(s2);
	return !(ots1.Compare(ots2));	
}
// This code reads up the file, discards the bookends, and saves only the gibberish itself.
// the bEscaped option allows you to load a normal ASCII-Armored file if off, and allows
// you to load an escaped ASCII-armored file (such as inside the contracts when the public keys
// are escaped with a "- " before the rest of the ------- starts.)
bool OTASCIIArmor::LoadFromString(OTString & theStr, bool bEscaped/*=false*/)
{
	char buffer1[2100];
	
	memset(buffer1, 0, 2100);
	
	bool bContentMode = false;				// "currently in content mode"
	bool bHaveEnteredContentMode = false;	// "have yet to enter content mode"
	
	// Clear out whatever string might have been in there before.
	Release();
	
	// Load up the string from theStr, 
	// (bookended by "-----BEGIN ... -----" and END messages)
	bool bIsEOF = false;
	theStr.reset(); // So we can call theStr.sgets(). Making sure position is at start of string.
	
	do
	{
		bIsEOF = !(theStr.sgets(buffer1, 2048));
		//		bIsEOF = fin.getline(buffer1, 2048).eof();
		
		std::string line		= buffer1;	
		const char * pConstBuf	= line.c_str();
		char * pBuf				= (char *)pConstBuf;
		
		// It's not a blank line.
		if (line.length() < 2)
		{
			continue;
		}
		
		// if we're on a dashed line...
		else if (line.at(0) == '-' && line.at(2) == '-' && line.at(3) == '-'
				 && (bEscaped ? (line.at(1) == ' ') : (line.at(1) == '-') ) )
		{			
			// If I just hit a dash, that means there are only two options:
			
			// a. I have not yet entered content mode, and potentially just now entering it for the first time.
			if (!bHaveEnteredContentMode)
			{
				if (line.find("BEGIN")!=std::string::npos && line.at(0) == '-' && line.at(2) == '-' && 
					line.at(3) == '-' && (bEscaped ? (line.at(1) == ' ') : (line.at(1) == '-')))
				{
//					OTLog::Error("Reading ascii-armored contents...");
					bHaveEnteredContentMode = true;
					bContentMode = true;
					continue;
				}
				else
				{
					continue;
				}				
				
			}
			
			// b. I am now LEAVING content mode!
			else if (bContentMode && line.find("END")!=std::string::npos)
			{
//				OTLog::Error("Finished reading ascii-armored contents.\n");
//				OTLog::vError("Finished reading ascii-armored contents:\n%s(END DATA)\n", Get());
				bContentMode   = false;
				continue;
			}
		}
		
		
		// Else we're on a normal line, not a dashed line.
		else
		{
			if (bHaveEnteredContentMode && bContentMode)
			{
				if (line.compare(0,8,"Version:") == 0)
				{
//					OTLog::Error("Skipping version line...\n");
					continue;
				}
			}
			
		}
		
		// Here we save the line to member variables, if appropriate
		if (bContentMode)
		{
			Concatenate("%s\n", pBuf);
		}
	}
	while(!bIsEOF && (bContentMode || !bHaveEnteredContentMode));
	
	
	// reset the string position back to 0
	theStr.reset();
	
	if (!bHaveEnteredContentMode)
	{
		OTLog::Error("Error in OTASCIIArmor::LoadFromString: EOF before ascii-armored content found.\n");
		return false;
	}
	else if (bContentMode)
	{
		OTLog::Error("Error in OTASCIIArmor::LoadFromString: EOF while still reading content.\n");
		return false;
	}
	else
		return true;
}
Example #25
0
void OTLog::Output(int nVerbosity, OTString & strOutput)
{
	if (strOutput.Exists())
		OTLog::Output(nVerbosity, strOutput.Get());
}
/// if we pack, compress, encode on the way in, that means, therefore, we
/// need to decode, uncompress, then unpack on our way out. Right?
///
/// This function will base64-DECODE the string contents, then uncompress them using
/// zlib, and then unpack the result using whatever is the default packer (MsgPack, Protobuf, etc).
/// 
/// I originally added compression because message sizes were too big. Now I'm adding packing, 
/// to solve any issues of binary compatibility across various platforms.
//
bool OTASCIIArmor::GetAndUnpackString(OTString & theData, bool bLineBreaks) const //bLineBreaks=true
{	
	size_t		outSize	= 0;
	uint8_t *	pData	= NULL;
	
	theData.Release();
	
	if (GetLength() < 1)
	{
		return true;
	}
	
	// --------------------------------------------------------------
	//
	pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0));
	
	if (pData)
	{
		// -------------------------------------------
		// EASY ZLIB
		//
		long nDestLen = DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.)
		unsigned char* pDest = new unsigned char [nDestLen+10]; // For safety.
		
		OT_ASSERT(NULL != pDest);
		
		int nErr = ezuncompress( pDest, &nDestLen, pData, outSize );
		if ( nErr == EZ_BUF_ERROR )
		{
			delete [] pDest;
			pDest = new unsigned char [nDestLen]; // enough room now
			
			OT_ASSERT(NULL != pDest);
			
			nErr = ezuncompress( pDest, &nDestLen, pData, outSize );
		}
		
		// Now we're done with this memory, let's free it.
		delete [] pData; pData=NULL;
		
		// ----------------------------------------
		
		if ( nErr == EZ_BUF_ERROR )
		{
			delete [] pDest;
			pDest = NULL;
			
			OT_ASSERT_MSG(false, "Buffer error in OTASCIIArmor::GetAndUnpackString\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::GetAndUnpackString\n");
			return false; // not really necessary but just making sure.
		}
		else if ( nErr == EZ_DATA_ERROR )
		{
			delete [] pDest;
			pDest = NULL;
			
			OTLog::vError("corrupted pSrc passed to ezuncompress OTASCIIArmor::GetAndUnpackString, size: %d\n", outSize);
			
			OT_ASSERT(false);
			
			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::GetAndUnpackString\n");
			return false; // not really necessary but just making sure.
		}
		
		// ---------------------------------------
		
		// PUT THE PACKED BUFFER HERE, AND UNPACK INTO THEDATA
		
		// --------------------------------------------------------
		
		OTDB::OTPacker * pPacker = OTASCIIArmor::GetPacker(); // No need to check for failure, since this already ASSERTS. No need to cleanup either.
		
		OTDB::PackedBuffer * pBuffer = pPacker->CreateBuffer(); // Need to clean this up.
		OT_ASSERT(NULL != pBuffer);
		OTCleanup<OTDB::PackedBuffer> theBufferAngel(*pBuffer); // This will make sure buffer is deleted later.
		
		const size_t theDestLen = nDestLen;
		
		pBuffer->SetData(pDest, // const unsigned char *
						 theDestLen);

		delete [] pDest; pDest=NULL; 

		// -----------------------------
		
		OTDB::OTDBString * pOTDBString = dynamic_cast<OTDB::OTDBString *>(OTDB::CreateObject(OTDB::STORED_OBJ_STRING));
		OT_ASSERT(NULL != pOTDBString);
		OTCleanup<OTDB::OTDBString> theStringAngel(*pOTDBString); // clean up this string.
		
		bool bUnpacked = pPacker->Unpack(*pBuffer, *pOTDBString);
		
		// ----------------------
		
		if (false == bUnpacked)
		{
			OTLog::Error("Failed unpacking string in OTASCIIArmor::GetAndUnpackString.\n");
			
			return false;
		}
		
		// --------------------------------------------------------
		
		// This enforces the null termination. (using the 2nd parameter as nEnforcedMaxLength)
		theData.Set(pOTDBString->m_string.c_str(), pOTDBString->m_string.length());
		
		return true;
	}
	else 
	{
		OTLog::Error("OTASCIIArmor::GetAndUnpackString: NULL pData while base64-decoding pData.\n");
		return false;
	}
}
// return -1 if error, 0 if nothing, and 1 if the node was processed.
int OTBasket::ProcessXMLNode(irr::io::IrrXMLReader*& xml)
{
    if (!strcmp("currencyBasket", xml->getNodeName()))
    {
        OTString strSubCount, strMinTrans;
        strSubCount			= xml->getAttributeValue("contractCount");
        strMinTrans			= xml->getAttributeValue("minimumTransfer");

        m_nSubCount			= atoi(strSubCount.Get());
        m_lMinimumTransfer	= atol(strMinTrans.Get());

        OTLog::Output(1, "Loading currency basket...\n");

        return 1;
    }
    else if (!strcmp("requestExchange", xml->getNodeName()))
    {
        OTString strTransferMultiple, strRequestAccountID, strDirection, strTemp;

        strTransferMultiple	= xml->getAttributeValue("transferMultiple");
        strRequestAccountID	= xml->getAttributeValue("transferAccountID");
        strDirection        = xml->getAttributeValue("direction");
        strTemp             = xml->getAttributeValue("closingTransactionNo");

        if (strTransferMultiple.Exists())
            m_nTransferMultiple	= atoi(strTransferMultiple.Get());
        if (strRequestAccountID.Exists())
            m_RequestAccountID.SetString(strRequestAccountID);
        if (strDirection.Exists())
            m_bExchangingIn = strDirection.Compare("in");
        if (strTemp.Exists())
            SetClosingNum(atol(	strTemp.Get()	));

        OTLog::vOutput(2, "Basket Transfer multiple is %d. Direction is %s. Closing number is %ld. "
                       "Target account is:\n%s\n", m_nTransferMultiple, strDirection.Get(),
                       m_lClosingTransactionNo, strRequestAccountID.Get());

        return 1;
    }
    else if (!strcmp("basketItem", xml->getNodeName()))
    {
        BasketItem * pItem = new BasketItem;

        OT_ASSERT_MSG(NULL != pItem, "Error allocating memory in OTBasket::ProcessXMLNode\n");

        OTString strTemp;

        strTemp = xml->getAttributeValue("minimumTransfer");
        if (strTemp.Exists())
            pItem->lMinimumTransferAmount	= atol(	strTemp.Get()	);

        strTemp = xml->getAttributeValue("closingTransactionNo");
        if (strTemp.Exists())
            pItem->lClosingTransactionNo	= atol(	strTemp.Get()	);

        OTString	strSubAccountID(xml->getAttributeValue("accountID")),
                    strContractID(xml->getAttributeValue("assetID"));
        pItem->SUB_ACCOUNT_ID.SetString(strSubAccountID);
        pItem->SUB_CONTRACT_ID.SetString(strContractID);

        m_dequeItems.push_back(pItem);

        OTLog::Output(2, "Loaded basket item.\n");

        return 1;
    }

    return 0;
}
bool OTASCIIArmor::GetString(OTString & theData, bool bLineBreaks) const //bLineBreaks=true
{	
	return GetAndUnpackString(theData, bLineBreaks);
	
	
	
	
	
	size_t		outSize	= 0;
	uint8_t *	pData	= NULL;
	
	theData.Release();
	
	if (GetLength() < 1) {
		return true;
	}
	
	pData = OT_base64_decode(Get(), &outSize, (bLineBreaks ? 1 : 0));
	
	if (pData)
	{
		long nDestLen = DEFAULT_BUFFER_SIZE_EASYZLIB; // todo stop hardcoding numbers (but this one is OK I think.)
		unsigned char* pDest = new unsigned char [nDestLen+10]; // For safety.
		
		OT_ASSERT(NULL != pDest);
		
		int nErr = ezuncompress( pDest, &nDestLen, pData, outSize );
		if ( nErr == EZ_BUF_ERROR )
		{
			delete [] pDest;
			pDest = new unsigned char [nDestLen]; // enough room now
			
			OT_ASSERT(NULL != pDest);
			
			nErr = ezuncompress( pDest, &nDestLen, pData, outSize );
		}
		
		// Now we're done with this memory, let's free it.
		delete [] pData; pData=NULL;
		
		// ----------------------------------------
		
		if ( nErr == EZ_BUF_ERROR )
		{
			delete [] pDest;
			pDest = NULL;
			
			OT_ASSERT_MSG(false, "Buffer error in OTASCIIArmor::GetString\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::GetString\n");
			return false; // not really necessary but just making sure.
		}
		else if ( nErr == EZ_DATA_ERROR )
		{
			delete [] pDest;
			pDest = NULL;
			
			OTLog::vError("corrupted pSrc passed to ezuncompress OTASCIIArmor::GetString, size: %d\n", outSize);
			
			OT_ASSERT(false);
			
			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::GetString\n");
			return false; // not really necessary but just making sure.
		}
		
		// This enforces the null termination. (using the extra parameter nDestLen as nEnforcedMaxLength)
		theData.Set((const char*)pDest, nDestLen);
		
		delete [] pDest; pDest=NULL; 
		return true;
	}
	else 
	{
		OTLog::Error("NULL pData while base64_decodeing pData.\n");
		return false;
	}
}
int OTSignedFile::ProcessXMLNode(irr::io::IrrXMLReader*& xml)
{
	int nReturnVal = 0;
	
	// Here we call the parent class first.
	// If the node is found there, or there is some error,
	// then we just return either way.  But if it comes back
	// as '0', then nothing happened, and we'll continue executing.
	//
	// -- Note you can choose not to call the parent if
	// you don't want to use any of those xml tags.
	// As I do below, in the case of OTAccount.
	//if (nReturnVal = OTContract::ProcessXMLNode(xml))
	//	return nReturnVal;
	
	if (!strcmp("signedFile", xml->getNodeName())) 
	{		
		m_strVersion			= xml->getAttributeValue("version");	
		
		m_strPurportedLocalDir	= xml->getAttributeValue("localDir");					
		m_strPurportedFilename	= xml->getAttributeValue("filename");					
		
		// ---------------------
				
		nReturnVal = 1;
	}
	
	else if (!strcmp("filePayload", xml->getNodeName())) 
	{
		// go to the next node and read the text.
		xml->read();
		
		if (EXN_TEXT == xml->getNodeType())
		{
			OTString strNodeData = xml->getNodeData();
			
			// Sometimes the XML reads up the data with a prepended newline.
			// This screws up my own objects which expect a consistent in/out
			// So I'm checking here for that prepended newline, and removing it.
			char cNewline;
			if (strNodeData.At(0, cNewline))
			{
				OTASCIIArmor ascNodeData;
				
				if ('\n' == cNewline)
				{
					ascNodeData.Set(strNodeData.Get() + 1);
					ascNodeData.GetString(m_strSignedFilePayload, true); // linebreaks = true
				}
				else
				{
					ascNodeData.Set(strNodeData.Get());
					ascNodeData.GetString(m_strSignedFilePayload, true); // linebreaks = true
				}
			}
		}
		else {
			fprintf(stderr, "Error in OTSignedFile::ProcessXMLNode: filePayload field without value.\n");
			return (-1); // error condition
		}
		
		return 1;
	}
	
	return nReturnVal;	
}
// return -1 if error, 0 if nothing, and 1 if the node was processed.
int32_t OTAccount::ProcessXMLNode(IrrXMLReader*& xml)
{
	int32_t nReturnVal = 0;

    const OTString strNodeName(xml->getNodeName());

	// Here we call the parent class first.
	// If the node is found there, or there is some error,
	// then we just return either way.  But if it comes back
	// as '0', then nothing happened, and we'll continue executing.
	//
	// -- Note you can choose not to call the parent if
	// you don't want to use any of those xml tags.
	// As I do below, in the case of OTAccount.
	//if (nReturnVal = OTTransactionType::ProcessXMLNode(xml))
	//	return nReturnVal;

	if (strNodeName.Compare("assetAccount"))
	{
		OTString strAcctType;

		m_strVersion	= xml->getAttributeValue("version");
		strAcctType		= xml->getAttributeValue("type");

		if (!strAcctType.Exists())
		{
			OTLog::Error("OTAccount::ProcessXMLNode: Failed: Empty assetAccount 'type' attribute.\n");
			return (-1);
		}

		m_AcctType = TranslateAccountTypeStringToEnum(strAcctType);

		if (OTAccount::err_acct == m_AcctType)
		{
			OTLog::Error("OTAccount::ProcessXMLNode: Failed: assetAccount 'type' attribute contains unknown value.\n");
			return (-1);
		}

		// -------------------------------------------------
        const OTString strAcctAssetType	= xml->getAttributeValue("assetTypeID");

        if (strAcctAssetType.Exists())
            m_AcctAssetTypeID.SetString(strAcctAssetType);
		// -------------------------------------------------

		OTString	strAccountID(xml->getAttributeValue("accountID")),
        strServerID(xml->getAttributeValue("serverID")),
        strAcctUserID(xml->getAttributeValue("userID"));

		OTIdentifier	ACCOUNT_ID(strAccountID),
                        SERVER_ID(strServerID),
                        USER_ID(strAcctUserID);

		SetPurportedAccountID(ACCOUNT_ID);
		SetPurportedServerID(SERVER_ID);
		SetUserID(USER_ID);

		OTString strAssetTypeID(m_AcctAssetTypeID);
		OTLog::vOutput(3,
                       //	"\n===> Loading XML for Account into memory structures..."
                       "\n\nAccount Type: %s\nAccountID: %s\nUserID: %s\n"
                       "AssetTypeID: %s\nServerID: %s\n",
                       strAcctType.Get(), strAccountID.Get(), strAcctUserID.Get(),
                       strAssetTypeID.Get(), strServerID.Get());

		nReturnVal = 1;
	}

	else if (strNodeName.Compare("inboxHash"))
	{
		// -------------------------------------------------
        const OTString strHash	= xml->getAttributeValue("value");
        if (strHash.Exists())
            m_InboxHash.SetString(strHash);
		// -------------------------------------------------
		OTLog::vOutput(3, "Account inboxHash: %s\n", strHash.Get());
		// -------------------------------------------------
		nReturnVal = 1;
	}

	else if (strNodeName.Compare("outboxHash"))
	{
		// -------------------------------------------------
        const OTString strHash	= xml->getAttributeValue("value");
        if (strHash.Exists())
            m_OutboxHash.SetString(strHash);
		// -------------------------------------------------
		OTLog::vOutput(3, "Account outboxHash: %s\n", strHash.Get());
		// -------------------------------------------------
		nReturnVal = 1;
	}

    else if (strNodeName.Compare("MARKED_FOR_DELETION"))
    {
        m_bMarkForDeletion = true;
        OTLog::vOutput(3, "This asset account has been MARKED_FOR_DELETION (at some point prior.)\n");

        nReturnVal = 1;
    }

    else if (strNodeName.Compare("balance"))
	{
		m_BalanceDate	= xml->getAttributeValue("date");
		m_BalanceAmount	= xml->getAttributeValue("amount");

		// I convert to integer / int64_t and back to string.
		// (Just an easy way to keep the data clean.)

		int32_t nDate		= atoi(m_BalanceDate.Get());
		int64_t lAmount	= atol(m_BalanceAmount.Get());

		m_BalanceDate.Format("%d", nDate);
		m_BalanceAmount.Format("%lld", lAmount);

//		OTLog::vOutput(1, "\nBALANCE  --  %s\n",
//					   m_BalanceAmount.Get());
		OTLog::vOutput(3, "\nBALANCE  --  %s\nDATE     --  %s\n",
					   m_BalanceAmount.Get(), m_BalanceDate.Get());

		nReturnVal = 1;
	}

    else if (strNodeName.Compare("stashinfo"))
	{
		if (!IsStashAcct())
		{
			OTLog::Error("OTAccount::ProcessXMLNode: Error: Encountered stashinfo tag while loading NON-STASH account. \n");
			return (-1);
		}
		// ------------------------------------------------------------------------
		int64_t lTransNum = 0;
		const OTString	strStashTransNum	= xml->getAttributeValue("cronItemNum");
		if (!strStashTransNum.Exists() || ((lTransNum = atol(strStashTransNum.Get())) <= 0))
		{
			m_lStashTransNum = 0;
			OTLog::vError("OTAccount::ProcessXMLNode: Error: Bad transaction number for supposed corresponding cron item: %lld \n",
						 lTransNum);
			return (-1);
		}
		else
			m_lStashTransNum = lTransNum;

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

		OTLog::vOutput(3, "\nSTASH INFO:   CronItemNum     --  %lld\n", m_lStashTransNum);

		nReturnVal = 1;
	}

	return nReturnVal;
}