summaryrefslogtreecommitdiff
path: root/meta-ibs
diff options
context:
space:
mode:
authoreportnov <eportnov@ibs.ru>2022-09-02 15:32:25 +0300
committereportnov <eportnov@ibs.ru>2022-09-02 15:33:40 +0300
commite48fffd96e3623adf0a3756aaf869970bdc936dd (patch)
tree6b2912b88bf4ac5c44b6783140d81382c43a13a6 /meta-ibs
parent6c8befb66b45f29e8e287a249a2d1d2b22bebe8f (diff)
downloadopenbmc-e48fffd96e3623adf0a3756aaf869970bdc936dd.tar.xz
Add smtp client
Diffstat (limited to 'meta-ibs')
-rw-r--r--meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend2
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/00010-Add-smtp-client.patch637
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb_%.bbappend1
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/curl/curl_7.83.0.bbappend2
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/CMakeLists.txt118
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/main.cpp14
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/cc.cpp31
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/cc.hpp21
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/date.cpp16
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/date.hpp17
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/from.cpp22
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/from.hpp19
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/mail_to.cpp23
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/mail_to.hpp21
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/subject.cpp21
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/subject.hpp19
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/text.cpp24
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/text.hpp19
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/types/idecorator.hpp82
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/types/imessage_build.hpp14
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_sender.cpp123
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_sender.hpp48
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/settings_storage.hpp14
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/smtp_service.cpp96
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/smtp_service.hpp36
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/files/xyz.openbmc_project.SMTP.service9
-rw-r--r--meta-ibs/meta-cp2-5422/recipes-support/smtp/smtp.bb39
27 files changed, 1487 insertions, 1 deletions
diff --git a/meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend b/meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend
index a5cfc60634..f07e729095 100644
--- a/meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend
+++ b/meta-ibs/meta-common/recipes-ibs/images/obmc-phosphor-image.bbappend
@@ -23,7 +23,7 @@ IMAGE_INSTALL += " net-snmp-lib-agent \
net-snmp-server-snmptrapd \
"
-OBMC_IMAGE_EXTRA_INSTALL += " msmtp"
+OBMC_IMAGE_EXTRA_INSTALL += " smtp"
fix_shadow_perms() {
chgrp shadow ${IMAGE_ROOTFS}${sysconfdir}/shadow
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/00010-Add-smtp-client.patch b/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/00010-Add-smtp-client.patch
new file mode 100644
index 0000000000..7b0172c881
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb/00010-Add-smtp-client.patch
@@ -0,0 +1,637 @@
+From 77a6599736c27aae08f1b91f3b36c9b04808f563 Mon Sep 17 00:00:00 2001
+From: eportnov <eportnov@ibs.ru>
+Date: Fri, 2 Sep 2022 15:11:28 +0300
+Subject: [PATCH] Add smtp client
+
+---
+ meson.build | 4 +
+ redfish-core/include/redfish.hpp | 4 +-
+ .../include/registries/privilege_registry.hpp | 8 +
+ .../utils/smtp/change_parameters_parser.hpp | 27 +++
+ .../utils/smtp/send_message_parser.hpp | 29 +++
+ .../include/utils/smtp/types/iparser.hpp | 21 ++
+ redfish-core/lib/service_root.hpp | 1 +
+ redfish-core/lib/smtp.hpp | 191 ++++++++++++++++++
+ .../utils/smtp/change_parameters_parser.cpp | 62 ++++++
+ .../src/utils/smtp/send_message_parser.cpp | 76 +++++++
+ redfish-core/src/utils/smtp/types/iparser.cpp | 35 ++++
+ redfish-core/ut/smtp_reader_parser_test.cpp | 45 +++++
+ 12 files changed, 502 insertions(+), 1 deletion(-)
+ create mode 100644 redfish-core/include/utils/smtp/change_parameters_parser.hpp
+ create mode 100644 redfish-core/include/utils/smtp/send_message_parser.hpp
+ create mode 100644 redfish-core/include/utils/smtp/types/iparser.hpp
+ create mode 100644 redfish-core/lib/smtp.hpp
+ create mode 100644 redfish-core/src/utils/smtp/change_parameters_parser.cpp
+ create mode 100644 redfish-core/src/utils/smtp/send_message_parser.cpp
+ create mode 100644 redfish-core/src/utils/smtp/types/iparser.cpp
+ create mode 100644 redfish-core/ut/smtp_reader_parser_test.cpp
+
+diff --git a/meson.build b/meson.build
+index 45d440ef..3787e145 100644
+--- a/meson.build
++++ b/meson.build
+@@ -367,6 +367,9 @@ install_subdir('static', install_dir : 'share/www', strip_directory : true)
+ srcfiles_bmcweb = [
+ 'redfish-core/src/error_messages.cpp',
+ 'redfish-core/src/utils/json_utils.cpp',
++ 'redfish-core/src/utils/smtp/send_message_parser.cpp',
++ 'redfish-core/src/utils/smtp/change_parameters_parser.cpp',
++ 'redfish-core/src/utils/smtp/types/iparser.cpp',
+ 'src/boost_asio_ssl.cpp',
+ 'src/boost_asio.cpp',
+ 'src/boost_beast.cpp',
+@@ -409,6 +412,7 @@ srcfiles_unittest = [
+ 'redfish-core/ut/hex_utils_test.cpp',
+ 'redfish-core/ut/ip_utils_test.cpp',
+ 'redfish-core/ut/json_utils_test.cpp',
++ 'redfish-core/ut/smtp_reader_parser_test.cpp',
+ 'redfish-core/ut/lock_test.cpp',
+ 'redfish-core/ut/privileges_test.cpp',
+ 'redfish-core/ut/registries_test.cpp',
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index ab635f91..2854a745 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -47,6 +47,7 @@
+ #include "../lib/trigger.hpp"
+ #include "../lib/update_service.hpp"
+ #include "../lib/virtual_media.hpp"
++#include "../lib/smtp.hpp"
+
+ namespace redfish
+ {
+@@ -222,7 +223,8 @@ class RedfishService
+ requestRoutesMetricReport(app);
+ requestRoutesTriggerCollection(app);
+ requestRoutesTrigger(app);
+-
++ requestRoutesSmtp(app);
++ requestSmtpFunctions(app);
+ // Note, this must be the last route registered
+ requestRoutesRedfish(app);
+ }
+diff --git a/redfish-core/include/registries/privilege_registry.hpp b/redfish-core/include/registries/privilege_registry.hpp
+index 035aee4a..5ec62749 100644
+--- a/redfish-core/include/registries/privilege_registry.hpp
++++ b/redfish-core/include/registries/privilege_registry.hpp
+@@ -1363,6 +1363,14 @@ const static auto& postSimpleStorageCollection = privilegeSetConfigureComponents
+ const static auto& putSimpleStorageCollection = privilegeSetConfigureComponents;
+ const static auto& deleteSimpleStorageCollection = privilegeSetConfigureComponents;
+
++// SmtpCollection
++const static auto& getSmtpCollection = privilegeSetLogin;
++const static auto& headSmtpCollection = privilegeSetLogin;
++const static auto& patchSmtpCollection = privilegeSetConfigureComponents;
++const static auto& postSmtpCollection = privilegeSetConfigureComponents;
++const static auto& putSmtpCollection = privilegeSetConfigureComponents;
++const static auto& deleteSmtpCollection = privilegeSetConfigureComponents;
++
+ // SoftwareInventory
+ const static auto& getSoftwareInventory = privilegeSetLogin;
+ const static auto& headSoftwareInventory = privilegeSetLogin;
+diff --git a/redfish-core/include/utils/smtp/change_parameters_parser.hpp b/redfish-core/include/utils/smtp/change_parameters_parser.hpp
+new file mode 100644
+index 00000000..ee18b57b
+--- /dev/null
++++ b/redfish-core/include/utils/smtp/change_parameters_parser.hpp
+@@ -0,0 +1,27 @@
++#pragma once
++
++#include "types/iparser.hpp"
++
++namespace redfish::smtp::parser
++{
++ class ChangeParameters : public types::IParser
++ {
++ public:
++ explicit ChangeParameters( std::string const& function_with_parameters );
++ ~ChangeParameters() override = default;
++
++ std::string GetUser() const;
++ std::string GetPassword() const;
++ std::string GetHost() const;
++ std::string GetPort() const;
++
++ std::string GetMethodName() const override;
++ private:
++ void FillParams( types::ParserResult const& params );
++
++ std::string mUser;
++ std::string mPassword;
++ std::string mHost;
++ std::string mPort;
++ };
++}
+diff --git a/redfish-core/include/utils/smtp/send_message_parser.hpp b/redfish-core/include/utils/smtp/send_message_parser.hpp
+new file mode 100644
+index 00000000..8ae009cf
+--- /dev/null
++++ b/redfish-core/include/utils/smtp/send_message_parser.hpp
+@@ -0,0 +1,29 @@
++#pragma once
++
++#include "types/iparser.hpp"
++
++namespace redfish::smtp::parser
++{
++ class SendMessage : public types::IParser
++ {
++ public:
++ explicit SendMessage( std::string const& function_with_parameters );
++ ~SendMessage() override = default;
++
++ std::string GetFrom() const;
++ std::string GetTo() const;
++ std::list<std::string> GetCc() const;
++ std::string GetSubject() const;
++ std::string GetText() const;
++
++ std::string GetMethodName() const override;
++ private:
++ void FillParams( types::ParserResult const& params );
++
++ std::string mFrom;
++ std::string mTo;
++ std::list<std::string> mCc;
++ std::string mSubject;
++ std::string mText;
++ };
++}
+diff --git a/redfish-core/include/utils/smtp/types/iparser.hpp b/redfish-core/include/utils/smtp/types/iparser.hpp
+new file mode 100644
+index 00000000..0d9fe511
+--- /dev/null
++++ b/redfish-core/include/utils/smtp/types/iparser.hpp
+@@ -0,0 +1,21 @@
++#pragma once
++
++#include <string>
++#include <list>
++#include <unordered_map>
++
++namespace redfish::smtp::parser::types
++{
++ using ParserResult = std::unordered_multimap<std::string, std::string>;
++
++ class IParser
++ {
++ public:
++ virtual ~IParser() = default;
++
++ virtual std::string GetMethodName() const = 0;
++ protected:
++ std::list<std::string> ParseLine( std::string const& line, std::string const& delimiter );
++ ParserResult BuildParams(std::list<std::string> const& parsed_data);
++ };
++}
+diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp
+index 387b6141..aa97c91d 100644
+--- a/redfish-core/lib/service_root.hpp
++++ b/redfish-core/lib/service_root.hpp
+@@ -63,6 +63,7 @@ inline void
+ asyncResp->res.jsonValue["TelemetryService"]["@odata.id"] =
+ "/redfish/v1/TelemetryService";
+ asyncResp->res.jsonValue["Cables"]["@odata.id"] = "/redfish/v1/Cables";
++ asyncResp->res.jsonValue["Smtp"]["@odata.id"] = "/redfish/v1/Smtp";
+
+ nlohmann::json& protocolFeatures =
+ asyncResp->res.jsonValue["ProtocolFeaturesSupported"];
+diff --git a/redfish-core/lib/smtp.hpp b/redfish-core/lib/smtp.hpp
+new file mode 100644
+index 00000000..1bd798f7
+--- /dev/null
++++ b/redfish-core/lib/smtp.hpp
+@@ -0,0 +1,191 @@
++#include <app.hpp>
++#include <registries/privilege_registry.hpp>
++#include <query.hpp>
++
++#include <iostream>
++
++#include "utils/smtp/send_message_parser.hpp"
++#include "utils/smtp/change_parameters_parser.hpp"
++
++namespace redfish
++{
++ constexpr const char* SERVICE_PATH = "xyz.openbmc_project.SMTP";
++ constexpr const char* OBJECT_PATH = "/xyz/openbmc_project/SMTP";
++ constexpr const char* INTERFACE_PATH = "xyz.openbmc_project.SMTP";
++
++ namespace smtp
++ {
++ inline std::optional<std::string> GetFunctionName( std::string const& function_with_parameters )
++ {
++ static constexpr char FIRST_DELIMITER = '&';
++ static constexpr int ZERO_POSITION = 0;
++
++ auto position = function_with_parameters.find(FIRST_DELIMITER);
++ if( position == std::string::npos )
++ {
++ return {};
++ }
++ return function_with_parameters.substr( ZERO_POSITION, position );
++ }
++
++ inline void SendMail( std::string const& function_with_parameters, std::shared_ptr<bmcweb::AsyncResp> const& asyncResp )
++ {
++ auto parsing_result = parser::SendMessage{function_with_parameters};
++
++ crow::connections::systemBus->async_method_call([asyncResp](const boost::system::error_code& error_code, bool result){
++ if (error_code.value() == EBADR ||
++ error_code == boost::system::errc::host_unreachable)
++ {
++ BMCWEB_LOG_ERROR << "host unreachable " << error_code;
++ std::cout << "host unreachabler" << std::endl;
++ return;
++ }
++ if (error_code)
++ {
++ BMCWEB_LOG_ERROR << "respHandler DBus error " << error_code;
++ std::cout << "respHandler DBus error" << std::endl;
++ return;
++ }
++ asyncResp->res.jsonValue["result"] = result;
++ },
++ SERVICE_PATH, OBJECT_PATH, INTERFACE_PATH,
++ parsing_result.GetMethodName(),
++ parsing_result.GetFrom(),
++ parsing_result.GetTo(),
++ parsing_result.GetCc(),
++ parsing_result.GetSubject(),
++ parsing_result.GetText());
++ }
++
++ inline void ChangeParameters( std::string const& function_with_parameters, std::shared_ptr<bmcweb::AsyncResp> const& asyncResp )
++ {
++ auto parsing_result = parser::ChangeParameters{function_with_parameters};
++
++ crow::connections::systemBus->async_method_call([asyncResp](const boost::system::error_code& error_code, bool result){
++ if (error_code.value() == EBADR ||
++ error_code == boost::system::errc::host_unreachable)
++ {
++ BMCWEB_LOG_ERROR << "host unreachable " << error_code;
++ std::cout << "host unreachable" << std::endl;
++ return;
++ }
++ if (error_code)
++ {
++ BMCWEB_LOG_ERROR << "respHandler DBus error " << error_code;
++ std::cout << "respHandler DBus error" << std::endl;
++ return;
++ }
++ asyncResp->res.jsonValue["result"] = result;
++ },
++ SERVICE_PATH, OBJECT_PATH, INTERFACE_PATH,
++ parsing_result.GetMethodName(),
++ parsing_result.GetUser(),
++ parsing_result.GetPassword(),
++ parsing_result.GetHost(),
++ parsing_result.GetPort());
++ }
++ }
++
++ inline void FillResp(crow::Response& resp, const dbus::utility::DBusPropertiesMap& properties)
++ {
++ for (const auto& [propKey, propVariant] : properties)
++ {
++ if (propKey == "Host" )
++ {
++ auto host_as_string = std::get_if<std::string>(&propVariant);
++ if(host_as_string)
++ {
++ resp.jsonValue["host"] = *host_as_string;
++ }
++ }
++ if (propKey == "Port" )
++ {
++ auto port_as_string = std::get_if<std::string>(&propVariant);
++ if(port_as_string)
++ {
++ resp.jsonValue["port"] = *port_as_string;
++ }
++ }
++ if (propKey == "User" )
++ {
++ auto user_as_string = std::get_if<std::string>(&propVariant);
++ if(user_as_string)
++ {
++ resp.jsonValue["user"] = *user_as_string;
++ }
++ }
++ }
++ }
++
++ inline void requestRoutesSmtp(App& app)
++ {
++ BMCWEB_ROUTE(app, "/redfish/v1/Smtp/")
++ .privileges(redfish::privileges::getSmtpCollection)
++ .methods(boost::beast::http::verb::get)(
++ [&app](const crow::Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
++ {
++ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
++ {
++ return;
++ }
++
++ crow::connections::systemBus->async_method_call([asyncResp](const boost::system::error_code& error_code,
++ const dbus::utility::DBusPropertiesMap& properties)
++ {
++ if (error_code)
++ {
++ BMCWEB_LOG_DEBUG << "DBUS response error " << error_code;
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ FillResp(asyncResp->res, properties);
++ }, SERVICE_PATH, OBJECT_PATH, "org.freedesktop.DBus.Properties",
++ "GetAll", "xyz.openbmc_project.SMTP");
++
++ asyncResp->res.jsonValue["@odata.type"] ="#SmtpCollection";
++ asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Smtp";
++ asyncResp->res.jsonValue["Name"] = "Smtp Collection";
++ });
++ }
++
++
++
++ inline void requestSmtpFunctions(App& app)
++ {
++ BMCWEB_ROUTE(app, "/redfish/v1/Smtp/<str>/")
++ .privileges(redfish::privileges::getSmtpCollection)
++ .methods(boost::beast::http::verb::get)(
++ [&app](const crow::Request& req,
++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
++ const std::string& function_with_parameters)
++ {
++ static constexpr std::string_view SEND_MAIL_METHOD_NAME = "SendMail";
++ static constexpr std::string_view CHANGE_PARAMETERS_METHOD_NAME = "ChangeParameters";
++
++ if (!redfish::setUpRedfishRoute(app, req, asyncResp))
++ {
++ return;
++ }
++ auto function_name = smtp::GetFunctionName(function_with_parameters);
++ if(!function_name)
++ {
++ return;
++ }
++
++ asyncResp->res.jsonValue["@odata.type"] ="#SmtpCollection";
++ asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Smtp/" + *function_name;
++ asyncResp->res.jsonValue["Name"] = "Smtp Collection";
++
++ if(*function_name == SEND_MAIL_METHOD_NAME)
++ {
++ smtp::SendMail(function_with_parameters, asyncResp);
++ }
++ else if(*function_name == CHANGE_PARAMETERS_METHOD_NAME)
++ {
++ smtp::ChangeParameters(function_with_parameters, asyncResp);
++ }
++ });
++ }
++}
+diff --git a/redfish-core/src/utils/smtp/change_parameters_parser.cpp b/redfish-core/src/utils/smtp/change_parameters_parser.cpp
+new file mode 100644
+index 00000000..f78b9482
+--- /dev/null
++++ b/redfish-core/src/utils/smtp/change_parameters_parser.cpp
+@@ -0,0 +1,62 @@
++#include "utils/smtp/change_parameters_parser.hpp"
++
++namespace redfish::smtp::parser
++{
++ ChangeParameters::ChangeParameters( std::string const& function_with_parameters )
++ {
++ static const std::string DELIMITER_ON_LINE = "&";
++
++ auto params = BuildParams(ParseLine(function_with_parameters, DELIMITER_ON_LINE));
++ FillParams( params );
++ }
++
++ std::string ChangeParameters::GetUser() const
++ {
++ return mUser;
++ }
++ std::string ChangeParameters::GetPassword() const
++ {
++ return mPassword;
++ }
++ std::string ChangeParameters::GetHost() const
++ {
++ return mHost;
++ }
++ std::string ChangeParameters::GetPort() const
++ {
++ return mPort;
++ }
++
++ std::string ChangeParameters::GetMethodName() const
++ {
++ constexpr const char* CHANGE_METHOD_NAME = "ChangeParameters";
++ return CHANGE_METHOD_NAME;
++ }
++
++ void ChangeParameters::FillParams( types::ParserResult const& params )
++ {
++ auto user = params.find("user");
++ if(user != params.end())
++ {
++ mUser = (*user).second;
++ }
++
++ auto password = params.find("password");
++ if(password != params.end())
++ {
++ mPassword = (*password).second;
++ }
++
++ auto host = params.find("host");
++ if(host != params.end())
++ {
++ mHost = (*host).second;
++ }
++
++ auto port = params.find("port");
++ if(port != params.end())
++ {
++ mPort = (*port).second;
++ }
++ }
++}
+diff --git a/redfish-core/src/utils/smtp/send_message_parser.cpp b/redfish-core/src/utils/smtp/send_message_parser.cpp
+new file mode 100644
+index 00000000..0904a3e4
+--- /dev/null
++++ b/redfish-core/src/utils/smtp/send_message_parser.cpp
+@@ -0,0 +1,76 @@
++#include "utils/smtp/send_message_parser.hpp"
++
++namespace redfish::smtp::parser
++{
++ SendMessage::SendMessage( std::string const& function_with_parameters )
++ {
++ static const std::string DELIMITER_ON_LINE = "&";
++
++ auto params = BuildParams(ParseLine(function_with_parameters, DELIMITER_ON_LINE));
++ FillParams( params );
++ }
++
++ std::string SendMessage::GetFrom() const
++ {
++ return mFrom;
++ }
++
++ std::string SendMessage::GetTo() const
++ {
++ return mTo;
++ }
++
++ std::list<std::string> SendMessage::GetCc() const
++ {
++ return mCc;
++ }
++
++ std::string SendMessage::GetSubject() const
++ {
++ return mSubject;
++ }
++
++ std::string SendMessage::GetText() const
++ {
++ return mText;
++ }
++
++ std::string SendMessage::GetMethodName() const
++ {
++ constexpr const char* SEND_METHOD_NAME = "SendMail";
++ return SEND_METHOD_NAME;
++ }
++
++ void SendMessage::FillParams( types::ParserResult const& params )
++ {
++ auto from = params.find("from");
++ if(from != params.end())
++ {
++ mFrom = (*from).second;
++ }
++
++ auto to = params.find("to");
++ if(to != params.end())
++ {
++ mTo = (*to).second;
++ }
++
++ auto cc = params.equal_range("cc");
++ for(auto it = cc.first; it != cc.second; ++it)
++ {
++ mCc.push_back( (*it).second );
++ }
++
++ auto subject = params.find("subject");
++ if(subject != params.end())
++ {
++ mSubject = (*subject).second;
++ }
++
++ auto text = params.find("text");
++ if(text != params.end())
++ {
++ mText = (*text).second;
++ }
++ }
++}
+diff --git a/redfish-core/src/utils/smtp/types/iparser.cpp b/redfish-core/src/utils/smtp/types/iparser.cpp
+new file mode 100644
+index 00000000..ac95b967
+--- /dev/null
++++ b/redfish-core/src/utils/smtp/types/iparser.cpp
+@@ -0,0 +1,35 @@
++#include "utils/smtp/types/iparser.hpp"
++
++namespace redfish::smtp::parser::types
++{
++ std::list<std::string> IParser::ParseLine( std::string const& line, std::string const& delimiter )
++ {
++ std::list<std::string> result;
++
++ auto start = 0U;
++ auto end = line.find(delimiter);
++ while(end != std::string::npos)
++ {
++ auto parsed = line.substr(start, end - start);
++ result.push_back(parsed);
++ start = end + delimiter.length();
++ end = line.find(delimiter, start);
++ }
++ auto parsed = line.substr(start, end);
++ result.push_back(parsed);
++ return result;
++ }
++
++ ParserResult IParser::BuildParams(std::list<std::string> const& parsed_data)
++ {
++ static const std::string DELIMITER_ON_PARAMETER = "=";
++
++ std::unordered_multimap<std::string, std::string> result;
++ for(const auto& not_parsed_param : parsed_data)
++ {
++ auto param_pair = ParseLine( not_parsed_param, DELIMITER_ON_PARAMETER );
++ result.insert( {param_pair.front(), param_pair.back()} );
++ }
++ return result;
++ }
++}
+diff --git a/redfish-core/ut/smtp_reader_parser_test.cpp b/redfish-core/ut/smtp_reader_parser_test.cpp
+new file mode 100644
+index 00000000..67a6645c
+--- /dev/null
++++ b/redfish-core/ut/smtp_reader_parser_test.cpp
+@@ -0,0 +1,45 @@
++#include "utils/smtp/send_message_parser.hpp"
++#include "utils/smtp/change_parameters_parser.hpp"
++#include "smtp.hpp"
++
++#include <string>
++
++#include <gmock/gmock.h>
++#include <gtest/gtest.h>
++
++namespace redfish::json_util
++{
++namespace
++{
++
++using ::testing::ElementsAre;
++
++TEST(SmtpReaderParser, SendMessage)
++{
++ smtp::parser::SendMessage message_parser{"SendMail&from=claiff@mail.ru&to=claiff1990@gmail.com&cc=claiff@mail.ru&cc=claiff@mail.com&subject=theme&text=text"};
++ EXPECT_EQ(message_parser.GetFrom(), "claiff@mail.ru");
++ ASSERT_THAT(message_parser.GetCc(), ElementsAre("claiff@mail.com", "claiff@mail.ru"));
++ EXPECT_EQ(message_parser.GetTo(), "claiff1990@gmail.com");
++ EXPECT_EQ(message_parser.GetSubject(), "theme");
++ EXPECT_EQ(message_parser.GetText(), "text");
++ EXPECT_EQ(message_parser.GetMethodName(), "SendMail");
++}
++
++TEST(SmtpReaderParser, ChangeParameters)
++{
++ smtp::parser::ChangeParameters message_parser{"ChangeParameters&user=claiff@mail.ru&password=32311&host=smtp.mail.ru&port=465"};
++ EXPECT_EQ(message_parser.GetUser(), "claiff@mail.ru");
++ EXPECT_EQ(message_parser.GetPassword(), "32311");
++ EXPECT_EQ(message_parser.GetHost(), "smtp.mail.ru");
++ EXPECT_EQ(message_parser.GetPort(), "465");
++}
++
++TEST(SmtpReaderParser, GetFunctionName)
++{
++ static constexpr std::string_view MESSAGE = "ChangeParameters&user=claiff@mail.ru&password=32311&host=smtp.mail.ru&port=465";
++ auto result = smtp::GetFunctionName(MESSAGE.data());
++ EXPECT_EQ(result, "ChangeParameters");
++}
++
++} // namespace
++} // namespace redfish::json_util
diff --git a/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb_%.bbappend b/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb_%.bbappend
index 1671177ac5..29a8481044 100644
--- a/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb_%.bbappend
+++ b/meta-ibs/meta-cp2-5422/recipes-phosphor/interfaces/bmcweb_%.bbappend
@@ -10,6 +10,7 @@ SRC_URI += "\
file://0007-Removed-non-working-boot-override-modes.patch \
file://0008-Add-pcie-device-names.patch \
file://0009-fix-circular-buffer-telemetry.patch \
+ file://00010-Add-smtp-client.patch \
"
EXTRA_OEMESON += "\
diff --git a/meta-ibs/meta-cp2-5422/recipes-support/curl/curl_7.83.0.bbappend b/meta-ibs/meta-cp2-5422/recipes-support/curl/curl_7.83.0.bbappend
new file mode 100644
index 0000000000..152c55ddb2
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/curl/curl_7.83.0.bbappend
@@ -0,0 +1,2 @@
+FILESEXTRAPATHS:append := "${THISDIR}/${PN}:"
+PACKAGECONFIG:append = " smtp"
diff --git a/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/CMakeLists.txt b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/CMakeLists.txt
new file mode 100644
index 0000000000..4d93f95770
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/CMakeLists.txt
@@ -0,0 +1,118 @@
+cmake_minimum_required(VERSION 3.5)
+
+project(smtp LANGUAGES CXX)
+
+cmake_policy(SET CMP0054 NEW)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -fno-rtti")
+# Silence sdbusplus warnings
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -flto")
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -O0")
+
+if(NOT ${YOCTO_DEPENDENCIES})
+ include(ExternalProject)
+
+ ExternalProject_Add(
+ Boost
+ URL "https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/boost_1_76_0.tar.bz2"
+ URL_MD5 "33334dd7f862e8ac9fe1cc7c6584fb6d"
+ SOURCE_DIR ${CMAKE_BINARY_DIR}/src/boost
+ BINARY_DIR ${CMAKE_BINARY_DIR}/libs/boost
+ CONFIGURE_COMMAND cd <SOURCE_DIR> && ./bootstrap.sh
+ BUILD_COMMAND cd <SOURCE_DIR> && ./b2 --exec-prefix=<BINARY_DIR>
+ --prefix=<BINARY_DIR> --with-system --with-coroutine install
+ INSTALL_COMMAND ""
+ UPDATE_COMMAND "")
+
+ set(CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/libs/boost/ ${CMAKE_PREFIX_PATH})
+ include_directories(SYSTEM ${CMAKE_BINARY_DIR}/libs/boost/include)
+ link_directories(SYSTEM ${CMAKE_BINARY_DIR}/libs/boost/lib)
+
+ ExternalProject_Add(
+ sdbusplus-project
+ PREFIX ${CMAKE_BINARY_DIR}/sdbusplus-project
+ GIT_REPOSITORY https://github.com/openbmc/sdbusplus.git
+ GIT_TAG afe80cf2e5dc4aefe3b041adeb0230e61929bf12
+ SOURCE_DIR ${CMAKE_BINARY_DIR}/sdbusplus-src
+ BINARY_DIR ${CMAKE_BINARY_DIR}/sdbusplus-build
+ CONFIGURE_COMMAND ""
+ BUILD_COMMAND cd ${CMAKE_BINARY_DIR}/sdbusplus-src && ./bootstrap.sh &&
+ ./configure --enable-transaction && make -j libsdbusplus.la
+ INSTALL_COMMAND ""
+ LOG_DOWNLOAD ON
+ UPDATE_COMMAND "")
+
+ include_directories(${CMAKE_BINARY_DIR}/sdbusplus-src)
+ link_directories(${CMAKE_BINARY_DIR}/sdbusplus-src/.libs)
+
+ # Boost related definitions
+ add_definitions(-DBOOST_COROUTINES_NO_DEPRECATION_WARNING)
+ add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY)
+ add_definitions(-DBOOST_SYSTEM_NO_DEPRECATED)
+ add_definitions(-DBOOST_ALL_NO_LIB)
+ add_definitions(-DBOOST_NO_RTTI)
+ add_definitions(-DBOOST_NO_TYPEID)
+ add_definitions(-DBOOST_ASIO_DISABLE_THREADS)
+else()
+ # Include Boost library. This allows specify exact version of BOOST to be
+ # used, especially important while using valgrind, to point BOOST that is
+ # compiled with valgrind support
+ if(${BOOST_VERSION})
+ find_package(Boost ${BOOST_VERSION} EXACT)
+ else()
+ find_package(Boost 1.69 REQUIRED COMPONENTS coroutine context)
+ endif()
+ message("++ Using Boost version: " ${Boost_VERSION})
+
+ include_directories(${Boost_INCLUDE_DIRS})
+ link_directories(${Boost_LIBRARY_DIRS})
+endif()
+
+include_directories(src)
+
+set(SRC_DIR src)
+set(SRC_FILES
+ ${SRC_DIR}/main.cpp
+ ${SRC_DIR}/smtp_service.cpp
+ ${SRC_DIR}/smtp_service.hpp
+ ${SRC_DIR}/message_sender.hpp
+ ${SRC_DIR}/message_sender.cpp
+ ${SRC_DIR}/settings_storage.hpp
+
+ ${SRC_DIR}/message_builder/date.hpp
+ ${SRC_DIR}/message_builder/date.cpp
+ ${SRC_DIR}/message_builder/mail_to.hpp
+ ${SRC_DIR}/message_builder/mail_to.cpp
+ ${SRC_DIR}/message_builder/cc.hpp
+ ${SRC_DIR}/message_builder/cc.cpp
+ ${SRC_DIR}/message_builder/subject.hpp
+ ${SRC_DIR}/message_builder/subject.cpp
+ ${SRC_DIR}/message_builder/text.hpp
+ ${SRC_DIR}/message_builder/text.cpp
+ ${SRC_DIR}/message_builder/from.hpp
+ ${SRC_DIR}/message_builder/from.cpp
+
+ ${SRC_DIR}/message_builder/types/idecorator.hpp
+ )
+
+add_executable(smtp ${SRC_FILES})
+if(NOT ${YOCTO_DEPENDENCIES})
+ add_dependencies(smtp sdbusplus-project)
+endif()
+target_link_libraries(smtp boost_context)
+target_link_libraries(smtp sdbusplus)
+target_link_libraries(smtp systemd)
+target_link_libraries(smtp curl)
+
+#target_link_libraries(curl_smtp curl)
+#target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})
+#target_link_libraries (${PROJECT_NAME} ${SDBUSPLUSPLUS_LIBRARIES}
+# phosphor_logging)
+install(TARGETS smtp DESTINATION bin)
+install(FILES ${PROJECT_SOURCE_DIR}/xyz.openbmc_project.SMTP.service
+ DESTINATION /lib/systemd/system/)
diff --git a/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/main.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/main.cpp
new file mode 100644
index 0000000000..ba2848da3e
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/cc.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/cc.cpp
new file mode 100644
index 0000000000..c686ef2057
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/cc.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/cc.hpp
new file mode 100644
index 0000000000..5062c370ad
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/date.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/date.cpp
new file mode 100644
index 0000000000..96ee2e155d
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/date.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/date.hpp
new file mode 100644
index 0000000000..00fb6cbb15
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/from.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/from.cpp
new file mode 100644
index 0000000000..094e1a2fa4
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/from.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/from.hpp
new file mode 100644
index 0000000000..4605469b87
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/mail_to.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/mail_to.cpp
new file mode 100644
index 0000000000..c73e2a7888
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/mail_to.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/mail_to.hpp
new file mode 100644
index 0000000000..0245fd69a6
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/subject.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/subject.cpp
new file mode 100644
index 0000000000..84e7e43e07
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/subject.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/subject.hpp
new file mode 100644
index 0000000000..bf8bfab591
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/text.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/text.cpp
new file mode 100644
index 0000000000..e5e6bf069c
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/text.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/text.hpp
new file mode 100644
index 0000000000..4df90e15c9
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/types/idecorator.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/types/idecorator.hpp
new file mode 100644
index 0000000000..3fabcd4902
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/types/imessage_build.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_builder/types/imessage_build.hpp
new file mode 100644
index 0000000000..4c4f1b8be1
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_sender.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_sender.cpp
new file mode 100644
index 0000000000..5b2950ca7f
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_sender.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/message_sender.hpp
new file mode 100644
index 0000000000..0728f0ee1f
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/settings_storage.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/settings_storage.hpp
new file mode 100644
index 0000000000..d442d6ff1f
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/smtp_service.cpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/smtp_service.cpp
new file mode 100644
index 0000000000..6235e4c8ca
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/smtp_service.hpp b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/src/smtp_service.hpp
new file mode 100644
index 0000000000..7149e3aef6
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/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;
+ };
+}
diff --git a/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/xyz.openbmc_project.SMTP.service b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/xyz.openbmc_project.SMTP.service
new file mode 100644
index 0000000000..a7c89ef9c0
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/files/xyz.openbmc_project.SMTP.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=SMTP client
+
+[Service]
+ExecStart=/usr/bin/smtp
+Type=oneshot
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-ibs/meta-cp2-5422/recipes-support/smtp/smtp.bb b/meta-ibs/meta-cp2-5422/recipes-support/smtp/smtp.bb
new file mode 100644
index 0000000000..13df29f92d
--- /dev/null
+++ b/meta-ibs/meta-cp2-5422/recipes-support/smtp/smtp.bb
@@ -0,0 +1,39 @@
+SUMMARY = "Simple SMTP client"
+DESCRIPTION = "Simple SMTP client"
+
+S = "${WORKDIR}"
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "\
+ file://${IBSBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658 \
+ "
+
+SYSTEMD_SERVICE:${PN} = "xyz.openbmc_project.SMTP.service"
+
+DEPENDS = "boost systemd sdbusplus curl"
+
+inherit cmake systemd
+
+SRC_URI = "file://xyz.openbmc_project.SMTP.service \
+ file://CMakeLists.txt \
+ file://src/main.cpp \
+ file://src/smtp_service.cpp \
+ file://src/smtp_service.hpp \
+ file://src/message_sender.cpp \
+ file://src/message_sender.hpp \
+ file://src/settings_storage.hpp \
+ file://src/message_builder/cc.hpp \
+ file://src/message_builder/cc.cpp \
+ file://src/message_builder/date.hpp \
+ file://src/message_builder/date.cpp \
+ file://src/message_builder/mail_to.hpp \
+ file://src/message_builder/mail_to.cpp \
+ file://src/message_builder/from.hpp \
+ file://src/message_builder/from.cpp \
+ file://src/message_builder/subject.hpp \
+ file://src/message_builder/subject.cpp \
+ file://src/message_builder/text.hpp \
+ file://src/message_builder/text.cpp \
+ file://src/message_builder/types/idecorator.hpp \
+ file://src/message_builder/types/imessage_build.hpp \
+ "