diff options
author | eportnov <eportnov@ibs.ru> | 2022-09-02 15:20:11 +0300 |
---|---|---|
committer | eportnov <eportnov@ibs.ru> | 2022-09-02 15:34:19 +0300 |
commit | 5572218ea878453ef86268b7fe7be2973272074b (patch) | |
tree | 7bd6242e8d929ca8872a5514c828d3478604a7b7 | |
parent | bb4b9659e72f1bbf25caab7701d81b7b0f20440c (diff) | |
download | openbmc-5572218ea878453ef86268b7fe7be2973272074b.tar.xz |
Add smtp client
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 5064f117ba..9e44a33192 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 @@ -21,7 +21,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 \ + " |