Example #1
0
// This constructor gets the string version of the ID passed in,
// and sets that string on this object. (For when you need a string
// version of an ID.)
OTString::OTString(const OTIdentifier & theValue) : m_lLength(0), m_lPosition(0), m_strBuffer(NULL)
{
//	Initialize();

    if (theValue.GetSize() > 0)
        theValue.GetString(*this);
}
Example #2
0
// This constructor gets the string version of the ID passed in,
// and sets that string on this object. (For when you need a string
// version of an ID.)
OTString::OTString(const OTIdentifier & theValue)
{
	Initialize();
	
	if (theValue.GetSize() > 0)
		theValue.GetString(*this);
}
Example #3
0
bool OTToken::RecordTokenAsSpent(OTString & theCleartextToken)
{
	OTString strAssetID(GetAssetID());
		
	// ----------------------------------------------------------------------------
	
	// Calculate the filename (a hash of the Lucre cleartext token ID)
	OTIdentifier theTokenHash;
	theTokenHash.CalculateDigest(theCleartextToken);

	// Grab the new hash into a string (for use as a filename)
	OTString strTokenHash(theTokenHash);
		
	OTString strAssetFolder;
	strAssetFolder.Format("%s.%d", strAssetID.Get(), GetSeries());
	
	// --------------------------------------------------------------------
	// See if the spent token file ALREADY EXISTS...
	bool bTokenIsPresent = OTDB::Exists(OTLog::SpentFolder(), strAssetFolder.Get(), strTokenHash.Get());
	
	// If so, we're trying to record a token that was already recorded...
	if (bTokenIsPresent)
	{
		OTLog::vError("OTToken::RecordTokenAsSpent: Trying to record token as spent,"
					  " but it was already recorded: %s%s%s%s%s\n", 
					  OTLog::SpentFolder(), OTLog::PathSeparator(), strAssetFolder.Get(), 
					  OTLog::PathSeparator(), strTokenHash.Get());
		return false;
	}
	
	// ----------------------------------------------------------------------
	
	// FINISHED:
	
	// We actually save the token itself into the file, which is named based
	// on a hash of the Lucre data.
	// The success of that operation is also now the success of this one.
	
	OTString strToken;
	SaveContract(strToken);
	
	bool bSaved = OTDB::StorePlainString(strToken.Get(), OTLog::SpentFolder(), 
										 strAssetFolder.Get(), strTokenHash.Get());
	if (!bSaved)
	{
		OTLog::vError("OTToken::RecordTokenAsSpent: Error saving file: %s%s%s%s%s\n", 
					  OTLog::SpentFolder(), OTLog::PathSeparator(), strAssetFolder.Get(), 
					  OTLog::PathSeparator(), strTokenHash.Get());
	}
	
	return bSaved;
}
// So we can implement the SAMY hash, which is currently an XOR of SHA-256 with WHRLPOOL
//
// Originally, it was SHA512 and WHRLPOOL, which both have a 512-bit output-size.
// I was then going to cut the result in half and XOR together again. But then I 
// though, for now, instead of doing all that extra work, I'll just change the
// two "HashAlgorithms" from SHA512 and WHRLPOOL to SHA256 and WHIRLPOOL.
//
// This was very much easier, as I only had to change the little "512" to say 
// "256" instead, and basically the job was done. Of course, this means that OT
// is generating a 256-bit hash in THIS object, and a 512-bit WHIRLPOOL hash in
// the other object. i.e. There is still one 512-bit hash that you are forced to
// calculate, even if you throw away half of it after the calculation is done.
//
// Since the main object has a 256-bit hash, the XOR() function below was already
// coded to XOR the minimum length based on the smallest of the two objects.
// Therefore, it will XOR 256 bits of the WHRLPOOL output into the 256 bits of
// the main output (SHA256) and stop there: we now have a 256 bit ID. 
//
// The purpose here is to reduce the ID size so that it will work on Windows with
// the filenames. The current 512bit output is 64 bytes, or 128 characters when
// exported to a hex string (in all the OT contracts for example, over and over 
// again.)
//
// The new size will be 256bit, which is 32 bytes of binary. In hex string that
// would be 64 characters. But we're also converting from Hex to Base62, which
// means we'll get it down to around 43 characters.
//
// This means our IDs are going to go from this:
//
//
// To this:
//
//
// You might ask: is 256 bits big enough of a hash size to be safe from collisions?
// Practically speaking, I believe so.  The IDs are used for accounts, servers, asset types,
// and users. How many different asset types do you expect there will be, where changing the
// contract to anything still intelligible would result in a still-valid signature? To find
// a collision in a contract, where the signature would still work, would you expect the necessary
// changed plaintext to be something that would still make sense in the contract? Would such
// a random piece of data turn out to form proper XML?
//
// 256bits is enough to store the number of atoms in the Universe. If we ever need a bigger
// hashsize, just go change the HashAlgorithm1 back to "SHA512" instead of "SHA256", and you'll
// instantly have a doubled hash output size  :-)
//
bool OTIdentifier::XOR(const OTIdentifier & theInput)
{
	// Go with the smallest of the two
	const int64_t lSize = (GetSize() > theInput.GetSize() ? theInput.GetSize() : GetSize());
	
	for (int32_t i = 0; i < lSize; i++)
	{
		// When converting to BigInteger internally, this will be a bit more efficient.
		((char*)GetPointer())[i] ^= ((char*)theInput.GetPointer())[i]; // todo cast
	}
	
	return true;
}
Example #5
0
bool OTPayment::GetSenderAcctID(OTIdentifier & theOutput) const
{
    theOutput.Release();
    // ----------------------
    if (!m_bAreTempValuesSet)
        return false;
    
    bool bSuccess = false;
    
    switch (m_Type) 
    {
        case OTPayment::CHEQUE:
        case OTPayment::VOUCHER:
        case OTPayment::INVOICE:
        case OTPayment::PAYMENT_PLAN:
            theOutput = m_SenderAcctID;
            bSuccess  = true;
            break;
            
        case OTPayment::SMART_CONTRACT:
        case OTPayment::PURSE:
            bSuccess  = false;
            break;
            
        default:
            OTLog::Error("OTPayment::GetSenderAcctID: Bad payment type!\n");
            break;
    }
    
    return bSuccess;
}
bool  OTAccount::GetOutboxHash(OTIdentifier & theOutput)
{
    theOutput.Release();

    if (!m_OutboxHash.IsEmpty())
    {
        theOutput = m_OutboxHash;
        return true;
    }
    else if (!GetUserID().IsEmpty() &&
             !GetRealAccountID().IsEmpty() &&
             !GetRealServerID().IsEmpty()
             )
    {
        OTLedger theOutbox(GetUserID(), GetRealAccountID(), GetRealServerID());

        if (theOutbox.LoadOutbox() && theOutbox.CalculateOutboxHash(theOutput))
        {
            SetOutboxHash(theOutput);
            return true;
        }
    }

    return false;
}
bool OTPurse::GetNymID(OTIdentifier & theOutput) const
{
    bool bSuccess = false;
    theOutput.Release();
    // --------------------------------------
    if (this->IsNymIDIncluded() && !m_UserID.IsEmpty())
    {
        bSuccess = true;
        theOutput = m_UserID;
    }
    // --------------------------------------
    else if (this->IsUsingATempNym() && (NULL != m_pTempNym))
    {
        bSuccess  = true;
        m_pTempNym->GetIdentifier(theOutput);
    }
    // --------------------------------------
    else if (!m_UserID.IsEmpty())
    {
        bSuccess  = true;
        theOutput = m_UserID;
    }
    // --------------------------------------
    return bSuccess;
}
Example #8
0
// Note: ALL failures will return true, even if the token has NOT already been
// spent, and the failure was actually due to a directory creation error. Why,
// you might ask? Because no matter WHAT is causing the failure, any return of
// false is a signal that the token is SAFE TO ACCEPT AS TENDER. If there was a
// temporary file system error, someone could suddenly deposit the same token
// over and over again and this method would return "false" (Token is "not already
// spent.")
//
// We simply cannot risk that, so false is not returned unless execution reaches
// the very bottom of this method. Every other error acts as if the token is
// no good, for security reasons. If the token really IS good, the user can submit
// it again later and it will work.
//
bool OTToken::IsTokenAlreadySpent(OTString & theCleartextToken)
{
	OTString strAssetID(GetAssetID());
	
	// ----------------------------------------------------------------------------	
	
	// Calculate the filename (a hash of the Lucre cleartext token ID)
	OTIdentifier theTokenHash;
	theTokenHash.CalculateDigest(theCleartextToken);
	
	// Grab the new hash into a string (for use as a filename)
	OTString strTokenHash(theTokenHash);
	
	// ----------------------------------------------------------------------------	
	
	OTString strAssetFolder;
	strAssetFolder.Format("%s.%d", strAssetID.Get(), GetSeries());
	
	bool bTokenIsPresent = OTDB::Exists(OTLog::SpentFolder(), strAssetFolder.Get(), strTokenHash.Get());

	// --------------------------------------------------------------------
	
	if (bTokenIsPresent)
	{
		OTLog::vOutput(0, "\nOTToken::IsTokenAlreadySpent: Token was already spent: %s%s%s%s%s\n", 
					   OTLog::SpentFolder(), OTLog::PathSeparator(), strAssetFolder.Get(), 
					   OTLog::PathSeparator(), strTokenHash.Get());
		return true;	// all errors must return true in this function.
						// But this is not an error. Token really WAS already
	}					// spent, and this true is for real. The others are just
						// for security reasons because of this one.
	
	// This is the ideal case: the token was NOT already spent, it was good,
	// so we can return false and the depositor can be credited appropriately.
	// IsTokenAlreadySpent?  NO-it was NOT already spent. You can only POSSIBLY
	// get a false out of this method if you actually reached the bottom (here.)
	return false;
}
// This method implements the SAMY hash
bool OTIdentifier::CalculateDigest(const OTData & dataInput)
{
//#ifndef ANDROID // SHA256 on Android; no whirlpool until OpenSSL 1.0.0 is added.
	OTIdentifier idSecondHash;
	
	if (idSecondHash.CalculateDigest(dataInput, HashAlgorithm2) &&
		CalculateDigest(dataInput, HashAlgorithm1))
	{
		// At this point, we have successfully generated the WHRLPOOL hash in 
		// idSecondHash, and we've successfully generated the SHA-256 hash in 
		// this object.
		// Next we XOR them together for the final product.
		return XOR(idSecondHash);
	}
//#else // ANDROID
//	if (CalculateDigest(dataInput, HashAlgorithm1)) // SHA256 only until I add the new OpenSSL 1.0 for Android
//	{
//		return true;
//	}	
//#endif // ANDROID
	
	return false;
}
// This method implements the SAMY hash
bool OTIdentifier::CalculateDigest(const OTString & strInput)
{
#ifndef ANDROID // If NOT Android...
	OTIdentifier idSecondHash;
	
	if (idSecondHash.CalculateDigest(strInput, HashAlgorithm2) &&
		CalculateDigest(strInput, HashAlgorithm1))
	{
		// At this point, we have successfully generated the WHRLPOOL hash in 
		// idSecondHash, and we've successfully generated the SHA-256 hash in 
		// this object.
		// Next we XOR them together for the final product.
		return XOR(idSecondHash);
	}
#else // SHA256 on Android; no whirlpool until OpenSSL 1.0.0 is added.
	if (CalculateDigest(strInput, HashAlgorithm1))
	{
		return true;
	}	
#endif // ANDROID
	
	return false;
}
Example #11
0
// Most contracts calculate their ID by hashing the Raw File (signatures and all).
// The Basket only hashes the unsigned contents, and only with the account IDs removed.
// This way, the basket will produce a consistent ID across multiple different servers.
void OTBasket::CalculateContractID(OTIdentifier & newID)
{
	const OTString strContents(m_xmlUnsigned);
	
	// Produce a version of the file without account IDs (which are different from server to server.)
	//
	m_bHideAccountID	= true;
	
	UpdateContents();  // <=========
	
	newID.CalculateDigest(m_xmlUnsigned);

	// Put it back the way it was.
	m_bHideAccountID	= false;
//	UpdateContents(); // No need to do this, we already had this string before (above).
	m_xmlUnsigned = strContents; // Here we just set it back again.
}
Example #12
0
bool OTPayment::GetRecipientAcctID(OTIdentifier & theOutput) const
{
    // NOTE:
    // A cheque HAS NO "Recipient Asset Acct ID", since the recipient's account (where he deposits
    // the cheque) is not known UNTIL the time of the deposit. It's certain not known at the time 
    // that the cheque is written...

    theOutput.Release();
    // ----------------------
    if (!m_bAreTempValuesSet)
        return false;
    
    bool bSuccess = false;
    
    switch (m_Type) 
    {
        case OTPayment::PAYMENT_PLAN:
            if (m_bHasRecipient)
            {
                theOutput = m_RecipientAcctID;
                bSuccess  = true;
            }
            else
                bSuccess  = false;
            
            break;
            
        case OTPayment::CHEQUE:
        case OTPayment::VOUCHER:
        case OTPayment::INVOICE:
        case OTPayment::SMART_CONTRACT:
        case OTPayment::PURSE:  // A purse might have a recipient USER, but never a recipient ACCOUNT.
            bSuccess  = false;
            break;
            
        default:
            OTLog::Error("OTPayment::GetRecipientAcctID: Bad payment type!\n");
            break;
    }
    
    return bSuccess;
}
Example #13
0
// With a voucher (cashier's cheque) the "bank" is the "sender",
// whereas the actual Nym who purchased it is the "remitter."
//
bool OTPayment::GetRemitterUserID(OTIdentifier & theOutput) const
{
    theOutput.Release();
    // ----------------------
    if (!m_bAreTempValuesSet)
        return false;
    
    bool bSuccess = false;
    
    switch (m_Type)
    {
        case OTPayment::VOUCHER:
            theOutput = m_RemitterUserID;
            bSuccess  = true;
            break;
            
        default:
            OTLog::Error("OTPayment::GetRemitterUserID: Bad payment type! Expected a voucher cheque.\n");
            break;
    }
    
    return bSuccess;
}
Example #14
0
bool operator<(const OTIdentifier& lhs, const OTIdentifier& rhs)
{
    return lhs.get() < rhs.get();
}
Example #15
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 #16
0
bool operator!=(const OTIdentifier& lhs, const Identifier& rhs)
{
    return lhs.get() != rhs;
}
Example #17
0
_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;
}
Example #18
0
// The above method uses this one internally...
bool OTAccount::GenerateNewAccount(const OTPseudonym & theServer, const OTMessage & theMessage,
								   const OTAccount::AccountType eAcctType/*=OTAccount::simple*/)
{
	// First we generate a secure random number into a binary object.
	OTPayload thePayload;
	thePayload.SetPayloadSize(100);
	if (!RAND_bytes((unsigned char*)thePayload.GetPayloadPointer(), 100)) 
	{
		OTLog::Error("The PRNG is not seeded!\n");
//		abort(  );
		return false;	
	}
	
	// Next we calculate that binary object into a message digest (an OTIdentifier).
	OTIdentifier newID;
	if (!newID.CalculateDigest(thePayload))
	{
		OTLog::Error("Error generating new account ID.\n");
		return false;	
	}		
	
	// Next we get that digest (which is a binary hash number)
	// and extract a human-readable standard string format of that hash,
	// into an OTString.
	OTString strID(newID);
	
	SetRealAccountID(newID);		// Set the account number based on what we just generated.
	SetPurportedAccountID(newID);	// Might as well set them both. (Safe here to do so, for once.)

	m_strName.Set(strID); // So it's not blank. The user can always change it.
	
	// Next we create the full path filename for the account using the ID.
	m_strFilename.Format("%s%s%s%s%s", OTLog::Path(), OTLog::PathSeparator(),
						 OTLog::AccountFolder(),
						 OTLog::PathSeparator(), strID.Get());
	
	// Then we try to load it, in order to make sure that it doesn't already exist.
	if (LoadContractRawFile())
	{
		OTLog::Error("Error generating new account ID, account already exists.\n");
		return false;	
	}

	// Set up the various important starting values of the account.
	m_AcctType = eAcctType; // account type defaults to OTAccount::simple. But there are also issuer accts...
	
	// for basket accounts, the server is the user.
	if (OTAccount::basket == eAcctType)
	{
		theServer.GetIdentifier(m_AcctUserID);
	}
	else 
	{
		m_AcctUserID.SetString(theMessage.m_strNymID);
	}

	m_AcctAssetTypeID.SetString(theMessage.m_strAssetID);
	
	OTString TEMPstr(m_AcctAssetTypeID);

	OTLog::vOutput(3, "Creating new account, type:\n%s\nChanged to ID then back to string:\n%s\n", 
				   theMessage.m_strAssetID.Get(), TEMPstr.Get());
	
	OTIdentifier SERVER_ID(theMessage.m_strServerID);	
	SetRealServerID(SERVER_ID);			// todo this assumes the serverID on the message is correct. It's vetted, but still...
	SetPurportedServerID(SERVER_ID);

	const time_t tDate = time(NULL); // Today, now.
	m_BalanceDate.Format("%d", tDate);
		
	m_BalanceAmount.Set("0");
	
		
	// Sign the Account (so we know that we did)... Otherwise someone could put a fake
	// account file on the server if the code wasn't designed to verify the signature on the
	// account.
	SignContract(theServer);		
	SaveContract();		
	
	// Save the Account to storage (based on its ID.)
	SaveAccount();

	// Don't know why I had this here. Putting SaveAccount() instead.
//	OTString strFilename(m_strFilename);
//	SaveContract(strFilename.Get()); // Saves the account to a specific filename
	
	// No need to create the inbox and outbox ledgers...they will be created automatically
	// if they do not exist when they are needed.
	
	return true;
}
// The above method uses this one internally...
bool OTAccount::GenerateNewAccount(const OTPseudonym & theServer, const OTMessage & theMessage,
								   const OTAccount::AccountType eAcctType/*=OTAccount::simple*/,
								   int64_t lStashTransNum/*=0*/)
{
    const char *szFunc = "OTAccount::GenerateNewAccount";
    // -----------------------------------------------
	// First we generate a secure random number into a binary object...
    //
    OTPayload thePayload;

    if (false == thePayload.Randomize(100)) // todo hardcoding. Plus: is 100 bytes of random a little much here?
    {
		OTLog::vError("%s: Failed trying to acquire random numbers.\n", szFunc);
		return false;
    }
	// --------------------------------------------------
    //
	// Next we calculate that binary object into a message digest (an OTIdentifier).
    //
	OTIdentifier newID;
	if (!newID.CalculateDigest(thePayload))
	{
		OTLog::vError("%s: Error generating new account ID.\n", szFunc);
		return false;
	}
    // --------------------------------------------------
    //
	// Next we get that digest (which is a binary hash number)
	// and extract a human-readable standard string format of that hash,
	// into an OTString.
    //
	OTString strID(newID);

	SetRealAccountID(newID);		// Set the account number based on what we just generated.
	SetPurportedAccountID(newID);	// Might as well set them both. (Safe here to do so, for once.)

	m_strName.Set(strID); // So it's not blank. The user can always change it.

	// Next we create the full path filename for the account using the ID.
    //
	m_strFoldername = OTFolders::Account().Get();
	m_strFilename = strID.Get();

	// Then we try to load it, in order to make sure that it doesn't already exist.
	// --------------------------------------------------------------------

	if (OTDB::Exists(m_strFoldername.Get(), m_strFilename.Get()))
	{
		OTLog::vError("%s: Account already exists: %s\n", szFunc,
					  m_strFilename.Get());
		return false;
	}

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

	// Set up the various important starting values of the account.
	m_AcctType = eAcctType; // account type defaults to OTAccount::simple. But there are also issuer accts...

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

	if (IsInternalServerAcct())  // basket, basketsub, mint, voucher, and stash accounts are all "owned" by the server.
	{
		theServer.GetIdentifier(m_AcctUserID);
	}
	else
	{
		m_AcctUserID.SetString(theMessage.m_strNymID);
	}

	// --------------------------------------------------------------------
	m_AcctAssetTypeID.SetString(theMessage.m_strAssetID);

	OTLog::vOutput(3, "%s: Creating new account, type:\n%s\n", szFunc,
				   theMessage.m_strAssetID.Get());

	OTIdentifier SERVER_ID(theMessage.m_strServerID);
	SetRealServerID(SERVER_ID);			// todo this assumes the serverID on the message is correct. It's vetted, but still...
	SetPurportedServerID(SERVER_ID);

	const time64_t tDate = OTTimeGetCurrentTime(); // Today, now.
	m_BalanceDate.Format("%d", tDate);

	m_BalanceAmount.Set("0");

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

	if (IsStashAcct())
	{
		OT_ASSERT_MSG(lStashTransNum > 0,
					  "You created a stash account, but with a zero-or-negative transaction number for its cron item.");
		m_lStashTransNum	= lStashTransNum;
	}

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

	// Sign the Account (so we know that we did)... Otherwise someone could put a fake
	// account file on the server if the code wasn't designed to verify the signature on the
	// account.
	SignContract(theServer);
	SaveContract();

	// Save the Account to storage (based on its ID.)
	SaveAccount();

	// Don't know why I had this here. Putting SaveAccount() instead.
//	OTString strFilename(m_strFilename);
//	SaveContract(strFilename.Get()); // Saves the account to a specific filename

	// No need to create the inbox and outbox ledgers...they will be created automatically
	// if they do not exist when they are needed.

	return true;
}