diff options
author | eportnov <eportnov@ibs.ru> | 2022-09-09 11:10:14 +0300 |
---|---|---|
committer | eportnov <eportnov@ibs.ru> | 2022-09-09 12:41:59 +0300 |
commit | 9fa4addff6f90a8b5697a594e034f5517d64dd25 (patch) | |
tree | b429545eba770ea5aadd030b40f62ca8ab5b208a /src | |
download | obmc-sila-smtp-9fa4addff6f90a8b5697a594e034f5517d64dd25.tar.xz |
first comit
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 14 | ||||
-rw-r--r-- | src/message_builder/cc.cpp | 31 | ||||
-rw-r--r-- | src/message_builder/cc.hpp | 21 | ||||
-rw-r--r-- | src/message_builder/date.cpp | 16 | ||||
-rw-r--r-- | src/message_builder/date.hpp | 17 | ||||
-rw-r--r-- | src/message_builder/from.cpp | 22 | ||||
-rw-r--r-- | src/message_builder/from.hpp | 19 | ||||
-rw-r--r-- | src/message_builder/mail_to.cpp | 23 | ||||
-rw-r--r-- | src/message_builder/mail_to.hpp | 21 | ||||
-rw-r--r-- | src/message_builder/subject.cpp | 21 | ||||
-rw-r--r-- | src/message_builder/subject.hpp | 19 | ||||
-rw-r--r-- | src/message_builder/text.cpp | 24 | ||||
-rw-r--r-- | src/message_builder/text.hpp | 19 | ||||
-rw-r--r-- | src/message_builder/types/idecorator.hpp | 82 | ||||
-rw-r--r-- | src/message_builder/types/imessage_build.hpp | 14 | ||||
-rw-r--r-- | src/message_sender.cpp | 123 | ||||
-rw-r--r-- | src/message_sender.hpp | 48 | ||||
-rw-r--r-- | src/settings_storage.hpp | 14 | ||||
-rw-r--r-- | src/smtp_service.cpp | 96 | ||||
-rw-r--r-- | src/smtp_service.hpp | 36 |
20 files changed, 680 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..ba2848d --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,14 @@ +#include <sdbusplus/asio/connection.hpp> + +#include "smtp_service.hpp" + +int main() +{ + boost::asio::io_service io_context; + + auto connection = std::make_shared<sdbusplus::asio::connection>( io_context ); + smtp::SmtpService smtp{ connection }; + + io_context.run(); + return 0; +} diff --git a/src/message_builder/cc.cpp b/src/message_builder/cc.cpp new file mode 100644 index 0000000..c686ef2 --- /dev/null +++ b/src/message_builder/cc.cpp @@ -0,0 +1,31 @@ +#include "cc.hpp" + +namespace smtp::message_builder +{ + Cc::Cc( std::list<std::string> const& mail_to ) + : mMailTo( mail_to ) + { + + } + + std::string Cc::Get() const + { + std::string result; + if( mBase ) + { + result = mBase->Get(); + } + + if( mMailTo.empty() ) + { + return result; + } + + for(const auto& cc : mMailTo) + { + result += "Cc: " + cc + "\r\n"; + } + + return result; + } +} diff --git a/src/message_builder/cc.hpp b/src/message_builder/cc.hpp new file mode 100644 index 0000000..5062c37 --- /dev/null +++ b/src/message_builder/cc.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <list> + +#include "types/idecorator.hpp" +#include "types/imessage_build.hpp" + +namespace smtp::message_builder +{ + class Cc : public types::IDecorator<types::IMessageBuilder> + { + public: + explicit Cc( std::list<std::string> const& mail_to ); + ~Cc() override = default; + + std::string Get() const override; + private: + std::list<std::string> const& mMailTo; + }; +} + diff --git a/src/message_builder/date.cpp b/src/message_builder/date.cpp new file mode 100644 index 0000000..96ee2e1 --- /dev/null +++ b/src/message_builder/date.cpp @@ -0,0 +1,16 @@ +#include "date.hpp" + +namespace smtp::message_builder +{ + std::string Date::Get() const + { + std::string result; + + if( mBase ) + { + result = mBase->Get(); + } + result += "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n"; + return result; + } +} diff --git a/src/message_builder/date.hpp b/src/message_builder/date.hpp new file mode 100644 index 0000000..00fb6cb --- /dev/null +++ b/src/message_builder/date.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "types/idecorator.hpp" +#include "types/imessage_build.hpp" + +namespace smtp::message_builder +{ + class Date : public types::IDecorator<types::IMessageBuilder> + { + public: + Date() = default; + ~Date() override = default; + + std::string Get() const override; + }; +} + diff --git a/src/message_builder/from.cpp b/src/message_builder/from.cpp new file mode 100644 index 0000000..094e1a2 --- /dev/null +++ b/src/message_builder/from.cpp @@ -0,0 +1,22 @@ +#include "from.hpp" + +namespace smtp::message_builder +{ + + From::From( std::string const& mail_to ) + :mMailTo( mail_to ) + { + + } + + std::string From::Get() const + { + std::string result; + if( mBase ) + { + result = mBase->Get(); + } + result += "From: " + mMailTo + "\r\n"; + return result; + } +} diff --git a/src/message_builder/from.hpp b/src/message_builder/from.hpp new file mode 100644 index 0000000..4605469 --- /dev/null +++ b/src/message_builder/from.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "types/idecorator.hpp" +#include "types/imessage_build.hpp" + +namespace smtp::message_builder +{ + class From : public types::IDecorator<types::IMessageBuilder> + { + public: + explicit From( std::string const& mail_to ); + ~From() override = default; + + std::string Get() const override; + private: + std::string const& mMailTo; + }; +} + diff --git a/src/message_builder/mail_to.cpp b/src/message_builder/mail_to.cpp new file mode 100644 index 0000000..c73e2a7 --- /dev/null +++ b/src/message_builder/mail_to.cpp @@ -0,0 +1,23 @@ +#include "mail_to.hpp" + +namespace smtp::message_builder +{ + MailTo::MailTo( std::string const& mail_to) + : mMailTo( mail_to ) + { + + } + + std::string MailTo::Get() const + { + std::string result; + if( mBase ) + { + result = mBase->Get(); + } + + result += "To: " + mMailTo +"\r\n"; + + return result; + } +} diff --git a/src/message_builder/mail_to.hpp b/src/message_builder/mail_to.hpp new file mode 100644 index 0000000..0245fd6 --- /dev/null +++ b/src/message_builder/mail_to.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <list> + +#include "types/idecorator.hpp" +#include "types/imessage_build.hpp" + +namespace smtp::message_builder +{ + class MailTo : public types::IDecorator<types::IMessageBuilder> + { + public: + explicit MailTo( std::string const& mail_to ); + ~MailTo() override = default; + + std::string Get() const override; + private: + std::string const& mMailTo; + }; +} + diff --git a/src/message_builder/subject.cpp b/src/message_builder/subject.cpp new file mode 100644 index 0000000..84e7e43 --- /dev/null +++ b/src/message_builder/subject.cpp @@ -0,0 +1,21 @@ +#include "subject.hpp" + +namespace smtp::message_builder +{ + Subject::Subject( std::string const& subject ) + : mSubject(subject) + { + + } + + std::string Subject::Get() const + { + std::string result; + if( mBase ) + { + result = mBase->Get(); + } + result += "Subject: " + mSubject + "\r\n"; + return result; + } +} diff --git a/src/message_builder/subject.hpp b/src/message_builder/subject.hpp new file mode 100644 index 0000000..bf8bfab --- /dev/null +++ b/src/message_builder/subject.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "types/idecorator.hpp" +#include "types/imessage_build.hpp" + +namespace smtp::message_builder +{ + class Subject : public types::IDecorator<types::IMessageBuilder> + { + public: + explicit Subject( std::string const& subject ); + ~Subject() override = default; + + std::string Get() const override; + private: + std::string const& mSubject; + }; +} + diff --git a/src/message_builder/text.cpp b/src/message_builder/text.cpp new file mode 100644 index 0000000..e5e6bf0 --- /dev/null +++ b/src/message_builder/text.cpp @@ -0,0 +1,24 @@ +#include "text.hpp" + +namespace smtp::message_builder +{ + Text::Text( std::string const& text) + : mText( text ) + { + + } + + std::string Text::Get() const + { + std::string result; + if( mBase ) + { + result = mBase->Get(); + } + + result += "\r\n"; + result += mText + "\r\n"; + + return result; + } +} diff --git a/src/message_builder/text.hpp b/src/message_builder/text.hpp new file mode 100644 index 0000000..4df90e1 --- /dev/null +++ b/src/message_builder/text.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include "types/idecorator.hpp" +#include "types/imessage_build.hpp" + +namespace smtp::message_builder +{ + class Text : public types::IDecorator<types::IMessageBuilder> + { + public: + explicit Text( std::string const& text ); + ~Text() override = default; + + std::string Get() const override; + private: + std::string const& mText; + }; +} + diff --git a/src/message_builder/types/idecorator.hpp b/src/message_builder/types/idecorator.hpp new file mode 100644 index 0000000..3fabcd4 --- /dev/null +++ b/src/message_builder/types/idecorator.hpp @@ -0,0 +1,82 @@ +#pragma once
+
+#include <memory>
+
+namespace smtp::message_builder::types
+{
+
+/**
+ * @brief Базовый интерфейс описания декоратора
+ * @details См. https://refactoring.guru/ru/design-patterns/decorator
+ * @tparam T Тип декорируемого класса, T должен обладать возможностью наследования (в том числе виртуальный деструктор)
+ */
+ template < typename T, typename TPointerType = std::shared_ptr<T> > class IDecorator : public T
+ {
+ public:
+ using PointerType = TPointerType;
+ using Type = IDecorator<T, TPointerType>;
+
+ ~IDecorator() override = default;
+
+ /**
+ * @brief Установить указатель на декорируемый класс
+ * @details По возможности используйте метод Apply() как наиболее универсальный
+ * @param base Указатель на декорируемый класс
+ */
+ void SetBase( PointerType const& base ) noexcept
+ {
+ mBase = base;
+ }
+
+ void SetBase( PointerType&& base ) noexcept
+ {
+ mBase = std::move( base );
+ }
+
+ /**
+ * @brief Установить указатель на декорируемый класс (цепочка обязанностей)
+ * @details См. https://refactoring.guru/ru/design-patterns/chain-of-responsibility/cpp/example
+ * @details Цепь вызовов: декоратор1 -> декоратор2 -> базовый класс
+ * @param base_or_decorator Указатель на декорируемый класс или целевой декоратор
+ */
+ Type& Apply( PointerType const& base_or_decorator ) noexcept
+ {
+ if( !base_or_decorator )
+ {
+ return *this;
+ }
+
+ SetBase( base_or_decorator );
+ return GetApplyResult();
+ }
+
+ Type& Apply( PointerType&& base_or_decorator ) noexcept
+ {
+ if( !base_or_decorator )
+ {
+ return *this;
+ }
+
+ SetBase( std::move( base_or_decorator ) );
+ return GetApplyResult();
+ }
+
+ private:
+ Type& GetApplyResult() noexcept
+ {
+ auto as_decorator = dynamic_cast< Type * >( mBase.get() );
+ if( as_decorator )
+ {
+ return *as_decorator;
+ }
+
+ return *this;
+ }
+
+ protected:
+ PointerType mBase;
+ };
+
+ template < typename T, typename TDeleter = std::default_delete<T> > using IDecoratorUnique = IDecorator<T, std::unique_ptr<T, TDeleter> >;
+
+} // namespace sbis::devices::generic::types
diff --git a/src/message_builder/types/imessage_build.hpp b/src/message_builder/types/imessage_build.hpp new file mode 100644 index 0000000..4c4f1b8 --- /dev/null +++ b/src/message_builder/types/imessage_build.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <string> + +namespace smtp::message_builder::types +{ + class IMessageBuilder + { + public: + virtual ~IMessageBuilder() = default; + + virtual std::string Get() const = 0; + }; +} diff --git a/src/message_sender.cpp b/src/message_sender.cpp new file mode 100644 index 0000000..5b2950c --- /dev/null +++ b/src/message_sender.cpp @@ -0,0 +1,123 @@ +#include <string.h> + +#include "message_sender.hpp" +#include "message_builder/date.hpp" +#include "message_builder/mail_to.hpp" +#include "message_builder/cc.hpp" +#include "message_builder/subject.hpp" +#include "message_builder/text.hpp" +#include "message_builder/from.hpp" + +namespace smtp +{ + static std::string mText = ""; + + // + // Constructors/Destructors + // + MessageSender::MessageSender( SettingsStorage const& settings_storage ) + : mSettingsStorage( settings_storage ) + { + + } + + // + //Public methods + // + bool MessageSender::Send( std::string const& mail_from, std::string const& mail_to, std::list<std::string> const& cc, + std::string const& subject, std::string const& text ) + { + CURLcode result = CURLE_OK; + + struct curl_slist *recipients = NULL; + struct WriteThis upload_ctx; + + upload_ctx.counter = 0; + + auto curl = curl_easy_init(); + + if( !curl ) + { + //Error + return false; + } + mText = GetText( mail_from, mail_to, cc, subject, text); + FillRecipients( curl, mail_to, cc, recipients ); + + curl_easy_setopt(curl, CURLOPT_USERNAME, mSettingsStorage.username.c_str()); + curl_easy_setopt(curl, CURLOPT_PASSWORD, mSettingsStorage.password.c_str()); + curl_easy_setopt(curl, CURLOPT_URL, GetHostPortData().c_str()); + + curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL); + curl_easy_setopt(curl, CURLOPT_MAIL_FROM, mail_from.c_str()); + + curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadCallBack); + curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); + curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + + result = curl_easy_perform(curl); + + if (result != CURLE_OK) + { + fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(result)); + return false; + } + + curl_slist_free_all(recipients); + curl_easy_cleanup(curl); + return true; + } + + // + //Private methods + // + std::string MessageSender::GetText( std::string const& mail_from, std::string const& mail_to, std::list<std::string> const& cc, + std::string const& subject, std::string const& text ) const + { + auto text_decorator = std::make_shared<message_builder::Text>( text ); + text_decorator->Apply( std::make_shared<message_builder::Subject>( subject ) ) + .Apply( std::make_shared<message_builder::Cc>( cc ) ) + .Apply( std::make_shared<message_builder::From>( mail_from ) ) + .Apply( std::make_shared<message_builder::MailTo>( mail_to ) ) + .Apply( std::make_shared<message_builder::Date>() ); + return text_decorator->Get(); + } + + void MessageSender::FillRecipients( CURL* curl, std::string const& mail_to, std::list<std::string> const& cc, curl_slist* recipients ) + { + recipients = curl_slist_append( recipients, mail_to.c_str() ); + + for( const auto& recipient : cc ) + { + recipients = curl_slist_append( recipients, recipient.c_str() ); + } + + curl_easy_setopt( curl, CURLOPT_MAIL_RCPT, recipients ); + } + + std::string MessageSender::GetHostPortData() const + { + auto result = "smtp://" + mSettingsStorage.host; + if( !mSettingsStorage.port.empty() ) + { + result += ":" + mSettingsStorage.port; + } + return result; + } + + size_t MessageSender::ReadCallBack( void *ptr, size_t size, size_t nmemb, void *userp ) + { + struct WriteThis *pooh = reinterpret_cast<WriteThis*>( userp ); + if( size * nmemb < 1 ) + { + return 0; + } + if( pooh->counter++ > 0 ) + { + return 0; + } + memcpy( ptr, mText.c_str(), mText.size() ); + return mText.size(); + } +} diff --git a/src/message_sender.hpp b/src/message_sender.hpp new file mode 100644 index 0000000..0728f0e --- /dev/null +++ b/src/message_sender.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include <list> +#include <memory> + +#include <curl/curl.h> + +#include "settings_storage.hpp" + +namespace smtp +{ + struct WriteThis + { + int counter; + }; + + class MessageSender + { + public: + MessageSender( SettingsStorage const& settings_storage ); + ~MessageSender() = default; + + bool Send( std::string const& mail_from, std::string const& mail_to, std::list<std::string> const& cc, + std::string const& subject, std::string const& text ); + private: + std::string GetText( std::string const& mail_from, std::string const& mail_to, std::list<std::string> const& cc, + std::string const& subject, std::string const& textt ) const; + void InitSenders( std::string const& mail_from, std::list<std::string> const& mail_to ); + void FillRecipients( CURL* curl, std::string const& mail_to, std::list<std::string> const& cc, curl_slist* recipients ); + std::string GetHostPortData() const; + void ProcessSending(const std::string &mail_from, const std::list<std::string> &mail_to, const std::string &subject, const std::string &text); + timeval GetNowTime() const noexcept; + bool IsTimeOut( timeval const& start_time ) const noexcept; + long GetTimeDiff( timeval const& left, timeval const& right ) const noexcept; + timeval GetTimeout() const; + int ProcessHandle( timeval& timeout ) const; + void ClearPtrs(); + static size_t ReadCallBack( void *ptr, size_t size, size_t nmemb, void *userp ); + +// CURL *curl; +// CURLM *mcurl; + struct WriteThis pooh; + struct curl_slist* recipients = NULL; + SettingsStorage const& mSettingsStorage; + }; +} + + diff --git a/src/settings_storage.hpp b/src/settings_storage.hpp new file mode 100644 index 0000000..d442d6f --- /dev/null +++ b/src/settings_storage.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <string> + +namespace smtp +{ + struct SettingsStorage + { + std::string username; + std::string password; + std::string host; + std::string port; + }; +} diff --git a/src/smtp_service.cpp b/src/smtp_service.cpp new file mode 100644 index 0000000..6235e4c --- /dev/null +++ b/src/smtp_service.cpp @@ -0,0 +1,96 @@ +#include "smtp_service.hpp" +#include "message_sender.hpp" + +namespace smtp +{ + static constexpr char HOST_PROPERTY[] = "Host"; + static constexpr char USER_PROPERTY[] = "User"; + static constexpr char PORT_PROPERTY[] = "Port"; + + // + // Constructors + // + + SmtpService::SmtpService( ConnectionPtr connection ) + { + FillStorageByDefault(); + CreateService( connection ); + CreateInterface( connection ); + } + + // + // Private methods + // + + void SmtpService::FillStorageByDefault() + { + mStorage.host = ""; + mStorage.username = ""; + mStorage.password = ""; + mStorage.port = ""; + } + + void SmtpService::CreateService( ConnectionPtr connection ) + { + static constexpr char SMTP_BUS_NAME[] = "xyz.openbmc_project.SMTP"; + + connection->request_name( SMTP_BUS_NAME ); + } + + void SmtpService::CreateInterface( ConnectionPtr connection ) + { + static constexpr char SMTP_OBJECT_NAME[] = "/xyz/openbmc_project/SMTP"; + static constexpr char SMTP_INTERFACE_NAME[] = "xyz.openbmc_project.SMTP"; + + mObjectServer = std::make_shared<sdbusplus::asio::object_server>( connection ); + mInterface = mObjectServer->add_interface( SMTP_OBJECT_NAME, SMTP_INTERFACE_NAME ); + + AddProperties(); + AddMethods(); + + mInterface->initialize(); + } + + void SmtpService::AddProperties() + { + mInterface->register_property( HOST_PROPERTY, mStorage.host, sdbusplus::asio::PropertyPermission::readOnly ); + mInterface->register_property( USER_PROPERTY, mStorage.username, sdbusplus::asio::PropertyPermission::readOnly ); + mInterface->register_property( PORT_PROPERTY, mStorage.port, sdbusplus::asio::PropertyPermission::readOnly ); + } + + void SmtpService::AddMethods() + { + static constexpr char SMTP_SEND_MESSAGE_METHOD_NAME[] = "SendMail"; + static constexpr char SMTP_CHANGE_PARAMETERS_METHOD_NAME[] = "ChangeParameters"; + + mInterface->register_method(SMTP_SEND_MESSAGE_METHOD_NAME, [this]( std::string const& mail_from, + std::string const& mail_to, + std::list<std::string> const& cc, + std::string const& theme, + std::string const& text ) + { return MessageSender{ mStorage }.Send( mail_from, mail_to, cc, theme, text );}); + + + mInterface->register_method(SMTP_CHANGE_PARAMETERS_METHOD_NAME, [this]( std::string const& user, + std::string const& password, + std::string const& host, + std::string const& port ) + { return RefreshSettings(user, password, host, port);}); + } + + bool SmtpService::RefreshSettings(std::string const& user, + std::string const& password, + std::string const& host, + std::string const& port) + { + mStorage.username = user; + mStorage.password = password; + mStorage.host = host; + mStorage.port = port; + + mInterface->set_property(HOST_PROPERTY, host); + mInterface->set_property(USER_PROPERTY, user); + mInterface->set_property(PORT_PROPERTY, port); + return true; + } +} diff --git a/src/smtp_service.hpp b/src/smtp_service.hpp new file mode 100644 index 0000000..7149e3a --- /dev/null +++ b/src/smtp_service.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include <boost/asio/io_service.hpp> + +#include <sdbusplus/asio/connection.hpp> +#include <sdbusplus/asio/object_server.hpp> + +#include "settings_storage.hpp" + +namespace smtp +{ + using ConnectionPtr = std::shared_ptr<sdbusplus::asio::connection>; + using InterfacePtr = std::shared_ptr<sdbusplus::asio::dbus_interface>; + using ObjectServerPtr = std::shared_ptr<sdbusplus::asio::object_server>; + + class SmtpService + { + public: + SmtpService( ConnectionPtr connection ); + ~SmtpService() = default; + private: + void FillStorageByDefault(); + void CreateService( ConnectionPtr bus ); + void CreateInterface( ConnectionPtr connection ); + void AddProperties(); + void AddMethods(); + bool RefreshSettings(std::string const& user, + std::string const& password, + std::string const& host, + std::string const& port); + + InterfacePtr mInterface; + ObjectServerPtr mObjectServer; + SettingsStorage mStorage; + }; +} |