// Message retrieved from Payload
bool OTPayload::GetMessage(OTMessage & theMessage) const
{
	// validate checksum
	uint32_t lSize	= GetSize();
	uint32_t lIndex	= lSize-2; // the index to where the NULL terminator SHOULD be if they
						  // sent us a string like they were supposed to. (A contract.)
						  // (nSize-1 would be the location of the checksum at the end.)
	if (0 == lSize)
		return false;
	
	if (IsChecksumValid((OT_BYTE*)GetPointer(), (uint32_t)lSize))
	{
		// We add the null-terminator ourselves at this point, for security reasons,
		// since we will process the data, after this point, as a string.
		((OT_BYTE *)GetPointer())[lIndex] = 0;
		
		theMessage.Release();
		
		// Why is this safe, where I cast the Payload data pointer as
		// a char * and tell the string to set itself from that?
		// Because (1) I just validated the checksum, and
		// (2) There place where the NULL should be, I set to 0, by hand,
		// just above 2 lines. So when this set operation occurs, the
		// farthest it will go is to that 0.
		theMessage.m_strRawFile.Set((const char *)GetPointer());
		return true;
	}
	else {
		OTLog::Error("Invalid Checksum in OTPayload::GetMessage\n");
		return false;
	}
}
// 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;
}
// OTMessageOutbuffer deletes the OTMessage when you call this.
//
bool OTMessageOutbuffer::RemoveSentMessage(const int64_t & lRequestNum, const OTString & strServerID, const OTString & strNymID)
{
    OTString strFolder, strFile;
    strFolder.Format("%s%s%s%s%s%s%s",
                     OTFolders::Nym().Get(),         OTLog::PathSeparator(),
                     strServerID.Get(),          OTLog::PathSeparator(),
                     "sent", /*todo hardcoding*/ OTLog::PathSeparator(),
                     strNymID.Get());
    strFile.Format("%lld.msg", lRequestNum);
    // ------------------------------------------------
    mapOfMessages::iterator it = m_mapMessages.begin();
    
    bool bReturnValue = false;
    
    while (it != m_mapMessages.end())
    {
        // -----------------------------
        const int64_t  & lTempReqNum   = it->first;
        // -----------------------
        if (lTempReqNum != lRequestNum)
        {
            ++it;
            continue;
        }
        // -----------------------
        OTMessage   * pMsg          = it->second;
        OT_ASSERT(NULL != pMsg);
        // -----------------------------
        //
        // If a server ID was passed in, but doesn't match the server ID on this message,
        // Then skip this one. (Same with the NymID.)
        if (!strServerID.Compare(pMsg->m_strServerID) ||
            !strNymID.   Compare(pMsg->m_strNymID))
        {
            ++it;
            continue;
        }
        // --------
        else
        {
            delete pMsg; pMsg = NULL;
            // ----------------------
            mapOfMessages::iterator temp_it = it;
            ++temp_it;
            m_mapMessages.erase(it);
            it = temp_it; // here's where it gets incremented. (During the erase, basically.)
            // ----------------------
            bReturnValue = true;
            break;
        }
    }
    // ----------------------------------
    // Whether we found it in RAM or not, let's make sure to delete it from
    // local storage, if it's there... (Since there's a list there we have to update,
    // anyway.)
    // We keep a list of the request numbers, so let's load it up, remove the number
    // from that list, and then save it again.
    // ----------------------------------
    OTNumList theNumList;
    std::string str_data_filename("sent.dat");  // todo hardcoding.
    if (OTDB::Exists(strFolder.Get(), str_data_filename))
    {
        OTString strNumList(OTDB::QueryPlainString(strFolder.Get(), str_data_filename));
        if (strNumList.Exists())
            theNumList.Add(strNumList);
        theNumList.Remove(lRequestNum);
    }
    else // it doesn't exist on disk, so let's just create it from the list we have in RAM so we can store it to disk.
    {
        it = m_mapMessages.begin();
        while (it != m_mapMessages.end())
        {
            // -----------------------------
            const int64_t  & lTempReqNum   = it->first;
            // -----------------------
            OTMessage   * pMsg          = it->second;
            OT_ASSERT(NULL != pMsg);
            // -----------------------------
            //
            // If a server ID was passed in, but doesn't match the server ID on this message,
            // Then skip this one. (Same with the NymID.)
            //
            if (!strServerID.Compare(pMsg->m_strServerID) ||
                !strNymID.   Compare(pMsg->m_strNymID))
            {
                ++it;
                continue;
            }
            // --------
            else
            {
                theNumList.Add(lTempReqNum);
            }
            ++it;
        }
    }// else
    // ----------------------------------
    // By this point, theNumList has either been loaded from local storage and had the number removed,
    // or it wasn't in local storage and thus we created it and added all the numbers to it from RAM (not
    // including the one being erased, since it was already removed from the RAM list, above.) So either
    // way, the number being removed is now ABSENT from theNumList.
    //
    // Therefore nothing left to do here, but save it back again!
    //
    OTString strOutput;
    theNumList.Output(strOutput);
    if (!OTDB::StorePlainString(strOutput.Get(), strFolder.Get(), str_data_filename))
    {
        OTLog::Error("OTMessageOutbuffer::RemoveSentMessage: Error: failed writing list of request numbers to storage.\n");
    }
    // ----------------------------------
    // Now that we've updated the numlist in local storage, let's
    // erase the sent message itself...
    //
    OTMessage * pMsg = new OTMessage;
    OT_ASSERT(NULL != pMsg);
    OTCleanup<OTMessage> theMsgAngel(pMsg);
    
    if (OTDB::Exists(strFolder.Get(), strFile.Get()) && pMsg->LoadContract(strFolder.Get(), strFile.Get()))
    {
        OTDB::EraseValueByKey(strFolder.Get(), strFile.Get());
        return true;
    }
    // ----------------------------------
	return bReturnValue;
}
// WARNING: ONLY call this (with arguments) directly after a successful @getNymbox has been received!
// See comments below for more details.
//
void OTMessageOutbuffer::Clear(const OTString * pstrServerID/*=NULL*/, const OTString * pstrNymID/*=NULL*/, OTPseudonym * pNym/*=NULL*/,
                               const bool     * pbHarvestingForRetry/*=NULL*/)
{
//  const char * szFuncName		= "OTMessageOutbuffer::Clear";
    // -----------------------------------------------
    
    mapOfMessages::iterator it = m_mapMessages.begin();
    
    while (it != m_mapMessages.end())
    {
        // -----------------------------
        const int64_t  & lRequestNum   = it->first;
        OTMessage   * pThisMsg      = it->second;
        OT_ASSERT(NULL != pThisMsg);
        // -----------------------------
        //
        // If a server ID was passed in, but doesn't match the server ID on this message,
        // Then skip this one. (Same with the NymID.)
        if (
            ((NULL != pstrServerID) && !pstrServerID->Compare(pThisMsg->m_strServerID)) ||
            ((NULL != pstrNymID)    && !pstrNymID->Compare   (pThisMsg->m_strNymID))
            )
        {
            ++it;
            continue;
        }
        // --------
        else
        {
            /*
             Sent messages are cached because some of them are so important, that
             the server drops a reply notice into the Nymbox to make sure they were
             received. This way, when we download the Nymbox we can SEE which messages
             were ACTUALLY replied to, and at that time, we removed those messages
             already from *this "sent buffer." After that loop was done, we called
             CLEAR (this function) and cleared ALL the sent messages from the buffer
             (for the appropriate server and nym IDs...clear without those IDs is
             only for the destructor.)
             
             This Clear, where we are now, HARVESTS the transaction numbers back
             from any messages left in the sent buffer. We are able to do this with
             confidence because we know that this function is only called in @getNymbox
             on client side, and only after the ones with actual replies (as evidenced
             by the Nymbox) have already been removed from *this "sent buffer."
             
             Why were they removed in advance? Because clearly: if the server HAS replied
             to them already, then there's no need to harvest anything: just let it
             process as normal, whether the transaction inside is a success or fail.
             (We KNOW the message didn't fail because otherwise there wouldn't even be
             a notice in the Nymbox. So this is about the transaction inside.)

             So we remove the ones that we DEFINITELY know the server HAS replied to.
             
             And the ones remaining? We know for those, the server definitely has NOT
             replied to them (the message must have been dropped by the network or
             something.) How do we know this? Because there would be a notice in the
             Nymbox! So at the moment of successful @getNymbox, we are able to loop through
             those receipts and know FOR SURE, WHICH ones definitely have a reply, and
             which ones definitely DO NOT.
             
             The ones where we definitely do NOT have a reply--that is, the ones that are in
             the "sent messages" buffer, but are not in the Nymbox with the same request
             number--we harvest those numbers, since the server clearly never saw them, or
             rejected the message before the transaction itself even had a chance to run.
             
             */
            if (NULL != pNym)
            {
                OT_ASSERT(NULL != pstrNymID && pstrNymID->Exists());
                const OTIdentifier MSG_NYM_ID(*pstrNymID);
                OT_ASSERT(pNym->CompareID(MSG_NYM_ID));
                // ----------------------------
                OT_ASSERT(NULL != pstrServerID && pstrServerID->Exists());
                // ----------------------------
                OT_ASSERT(NULL != pbHarvestingForRetry);
                // ----------------------------
                /*
                 getNymbox			-- client is NOT sending hash, server is NOT rejecting bad hashes, server IS SENDING HASH in the @getNymbox reply
                 getRequest			-- client is NOT sending hash, server is NOT rejecting bad hashes, server IS SENDING HASH in the @getRequest reply
                 
                 processNymbox		-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @processNymbox  reply
                 notarizeTransactions	-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @notarizeTransactions  reply
                 processInbox 		-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @processInbox  reply
                 triggerClause 		-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @triggerClause reply
                 
                 getTransactionNum 	-- client is SENDING HASH, server is REJECTING BAD HASHES, server is SENDING HASH in the @getTransactionNum reply
                 
                 Already covered in NotarizeTransaction: 
                    transfer, withdrawal, deposit, marketOffer, paymentPlan, smartContract, cancelCronItem, exchangeBasket
                 */
                
                if (pThisMsg->m_ascPayload.Exists() &&
                    (
                     pThisMsg->m_strCommand.Compare("processNymbox")        ||
                     pThisMsg->m_strCommand.Compare("processInbox")         ||
                     pThisMsg->m_strCommand.Compare("notarizeTransactions") ||
                     pThisMsg->m_strCommand.Compare("triggerClause")
                    )
                   )
                {
                    // 
                    // If we are here in the first place (i.e. after @getNymbox just removed
                    // all the messages in this sent buffer that already had a reply sitting
                    // in the nymbox) therefore we KNOW any messages in here never got a reply
                    // from the server, 
                    
                    const bool bReplyWasSuccess        = false; // If the msg had been a success, the reply (whether transaction within succeeded or failed) would have been dropped into my Nymbox, and thus removed from this "sent buffer" in @getNymbox.
                    const bool bReplyWasFailure        = true; // If the msg had been an explicit failure, the reply (without the transaction inside of it even having a chance to succeed or fail) would definitely NOT have been dropped into my Nymbox, and thus removed from this "sent buffer" in @getNymbox. However, IN THIS ONE CASE, since we DID just download the Nymbox and verify there ARE NO REPLIES for this request number (before calling this function), and since a dropped message is basically identical to a rejected message, since in either case, the transaction itself never even had a chance to run, we are able to now harvest the message AS IF the server HAD explicitly rejected the message. This is why I pass true here, where anywhere else in the code I would always pass false unless I had explicitly received a failure from the server. This place in the code, where we are now, is the failsafe endpoint for missed/dropped messages! IF they STILL haven't been found by this point, they are cleaned up as if the message was explicitly rejected by the server before the transaction even had a chance to run.

                    const bool bTransactionWasSuccess  = false; // Per above, since "the transaction never had a chance to run" then it could NOT have been an explicit success.
                    const bool bTransactionWasFailure  = false; // Per above, since "the transaction never had a chance to run" then it could NOT have been an explicit failure.
                    // -----------------------------------------------------
                    pThisMsg->HarvestTransactionNumbers(*pNym,      // Actually it's pNym who is "harvesting" the numbers in this call.   <========= HARVEST
                                                        *pbHarvestingForRetry,
                                                        bReplyWasSuccess,
                                                        bReplyWasFailure,
                                                        bTransactionWasSuccess,
                                                        bTransactionWasFailure);
                } // if there's a transaction to be harvested inside this message.
            } // if pNym !NULL
            // ----------------------
            mapOfMessages::iterator temp_it = it;
            ++temp_it;
            m_mapMessages.erase(it);
            it = temp_it; // here's where the iterator gets incremented (during the erase, basically.)
            // ----------------------
            delete pThisMsg;                // <============ DELETE
            pThisMsg = NULL;
            // ---------------------------------------------------------------------------
            if (NULL != pstrNymID && NULL != pstrServerID)
            {
                OTString strFolder, strFile;
                strFolder.Format("%s%s%s%s%s%s%s",
                                 OTFolders::Nym().Get(),     OTLog::PathSeparator(),
                                 pstrServerID->Get(),        OTLog::PathSeparator(),
                                 "sent", /*todo hardcoding*/ OTLog::PathSeparator(),
                                 pstrNymID->Get());
                strFile.Format("%lld.msg", lRequestNum);
                // ---------------------------------------------------------------------------
                OTNumList theNumList;
                std::string str_data_filename("sent.dat");  // todo hardcoding.
                if (OTDB::Exists(strFolder.Get(), str_data_filename))
                {
                    OTString strNumList(OTDB::QueryPlainString(strFolder.Get(), str_data_filename));
                    if (strNumList.Exists())
                        theNumList.Add(strNumList);
                    theNumList.Remove(lRequestNum); // Clear (this function) loops and removes them. (Here's the one being removed this iteration.)
                }
                else // it doesn't exist on disk, so let's just create it from the list we have in RAM so we can store it to disk.
                {    // NOTE: this may be unnecessary since we are "clear"ing them all anyway. But that just means we can remove this
                     // block during optimization. Todo optimize.
                     // Since we create the NumList based on m_mapMessages, and since the message for this iteration was already removed
                     // above, we don't need to remove anything at this point, we just create the NumList to contain the same numbers as are
                     // in m_mapMessages.
                     //
                    it = m_mapMessages.begin();
                    while (it != m_mapMessages.end())
                    {
                        // -----------------------------
                        const int64_t  & lTempReqNum   = it->first;
                        // -----------------------
                        OTMessage   * pMsg          = it->second;
                        OT_ASSERT(NULL != pMsg);
                        // -----------------------------
                        //
                        // If a server ID was passed in, but doesn't match the server ID on this message,
                        // Then skip this one. (Same with the NymID.)
                        //
                        if (!pstrServerID->Compare(pMsg->m_strServerID) ||
                            !pstrNymID->   Compare(pMsg->m_strNymID))
                        {
                            ++it;
                            continue;
                        }
                        // --------
                        else
                        {
                            theNumList.Add(lTempReqNum);
                        }
                        ++it;
                    }
                }// else
                // ----------------------------------
                // By this point, theNumList has either been loaded from local storage and had the number removed,
                // or it wasn't in local storage and thus we created it and added all the numbers to it from RAM (not
                // including the one being erased, since it was already removed from the RAM list, above.) So either
                // way, the number being removed is now ABSENT from theNumList.
                //
                // Therefore nothing left to do here, but save it back again!
                //
                OTString strOutput;
                theNumList.Output(strOutput);
                if (!OTDB::StorePlainString(strOutput.Get(), strFolder.Get(), str_data_filename)) // todo hardcoding.
                {
                    OTLog::Error("OTMessageOutbuffer::Clear: Error: failed writing list of request numbers to storage.\n");
                }
                // ----------------------------------
                // Make sure any messages being erased here, are also erased from local storage.
                // Now that we've updated the numlist in local storage, let's
                // erase the sent message itself...
                //
                OTMessage * pMsg = new OTMessage;
                OT_ASSERT(NULL != pMsg);
                OTCleanup<OTMessage> theMsgAngel(pMsg);
                
                if (OTDB::Exists(strFolder.Get(), strFile.Get()) && pMsg->LoadContract(strFolder.Get(), strFile.Get()))
                {
                    OTDB::EraseValueByKey(strFolder.Get(), strFile.Get());
                }
            }
            // ---------------------------------------------------------------------------
        }
    }
}
OTMessage * OTMessageOutbuffer::GetSentMessage(const int64_t & lRequestNum, const OTString & strServerID, const OTString & strNymID)
{
    mapOfMessages::iterator it = m_mapMessages.begin();
    
    for ( ; it != m_mapMessages.end(); ++it)
    {
        // -----------------------------
        const int64_t  & lTempReqNum   = it->first;
        // -----------------------
        if (lTempReqNum != lRequestNum)
        {
            continue;
        }
        // -----------------------
        OTMessage   * pMsg          = it->second;
        OT_ASSERT(NULL != pMsg);
        // -----------------------------
        //
        // If a server ID was passed in, but doesn't match the server ID on this message,
        // Then skip this one. (Same with the NymID.)
        if (!strServerID.Compare(pMsg->m_strServerID) ||
            !strNymID.   Compare(pMsg->m_strNymID))
        {
            continue;
        }
        // --------
        else
        {
            return pMsg;
        }
    }
    // ----------------------------------
    // Didn't find it? Okay let's load it from local storage, if it's there...
    //
    OTString strFolder, strFile;
    strFolder.Format("%s%s%s%s%s%s%s",
                     OTFolders::Nym().Get(),         OTLog::PathSeparator(),
                     strServerID.Get(),          OTLog::PathSeparator(),
                     "sent", /*todo hardcoding*/ OTLog::PathSeparator(),
                     strNymID.Get());
    strFile.Format("%lld.msg", lRequestNum);
    // -----------------------------------
    // Check the existing list, if it exists.
    //
    OTNumList theNumList;
    std::string str_data_filename("sent.dat");
    if (OTDB::Exists(strFolder.Get(), str_data_filename)) // todo hardcoding.
    {
        OTString strNumList(OTDB::QueryPlainString(strFolder.Get(), str_data_filename));
        
        if (strNumList.Exists())
            theNumList.Add(strNumList);
        
        if (theNumList.Verify(lRequestNum))
        {
            // Even if the outgoing message was stored, we still act like it
            // "doesn't exist" if it doesn't appear on the official list.
            // The list is what matters -- the message is just the contents referenced
            // by that list.
            // -----------------------------------
            OTMessage * pMsg = new OTMessage;
            OT_ASSERT(NULL != pMsg);
            OTCleanup<OTMessage> theMsgAngel(pMsg);
            
            if (OTDB::Exists(strFolder.Get(), strFile.Get()) && pMsg->LoadContract(strFolder.Get(), strFile.Get()))
            {
                // Since we had to load it from local storage, let's add it to
                // the list in RAM.
                //
                m_mapMessages.insert(std::pair<int64_t, OTMessage *>(lRequestNum, pMsg));
                theMsgAngel.SetCleanupTargetPointer(NULL);
                return pMsg;
            }
            // ----------------------------------
        }
    }
    // ----------------------------------
    // STILL didn't find it? (Failure.)
    //
	return NULL;
}
void OTMessageOutbuffer::AddSentMessage(OTMessage & theMessage) // must be heap allocated.
{
    int64_t lRequestNum = 0;
    
    if (theMessage.m_strRequestNum.Exists())
        lRequestNum = atol(theMessage.m_strRequestNum.Get()); // The map index is the request number on the message itself.
    // ----------------
    // It's technically possible to have TWO messages (from two different
    // servers) that happen to have the same request number. So we verify
    // that here, before removing any old ones with the same number and IDs.
    //
    mapOfMessages::iterator it = m_mapMessages.begin();
    
    for (; it != m_mapMessages.end(); ++it)
    {
        // -----------------------------
        const int64_t  & lTempReqNum   = it->first;
        // -----------------------
        if (lTempReqNum != lRequestNum)
        {
            continue;
        }
        // -----------------------
        OTMessage   * pMsg          = it->second;
        OT_ASSERT(NULL != pMsg);
        // -----------------------------
        //
        // If a server ID was passed in, but doesn't match the server ID on this message,
        // Then skip this one. (Same with the NymID.)
        //
        if (!theMessage.m_strServerID.Compare(pMsg->m_strServerID) ||
            !theMessage.m_strNymID.   Compare(pMsg->m_strNymID))
        {
            continue;
        }
        // --------
        else
        {
            delete pMsg;
            pMsg = NULL;
            m_mapMessages.erase(it);
            break;
        }
    }
    // Whatever it was, it's gone now!
    // ----------------------------------
    // Now that we KNOW there's nothing already there with that request number (for that
    // server ID and Nym ID), we go ahead and add the new message to the map. (And take ownership.)
    //
    m_mapMessages.insert(std::pair<int64_t, OTMessage *>(lRequestNum, &theMessage));
    // ----------------------------------
    //
    // Save it to local storage, in case we don't see the reply until the next run.
    //
    bool bAlreadyExists=false, bIsNewFolder=false;
    OTString strFolder, strFolder1, strFolder2;
    strFolder1.Format("%s%s%s",
                      OTFolders::Nym().Get(),               OTLog::PathSeparator(),
                      theMessage.m_strServerID.Get());
    strFolder2.Format("%s%s%s", strFolder1.Get(), OTLog::PathSeparator(),
                      "sent" /*todo hardcoding*/);
    // ----------------------------------
    strFolder.Format("%s%s%s", strFolder2.Get(), OTLog::PathSeparator(),
                     theMessage.m_strNymID.Get());
    // ----------------------------------

	OTString strFolderPath = "", strFolder1Path = "", strFolder2Path = "";

	OTPaths::AppendFolder(strFolderPath,  m_strDataFolder,strFolder );
	OTPaths::AppendFolder(strFolder1Path, m_strDataFolder,strFolder1);
	OTPaths::AppendFolder(strFolder2Path, m_strDataFolder,strFolder2);

	OTPaths::ConfirmCreateFolder(strFolderPath,bAlreadyExists,bIsNewFolder);
	OTPaths::ConfirmCreateFolder(strFolder1Path,bAlreadyExists,bIsNewFolder);
	OTPaths::ConfirmCreateFolder(strFolder2Path,bAlreadyExists,bIsNewFolder);
    
    OTString strFile;
    strFile.Format("%s.msg", theMessage.m_strRequestNum.Get());
    
    theMessage.SaveContract(strFolder.Get(), strFile.Get());
    // ----------------------------------
    // We also keep a list of the request numbers, so let's load it up, add the number
    // to that list, and then save it again.
    //
    OTNumList theNumList;
    std::string str_data_filename("sent.dat"); // todo hardcoding.
    if (OTDB::Exists(strFolder.Get(), str_data_filename))
    {
        OTString strNumList(OTDB::QueryPlainString(strFolder.Get(), str_data_filename));
        if (strNumList.Exists())
            theNumList.Add(strNumList);
        theNumList.Add(lRequestNum); // Add the new request number to it.
    }
    else // it doesn't exist on disk, so let's just create it from the list we have in RAM so we can store it to disk.
    {
        it = m_mapMessages.begin();
        while (it != m_mapMessages.end())
        {
            // -----------------------------
            const int64_t  & lTempReqNum   = it->first;
            // -----------------------
            OTMessage   * pMsg          = it->second;
            OT_ASSERT(NULL != pMsg);
            // -----------------------------
            //
            // If a server ID was passed in, but doesn't match the server ID on this message,
            // Then skip this one. (Same with the NymID.)
            //
            if (!theMessage.m_strServerID.Compare(pMsg->m_strServerID) ||
                !theMessage.m_strNymID.   Compare(pMsg->m_strNymID))
            {
                ++it;
                continue;
            }
            // --------
            else
            {
                theNumList.Add(lTempReqNum);
            }
            ++it;
        }
    }// else
    // ----------------------------------
    // By this point, theNumList has either been loaded from local storage and had the new number added,
    // or it wasn't in local storage and thus we created it and added all the numnbers to it (including new one.)
    // Therefore nothing left to do here, but save it back again!
    //
    OTString strOutput;
    theNumList.Output(strOutput);
    
    if (!OTDB::StorePlainString(strOutput.Get(), strFolder.Get(), str_data_filename)) // todo hardcoding.
    {
        OTLog::Error("OTMessageOutbuffer::AddSentMessage: Error: failed writing list of request numbers to storage.\n");
    }
}
// Process my reply back out to the client.  @something.
void OTClientConnection::ProcessReply(OTMessage &theReply)
{
    int  err;
	uint32_t nwritten;
	bool bSendCommand = false;
	bool bSendPayload = false;
	
	u_header  theCMD;
	OTPayload thePayload;

	// For now let's send ALL replies in Envelopes (encrypted to public key of client)
	// IF we have a public key, that is. Otherwise we send as a normal message.
	//
	// All messages already require either a public key, or a nymID used to look up a
	// public key. So given that I have that information when I reply, I might as well
	// ENCRYPT my reply to that same public key. More secure that way.
	//
	// The wallet (and server) are both ready to open and process these encrypted envelopes.
	
		
	// If GetKey() returns something, that means the key was set in there, it's
	// not just a null pointer. This means we can use it!  So let's encrypt to it.
	if (m_PublicKey.GetKey())
	{
		OTString strEnvelopeContents;
		// Save the ready-to-go message into a string.
		theReply.SaveContract(strEnvelopeContents);
		
		OTEnvelope theEnvelope;
		// Seal the string up into an encrypted Envelope
		theEnvelope.Seal(m_PublicKey, strEnvelopeContents);
		
		// From here on out, theMessage is disposable. OTPayload takes over. 
		// OTMessage doesn't care about checksums and headers.
		thePayload.SetEnvelope(theEnvelope);
		
		// Now that the payload is ready, we'll set up the header.
		SetupHeader(&theCMD, CMD_TYPE_1, TYPE_1_CMD_2, thePayload);
	}
	else {
		thePayload.SetMessage(theReply);
		
		// Now that the payload is ready, we'll set up the header.
		SetupHeader(&theCMD, CMD_TYPE_1, TYPE_1_CMD_1, thePayload);
	}
	
	bSendCommand = true;
	bSendPayload = true;				
	
	
	fprintf(stderr, "\n****************************************************************\n"
			"===> Finished setting up header for response.\nFirst 9 bytes are: %d %d %d %d %d %d %d %d %d...\n",
			theCMD.buf[0], theCMD.buf[1], theCMD.buf[2], theCMD.buf[3], theCMD.buf[4], 
			theCMD.buf[5], theCMD.buf[6], theCMD.buf[7], theCMD.buf[8]);
	
	
	// ------------------------------------------------------------------------------			
	/*
	 // Write to Client
	 strcpy(buffer, "Hello Client!");
	 SFSocketWrite(clientSocket, buffer, strlen(buffer));
	 
	 */
	
	if (bSendCommand)
	{
		
		int nHeaderSize = OT_CMD_HEADER_SIZE;
		
		for (nwritten = 0;  nwritten < nHeaderSize;  nwritten += err)
		{
			err = SFSocketWrite(m_pSocket, theCMD.buf + nwritten, nHeaderSize - nwritten);

#ifdef _WIN32
			if (0 == err || SOCKET_ERROR == err) // 0 means disconnect. error means error. >0 means bytes read.
#else
			if (err <= 0)
#endif
				break;
		}
	}
	// At this point, we have sent the header across the pipe.
	
	if (bSendPayload)
	{
		
		uint32_t nPayloadSize = thePayload.GetSize();
		
		for (nwritten = 0;  nwritten < nPayloadSize;  nwritten += err)
		{
			err = SFSocketWrite(m_pSocket, (unsigned char *)thePayload.GetPayloadPointer() + nwritten, nPayloadSize - nwritten);

#ifdef _WIN32
			if (0 == err || SOCKET_ERROR == err) // 0 means disconnect. error means error. >0 means bytes read.
#else
			if (err <= 0)
#endif
				break;
		}		
	}
	// At this point, we have sent the payload across the pipe.		
	
	fprintf(stderr, "...Done.\n");
}