diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c214e8..058af2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,24 +14,42 @@ if (NOT (BUILD_EMAIL_TO_TEXT_MODE OR BUILD_OCR_MODE OR BUILD_OFD_LOCAL_QR_SCAN O endif() if (BUILD_OFD_LOCAL_QR_SCAN OR BUILD_OFD_BINARYEYE_SCAN) - add_compile_definitions(BUILD_OFD_MODE) + if(CMAKE_VERSION VERSION_LESS 3.12) + add_definitions(BUILD_OFD_MODE) + else() + add_compile_definitions(BUILD_OFD_MODE) + endif() endif() if (BUILD_EMAIL_TO_TEXT_MODE) - add_compile_definitions(BUILD_EMAIL_TO_TEXT_MODE) + if(CMAKE_VERSION VERSION_LESS 3.12) + add_definitions(BUILD_EMAIL_TO_TEXT_MODE) + else() + add_compile_definitions(BUILD_EMAIL_TO_TEXT_MODE) + endif() endif() if (BUILD_OCR_MODE) - add_compile_definitions(BUILD_OCR_MODE) + if(CMAKE_VERSION VERSION_LESS 3.12) + add_definitions(BUILD_OCR_MODE) + else() + add_compile_definitions(BUILD_OCR_MODE) + endif() endif() if (BUILD_OFD_LOCAL_QR_SCAN) - add_compile_definitions(BUILD_OFD_LOCAL_QR_SCAN) + if(CMAKE_VERSION VERSION_LESS 3.12) + add_definitions(BUILD_OFD_LOCAL_QR_SCAN) + else() + add_compile_definitions(BUILD_OFD_LOCAL_QR_SCAN) + endif() endif() if (BUILD_OFD_BINARYEYE_SCAN) - add_compile_definitions(BUILD_OFD_BINARYEYE_SCAN) + if(CMAKE_VERSION VERSION_LESS 3.12) + add_definitions(BUILD_OFD_BINARYEYE_SCAN) + else() + add_compile_definitions(BUILD_OFD_BINARYEYE_SCAN) + endif() endif() -include(FetchContent) - SET(CMAKE_BUILD_TYPE Debug) set(CMAKE_AUTOUIC ON) @@ -98,6 +116,7 @@ endif() if (BUILD_OFD_BINARYEYE_SCAN OR BUILD_OFD_LOCAL_QR_SCAN) list(APPEND PROJECT_SOURCES exceptions/ofdrequestexception.h exceptions/ofdrequestexception.cpp) + list(APPEND PROJECT_SOURCES http_server/http_server.h http_server/http_server.cpp) endif() if (BUILD_TRANSLATIONS) @@ -190,6 +209,7 @@ endif() if (BUILD_OCR_MODE) target_link_libraries(checks-parser PRIVATE -ltesseract) endif() + target_link_libraries(checks-parser PRIVATE -lcurl) if (BUILD_OCR_MODE OR BUILD_OFD_LOCAL_QR_SCAN OR BUILD_OFD_BINARYEYE_SCAN) @@ -199,14 +219,6 @@ if (BUILD_OCR_MODE OR BUILD_OFD_LOCAL_QR_SCAN OR BUILD_OFD_BINARYEYE_SCAN) include_directories( ${OpenCV_INCLUDE_DIRS} ) endif() -if(BUILD_OFD_BINARYEYE_SCAN) - FetchContent_Declare(httplib SYSTEM - GIT_REPOSITORY https://github.com/yhirose/cpp-httplib - GIT_TAG 787a34ad7f01f20922a237d5142aae469828be72 - GIT_SHALLOW TRUE) - FetchContent_MakeAvailable(httplib) - target_link_libraries(checks-parser PRIVATE httplib) -endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8) target_link_libraries(checks-parser PRIVATE -lstdc++fs) endif() diff --git a/README.ru.md b/README.ru.md index 21b7b29..80acf74 100644 --- a/README.ru.md +++ b/README.ru.md @@ -29,6 +29,7 @@ * curl * nlohmann-json * qt5 +* qrencode Пожалуйста, не стесняйтесь и открывайте issue, если вы не можете собрать приложение. Я помогу вам, и если вы собираете приложение на дистрибутиве, который здесь не перечислен, как только мы решим вашу проблему, я добавлю новый дистрибутив в этот список! diff --git a/deploy/appimage/AppRun b/deploy/appimage/AppRun index 4a78749..352e769 100644 --- a/deploy/appimage/AppRun +++ b/deploy/appimage/AppRun @@ -1,4 +1,5 @@ #!/bin/bash export TESSDATA_PREFIX=$APPDIR/usr/share/tesseract-ocr/4.00/tessdata +export LD_LIBRARY_PATH=$APPDIR/usr/lib -$APPDIR/usr/bin/checks-parser +$APPDIR/usr/bin/checks-parser diff --git a/http_server/http_server.cpp b/http_server/http_server.cpp new file mode 100644 index 0000000..4d7404b --- /dev/null +++ b/http_server/http_server.cpp @@ -0,0 +1,112 @@ +#include "http_server.h" +#include +#include +#include +#include +#include +#include + +void HttpServer::generateRandomPort() { + port = rand() % (65535 - 1024) + 1024; +} + +HttpServer::HttpServer(QWidget *caller) : caller(caller) { + started = false; + port = 8080; +} + +HttpServer::~HttpServer() { + started = false; + shutdown(serverSocket, SHUT_RDWR); + close(serverSocket); + + for (auto &thread : clientHandlersThreads) { + thread.join(); + } + + listenClientsThread.join(); +} + +int HttpServer::start() { + unsigned short number_of_retries = 0; + + while (number_of_retries < 10) { + + serverSocket = socket(AF_INET, SOCK_STREAM, 0); + if (serverSocket < 0) { + std::cerr << "Could not obtain socket." << std::endl; + number_of_retries ++; + continue; + } + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(port); + serverAddress.sin_addr.s_addr = INADDR_ANY; + + if (bind(serverSocket, (sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) { + std::cerr << "Port " << port << " seems to be occupied. Trying to generate another one" << std::endl; + number_of_retries ++; + generateRandomPort(); + continue; + } + + if (listen(serverSocket, 1) < 0) { + std::cerr << "Could not listen port." << std::endl; + number_of_retries ++; + generateRandomPort(); + continue; + } + started = true; + std::cout << "Listening on port: " << port << std::endl; + listenClientsThread = std::thread(&HttpServer::acceptClients, this); + return 0; + } + return -1; +} + +void HttpServer::handleClient(int clientSocket) { + std::string localIp; + try { + localIp = get_local_ip_address(); + } catch(std::exception e) { + std::cerr << e.what() << std::endl; + close(clientSocket); + return; + } + + char buffer[256] = {0}; + + recv(clientSocket, buffer, 256, 0); + + std::string response = "HTTP/1.1 301 Moved Permanently\r\n" + "Content-Length: 0\r\n" + "Keep-Alive: timeout=5, max=100\r\n" + "Location: binaryeye://scan/?ret=http://" + get_local_ip_address() + ":" + std::to_string(port) + "/?result={RESULT}\r\n" + "\r\n"; + + if (send(clientSocket, response.c_str(), response.length(), 0) < 0) { + std::cerr << response.c_str() << std::endl; + std::cerr << response.length() << std::endl; + std::cerr << "Could not send message" << std::endl; + } + emit ((OFDScene *)caller)->httpNewMessage(QString::fromStdString(std::string(buffer))); +} + +void HttpServer::acceptClients() { + while (true) { + if (!started) return; + int clientSocket = accept(serverSocket, nullptr, nullptr); + if (!started) return; + + clientHandlersThreads.push_back ( + std::thread(&HttpServer::handleClient, this, clientSocket) + ); + } +} + +unsigned short HttpServer::getPort() { + return port; +} + +bool HttpServer::isStarted() { + return started; +} diff --git a/http_server/http_server.h b/http_server/http_server.h new file mode 100644 index 0000000..af3b40c --- /dev/null +++ b/http_server/http_server.h @@ -0,0 +1,37 @@ +#ifndef CHECKS_PARSER_HTTP_SERVER +#define CHECKS_PARSER_HTTP_SERVER + +#include +#include +#include +#include + + +class HttpServer { +private: + unsigned short port; + int serverSocket; + sockaddr_in serverAddress; + + QWidget* caller; + + std::thread listenClientsThread; + std::vector clientHandlersThreads; + + bool started; + + void generateRandomPort(); +public: + HttpServer(QWidget *caller); + ~HttpServer(); + int start(); + void stop(); + void handleClient(int clientSocket); + void acceptClients(); + + unsigned short getPort(); + + bool isStarted(); +}; + +#endif //CHECKS_PARSER_HTTP_SERVER diff --git a/mainwindow.cpp b/mainwindow.cpp index 177df99..412022d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -6,8 +6,6 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); - - std::cout << "test" << std::endl; } MainWindow::~MainWindow() { diff --git a/ofdscene.cpp b/ofdscene.cpp index 84c681a..b9546f3 100644 --- a/ofdscene.cpp +++ b/ofdscene.cpp @@ -1,38 +1,70 @@ #include "ofdscene.h" +#include "scenes/ui_ofdscene.h" #include "ui_ofdscene.h" -#include "utils/utils.h" #include #include -#include -#include +#include + +#ifdef BUILD_OFD_LOCAL_QR_SCAN +# include +#endif + #include -#include #include - #include +#include #include -#include -#include -#include +#ifdef BUILD_OFD_BINARYEYE_SCAN +# include +# include +# include +# include +# include +# include +# include +#endif OFDScene::OFDScene(QWidget *parent) : QWidget(parent) , ui(new Ui::OFDScene) { ui->setupUi(this); ui->stop_server_button->hide(); + // std::string message = "GET /?result=t=20171112T153500&s=834.25&fn=8712000101054551&i=32332&fp=2169935838&n=1 HTTP/1.1\nHost: localhost:8080\nUser-Agent: curl/8.12.1\nAccept: */*"; + // emit this->httpNewMessage(message); +#ifdef BUILD_OFD_BINARYEYE_SCAN QObject::connect(this, &OFDScene::httpErrorOccured, this, &OFDScene::notifyHttpServerFailure); + connect(this, SIGNAL(httpNewMessage(QString)), this, SLOT(httpNewMessageHandler(QString))); +#endif +} + +Ui::OFDScene *OFDScene::getUI() { + return ui; } OFDScene::~OFDScene() { delete ui; } +#ifdef BUILD_OFD_BINARYEYE_SCAN void OFDScene::startHttpServer() { - std::string localIp = ""; + server = new HttpServer(this); + if (server->start() < 0) { + emit httpErrorOccured(); + } +} + +void OFDScene::on_binary_eye_button_clicked() { + httpServerThread = new std::thread(&OFDScene::startHttpServer, this); + ui->binary_eye_button->setEnabled(false); + ui->stop_server_button->show(); + + while (!server->isStarted()) {} + + std::string localIp; try { localIp = get_local_ip_address(); } catch(std::exception e) { @@ -40,48 +72,55 @@ void OFDScene::startHttpServer() { return; } - unsigned short number_of_retries = 0; + std::string connectionString = "binaryeye://scan?ret=http://" + localIp + ":" + std::to_string(server->getPort()) + "/?result={RESULT}"; - do { - if (number_of_retries == 10) { - emit httpErrorOccured(); - return; - } - this->port = rand() % (65535 - 1024) + 1024; + generate_qr_code(connectionString); - std::string connectionString = "binaryeye://scan/?ret=http://"+ localIp +":"+ std::to_string(port) +"/?result={RESULT}"; - - server.Get("/", [&](const httplib::Request &req, httplib::Response &res){ - std::cout << "New http connection" < paramsMap; - if (req.params.size() < 1) { - res.set_redirect(connectionString, 301); - std::cerr << "Too few params: " << req.params.size() << std::endl; - return; - } - std::string result = req.params.find("result")->second; - std::vector dataSplit = split(result, "&"); - for (std::string &pair : dataSplit) { - std::vector values = split(pair, "="); - paramsMap.insert(std::pair(values[0], values[1])); - } - - emit onDataDecode(paramsMap); - - res.set_redirect(connectionString, 301); - }); - - std::cout << "Listening on port: " << this->port << std::endl; - if (!server.listen("0.0.0.0", this->port)) { - std::cerr << "Random port seems to be occupied. Trying to generate another one" << std::endl; - number_of_retries ++; - continue; - } else { - break; - } - } while(true); + QMessageBox infoDialog = QMessageBox(); + infoDialog.setText(QString::fromStdString(connectionString)); + infoDialog.setIconPixmap(QPixmap(QString::fromStdString(get_path_relative_to_home(".local/share/checks_parser/binaryeye_connection.png"))).scaled(400, 400, Qt::KeepAspectRatio)); + infoDialog.setWindowTitle(tr("QR code for binaryeye to connect")); + infoDialog.setButtonText(1, tr("I've scanned")); + infoDialog.exec(); } +void OFDScene::notifyHttpServerFailure() { + QMessageBox infoDialog = QMessageBox(); + infoDialog.setText(tr("Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn't lucky, please, contact the developer.")); + infoDialog.setIcon(QMessageBox::Warning); + infoDialog.setWindowTitle(tr("Could not start http server.")); + infoDialog.exec(); +} + +void OFDScene::on_stop_server_button_clicked() { + delete server; + ui->stop_server_button->hide(); + ui->binary_eye_button->setEnabled(true); +} + +void OFDScene::httpNewMessageHandler(QString message) { + // std::cout << message << std::endl; + std::string parametersString = split(message.toStdString(), " ")[1]; + + //erase /?result= from the string + parametersString.erase(0, parametersString.find("=") + 1); + + std::vector parameters = split(parametersString, "&"); + + std::map paramsMap; + + for (auto ¶meter : parameters) { + std::vector values = split(parameter, "="); + paramsMap.insert(std::pair (values[0], values[1])); + } + + emit onDataDecode(paramsMap); +} + + +#endif //ifdef BUILD_OFD_BINARYEYE_SCAN + +#ifdef BUILD_OFD_LOCAL_QR_SCAN void OFDScene::on_choose_image_button_clicked() { QString filename = QFileDialog::getOpenFileName(); @@ -100,6 +139,7 @@ void OFDScene::on_choose_image_button_clicked() { connect(&dialog, &AdjustPictureDialog::decodedData, this, &OFDScene::onDataDecode); dialog.exec(); } +#endif //ifdef BUILD_OFD_LOCAL_QR_SCAN void OFDScene::onDataDecode(std::map data) { ui->fn_line_edit->setText(QString::fromStdString(data["fn"])); @@ -183,49 +223,3 @@ void OFDScene::on_parse_button_clicked() { delete d; } } - -void OFDScene::on_binary_eye_button_clicked() { - http_thread = new std::thread(&OFDScene::startHttpServer, this); - ui->binary_eye_button->setEnabled(false); - ui->stop_server_button->show(); - - while (!server.is_running()); - std::string localIp; - try { - localIp = get_local_ip_address(); - } catch(std::exception e) { - std::cerr << e.what() << std::endl; - return; - } - std::string connectionString = "binaryeye://scan?ret=http://" + localIp + ":" + std::to_string(port) + "/?result={RESULT}"; - - generate_qr_code(connectionString); - - QMessageBox infoDialog = QMessageBox(); - infoDialog.setText(QString::fromStdString(connectionString)); - infoDialog.setIconPixmap(QPixmap(QString::fromStdString(get_path_relative_to_home(".local/share/checks_parser/binaryeye_connection.png"))).scaled(400, 400, Qt::KeepAspectRatio)); - infoDialog.setWindowTitle(tr("QR code for binaryeye to connect")); - infoDialog.setButtonText(1, tr("I've scanned")); - infoDialog.exec(); -} - -void OFDScene::notifyHttpServerFailure() { - QMessageBox infoDialog = QMessageBox(); - infoDialog.setText(tr("Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn't lucky, please, contact the developer.")); - infoDialog.setIcon(QMessageBox::Warning); - infoDialog.setWindowTitle(tr("Could not start http server.")); - infoDialog.exec(); -} - -unsigned int OFDScene::getPort() { - return port; -} - - -void OFDScene::on_stop_server_button_clicked() { - server.stop(); - http_thread->join(); - ui->stop_server_button->hide(); - ui->binary_eye_button->setEnabled(true); -} - diff --git a/ofdscene.h b/ofdscene.h index 92ae8b4..b2dc550 100644 --- a/ofdscene.h +++ b/ofdscene.h @@ -2,9 +2,12 @@ #define OFDSCENE_H #include -#include -#include +#ifdef BUILD_OFD_BINARYEYE_SCAN +# include +# include +# include +#endif namespace Ui { class OFDScene; } @@ -15,31 +18,40 @@ class OFDScene : public QWidget public: explicit OFDScene(QWidget *parent = nullptr); + Ui::OFDScene *getUI(); ~OFDScene(); +#ifdef BUILD_OFD_BINARYEYE_SCAN void startHttpServer(); - - unsigned int getPort(); +#endif private slots: +#ifdef BUILD_OFD_LOCAL_QR_SCAN void on_choose_image_button_clicked(); - void onDataDecode(std::map); +#endif + void onDataDecode(std::map); void on_parse_button_clicked(); +#ifdef BUILD_OFD_BINARYEYE_SCAN + + void on_binary_eye_button_clicked(); void notifyHttpServerFailure(); - void on_stop_server_button_clicked(); +// public slots: + void httpNewMessageHandler(QString message); signals: - + void httpNewMessage(QString message); void httpErrorOccured(); +#endif private: Ui::OFDScene *ui; - std::thread *http_thread; - unsigned int port; - httplib::Server server; +#ifdef BUILD_OFD_BINARYEYE_SCAN + std::thread *httpServerThread; + HttpServer *server = NULL; +#endif }; #endif // OFDSCENE_H diff --git a/translations/en_US.ts b/translations/en_US.ts index 8c1226b..af0ac7d 100644 --- a/translations/en_US.ts +++ b/translations/en_US.ts @@ -372,67 +372,67 @@ Parse - + Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn't lucky, please, contact the developer. - + Could not start http server. - + Please, select a picture where QR code that contains info about check is present Please, select a picture where QR code that contains info about check is present - + Picture was not selected Picture was not selected - + Selected image: Selected image: - + Captcha was not solved correctly! Captcha was not solved correctly! - + Captcha is incorrect Captcha is incorrect - + Internal server error. Please, try again later. Internal server error. Please, try again later. - + Internal server error Internal server error - + Check not found. Please, ensure correctness of entered data. Check not found. Please, ensure correctness of entered data. - + Check was not found Check was not found - + QR code for binaryeye to connect - + I've scanned diff --git a/translations/ru_RU.ts b/translations/ru_RU.ts index 5de696c..ed7f001 100644 --- a/translations/ru_RU.ts +++ b/translations/ru_RU.ts @@ -372,67 +372,67 @@ Парсить - + Could not start http server. 10 times in a row random port was occupied. Either you should run for a lottery ticket, or the problem is in the program. If the lottery ticket wasn't lucky, please, contact the developer. - + Could not start http server. - + Please, select a picture where QR code that contains info about check is present Пожалуйста, выберете изображение, содержащее QR код с информацией о чеке - + Picture was not selected Изображение не было выбрано - + Selected image: Выбранное изображение: - + Captcha was not solved correctly! Капча была решена неверно! - + Captcha is incorrect Капча введена неверно - + Internal server error. Please, try again later. Внутренняя ошибка сервера. Пожалуйста, попробуйте снова позже. - + Internal server error Внутренняя ошибка сервера - + Check not found. Please, ensure correctness of entered data. Чек не найден. Пожалуйста, убедитесь в правильности введённых данных. - + Check was not found Чек не найден - + QR code for binaryeye to connect - + I've scanned