jblanked 1 год назад
Родитель
Сommit
79d186b44a

+ 1 - 0
CHANGELOG.md

@@ -1,5 +1,6 @@
 ## 0.7
 ## 0.7
 - Improved memory allocation
 - Improved memory allocation
+- App restructured
 
 
 ## 0.6
 ## 0.6
 - Added a DOWNLOAD method, which downloads the file at the specified path. This is best used for downloading images, binary files, and other non-text files.
 - Added a DOWNLOAD method, which downloads the file at the specified path. This is best used for downloading images, binary files, and other non-text files.

+ 0 - 21
LICENSE

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2024 jblanked
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 5 - 1
README.md

@@ -49,7 +49,7 @@
    - Enter the complete URL of the website you intend to crawl (e.g., https://www.example.com/).
    - Enter the complete URL of the website you intend to crawl (e.g., https://www.example.com/).
 
 
 2. **HTTP Method**
 2. **HTTP Method**
-   - Choose between GET, POST, DELETE, and PUT.
+   - Choose between GET, POST, DELETE, PUT, and DOWNLOAD.
 
 
 3. **Headers**
 3. **Headers**
    - Add your required headers to be used in your HTTP requests
    - Add your required headers to be used in your HTTP requests
@@ -81,4 +81,8 @@ The Web Crawler app uses logging to help identify issues:
 
 
 Connect your Flipper Zero to a computer and use a serial terminal to view these logs for detailed troubleshooting.
 Connect your Flipper Zero to a computer and use a serial terminal to view these logs for detailed troubleshooting.
 
 
+## Known Issues
+1. **Screen Delay**: Occasionally, the Run screen may get stuck on "Receiving Data".
+   - If it takes longer than 10 seconds, restart your Flipper Zero.
+
 *Happy Crawling! 🕷️* 
 *Happy Crawling! 🕷️* 

+ 1 - 6
web_crawler_i.h → alloc/web_crawler_alloc.c

@@ -1,5 +1,4 @@
-#ifndef WEB_CRAWLER_I_H
-#define WEB_CRAWLER_I_H
+#include <alloc/web_crawler_alloc.h>
 
 
 /**
 /**
  * @brief      Function to allocate resources for the WebCrawlerApp.
  * @brief      Function to allocate resources for the WebCrawlerApp.
@@ -330,12 +329,8 @@ WebCrawlerApp *web_crawler_app_alloc()
         // Password handling can be omitted for security or handled securely
         // Password handling can be omitted for security or handled securely
     }
     }
 
 
-    app_instance = app;
-
     // Start with the Submenu view
     // Start with the Submenu view
     view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewSubmenuMain);
     view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewSubmenuMain);
 
 
     return app;
     return app;
 }
 }
-
-#endif // WEB_CRAWLER_I_H

+ 14 - 0
alloc/web_crawler_alloc.h

@@ -0,0 +1,14 @@
+#ifndef WEB_CRAWLER_I_H
+#define WEB_CRAWLER_I_H
+
+#include <web_crawler.h>
+#include <callback/web_crawler_callback.h>
+#include <flip_storage/web_crawler_storage.h>
+
+/**
+ * @brief      Function to allocate resources for the WebCrawlerApp.
+ * @return     Pointer to the initialized WebCrawlerApp, or NULL on failure.
+ */
+WebCrawlerApp *web_crawler_app_alloc();
+
+#endif // WEB_CRAWLER_I_H

+ 6 - 11
app.c

@@ -1,10 +1,5 @@
-#include <uart_text_input.h>
-#include <web_crawler_e.h>
-#include <flipper_http.h>
-#include <web_crawler_storage.h>
-#include <web_crawler_free.h>
-#include <web_crawler_callback.h>
-#include <web_crawler_i.h>
+#include <web_crawler.h>
+#include <alloc/web_crawler_alloc.h>
 /**
 /**
  * @brief      Entry point for the WebCrawler application.
  * @brief      Entry point for the WebCrawler application.
  * @param      p  Input parameter - unused
  * @param      p  Input parameter - unused
@@ -14,8 +9,8 @@ int32_t web_crawler_app(void *p)
 {
 {
     UNUSED(p);
     UNUSED(p);
 
 
-    WebCrawlerApp *app = web_crawler_app_alloc();
-    if (!app)
+    app_instance = web_crawler_app_alloc();
+    if (!app_instance)
     {
     {
         FURI_LOG_E(TAG, "Failed to allocate WebCrawlerApp");
         FURI_LOG_E(TAG, "Failed to allocate WebCrawlerApp");
         return -1;
         return -1;
@@ -28,10 +23,10 @@ int32_t web_crawler_app(void *p)
     }
     }
 
 
     // Run the application
     // Run the application
-    view_dispatcher_run(app->view_dispatcher);
+    view_dispatcher_run(app_instance->view_dispatcher);
 
 
     // Free resources after the application loop ends
     // Free resources after the application loop ends
-    web_crawler_app_free(app);
+    web_crawler_app_free(app_instance);
 
 
     return 0;
     return 0;
 }
 }

+ 33 - 45
web_crawler_callback.h → callback/web_crawler_callback.c

@@ -1,21 +1,9 @@
-// web_crawler_callback.h
-static bool sent_http_request = false;
-static bool get_success = false;
-static bool already_success = false;
-static WebCrawlerApp *app_instance = NULL;
-
-// Forward declaration of callback functions
-static void web_crawler_setting_item_path_clicked(void *context, uint32_t index);
-static void web_crawler_setting_item_headers_clicked(void *context, uint32_t index);
-static void web_crawler_setting_item_payload_clicked(void *context, uint32_t index);
-static void web_crawler_setting_item_ssid_clicked(void *context, uint32_t index);
-static void web_crawler_setting_item_password_clicked(void *context, uint32_t index);
-static void web_crawler_setting_item_file_type_clicked(void *context, uint32_t index);
-static void web_crawler_setting_item_file_rename_clicked(void *context, uint32_t index);
-static void web_crawler_setting_item_file_delete_clicked(void *context, uint32_t index);
-static void web_crawler_setting_item_file_read_clicked(void *context, uint32_t index);
-
-static void web_crawler_http_method_change(VariableItem *item)
+#include <callback/web_crawler_callback.h>
+bool sent_http_request = false;
+bool get_success = false;
+bool already_success = false;
+
+void web_crawler_http_method_change(VariableItem *item)
 {
 {
     uint8_t index = variable_item_get_current_value_index(item);
     uint8_t index = variable_item_get_current_value_index(item);
     variable_item_set_current_value_text(item, http_method_names[index]);
     variable_item_set_current_value_text(item, http_method_names[index]);
@@ -38,7 +26,7 @@ static void web_crawler_http_method_change(VariableItem *item)
     }
     }
 }
 }
 
 
-static void web_crawler_view_draw_callback(Canvas *canvas, void *context)
+void web_crawler_view_draw_callback(Canvas *canvas, void *context)
 {
 {
     UNUSED(context);
     UNUSED(context);
     if (!app_instance)
     if (!app_instance)
@@ -209,7 +197,7 @@ static void web_crawler_view_draw_callback(Canvas *canvas, void *context)
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  * @return     WebCrawlerViewSubmenu
  * @return     WebCrawlerViewSubmenu
  */
  */
-static uint32_t web_crawler_back_to_configure_callback(void *context)
+uint32_t web_crawler_back_to_configure_callback(void *context)
 {
 {
     UNUSED(context);
     UNUSED(context);
     // free file read widget if it exists
     // free file read widget if it exists
@@ -225,7 +213,7 @@ static uint32_t web_crawler_back_to_configure_callback(void *context)
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  * @return     WebCrawlerViewSubmenu
  * @return     WebCrawlerViewSubmenu
  */
  */
-static uint32_t web_crawler_back_to_main_callback(void *context)
+uint32_t web_crawler_back_to_main_callback(void *context)
 {
 {
     UNUSED(context);
     UNUSED(context);
     // reset GET request flags
     // reset GET request flags
@@ -240,19 +228,19 @@ static uint32_t web_crawler_back_to_main_callback(void *context)
     return WebCrawlerViewSubmenuMain; // Return to the main submenu
     return WebCrawlerViewSubmenuMain; // Return to the main submenu
 }
 }
 
 
-static uint32_t web_crawler_back_to_file_callback(void *context)
+uint32_t web_crawler_back_to_file_callback(void *context)
 {
 {
     UNUSED(context);
     UNUSED(context);
     return WebCrawlerViewVariableItemListFile; // Return to the file submenu
     return WebCrawlerViewVariableItemListFile; // Return to the file submenu
 }
 }
 
 
-static uint32_t web_crawler_back_to_wifi_callback(void *context)
+uint32_t web_crawler_back_to_wifi_callback(void *context)
 {
 {
     UNUSED(context);
     UNUSED(context);
     return WebCrawlerViewVariableItemListWifi; // Return to the wifi submenu
     return WebCrawlerViewVariableItemListWifi; // Return to the wifi submenu
 }
 }
 
 
-static uint32_t web_crawler_back_to_request_callback(void *context)
+uint32_t web_crawler_back_to_request_callback(void *context)
 {
 {
     UNUSED(context);
     UNUSED(context);
     return WebCrawlerViewVariableItemListRequest; // Return to the request submenu
     return WebCrawlerViewVariableItemListRequest; // Return to the request submenu
@@ -263,7 +251,7 @@ static uint32_t web_crawler_back_to_request_callback(void *context)
  * @param      context   The context - unused
  * @param      context   The context - unused
  * @return     VIEW_NONE to exit the app
  * @return     VIEW_NONE to exit the app
  */
  */
-static uint32_t web_crawler_exit_app_callback(void *context)
+uint32_t web_crawler_exit_app_callback(void *context)
 {
 {
     UNUSED(context);
     UNUSED(context);
     return VIEW_NONE;
     return VIEW_NONE;
@@ -274,7 +262,7 @@ static uint32_t web_crawler_exit_app_callback(void *context)
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  * @param      index     The WebCrawlerSubmenuIndex item that was clicked.
  * @param      index     The WebCrawlerSubmenuIndex item that was clicked.
  */
  */
-static void web_crawler_submenu_callback(void *context, uint32_t index)
+void web_crawler_submenu_callback(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
 
 
@@ -313,7 +301,7 @@ static void web_crawler_submenu_callback(void *context, uint32_t index)
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  * @param      index     The index of the item that was clicked.
  * @param      index     The index of the item that was clicked.
  */
  */
-static void web_crawler_wifi_enter_callback(void *context, uint32_t index)
+void web_crawler_wifi_enter_callback(void *context, uint32_t index)
 {
 {
     switch (index)
     switch (index)
     {
     {
@@ -334,7 +322,7 @@ static void web_crawler_wifi_enter_callback(void *context, uint32_t index)
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  * @param      index     The index of the item that was clicked.
  * @param      index     The index of the item that was clicked.
  */
  */
-static void web_crawler_file_enter_callback(void *context, uint32_t index)
+void web_crawler_file_enter_callback(void *context, uint32_t index)
 {
 {
     switch (index)
     switch (index)
     {
     {
@@ -361,7 +349,7 @@ static void web_crawler_file_enter_callback(void *context, uint32_t index)
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  * @param      index     The index of the item that was clicked.
  * @param      index     The index of the item that was clicked.
  */
  */
-static void web_crawler_request_enter_callback(void *context, uint32_t index)
+void web_crawler_request_enter_callback(void *context, uint32_t index)
 {
 {
     switch (index)
     switch (index)
     {
     {
@@ -389,7 +377,7 @@ static void web_crawler_request_enter_callback(void *context, uint32_t index)
  * @brief      Callback for when the user finishes entering the URL.
  * @brief      Callback for when the user finishes entering the URL.
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  */
  */
-static void web_crawler_set_path_updated(void *context)
+void web_crawler_set_path_updated(void *context)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -421,7 +409,7 @@ static void web_crawler_set_path_updated(void *context)
  * @brief      Callback for when the user finishes entering the headers
  * @brief      Callback for when the user finishes entering the headers
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  */
  */
-static void web_crawler_set_headers_updated(void *context)
+void web_crawler_set_headers_updated(void *context)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -453,7 +441,7 @@ static void web_crawler_set_headers_updated(void *context)
  * @brief      Callback for when the user finishes entering the payload.
  * @brief      Callback for when the user finishes entering the payload.
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  */
  */
-static void web_crawler_set_payload_updated(void *context)
+void web_crawler_set_payload_updated(void *context)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -485,7 +473,7 @@ static void web_crawler_set_payload_updated(void *context)
  * @brief      Callback for when the user finishes entering the SSID.
  * @brief      Callback for when the user finishes entering the SSID.
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  */
  */
-static void web_crawler_set_ssid_updated(void *context)
+void web_crawler_set_ssid_updated(void *context)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -524,7 +512,7 @@ static void web_crawler_set_ssid_updated(void *context)
  * @brief      Callback for when the user finishes entering the Password.
  * @brief      Callback for when the user finishes entering the Password.
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  */
  */
-static void web_crawler_set_password_update(void *context)
+void web_crawler_set_password_update(void *context)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -563,7 +551,7 @@ static void web_crawler_set_password_update(void *context)
  * @brief      Callback for when the user finishes entering the File Type.
  * @brief      Callback for when the user finishes entering the File Type.
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  */
  */
-static void web_crawler_set_file_type_update(void *context)
+void web_crawler_set_file_type_update(void *context)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -611,7 +599,7 @@ static void web_crawler_set_file_type_update(void *context)
  * @brief      Callback for when the user finishes entering the File Rename.
  * @brief      Callback for when the user finishes entering the File Rename.
  * @param      context   The context - WebCrawlerApp object.
  * @param      context   The context - WebCrawlerApp object.
  */
  */
-static void web_crawler_set_file_rename_update(void *context)
+void web_crawler_set_file_rename_update(void *context)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -664,7 +652,7 @@ static void web_crawler_set_file_rename_update(void *context)
  * @param      context  The context - WebCrawlerApp object.
  * @param      context  The context - WebCrawlerApp object.
  * @param      index    The index of the item that was clicked.
  * @param      index    The index of the item that was clicked.
  */
  */
-static void web_crawler_setting_item_path_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_path_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -716,7 +704,7 @@ static void web_crawler_setting_item_path_clicked(void *context, uint32_t index)
  * @param      context  The context - WebCrawlerApp object.
  * @param      context  The context - WebCrawlerApp object.
  * @param      index    The index of the item that was clicked.
  * @param      index    The index of the item that was clicked.
  */
  */
-static void web_crawler_setting_item_headers_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_headers_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -777,7 +765,7 @@ static void web_crawler_setting_item_headers_clicked(void *context, uint32_t ind
  * @param      context  The context - WebCrawlerApp object.
  * @param      context  The context - WebCrawlerApp object.
  * @param      index    The index of the item that was clicked.
  * @param      index    The index of the item that was clicked.
  */
  */
-static void web_crawler_setting_item_payload_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_payload_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -828,7 +816,7 @@ static void web_crawler_setting_item_payload_clicked(void *context, uint32_t ind
  * @param      context  The context - WebCrawlerApp object.
  * @param      context  The context - WebCrawlerApp object.
  * @param      index    The index of the item that was clicked.
  * @param      index    The index of the item that was clicked.
  */
  */
-static void web_crawler_setting_item_ssid_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_ssid_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -879,7 +867,7 @@ static void web_crawler_setting_item_ssid_clicked(void *context, uint32_t index)
  * @param      context  The context - WebCrawlerApp object.
  * @param      context  The context - WebCrawlerApp object.
  * @param      index    The index of the item that was clicked.
  * @param      index    The index of the item that was clicked.
  */
  */
-static void web_crawler_setting_item_password_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_password_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -922,7 +910,7 @@ static void web_crawler_setting_item_password_clicked(void *context, uint32_t in
  * @param      context  The context - WebCrawlerApp object.
  * @param      context  The context - WebCrawlerApp object.
  * @param      index    The index of the item that was clicked.
  * @param      index    The index of the item that was clicked.
  */
  */
-static void web_crawler_setting_item_file_type_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_file_type_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -973,7 +961,7 @@ static void web_crawler_setting_item_file_type_clicked(void *context, uint32_t i
  * @param      context  The context - WebCrawlerApp object.
  * @param      context  The context - WebCrawlerApp object.
  * @param      index    The index of the item that was clicked.
  * @param      index    The index of the item that was clicked.
  */
  */
-static void web_crawler_setting_item_file_rename_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_file_rename_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -1024,7 +1012,7 @@ static void web_crawler_setting_item_file_rename_clicked(void *context, uint32_t
  * @param      context  The context - WebCrawlerApp object.
  * @param      context  The context - WebCrawlerApp object.
  * @param      index    The index of the item that was clicked.
  * @param      index    The index of the item that was clicked.
  */
  */
-static void web_crawler_setting_item_file_delete_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_file_delete_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)
@@ -1048,7 +1036,7 @@ static void web_crawler_setting_item_file_delete_clicked(void *context, uint32_t
     view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewFileDelete);
     view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewFileDelete);
 }
 }
 
 
-static void web_crawler_setting_item_file_read_clicked(void *context, uint32_t index)
+void web_crawler_setting_item_file_read_clicked(void *context, uint32_t index)
 {
 {
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     WebCrawlerApp *app = (WebCrawlerApp *)context;
     if (!app)
     if (!app)

+ 167 - 0
callback/web_crawler_callback.h

@@ -0,0 +1,167 @@
+#ifndef WEB_CRAWLER_CALLBACK_H
+#define WEB_CRAWLER_CALLBACK_H
+#include "web_crawler.h"
+#include <flip_storage/web_crawler_storage.h>
+
+extern bool sent_http_request;
+extern bool get_success;
+extern bool already_success;
+
+void web_crawler_http_method_change(VariableItem *item);
+
+void web_crawler_view_draw_callback(Canvas *canvas, void *context);
+
+/**
+ * @brief      Navigation callback to handle exiting from other views to the submenu.
+ * @param      context   The context - WebCrawlerApp object.
+ * @return     WebCrawlerViewSubmenu
+ */
+uint32_t web_crawler_back_to_configure_callback(void *context);
+
+/**
+ * @brief      Navigation callback to handle returning to the Wifi Settings screen.
+ * @param      context   The context - WebCrawlerApp object.
+ * @return     WebCrawlerViewSubmenu
+ */
+uint32_t web_crawler_back_to_main_callback(void *context);
+uint32_t web_crawler_back_to_file_callback(void *context);
+
+uint32_t web_crawler_back_to_wifi_callback(void *context);
+
+uint32_t web_crawler_back_to_request_callback(void *context);
+
+/**
+ * @brief      Navigation callback to handle exiting the app from the main submenu.
+ * @param      context   The context - unused
+ * @return     VIEW_NONE to exit the app
+ */
+uint32_t web_crawler_exit_app_callback(void *context);
+
+/**
+ * @brief      Handle submenu item selection.
+ * @param      context   The context - WebCrawlerApp object.
+ * @param      index     The WebCrawlerSubmenuIndex item that was clicked.
+ */
+void web_crawler_submenu_callback(void *context, uint32_t index);
+
+/**
+ * @brief      Configuration enter callback to handle different items.
+ * @param      context   The context - WebCrawlerApp object.
+ * @param      index     The index of the item that was clicked.
+ */
+void web_crawler_wifi_enter_callback(void *context, uint32_t index);
+
+/**
+ * @brief      Configuration enter callback to handle different items.
+ * @param      context   The context - WebCrawlerApp object.
+ * @param      index     The index of the item that was clicked.
+ */
+void web_crawler_file_enter_callback(void *context, uint32_t index);
+
+/**
+ * @brief      Configuration enter callback to handle different items.
+ * @param      context   The context - WebCrawlerApp object.
+ * @param      index     The index of the item that was clicked.
+ */
+void web_crawler_request_enter_callback(void *context, uint32_t index);
+
+/**
+ * @brief      Callback for when the user finishes entering the URL.
+ * @param      context   The context - WebCrawlerApp object.
+ */
+void web_crawler_set_path_updated(void *context);
+
+/**
+ * @brief      Callback for when the user finishes entering the headers
+ * @param      context   The context - WebCrawlerApp object.
+ */
+void web_crawler_set_headers_updated(void *context);
+
+/**
+ * @brief      Callback for when the user finishes entering the payload.
+ * @param      context   The context - WebCrawlerApp object.
+ */
+void web_crawler_set_payload_updated(void *context);
+
+/**
+ * @brief      Callback for when the user finishes entering the SSID.
+ * @param      context   The context - WebCrawlerApp object.
+ */
+void web_crawler_set_ssid_updated(void *context);
+
+/**
+ * @brief      Callback for when the user finishes entering the Password.
+ * @param      context   The context - WebCrawlerApp object.
+ */
+void web_crawler_set_password_update(void *context);
+
+/**
+ * @brief      Callback for when the user finishes entering the File Type.
+ * @param      context   The context - WebCrawlerApp object.
+ */
+void web_crawler_set_file_type_update(void *context);
+
+/**
+ * @brief      Callback for when the user finishes entering the File Rename.
+ * @param      context   The context - WebCrawlerApp object.
+ */
+void web_crawler_set_file_rename_update(void *context);
+
+/**
+ * @brief      Handler for Path configuration item click.
+ * @param      context  The context - WebCrawlerApp object.
+ * @param      index    The index of the item that was clicked.
+ */
+void web_crawler_setting_item_path_clicked(void *context, uint32_t index);
+
+/**
+ * @brief      Handler for headers configuration item click.
+ * @param      context  The context - WebCrawlerApp object.
+ * @param      index    The index of the item that was clicked.
+ */
+void web_crawler_setting_item_headers_clicked(void *context, uint32_t index);
+
+/**
+ * @brief      Handler for payload configuration item click.
+ * @param      context  The context - WebCrawlerApp object.
+ * @param      index    The index of the item that was clicked.
+ */
+void web_crawler_setting_item_payload_clicked(void *context, uint32_t index);
+
+/**
+ * @brief      Handler for SSID configuration item click.
+ * @param      context  The context - WebCrawlerApp object.
+ * @param      index    The index of the item that was clicked.
+ */
+void web_crawler_setting_item_ssid_clicked(void *context, uint32_t index);
+
+/**
+ * @brief      Handler for Password configuration item click.
+ * @param      context  The context - WebCrawlerApp object.
+ * @param      index    The index of the item that was clicked.
+ */
+void web_crawler_setting_item_password_clicked(void *context, uint32_t index);
+
+/**
+ * @brief      Handler for File Type configuration item click.
+ * @param      context  The context - WebCrawlerApp object.
+ * @param      index    The index of the item that was clicked.
+ */
+void web_crawler_setting_item_file_type_clicked(void *context, uint32_t index);
+
+/**
+ * @brief      Handler for File Rename configuration item click.
+ * @param      context  The context - WebCrawlerApp object.
+ * @param      index    The index of the item that was clicked.
+ */
+void web_crawler_setting_item_file_rename_clicked(void *context, uint32_t index);
+
+/**
+ * @brief      Handler for File Delete configuration item click.
+ * @param      context  The context - WebCrawlerApp object.
+ * @param      index    The index of the item that was clicked.
+ */
+void web_crawler_setting_item_file_delete_clicked(void *context, uint32_t index);
+
+void web_crawler_setting_item_file_read_clicked(void *context, uint32_t index);
+#endif

+ 2 - 25
easy_flipper.h → easy_flipper/easy_flipper.c

@@ -1,25 +1,4 @@
-#ifndef EASY_FLIPPER_H
-#define EASY_FLIPPER_H
-
-#include <malloc.h>
-#include <furi.h>
-#include <furi_hal.h>
-#include <gui/gui.h>
-#include <gui/view.h>
-#include <gui/modules/submenu.h>
-#include <gui/view_dispatcher.h>
-#include <gui/modules/menu.h>
-#include <gui/modules/submenu.h>
-#include <gui/modules/widget.h>
-#include <gui/modules/text_input.h>
-#include <gui/modules/text_box.h>
-#include <gui/modules/variable_item_list.h>
-#include <gui/modules/dialog_ex.h>
-#include <gui/modules/popup.h>
-#include <gui/modules/loading.h>
-#include <uart_text_input.h>
-
-#define EASY_TAG "EasyFlipper"
+#include <easy_flipper/easy_flipper.h>
 
 
 /**
 /**
  * @brief Navigation callback for exiting the application
  * @brief Navigation callback for exiting the application
@@ -588,6 +567,4 @@ bool easy_flipper_set_char_to_furi_string(FuriString **furi_string, char *buffer
     }
     }
     furi_string_set_str(*furi_string, buffer);
     furi_string_set_str(*furi_string, buffer);
     return true;
     return true;
-}
-
-#endif // EASY_FLIPPER_H
+}

+ 262 - 0
easy_flipper/easy_flipper.h

@@ -0,0 +1,262 @@
+#ifndef EASY_FLIPPER_H
+#define EASY_FLIPPER_H
+
+#include <malloc.h>
+#include <furi.h>
+#include <furi_hal.h>
+#include <gui/gui.h>
+#include <gui/view.h>
+#include <gui/modules/submenu.h>
+#include <gui/view_dispatcher.h>
+#include <gui/modules/menu.h>
+#include <gui/modules/submenu.h>
+#include <gui/modules/widget.h>
+#include <gui/modules/text_input.h>
+#include <gui/modules/text_box.h>
+#include <gui/modules/variable_item_list.h>
+#include <gui/modules/dialog_ex.h>
+#include <gui/modules/popup.h>
+#include <gui/modules/loading.h>
+#include <text_input/uart_text_input.h>
+#include <stdio.h>
+#include <string.h>
+#include <jsmn/jsmn.h>
+
+#define EASY_TAG "EasyFlipper"
+
+/**
+ * @brief Navigation callback for exiting the application
+ * @param context The context - unused
+ * @return next view id (VIEW_NONE to exit the app)
+ */
+uint32_t easy_flipper_callback_exit_app(void *context);
+/**
+ * @brief Initialize a buffer
+ * @param buffer The buffer to initialize
+ * @param buffer_size The size of the buffer
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_buffer(char **buffer, uint32_t buffer_size);
+/**
+ * @brief Initialize a View object
+ * @param view The View object to initialize
+ * @param view_id The ID/Index of the view
+ * @param draw_callback The draw callback function (set to NULL if not needed)
+ * @param input_callback The input callback function (set to NULL if not needed)
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_view(
+    View **view,
+    int32_t view_id,
+    void draw_callback(Canvas *, void *),
+    bool input_callback(InputEvent *, void *),
+    uint32_t (*previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
+
+/**
+ * @brief Initialize a ViewDispatcher object
+ * @param view_dispatcher The ViewDispatcher object to initialize
+ * @param gui The GUI object
+ * @param context The context to pass to the event callback
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_view_dispatcher(ViewDispatcher **view_dispatcher, Gui *gui, void *context);
+
+/**
+ * @brief Initialize a Submenu object
+ * @note This does not set the items in the submenu
+ * @param submenu The Submenu object to initialize
+ * @param view_id The ID/Index of the view
+ * @param title The title/header of the submenu
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_submenu(
+    Submenu **submenu,
+    int32_t view_id,
+    char *title,
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher);
+
+/**
+ * @brief Initialize a Menu object
+ * @note This does not set the items in the menu
+ * @param menu The Menu object to initialize
+ * @param view_id The ID/Index of the view
+ * @param item_callback The item callback function
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_menu(
+    Menu **menu,
+    int32_t view_id,
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher);
+
+/**
+ * @brief Initialize a Widget object
+ * @param widget The Widget object to initialize
+ * @param view_id The ID/Index of the view
+ * @param text The text to display in the widget
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_widget(
+    Widget **widget,
+    int32_t view_id,
+    char *text,
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher);
+
+/**
+ * @brief Initialize a VariableItemList object
+ * @note This does not set the items in the VariableItemList
+ * @param variable_item_list The VariableItemList object to initialize
+ * @param view_id The ID/Index of the view
+ * @param enter_callback The enter callback function (can be set to NULL)
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @param context The context to pass to the enter callback (usually the app)
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_variable_item_list(
+    VariableItemList **variable_item_list,
+    int32_t view_id,
+    void (*enter_callback)(void *, uint32_t),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
+
+/**
+ * @brief Initialize a TextInput object
+ * @param text_input The TextInput object to initialize
+ * @param view_id The ID/Index of the view
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_text_input(
+    TextInput **text_input,
+    int32_t view_id,
+    char *header_text,
+    char *text_input_temp_buffer,
+    uint32_t text_input_buffer_size,
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
+
+/**
+ * @brief Initialize a UART_TextInput object
+ * @param uart_text_input The UART_TextInput object to initialize
+ * @param view_id The ID/Index of the view
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_uart_text_input(
+    UART_TextInput **uart_text_input,
+    int32_t view_id,
+    char *header_text,
+    char *uart_text_input_temp_buffer,
+    uint32_t uart_text_input_buffer_size,
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
+
+/**
+ * @brief Initialize a DialogEx object
+ * @param dialog_ex The DialogEx object to initialize
+ * @param view_id The ID/Index of the view
+ * @param header The header of the dialog
+ * @param header_x The x coordinate of the header
+ * @param header_y The y coordinate of the header
+ * @param text The text of the dialog
+ * @param text_x The x coordinate of the dialog
+ * @param text_y The y coordinate of the dialog
+ * @param left_button_text The text of the left button
+ * @param right_button_text The text of the right button
+ * @param center_button_text The text of the center button
+ * @param result_callback The result callback function
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @param context The context to pass to the result callback
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_dialog_ex(
+    DialogEx **dialog_ex,
+    int32_t view_id,
+    char *header,
+    uint16_t header_x,
+    uint16_t header_y,
+    char *text,
+    uint16_t text_x,
+    uint16_t text_y,
+    char *left_button_text,
+    char *right_button_text,
+    char *center_button_text,
+    void (*result_callback)(DialogExResult, void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
+
+/**
+ * @brief Initialize a Popup object
+ * @param popup The Popup object to initialize
+ * @param view_id The ID/Index of the view
+ * @param header The header of the dialog
+ * @param header_x The x coordinate of the header
+ * @param header_y The y coordinate of the header
+ * @param text The text of the dialog
+ * @param text_x The x coordinate of the dialog
+ * @param text_y The y coordinate of the dialog
+ * @param result_callback The result callback function
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @param context The context to pass to the result callback
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_popup(
+    Popup **popup,
+    int32_t view_id,
+    char *header,
+    uint16_t header_x,
+    uint16_t header_y,
+    char *text,
+    uint16_t text_x,
+    uint16_t text_y,
+    void (*result_callback)(void *),
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher,
+    void *context);
+
+/**
+ * @brief Initialize a Loading object
+ * @param loading The Loading object to initialize
+ * @param view_id The ID/Index of the view
+ * @param previous_callback The previous callback function (can be set to NULL)
+ * @param view_dispatcher The ViewDispatcher object
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_loading(
+    Loading **loading,
+    int32_t view_id,
+    uint32_t(previous_callback)(void *),
+    ViewDispatcher **view_dispatcher);
+
+/**
+ * @brief Set a char butter to a FuriString
+ * @param furi_string The FuriString object
+ * @param buffer The buffer to copy the string to
+ * @return true if successful, false otherwise
+ */
+bool easy_flipper_set_char_to_furi_string(FuriString **furi_string, char *buffer);
+
+#endif

+ 5 - 22
web_crawler_storage.h → flip_storage/web_crawler_storage.c

@@ -1,23 +1,7 @@
-#ifndef WEB_CRAWLER_STORAGE_H
-#define WEB_CRAWLER_STORAGE_H
-
-#include <furi.h>
-#include <storage/storage.h>
-
-#define SETTINGS_PATH STORAGE_EXT_PATH_PREFIX "/apps_data/" http_tag "/settings.bin"
-#define RECEIVED_DATA_PATH STORAGE_EXT_PATH_PREFIX "/apps_data/" http_tag "/" // add the file name to the end (e.g. "received_data.txt")
-
-// will need to make a duplicate of the file
-// one to save data, and the other for users to manipulate
-
-#define MAX_RECEIVED_DATA_SIZE 1024
-#define SHOW_MAX_FILE_SIZE 2048
-
-// Define the truncation notice
-#define TRUNCATION_NOTICE "\n\n[Data truncated due to size limits]"
+#include <flip_storage/web_crawler_storage.h>
 
 
 // Function to save settings: path, SSID, and password
 // Function to save settings: path, SSID, and password
-static void save_settings(
+void save_settings(
     const char *path,
     const char *path,
     const char *ssid,
     const char *ssid,
     const char *password,
     const char *password,
@@ -119,7 +103,7 @@ static void save_settings(
 }
 }
 
 
 // Function to load settings (the variables must be opened in the order they were saved)
 // Function to load settings (the variables must be opened in the order they were saved)
-static bool load_settings(
+bool load_settings(
     char *path,
     char *path,
     size_t path_size,
     size_t path_size,
     char *ssid,
     char *ssid,
@@ -271,7 +255,7 @@ static bool load_settings(
     return true;
     return true;
 }
 }
 
 
-static bool delete_received_data(WebCrawlerApp *app)
+bool delete_received_data(WebCrawlerApp *app)
 {
 {
     if (app == NULL)
     if (app == NULL)
     {
     {
@@ -328,7 +312,7 @@ static bool delete_received_data(WebCrawlerApp *app)
     return true;
     return true;
 }
 }
 
 
-static bool rename_received_data(const char *old_name, const char *new_name, const char *file_type, const char *old_file_type)
+bool rename_received_data(const char *old_name, const char *new_name, const char *file_type, const char *old_file_type)
 {
 {
     // Open the storage record
     // Open the storage record
     Storage *storage = furi_record_open(RECORD_STORAGE);
     Storage *storage = furi_record_open(RECORD_STORAGE);
@@ -404,4 +388,3 @@ static bool rename_received_data(const char *old_name, const char *new_name, con
         return renamed;
         return renamed;
     }
     }
 }
 }
-#endif // WEB_CRAWLER_STORAGE_H

+ 43 - 0
flip_storage/web_crawler_storage.h

@@ -0,0 +1,43 @@
+#ifndef WEB_CRAWLER_STORAGE_H
+#define WEB_CRAWLER_STORAGE_H
+#include <web_crawler.h>
+#include <furi.h>
+#include <storage/storage.h>
+
+#define SETTINGS_PATH STORAGE_EXT_PATH_PREFIX "/apps_data/" http_tag "/settings.bin"
+#define RECEIVED_DATA_PATH STORAGE_EXT_PATH_PREFIX "/apps_data/" http_tag "/" // add the file name to the end (e.g. "received_data.txt")
+
+// Function to save settings: path, SSID, and password
+void save_settings(
+    const char *path,
+    const char *ssid,
+    const char *password,
+    const char *file_rename,
+    const char *file_type,
+    const char *http_method,
+    const char *headers,
+    const char *payload);
+
+// Function to load settings (the variables must be opened in the order they were saved)
+bool load_settings(
+    char *path,
+    size_t path_size,
+    char *ssid,
+    size_t ssid_size,
+    char *password,
+    size_t password_size,
+    char *file_rename,
+    size_t file_rename_size,
+    char *file_type,
+    size_t file_type_size,
+    char *http_method,
+    size_t http_method_size,
+    char *headers,
+    size_t headers_size,
+    char *payload,
+    size_t payload_size,
+    WebCrawlerApp *app);
+
+bool delete_received_data(WebCrawlerApp *app);
+bool rename_received_data(const char *old_name, const char *new_name, const char *file_type, const char *old_file_type);
+#endif // WEB_CRAWLER_STORAGE_H

+ 9 - 146
flipper_http.h → flipper_http/flipper_http.c

@@ -1,140 +1,7 @@
-// flipper_http.h
-#ifndef FLIPPER_HTTP_H
-#define FLIPPER_HTTP_H
-
-#include <furi.h>
-#include <furi_hal.h>
-#include <furi_hal_gpio.h>
-#include <furi_hal_serial.h>
-#include <storage/storage.h>
-
-// STORAGE_EXT_PATH_PREFIX is defined in the Furi SDK as /ext
-
-#define HTTP_TAG "WebCrawler"             // change this to your app name
-#define http_tag "web_crawler"            // change this to your app id
-#define UART_CH (FuriHalSerialIdUsart)    // UART channel
-#define TIMEOUT_DURATION_TICKS (3 * 1000) // 3 seconds
-#define BAUDRATE (115200)                 // UART baudrate
-#define RX_BUF_SIZE 2048                  // UART RX buffer size
-#define RX_LINE_BUFFER_SIZE 2048          // UART RX line buffer size (increase for large responses)
-#define MAX_FILE_SHOW 5000                // Maximum data from file to show
-
-// Forward declaration for callback
-typedef void (*FlipperHTTP_Callback)(const char *line, void *context);
-
-// Functions
-bool flipper_http_init(FlipperHTTP_Callback callback, void *context);
-void flipper_http_deinit();
-//---
-void flipper_http_rx_callback(const char *line, void *context);
-bool flipper_http_send_data(const char *data);
-//---
-bool flipper_http_connect_wifi();
-bool flipper_http_disconnect_wifi();
-bool flipper_http_ping();
-bool flipper_http_scan_wifi();
-bool flipper_http_save_wifi(const char *ssid, const char *password);
-bool flipper_http_ip_wifi();
-bool flipper_http_ip_address();
-//---
-bool flipper_http_list_commands();
-bool flipper_http_led_on();
-bool flipper_http_led_off();
-bool flipper_http_parse_json(const char *key, const char *json_data);
-bool flipper_http_parse_json_array(const char *key, int index, const char *json_data);
-//---
-bool flipper_http_get_request(const char *url);
-bool flipper_http_get_request_with_headers(const char *url, const char *headers);
-bool flipper_http_post_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
-bool flipper_http_put_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
-bool flipper_http_delete_request_with_headers(
-    const char *url,
-    const char *headers,
-    const char *payload);
-//---
-bool flipper_http_get_request_bytes(const char *url, const char *headers);
-bool flipper_http_post_request_bytes(const char *url, const char *headers, const char *payload);
-//
-bool flipper_http_append_to_file(
-    const void *data,
-    size_t data_size,
-    bool start_new_file,
-    char *file_path);
-
-FuriString *flipper_http_load_from_file(char *file_path);
-static char *trim(const char *str);
-//
-bool flipper_http_process_response_async(bool (*http_request)(void), bool (*parse_json)(void));
-
-// State variable to track the UART state
-typedef enum
-{
-    INACTIVE,  // Inactive state
-    IDLE,      // Default state
-    RECEIVING, // Receiving data
-    SENDING,   // Sending data
-    ISSUE,     // Issue with connection
-} SerialState;
-
-// Event Flags for UART Worker Thread
-typedef enum
-{
-    WorkerEvtStop = (1 << 0),
-    WorkerEvtRxDone = (1 << 1),
-} WorkerEvtFlags;
-
-// FlipperHTTP Structure
-typedef struct
-{
-    FuriStreamBuffer *flipper_http_stream;  // Stream buffer for UART communication
-    FuriHalSerialHandle *serial_handle;     // Serial handle for UART communication
-    FuriThread *rx_thread;                  // Worker thread for UART
-    FuriThreadId rx_thread_id;              // Worker thread ID
-    FlipperHTTP_Callback handle_rx_line_cb; // Callback for received lines
-    void *callback_context;                 // Context for the callback
-    SerialState state;                      // State of the UART
-
-    // variable to store the last received data from the UART
-    char *last_response;
-    char file_path[256]; // Path to save the received data
-
-    // Timer-related members
-    FuriTimer *get_timeout_timer; // Timer for HTTP request timeout
-
-    bool started_receiving_get; // Indicates if a GET request has started
-    bool just_started_get;      // Indicates if GET data reception has just started
-
-    bool started_receiving_post; // Indicates if a POST request has started
-    bool just_started_post;      // Indicates if POST data reception has just started
-
-    bool started_receiving_put; // Indicates if a PUT request has started
-    bool just_started_put;      // Indicates if PUT data reception has just started
-
-    bool started_receiving_delete; // Indicates if a DELETE request has started
-    bool just_started_delete;      // Indicates if DELETE data reception has just started
-
-    // Buffer to hold the raw bytes received from the UART
-    uint8_t *received_bytes;
-    size_t received_bytes_len; // Length of the received bytes
-    bool is_bytes_request;     // Flag to indicate if the request is for bytes
-    bool save_bytes;           // Flag to save the received data to a file
-    bool save_received_data;   // Flag to save the received data to a file
-} FlipperHTTP;
-
-static FlipperHTTP fhttp;
-// Global static array for the line buffer
-static char rx_line_buffer[RX_LINE_BUFFER_SIZE];
-#define FILE_BUFFER_SIZE 512
-static uint8_t file_buffer[FILE_BUFFER_SIZE];
-
-// fhttp.last_response holds the last received data from the UART, which could be [GET/END], [POST/END], [PUT/END], [DELETE/END], etc
-
+#include <flipper_http/flipper_http.h>
+FlipperHTTP fhttp;
+char rx_line_buffer[RX_LINE_BUFFER_SIZE];
+uint8_t file_buffer[FILE_BUFFER_SIZE];
 // Function to append received data to file
 // Function to append received data to file
 // make sure to initialize the file path before calling this function
 // make sure to initialize the file path before calling this function
 bool flipper_http_append_to_file(
 bool flipper_http_append_to_file(
@@ -247,7 +114,7 @@ FuriString *flipper_http_load_from_file(char *file_path)
         storage_file_close(file);
         storage_file_close(file);
         storage_file_free(file);
         storage_file_free(file);
         furi_record_close(RECORD_STORAGE);
         furi_record_close(RECORD_STORAGE);
-        return false;
+        return NULL;
     }
     }
 
 
     // Append each byte to the FuriString
     // Append each byte to the FuriString
@@ -276,7 +143,7 @@ FuriString *flipper_http_load_from_file(char *file_path)
  * @note       This function will handle received data asynchronously via the callback.
  * @note       This function will handle received data asynchronously via the callback.
  */
  */
 // UART worker thread
 // UART worker thread
-static int32_t flipper_http_worker(void *context)
+int32_t flipper_http_worker(void *context)
 {
 {
     UNUSED(context);
     UNUSED(context);
     size_t rx_line_pos = 0;
     size_t rx_line_pos = 0;
@@ -331,8 +198,6 @@ static int32_t flipper_http_worker(void *context)
                         // Invoke the callback with the complete line
                         // Invoke the callback with the complete line
                         fhttp.handle_rx_line_cb(rx_line_buffer, fhttp.callback_context);
                         fhttp.handle_rx_line_cb(rx_line_buffer, fhttp.callback_context);
 
 
-                        // save the received data
-
                         // Reset the line buffer position
                         // Reset the line buffer position
                         rx_line_pos = 0;
                         rx_line_pos = 0;
                     }
                     }
@@ -417,7 +282,7 @@ void get_timeout_timer_callback(void *context)
  * @param      context   The context to pass to the callback.
  * @param      context   The context to pass to the callback.
  * @note       This function will handle received data asynchronously via the callback.
  * @note       This function will handle received data asynchronously via the callback.
  */
  */
-static void _flipper_http_rx_callback(
+void _flipper_http_rx_callback(
     FuriHalSerialHandle *handle,
     FuriHalSerialHandle *handle,
     FuriHalSerialRxEvent event,
     FuriHalSerialRxEvent event,
     void *context)
     void *context)
@@ -1246,7 +1111,7 @@ void flipper_http_rx_callback(const char *line, void *context)
     }
     }
 
 
     // Uncomment below line to log the data received over UART
     // Uncomment below line to log the data received over UART
-    FURI_LOG_I(HTTP_TAG, "Received UART line: %s", line);
+    // FURI_LOG_I(HTTP_TAG, "Received UART line: %s", line);
 
 
     // Check if we've started receiving data from a GET request
     // Check if we've started receiving data from a GET request
     if (fhttp.started_receiving_get)
     if (fhttp.started_receiving_get)
@@ -1557,6 +1422,4 @@ bool flipper_http_process_response_async(bool (*http_request)(void), bool (*pars
         return false;
         return false;
     }
     }
     return true;
     return true;
-}
-
-#endif // FLIPPER_HTTP_H
+}

+ 363 - 0
flipper_http/flipper_http.h

@@ -0,0 +1,363 @@
+// flipper_http.h
+#ifndef FLIPPER_HTTP_H
+#define FLIPPER_HTTP_H
+
+#include <furi.h>
+#include <furi_hal.h>
+#include <furi_hal_gpio.h>
+#include <furi_hal_serial.h>
+#include <storage/storage.h>
+
+// STORAGE_EXT_PATH_PREFIX is defined in the Furi SDK as /ext
+
+#define HTTP_TAG "WebCrawler"             // change this to your app name
+#define http_tag "web_crawler"            // change this to your app id
+#define UART_CH (FuriHalSerialIdUsart)    // UART channel
+#define TIMEOUT_DURATION_TICKS (5 * 1000) // 5 seconds
+#define BAUDRATE (115200)                 // UART baudrate
+#define RX_BUF_SIZE 2048                  // UART RX buffer size
+#define RX_LINE_BUFFER_SIZE 2048          // UART RX line buffer size (increase for large responses)
+#define MAX_FILE_SHOW 4096                // Maximum data from file to show
+#define FILE_BUFFER_SIZE 512              // File buffer size
+
+// Forward declaration for callback
+typedef void (*FlipperHTTP_Callback)(const char *line, void *context);
+
+// State variable to track the UART state
+typedef enum
+{
+    INACTIVE,  // Inactive state
+    IDLE,      // Default state
+    RECEIVING, // Receiving data
+    SENDING,   // Sending data
+    ISSUE,     // Issue with connection
+} SerialState;
+
+// Event Flags for UART Worker Thread
+typedef enum
+{
+    WorkerEvtStop = (1 << 0),
+    WorkerEvtRxDone = (1 << 1),
+} WorkerEvtFlags;
+
+// FlipperHTTP Structure
+typedef struct
+{
+    FuriStreamBuffer *flipper_http_stream;  // Stream buffer for UART communication
+    FuriHalSerialHandle *serial_handle;     // Serial handle for UART communication
+    FuriThread *rx_thread;                  // Worker thread for UART
+    FuriThreadId rx_thread_id;              // Worker thread ID
+    FlipperHTTP_Callback handle_rx_line_cb; // Callback for received lines
+    void *callback_context;                 // Context for the callback
+    SerialState state;                      // State of the UART
+
+    // variable to store the last received data from the UART
+    char *last_response;
+    char file_path[256]; // Path to save the received data
+
+    // Timer-related members
+    FuriTimer *get_timeout_timer; // Timer for HTTP request timeout
+
+    bool started_receiving_get; // Indicates if a GET request has started
+    bool just_started_get;      // Indicates if GET data reception has just started
+
+    bool started_receiving_post; // Indicates if a POST request has started
+    bool just_started_post;      // Indicates if POST data reception has just started
+
+    bool started_receiving_put; // Indicates if a PUT request has started
+    bool just_started_put;      // Indicates if PUT data reception has just started
+
+    bool started_receiving_delete; // Indicates if a DELETE request has started
+    bool just_started_delete;      // Indicates if DELETE data reception has just started
+
+    // Buffer to hold the raw bytes received from the UART
+    uint8_t *received_bytes;
+    size_t received_bytes_len; // Length of the received bytes
+    bool is_bytes_request;     // Flag to indicate if the request is for bytes
+    bool save_bytes;           // Flag to save the received data to a file
+    bool save_received_data;   // Flag to save the received data to a file
+} FlipperHTTP;
+
+extern FlipperHTTP fhttp;
+// Global static array for the line buffer
+extern char rx_line_buffer[RX_LINE_BUFFER_SIZE];
+extern uint8_t file_buffer[FILE_BUFFER_SIZE];
+
+// fhttp.last_response holds the last received data from the UART
+
+// Function to append received data to file
+// make sure to initialize the file path before calling this function
+bool flipper_http_append_to_file(
+    const void *data,
+    size_t data_size,
+    bool start_new_file,
+    char *file_path);
+
+FuriString *flipper_http_load_from_file(char *file_path);
+
+// UART worker thread
+/**
+ * @brief      Worker thread to handle UART data asynchronously.
+ * @return     0
+ * @param      context   The context to pass to the callback.
+ * @note       This function will handle received data asynchronously via the callback.
+ */
+// UART worker thread
+int32_t flipper_http_worker(void *context);
+
+// Timer callback function
+/**
+ * @brief      Callback function for the GET timeout timer.
+ * @return     0
+ * @param      context   The context to pass to the callback.
+ * @note       This function will be called when the GET request times out.
+ */
+void get_timeout_timer_callback(void *context);
+
+// UART RX Handler Callback (Interrupt Context)
+/**
+ * @brief      A private callback function to handle received data asynchronously.
+ * @return     void
+ * @param      handle    The UART handle.
+ * @param      event     The event type.
+ * @param      context   The context to pass to the callback.
+ * @note       This function will handle received data asynchronously via the callback.
+ */
+void _flipper_http_rx_callback(
+    FuriHalSerialHandle *handle,
+    FuriHalSerialRxEvent event,
+    void *context);
+
+// UART initialization function
+/**
+ * @brief      Initialize UART.
+ * @return     true if the UART was initialized successfully, false otherwise.
+ * @param      callback  The callback function to handle received data (ex. flipper_http_rx_callback).
+ * @param      context   The context to pass to the callback.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_init(FlipperHTTP_Callback callback, void *context);
+
+// Deinitialize UART
+/**
+ * @brief      Deinitialize UART.
+ * @return     void
+ * @note       This function will stop the asynchronous RX, release the serial handle, and free the resources.
+ */
+void flipper_http_deinit();
+
+// Function to send data over UART with newline termination
+/**
+ * @brief      Send data over UART with newline termination.
+ * @return     true if the data was sent successfully, false otherwise.
+ * @param      data  The data to send over UART.
+ * @note       The data will be sent over UART with a newline character appended.
+ */
+bool flipper_http_send_data(const char *data);
+
+// Function to send a PING request
+/**
+ * @brief      Send a PING request to check if the Wifi Dev Board is connected.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ * @note       This is best used to check if the Wifi Dev Board is connected.
+ * @note       The state will remain INACTIVE until a PONG is received.
+ */
+bool flipper_http_ping();
+
+// Function to list available commands
+/**
+ * @brief      Send a command to list available commands.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_list_commands();
+
+// Function to turn on the LED
+/**
+ * @brief      Allow the LED to display while processing.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_led_on();
+
+// Function to turn off the LED
+/**
+ * @brief      Disable the LED from displaying while processing.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_led_off();
+
+// Function to parse JSON data
+/**
+ * @brief      Parse JSON data.
+ * @return     true if the JSON data was parsed successfully, false otherwise.
+ * @param      key       The key to parse from the JSON data.
+ * @param      json_data The JSON data to parse.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_parse_json(const char *key, const char *json_data);
+
+// Function to parse JSON array data
+/**
+ * @brief      Parse JSON array data.
+ * @return     true if the JSON array data was parsed successfully, false otherwise.
+ * @param      key       The key to parse from the JSON array data.
+ * @param      index     The index to parse from the JSON array data.
+ * @param      json_data The JSON array data to parse.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_parse_json_array(const char *key, int index, const char *json_data);
+
+// Function to scan for WiFi networks
+/**
+ * @brief      Send a command to scan for WiFi networks.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_scan_wifi();
+
+// Function to save WiFi settings (returns true if successful)
+/**
+ * @brief      Send a command to save WiFi settings.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_save_wifi(const char *ssid, const char *password);
+
+// Function to get IP address of WiFi Devboard
+/**
+ * @brief      Send a command to get the IP address of the WiFi Devboard
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_ip_address();
+
+// Function to get IP address of the connected WiFi network
+/**
+ * @brief      Send a command to get the IP address of the connected WiFi network.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_ip_wifi();
+
+// Function to disconnect from WiFi (returns true if successful)
+/**
+ * @brief      Send a command to disconnect from WiFi.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_disconnect_wifi();
+
+// Function to connect to WiFi (returns true if successful)
+/**
+ * @brief      Send a command to connect to WiFi.
+ * @return     true if the request was successful, false otherwise.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_connect_wifi();
+
+// Function to send a GET request
+/**
+ * @brief      Send a GET request to the specified URL.
+ * @return     true if the request was successful, false otherwise.
+ * @param      url  The URL to send the GET request to.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_get_request(const char *url);
+
+// Function to send a GET request with headers
+/**
+ * @brief      Send a GET request to the specified URL.
+ * @return     true if the request was successful, false otherwise.
+ * @param      url  The URL to send the GET request to.
+ * @param      headers  The headers to send with the GET request.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_get_request_with_headers(const char *url, const char *headers);
+
+// Function to send a GET request with headers and return bytes
+/**
+ * @brief      Send a GET request to the specified URL.
+ * @return     true if the request was successful, false otherwise.
+ * @param      url  The URL to send the GET request to.
+ * @param      headers  The headers to send with the GET request.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_get_request_bytes(const char *url, const char *headers);
+
+// Function to send a POST request with headers
+/**
+ * @brief      Send a POST request to the specified URL.
+ * @return     true if the request was successful, false otherwise.
+ * @param      url  The URL to send the POST request to.
+ * @param      headers  The headers to send with the POST request.
+ * @param      data  The data to send with the POST request.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_post_request_with_headers(
+    const char *url,
+    const char *headers,
+    const char *payload);
+
+// Function to send a POST request with headers and return bytes
+/**
+ * @brief      Send a POST request to the specified URL.
+ * @return     true if the request was successful, false otherwise.
+ * @param      url  The URL to send the POST request to.
+ * @param      headers  The headers to send with the POST request.
+ * @param      payload  The data to send with the POST request.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_post_request_bytes(const char *url, const char *headers, const char *payload);
+
+// Function to send a PUT request with headers
+/**
+ * @brief      Send a PUT request to the specified URL.
+ * @return     true if the request was successful, false otherwise.
+ * @param      url  The URL to send the PUT request to.
+ * @param      headers  The headers to send with the PUT request.
+ * @param      data  The data to send with the PUT request.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_put_request_with_headers(
+    const char *url,
+    const char *headers,
+    const char *payload);
+
+// Function to send a DELETE request with headers
+/**
+ * @brief      Send a DELETE request to the specified URL.
+ * @return     true if the request was successful, false otherwise.
+ * @param      url  The URL to send the DELETE request to.
+ * @param      headers  The headers to send with the DELETE request.
+ * @param      data  The data to send with the DELETE request.
+ * @note       The received data will be handled asynchronously via the callback.
+ */
+bool flipper_http_delete_request_with_headers(
+    const char *url,
+    const char *headers,
+    const char *payload);
+
+// Function to handle received data asynchronously
+/**
+ * @brief      Callback function to handle received data asynchronously.
+ * @return     void
+ * @param      line     The received line.
+ * @param      context  The context passed to the callback.
+ * @note       The received data will be handled asynchronously via the callback and handles the state of the UART.
+ */
+void flipper_http_rx_callback(const char *line, void *context);
+
+// Function to trim leading and trailing spaces and newlines from a constant string
+char *trim(const char *str);
+/**
+ * @brief Process requests and parse JSON data asynchronously
+ * @param http_request The function to send the request
+ * @param parse_json The function to parse the JSON
+ * @return true if successful, false otherwise
+ */
+bool flipper_http_process_response_async(bool (*http_request)(void), bool (*parse_json)(void));
+
+#endif // FLIPPER_HTTP_H

+ 747 - 0
jsmn/jsmn.c

@@ -0,0 +1,747 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2010 Serge Zaitsev
+ *
+ * [License text continues...]
+ */
+
+#include <jsmn/jsmn.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Allocates a fresh unused token from the token pool.
+ */
+static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens,
+                                   const size_t num_tokens)
+{
+    jsmntok_t *tok;
+
+    if (parser->toknext >= num_tokens)
+    {
+        return NULL;
+    }
+    tok = &tokens[parser->toknext++];
+    tok->start = tok->end = -1;
+    tok->size = 0;
+#ifdef JSMN_PARENT_LINKS
+    tok->parent = -1;
+#endif
+    return tok;
+}
+
+/**
+ * Fills token type and boundaries.
+ */
+static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type,
+                            const int start, const int end)
+{
+    token->type = type;
+    token->start = start;
+    token->end = end;
+    token->size = 0;
+}
+
+/**
+ * Fills next available token with JSON primitive.
+ */
+static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+                                const size_t len, jsmntok_t *tokens,
+                                const size_t num_tokens)
+{
+    jsmntok_t *token;
+    int start;
+
+    start = parser->pos;
+
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+        switch (js[parser->pos])
+        {
+#ifndef JSMN_STRICT
+        /* In strict mode primitive must be followed by "," or "}" or "]" */
+        case ':':
+#endif
+        case '\t':
+        case '\r':
+        case '\n':
+        case ' ':
+        case ',':
+        case ']':
+        case '}':
+            goto found;
+        default:
+            /* to quiet a warning from gcc*/
+            break;
+        }
+        if (js[parser->pos] < 32 || js[parser->pos] >= 127)
+        {
+            parser->pos = start;
+            return JSMN_ERROR_INVAL;
+        }
+    }
+#ifdef JSMN_STRICT
+    /* In strict mode primitive must be followed by a comma/object/array */
+    parser->pos = start;
+    return JSMN_ERROR_PART;
+#endif
+
+found:
+    if (tokens == NULL)
+    {
+        parser->pos--;
+        return 0;
+    }
+    token = jsmn_alloc_token(parser, tokens, num_tokens);
+    if (token == NULL)
+    {
+        parser->pos = start;
+        return JSMN_ERROR_NOMEM;
+    }
+    jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+    token->parent = parser->toksuper;
+#endif
+    parser->pos--;
+    return 0;
+}
+
+/**
+ * Fills next token with JSON string.
+ */
+static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+                             const size_t len, jsmntok_t *tokens,
+                             const size_t num_tokens)
+{
+    jsmntok_t *token;
+
+    int start = parser->pos;
+
+    /* Skip starting quote */
+    parser->pos++;
+
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+        char c = js[parser->pos];
+
+        /* Quote: end of string */
+        if (c == '\"')
+        {
+            if (tokens == NULL)
+            {
+                return 0;
+            }
+            token = jsmn_alloc_token(parser, tokens, num_tokens);
+            if (token == NULL)
+            {
+                parser->pos = start;
+                return JSMN_ERROR_NOMEM;
+            }
+            jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos);
+#ifdef JSMN_PARENT_LINKS
+            token->parent = parser->toksuper;
+#endif
+            return 0;
+        }
+
+        /* Backslash: Quoted symbol expected */
+        if (c == '\\' && parser->pos + 1 < len)
+        {
+            int i;
+            parser->pos++;
+            switch (js[parser->pos])
+            {
+            /* Allowed escaped symbols */
+            case '\"':
+            case '/':
+            case '\\':
+            case 'b':
+            case 'f':
+            case 'r':
+            case 'n':
+            case 't':
+                break;
+            /* Allows escaped symbol \uXXXX */
+            case 'u':
+                parser->pos++;
+                for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++)
+                {
+                    /* If it isn't a hex character we have an error */
+                    if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
+                          (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
+                          (js[parser->pos] >= 97 && js[parser->pos] <= 102)))
+                    { /* a-f */
+                        parser->pos = start;
+                        return JSMN_ERROR_INVAL;
+                    }
+                    parser->pos++;
+                }
+                parser->pos--;
+                break;
+            /* Unexpected symbol */
+            default:
+                parser->pos = start;
+                return JSMN_ERROR_INVAL;
+            }
+        }
+    }
+    parser->pos = start;
+    return JSMN_ERROR_PART;
+}
+
+/**
+ * Create JSON parser over an array of tokens
+ */
+void jsmn_init(jsmn_parser *parser)
+{
+    parser->pos = 0;
+    parser->toknext = 0;
+    parser->toksuper = -1;
+}
+
+/**
+ * Parse JSON string and fill tokens.
+ */
+int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+               jsmntok_t *tokens, const unsigned int num_tokens)
+{
+    int r;
+    int i;
+    jsmntok_t *token;
+    int count = parser->toknext;
+
+    for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++)
+    {
+        char c;
+        jsmntype_t type;
+
+        c = js[parser->pos];
+        switch (c)
+        {
+        case '{':
+        case '[':
+            count++;
+            if (tokens == NULL)
+            {
+                break;
+            }
+            token = jsmn_alloc_token(parser, tokens, num_tokens);
+            if (token == NULL)
+            {
+                return JSMN_ERROR_NOMEM;
+            }
+            if (parser->toksuper != -1)
+            {
+                jsmntok_t *t = &tokens[parser->toksuper];
+#ifdef JSMN_STRICT
+                /* In strict mode an object or array can't become a key */
+                if (t->type == JSMN_OBJECT)
+                {
+                    return JSMN_ERROR_INVAL;
+                }
+#endif
+                t->size++;
+#ifdef JSMN_PARENT_LINKS
+                token->parent = parser->toksuper;
+#endif
+            }
+            token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
+            token->start = parser->pos;
+            parser->toksuper = parser->toknext - 1;
+            break;
+        case '}':
+        case ']':
+            if (tokens == NULL)
+            {
+                break;
+            }
+            type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
+#ifdef JSMN_PARENT_LINKS
+            if (parser->toknext < 1)
+            {
+                return JSMN_ERROR_INVAL;
+            }
+            token = &tokens[parser->toknext - 1];
+            for (;;)
+            {
+                if (token->start != -1 && token->end == -1)
+                {
+                    if (token->type != type)
+                    {
+                        return JSMN_ERROR_INVAL;
+                    }
+                    token->end = parser->pos + 1;
+                    parser->toksuper = token->parent;
+                    break;
+                }
+                if (token->parent == -1)
+                {
+                    if (token->type != type || parser->toksuper == -1)
+                    {
+                        return JSMN_ERROR_INVAL;
+                    }
+                    break;
+                }
+                token = &tokens[token->parent];
+            }
+#else
+            for (i = parser->toknext - 1; i >= 0; i--)
+            {
+                token = &tokens[i];
+                if (token->start != -1 && token->end == -1)
+                {
+                    if (token->type != type)
+                    {
+                        return JSMN_ERROR_INVAL;
+                    }
+                    parser->toksuper = -1;
+                    token->end = parser->pos + 1;
+                    break;
+                }
+            }
+            /* Error if unmatched closing bracket */
+            if (i == -1)
+            {
+                return JSMN_ERROR_INVAL;
+            }
+            for (; i >= 0; i--)
+            {
+                token = &tokens[i];
+                if (token->start != -1 && token->end == -1)
+                {
+                    parser->toksuper = i;
+                    break;
+                }
+            }
+#endif
+            break;
+        case '\"':
+            r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
+            if (r < 0)
+            {
+                return r;
+            }
+            count++;
+            if (parser->toksuper != -1 && tokens != NULL)
+            {
+                tokens[parser->toksuper].size++;
+            }
+            break;
+        case '\t':
+        case '\r':
+        case '\n':
+        case ' ':
+            break;
+        case ':':
+            parser->toksuper = parser->toknext - 1;
+            break;
+        case ',':
+            if (tokens != NULL && parser->toksuper != -1 &&
+                tokens[parser->toksuper].type != JSMN_ARRAY &&
+                tokens[parser->toksuper].type != JSMN_OBJECT)
+            {
+#ifdef JSMN_PARENT_LINKS
+                parser->toksuper = tokens[parser->toksuper].parent;
+#else
+                for (i = parser->toknext - 1; i >= 0; i--)
+                {
+                    if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT)
+                    {
+                        if (tokens[i].start != -1 && tokens[i].end == -1)
+                        {
+                            parser->toksuper = i;
+                            break;
+                        }
+                    }
+                }
+#endif
+            }
+            break;
+#ifdef JSMN_STRICT
+        /* In strict mode primitives are: numbers and booleans */
+        case '-':
+        case '0':
+        case '1':
+        case '2':
+        case '3':
+        case '4':
+        case '5':
+        case '6':
+        case '7':
+        case '8':
+        case '9':
+        case 't':
+        case 'f':
+        case 'n':
+            /* And they must not be keys of the object */
+            if (tokens != NULL && parser->toksuper != -1)
+            {
+                const jsmntok_t *t = &tokens[parser->toksuper];
+                if (t->type == JSMN_OBJECT ||
+                    (t->type == JSMN_STRING && t->size != 0))
+                {
+                    return JSMN_ERROR_INVAL;
+                }
+            }
+#else
+        /* In non-strict mode every unquoted value is a primitive */
+        default:
+#endif
+            r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
+            if (r < 0)
+            {
+                return r;
+            }
+            count++;
+            if (parser->toksuper != -1 && tokens != NULL)
+            {
+                tokens[parser->toksuper].size++;
+            }
+            break;
+
+#ifdef JSMN_STRICT
+        /* Unexpected char in strict mode */
+        default:
+            return JSMN_ERROR_INVAL;
+#endif
+        }
+    }
+
+    if (tokens != NULL)
+    {
+        for (i = parser->toknext - 1; i >= 0; i--)
+        {
+            /* Unmatched opened object or array */
+            if (tokens[i].start != -1 && tokens[i].end == -1)
+            {
+                return JSMN_ERROR_PART;
+            }
+        }
+    }
+
+    return count;
+}
+
+// Helper function to create a JSON object
+char *jsmn(const char *key, const char *value)
+{
+    int length = strlen(key) + strlen(value) + 8;         // Calculate required length
+    char *result = (char *)malloc(length * sizeof(char)); // Allocate memory
+    if (result == NULL)
+    {
+        return NULL; // Handle memory allocation failure
+    }
+    snprintf(result, length, "{\"%s\":\"%s\"}", key, value);
+    return result; // Caller is responsible for freeing this memory
+}
+
+// Helper function to compare JSON keys
+int jsoneq(const char *json, jsmntok_t *tok, const char *s)
+{
+    if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start &&
+        strncmp(json + tok->start, s, tok->end - tok->start) == 0)
+    {
+        return 0;
+    }
+    return -1;
+}
+
+// Return the value of the key in the JSON data
+char *get_json_value(char *key, char *json_data, uint32_t max_tokens)
+{
+    // Parse the JSON feed
+    if (json_data != NULL)
+    {
+        jsmn_parser parser;
+        jsmn_init(&parser);
+
+        // Allocate tokens array on the heap
+        jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
+        if (tokens == NULL)
+        {
+            FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
+            return NULL;
+        }
+
+        int ret = jsmn_parse(&parser, json_data, strlen(json_data), tokens, max_tokens);
+        if (ret < 0)
+        {
+            // Handle parsing errors
+            FURI_LOG_E("JSMM.H", "Failed to parse JSON: %d", ret);
+            free(tokens);
+            return NULL;
+        }
+
+        // Ensure that the root element is an object
+        if (ret < 1 || tokens[0].type != JSMN_OBJECT)
+        {
+            FURI_LOG_E("JSMM.H", "Root element is not an object.");
+            free(tokens);
+            return NULL;
+        }
+
+        // Loop through the tokens to find the key
+        for (int i = 1; i < ret; i++)
+        {
+            if (jsoneq(json_data, &tokens[i], key) == 0)
+            {
+                // We found the key. Now, return the associated value.
+                int length = tokens[i + 1].end - tokens[i + 1].start;
+                char *value = malloc(length + 1);
+                if (value == NULL)
+                {
+                    FURI_LOG_E("JSMM.H", "Failed to allocate memory for value.");
+                    free(tokens);
+                    return NULL;
+                }
+                strncpy(value, json_data + tokens[i + 1].start, length);
+                value[length] = '\0'; // Null-terminate the string
+
+                free(tokens); // Free the token array
+                return value; // Return the extracted value
+            }
+        }
+
+        // Free the token array if key was not found
+        free(tokens);
+    }
+    else
+    {
+        FURI_LOG_E("JSMM.H", "JSON data is NULL");
+    }
+    FURI_LOG_E("JSMM.H", "Failed to find the key in the JSON.");
+    return NULL; // Return NULL if something goes wrong
+}
+
+// Revised get_json_array_value function
+char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens)
+{
+    // Retrieve the array string for the given key
+    char *array_str = get_json_value(key, json_data, max_tokens);
+    if (array_str == NULL)
+    {
+        FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
+        return NULL;
+    }
+
+    // Initialize the JSON parser
+    jsmn_parser parser;
+    jsmn_init(&parser);
+
+    // Allocate memory for JSON tokens
+    jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens);
+    if (tokens == NULL)
+    {
+        FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
+        free(array_str);
+        return NULL;
+    }
+
+    // Parse the JSON array
+    int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
+    if (ret < 0)
+    {
+        FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
+        free(tokens);
+        free(array_str);
+        return NULL;
+    }
+
+    // Ensure the root element is an array
+    if (ret < 1 || tokens[0].type != JSMN_ARRAY)
+    {
+        FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
+        free(tokens);
+        free(array_str);
+        return NULL;
+    }
+
+    // Check if the index is within bounds
+    if (index >= (uint32_t)tokens[0].size)
+    {
+        FURI_LOG_E("JSMM.H", "Index %lu out of bounds for array with size %d.", (unsigned long)index, tokens[0].size);
+        free(tokens);
+        free(array_str);
+        return NULL;
+    }
+
+    // Locate the token corresponding to the desired array element
+    int current_token = 1; // Start after the array token
+    for (uint32_t i = 0; i < index; i++)
+    {
+        if (tokens[current_token].type == JSMN_OBJECT)
+        {
+            // For objects, skip all key-value pairs
+            current_token += 1 + 2 * tokens[current_token].size;
+        }
+        else if (tokens[current_token].type == JSMN_ARRAY)
+        {
+            // For nested arrays, skip all elements
+            current_token += 1 + tokens[current_token].size;
+        }
+        else
+        {
+            // For primitive types, simply move to the next token
+            current_token += 1;
+        }
+
+        // Safety check to prevent out-of-bounds
+        if (current_token >= ret)
+        {
+            FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
+            free(tokens);
+            free(array_str);
+            return NULL;
+        }
+    }
+
+    // Extract the array element
+    jsmntok_t element = tokens[current_token];
+    int length = element.end - element.start;
+    char *value = malloc(length + 1);
+    if (value == NULL)
+    {
+        FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
+        free(tokens);
+        free(array_str);
+        return NULL;
+    }
+
+    // Copy the element value to a new string
+    strncpy(value, array_str + element.start, length);
+    value[length] = '\0'; // Null-terminate the string
+
+    // Clean up
+    free(tokens);
+    free(array_str);
+
+    return value;
+}
+
+// Revised get_json_array_values function with correct token skipping
+char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values)
+{
+    // Retrieve the array string for the given key
+    char *array_str = get_json_value(key, json_data, max_tokens);
+    if (array_str == NULL)
+    {
+        FURI_LOG_E("JSMM.H", "Failed to get array for key: %s", key);
+        return NULL;
+    }
+
+    // Initialize the JSON parser
+    jsmn_parser parser;
+    jsmn_init(&parser);
+
+    // Allocate memory for JSON tokens
+    jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * max_tokens); // Allocate on the heap
+    if (tokens == NULL)
+    {
+        FURI_LOG_E("JSMM.H", "Failed to allocate memory for JSON tokens.");
+        free(array_str);
+        return NULL;
+    }
+
+    // Parse the JSON array
+    int ret = jsmn_parse(&parser, array_str, strlen(array_str), tokens, max_tokens);
+    if (ret < 0)
+    {
+        FURI_LOG_E("JSMM.H", "Failed to parse JSON array: %d", ret);
+        free(tokens);
+        free(array_str);
+        return NULL;
+    }
+
+    // Ensure the root element is an array
+    if (tokens[0].type != JSMN_ARRAY)
+    {
+        FURI_LOG_E("JSMM.H", "Value for key '%s' is not an array.", key);
+        free(tokens);
+        free(array_str);
+        return NULL;
+    }
+
+    // Allocate memory for the array of values (maximum possible)
+    int array_size = tokens[0].size;
+    char **values = malloc(array_size * sizeof(char *));
+    if (values == NULL)
+    {
+        FURI_LOG_E("JSMM.H", "Failed to allocate memory for array of values.");
+        free(tokens);
+        free(array_str);
+        return NULL;
+    }
+
+    int actual_num_values = 0;
+
+    // Traverse the array and extract all object values
+    int current_token = 1; // Start after the array token
+    for (int i = 0; i < array_size; i++)
+    {
+        if (current_token >= ret)
+        {
+            FURI_LOG_E("JSMM.H", "Unexpected end of tokens while traversing array.");
+            break;
+        }
+
+        jsmntok_t element = tokens[current_token];
+
+        if (element.type != JSMN_OBJECT)
+        {
+            FURI_LOG_E("JSMM.H", "Array element %d is not an object, skipping.", i);
+            // Skip this element
+            current_token += 1;
+            continue;
+        }
+
+        int length = element.end - element.start;
+
+        // Allocate a new string for the value and copy the data
+        char *value = malloc(length + 1);
+        if (value == NULL)
+        {
+            FURI_LOG_E("JSMM.H", "Failed to allocate memory for array element.");
+            for (int j = 0; j < actual_num_values; j++)
+            {
+                free(values[j]);
+            }
+            free(values);
+            free(tokens);
+            free(array_str);
+            return NULL;
+        }
+
+        strncpy(value, array_str + element.start, length);
+        value[length] = '\0'; // Null-terminate the string
+
+        values[actual_num_values] = value;
+        actual_num_values++;
+
+        // Skip all tokens related to this object to avoid misparsing
+        current_token += 1 + (2 * element.size); // Each key-value pair consumes two tokens
+    }
+
+    *num_values = actual_num_values;
+
+    // Reallocate the values array to actual_num_values if necessary
+    if (actual_num_values < array_size)
+    {
+        char **reduced_values = realloc(values, actual_num_values * sizeof(char *));
+        if (reduced_values != NULL)
+        {
+            values = reduced_values;
+        }
+
+        // Free the remaining values
+        for (int i = actual_num_values; i < array_size; i++)
+        {
+            free(values[i]);
+        }
+    }
+
+    // Clean up
+    free(tokens);
+    free(array_str);
+    return values;
+}

+ 132 - 0
jsmn/jsmn.h

@@ -0,0 +1,132 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2010 Serge Zaitsev
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * [License text continues...]
+ */
+
+#ifndef JSMN_H
+#define JSMN_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef JSMN_STATIC
+#define JSMN_API static
+#else
+#define JSMN_API extern
+#endif
+
+    /**
+     * JSON type identifier. Basic types are:
+     * 	o Object
+     * 	o Array
+     * 	o String
+     * 	o Other primitive: number, boolean (true/false) or null
+     */
+    typedef enum
+    {
+        JSMN_UNDEFINED = 0,
+        JSMN_OBJECT = 1 << 0,
+        JSMN_ARRAY = 1 << 1,
+        JSMN_STRING = 1 << 2,
+        JSMN_PRIMITIVE = 1 << 3
+    } jsmntype_t;
+
+    enum jsmnerr
+    {
+        /* Not enough tokens were provided */
+        JSMN_ERROR_NOMEM = -1,
+        /* Invalid character inside JSON string */
+        JSMN_ERROR_INVAL = -2,
+        /* The string is not a full JSON packet, more bytes expected */
+        JSMN_ERROR_PART = -3
+    };
+
+    /**
+     * JSON token description.
+     * type		type (object, array, string etc.)
+     * start	start position in JSON data string
+     * end		end position in JSON data string
+     */
+    typedef struct
+    {
+        jsmntype_t type;
+        int start;
+        int end;
+        int size;
+#ifdef JSMN_PARENT_LINKS
+        int parent;
+#endif
+    } jsmntok_t;
+
+    /**
+     * JSON parser. Contains an array of token blocks available. Also stores
+     * the string being parsed now and current position in that string.
+     */
+    typedef struct
+    {
+        unsigned int pos;     /* offset in the JSON string */
+        unsigned int toknext; /* next token to allocate */
+        int toksuper;         /* superior token node, e.g. parent object or array */
+    } jsmn_parser;
+
+    /**
+     * Create JSON parser over an array of tokens
+     */
+    JSMN_API void jsmn_init(jsmn_parser *parser);
+
+    /**
+     * Run JSON parser. It parses a JSON data string into and array of tokens, each
+     * describing a single JSON object.
+     */
+    JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len,
+                            jsmntok_t *tokens, const unsigned int num_tokens);
+
+#ifndef JSMN_HEADER
+/* Implementation has been moved to jsmn.c */
+#endif /* JSMN_HEADER */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* JSMN_H */
+
+/* Custom Helper Functions */
+#ifndef JB_JSMN_EDIT
+#define JB_JSMN_EDIT
+/* Added in by JBlanked on 2024-10-16 for use in Flipper Zero SDK*/
+
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <furi.h>
+
+// Helper function to create a JSON object
+char *jsmn(const char *key, const char *value);
+// Helper function to compare JSON keys
+int jsoneq(const char *json, jsmntok_t *tok, const char *s);
+
+// Return the value of the key in the JSON data
+char *get_json_value(char *key, char *json_data, uint32_t max_tokens);
+
+// Revised get_json_array_value function
+char *get_json_array_value(char *key, uint32_t index, char *json_data, uint32_t max_tokens);
+
+// Revised get_json_array_values function with correct token skipping
+char **get_json_array_values(char *key, char *json_data, uint32_t max_tokens, int *num_values);
+#endif /* JB_JSMN_EDIT */

+ 1 - 20
uart_text_input.h → text_input/uart_text_input.c

@@ -1,26 +1,9 @@
 // from https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/uart_terminal/uart_text_input.c
 // from https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/uart_terminal/uart_text_input.c
 // all credits to xMasterX for the code
 // all credits to xMasterX for the code
-#ifndef UART_TEXT_INPUT_H
-#define UART_TEXT_INPUT_H
-
+#include "uart_text_input.h"
 #include <gui/elements.h>
 #include <gui/elements.h>
 #include "web_crawler_icons.h"
 #include "web_crawler_icons.h"
 #include <furi.h>
 #include <furi.h>
-#include <furi.h>
-#include <furi_hal.h>
-#include <gui/gui.h>
-#include <gui/view.h>
-#include <core/common_defines.h>
-
-/** Text input anonymous structure */
-typedef struct UART_TextInput UART_TextInput;
-typedef void (*UART_TextInputCallback)(void *context);
-typedef bool (*UART_TextInputValidatorCallback)(const char *text, FuriString *error, void *context);
-
-UART_TextInputValidatorCallback
-uart_text_input_get_validator_callback(UART_TextInput *uart_text_input);
-
-void uart_text_input_reset(UART_TextInput *uart_text_input);
 
 
 struct UART_TextInput
 struct UART_TextInput
 {
 {
@@ -799,5 +782,3 @@ void uart_text_input_set_header_text(UART_TextInput *uart_text_input, const char
     with_view_model(
     with_view_model(
         uart_text_input->view, UART_TextInputModel * model, { model->header = text; }, true);
         uart_text_input->view, UART_TextInputModel * model, { model->header = text; }, true);
 }
 }
-
-#endif // UART_TEXT_INPUT_H

+ 83 - 0
text_input/uart_text_input.h

@@ -0,0 +1,83 @@
+#pragma once
+// from https://github.com/xMasterX/all-the-plugins/blob/dev/base_pack/uart_terminal/uart_text_input.c
+// all credits to xMasterX for the code
+#include <gui/view.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+    /** Text input anonymous structure */
+    typedef struct UART_TextInput UART_TextInput;
+    typedef void (*UART_TextInputCallback)(void *context);
+    typedef bool (*UART_TextInputValidatorCallback)(const char *text, FuriString *error, void *context);
+
+    /** Allocate and initialize text input
+     *
+     * This text input is used to enter string
+     *
+     * @return     UART_TextInput instance
+     */
+    UART_TextInput *uart_text_input_alloc();
+
+    /** Deinitialize and free text input
+     *
+     * @param      uart_text_input  UART_TextInput instance
+     */
+    void uart_text_input_free(UART_TextInput *uart_text_input);
+
+    /** Clean text input view Note: this function does not free memory
+     *
+     * @param      uart_text_input  Text input instance
+     */
+    void uart_text_input_reset(UART_TextInput *uart_text_input);
+
+    /** Get text input view
+     *
+     * @param      uart_text_input  UART_TextInput instance
+     *
+     * @return     View instance that can be used for embedding
+     */
+    View *uart_text_input_get_view(UART_TextInput *uart_text_input);
+
+    /** Set text input result callback
+     *
+     * @param      uart_text_input          UART_TextInput instance
+     * @param      callback            callback fn
+     * @param      callback_context    callback context
+     * @param      text_buffer         pointer to YOUR text buffer, that we going
+     *                                 to modify
+     * @param      text_buffer_size    YOUR text buffer size in bytes. Max string
+     *                                 length will be text_buffer_size-1.
+     * @param      clear_default_text  clear text from text_buffer on first OK
+     *                                 event
+     */
+    void uart_text_input_set_result_callback(
+        UART_TextInput *uart_text_input,
+        UART_TextInputCallback callback,
+        void *callback_context,
+        char *text_buffer,
+        size_t text_buffer_size,
+        bool clear_default_text);
+
+    void uart_text_input_set_validator(
+        UART_TextInput *uart_text_input,
+        UART_TextInputValidatorCallback callback,
+        void *callback_context);
+
+    UART_TextInputValidatorCallback
+    uart_text_input_get_validator_callback(UART_TextInput *uart_text_input);
+
+    void *uart_text_input_get_validator_callback_context(UART_TextInput *uart_text_input);
+
+    /** Set text input header text
+     *
+     * @param      uart_text_input  UART_TextInput instance
+     * @param      text        text to be shown
+     */
+    void uart_text_input_set_header_text(UART_TextInput *uart_text_input, const char *text);
+
+#ifdef __cplusplus
+}
+#endif

+ 8 - 5
web_crawler_free.h → web_crawler.c

@@ -1,6 +1,6 @@
-// web_crawler_free.h
+#include <web_crawler.h>
 
 
-static void free_buffers(WebCrawlerApp *app)
+void free_buffers(WebCrawlerApp *app)
 {
 {
     if (!app)
     if (!app)
     {
     {
@@ -104,7 +104,7 @@ static void free_buffers(WebCrawlerApp *app)
     }
     }
 }
 }
 
 
-static void free_resources(WebCrawlerApp *app)
+void free_resources(WebCrawlerApp *app)
 {
 {
     if (!app)
     if (!app)
     {
     {
@@ -115,7 +115,7 @@ static void free_resources(WebCrawlerApp *app)
     free_buffers(app);
     free_buffers(app);
 }
 }
 
 
-static void free_all(WebCrawlerApp *app, char *reason)
+void free_all(WebCrawlerApp *app, char *reason)
 {
 {
     if (!app)
     if (!app)
     {
     {
@@ -169,7 +169,7 @@ static void free_all(WebCrawlerApp *app, char *reason)
  * @brief      Function to free the resources used by WebCrawlerApp.
  * @brief      Function to free the resources used by WebCrawlerApp.
  * @param      app  The WebCrawlerApp object to free.
  * @param      app  The WebCrawlerApp object to free.
  */
  */
-static void web_crawler_app_free(WebCrawlerApp *app)
+void web_crawler_app_free(WebCrawlerApp *app)
 {
 {
     if (!app)
     if (!app)
     {
     {
@@ -275,3 +275,6 @@ static void web_crawler_app_free(WebCrawlerApp *app)
         free(app);
         free(app);
     }
     }
 }
 }
+
+WebCrawlerApp *app_instance = NULL;
+char *http_method_names[] = {"GET", "POST", "PUT", "DELETE", "DOWNLOAD"};

+ 21 - 2
web_crawler_e.h → web_crawler.h

@@ -2,11 +2,15 @@
 #ifndef WEB_CRAWLER_E
 #ifndef WEB_CRAWLER_E
 #define WEB_CRAWLER_E
 #define WEB_CRAWLER_E
 
 
-#include <easy_flipper.h>
+#include <easy_flipper/easy_flipper.h>
+#include <flipper_http/flipper_http.h>
+#include <jsmn/jsmn.h>
+#include <text_input/uart_text_input.h>
+#include "web_crawler_icons.h"
 #include <storage/storage.h>
 #include <storage/storage.h>
 
 
 #define TAG "WebCrawler"
 #define TAG "WebCrawler"
-static char *http_method_names[] = {"GET", "POST", "PUT", "DELETE", "DOWNLOAD"};
+extern char *http_method_names[];
 
 
 // Define the submenu items for our WebCrawler application
 // Define the submenu items for our WebCrawler application
 typedef enum
 typedef enum
@@ -111,4 +115,19 @@ typedef struct
     char *temp_buffer_payload;
     char *temp_buffer_payload;
     uint32_t temp_buffer_size_payload;
     uint32_t temp_buffer_size_payload;
 } WebCrawlerApp;
 } WebCrawlerApp;
+
+void free_buffers(WebCrawlerApp *app);
+
+void free_resources(WebCrawlerApp *app);
+
+void free_all(WebCrawlerApp *app, char *reason);
+
+/**
+ * @brief      Function to free the resources used by WebCrawlerApp.
+ * @param      app  The WebCrawlerApp object to free.
+ */
+void web_crawler_app_free(WebCrawlerApp *app);
+
+extern WebCrawlerApp *app_instance;
+
 #endif // WEB_CRAWLER_E
 #endif // WEB_CRAWLER_E