#include "web_export_server.h" #include "config.h" #include "flight_logbook.h" #include "sd_mutex.h" #include "airline_filter.h" #include "aircraft_watchlist.h" #include "aircraft_table.h" #include "settings_store.h" #include #include #include #include #include namespace WebExportServer { namespace { constexpr uint8_t MAX_DAYS_QUERIED = 31; WebServer server(80); // Only accept plain filenames/labels from form fields - no // "/" and no ".." - so that no escape from the respective // SD directory is possible via the WebUI (path traversal). bool isSafeName(const String& name) { if (name.length() == 0 || name.length() > 40) return false; if (name.indexOf('/') >= 0 || name.indexOf('\\') >= 0) return false; if (name.indexOf("..") >= 0) return false; return true; } // Intentional duplicates of the same-named (local/static) functions // from radar_screen.cpp - not exported there, and following the project's // established convention "each screen/module duplicates its own small // helpers instead of a shared module" (see e.g. timeout_screen.cpp), // deliberately redefined here instead of refactoring radar_screen.cpp. // If the logic in radar_screen.cpp changes, please keep this copy // in sync so that the WebUI radar shows the same rings/markers as the // device display. bool isEmergencySquawkWeb(const char* squawk) { if (!squawk[0]) return false; for (uint8_t i = 0; i < Config::EMERGENCY_SQUAWK_COUNT; i++) { if (strcmp(squawk, Config::EMERGENCY_SQUAWKS[i]) == 0) return true; } return false; } // "Notable" (orange ring) is currently limited to nothing at all - // the part about military/government callsign prefixes // (Config::NOTABLE_CALLSIGN_PREFIXES) is NOT implemented, because this // constant does not exist anywhere in the project (not even in // radar_screen.cpp) - the associated feature has never actually been // specified/implemented. "notable" is therefore hardcoded to false // below in handleRadarJson(). As soon as there is a real prefix list, // add an isNotableCallsignWeb() function analogous to // isEmergencySquawkWeb() here. bool isHeavyCategoryWeb(const char* category) { return category[0] == 'A' && category[1] == '5'; } String htmlHeader(const String& title) { String html; html += ""; html += ""; html += "" + title + ""; html += ""; html += "

" + title + "

"; return html; } // Live radar view for the start page: a that uses JavaScript // to fetch /radar.json every few seconds and draw the aircraft polar // (bearing/distance, exactly like on the device display). Intentionally // kept with fetch()-polling instead of WebSocket/SSE - significantly less // code and memory usage on the ESP32, and perfectly adequate for a page // occasionally opened from a phone. // // The range selector ("; for (uint8_t i = 0; i < Config::RANGE_STEP_COUNT; i++) { bool isDefault = fabsf(Config::RANGE_STEPS_KM[i] - deviceRangeKm) < 0.5f; html += "