32 #include <ibrcommon/Logger.h>
33 #include <vmime/platforms/posix/posixHandler.hpp>
39 bool EMailSmtpService::_run(
false);
47 EMailSmtpService::EMailSmtpService()
48 : _config(daemon::Configuration::getInstance().getEMail()),
49 _storage(dtn::core::
BundleCore::getInstance().getStorage()),
50 _certificateVerifier(vmime::create<vmime::security::cert::defaultCertificateVerifier>())
57 vmime::platform::setHandler<vmime::platforms::posix::posixHandler>();
67 vmime::ref<vmime::net::session> session =
68 vmime::create<vmime::net::session>();
71 _transport = session->getTransport(vmime::utility::url(url));
74 _transport->setProperty(
"options.need-authentication",
78 _transport->setProperty(
"server.port", _config.
getSmtpPort());
83 _transport->setProperty(
"connection.tls",
true);
84 _transport->setProperty(
"connection.tls.required",
true);
88 _transport->setTimeoutHandlerFactory(vmime::create<TimeoutHandlerFactory>());
93 _transport->setCertificateVerifier(_certificateVerifier);
95 }
catch (vmime::exception &e) {
96 IBRCOMMON_LOGGER(error) <<
"EMail Convergence Layer: Unable to create SMTP service: " << e.what() << IBRCOMMON_LOGGER_ENDL;
100 _threadMutex.enter();
107 EMailSmtpService::~EMailSmtpService()
114 while(!_queue.empty()) {
115 Task *t = _queue.front();
127 _threadMutex.enter();
149 }
catch(std::exception &e) {
152 if(dynamic_cast<vmime::exceptions::authentication_error*>(&e) != NULL)
155 IBRCOMMON_LOGGER(error) <<
"EMail Convergence Layer: SMTP authentication error (username/password correct?)" << IBRCOMMON_LOGGER_ENDL;
157 else if(dynamic_cast<vmime::exceptions::connection_error*>(&e) != NULL)
160 IBRCOMMON_LOGGER(error) <<
"EMail Convergence Layer: Unable to connect to the SMTP server" << IBRCOMMON_LOGGER_ENDL;
165 IBRCOMMON_LOGGER(error) <<
"EMail Convergence Layer: SMTP error: " << e.what() << IBRCOMMON_LOGGER_ENDL;
171 _threadMutex.leave();
174 }
catch(ibrcommon::QueueUnblockedException&) {
186 _threadMutex.leave();
189 void EMailSmtpService::connect()
192 _transport->connect();
195 bool EMailSmtpService::isConnected()
197 return _transport->isConnected();
200 void EMailSmtpService::disconnect()
203 _transport->disconnect();
206 void EMailSmtpService::loadCerificates()
208 std::vector<std::string> certPath;
210 std::vector<vmime::ref <vmime::security::cert::X509Certificate> > ca;
212 if(!certPath.empty()) {
213 for(std::vector<std::string>::iterator it = certPath.begin() ; it != certPath.end(); ++it)
216 ca.push_back(loadCertificateFromFile((*it)));
217 }
catch(InvalidCertificate &e) {
218 IBRCOMMON_LOGGER(error) <<
"EMail Convergence Layer: Certificate load error: " << e.what() << IBRCOMMON_LOGGER_ENDL;
221 _certificateVerifier->setX509RootCAs(ca);
225 std::vector<vmime::ref <vmime::security::cert::X509Certificate> > user;
227 if(!certPath.empty()) {
228 for(std::vector<std::string>::iterator it = certPath.begin() ; it != certPath.end(); ++it)
231 user.push_back(loadCertificateFromFile((*it)));
232 }
catch(InvalidCertificate &e) {
233 IBRCOMMON_LOGGER(error) <<
"EMail Convergence Layer: Certificate load error: " << e.what() << IBRCOMMON_LOGGER_ENDL;
236 _certificateVerifier->setX509TrustedCerts(user);
240 vmime::ref<vmime::security::cert::X509Certificate> EMailSmtpService::loadCertificateFromFile(
const std::string &path)
242 std::ifstream certFile;
243 certFile.open(path.c_str(), std::ios::in | std::ios::binary);
246 throw(InvalidCertificate(
"Unable to find certificate at \"" + path +
"\""));
250 vmime::utility::inputStreamAdapter is(certFile);
251 vmime::ref<vmime::security::cert::X509Certificate> cert;
252 cert = vmime::security::cert::X509Certificate::import(is);
257 throw(InvalidCertificate(
"The certificate at \"" + path +
"\" does not seem to be PEM or DER encoded"));
270 _threadMutex.leave();
275 _threadMutex.leave();
278 void EMailSmtpService::submit(Task *t)
286 context.
setPeer(t->getNode().getEID());
296 if (ret != BundleFilter::ACCEPT)
298 IBRCOMMON_LOGGER_DEBUG(1) <<
"BPTables: OUTPUT table prohibits sending" << IBRCOMMON_LOGGER_ENDL;
305 vmime::ref<vmime::message> msg = vmime::create <vmime::message>();
306 vmime::ref<vmime::header> header = msg->getHeader();
307 vmime::ref<vmime::body> body = msg->getBody();
310 vmime::headerFieldFactory* hfFactory =
311 vmime::headerFieldFactory::getInstance();
314 header->appendField(hfFactory->create(vmime::fields::FROM,
317 header->appendField(hfFactory->create(vmime::fields::TO,
320 header->appendField(hfFactory->create(vmime::fields::SUBJECT,
321 "Bundle for " + t->getNode().getEID().getString()));
324 header->appendField(hfFactory->create(
"Bundle-EMailCL-Version",
"1"));
325 header->appendField(hfFactory->create(
"Bundle-Flags",
327 header->appendField(hfFactory->create(
"Bundle-Destination",
329 header->appendField(hfFactory->create(
"Bundle-Source",
331 header->appendField(hfFactory->create(
"Bundle-Report-To",
333 header->appendField(hfFactory->create(
"Bundle-Custodian",
335 header->appendField(hfFactory->create(
"Bundle-Creation-Time",
337 header->appendField(hfFactory->create(
"Bundle-Sequence-Number",
339 header->appendField(hfFactory->create(
"Bundle-Lifetime",
343 header->appendField(hfFactory->create(
"Bundle-Fragment-Offset",
345 header->appendField(hfFactory->create(
"Bundle-Total-Application-Data-Unit-Length",
350 unsigned int additionalBlocks = 0;
353 if(bundle.
size() > 0)
354 header->appendField(hfFactory->create(
"MIME-Version",
"1.0"));
362 header->appendField(hfFactory->create(
"Bundle-Payload-Flags",
363 toString(getProcFlags(payload))));
364 header->appendField(hfFactory->create(
"Bundle-Payload-Block-Length",
366 header->appendField(hfFactory->create(
"Bundle-Payload-Data-Name",
370 ibrcommon::BLOB::iostream data = payload.
getBLOB().iostream();
371 std::stringstream ss;
374 vmime::ref<vmime::utility::inputStream> dataStream =
375 vmime::create<vmime::utility::inputStreamStringAdapter>(ss.str());
377 vmime::ref<vmime::attachment> payloadAttachement =
378 vmime::create<vmime::fileAttachment>(
380 vmime::word(
"payload.data"),
381 vmime::mediaType(
"application/octet-stream")
383 vmime::attachmentHelper::addAttachment(msg, payloadAttachement);
385 }
catch(
const std::bad_cast&) {};
392 std::stringstream attachment;
396 vmime::ref<vmime::utility::inputStream> dataStream =
397 vmime::create<vmime::utility::inputStreamStringAdapter>(attachment.str());
399 vmime::ref<vmime::attachment> extensionAttachement =
400 vmime::create<vmime::fileAttachment>(
402 vmime::word(
"block-" + toString(additionalBlocks) +
".data"),
403 vmime::mediaType(
"application/octet-stream")
406 vmime::attachmentHelper::addAttachment(msg, extensionAttachement);
409 vmime::ref<vmime::header> extensionHeader = msg->getBody()->getPartAt(msg->getBody()->getPartCount()-1)->getHeader();
410 std::stringstream ss;
413 extensionHeader->appendField(hfFactory->create(
"Block-Type", ss.str()));
415 extensionHeader->appendField(hfFactory->create(
"Block-Processing-Flags",
416 toString(getProcFlags(block))));
422 for(Block::eid_list::const_iterator eidIt = eids.begin(); eidIt != eids.end(); eidIt++)
424 extensionHeader->appendField(hfFactory->create(
"Block-EID-Reference",
425 (*eidIt).getString()));
430 header->appendField(hfFactory->create(
"Bundle-Additional-Block",
431 "block-" + toString(additionalBlocks++) +
".data"));
433 }
catch(
const std::bad_cast&) {};
436 _transport->send(msg);
439 IBRCOMMON_LOGGER(info) <<
"EMail Convergence Layer: Bundle " << t->getJob().getBundle().toString() <<
" for node " << t->getNode().getEID().getString() <<
" submitted via smtp" << IBRCOMMON_LOGGER_ENDL;
444 unsigned int out = 0;
464 std::string EMailSmtpService::toString(
int i)
466 std::stringstream ss;
472 : _node(node), _job(job), _recipient(recipient), _timesChecked(0) {}
496 bool EMailSmtpService::TimeoutHandler::isTimeOut()
501 return (getTime() >= last +
505 void EMailSmtpService::TimeoutHandler::resetTimeOut()
510 bool EMailSmtpService::TimeoutHandler::handleTimeOut()
static Configuration & getInstance(bool reset=false)
const dtn::core::Node getNode()
Task(const dtn::core::Node &node, const dtn::net::BundleTransfer &job, std::string recipient)
Bitset< FLAGS > procflags
bool get(ProcFlags flag) const
static EMailSmtpService & getInstance()
bool checkForReturningMail()
std::string getOwnAddress() const
void setBundle(const dtn::data::Bundle &data)
dtn::data::Timestamp timestamp
static void raise(const dtn::data::EID &peer, const dtn::data::BundleID &id, const AbortReason reason=REASON_UNDEFINED)
std::string getRecipient()
virtual bool contains(const dtn::data::BundleID &id)=0
static void raise(const dtn::data::EID peer, const dtn::data::MetaBundle &bundle)
std::string getSmtpServer() const
size_t getSmtpKeepAliveTimeout() const
virtual std::ostream & serialize(std::ostream &stream, Length &length) const =0
BundleFilter::ACTION filter(BundleFilter::TABLE table, const FilterContext &context, dtn::data::Bundle &bundle) const
std::list< dtn::data::EID > eid_list
std::string getSmtpUsername() const
void setProtocol(const dtn::core::Node::Protocol &protocol)
bool smtpAuthenticationNeeded() const
dtn::data::Number sequencenumber
bool get(FLAGS flag) const
void setPeer(const dtn::data::EID &endpoint)
std::string toString() const
block_list::const_iterator const_iterator
virtual Length getLength() const
virtual const eid_list & getEIDList() const
std::string getSmtpPassword() const
virtual dtn::data::Bundle get(const dtn::data::BundleID &id)=0
const dtn::net::BundleTransfer getJob()
std::vector< std::string > getTlsCACerts() const
void abort(const TransferAbortedEvent::AbortReason reason)
const dtn::data::MetaBundle & getBundle() const
std::string getString() const
static void raise(const dtn::data::MetaBundle &bundle, EventBundleAction action, dtn::data::StatusReportBlock::REASON_CODE reason=dtn::data::StatusReportBlock::NO_ADDITIONAL_INFORMATION)
ibrcommon::BLOB::Reference getBLOB() const
const dtn::data::EID & getEID() const
const block_t & getType() const
dtn::data::Number fragmentoffset
void storeProcessedTask(EMailSmtpService::Task *task)
std::vector< std::string > getTlsUserCerts() const
static EMailImapService & getInstance()
static BundleCore & getInstance()