web_crawler_callback.h 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. // web_crawler_callback.h
  2. static bool sent_http_request = false;
  3. static bool get_success = false;
  4. static bool already_success = false;
  5. static WebCrawlerApp* app_instance = NULL;
  6. // Forward declaration of callback functions
  7. static void web_crawler_setting_item_path_clicked(void* context, uint32_t index);
  8. static void web_crawler_setting_item_headers_clicked(void* context, uint32_t index);
  9. static void web_crawler_setting_item_payload_clicked(void* context, uint32_t index);
  10. static void web_crawler_setting_item_ssid_clicked(void* context, uint32_t index);
  11. static void web_crawler_setting_item_password_clicked(void* context, uint32_t index);
  12. static void web_crawler_setting_item_file_type_clicked(void* context, uint32_t index);
  13. static void web_crawler_setting_item_file_rename_clicked(void* context, uint32_t index);
  14. static void web_crawler_setting_item_file_delete_clicked(void* context, uint32_t index);
  15. static void web_crawler_setting_item_file_read_clicked(void* context, uint32_t index);
  16. static void web_crawler_http_method_change(VariableItem* item) {
  17. uint8_t index = variable_item_get_current_value_index(item);
  18. variable_item_set_current_value_text(item, http_method_names[index]);
  19. // save the http method
  20. if(app_instance) {
  21. strncpy(
  22. app_instance->http_method,
  23. http_method_names[index],
  24. strlen(http_method_names[index]) + 1);
  25. // save the settings
  26. save_settings(
  27. app_instance->path,
  28. app_instance->ssid,
  29. app_instance->password,
  30. app_instance->file_rename,
  31. app_instance->file_type,
  32. app_instance->http_method,
  33. app_instance->headers,
  34. app_instance->payload);
  35. }
  36. }
  37. static void web_crawler_view_draw_callback(Canvas* canvas, void* context) {
  38. UNUSED(context);
  39. if(!app_instance) {
  40. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  41. return;
  42. }
  43. if(!canvas) {
  44. FURI_LOG_E(TAG, "Canvas is NULL");
  45. return;
  46. }
  47. canvas_clear(canvas);
  48. canvas_set_font(canvas, FontSecondary);
  49. if(fhttp.state == INACTIVE) {
  50. canvas_draw_str(canvas, 0, 7, "Wifi Dev Board disconnected.");
  51. canvas_draw_str(canvas, 0, 17, "Please connect to the board.");
  52. canvas_draw_str(canvas, 0, 32, "If your board is connected,");
  53. canvas_draw_str(canvas, 0, 42, "make sure you have flashed");
  54. canvas_draw_str(canvas, 0, 52, "your WiFi Devboard with the");
  55. canvas_draw_str(canvas, 0, 62, "latest FlipperHTTP flash.");
  56. return;
  57. }
  58. if(app_instance->path) {
  59. if(!sent_http_request) {
  60. snprintf(
  61. fhttp.file_path,
  62. sizeof(fhttp.file_path),
  63. STORAGE_EXT_PATH_PREFIX "/apps_data/web_crawler/received_data.txt");
  64. fhttp.save_received_data = true;
  65. if(strstr(app_instance->http_method, "GET") != NULL) {
  66. canvas_draw_str(canvas, 0, 10, "Sending GET request...");
  67. fhttp.is_bytes_request = false;
  68. // Perform GET request and handle the response
  69. if(app_instance->headers == NULL || app_instance->headers[0] == '\0' ||
  70. strstr(app_instance->headers, " ") == NULL) {
  71. get_success = flipper_http_get_request(app_instance->path);
  72. } else {
  73. get_success = flipper_http_get_request_with_headers(
  74. app_instance->path, app_instance->headers);
  75. }
  76. } else if(strstr(app_instance->http_method, "POST") != NULL) {
  77. canvas_draw_str(canvas, 0, 10, "Sending POST request...");
  78. fhttp.is_bytes_request = false;
  79. // Perform POST request and handle the response
  80. get_success = flipper_http_post_request_with_headers(
  81. app_instance->path, app_instance->headers, app_instance->payload);
  82. } else if(strstr(app_instance->http_method, "PUT") != NULL) {
  83. canvas_draw_str(canvas, 0, 10, "Sending PUT request...");
  84. fhttp.is_bytes_request = false;
  85. // Perform PUT request and handle the response
  86. get_success = flipper_http_put_request_with_headers(
  87. app_instance->path, app_instance->headers, app_instance->payload);
  88. } else if(strstr(app_instance->http_method, "DELETE") != NULL) {
  89. canvas_draw_str(canvas, 0, 10, "Sending DELETE request...");
  90. fhttp.is_bytes_request = false;
  91. // Perform DELETE request and handle the response
  92. get_success = flipper_http_delete_request_with_headers(
  93. app_instance->path, app_instance->headers, app_instance->payload);
  94. } else {
  95. // download file
  96. canvas_draw_str(canvas, 0, 10, "Downloading file...");
  97. fhttp.is_bytes_request = true;
  98. // Perform GET request and handle the response
  99. get_success =
  100. flipper_http_get_request_bytes(app_instance->path, app_instance->headers);
  101. }
  102. canvas_draw_str(canvas, 0, 20, "Sent!");
  103. if(get_success) {
  104. canvas_draw_str(canvas, 0, 30, "Receiving data...");
  105. // Set the state to RECEIVING to ensure we continue to see the receiving message
  106. fhttp.state = RECEIVING;
  107. } else {
  108. canvas_draw_str(canvas, 0, 30, "Failed.");
  109. }
  110. sent_http_request = true;
  111. } else {
  112. // print state
  113. if(get_success && fhttp.state == RECEIVING) {
  114. canvas_draw_str(canvas, 0, 10, "Receiving and parsing data...");
  115. } else if(get_success && fhttp.state == IDLE) {
  116. canvas_draw_str(canvas, 0, 10, "Data saved to file.");
  117. canvas_draw_str(canvas, 0, 20, "Press BACK to return.");
  118. } else {
  119. if(fhttp.state == ISSUE) {
  120. if(strstr(
  121. fhttp.last_response,
  122. "[ERROR] Not connected to Wifi. Failed to reconnect.") != NULL) {
  123. canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
  124. canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
  125. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  126. } else if(
  127. strstr(fhttp.last_response, "[ERROR] Failed to connect to Wifi.") !=
  128. NULL) {
  129. canvas_draw_str(canvas, 0, 10, "[ERROR] Not connected to Wifi.");
  130. canvas_draw_str(canvas, 0, 50, "Update your WiFi settings.");
  131. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  132. } else if(
  133. strstr(
  134. fhttp.last_response,
  135. "[ERROR] GET request failed with error: connection refused") != NULL) {
  136. canvas_draw_str(canvas, 0, 10, "[ERROR] Connection refused.");
  137. canvas_draw_str(canvas, 0, 50, "Choose another URL.");
  138. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  139. } else {
  140. canvas_draw_str(canvas, 0, 10, "[ERROR] Failed to sync data.");
  141. canvas_draw_str(canvas, 0, 30, "If this is your third attempt,");
  142. canvas_draw_str(canvas, 0, 40, "it's likely your URL is not");
  143. canvas_draw_str(canvas, 0, 50, "compabilbe or correct.");
  144. canvas_draw_str(canvas, 0, 60, "Press BACK to return.");
  145. }
  146. } else {
  147. canvas_draw_str(canvas, 0, 10, "HTTP request failed.");
  148. canvas_draw_str(canvas, 0, 20, "Press BACK to return.");
  149. }
  150. get_success = false;
  151. }
  152. }
  153. } else {
  154. canvas_draw_str(canvas, 0, 10, "URL not set.");
  155. }
  156. }
  157. /**
  158. * @brief Navigation callback to handle exiting from other views to the submenu.
  159. * @param context The context - WebCrawlerApp object.
  160. * @return WebCrawlerViewSubmenu
  161. */
  162. static uint32_t web_crawler_back_to_configure_callback(void* context) {
  163. UNUSED(context);
  164. // free file read widget if it exists
  165. if(app_instance->widget_file_read) {
  166. widget_reset(app_instance->widget_file_read);
  167. }
  168. return WebCrawlerViewSubmenuConfig; // Return to the configure screen
  169. }
  170. /**
  171. * @brief Navigation callback to handle returning to the Wifi Settings screen.
  172. * @param context The context - WebCrawlerApp object.
  173. * @return WebCrawlerViewSubmenu
  174. */
  175. static uint32_t web_crawler_back_to_main_callback(void* context) {
  176. UNUSED(context);
  177. // reset GET request flags
  178. sent_http_request = false;
  179. get_success = false;
  180. already_success = false;
  181. // free file read widget if it exists
  182. if(app_instance->widget_file_read) {
  183. widget_reset(app_instance->widget_file_read);
  184. }
  185. return WebCrawlerViewSubmenuMain; // Return to the main submenu
  186. }
  187. static uint32_t web_crawler_back_to_file_callback(void* context) {
  188. UNUSED(context);
  189. return WebCrawlerViewVariableItemListFile; // Return to the file submenu
  190. }
  191. static uint32_t web_crawler_back_to_wifi_callback(void* context) {
  192. UNUSED(context);
  193. return WebCrawlerViewVariableItemListWifi; // Return to the wifi submenu
  194. }
  195. static uint32_t web_crawler_back_to_request_callback(void* context) {
  196. UNUSED(context);
  197. return WebCrawlerViewVariableItemListRequest; // Return to the request submenu
  198. }
  199. /**
  200. * @brief Navigation callback to handle exiting the app from the main submenu.
  201. * @param context The context - unused
  202. * @return VIEW_NONE to exit the app
  203. */
  204. static uint32_t web_crawler_exit_app_callback(void* context) {
  205. UNUSED(context);
  206. return VIEW_NONE;
  207. }
  208. /**
  209. * @brief Handle submenu item selection.
  210. * @param context The context - WebCrawlerApp object.
  211. * @param index The WebCrawlerSubmenuIndex item that was clicked.
  212. */
  213. static void web_crawler_submenu_callback(void* context, uint32_t index) {
  214. WebCrawlerApp* app = (WebCrawlerApp*)context;
  215. if(app->view_dispatcher) {
  216. switch(index) {
  217. case WebCrawlerSubmenuIndexRun:
  218. sent_http_request = false; // Reset the flag
  219. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewRun);
  220. break;
  221. case WebCrawlerSubmenuIndexAbout:
  222. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewAbout);
  223. break;
  224. case WebCrawlerSubmenuIndexConfig:
  225. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewSubmenuConfig);
  226. break;
  227. case WebCrawlerSubmenuIndexWifi:
  228. view_dispatcher_switch_to_view(
  229. app->view_dispatcher, WebCrawlerViewVariableItemListWifi);
  230. break;
  231. case WebCrawlerSubmenuIndexRequest:
  232. view_dispatcher_switch_to_view(
  233. app->view_dispatcher, WebCrawlerViewVariableItemListRequest);
  234. break;
  235. case WebCrawlerSubmenuIndexFile:
  236. view_dispatcher_switch_to_view(
  237. app->view_dispatcher, WebCrawlerViewVariableItemListFile);
  238. break;
  239. default:
  240. FURI_LOG_E(TAG, "Unknown submenu index");
  241. break;
  242. }
  243. }
  244. }
  245. /**
  246. * @brief Configuration enter callback to handle different items.
  247. * @param context The context - WebCrawlerApp object.
  248. * @param index The index of the item that was clicked.
  249. */
  250. static void web_crawler_wifi_enter_callback(void* context, uint32_t index) {
  251. switch(index) {
  252. case 0: // SSID
  253. web_crawler_setting_item_ssid_clicked(context, index);
  254. break;
  255. case 1: // Password
  256. web_crawler_setting_item_password_clicked(context, index);
  257. break;
  258. default:
  259. FURI_LOG_E(TAG, "Unknown configuration item index");
  260. break;
  261. }
  262. }
  263. /**
  264. * @brief Configuration enter callback to handle different items.
  265. * @param context The context - WebCrawlerApp object.
  266. * @param index The index of the item that was clicked.
  267. */
  268. static void web_crawler_file_enter_callback(void* context, uint32_t index) {
  269. switch(index) {
  270. case 0: // File Read
  271. web_crawler_setting_item_file_read_clicked(context, index);
  272. break;
  273. case 1: // FIle Type
  274. web_crawler_setting_item_file_type_clicked(context, index);
  275. break;
  276. case 2: // File Rename
  277. web_crawler_setting_item_file_rename_clicked(context, index);
  278. break;
  279. case 3: // File Delete
  280. web_crawler_setting_item_file_delete_clicked(context, index);
  281. break;
  282. default:
  283. FURI_LOG_E(TAG, "Unknown configuration item index");
  284. break;
  285. }
  286. }
  287. /**
  288. * @brief Configuration enter callback to handle different items.
  289. * @param context The context - WebCrawlerApp object.
  290. * @param index The index of the item that was clicked.
  291. */
  292. static void web_crawler_request_enter_callback(void* context, uint32_t index) {
  293. switch(index) {
  294. case 0: // URL
  295. web_crawler_setting_item_path_clicked(context, index);
  296. break;
  297. case 1:
  298. // HTTP Method
  299. break;
  300. case 2:
  301. // Headers
  302. web_crawler_setting_item_headers_clicked(context, index);
  303. break;
  304. case 3:
  305. // Payload
  306. web_crawler_setting_item_payload_clicked(context, index);
  307. break;
  308. default:
  309. FURI_LOG_E(TAG, "Unknown configuration item index");
  310. break;
  311. }
  312. }
  313. /**
  314. * @brief Callback for when the user finishes entering the URL.
  315. * @param context The context - WebCrawlerApp object.
  316. */
  317. static void web_crawler_set_path_updated(void* context) {
  318. WebCrawlerApp* app = (WebCrawlerApp*)context;
  319. if(!app) {
  320. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  321. return;
  322. }
  323. if(!app->path || !app->temp_buffer_path || !app->temp_buffer_size_path || !app->path_item) {
  324. FURI_LOG_E(TAG, "Invalid path buffer");
  325. return;
  326. }
  327. // Store the entered URL from temp_buffer_path to path
  328. strncpy(app->path, app->temp_buffer_path, app->temp_buffer_size_path - 1);
  329. if(app->path_item) {
  330. variable_item_set_current_value_text(app->path_item, app->path);
  331. // Save the URL to the settings
  332. save_settings(
  333. app->path,
  334. app->ssid,
  335. app->password,
  336. app->file_rename,
  337. app->file_type,
  338. app->http_method,
  339. app->headers,
  340. app->payload);
  341. }
  342. // Return to the Configure view
  343. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewVariableItemListRequest);
  344. }
  345. /**
  346. * @brief Callback for when the user finishes entering the headers
  347. * @param context The context - WebCrawlerApp object.
  348. */
  349. static void web_crawler_set_headers_updated(void* context) {
  350. WebCrawlerApp* app = (WebCrawlerApp*)context;
  351. if(!app) {
  352. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  353. return;
  354. }
  355. if(!app->temp_buffer_headers || !app->temp_buffer_size_headers || !app->headers_item) {
  356. FURI_LOG_E(TAG, "Invalid headers buffer");
  357. return;
  358. }
  359. // Store the entered headers from temp_buffer_headers to headers
  360. strncpy(app->headers, app->temp_buffer_headers, app->temp_buffer_size_headers - 1);
  361. if(app->headers_item) {
  362. variable_item_set_current_value_text(app->headers_item, app->headers);
  363. // Save the headers to the settings
  364. save_settings(
  365. app->path,
  366. app->ssid,
  367. app->password,
  368. app->file_rename,
  369. app->file_type,
  370. app->http_method,
  371. app->headers,
  372. app->payload);
  373. }
  374. // Return to the Configure view
  375. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewVariableItemListRequest);
  376. }
  377. /**
  378. * @brief Callback for when the user finishes entering the payload.
  379. * @param context The context - WebCrawlerApp object.
  380. */
  381. static void web_crawler_set_payload_updated(void* context) {
  382. WebCrawlerApp* app = (WebCrawlerApp*)context;
  383. if(!app) {
  384. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  385. return;
  386. }
  387. if(!app->temp_buffer_payload || !app->temp_buffer_size_payload || !app->payload_item) {
  388. FURI_LOG_E(TAG, "Invalid payload buffer");
  389. return;
  390. }
  391. // Store the entered payload from temp_buffer_payload to payload
  392. strncpy(app->payload, app->temp_buffer_payload, app->temp_buffer_size_payload - 1);
  393. if(app->payload_item) {
  394. variable_item_set_current_value_text(app->payload_item, app->payload);
  395. // Save the payload to the settings
  396. save_settings(
  397. app->path,
  398. app->ssid,
  399. app->password,
  400. app->file_rename,
  401. app->file_type,
  402. app->http_method,
  403. app->headers,
  404. app->payload);
  405. }
  406. // Return to the Configure view
  407. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewVariableItemListRequest);
  408. }
  409. /**
  410. * @brief Callback for when the user finishes entering the SSID.
  411. * @param context The context - WebCrawlerApp object.
  412. */
  413. static void web_crawler_set_ssid_updated(void* context) {
  414. WebCrawlerApp* app = (WebCrawlerApp*)context;
  415. if(!app) {
  416. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  417. return;
  418. }
  419. if(!app->temp_buffer_ssid || !app->temp_buffer_size_ssid || !app->ssid || !app->ssid_item) {
  420. FURI_LOG_E(TAG, "Invalid SSID buffer");
  421. return;
  422. }
  423. // Store the entered SSID from temp_buffer_ssid to ssid
  424. strncpy(app->ssid, app->temp_buffer_ssid, app->temp_buffer_size_ssid - 1);
  425. if(app->ssid_item) {
  426. variable_item_set_current_value_text(app->ssid_item, app->ssid);
  427. // Save the SSID to the settings
  428. save_settings(
  429. app->path,
  430. app->ssid,
  431. app->password,
  432. app->file_rename,
  433. app->file_type,
  434. app->http_method,
  435. app->headers,
  436. app->payload);
  437. // send to UART
  438. if(!flipper_http_save_wifi(app->ssid, app->password)) {
  439. FURI_LOG_E(TAG, "Failed to save wifi settings via UART");
  440. FURI_LOG_E(TAG, "Make sure the Flipper is connected to the Wifi Dev Board");
  441. }
  442. }
  443. // Return to the Configure view
  444. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewVariableItemListWifi);
  445. }
  446. /**
  447. * @brief Callback for when the user finishes entering the Password.
  448. * @param context The context - WebCrawlerApp object.
  449. */
  450. static void web_crawler_set_password_update(void* context) {
  451. WebCrawlerApp* app = (WebCrawlerApp*)context;
  452. if(!app) {
  453. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  454. return;
  455. }
  456. if(!app->temp_buffer_password || !app->temp_buffer_size_password || !app->password ||
  457. !app->password_item) {
  458. FURI_LOG_E(TAG, "Invalid password buffer");
  459. return;
  460. }
  461. // Store the entered Password from temp_buffer_password to password
  462. strncpy(app->password, app->temp_buffer_password, app->temp_buffer_size_password - 1);
  463. if(app->password_item) {
  464. variable_item_set_current_value_text(app->password_item, app->password);
  465. // Save the Password to the settings
  466. save_settings(
  467. app->path,
  468. app->ssid,
  469. app->password,
  470. app->file_rename,
  471. app->file_type,
  472. app->http_method,
  473. app->headers,
  474. app->payload);
  475. // send to UART
  476. if(!flipper_http_save_wifi(app->ssid, app->password)) {
  477. FURI_LOG_E(TAG, "Failed to save wifi settings via UART");
  478. FURI_LOG_E(TAG, "Make sure the Flipper is connected to the Wifi Dev Board");
  479. }
  480. }
  481. // Return to the Configure view
  482. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewVariableItemListWifi);
  483. }
  484. /**
  485. * @brief Callback for when the user finishes entering the File Type.
  486. * @param context The context - WebCrawlerApp object.
  487. */
  488. static void web_crawler_set_file_type_update(void* context) {
  489. WebCrawlerApp* app = (WebCrawlerApp*)context;
  490. if(!app) {
  491. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  492. return;
  493. }
  494. if(!app->temp_buffer_file_type || !app->temp_buffer_size_file_type || !app->file_type ||
  495. !app->file_type_item) {
  496. FURI_LOG_E(TAG, "Invalid file type buffer");
  497. return;
  498. }
  499. // Temporary buffer to store the old name
  500. char old_file_type[256];
  501. strncpy(old_file_type, app->file_type, sizeof(old_file_type) - 1);
  502. old_file_type[sizeof(old_file_type) - 1] = '\0'; // Null-terminate
  503. strncpy(app->file_type, app->temp_buffer_file_type, app->temp_buffer_size_file_type - 1);
  504. if(app->file_type_item) {
  505. variable_item_set_current_value_text(app->file_type_item, app->file_type);
  506. // Save the File Type to the settings
  507. save_settings(
  508. app->path,
  509. app->ssid,
  510. app->password,
  511. app->file_rename,
  512. app->file_type,
  513. app->http_method,
  514. app->headers,
  515. app->payload);
  516. }
  517. rename_received_data(app->file_rename, app->file_rename, app->file_type, old_file_type);
  518. // set the file path for fhttp.file_path
  519. if(app->file_rename && app->file_type) {
  520. char file_path[256];
  521. snprintf(
  522. file_path,
  523. sizeof(file_path),
  524. "%s%s%s",
  525. RECEIVED_DATA_PATH,
  526. app->file_rename,
  527. app->file_type);
  528. file_path[sizeof(file_path) - 1] = '\0'; // Null-terminate
  529. strncpy(fhttp.file_path, file_path, sizeof(fhttp.file_path) - 1);
  530. fhttp.file_path[sizeof(fhttp.file_path) - 1] = '\0'; // Null-terminate
  531. }
  532. // Return to the Configure view
  533. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewVariableItemListFile);
  534. }
  535. /**
  536. * @brief Callback for when the user finishes entering the File Rename.
  537. * @param context The context - WebCrawlerApp object.
  538. */
  539. static void web_crawler_set_file_rename_update(void* context) {
  540. WebCrawlerApp* app = (WebCrawlerApp*)context;
  541. if(!app) {
  542. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  543. return;
  544. }
  545. if(!app->temp_buffer_file_rename || !app->temp_buffer_size_file_rename || !app->file_rename ||
  546. !app->file_rename_item) {
  547. FURI_LOG_E(TAG, "Invalid file rename buffer");
  548. return;
  549. }
  550. // Temporary buffer to store the old name
  551. char old_name[256];
  552. // Ensure that app->file_rename is null-terminated
  553. strncpy(old_name, app->file_rename, sizeof(old_name) - 1);
  554. old_name[sizeof(old_name) - 1] = '\0'; // Null-terminate
  555. // Store the entered File Rename from temp_buffer_file_rename to file_rename
  556. strncpy(app->file_rename, app->temp_buffer_file_rename, app->temp_buffer_size_file_rename - 1);
  557. if(app->file_rename_item) {
  558. variable_item_set_current_value_text(app->file_rename_item, app->file_rename);
  559. // Save the File Rename to the settings
  560. save_settings(
  561. app->path,
  562. app->ssid,
  563. app->password,
  564. app->file_rename,
  565. app->file_type,
  566. app->http_method,
  567. app->headers,
  568. app->payload);
  569. }
  570. rename_received_data(old_name, app->file_rename, app->file_type, app->file_type);
  571. // set the file path for fhttp.file_path
  572. if(app->file_rename && app->file_type) {
  573. char file_path[256];
  574. snprintf(
  575. file_path,
  576. sizeof(file_path),
  577. "%s%s%s",
  578. RECEIVED_DATA_PATH,
  579. app->file_rename,
  580. app->file_type);
  581. file_path[sizeof(file_path) - 1] = '\0'; // Null-terminate
  582. strncpy(fhttp.file_path, file_path, sizeof(fhttp.file_path) - 1);
  583. fhttp.file_path[sizeof(fhttp.file_path) - 1] = '\0'; // Null-terminate
  584. }
  585. // Return to the Configure view
  586. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewVariableItemListFile);
  587. }
  588. /**
  589. * @brief Handler for Path configuration item click.
  590. * @param context The context - WebCrawlerApp object.
  591. * @param index The index of the item that was clicked.
  592. */
  593. static void web_crawler_setting_item_path_clicked(void* context, uint32_t index) {
  594. WebCrawlerApp* app = (WebCrawlerApp*)context;
  595. if(!app) {
  596. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  597. return;
  598. }
  599. if(!app->text_input_path) {
  600. FURI_LOG_E(TAG, "Text input is NULL");
  601. return;
  602. }
  603. UNUSED(index);
  604. // Initialize temp_buffer with existing path
  605. if(app->path && strlen(app->path) > 0) {
  606. strncpy(app->temp_buffer_path, app->path, app->temp_buffer_size_path - 1);
  607. } else {
  608. strncpy(app->temp_buffer_path, "https://httpbin.org/get", app->temp_buffer_size_path - 1);
  609. }
  610. app->temp_buffer_path[app->temp_buffer_size_path - 1] = '\0';
  611. // Configure the text input
  612. bool clear_previous_text = false;
  613. text_input_set_result_callback(
  614. app->text_input_path,
  615. web_crawler_set_path_updated,
  616. app,
  617. app->temp_buffer_path,
  618. app->temp_buffer_size_path,
  619. clear_previous_text);
  620. // Set the previous callback to return to Configure screen
  621. view_set_previous_callback(
  622. text_input_get_view(app->text_input_path), web_crawler_back_to_request_callback);
  623. // Show text input dialog
  624. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewTextInput);
  625. }
  626. /**
  627. * @brief Handler for headers configuration item click.
  628. * @param context The context - WebCrawlerApp object.
  629. * @param index The index of the item that was clicked.
  630. */
  631. static void web_crawler_setting_item_headers_clicked(void* context, uint32_t index) {
  632. WebCrawlerApp* app = (WebCrawlerApp*)context;
  633. if(!app) {
  634. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  635. return;
  636. }
  637. UNUSED(index);
  638. if(!app->text_input_headers) {
  639. FURI_LOG_E(TAG, "Text input is NULL");
  640. return;
  641. }
  642. if(!app->headers) {
  643. FURI_LOG_E(TAG, "Headers is NULL");
  644. return;
  645. }
  646. if(!app->temp_buffer_headers) {
  647. FURI_LOG_E(TAG, "Temp buffer headers is NULL");
  648. return;
  649. }
  650. // Initialize temp_buffer with existing headers
  651. if(app->headers && strlen(app->headers) > 0) {
  652. strncpy(app->temp_buffer_headers, app->headers, app->temp_buffer_size_headers - 1);
  653. } else {
  654. strncpy(
  655. app->temp_buffer_headers,
  656. "{\"Content-Type\":\"application/json\",\"key\":\"value\"}",
  657. app->temp_buffer_size_headers - 1);
  658. }
  659. app->temp_buffer_headers[app->temp_buffer_size_headers - 1] = '\0';
  660. // Configure the text input
  661. bool clear_previous_text = false;
  662. text_input_set_result_callback(
  663. app->text_input_headers,
  664. web_crawler_set_headers_updated,
  665. app,
  666. app->temp_buffer_headers,
  667. app->temp_buffer_size_headers,
  668. clear_previous_text);
  669. // Set the previous callback to return to Configure screen
  670. view_set_previous_callback(
  671. text_input_get_view(app->text_input_headers), web_crawler_back_to_request_callback);
  672. // Show text input dialog
  673. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewTextInputHeaders);
  674. }
  675. /**
  676. * @brief Handler for payload configuration item click.
  677. * @param context The context - WebCrawlerApp object.
  678. * @param index The index of the item that was clicked.
  679. */
  680. static void web_crawler_setting_item_payload_clicked(void* context, uint32_t index) {
  681. WebCrawlerApp* app = (WebCrawlerApp*)context;
  682. if(!app) {
  683. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  684. return;
  685. }
  686. UNUSED(index);
  687. if(!app->text_input_payload) {
  688. FURI_LOG_E(TAG, "Text input is NULL");
  689. return;
  690. }
  691. // Initialize temp_buffer with existing payload
  692. if(app->payload && strlen(app->payload) > 0) {
  693. strncpy(app->temp_buffer_payload, app->payload, app->temp_buffer_size_payload - 1);
  694. } else {
  695. strncpy(
  696. app->temp_buffer_payload, "{\"key\":\"value\"}", app->temp_buffer_size_payload - 1);
  697. }
  698. app->temp_buffer_payload[app->temp_buffer_size_payload - 1] = '\0';
  699. // Configure the text input
  700. bool clear_previous_text = false;
  701. text_input_set_result_callback(
  702. app->text_input_payload,
  703. web_crawler_set_payload_updated,
  704. app,
  705. app->temp_buffer_payload,
  706. app->temp_buffer_size_payload,
  707. clear_previous_text);
  708. // Set the previous callback to return to Configure screen
  709. view_set_previous_callback(
  710. text_input_get_view(app->text_input_payload), web_crawler_back_to_request_callback);
  711. // Show text input dialog
  712. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewTextInputPayload);
  713. }
  714. /**
  715. * @brief Handler for SSID configuration item click.
  716. * @param context The context - WebCrawlerApp object.
  717. * @param index The index of the item that was clicked.
  718. */
  719. static void web_crawler_setting_item_ssid_clicked(void* context, uint32_t index) {
  720. WebCrawlerApp* app = (WebCrawlerApp*)context;
  721. if(!app) {
  722. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  723. return;
  724. }
  725. UNUSED(index);
  726. if(!app->text_input_ssid) {
  727. FURI_LOG_E(TAG, "Text input is NULL");
  728. return;
  729. }
  730. // Initialize temp_buffer with existing SSID
  731. if(app->ssid && strlen(app->ssid) > 0) {
  732. strncpy(app->temp_buffer_ssid, app->ssid, app->temp_buffer_size_ssid - 1);
  733. } else {
  734. strncpy(app->temp_buffer_ssid, "", app->temp_buffer_size_ssid - 1);
  735. }
  736. app->temp_buffer_ssid[app->temp_buffer_size_ssid - 1] = '\0';
  737. // Configure the text input
  738. bool clear_previous_text = false;
  739. text_input_set_result_callback(
  740. app->text_input_ssid,
  741. web_crawler_set_ssid_updated,
  742. app,
  743. app->temp_buffer_ssid,
  744. app->temp_buffer_size_ssid,
  745. clear_previous_text);
  746. // Set the previous callback to return to Configure screen
  747. view_set_previous_callback(
  748. text_input_get_view(app->text_input_ssid), web_crawler_back_to_wifi_callback);
  749. // Show text input dialog
  750. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewTextInputSSID);
  751. }
  752. /**
  753. * @brief Handler for Password configuration item click.
  754. * @param context The context - WebCrawlerApp object.
  755. * @param index The index of the item that was clicked.
  756. */
  757. static void web_crawler_setting_item_password_clicked(void* context, uint32_t index) {
  758. WebCrawlerApp* app = (WebCrawlerApp*)context;
  759. if(!app) {
  760. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  761. return;
  762. }
  763. UNUSED(index);
  764. if(!app->text_input_password) {
  765. FURI_LOG_E(TAG, "Text input is NULL");
  766. return;
  767. }
  768. // Initialize temp_buffer with existing password
  769. strncpy(app->temp_buffer_password, app->password, app->temp_buffer_size_password - 1);
  770. app->temp_buffer_password[app->temp_buffer_size_password - 1] = '\0';
  771. // Configure the text input
  772. bool clear_previous_text = false;
  773. text_input_set_result_callback(
  774. app->text_input_password,
  775. web_crawler_set_password_update,
  776. app,
  777. app->temp_buffer_password,
  778. app->temp_buffer_size_password,
  779. clear_previous_text);
  780. // Set the previous callback to return to Configure screen
  781. view_set_previous_callback(
  782. text_input_get_view(app->text_input_password), web_crawler_back_to_wifi_callback);
  783. // Show text input dialog
  784. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewTextInputPassword);
  785. }
  786. /**
  787. * @brief Handler for File Type configuration item click.
  788. * @param context The context - WebCrawlerApp object.
  789. * @param index The index of the item that was clicked.
  790. */
  791. static void web_crawler_setting_item_file_type_clicked(void* context, uint32_t index) {
  792. WebCrawlerApp* app = (WebCrawlerApp*)context;
  793. if(!app) {
  794. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  795. return;
  796. }
  797. UNUSED(index);
  798. if(!app->text_input_file_type) {
  799. FURI_LOG_E(TAG, "Text input is NULL");
  800. return;
  801. }
  802. // Initialize temp_buffer with existing file_type
  803. if(app->file_type && strlen(app->file_type) > 0) {
  804. strncpy(app->temp_buffer_file_type, app->file_type, app->temp_buffer_size_file_type - 1);
  805. } else {
  806. strncpy(app->temp_buffer_file_type, ".txt", app->temp_buffer_size_file_type - 1);
  807. }
  808. app->temp_buffer_file_type[app->temp_buffer_size_file_type - 1] = '\0';
  809. // Configure the text input
  810. bool clear_previous_text = false;
  811. text_input_set_result_callback(
  812. app->text_input_file_type,
  813. web_crawler_set_file_type_update,
  814. app,
  815. app->temp_buffer_file_type,
  816. app->temp_buffer_size_file_type,
  817. clear_previous_text);
  818. // Set the previous callback to return to Configure screen
  819. view_set_previous_callback(
  820. text_input_get_view(app->text_input_file_type), web_crawler_back_to_file_callback);
  821. // Show text input dialog
  822. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewTextInputFileType);
  823. }
  824. /**
  825. * @brief Handler for File Rename configuration item click.
  826. * @param context The context - WebCrawlerApp object.
  827. * @param index The index of the item that was clicked.
  828. */
  829. static void web_crawler_setting_item_file_rename_clicked(void* context, uint32_t index) {
  830. WebCrawlerApp* app = (WebCrawlerApp*)context;
  831. if(!app) {
  832. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  833. return;
  834. }
  835. UNUSED(index);
  836. if(!app->text_input_file_rename) {
  837. FURI_LOG_E(TAG, "Text input is NULL");
  838. return;
  839. }
  840. // Initialize temp_buffer with existing file_rename
  841. if(app->file_rename && strlen(app->file_rename) > 0) {
  842. strncpy(
  843. app->temp_buffer_file_rename, app->file_rename, app->temp_buffer_size_file_rename - 1);
  844. } else {
  845. strncpy(
  846. app->temp_buffer_file_rename, "received_data", app->temp_buffer_size_file_rename - 1);
  847. }
  848. app->temp_buffer_file_rename[app->temp_buffer_size_file_rename - 1] = '\0';
  849. // Configure the text input
  850. bool clear_previous_text = false;
  851. text_input_set_result_callback(
  852. app->text_input_file_rename,
  853. web_crawler_set_file_rename_update,
  854. app,
  855. app->temp_buffer_file_rename,
  856. app->temp_buffer_size_file_rename,
  857. clear_previous_text);
  858. // Set the previous callback to return to Configure screen
  859. view_set_previous_callback(
  860. text_input_get_view(app->text_input_file_rename), web_crawler_back_to_file_callback);
  861. // Show text input dialog
  862. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewTextInputFileRename);
  863. }
  864. /**
  865. * @brief Handler for File Delete configuration item click.
  866. * @param context The context - WebCrawlerApp object.
  867. * @param index The index of the item that was clicked.
  868. */
  869. static void web_crawler_setting_item_file_delete_clicked(void* context, uint32_t index) {
  870. WebCrawlerApp* app = (WebCrawlerApp*)context;
  871. if(!app) {
  872. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  873. return;
  874. }
  875. UNUSED(index);
  876. if(!delete_received_data(app)) {
  877. FURI_LOG_E(TAG, "Failed to delete file");
  878. }
  879. // Set the previous callback to return to Configure screen
  880. view_set_previous_callback(
  881. widget_get_view(app->widget_file_delete), web_crawler_back_to_file_callback);
  882. // Show text input dialog
  883. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewFileDelete);
  884. }
  885. static void web_crawler_setting_item_file_read_clicked(void* context, uint32_t index) {
  886. WebCrawlerApp* app = (WebCrawlerApp*)context;
  887. if(!app) {
  888. FURI_LOG_E(TAG, "WebCrawlerApp is NULL");
  889. return;
  890. }
  891. UNUSED(index);
  892. widget_reset(app->widget_file_read);
  893. // load the received data from the saved file
  894. FuriString* received_data = flipper_http_load_from_file(fhttp.file_path);
  895. if(received_data == NULL) {
  896. FURI_LOG_E(TAG, "Failed to load received data from file.");
  897. if(app->widget_file_read) {
  898. widget_add_text_scroll_element(app->widget_file_read, 0, 0, 128, 64, "File is empty.");
  899. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewFileRead);
  900. }
  901. return;
  902. }
  903. const char* data_cstr = furi_string_get_cstr(received_data);
  904. if(data_cstr == NULL) {
  905. FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
  906. furi_string_free(received_data);
  907. if(app->widget_file_read) {
  908. widget_add_text_scroll_element(app->widget_file_read, 0, 0, 128, 64, "File is empty.");
  909. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewFileRead);
  910. }
  911. return;
  912. }
  913. widget_add_text_scroll_element(app_instance->widget_file_read, 0, 0, 128, 64, data_cstr);
  914. furi_string_free(received_data);
  915. // Set the previous callback to return to Configure screen
  916. view_set_previous_callback(
  917. widget_get_view(app->widget_file_read), web_crawler_back_to_file_callback);
  918. // Show text input dialog
  919. view_dispatcher_switch_to_view(app->view_dispatcher, WebCrawlerViewFileRead);
  920. }