void
   SMTPClientConnection::ProtocolEHLOSent_(int code, const AnsiString &request)
   {
      if (!IsPositiveCompletion(code))
      {
         bool ehlo_required = GetConnectionSecurity() == CSSTARTTLSRequired ||
                              use_smtpauth_;

         if (ehlo_required)
         {
            // hMailServer is configured to require EHLO, but the remote server does not support it.
            UpdateAllRecipientsWithError_(500, "Server does not support EHLO command.", false);
            SendQUIT_();
         }
         else
         {
            // Server does not support EHLO, but we do not require it. Switch to HELO.
            String computer_name = Utilities::ComputerName(); 
            EnqueueWrite_("HELO " + computer_name);
            SetState_(HELOSENT);
         }

         return;
      }

      if (GetConnectionSecurity() == CSSTARTTLSRequired || 
          GetConnectionSecurity() == CSSTARTTLSOptional)
      {
         if (!IsSSLConnection())
         {
            if (request.Contains("STARTTLS"))
            {
               EnqueueWrite_("STARTTLS");
               SetState_(STARTTLSSENT);
               return;
            }
            else
            {
               // Remote server does not support STARTTLS
               if (GetConnectionSecurity() == CSSTARTTLSRequired)
               {
                  UpdateAllRecipientsWithError_(500, "Server does not support STARTTLS.", false);
                  SendQUIT_();
                  return;
               }
            }
         }
      }

      if (use_smtpauth_)
      {
         // Ask the server to initiate login process.
         EnqueueWrite_("AUTH LOGIN");
         SetState_(AUTHLOGINSENT);
      }
      else
      {
         ProtocolSendMailFrom_();
      }
   }
 void
 SMTPClientConnection::ProtocolSTARTTLSSent_(int code)
 {
    if (IsPositiveCompletion(code))
    {
       EnqueueHandshake();
    }
    else
    {
       HandleHandshakeFailed_();
    }
 }
   bool
   SMTPClientConnection::_ProtocolPassswordCheck(int iCode, const String &sServerLine)
   {
      if (!IsPositiveCompletion(iCode))
      {
         // Authentication failed with an permanent error.
         String sErrorMessage = "Authentication error. Server response: " + sServerLine;
         _UpdateAllRecipientsWithError(iCode, sErrorMessage, false);

         _SendQUIT();

         return false;
      }
      
      // The server accepted our authentication.
      _SetState(MAILFROM);
      return true;
     
   }
   void
   SMTPClientConnection::ProtocolRcptToSent_(int code, const AnsiString &request)
   {
      if (cur_recipient_ < recipients_.size())
      {
         if (IsPositiveCompletion(code))
         {
            actual_recipients_.insert(recipients_[cur_recipient_]);
         }
         else
         {
            UpdateRecipientWithError_(code, request, recipients_[cur_recipient_], false);
         }
      }

      std::shared_ptr<MessageRecipient> pRecipient = GetNextRecipient_();
      if (pRecipient)
      {
         // Send next recipient.
         EnqueueWrite_("RCPT TO:<" + pRecipient->GetAddress() + ">");
         current_state_ = RCPTTOSENT;
      }
      else
      {
         if (actual_recipients_.size() == 0)
         {
            SendQUIT_();
         }
         else
         {
            EnqueueWrite_("DATA");
            current_state_ = DATACOMMANDSENT;
         }
         
      }
   }
   void
   SMTPClientConnection::InternalParseData(const AnsiString  &Request)
   {
      LOG_DEBUG("SMTPClientConnection::_ParseASCII()");

      String sData = "RECEIVED: " + Request;
      LOG_SMTP_CLIENT(GetSessionID(), GetIPAddress().ToString(), sData);

      // Below 3 lines is fix of the problem that occurs when the remote server answers
      // with 2 line in his welcome message.
      String sMinus = "-";
      if ((Request.GetLength() > 3) && (Request.GetAt(3) == sMinus.GetAt(0)))
      {
         LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 1");
         return;
      }

      int lFirstSpace = Request.Find(" ");
   
      AnsiString sFirstWordTemp;
      if (lFirstSpace < 0)
         sFirstWordTemp = Request;
      else
         sFirstWordTemp = Request.Mid(0, lFirstSpace);
      sFirstWordTemp.MakeUpper();
      int iCode = atoi(sFirstWordTemp);

      // We should not update all recipient's if we've just sent a
      // RCPT TO. We should only update the specific one we've just
      // sent to.
      // 
      // Also, we should not update state if we've just sent QUIT to
      // the server. At the time we send QUIT, the message has already
      // been either accepted for delivery and rejected. Any error after
      // this isn't relvat.
      if (m_CurrentState != RCPTTOSENT && m_CurrentState != QUITSENT)
      {
         if (IsPermanentNegative(iCode))
         {
            _UpdateAllRecipientsWithError(iCode, Request, false);
            _SendQUIT();
            return;
         }
         else if (IsTransientNegative(iCode))
         {
            _UpdateAllRecipientsWithError(iCode, Request, false);
            _SendQUIT();
            return;
         }
      }
   
      switch (m_CurrentState)
      {
      case SENDUSERNAME:
         _ProtocolSendUsername();
         break;
      case SENDPASSWORD:
         _ProtocolSendPassword();
         break;
      case PASSWORDCHECK:
         if (!_ProtocolPassswordCheck(iCode, Request))
         {
            // Authentication failed. We have just sent
            // a quit command.
            return;
         }

         break;
      }
      
      if (m_CurrentState == HELO)
      {
         if (iCode == 220)
         {
			   String sComputerName = Utilities::ComputerName(); 
      
            if (m_bUseSMTPAuth)
            {
               _SendData("EHLO " + sComputerName);
               _SetState(EHLOSENT);
            }
            else
            {
               _SendData("HELO " + sComputerName);
               _SetState(HELOSENT);
            }
        
            LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 2");

            return ;
         }
         else
         {
            LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 3");
            _UpdateAllRecipientsWithError(iCode, Request, false);
            _SendQUIT();
            return;
         }
      }

      if (m_CurrentState == EHLOSENT)
      {
         // Ask the server to initiate login process.
         _SendData("AUTH LOGIN");
         _SetState(SENDUSERNAME);
         return ;
      }

      if (m_CurrentState == HELOSENT)
      {
         if (IsPositiveCompletion(iCode))
         {
            // --- Server accepted HELO. Go to HEADER/MAILFROM state.
            _SetState(MAILFROM);
         }
	      else
         {
            _UpdateAllRecipientsWithError(iCode, Request, false);
         }
      }
   

      if (m_CurrentState == MAILFROM)
      {
         String sFrom = m_pDeliveryMessage->GetFromAddress();
         String sData = "MAIL FROM:<" + sFrom + ">";
         _SendData(sData);
         m_CurrentState = MAILFROMSENT;
         LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 4");
         return;
      }

      if (m_CurrentState == MAILFROMSENT)
      {
         if (IsPositiveCompletion(iCode))
         {
            // --- Server accepted mail from. Go to header/rcpt to state.
            m_CurrentState = RCPTTO;
         }
         else
         {
            LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 5");
            _UpdateAllRecipientsWithError(iCode, Request, false);
         }

      }

      if (m_CurrentState == RCPTTO)
      {
         LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 6");

         shared_ptr<MessageRecipient> pRecipient = _GetNextRecipient();
         if (!pRecipient) 
         {
            _SendQUIT();
            return;
         }
         
         String sRecipient = pRecipient->GetAddress();
         String sData = "RCPT TO:<" + sRecipient + ">";
         _SendData(sData);
         m_CurrentState = RCPTTOSENT;

         return;

      }

      if (m_CurrentState == RCPTTOSENT)
      {
         if (m_iCurRecipient < m_vecRecipients.size())
         {
            if (IsPositiveCompletion(iCode))
            {
               _actualRecipients.insert(m_vecRecipients[m_iCurRecipient]);
            }
            else
            {
               _UpdateRecipientWithError(iCode, Request, m_vecRecipients[m_iCurRecipient], false);
            }
         }

         shared_ptr<MessageRecipient> pRecipient = _GetNextRecipient();
         if (pRecipient)
         {
            // Send next recipient.
            _SendData("RCPT TO:<" + pRecipient->GetAddress() + ">");
            m_CurrentState = RCPTTOSENT;
         }
         else
         {
            if (_actualRecipients.size() == 0)
            {
               _SendQUIT();
               return;
            }
            
            m_CurrentState = DATAQUESTION;
         }
      }

      if (m_CurrentState == DATAQUESTION)
      {
         _SendData("DATA");
         m_CurrentState = DATA;
         LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 7");
         return;
      }

      if (m_CurrentState == DATA)
      {
         if (IsPositiveIntermediate(iCode))
         {
            // Send the data!
            const String fileName = PersistentMessage::GetFileName(m_pDeliveryMessage);
            LOG_DEBUG("SMTPClientConnection::~_BEFORE SendFile");
            _StartSendFile(fileName);
            LOG_DEBUG("SMTPClientConnection::~_AFTER SendFile");
            return;
         }
      }

      if (m_CurrentState == DATASENT)
      {
            LOG_DEBUG("SMTPClientConnection::~_BEFORE SendQUIT");
         _SendQUIT();
            LOG_DEBUG("SMTPClientConnection::~_AFTER SendQUIT");

         if (IsPositiveCompletion(iCode))
         {
            _UpdateSuccessfulRecipients();
            LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 9");
            return;
         }
         else
         {
            _UpdateAllRecipientsWithError(iCode, Request, false);
            LOG_DEBUG("SMTPClientConnection::~_ParseASCII() - 10");
         }

         return;
      }

      if (m_CurrentState == QUITSENT)
      {     
         // We just received a reply on our QUIT. Time to disconnect.
         m_bPendingDisconnect = true;
         PostDisconnect();
      }
   }
   bool
   SMTPClientConnection::InternalParseData(const AnsiString &Request)
   {
      LogReceivedResponse_(Request);

      int lFirstSpace = Request.Find(" ");
   
      AnsiString sFirstWordTemp;
      if (lFirstSpace < 0)
         sFirstWordTemp = Request;
      else
         sFirstWordTemp = Request.Mid(0, lFirstSpace);

      sFirstWordTemp.MakeUpper();
      int iCode = atoi(sFirstWordTemp);
   
      bool ifFailureFailAllRecipientsAndQuit = 
         current_state_ == HELO ||
         current_state_ == HELOSENT ||
         current_state_ == AUTHLOGINSENT ||
         current_state_ == USERNAMESENT || 
         current_state_ == PASSWORDSENT ||
         current_state_ == MAILFROMSENT ||
         current_state_ == DATACOMMANDSENT ||
         current_state_ == DATASENT ||
         current_state_ == PASSWORDSENT;

      if (ifFailureFailAllRecipientsAndQuit)
      {
         if (!IsPositiveCompletion(iCode))
         {
            UpdateAllRecipientsWithError_(iCode, Request, false);
            SendQUIT_();
            return true;
         }
      }

      switch (current_state_)
      {
      case HELO:
         ProtocolStateHELOEHLO_(Request);  
         return true;
      case HELOSENT:
         ProtocolHELOSent_(Request);
         return true;
      case EHLOSENT:
         ProtocolEHLOSent_(iCode, Request);
         return true;
      case STARTTLSSENT:
         ProtocolSTARTTLSSent_(iCode);
         return false;
      case AUTHLOGINSENT:
         ProtocolSendUsername_();
         return true;
      case USERNAMESENT:
         ProtocolSendPassword_();
         return true;
      case PASSWORDSENT:
         ProtocolSendMailFrom_();
         return true;
      case MAILFROMSENT:
         ProtocolMailFromSent_();
         return true;
      case DATACOMMANDSENT:
         ProtocolData_();
         return false;
      case DATASENT:
         SendQUIT_();
         UpdateSuccessfulRecipients_();
         return true;
      case RCPTTOSENT:
         ProtocolRcptToSent_(iCode, Request);
         return true;
      case QUITSENT:
         // We just received a reply on our QUIT. Time to disconnect.
         EnqueueDisconnect();
         return false;
      }

      return true;
   }