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