From 9fa4addff6f90a8b5697a594e034f5517d64dd25 Mon Sep 17 00:00:00 2001 From: eportnov Date: Fri, 9 Sep 2022 11:10:14 +0300 Subject: first comit --- .gitignore | 6 + CMakeLists.txt | 118 ++++++++++++++++ LICENSE | 201 +++++++++++++++++++++++++++ src/main.cpp | 14 ++ src/message_builder/cc.cpp | 31 +++++ src/message_builder/cc.hpp | 21 +++ src/message_builder/date.cpp | 16 +++ src/message_builder/date.hpp | 17 +++ src/message_builder/from.cpp | 22 +++ src/message_builder/from.hpp | 19 +++ src/message_builder/mail_to.cpp | 23 +++ src/message_builder/mail_to.hpp | 21 +++ src/message_builder/subject.cpp | 21 +++ src/message_builder/subject.hpp | 19 +++ src/message_builder/text.cpp | 24 ++++ src/message_builder/text.hpp | 19 +++ src/message_builder/types/idecorator.hpp | 82 +++++++++++ src/message_builder/types/imessage_build.hpp | 14 ++ src/message_sender.cpp | 123 ++++++++++++++++ src/message_sender.hpp | 48 +++++++ src/settings_storage.hpp | 14 ++ src/smtp_service.cpp | 96 +++++++++++++ src/smtp_service.hpp | 36 +++++ xyz.openbmc_project.SMTP.service | 9 ++ 24 files changed, 1014 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 src/main.cpp create mode 100644 src/message_builder/cc.cpp create mode 100644 src/message_builder/cc.hpp create mode 100644 src/message_builder/date.cpp create mode 100644 src/message_builder/date.hpp create mode 100644 src/message_builder/from.cpp create mode 100644 src/message_builder/from.hpp create mode 100644 src/message_builder/mail_to.cpp create mode 100644 src/message_builder/mail_to.hpp create mode 100644 src/message_builder/subject.cpp create mode 100644 src/message_builder/subject.hpp create mode 100644 src/message_builder/text.cpp create mode 100644 src/message_builder/text.hpp create mode 100644 src/message_builder/types/idecorator.hpp create mode 100644 src/message_builder/types/imessage_build.hpp create mode 100644 src/message_sender.cpp create mode 100644 src/message_sender.hpp create mode 100644 src/settings_storage.hpp create mode 100644 src/smtp_service.cpp create mode 100644 src/smtp_service.hpp create mode 100644 xyz.openbmc_project.SMTP.service 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 && ./bootstrap.sh + BUILD_COMMAND cd && ./b2 --exec-prefix= + --prefix= --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 + +#include "smtp_service.hpp" + +int main() +{ + boost::asio::io_service io_context; + + auto connection = std::make_shared( 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 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 + +#include "types/idecorator.hpp" +#include "types/imessage_build.hpp" + +namespace smtp::message_builder +{ + class Cc : public types::IDecorator + { + public: + explicit Cc( std::list const& mail_to ); + ~Cc() override = default; + + std::string Get() const override; + private: + std::list 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 + { + 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 + { + 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 + +#include "types/idecorator.hpp" +#include "types/imessage_build.hpp" + +namespace smtp::message_builder +{ + class MailTo : public types::IDecorator + { + 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 + { + 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 + { + 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 + +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 > class IDecorator : public T + { + public: + using PointerType = TPointerType; + using Type = IDecorator; + + ~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 > using IDecoratorUnique = IDecorator >; + +} // 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 + +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 + +#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 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 const& cc, + std::string const& subject, std::string const& text ) const + { + auto text_decorator = std::make_shared( text ); + text_decorator->Apply( std::make_shared( subject ) ) + .Apply( std::make_shared( cc ) ) + .Apply( std::make_shared( mail_from ) ) + .Apply( std::make_shared( mail_to ) ) + .Apply( std::make_shared() ); + return text_decorator->Get(); + } + + void MessageSender::FillRecipients( CURL* curl, std::string const& mail_to, std::list 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( 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 +#include + +#include + +#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 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 const& cc, + std::string const& subject, std::string const& textt ) const; + void InitSenders( std::string const& mail_from, std::list const& mail_to ); + void FillRecipients( CURL* curl, std::string const& mail_to, std::list const& cc, curl_slist* recipients ); + std::string GetHostPortData() const; + void ProcessSending(const std::string &mail_from, const std::list &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 + +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( 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 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 + +#include +#include + +#include "settings_storage.hpp" + +namespace smtp +{ + using ConnectionPtr = std::shared_ptr; + using InterfacePtr = std::shared_ptr; + using ObjectServerPtr = std::shared_ptr; + + 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 -- cgit v1.2.3