Message.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #include "Message.h"
  2. #include "Util/Base64.h"
  3. #include <JpegImageCollection.h>
  4. #include <Logging.h>
  5. #include <StringAlgorithm.h>
  6. #include <filesystem/path.h>
  7. #include <sstream>
  8. namespace MailServer {
  9. Message::Message(const std::string& address, const Util::Context& context, const std::string& message) :
  10. m_address(address),
  11. m_context(context),
  12. m_mimeBoundary("-_-InvalidBoundary-_-"),
  13. m_contentEncoding("none"),
  14. m_currentImage(0)
  15. {
  16. ProcessMessage(message);
  17. }
  18. std::string Decode(const std::string& data)
  19. {
  20. std::string result;
  21. if (StringAlgorithm::istarts_with(data, "=?utf-8?"))
  22. result = Util::Base64::Decode(std::string(data.begin() + 10, data.begin() + data.find_last_of('?')));
  23. else
  24. result = Util::Base64::Decode(data);
  25. return result;
  26. }
  27. void Message::ProcessMessage(const std::string& message)
  28. {
  29. try
  30. {
  31. Message::State::type state = Message::State::Header;
  32. std::string line;
  33. std::istringstream stream(message);
  34. while (std::getline(stream, line, '\r'))
  35. {
  36. StringAlgorithm::erase_all(line, '\n');
  37. switch (state)
  38. {
  39. case State::Header:
  40. state = ProcessHeaderLine(line);
  41. break;
  42. case State::Data:
  43. state = ProcessDataLine(line);
  44. break;
  45. case State::MimeBoundary:
  46. state = ProcessMimeBoundary(line);
  47. break;
  48. case State::Image:
  49. state = ProcessImage(line);
  50. break;
  51. }
  52. }
  53. if (StringAlgorithm::contains(m_contentEncoding, "base64"))
  54. {
  55. std::string decoded = Decode(m_subject);
  56. if (decoded.size() > 0)
  57. m_subject = decoded;
  58. }
  59. std::stringstream ss;
  60. ss << "From: " << m_sender << std::endl;
  61. Logging::Log(Logging::Severity::Debug, ss.str());
  62. ss.str("");
  63. ss << "To: " << m_receiver << std::endl;
  64. Logging::Log(Logging::Severity::Debug, ss.str());
  65. ss.str("");
  66. ss << "Subject: " << m_subject << std::endl;
  67. Logging::Log(Logging::Severity::Debug, ss.str());
  68. ss.str("");
  69. ss << "Received " << m_images.size() << " Images" << std::endl;
  70. Logging::Log(Logging::Severity::Info, ss.str());
  71. Image::JpegImageCollection imageCollection(m_images);
  72. filesystem::path path(m_context.path);
  73. path = path.make_absolute();
  74. path = path/filesystem::path(m_address);
  75. if (!path.exists())
  76. filesystem::create_directory(path);
  77. std::string fileName(Util::getTimeString());
  78. fileName.append(".jpg");
  79. path = path/filesystem::path(fileName);
  80. imageCollection.Save(path.str());
  81. ss.str("");
  82. ss << "Images Stored as " << path.str() << std::endl;
  83. Logging::Log(Logging::Severity::Info, ss.str());
  84. if (!m_context.url.empty())
  85. {
  86. std::stringstream url;
  87. url << m_context.url << "?ip=" << m_address << "&file=" << fileName;
  88. Http::HttpRequest request(url.str());
  89. m_context.client.Open(request);
  90. }
  91. }
  92. catch (std::exception& e)
  93. {
  94. std::stringstream ss;
  95. ss << "Message::ProcessMessage() - Error: " << e.what() << std::endl;
  96. Logging::Log(Logging::Severity::Error, ss.str());
  97. }
  98. }
  99. Message::State::type Message::ProcessHeaderLine(const std::string& line)
  100. {
  101. if (line.empty())
  102. return Message::State::Data;
  103. if (StringAlgorithm::istarts_with(line, "from:"))
  104. {
  105. m_sender = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
  106. return Message::State::Header;
  107. }
  108. if (StringAlgorithm::istarts_with(line, "to:"))
  109. {
  110. m_receiver = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
  111. return Message::State::Header;
  112. }
  113. if (StringAlgorithm::istarts_with(line, "subject:"))
  114. {
  115. m_subject = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
  116. return Message::State::Header;
  117. }
  118. if (StringAlgorithm::istarts_with(line, "date"))
  119. {
  120. m_date = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
  121. return Message::State::Header;
  122. }
  123. if (StringAlgorithm::istarts_with(line, "content-type:"))
  124. {
  125. m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
  126. return Message::State::Header;
  127. }
  128. if (StringAlgorithm::istarts_with(line, "boundary") || StringAlgorithm::istarts_with(line, "\tboundary") || StringAlgorithm::istarts_with(line, " boundary"))
  129. {
  130. m_mimeBoundary = std::string("--").append(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"')));
  131. return Message::State::Header;
  132. }
  133. if (StringAlgorithm::istarts_with(line, "content-transfer-encoding:"))
  134. {
  135. m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
  136. return Message::State::Header;
  137. }
  138. return Message::State::Header;
  139. }
  140. Message::State::type Message::ProcessDataLine(const std::string& line)
  141. {
  142. if (StringAlgorithm::istarts_with(line, m_mimeBoundary))
  143. {
  144. m_contentType = "";
  145. return Message::State::MimeBoundary;
  146. }
  147. return Message::State::Data;
  148. }
  149. Message::State::type Message::ProcessMimeBoundary(const std::string& line)
  150. {
  151. if (line.empty())
  152. {
  153. if (StringAlgorithm::istarts_with(m_contentType, "image/jpeg") || StringAlgorithm::istarts_with(m_contentType, "image/jpg"))
  154. {
  155. m_mimeImages.push_back(Image::MimeImage(m_imageName));
  156. m_imageName = "";
  157. return Message::State::Image;
  158. }
  159. return Message::State::Data;
  160. }
  161. if (StringAlgorithm::istarts_with(line, "content-type:"))
  162. {
  163. m_contentType = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
  164. return Message::State::MimeBoundary;
  165. }
  166. if (StringAlgorithm::istarts_with(line, "name") || StringAlgorithm::istarts_with(line, "\tname"))
  167. {
  168. m_imageName = "image.jpg";
  169. //m_imageName = Decode(std::string(line.begin() + line.find_first_of('"') + 1, line.begin() + line.find_last_of('"')));
  170. return Message::State::MimeBoundary;
  171. }
  172. if (StringAlgorithm::istarts_with(line, "content-transfer-encoding:"))
  173. {
  174. m_contentEncoding = std::string(line.begin() + line.find_first_of(' ') + 1, line.end());
  175. return Message::State::MimeBoundary;
  176. }
  177. return Message::State::MimeBoundary;
  178. }
  179. Message::State::type Message::ProcessImage(const std::string& line)
  180. {
  181. if (StringAlgorithm::istarts_with(line, m_mimeBoundary))
  182. {
  183. m_images.push_back(m_mimeImages[m_currentImage].DecodeImageData());
  184. ++m_currentImage;
  185. m_contentType = "";
  186. return Message::State::MimeBoundary;
  187. }
  188. m_mimeImages[m_currentImage].AppendData(line);
  189. return Message::State::Image;
  190. }
  191. } // namespace MailServer