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
   POP3ClientConnection::ParseStateCAPASent_(const String &sData)
   {
      if (!CommandIsSuccessfull_(sData) || !sData.Contains(_T("STLS")))
      {
         // STLS is not supported.
         if (GetConnectionSecurity() == CSSTARTTLSRequired)
         {
            String message = 
               Formatter::Format("The download of messages from external account {0} failed. The external aAccount is configured to use STARTTLS connection security, but the POP3 server does not support it.", account_->GetName());
            
            LOG_APPLICATION(message)
            QuitNow_();
            return;
         }
         else
         {
            SendUserName_();
            return;
         }
      }

      EnqueueWrite_("STLS");
      current_state_ = StateSTLSSent;
   }
 void
 POP3ClientConnection::OnConnectionTimeout()
 {  
    String sMessage = "QUIT\r\n";
    EnqueueWrite_(sMessage);
    
    Logger::Instance()->LogDebug("POP3ClientConnection::OnConnectionTimeout() - Connection timeout.");
 }
 void
 SMTPClientConnection::ProtocolSendMailFrom_()
 {
    String sFrom = delivery_message_->GetFromAddress();
    String sData = "MAIL FROM:<" + sFrom + ">";
    EnqueueWrite_(sData);
    current_state_ = MAILFROMSENT;
 }
   void
   POP3ClientConnection::SendCAPA_()
   {
      // We have connected successfully.
      // Time to send the username.
      EnqueueWrite_(_T("CAPA"));

      current_state_ = StateCAPASent;
   }
   void
   SMTPClientConnection::SendQUIT_()
   {
      // Disconnect from the remote SMTP server.
      session_ended_ = true;

      EnqueueWrite_("QUIT");
      SetState_(QUITSENT);
   }
 void
 SMTPClientConnection::ProtocolSendPassword_()
 {
    String sOut;
    StringParser::Base64Encode(password_, sOut);      
    
    SetState_(PASSWORDSENT);
    EnqueueWrite_(sOut);
 }
 void
 SMTPClientConnection::ProtocolSendUsername_()
 {
    String sOut;
    StringParser::Base64Encode(username_, sOut);      
    EnqueueWrite_(sOut);
    
    SetState_(USERNAMESENT);
 }
   bool
   POP3ClientConnection::HandleEtrn_(const String &sRequest, const String &account_name)
   {
      LogSMTPString_(sRequest, false);

      std::vector<String> vecParams = StringParser::SplitString(account_name, " ");
      if (vecParams.size() == 2)
      {
         bool bRetVal = true;
         switch (current_state_)
         {
            // Re-using POP states names for now
         case StateConnected:
            // Realize we shouldn't blindly send but this works for now
            EnqueueWrite_LogAsSMTP("HELO " + vecParams[1]);
            current_state_ = StateUsernameSent;
            return true;
         case StateUsernameSent:
            EnqueueWrite_LogAsSMTP("ETRN " + vecParams[1]);
            Sleep(20);
            current_state_ = StateUIDLRequestSent;
            return true;
         case StateUIDLRequestSent:
            EnqueueWrite_LogAsSMTP("QUIT");
            current_state_ = StateQUITSent;
            Sleep(20);
            return true;

         default:
            return false;
         }
      }
      else
      {
         //We just log error & QUIT because we have no domain to send..
         EnqueueWrite_("NOOP ETRN-Domain not set");
         Sleep(20);
         EnqueueWrite_("QUIT");
         ParseQuitResponse_(sRequest);
         return false;
      }
   }
   void
   POP3ClientConnection::QuitNow_()
   {
      String sResponse;
      sResponse.Format(_T("QUIT"));
   
      EnqueueWrite_(sResponse);

      SetReceiveBinary(false);
      current_state_ = StateQUITSent;
   }
   void
   SMTPClientConnection::ProtocolStateHELOEHLO_(const AnsiString &request)
   {
      bool use_esmtp  = GetConnectionSecurity() == CSSTARTTLSRequired ||
                        GetConnectionSecurity() == CSSTARTTLSOptional ||
                        use_smtpauth_;

      String computer_name = Utilities::ComputerName(); 

      if (use_esmtp)
      {
         EnqueueWrite_("EHLO " + computer_name);
         SetState_(EHLOSENT);
      }
      else
      {
         EnqueueWrite_("HELO " + computer_name);
         SetState_(HELOSENT);
      }
         
   }
   void
   POP3ClientConnection::SendUserName_()
   {
      // We have connected successfully.
      // Time to send the username.

      String sResponse;
      sResponse.Format(_T("USER %s"), account_->GetUsername().c_str());

      EnqueueWrite_(sResponse);

      current_state_ = StateUsernameSent;
   }
   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::ProtocolMailFromSent_()
   {
      std::shared_ptr<MessageRecipient> pRecipient = GetNextRecipient_();
      if (!pRecipient) 
      {
         SendQUIT_();
         return;
      }

      String sRecipient = pRecipient->GetAddress();
      String sData = "RCPT TO:<" + sRecipient + ">";
      EnqueueWrite_(sData);
      current_state_ = RCPTTOSENT;
   }
   bool
   POP3ClientConnection::MessageCleanup_()
   {
      int iIndex = (*cur_message_).first;
      String sUID = (*cur_message_).second;

      int iDaysToKeep = GetDaysToKeep_(sUID);

      String sResponse;
      bool bDeleteMessageNow = false;

      if (iDaysToKeep == 0)
      {
         // Never delete messages
         return false;
      }
      else if (iDaysToKeep > 0)
      {
         // Check wether we should delete this UID.
         std::shared_ptr<FetchAccountUID> pUID = GetUIDList_()->GetUID(sUID);

         // Get the creation date of the UID.
         DateTime dtCreation = pUID->GetCreationDate();
         DateTime dtNow = Time::GetDateFromSystemDate(Time::GetCurrentDateTime());

         DateTimeSpan dtSpan = dtNow - dtCreation;

         if (dtSpan.GetNumberOfDays() <= iDaysToKeep)
         {
            // No, we should not delete this UID.
            return false;
         }
      }

      // Delete the message.
      sResponse.Format(_T("DELE %d"), iIndex);
      EnqueueWrite_(sResponse);

      current_state_ = StateDELESent;

      // Delete this UID from the database.
      GetUIDList_()->DeleteUID(sUID);
     

      return true;
   }
   void 
   POP3ClientConnection::ParsePasswordSent_(const String &sData)
   {
      if (CommandIsSuccessfull_(sData))
      {
         current_state_ = StateUIDLRequestSent;

         // We have connected successfully.
         // Time to send the username.
         String sResponse;
         sResponse.Format(_T("UIDL"));
         
         EnqueueWrite_(sResponse);
         return;
      }

      QuitNow_();
      return;
   }
   void 
   POP3ClientConnection::ParseUsernameSent_(const String &sData)
   {
      if (CommandIsSuccessfull_(sData))
      {
         // We have connected successfully.
         // Time to send the username.

         String sResponse;
         sResponse.Format(_T("PASS %s"), account_->GetPassword().c_str());

         current_state_ = StatePasswordSent;

         EnqueueWrite_(sResponse);

         return;
      }

      QuitNow_();
      return;
   }
   void 
   SMTPClientConnection::ReadAndSend_()
   {
      // Continue sending the file..
      int bufferSize = GetBufferSize();
      std::shared_ptr<ByteBuffer> pBuffer = current_file_.ReadChunk(bufferSize);

      while (pBuffer->GetSize() > 0)
      {
         transmission_buffer_.Append(pBuffer->GetBuffer(), pBuffer->GetSize());

         if (transmission_buffer_.Flush())
         {
            // Data was sent. We'll wait with sending more data until
            // the current data has been sent.
            return; 
         }

         pBuffer = current_file_.ReadChunk(bufferSize);
      }

      // We're done sending!
      current_file_.Close();

      // No more data to send. Make sure all buffered data is flushed.
      transmission_buffer_.Flush(true);

      // We're ready to receive the Message accepted-response.
      // No \r\n on end because EnqueueWrite adds
      EnqueueWrite_("\r\n.");

      EnqueueRead();

      // State change moved to AFTER crlf.crlf to help with race condition
      current_state_ = DATASENT;
   }
 void
 POP3ClientConnection::OnConnectionTimeout()
 {  
    String sMessage = "QUIT\r\n";
    EnqueueWrite_(sMessage);
 }
   bool
   POP3ClientConnection::RequestNextMessage_()
   {
      while (cur_message_ != uidlresponse_.end())
      {
         String sCurrentUID = (*cur_message_).second;

         // Check if the current message is already in the list
         // of fetch UID's

         bool bMessageDownloaded = GetUIDList_()->IsUIDInList(sCurrentUID);

         if (bMessageDownloaded)
         {  
            // Mark this message as downloaded. This is so that we can
            // drop it later on when purging the mailbox. (We only purge
            // items we have downloaded). And since it was downloaded during
            // a previous session, we can safely drop it..
            int iID = (*cur_message_).first;
            downloaded_messages_[iID] = sCurrentUID;

            // The message has already been downloaded. Give scripts a chance
            // to override the default delete behavior.
            std::shared_ptr<Message> messageEmpty;
            FireOnExternalAccountDownload_(messageEmpty, sCurrentUID);
         }
         else
         {
            // Request message download now.

            current_message_ = std::shared_ptr<Message> (new Message);

            int iMessageIdx = (*cur_message_).first;

            String sResponse;
            sResponse.Format(_T("RETR %d"), iMessageIdx);

            EnqueueWrite_(sResponse);

            current_state_ = StateRETRSent;

            // Reset the transmission buffer. It will be
            // recreated when we receive binary the next time.

            transmission_buffer_.reset();

            SetReceiveBinary(true);
                          
            return true;
         }
      
         cur_message_++;

      }

      // We reached the end of the message list.
      if (cur_message_ == uidlresponse_.end())
      {
         StartMailboxCleanup_();
      }


      return false;
   }