/* Copyright (C) 2003 Frédéric Giudicelli (contact_nos@yahoo.com). All rights reserved. This product includes cryptographic software written by Eric Young (eay@cryptsoft.com) This program is released under the GPL with the additional exemption that compiling, linking, and/or using OpenSSL is allowed. 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. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // SmtpClient.cpp: implementation of the SmtpClient class. // ////////////////////////////////////////////////////////////////////// #include "SmtpClient.h" #include "svintl.h" #include ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// SmtpClient::SmtpClient() { m_IsEnabled = false; } SmtpClient::~SmtpClient() { } bool SmtpClient::SetInfo(mString MailFrom, mString Server, int Port, EntityLog * Logging) { struct hostent * hostinf; char ip[30]; m_Logging = Logging; m_IsEnabled = false; if(!MailFrom.size() || !Server.size() || !Port) { return true; } m_MailFrom = MailFrom; m_Server = Server; hostinf = gethostbyname(m_Server.c_str()); if(!hostinf || !hostinf->h_length) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_SOCKET); return false; } sprintf(ip, "%d.%d.%d.%d", (unsigned char)hostinf->h_addr_list[0][0], (unsigned char)hostinf->h_addr_list[0][1], (unsigned char)hostinf->h_addr_list[0][2], (unsigned char)hostinf->h_addr_list[0][3]); memset(&sockin, 0, sizeof(sockin)); sockin.sin_family = AF_INET; sockin.sin_port = htons (Port); sockin.sin_addr.s_addr=inet_addr(ip); m_Port = Port; m_IsEnabled = true; return true; } bool SmtpClient::Send(bool AdminMail, const mVector & MailTo, mString Subject, mString Body) const { if(!m_IsEnabled) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_DATAS); return false; } size_t i; for(i=0; iLogMessage(LOG_STATUS_TYPE_REQUEST, AdminMail?LOG_MESSAGE_TYPE_SEND_ADMIN_MAIL:LOG_MESSAGE_TYPE_SEND_MAIL, 0, NULL, LOG_NO_OBJECTID, MailTo[i].c_str()); if(Private_Send(AdminMail, MailTo[i], Subject, Body)) { if(m_Logging) { m_Logging->LogMessage(LOG_STATUS_TYPE_SUCCESS, AdminMail?LOG_MESSAGE_TYPE_SEND_ADMIN_MAIL:LOG_MESSAGE_TYPE_SEND_MAIL, 0, NULL, LOG_NO_OBJECTID, MailTo[i].c_str()); } NewpkiDebug(LOG_LEVEL_INFO, _sv("SMTP Client"), _sv("Successfully sent %smail to %s"), AdminMail?"admin ":"", MailTo[i].c_str()); } } return true; } bool SmtpClient::ReceiveSmtp(SOCKET hSocket, mString * cmd, int Code, bool AdminMail, const mString & MailTo) const { int ReturnCode; char RcvBuffer[4]; int RcvBufferLen; mString rcv_buffer; fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(hSocket, &rfds); tv.tv_sec = 30; tv.tv_usec = 0; if(select(hSocket + 1, &rfds, NULL, NULL, &tv) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_CONNECTION_LOST); LogError(AdminMail, MailTo, cmd, NULL); return false; } RcvBufferLen = recv(hSocket, RcvBuffer, 3, 0); if(RcvBufferLen != 3) { NEWPKIerr(PKI_ERROR_TXT, ERROR_CONNECTION_LOST); LogError(AdminMail, MailTo, cmd, NULL); return false; } RcvBuffer[3] = 0; sscanf(RcvBuffer, "%d", &ReturnCode); rcv_buffer = RcvBuffer; do { FD_ZERO(&rfds); FD_SET(hSocket, &rfds); tv.tv_sec = 30; tv.tv_usec = 0; if(select(hSocket + 1, &rfds, NULL, NULL, &tv) <= 0) { NEWPKIerr(PKI_ERROR_TXT, ERROR_CONNECTION_LOST); LogError(AdminMail, MailTo, cmd, NULL); return false; } RcvBufferLen = recv(hSocket, RcvBuffer, 1, 0); if(RcvBufferLen != 1) return 0; if(RcvBuffer[0] != '\n' && RcvBuffer[0] != '\r') rcv_buffer += RcvBuffer[0]; } while(RcvBuffer[0] != '\n'); if(ReturnCode != Code) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_DATAS); LogError(AdminMail, MailTo, cmd, &rcv_buffer); return false; } return true; } bool SmtpClient::SendSmtp(SOCKET hSocket, mString & cmd, int Code, bool AdminMail, const mString & MailTo) const { //Send command cmd += "\r\n"; if(send(hSocket, cmd.c_str(), cmd.size(), 0) != (int)cmd.size()) { NEWPKIerr(PKI_ERROR_TXT, ERROR_CONNECTION_LOST); LogError(AdminMail, MailTo, &cmd, NULL); return false; } //Get answer if(!ReceiveSmtp(hSocket, &cmd, Code, AdminMail, MailTo)) { return false; } return true; } bool SmtpClient::IsEnabled() const { return m_IsEnabled; } bool SmtpClient::Private_Send(bool AdminMail, const mString & MailTo, const mString & Subject, const mString & Body) const { SOCKET hSocket; mString snd_buffer; hSocket = socket(PF_INET, SOCK_STREAM, 0); if(hSocket == SOCKET_ERROR) { NEWPKIerr(PKI_ERROR_TXT, ERROR_BAD_SOCKET); LogError(AdminMail, MailTo, NULL, NULL); return false; } //Connect to server if(connect(hSocket,(sockaddr *)&sockin, sizeof(sockin)) == SOCKET_ERROR) { closesocket(hSocket); NEWPKIerr(PKI_ERROR_TXT, ERROR_CONNECT_FAILED); LogError(AdminMail, MailTo, NULL, NULL); return false; } //Getting initial server mString if(!ReceiveSmtp(hSocket, NULL, 220, AdminMail, MailTo)) { closesocket(hSocket); return false; } // Sending HELO snd_buffer = "HELO " + m_Server.c_string(); if(!SendSmtp(hSocket, snd_buffer, 250, AdminMail, MailTo)) { closesocket(hSocket); return false; } // Sending MAIL FROM snd_buffer = "MAIL FROM: <" + m_MailFrom.c_string() + ">"; if(!SendSmtp(hSocket, snd_buffer, 250, AdminMail, MailTo)) { closesocket(hSocket); return false; } // Sending RCPT TO snd_buffer = "RCPT TO: <" + MailTo.c_string() + ">"; if(!SendSmtp(hSocket, snd_buffer, 250, AdminMail, MailTo)) { closesocket(hSocket); return false; } // Sending DATA snd_buffer = "DATA"; if(!SendSmtp(hSocket, snd_buffer, 354, AdminMail, MailTo)) { closesocket(hSocket); return false; } //Sending the actual body snd_buffer = "From: <" + m_MailFrom.c_string() + ">\r\n"; snd_buffer += "To: " + MailTo.c_string() + "\r\n"; snd_buffer += "Subject: " + Subject.c_string() + "\r\n"; snd_buffer += "MIME-Version: 1.0\r\n" + Body.c_string() + "\r\n."; if(!SendSmtp(hSocket, snd_buffer, 250, AdminMail, MailTo)) { closesocket(hSocket); return false; } snd_buffer = "QUIT"; if(!SendSmtp(hSocket, snd_buffer, 221, AdminMail, MailTo)) { closesocket(hSocket); return false; } closesocket(hSocket); return true; } void SmtpClient::LogError(bool AdminMail, const mString & MailTo, mString * cmd, mString * resp) const { mString sError; if(cmd) { sError = "[OUT] " + cmd->c_string(); if(resp) { sError += "[IN] " + resp->c_string(); } ERR_add_error_data(1, sError.c_str()); } ERR_to_mstring(sError); if(m_Logging) m_Logging->LogMessage(LOG_STATUS_TYPE_FAILURE, AdminMail?LOG_MESSAGE_TYPE_SEND_ADMIN_MAIL:LOG_MESSAGE_TYPE_SEND_MAIL, 0, NULL, LOG_NO_OBJECTID, MailTo.c_str(), sError.c_str()); NewpkiDebug(LOG_LEVEL_WARNING, _sv("SMTP Client"), _sv("Failed to send %smail to %s on server %s:%d\n%s"), AdminMail?"admin ":"", MailTo.c_str(), m_Server.c_str(), m_Port, sError.c_str()); ERR_clear_error(); } SmtpClient::operator int() const { return (m_IsEnabled?1:0); }