summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreportnov <eportnov@ibs.ru>2022-09-09 11:10:14 +0300
committereportnov <eportnov@ibs.ru>2022-09-09 12:41:59 +0300
commit9fa4addff6f90a8b5697a594e034f5517d64dd25 (patch)
treeb429545eba770ea5aadd030b40f62ca8ab5b208a
downloadobmc-sila-smtp-9fa4addff6f90a8b5697a594e034f5517d64dd25.tar.xz
first comit
-rw-r--r--.gitignore6
-rw-r--r--CMakeLists.txt118
-rw-r--r--LICENSE201
-rw-r--r--src/main.cpp14
-rw-r--r--src/message_builder/cc.cpp31
-rw-r--r--src/message_builder/cc.hpp21
-rw-r--r--src/message_builder/date.cpp16
-rw-r--r--src/message_builder/date.hpp17
-rw-r--r--src/message_builder/from.cpp22
-rw-r--r--src/message_builder/from.hpp19
-rw-r--r--src/message_builder/mail_to.cpp23
-rw-r--r--src/message_builder/mail_to.hpp21
-rw-r--r--src/message_builder/subject.cpp21
-rw-r--r--src/message_builder/subject.hpp19
-rw-r--r--src/message_builder/text.cpp24
-rw-r--r--src/message_builder/text.hpp19
-rw-r--r--src/message_builder/types/idecorator.hpp82
-rw-r--r--src/message_builder/types/imessage_build.hpp14
-rw-r--r--src/message_sender.cpp123
-rw-r--r--src/message_sender.hpp48
-rw-r--r--src/settings_storage.hpp14
-rw-r--r--src/smtp_service.cpp96
-rw-r--r--src/smtp_service.hpp36
-rw-r--r--xyz.openbmc_project.SMTP.service9
24 files changed, 1014 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f7055ff
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+*.*
+!*.cpp
+!*.hpp
+!*.service
+!CMakeLists.txt
+!.gitignore
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..4d93f95
--- /dev/null
+++ b/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/LICENSE b/LICENSE
new file mode 100644
index 0000000..8dada3e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..ba2848d
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,14 @@
+#include <sdbusplus/asio/connection.hpp>
+
+#include "smtp_service.hpp"
+
+int main()
+{
+ boost::asio::io_service io_context;
+
+ auto connection = std::make_shared<sdbusplus::asio::connection>( io_context );
+ smtp::SmtpService smtp{ connection };
+
+ io_context.run();
+ return 0;
+}
diff --git a/src/message_builder/cc.cpp b/src/message_builder/cc.cpp
new file mode 100644
index 0000000..c686ef2
--- /dev/null
+++ b/src/message_builder/cc.cpp
@@ -0,0 +1,31 @@
+#include "cc.hpp"
+
+namespace smtp::message_builder
+{
+ Cc::Cc( std::list<std::string> const& mail_to )
+ : mMailTo( mail_to )
+ {
+
+ }
+
+ std::string Cc::Get() const
+ {
+ std::string result;
+ if( mBase )
+ {
+ result = mBase->Get();
+ }
+
+ if( mMailTo.empty() )
+ {
+ return result;
+ }
+
+ for(const auto& cc : mMailTo)
+ {
+ result += "Cc: " + cc + "\r\n";
+ }
+
+ return result;
+ }
+}
diff --git a/src/message_builder/cc.hpp b/src/message_builder/cc.hpp
new file mode 100644
index 0000000..5062c37
--- /dev/null
+++ b/src/message_builder/cc.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <list>
+
+#include "types/idecorator.hpp"
+#include "types/imessage_build.hpp"
+
+namespace smtp::message_builder
+{
+ class Cc : public types::IDecorator<types::IMessageBuilder>
+ {
+ public:
+ explicit Cc( std::list<std::string> const& mail_to );
+ ~Cc() override = default;
+
+ std::string Get() const override;
+ private:
+ std::list<std::string> const& mMailTo;
+ };
+}
+
diff --git a/src/message_builder/date.cpp b/src/message_builder/date.cpp
new file mode 100644
index 0000000..96ee2e1
--- /dev/null
+++ b/src/message_builder/date.cpp
@@ -0,0 +1,16 @@
+#include "date.hpp"
+
+namespace smtp::message_builder
+{
+ std::string Date::Get() const
+ {
+ std::string result;
+
+ if( mBase )
+ {
+ result = mBase->Get();
+ }
+ result += "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n";
+ return result;
+ }
+}
diff --git a/src/message_builder/date.hpp b/src/message_builder/date.hpp
new file mode 100644
index 0000000..00fb6cb
--- /dev/null
+++ b/src/message_builder/date.hpp
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "types/idecorator.hpp"
+#include "types/imessage_build.hpp"
+
+namespace smtp::message_builder
+{
+ class Date : public types::IDecorator<types::IMessageBuilder>
+ {
+ public:
+ Date() = default;
+ ~Date() override = default;
+
+ std::string Get() const override;
+ };
+}
+
diff --git a/src/message_builder/from.cpp b/src/message_builder/from.cpp
new file mode 100644
index 0000000..094e1a2
--- /dev/null
+++ b/src/message_builder/from.cpp
@@ -0,0 +1,22 @@
+#include "from.hpp"
+
+namespace smtp::message_builder
+{
+
+ From::From( std::string const& mail_to )
+ :mMailTo( mail_to )
+ {
+
+ }
+
+ std::string From::Get() const
+ {
+ std::string result;
+ if( mBase )
+ {
+ result = mBase->Get();
+ }
+ result += "From: " + mMailTo + "\r\n";
+ return result;
+ }
+}
diff --git a/src/message_builder/from.hpp b/src/message_builder/from.hpp
new file mode 100644
index 0000000..4605469
--- /dev/null
+++ b/src/message_builder/from.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "types/idecorator.hpp"
+#include "types/imessage_build.hpp"
+
+namespace smtp::message_builder
+{
+ class From : public types::IDecorator<types::IMessageBuilder>
+ {
+ public:
+ explicit From( std::string const& mail_to );
+ ~From() override = default;
+
+ std::string Get() const override;
+ private:
+ std::string const& mMailTo;
+ };
+}
+
diff --git a/src/message_builder/mail_to.cpp b/src/message_builder/mail_to.cpp
new file mode 100644
index 0000000..c73e2a7
--- /dev/null
+++ b/src/message_builder/mail_to.cpp
@@ -0,0 +1,23 @@
+#include "mail_to.hpp"
+
+namespace smtp::message_builder
+{
+ MailTo::MailTo( std::string const& mail_to)
+ : mMailTo( mail_to )
+ {
+
+ }
+
+ std::string MailTo::Get() const
+ {
+ std::string result;
+ if( mBase )
+ {
+ result = mBase->Get();
+ }
+
+ result += "To: " + mMailTo +"\r\n";
+
+ return result;
+ }
+}
diff --git a/src/message_builder/mail_to.hpp b/src/message_builder/mail_to.hpp
new file mode 100644
index 0000000..0245fd6
--- /dev/null
+++ b/src/message_builder/mail_to.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <list>
+
+#include "types/idecorator.hpp"
+#include "types/imessage_build.hpp"
+
+namespace smtp::message_builder
+{
+ class MailTo : public types::IDecorator<types::IMessageBuilder>
+ {
+ public:
+ explicit MailTo( std::string const& mail_to );
+ ~MailTo() override = default;
+
+ std::string Get() const override;
+ private:
+ std::string const& mMailTo;
+ };
+}
+
diff --git a/src/message_builder/subject.cpp b/src/message_builder/subject.cpp
new file mode 100644
index 0000000..84e7e43
--- /dev/null
+++ b/src/message_builder/subject.cpp
@@ -0,0 +1,21 @@
+#include "subject.hpp"
+
+namespace smtp::message_builder
+{
+ Subject::Subject( std::string const& subject )
+ : mSubject(subject)
+ {
+
+ }
+
+ std::string Subject::Get() const
+ {
+ std::string result;
+ if( mBase )
+ {
+ result = mBase->Get();
+ }
+ result += "Subject: " + mSubject + "\r\n";
+ return result;
+ }
+}
diff --git a/src/message_builder/subject.hpp b/src/message_builder/subject.hpp
new file mode 100644
index 0000000..bf8bfab
--- /dev/null
+++ b/src/message_builder/subject.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "types/idecorator.hpp"
+#include "types/imessage_build.hpp"
+
+namespace smtp::message_builder
+{
+ class Subject : public types::IDecorator<types::IMessageBuilder>
+ {
+ public:
+ explicit Subject( std::string const& subject );
+ ~Subject() override = default;
+
+ std::string Get() const override;
+ private:
+ std::string const& mSubject;
+ };
+}
+
diff --git a/src/message_builder/text.cpp b/src/message_builder/text.cpp
new file mode 100644
index 0000000..e5e6bf0
--- /dev/null
+++ b/src/message_builder/text.cpp
@@ -0,0 +1,24 @@
+#include "text.hpp"
+
+namespace smtp::message_builder
+{
+ Text::Text( std::string const& text)
+ : mText( text )
+ {
+
+ }
+
+ std::string Text::Get() const
+ {
+ std::string result;
+ if( mBase )
+ {
+ result = mBase->Get();
+ }
+
+ result += "\r\n";
+ result += mText + "\r\n";
+
+ return result;
+ }
+}
diff --git a/src/message_builder/text.hpp b/src/message_builder/text.hpp
new file mode 100644
index 0000000..4df90e1
--- /dev/null
+++ b/src/message_builder/text.hpp
@@ -0,0 +1,19 @@
+#pragma once
+
+#include "types/idecorator.hpp"
+#include "types/imessage_build.hpp"
+
+namespace smtp::message_builder
+{
+ class Text : public types::IDecorator<types::IMessageBuilder>
+ {
+ public:
+ explicit Text( std::string const& text );
+ ~Text() override = default;
+
+ std::string Get() const override;
+ private:
+ std::string const& mText;
+ };
+}
+
diff --git a/src/message_builder/types/idecorator.hpp b/src/message_builder/types/idecorator.hpp
new file mode 100644
index 0000000..3fabcd4
--- /dev/null
+++ b/src/message_builder/types/idecorator.hpp
@@ -0,0 +1,82 @@
+#pragma once
+
+#include <memory>
+
+namespace smtp::message_builder::types
+{
+
+/**
+ * @brief Базовый интерфейс описания декоратора
+ * @details См. https://refactoring.guru/ru/design-patterns/decorator
+ * @tparam T Тип декорируемого класса, T должен обладать возможностью наследования (в том числе виртуальный деструктор)
+ */
+ template < typename T, typename TPointerType = std::shared_ptr<T> > class IDecorator : public T
+ {
+ public:
+ using PointerType = TPointerType;
+ using Type = IDecorator<T, TPointerType>;
+
+ ~IDecorator() override = default;
+
+ /**
+ * @brief Установить указатель на декорируемый класс
+ * @details По возможности используйте метод Apply() как наиболее универсальный
+ * @param base Указатель на декорируемый класс
+ */
+ void SetBase( PointerType const& base ) noexcept
+ {
+ mBase = base;
+ }
+
+ void SetBase( PointerType&& base ) noexcept
+ {
+ mBase = std::move( base );
+ }
+
+ /**
+ * @brief Установить указатель на декорируемый класс (цепочка обязанностей)
+ * @details См. https://refactoring.guru/ru/design-patterns/chain-of-responsibility/cpp/example
+ * @details Цепь вызовов: декоратор1 -> декоратор2 -> базовый класс
+ * @param base_or_decorator Указатель на декорируемый класс или целевой декоратор
+ */
+ Type& Apply( PointerType const& base_or_decorator ) noexcept
+ {
+ if( !base_or_decorator )
+ {
+ return *this;
+ }
+
+ SetBase( base_or_decorator );
+ return GetApplyResult();
+ }
+
+ Type& Apply( PointerType&& base_or_decorator ) noexcept
+ {
+ if( !base_or_decorator )
+ {
+ return *this;
+ }
+
+ SetBase( std::move( base_or_decorator ) );
+ return GetApplyResult();
+ }
+
+ private:
+ Type& GetApplyResult() noexcept
+ {
+ auto as_decorator = dynamic_cast< Type * >( mBase.get() );
+ if( as_decorator )
+ {
+ return *as_decorator;
+ }
+
+ return *this;
+ }
+
+ protected:
+ PointerType mBase;
+ };
+
+ template < typename T, typename TDeleter = std::default_delete<T> > using IDecoratorUnique = IDecorator<T, std::unique_ptr<T, TDeleter> >;
+
+} // namespace sbis::devices::generic::types
diff --git a/src/message_builder/types/imessage_build.hpp b/src/message_builder/types/imessage_build.hpp
new file mode 100644
index 0000000..4c4f1b8
--- /dev/null
+++ b/src/message_builder/types/imessage_build.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <string>
+
+namespace smtp::message_builder::types
+{
+ class IMessageBuilder
+ {
+ public:
+ virtual ~IMessageBuilder() = default;
+
+ virtual std::string Get() const = 0;
+ };
+}
diff --git a/src/message_sender.cpp b/src/message_sender.cpp
new file mode 100644
index 0000000..5b2950c
--- /dev/null
+++ b/src/message_sender.cpp
@@ -0,0 +1,123 @@
+#include <string.h>
+
+#include "message_sender.hpp"
+#include "message_builder/date.hpp"
+#include "message_builder/mail_to.hpp"
+#include "message_builder/cc.hpp"
+#include "message_builder/subject.hpp"
+#include "message_builder/text.hpp"
+#include "message_builder/from.hpp"
+
+namespace smtp
+{
+ static std::string mText = "";
+
+ //
+ // Constructors/Destructors
+ //
+ MessageSender::MessageSender( SettingsStorage const& settings_storage )
+ : mSettingsStorage( settings_storage )
+ {
+
+ }
+
+ //
+ //Public methods
+ //
+ bool MessageSender::Send( std::string const& mail_from, std::string const& mail_to, std::list<std::string> const& cc,
+ std::string const& subject, std::string const& text )
+ {
+ CURLcode result = CURLE_OK;
+
+ struct curl_slist *recipients = NULL;
+ struct WriteThis upload_ctx;
+
+ upload_ctx.counter = 0;
+
+ auto curl = curl_easy_init();
+
+ if( !curl )
+ {
+ //Error
+ return false;
+ }
+ mText = GetText( mail_from, mail_to, cc, subject, text);
+ FillRecipients( curl, mail_to, cc, recipients );
+
+ curl_easy_setopt(curl, CURLOPT_USERNAME, mSettingsStorage.username.c_str());
+ curl_easy_setopt(curl, CURLOPT_PASSWORD, mSettingsStorage.password.c_str());
+ curl_easy_setopt(curl, CURLOPT_URL, GetHostPortData().c_str());
+
+ curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
+ curl_easy_setopt(curl, CURLOPT_MAIL_FROM, mail_from.c_str());
+
+ curl_easy_setopt(curl, CURLOPT_READFUNCTION, ReadCallBack);
+ curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+ result = curl_easy_perform(curl);
+
+ if (result != CURLE_OK)
+ {
+ fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(result));
+ return false;
+ }
+
+ curl_slist_free_all(recipients);
+ curl_easy_cleanup(curl);
+ return true;
+ }
+
+ //
+ //Private methods
+ //
+ std::string MessageSender::GetText( std::string const& mail_from, std::string const& mail_to, std::list<std::string> const& cc,
+ std::string const& subject, std::string const& text ) const
+ {
+ auto text_decorator = std::make_shared<message_builder::Text>( text );
+ text_decorator->Apply( std::make_shared<message_builder::Subject>( subject ) )
+ .Apply( std::make_shared<message_builder::Cc>( cc ) )
+ .Apply( std::make_shared<message_builder::From>( mail_from ) )
+ .Apply( std::make_shared<message_builder::MailTo>( mail_to ) )
+ .Apply( std::make_shared<message_builder::Date>() );
+ return text_decorator->Get();
+ }
+
+ void MessageSender::FillRecipients( CURL* curl, std::string const& mail_to, std::list<std::string> const& cc, curl_slist* recipients )
+ {
+ recipients = curl_slist_append( recipients, mail_to.c_str() );
+
+ for( const auto& recipient : cc )
+ {
+ recipients = curl_slist_append( recipients, recipient.c_str() );
+ }
+
+ curl_easy_setopt( curl, CURLOPT_MAIL_RCPT, recipients );
+ }
+
+ std::string MessageSender::GetHostPortData() const
+ {
+ auto result = "smtp://" + mSettingsStorage.host;
+ if( !mSettingsStorage.port.empty() )
+ {
+ result += ":" + mSettingsStorage.port;
+ }
+ return result;
+ }
+
+ size_t MessageSender::ReadCallBack( void *ptr, size_t size, size_t nmemb, void *userp )
+ {
+ struct WriteThis *pooh = reinterpret_cast<WriteThis*>( userp );
+ if( size * nmemb < 1 )
+ {
+ return 0;
+ }
+ if( pooh->counter++ > 0 )
+ {
+ return 0;
+ }
+ memcpy( ptr, mText.c_str(), mText.size() );
+ return mText.size();
+ }
+}
diff --git a/src/message_sender.hpp b/src/message_sender.hpp
new file mode 100644
index 0000000..0728f0e
--- /dev/null
+++ b/src/message_sender.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <list>
+#include <memory>
+
+#include <curl/curl.h>
+
+#include "settings_storage.hpp"
+
+namespace smtp
+{
+ struct WriteThis
+ {
+ int counter;
+ };
+
+ class MessageSender
+ {
+ public:
+ MessageSender( SettingsStorage const& settings_storage );
+ ~MessageSender() = default;
+
+ bool Send( std::string const& mail_from, std::string const& mail_to, std::list<std::string> const& cc,
+ std::string const& subject, std::string const& text );
+ private:
+ std::string GetText( std::string const& mail_from, std::string const& mail_to, std::list<std::string> const& cc,
+ std::string const& subject, std::string const& textt ) const;
+ void InitSenders( std::string const& mail_from, std::list<std::string> const& mail_to );
+ void FillRecipients( CURL* curl, std::string const& mail_to, std::list<std::string> const& cc, curl_slist* recipients );
+ std::string GetHostPortData() const;
+ void ProcessSending(const std::string &mail_from, const std::list<std::string> &mail_to, const std::string &subject, const std::string &text);
+ timeval GetNowTime() const noexcept;
+ bool IsTimeOut( timeval const& start_time ) const noexcept;
+ long GetTimeDiff( timeval const& left, timeval const& right ) const noexcept;
+ timeval GetTimeout() const;
+ int ProcessHandle( timeval& timeout ) const;
+ void ClearPtrs();
+ static size_t ReadCallBack( void *ptr, size_t size, size_t nmemb, void *userp );
+
+// CURL *curl;
+// CURLM *mcurl;
+ struct WriteThis pooh;
+ struct curl_slist* recipients = NULL;
+ SettingsStorage const& mSettingsStorage;
+ };
+}
+
+
diff --git a/src/settings_storage.hpp b/src/settings_storage.hpp
new file mode 100644
index 0000000..d442d6f
--- /dev/null
+++ b/src/settings_storage.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include <string>
+
+namespace smtp
+{
+ struct SettingsStorage
+ {
+ std::string username;
+ std::string password;
+ std::string host;
+ std::string port;
+ };
+}
diff --git a/src/smtp_service.cpp b/src/smtp_service.cpp
new file mode 100644
index 0000000..6235e4c
--- /dev/null
+++ b/src/smtp_service.cpp
@@ -0,0 +1,96 @@
+#include "smtp_service.hpp"
+#include "message_sender.hpp"
+
+namespace smtp
+{
+ static constexpr char HOST_PROPERTY[] = "Host";
+ static constexpr char USER_PROPERTY[] = "User";
+ static constexpr char PORT_PROPERTY[] = "Port";
+
+ //
+ // Constructors
+ //
+
+ SmtpService::SmtpService( ConnectionPtr connection )
+ {
+ FillStorageByDefault();
+ CreateService( connection );
+ CreateInterface( connection );
+ }
+
+ //
+ // Private methods
+ //
+
+ void SmtpService::FillStorageByDefault()
+ {
+ mStorage.host = "";
+ mStorage.username = "";
+ mStorage.password = "";
+ mStorage.port = "";
+ }
+
+ void SmtpService::CreateService( ConnectionPtr connection )
+ {
+ static constexpr char SMTP_BUS_NAME[] = "xyz.openbmc_project.SMTP";
+
+ connection->request_name( SMTP_BUS_NAME );
+ }
+
+ void SmtpService::CreateInterface( ConnectionPtr connection )
+ {
+ static constexpr char SMTP_OBJECT_NAME[] = "/xyz/openbmc_project/SMTP";
+ static constexpr char SMTP_INTERFACE_NAME[] = "xyz.openbmc_project.SMTP";
+
+ mObjectServer = std::make_shared<sdbusplus::asio::object_server>( connection );
+ mInterface = mObjectServer->add_interface( SMTP_OBJECT_NAME, SMTP_INTERFACE_NAME );
+
+ AddProperties();
+ AddMethods();
+
+ mInterface->initialize();
+ }
+
+ void SmtpService::AddProperties()
+ {
+ mInterface->register_property( HOST_PROPERTY, mStorage.host, sdbusplus::asio::PropertyPermission::readOnly );
+ mInterface->register_property( USER_PROPERTY, mStorage.username, sdbusplus::asio::PropertyPermission::readOnly );
+ mInterface->register_property( PORT_PROPERTY, mStorage.port, sdbusplus::asio::PropertyPermission::readOnly );
+ }
+
+ void SmtpService::AddMethods()
+ {
+ static constexpr char SMTP_SEND_MESSAGE_METHOD_NAME[] = "SendMail";
+ static constexpr char SMTP_CHANGE_PARAMETERS_METHOD_NAME[] = "ChangeParameters";
+
+ mInterface->register_method(SMTP_SEND_MESSAGE_METHOD_NAME, [this]( std::string const& mail_from,
+ std::string const& mail_to,
+ std::list<std::string> const& cc,
+ std::string const& theme,
+ std::string const& text )
+ { return MessageSender{ mStorage }.Send( mail_from, mail_to, cc, theme, text );});
+
+
+ mInterface->register_method(SMTP_CHANGE_PARAMETERS_METHOD_NAME, [this]( std::string const& user,
+ std::string const& password,
+ std::string const& host,
+ std::string const& port )
+ { return RefreshSettings(user, password, host, port);});
+ }
+
+ bool SmtpService::RefreshSettings(std::string const& user,
+ std::string const& password,
+ std::string const& host,
+ std::string const& port)
+ {
+ mStorage.username = user;
+ mStorage.password = password;
+ mStorage.host = host;
+ mStorage.port = port;
+
+ mInterface->set_property(HOST_PROPERTY, host);
+ mInterface->set_property(USER_PROPERTY, user);
+ mInterface->set_property(PORT_PROPERTY, port);
+ return true;
+ }
+}
diff --git a/src/smtp_service.hpp b/src/smtp_service.hpp
new file mode 100644
index 0000000..7149e3a
--- /dev/null
+++ b/src/smtp_service.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include <boost/asio/io_service.hpp>
+
+#include <sdbusplus/asio/connection.hpp>
+#include <sdbusplus/asio/object_server.hpp>
+
+#include "settings_storage.hpp"
+
+namespace smtp
+{
+ using ConnectionPtr = std::shared_ptr<sdbusplus::asio::connection>;
+ using InterfacePtr = std::shared_ptr<sdbusplus::asio::dbus_interface>;
+ using ObjectServerPtr = std::shared_ptr<sdbusplus::asio::object_server>;
+
+ class SmtpService
+ {
+ public:
+ SmtpService( ConnectionPtr connection );
+ ~SmtpService() = default;
+ private:
+ void FillStorageByDefault();
+ void CreateService( ConnectionPtr bus );
+ void CreateInterface( ConnectionPtr connection );
+ void AddProperties();
+ void AddMethods();
+ bool RefreshSettings(std::string const& user,
+ std::string const& password,
+ std::string const& host,
+ std::string const& port);
+
+ InterfacePtr mInterface;
+ ObjectServerPtr mObjectServer;
+ SettingsStorage mStorage;
+ };
+}
diff --git a/xyz.openbmc_project.SMTP.service b/xyz.openbmc_project.SMTP.service
new file mode 100644
index 0000000..a7c89ef
--- /dev/null
+++ b/xyz.openbmc_project.SMTP.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=SMTP client
+
+[Service]
+ExecStart=/usr/bin/smtp
+Type=oneshot
+
+[Install]
+WantedBy=basic.target