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