30 #include "modules/smtp/SMTPAudit_odb.h"
31 #include "modules/smtp/SMTPConfig_odb.h"
37 #include <boost/asio.hpp>
44 const boost::property_tree::ptree &cfg,
CoreUtilsPtr utils)
50 if (
config_.get<
bool>(
"module_config.want_ssl",
true))
51 flags |= CURL_GLOBAL_SSL;
52 if ((ret = curl_global_init(flags)) != 0)
54 throw std::runtime_error(
"Failed to initialize curl: return code: " +
59 auto audit_serializer_service =
62 "Cannot retrieve Audit::Serializer::JSONService.");
64 audit_serializer_service->register_serializer<
SMTPAudit>(
71 std::make_unique<SMTPServiceImpl>(*
this));
76 curl_global_cleanup();
77 auto audit_serializer_service =
80 "Cannot retrieve Audit::Serializer::JSONService.");
81 audit_serializer_service->unregister_serializer<
SMTPAudit>();
97 odb::transaction t(
utils_->database()->begin());
99 for (
const auto &cfg : result)
106 "We have more than one SMTPConfig entry in the database.");
107 INFO(
"SMTP module using SQL database for configuration.");
109 catch (
const odb::exception &e)
111 WARN(
"SMTP module failed to load database configure. Using default "
120 for (
auto &&itr :
config_.get_child(
"module_config.servers"))
123 server.
url = itr.second.get<std::string>(
"url");
124 server.
from = itr.second.get<std::string>(
"from",
"leosac@leosac.com");
125 server.
verify_host = itr.second.get<
bool>(
"verify_host",
true);
126 server.
verify_peer = itr.second.get<
bool>(
"verify_peer",
true);
127 server.
CA_info_file_ = itr.second.get<std::string>(
"ca_file",
"");
129 INFO(
"SMTP module server: "
146 <<
". No SMTP server configured.");
147 if (mail.
to.size() == 0)
158 auto curl = curl_easy_init();
161 if (!target.CA_info_file_.empty())
162 curl_easy_setopt(curl, CURLOPT_CAINFO, target.CA_info_file_.c_str());
163 if (!target.verify_host)
164 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
165 if (!target.verify_peer)
166 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
167 if (target.username.size())
168 curl_easy_setopt(curl, CURLOPT_USERNAME, target.username.c_str());
169 if (target.password.size())
170 curl_easy_setopt(curl, CURLOPT_PASSWORD, target.password.c_str());
171 if (target.from.size())
172 curl_easy_setopt(curl, CURLOPT_MAIL_FROM, target.from.c_str());
174 ASSERT_LOG(target.url.size(),
"No mail server url.");
175 curl_easy_setopt(curl, CURLOPT_URL, target.url.c_str());
177 curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, target.ms_timeout);
180 curl_easy_cleanup(curl);
186 ERROR(
"Cannot initialize curl_easy.");
201 static std::string build_mail_str(
const MailInfo &mail)
203 std::stringstream ss;
206 ss <<
"Date: " <<
to_local_rfc2822(std::chrono::system_clock::now()) <<
"\r\n";
207 ss <<
"To: " << mail.
to.at(0) <<
"\r\n";
209 ss <<
"Subject: " << mail.
title <<
"\r\n";
211 ss << mail.
body <<
"\r\n\r\n";
221 static size_t read_callback(
void *ptr,
size_t size,
size_t nmemb,
void *userp)
226 std::string content = build_mail_str(st->
mail);
227 auto wanted = size * nmemb;
228 auto available = content.size() - st->
counter;
229 auto to_transfer = std::min(available, wanted);
231 std::memset(ptr, 0, wanted);
232 std::memcpy(ptr, &content[0] + st->
counter, to_transfer);
242 struct curl_slist *recipients = NULL;
243 for (
const auto &recipient : mail.
to)
244 recipients = curl_slist_append(recipients, recipient.c_str());
245 curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
249 curl_easy_setopt(curl, CURLOPT_READFUNCTION, &read_callback);
250 curl_easy_setopt(curl, CURLOPT_READDATA, &status);
251 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
252 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
254 auto res = curl_easy_perform(curl);
255 curl_slist_free_all(recipients);
258 WARN(
"curl_easy_perform() failed: " << curl_easy_strerror(res));
271 using namespace odb::core;
272 auto db =
utils_->database();
273 schema_version v = db->schema_version(
"module_smtp");
274 schema_version cv(schema_catalog::current_version(*db,
"module_smtp"));
277 transaction t(db->begin());
278 schema_catalog::create_schema(*db,
"module_smtp");
282 srv.
url =
"smtp://mail.leosac.com";
284 srv.
from =
"leosac@leosac.com";
292 INFO(
"SMTP Module performing database migration. Going from version "
293 << v <<
" to version " << cv);
294 transaction t(db->begin());
295 schema_catalog::migrate(*db, cv,
"module_smtp");
303 json ret = json::array();
316 for (
const auto &server : req.at(
"servers"))
321 cfg->server_add(srv_info);
325 auto db =
utils_->database();
326 odb::transaction t(db->begin());
333 smtp_audit->finalize();
346 mail.
body = req.at(
"body");
347 mail.
title = req.at(
"subject");
348 for (
const auto &recipient : req.at(
"to"))
349 mail.
to.push_back(recipient);
360 auto &service_registered_event =
361 assert_cast<const service_event::ServiceRegistered &>(e);
362 if (service_registered_event.interface_type() ==
363 boost::typeindex::type_id<WebSockAPI::Service>())
399 ret = ws_srv->register_asio_handler_permission(
410 ret = ws_srv->register_asio_handler_permission(
421 INFO(
"Cannot register Websocket handlers. Service is not (yet) available.");