web_crawler_callback.c 36 KB

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