📄 smtp.cpp
字号:
/************************************************************************* * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * *************************************************************************/#include "smtp.h"/** * Constructor. * * @param domain The domain that should be used when sending the HELO cmd. * @param from The envelope from address. * @param server The address of the SMTP server. * @param port The port the SMTP server is listening on. */SMTP::SMTP ( const string &domain, const string &from, const string &server, unsigned int port ) : Logger (){ this->username = ""; this->password = ""; this->domain = domain; this->from = from; this->auth_type = NO_AUTH; this->ssl_type = SMTP::NO_SSL; this->socket = new InetSocket (server, port); // to synchronize logging this->socket->setParentLogger (this);}/** * Destructor. */SMTP::~SMTP () { delete this->socket;}/** * Start the SSL handshaking process. * * @throws TransferException * If the SMTP server responds with an error msg. * @throws TransferException * On any uncommon event that occurs while sending * data through the socket. * @throws SSLException * On any uncommon event that occurs while sending * data through the encrypted socket. * @throws IOException * If one of ca_file or ca_dir is not accessible. */void SMTP::startSSL (){ if (this->ssl_type != NO_SSL) { if (this->ssl_type == STARTTLS) { read_response (); this->socket->writeSocket ("STARTTLS\r\n"); read_response (); } this->socket->negotiate (); }}/** * Send the messages. * * @throws TransferException * If the SMTP server responds with an error msg. * @throws TransferException * On any uncommon event that occurs while sending * data through the socket. * @throws TransferException * If the connection to the host cannot be * established. * @throws SSLException * On any uncommon event that occurs while sending * data through the encrypted socket. * @throws IOException * If one of ca_file or ca_dir is not accessible. * @throws AuthenticationFailedException * If the given authentication method is not * supported by the SMTP server. * @throws DecodeException * If an error occured during the BASE64 * de-/encoding process. */void SMTP::sendMessage (){ this->socket->connect (); if (this->ssl_type != NO_SSL) { startSSL (); } if (this->ssl_type != STARTTLS) { read_response (); } if (this->auth_type == NO_AUTH) { sendHELO (); } else { authenticate (); } vector<Message>::iterator iter; for (iter = this->msgs.begin (); iter != this->msgs.end (); ++iter) { //TODO: try/catch Block??? sendMAILFROM (); sendRCPTTO (*iter); sendDATA (*iter); } sendQUIT (); this->msgs.clear ();}/** * send the HELO command. * * @throws TransferException * If the SMTP server responds with an error msg. * @throws TransferException * On any uncommon event that occurs while sending * data through the socket. * @throws SSLException * On any uncommon event that occurs while sending * data through the encrypted socket. */void SMTP::sendHELO (){ this->socket->writeSocket ("HELO " + this->domain + "\r\n"); string response = read_response ();}/** * Send the MAIL command. * * @throws TransferException * If the SMTP server responds with an error msg. * @throws TransferException * On any uncommon event that occurs while sending * data through the socket. * @throws SSLException * On any uncommon event that occurs while sending * data through the encrypted socket. */void SMTP::sendMAILFROM (){ this->socket->writeSocket ("MAIL FROM: <" + this->from + ">\r\n"); string response = read_response ();}/** * Send the RCPT command. * * @param msg The message that the RCPT TO cms belongs to. * * @throws TransferException * If the SMTP server responds with an error msg. * @throws TransferException * On any uncommon event that occurs while sending * data through the socket. * @throws SSLException * On any uncommon event that occurs while sending * data through the encrypted socket. */void SMTP::sendRCPTTO (Message &msg){ vector<string>::iterator iter; for (iter = msg.rcpts.begin (); iter != msg.rcpts.end (); ++iter) { this->socket->writeSocket ("RCPT TO: <" + *iter + ">\r\n"); string response = read_response (); }}/** * Send the DATA command. * * @param msg The message that the RCPT TO cms belongs to. * * @throws TransferException * If the SMTP server responds with an error msg. * @throws TransferException * On any uncommon event that occurs while sending * data through the socket. * @throws SSLException * On any uncommon event that occurs while sending * data through the encrypted socket. */void SMTP::sendDATA (Message &msg){ this->socket->writeSocket ("DATA\r\n"); string response; response = read_response (); this->socket->writeSocket (msg.msg + "\r\n.\r\n"); response = read_response ();}/** * Send the QUIT command. * * @throws TransferException * If the SMTP server responds with an error msg. * @throws TransferException * On any uncommon event that occurs while sending * data through the socket. * @throws SSLException * On any uncommon event that occurs while sending * data through the encrypted socket. */void SMTP::sendQUIT (){ this->socket->writeSocket ("QUIT\r\n"); string response = read_response (false);}/** * Reads the response from the smtp server. * * @param is_221_fatal If true a SMTP response with the ID 221 will * result in a TransferException. * * @throws TransferException * If the SMTP server responds with an error msg. * @throws TransferException * On any uncommon event that occurs while receiving * data from the socket. * @throws SSLException * On any uncommon event that occurs while receiving * data from the encrypted socket. */string SMTP::read_response (bool is_221_fatal){ string line = this->socket->readSocket (); /* get rid of the trailing \r */ if (line.at (line.length ()-1) == '\r') { line = line.substr (0, line.length ()-1); } string response = line; evalResponse (line, is_221_fatal); while (line.length () > 3 && line.at (3) == '-') { line = this->socket->readSocket (); /* get rid of the trailing \r */ if (line.at (line.length ()-1) == '\r') { line = line.substr (0, line.length ()-1); } response += line; evalResponse (line, is_221_fatal); } return (response);}/** * Evaluates the SMTP reply and throws an * TransferException if a fatal error occured or * prints a warning message to stderr on any * not fatal error. * * @param answer The response string from the SMTP server that * should be evaluated. * @param is_221_fatal If true a SMTP response with the ID 221 will * result in a TransferException. * * @throws TransferException * If the SMTP answer is a fatal error msg. */void SMTP::evalResponse (const string &response, bool is_221_fatal){ //TODO: 432??? string fatal[] = { "500", "501", "502", "503", "504", "421", "450", "451", "452", "550", "552", "553", "554", "534", "538", "454", "530", "535" }; string notify[] = { "211", "214", "551", "251" }; string ok[] = { "220", "250", "354", "221", "334", "235" }; // check for 221 if this is expected to be an error if (is_221_fatal && string (response, 0, 3) == "221") { throw (TransferException (response, "SMTP::evalResponse()", 1)); } for (int idx = 0; idx < 18; idx++) { if (string (response, 0, 3) == fatal[idx]) { throw (TransferException (response, "SMTP::evalResponse()", 2)); } } for (int idx = 0; idx < 4; idx++) { if (string (response, 0, 3) == notify[idx]) { LOG_ERROR << LIBSMTP_I18N_1 ("Host said: ") << response << endl; return; } } for (int idx = 0; idx < 6; idx++) { if (string (response, 0, 3) == ok[idx]) { return; } } // this point should never be reached throw ( TransferException (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -