30 #include <vmime/platforms/posix/posixHandler.hpp>
36 bool EMailImapService::_run(
false);
44 EMailImapService::EMailImapService()
45 : _config(daemon::Configuration::getInstance().getEMail()),
46 _certificateVerifier(vmime::create<vmime::security::cert::defaultCertificateVerifier>())
53 vmime::platform::setHandler<vmime::platforms::posix::posixHandler>();
63 vmime::ref<vmime::net::session> session =
64 vmime::create<vmime::net::session>();
67 _store = session->getStore(vmime::utility::url(url));
72 _store->setProperty(
"server.port", _config.
getImapPort());
77 _store->setProperty(
"connection.tls",
true);
78 _store->setProperty(
"connection.tls.required",
true);
84 _store->setCertificateVerifier(_certificateVerifier);
88 _store->setTimeoutHandlerFactory(vmime::create<TimeoutHandlerFactory>());
91 std::vector<std::string> folderPath = _config.
getImapFolder();
92 if(!folderPath.empty())
94 for(std::vector<std::string>::iterator it = folderPath.begin() ; it != folderPath.end(); ++it)
95 _path /= vmime::net::folder::path::component(*it);
104 }
catch (vmime::exception &e) {
109 EMailImapService::~EMailImapService()
117 while(!_processedTasks.empty())
120 _processedTasks.pop_front();
127 void EMailImapService::loadCerificates()
129 std::vector<std::string> certPath;
131 std::vector<vmime::ref <vmime::security::cert::X509Certificate> > ca;
133 if(!certPath.empty()) {
134 for(std::vector<std::string>::iterator it = certPath.begin() ; it != certPath.end(); ++it)
137 ca.push_back(loadCertificateFromFile((*it)));
138 }
catch(InvalidCertificate &e) {
142 _certificateVerifier->setX509RootCAs(ca);
146 std::vector<vmime::ref <vmime::security::cert::X509Certificate> > user;
148 if(!certPath.empty()) {
149 for(std::vector<std::string>::iterator it = certPath.begin() ; it != certPath.end(); ++it)
152 user.push_back(loadCertificateFromFile((*it)));
153 }
catch(InvalidCertificate &e) {
157 _certificateVerifier->setX509TrustedCerts(user);
161 vmime::ref<vmime::security::cert::X509Certificate> EMailImapService::loadCertificateFromFile(
const std::string &path)
163 std::ifstream certFile;
164 certFile.open(path.c_str(), std::ios::in | std::ios::binary);
167 throw(InvalidCertificate(
"Unable to find certificate at \"" + path +
"\""));
171 vmime::utility::inputStreamAdapter is(certFile);
172 vmime::ref<vmime::security::cert::X509Certificate> cert;
173 cert = vmime::security::cert::X509Certificate::import(is);
178 throw(InvalidCertificate(
"The certificate at \"" + path +
"\" does not seem to be PEM or DER encoded"));
187 _threadMutex.
enter();
195 }
catch(vmime::exception &e) {
198 }
catch(IMAPException &e) {
209 _threadMutex.
leave();
215 _processedTasks.push_back(t);
220 _threadMutex.
leave();
223 bool EMailImapService::TimeoutHandler::isTimeOut()
228 return (getTime() >= last +
232 void EMailImapService::TimeoutHandler::resetTimeOut()
237 bool EMailImapService::TimeoutHandler::handleTimeOut()
243 void EMailImapService::connect()
253 _folder = _store->getFolder(_path);
255 _folder = _store->getDefaultFolder();
258 _folder->open(vmime::net::folder::MODE_READ_WRITE,
true);
259 }
catch(vmime::exceptions::certificate_verification_exception&) {
260 throw IMAPException(
"Cannot verify certificate against trusted certificates");
261 }
catch(vmime::exceptions::authentication_error&) {
262 throw IMAPException(
"Authentication error (username/password correct?)");
263 }
catch(vmime::exceptions::connection_error&) {
264 throw IMAPException(
"Unable to connect to the IMAP server");
265 }
catch(vmime::exception &e) {
266 throw IMAPException(e.what());
271 bool EMailImapService::isConnected()
273 return _store->isConnected();
276 void EMailImapService::disconnect()
280 if(_folder->isOpen())
282 _store->disconnect();
286 void EMailImapService::queryServer()
293 std::vector<vmime::ref<vmime::net::message> > allMessages;
295 allMessages = _folder->getMessages();
296 _folder->fetchMessages(allMessages,
297 vmime::net::folder::FETCH_FLAGS | vmime::net::folder::FETCH_FULL_HEADER | vmime::net::folder::FETCH_UID);
298 }
catch(vmime::exception&) {
301 for(std::vector<vmime::ref<vmime::net::message> >::iterator it =
302 allMessages.begin(); it != allMessages.end(); ++it)
304 const int flags = (*it).get()->getFlags();
306 if(!flags & vmime::net::message::FLAG_SEEN) {
311 generateBundle((*it));
312 }
catch(IMAPException &e){
314 returningMailCheck((*it));
315 }
catch(BidNotFound&) {
319 }
catch(vmime::exceptions::no_such_field &e) {
324 (*it)->setFlags(vmime::net::message::FLAG_SEEN, vmime::net::message::FLAG_MODE_SET);
329 (*it)->setFlags(vmime::net::message::FLAG_DELETED, vmime::net::message::FLAG_MODE_SET);
339 std::list<EMailSmtpService::Task*>::iterator it = _processedTasks.begin();
340 while(it != _processedTasks.end())
342 if(!(*it)->checkForReturningMail()) {
347 _processedTasks.erase(it++);
355 void EMailImapService::generateBundle(vmime::ref<vmime::net::message> &msg)
365 vmime::ref<const vmime::header> header = msg->getHeader();
366 std::string mailID =
" (ID: " + msg->getUniqueId() +
")";
370 int version = toInt(header->findField(
"Bundle-EMailCL-Version")->getValue()->generate());
372 throw IMAPException(
"Wrong EMailCL version found in mail" + mailID);
373 }
catch(vmime::exceptions::no_such_field&) {
374 throw IMAPException(
"Field \"Bundle-EMailCL-Version\" not found in mail" + mailID);
375 }
catch(InvalidConversion&) {
376 throw IMAPException(
"Field \"Bundle-EMailCL-Version\" wrong formatted in mail" + mailID);
380 newBundle.
procflags = toInt(header->findField(
"Bundle-Flags")->getValue()->generate());
381 newBundle.
destination = header->findField(
"Bundle-Destination")->getValue()->generate();
383 newBundle.
reportto = header->findField(
"Bundle-Report-To")->getValue()->generate();
384 newBundle.
custodian = header->findField(
"Bundle-Custodian")->getValue()->generate();
385 newBundle.
timestamp = toInt(header->findField(
"Bundle-Creation-Time")->getValue()->generate());
386 newBundle.
sequencenumber = toInt(header->findField(
"Bundle-Sequence-Number")->getValue()->generate());
387 newBundle.
lifetime = toInt(header->findField(
"Bundle-Lifetime")->getValue()->generate());
388 }
catch(vmime::exceptions::no_such_field&) {
389 throw IMAPException(
"Missing bundle headers in mail" + mailID);
390 }
catch(InvalidConversion&) {
391 throw IMAPException(
"Wrong formatted bundle headers in mail" + mailID);
396 newBundle.
fragmentoffset = toInt(header->findField(
"Bundle-Fragment-Offset")->getValue()->generate());
397 newBundle.
appdatalength = toInt(header->findField(
"Bundle-Total-Application-Data-Unit-Length")->getValue()->generate());
398 }
catch(vmime::exceptions::no_such_field&) {
401 }
catch(InvalidConversion&) {
402 throw IMAPException(
"Wrong formatted fragment offset in mail" + mailID);
408 throw IMAPException(
"Bundle in mail" + mailID +
" already processed");
417 throw IMAPException(
"Bundle in mail" + mailID +
" was rejected by validator");
421 std::vector<vmime::ref<vmime::headerField> > additionalBlocks =
422 header.constCast<vmime::header>()->findAllFields(
"Bundle-Additional-Block");
423 std::vector<std::string> additionalBlockNames;
424 for(std::vector<vmime::ref<vmime::headerField> >::iterator it = additionalBlocks.begin();
425 it != additionalBlocks.end(); ++it)
427 additionalBlockNames.push_back((*it)->getValue()->generate());
431 std::vector<vmime::ref<const vmime::attachment> > attachments =
432 vmime::attachmentHelper::findAttachmentsInMessage(msg->getParsedMessage());
436 std::string payloadName;
438 payloadFlags = toInt(header->findField(
"Bundle-Payload-Flags")->getValue()->generate());
441 payloadName = header->findField(
"Bundle-Payload-Data-Name")->getValue()->generate();
442 }
catch(vmime::exceptions::no_such_field&) {
444 }
catch(InvalidConversion&) {
445 throw IMAPException(
"Wrong formatted payload flags in mail" + mailID);
452 for(std::vector<vmime::ref<const vmime::attachment> >::iterator it = attachments.begin(); it != attachments.end(); ++it)
454 if((*it)->getName().getBuffer() == payloadName && !payloadName.empty()) {
459 vmime::utility::outputStreamAdapter data((*payloadData));
460 (*it)->getData()->extract(data);
462 setProcFlags(pb, payloadFlags);
467 if(std::find(additionalBlockNames.begin(), additionalBlockNames.end(), (*it)->getName().getBuffer()) != additionalBlockNames.end())
472 blockType = toInt((*it)->getHeader()->findField(
"Block-Type")->getValue()->generate());
473 }
catch(vmime::exceptions::no_such_field&) {
474 throw IMAPException(
"Block type not found in attachment of mail" + mailID);
480 flags = toInt((*it)->getHeader()->findField(
"Block-Processing-Flags")->getValue()->generate());
481 }
catch(vmime::exceptions::no_such_field&) {
482 throw IMAPException(
"Missing block processing flags in extension attachment of mail" + mailID);
483 }
catch(InvalidConversion&) {
484 throw IMAPException(
"Wrong formatted processing flags in extension attachment of mail" + mailID);
492 addEIDList(block, (*it));
493 }
catch(InvalidConversion&) {
494 throw IMAPException(
"Wrong formatted EID list in extension attachment of mail" + mailID);
498 std::stringstream ss;
499 vmime::utility::outputStreamAdapter data(ss);
500 (*it)->getData()->extract(data);
510 throw IMAPException(
"Bundle in mail" + mailID +
" was rejected by validator");
517 void EMailImapService::returningMailCheck(vmime::ref<vmime::net::message> &msg)
521 bool bidFound =
false;
524 vmime::utility::outputStreamStringAdapter out(s);
526 vmime::messageParser mp(msg->getParsedMessage());
528 for(
int i = 0; i < mp.getTextPartCount(); ++i)
531 mp.getTextPartAt(i)->getText()->extract(out);
537 }
catch(InvalidConversion&) {}
542 for(
int i = 0; i < mp.getAttachmentCount(); ++i)
545 mp.getAttachmentAt(i)->getData()->extract(out);
551 }
catch(InvalidConversion&) {}
557 for(std::list<EMailSmtpService::Task*>::iterator iter = _processedTasks.begin(); iter != _processedTasks.end(); ++iter)
559 if((*iter)->getJob().getBundle() == bid)
562 _processedTasks.erase(iter);
569 throw BidNotFound(
"Found no bundle ID");
576 ret.
source = searchString(
"Bundle-Source: ", message);
577 ret.
timestamp = toInt(searchString(
"Bundle-Creation-Time: ", message));
578 ret.
sequencenumber = toInt(searchString(
"Bundle-Sequence-Number: ", message));
580 ret.
fragmentoffset = toInt(searchString(
"Bundle-Fragment-Offset: ", message));
586 throw InvalidConversion(
"No bundle ID was found");
590 std::string EMailImapService::searchString(
const std::string &search,
const std::string &s)
592 size_t start = 0, end = 0;
593 start = s.find(search);
594 if(start == std::string::npos)
595 throw StringNotFound(
"Unable to find the string");
596 start = start + search.length();
598 end = s.find(
"\r\n", start);
599 if(start == std::string::npos)
600 throw StringNotFound(
"Unable to find the string");
602 return s.substr(start, end-start);
605 int EMailImapService::toInt(std::string s)
607 std::stringstream ss(s);
610 if (ss.rdbuf()->in_avail() == 0)
return ret;
611 else throw InvalidConversion(
"Invalid integer " + s +
".");
614 std::string EMailImapService::toString(
int i)
616 std::stringstream ss;
621 void EMailImapService::addEIDList(
dtn::data::Block &block, vmime::utility::ref<const vmime::attachment> &attachment)
623 std::vector<vmime::ref<vmime::headerField> > eidFiels =
624 attachment->getHeader().constCast<vmime::header>()->findAllFields(
"Block-EID-Reference");
626 for(std::vector<vmime::ref<vmime::headerField> >::iterator it = eidFiels.begin(); it != eidFiels.end(); ++it)
628 }
catch(vmime::exceptions::no_such_field&) {
629 throw InvalidConversion(
"Invalid EID field.");
636 block.
set(dtn::data::Block::REPLICATE_IN_EVERY_FRAGMENT,
true);
638 block.
set(dtn::data::Block::TRANSMIT_STATUSREPORT_IF_NOT_PROCESSED,
true);
640 block.
set(dtn::data::Block::DELETE_BUNDLE_IF_NOT_PROCESSED,
true);
642 block.
set(dtn::data::Block::LAST_BLOCK,
true);
644 block.
set(dtn::data::Block::DISCARD_IF_NOT_PROCESSED,
true);
646 block.
set(dtn::data::Block::FORWARDED_WITHOUT_PROCESSED,
true);
648 block.
set(dtn::data::Block::BLOCK_CONTAINS_EIDS,
true);