void SMTPClientSession::loginUsingCRAM(const std::string& username, const std::string& method, Poco::DigestEngine& hmac) { std::string response; int status = sendCommand(std::string("AUTH ") + method, response); if (!isPositiveIntermediate(status)) throw SMTPException(std::string("Cannot authenticate using ") + method, response, status); std::string challengeBase64 = response.substr(4); std::istringstream istr(challengeBase64); Base64Decoder decoder(istr); std::string challenge; StreamCopier::copyToString(decoder, challenge); hmac.update(challenge); const DigestEngine::Digest& digest = hmac.digest(); std::string digestString(DigestEngine::digestToHex(digest)); std::string challengeResponse = username + " " + digestString; std::ostringstream challengeResponseBase64; Base64Encoder encoder(challengeResponseBase64); encoder.rdbuf()->setLineLength(0); encoder << challengeResponse; encoder.close(); status = sendCommand(challengeResponseBase64.str(), response); if (!isPositiveCompletion(status)) throw SMTPException(std::string("Login using ") + method + " failed", response, status); }
void SMTPClientSession::sendAddresses(const std::string& from, const Recipients& recipients) { std::string response; int status = 0; std::string::size_type emailPos = from.find('<'); if (emailPos == std::string::npos) { std::string sender("<"); sender.append(from); sender.append(">"); status = sendCommand("MAIL FROM:", sender, response); } else { status = sendCommand("MAIL FROM:", from.substr(emailPos, from.size() - emailPos), response); } if (!isPositiveCompletion(status)) throw SMTPException("Cannot send message", response, status); std::ostringstream recipient; for (Recipients::const_iterator it = recipients.begin(); it != recipients.end(); ++it) { recipient << '<' << *it << '>'; int status = sendCommand("RCPT TO:", recipient.str(), response); if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient.str(), response, status); recipient.str(""); } }
void SMTPClientSession::loginUsingLogin(const std::string& username, const std::string& password) { std::string response; int status = sendCommand("AUTH LOGIN", response); if (!isPositiveIntermediate(status)) throw SMTPException("Cannot authenticate using LOGIN", response, status); std::ostringstream usernameBase64; Base64Encoder usernameEncoder(usernameBase64); usernameEncoder.rdbuf()->setLineLength(0); usernameEncoder << username; usernameEncoder.close(); std::ostringstream passwordBase64; Base64Encoder passwordEncoder(passwordBase64); passwordEncoder.rdbuf()->setLineLength(0); passwordEncoder << password; passwordEncoder.close(); //Server request for username/password not defined could be either //S: login: //C: user_login //S: password: //C: user_password //or //S: password: //C: user_password //S: login: //C: user_login std::string decodedResponse; std::istringstream responseStream(response.substr(4)); Base64Decoder responseDecoder(responseStream); StreamCopier::copyToString(responseDecoder, decodedResponse); if (Poco::icompare(decodedResponse, 0, 8, "username") == 0) // username first (md5("Username:"******"Login using LOGIN username failed", response, status); status = sendCommand(passwordBase64.str(), response); if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN password failed", response, status); } else if (Poco::icompare(decodedResponse, 0, 8, "password") == 0) // password first (md5("Password:"******"Login using LOGIN password failed", response, status); status = sendCommand(usernameBase64.str(), response); if (!isPositiveCompletion(status)) throw SMTPException("Login using LOGIN username failed", response, status); } }
void SMTPClientSession::login(const std::string& hostname, std::string& response) { open(); int status = sendCommand("EHLO", hostname, response); if (isPermanentNegative(status)) status = sendCommand("HELO", hostname, response); if (!isPositiveCompletion(status)) throw SMTPException("Login failed", response, status); }
void SMTPClientSession::sendCommands(const MailMessage& message, const Recipients* pRecipients) { std::string response; int status = 0; const std::string& fromField = message.getSender(); std::string::size_type emailPos = fromField.find('<'); if (emailPos == std::string::npos) { std::string sender("<"); sender.append(fromField); sender.append(">"); status = sendCommand("MAIL FROM:", sender, response); } else { status = sendCommand("MAIL FROM:", fromField.substr(emailPos, fromField.size() - emailPos), response); } if (!isPositiveCompletion(status)) throw SMTPException("Cannot send message", response, status); std::ostringstream recipient; if (pRecipients) { for (Recipients::const_iterator it = pRecipients->begin(); it != pRecipients->end(); ++it) { recipient << '<' << *it << '>'; int status = sendCommand("RCPT TO:", recipient.str(), response); if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient.str(), response, status); recipient.str(""); } } else { for (MailMessage::Recipients::const_iterator it = message.recipients().begin(); it != message.recipients().end(); ++it) { recipient << '<' << it->getAddress() << '>'; int status = sendCommand("RCPT TO:", recipient.str(), response); if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient.str(), response, status); recipient.str(""); } } status = sendCommand("DATA", response); if (!isPositiveIntermediate(status)) throw SMTPException("Cannot send message data", response, status); }
void SMTPClientSession::open() { if (!_isOpen) { std::string response; int status = _socket.receiveStatusMessage(response); if (!isPositiveCompletion(status)) throw SMTPException("The mail service is unavailable", response, status); _isOpen = true; } }
void POP3ClientSession::login(const std::string& username, const std::string& password) { std::string response; _socket.receiveMessage(response); if (!isPositive(response)) throw SMTPException("The POP3 service is unavailable", response); sendCommand("USER", username, response); if (!isPositive(response)) throw POP3Exception("Login rejected for user", response); sendCommand("PASS", password, response); if (!isPositive(response)) throw POP3Exception("Password rejected for user", response); }
void SMTPClientSession::transportMessage(const MailMessage& message) { SocketOutputStream socketStream(_socket); MailOutputStream mailStream(socketStream); message.write(mailStream); mailStream.close(); socketStream.flush(); std::string response; int status = _socket.receiveStatusMessage(response); if (!isPositiveCompletion(status)) throw SMTPException("The server rejected the message", response, status); }
void SMTPClientSession::loginUsingXOAUTH2(const std::string& username, const std::string& password) { std::ostringstream credentialsBase64; Base64Encoder credentialsEncoder(credentialsBase64); credentialsEncoder.rdbuf()->setLineLength(0); credentialsEncoder << "user="******"\001auth=Bearer " << password << "\001\001"; credentialsEncoder.close(); std::string response; int status = sendCommand("AUTH XOAUTH2", credentialsBase64.str(), response); if (!isPositiveCompletion(status)) throw SMTPException("Login using XOAUTH2 failed", response, status); }
void SMTPClientSession::loginUsingPlain(const std::string& username, const std::string& password) { std::ostringstream credentialsBase64; Base64Encoder credentialsEncoder(credentialsBase64); credentialsEncoder.rdbuf()->setLineLength(0); credentialsEncoder << '\0' << username << '\0' << password; credentialsEncoder.close(); std::string response; int status = sendCommand("AUTH PLAIN", credentialsBase64.str(), response); if (!isPositiveCompletion(status)) throw SMTPException("Login using PLAIN failed", response, status); }
void SMTPClientSession::sendMessage(std::istream& istr) { std::string response; int status = 0; SocketOutputStream socketStream(_socket); MailOutputStream mailStream(socketStream); StreamCopier::copyStream(istr, mailStream); mailStream.close(); socketStream.flush(); status = _socket.receiveStatusMessage(response); if (!isPositiveCompletion(status)) throw SMTPException("The server rejected the message", response, status); }
void SMTPClientSession::login(const std::string& hostname, LoginMethod loginMethod, const std::string& username, const std::string& password) { std::string response; login(hostname, response); if (loginMethod == AUTH_CRAM_MD5) { if (response.find("CRAM-MD5", 0) != std::string::npos) { loginUsingCRAMMD5(username, password); } else throw SMTPException("The mail service does not support CRAM-MD5 authentication", response); } else if (loginMethod == AUTH_CRAM_SHA1) { if (response.find("CRAM-SHA1", 0) != std::string::npos) { loginUsingCRAMSHA1(username, password); } else throw SMTPException("The mail service does not support CRAM-SHA1 authentication", response); } else if (loginMethod == AUTH_LOGIN) { if (response.find("LOGIN", 0) != std::string::npos) { loginUsingLogin(username, password); } else throw SMTPException("The mail service does not support LOGIN authentication", response); } else if (loginMethod == AUTH_PLAIN) { if (response.find("PLAIN", 0) != std::string::npos) { loginUsingPlain(username, password); } else throw SMTPException("The mail service does not support PLAIN authentication", response); } else if (loginMethod == AUTH_XOAUTH2) { if (response.find("XOAUTH2", 0) != std::string::npos) { loginUsingXOAUTH2(username, password); } else throw SMTPException("The mail service does not support XOAUTH2 authentication", response); } else if (loginMethod != AUTH_NONE) { throw SMTPException("The autentication method is not supported"); } }
void SMTPClientSession::sendData() { std::string response; int status = sendCommand("DATA", response); if (!isPositiveIntermediate(status)) throw SMTPException("Cannot send message data", response, status); }