#include "Message.h" #include "Util/Base64.h" #include #include #include #include #include namespace MailServer { Message::Message(const std::string& address, const Util::Context& context, const std::string& message) : m_address(address), m_context(context), m_mimeBoundary("-_-InvalidBoundary-_-"), m_contentEncoding("none"), m_currentImage(0) { ProcessMessage(message); } std::string Decode(const std::string& data) { std::string result; if (StringAlgorithm::istarts_with(data, "=?utf-8?")) result = Util::Base64::Decode(std::string(data.begin() + 10, data.begin() + data.find_last_of('?'))); else result = Util::Base64::Decode(data); return result; } void Message::ProcessMessage(const std::string& message) { try { Message::State::type state = Message::State::Header; std::string line; std::istringstream stream(message); while (std::getline(stream, line, '\r')) { StringAlgorithm::erase_all(line, '\n'); switch (state) { case State::Header: state = ProcessHeaderLine(line); break; case State::Data: state = ProcessDataLine(line); break; case State::MimeBoundary: state = ProcessMimeBoundary(line); break; case State::Image: state = ProcessImage(line); break; } } if (StringAlgorithm::contains(m_contentEncoding, "base64")) { std::string decoded = Decode(m_subject); if (decoded.size() > 0) m_subject = decoded; } std::stringstream ss; ss << "From: " << m_sender << std::endl; Logging::Log(Logging::Severity::Debug, ss.str()); ss.str(""); ss << "To: " << m_receiver << std::endl; Logging::Log(Logging::Severity::Debug, ss.str()); ss.str(""); ss << "Subject: " << m_subject << std::endl; Logging::Log(Logging::Severity::Debug, ss.str()); ss.str(""); ss << "Received " << m_images.size() << " Images" << std::endl; Logging::Log(Logging::Severity::Info, ss.str()); Image::JpegImageCollection imageCollection(m_images); filesystem::path path(m_context.path); path = path.make_absolute(); path = path/filesystem::path(m_address); if (!path.exists()) filesystem::create_directory(path); std::string fileName(Util::getTimeString()); fileName.append(".jpg"); path = path/filesystem::path(fileName); imageCollection.Save(path.str()); ss.str(""); ss << "Images Stored as " << path.str() << std::endl; Logging::Log(Logging::Severity::Info, ss.str()); if (!m_context.url.empty()) { std::stringstream url; url << m_context.url << "?ip=" << m_address << "&file=" << fileName; Http::HttpRequest request(url.str()); m_context.client.Open(request); } } catch (std::exception& e) { std::stringstream ss; ss << "Message::ProcessMessage() - Error: " << e.what() << std::endl; Logging::Log(Logging::Severity::Error, ss.str()); } } Message::State::type Message::ProcessHeaderLine(const std::string& line) { if (line.empty()) return Message::State::Data; if (StringAlgorithm::istarts_with(line, "from:")) { m_sender = std::string(line.begin() + line.find_first_of(' ') + 1, line.end()); return Message::State::Header; } if (StringAlgorithm::istarts_with(line, "to:")) { m_receiver = std::string(line.begin() + line.find_first_of(' ') + 1, line.end()); return Message::State::Header; } if (StringAlgorithm::istarts_with(line, "subject:")) { m_subject = std::string(line.begin() + line.find_first_of(' ') + 1, line.end()); return Message::State::Header; } if (StringAlgorithm::istarts_with(line, "date")) { m_date = std::string(line.begin() + line.find_first_of(' ') + 1, line.end()); return Message::State::Header; } if (StringAlgorithm::istarts_with(line, "content-type:")) { m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end()); return Message::State::Header; } if (StringAlgorithm::istarts_with(line, "boundary") || StringAlgorithm::istarts_with(line, "\tboundary") || StringAlgorithm::istarts_with(line, " boundary")) { m_mimeBoundary = std::string("--").append(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"'))); return Message::State::Header; } if (StringAlgorithm::istarts_with(line, "content-transfer-encoding:")) { m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end()); return Message::State::Header; } return Message::State::Header; } Message::State::type Message::ProcessDataLine(const std::string& line) { if (StringAlgorithm::istarts_with(line, m_mimeBoundary)) { m_contentType = ""; return Message::State::MimeBoundary; } return Message::State::Data; } Message::State::type Message::ProcessMimeBoundary(const std::string& line) { if (line.empty()) { if (StringAlgorithm::istarts_with(m_contentType, "image/jpeg") || StringAlgorithm::istarts_with(m_contentType, "image/jpg")) { m_mimeImages.push_back(Image::MimeImage(m_imageName)); m_imageName = ""; return Message::State::Image; } return Message::State::Data; } if (StringAlgorithm::istarts_with(line, "content-type:")) { m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end()); return Message::State::MimeBoundary; } if (StringAlgorithm::istarts_with(line, "name") || StringAlgorithm::istarts_with(line, "\tname")) { m_imageName = "image.jpg"; //m_imageName = Decode(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"'))); return Message::State::MimeBoundary; } if (StringAlgorithm::istarts_with(line, "content-transfer-encoding:")) { m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end()); return Message::State::MimeBoundary; } return Message::State::MimeBoundary; } Message::State::type Message::ProcessImage(const std::string& line) { if (StringAlgorithm::istarts_with(line, m_mimeBoundary)) { m_images.push_back(m_mimeImages[m_currentImage].DecodeImageData()); ++m_currentImage; m_contentType = ""; return Message::State::MimeBoundary; } m_mimeImages[m_currentImage].AppendData(line); return Message::State::Image; } } // namespace MailServer