#include "utils/utils.h" #include "utils/base64.h" #include #include #include #include #include #include #include #include #include #include #include #include #if __GNUC__ < 8 && __clang_major__ < 17 # include using namespace std::experimental::filesystem; #else # include using namespace std::filesystem; #endif EmailParser::EmailParser() { } std::map EmailParser::parse(std::string &email_content) { //1. Search "Content-Type: image/.*" in the .eml file. // 1.1 If found 0, go to [2] // 1.2 If found 1, try decoding it, if it's not a QR code, go to [2] // 1.3 Loop through every found entry. If not found in any, go to [2] //2. Try decoding content of the e-mail //3. Search "t=\d{8}T\d{4,6}&s=\d{1,6}\.\d{1,2}&fn=\d{10,16}&i=\d{6}&fp=\d{10}&n=\d". Note that in some emails = and & signs could be replaced with its code in HTTP requests: %3D, %26 // 3.1 If not found, notify the user that we could not parse the .eml file /* Find content-types */ Check c; std::vector> content_types = {}; boost::regex content_type_regex("Content-Type: image/(gif|png|jpg)"); boost::regex part_end_regex("--.{5,48}"); for (boost::sregex_iterator it{email_content.begin(), email_content.end(), content_type_regex}, end{}; it != end; it ++) { unsigned int start_position = it->position(), end_position = -1; for (boost::sregex_iterator it2{email_content.begin() + start_position, email_content.end(), part_end_regex}, end2{}; it2 != end2; it2++) { end_position = it2->position(); break; } content_types.push_back(std::pair(start_position, end_position)); } /* iterate through found content-types and try searching qr codes, decode them and see if it's the needed data */ for (unsigned int i = 0; i < content_types.size(); i ++) { boost::regex to_erase("(Content.{5,64}\\r\\n)+"); boost::regex to_erase_two("--.{5,48}"); std::string part = email_content.substr(content_types[i].first, content_types[i].second); boost::erase_regex(part, to_erase); boost::erase_regex(part, to_erase_two); part.erase(std::remove(part.begin(), part.end(), '\r'), part.end()); part.erase(std::remove(part.begin(), part.end(), '\n'), part.end()); std::string decoded = base64_decode(part); cv::Mat image; if (decoded.substr(1, 3) == "PNG" || decoded.substr(1, 3) == "JPG") { std::vector data(decoded.begin(), decoded.end()); image = cv::imdecode(cv::Mat(data), 1); } else if (decoded.substr(0, 3) == "GIF") { std::string gif_file_path = get_application_home_path() + "/temp.gif"; std::ofstream gif_output(gif_file_path, std::ios::binary); gif_output << decoded; gif_output.close(); cv::VideoCapture gif(gif_file_path, cv::CAP_FFMPEG); gif.read(image); } cv::QRCodeDetector qrDecoder = cv::QRCodeDetector(); std::string decoded_qr_params = qrDecoder.detectAndDecode(image); boost::regex check_data_content("t=\\d+T\\d+&s=\\d+\\.\\d+&fn=\\d{16}&i=\\d{4,5}&fp=\\d{10}&n=\\d"); if (boost::regex_match(decoded_qr_params, check_data_content)) { std::map paramsMap = get_params_from_string(decoded_qr_params); return paramsMap; } } /* If the E-Mail has no QR code in it as a separate part, there's posibilly a QR code inserted using html's tag with base64-encoded image. Try searching it */ /* If there's no such case, the last chance is which will have a link with needed parameters or the qr code that should be downloaded and decoded */ /* If the code has reached this part and found nothing, it's most likely that there are no QR codes at all. */ // return Check(); } std::map EmailParser::parse_file(std::string path) { std::ifstream ifile(path, std::ios::in | std::ios::binary); const unsigned int size = std::filesystem::file_size(path); std::string content(size, '\0'); ifile.read(content.data(), size); return parse(content); return std::map(); }