flip_wifi_callback.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. #include <callback/flip_wifi_callback.h>
  2. static char *ssid_list[64];
  3. static uint32_t ssid_index = 0;
  4. static char current_ssid[64];
  5. static char current_password[64];
  6. static void flip_wifi_redraw_submenu_saved(void *context);
  7. static void flip_wifi_view_draw_callback_scan(Canvas *canvas, void *model);
  8. static void flip_wifi_view_draw_callback_saved(Canvas *canvas, void *model);
  9. static bool flip_wifi_view_input_callback_scan(InputEvent *event, void *context);
  10. static bool flip_wifi_view_input_callback_saved(InputEvent *event, void *context);
  11. static uint32_t callback_to_submenu_saved(void *context);
  12. static uint32_t callback_to_submenu_scan(void *context);
  13. static uint32_t callback_to_submenu_main(void *context);
  14. void flip_wifi_text_updated_password_scan(void *context);
  15. void flip_wifi_text_updated_password_saved(void *context);
  16. void flip_wifi_text_updated_add_ssid(void *context);
  17. void flip_wifi_text_updated_add_password(void *context);
  18. static bool flip_wifi_alloc_playlist(void *context)
  19. {
  20. FlipWiFiApp *app = (FlipWiFiApp *)context;
  21. if (!app)
  22. {
  23. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  24. return false;
  25. }
  26. if (!wifi_playlist)
  27. {
  28. wifi_playlist = (WiFiPlaylist *)malloc(sizeof(WiFiPlaylist));
  29. if (!wifi_playlist)
  30. {
  31. FURI_LOG_E(TAG, "Failed to allocate playlist");
  32. return false;
  33. }
  34. wifi_playlist->count = 0;
  35. }
  36. // Load the playlist from storage
  37. if (!load_playlist(wifi_playlist))
  38. {
  39. FURI_LOG_E(TAG, "Failed to load playlist");
  40. // playlist is empty?
  41. submenu_reset(app->submenu_wifi);
  42. submenu_set_header(app->submenu_wifi, "Saved APs");
  43. submenu_add_item(app->submenu_wifi, "[Add Network]", FlipWiFiSubmenuIndexWiFiSavedAddSSID, callback_submenu_choices, app);
  44. }
  45. else
  46. {
  47. // Update the submenu
  48. flip_wifi_redraw_submenu_saved(app);
  49. }
  50. return true;
  51. }
  52. static void flip_wifi_free_playlist(void)
  53. {
  54. if (wifi_playlist)
  55. {
  56. free(wifi_playlist);
  57. wifi_playlist = NULL;
  58. }
  59. }
  60. static bool flip_wifi_alloc_views(void *context, uint32_t view)
  61. {
  62. FlipWiFiApp *app = (FlipWiFiApp *)context;
  63. if (!app)
  64. {
  65. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  66. return false;
  67. }
  68. switch (view)
  69. {
  70. case FlipWiFiViewWiFiScan:
  71. if (!app->view_wifi)
  72. {
  73. if (!easy_flipper_set_view(&app->view_wifi, FlipWiFiViewGeneric, flip_wifi_view_draw_callback_scan, flip_wifi_view_input_callback_scan, callback_to_submenu_scan, &app->view_dispatcher, app))
  74. {
  75. return false;
  76. }
  77. if (!app->view_wifi)
  78. {
  79. FURI_LOG_E(TAG, "Failed to allocate view for WiFi Scan");
  80. return false;
  81. }
  82. }
  83. return true;
  84. case FlipWiFiViewWiFiSaved:
  85. if (!app->view_wifi)
  86. {
  87. if (!easy_flipper_set_view(&app->view_wifi, FlipWiFiViewGeneric, flip_wifi_view_draw_callback_saved, flip_wifi_view_input_callback_saved, callback_to_submenu_saved, &app->view_dispatcher, app))
  88. {
  89. return false;
  90. }
  91. if (!app->view_wifi)
  92. {
  93. FURI_LOG_E(TAG, "Failed to allocate view for WiFi Scan");
  94. return false;
  95. }
  96. }
  97. return true;
  98. default:
  99. return false;
  100. }
  101. }
  102. static void flip_wifi_free_views(void *context)
  103. {
  104. FlipWiFiApp *app = (FlipWiFiApp *)context;
  105. if (!app)
  106. {
  107. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  108. return;
  109. }
  110. if (app->view_wifi)
  111. {
  112. free(app->view_wifi);
  113. app->view_wifi = NULL;
  114. view_dispatcher_remove_view(app->view_dispatcher, FlipWiFiViewGeneric);
  115. }
  116. }
  117. static bool flip_wifi_alloc_widgets(void *context, uint32_t widget)
  118. {
  119. FlipWiFiApp *app = (FlipWiFiApp *)context;
  120. if (!app)
  121. {
  122. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  123. return false;
  124. }
  125. switch (widget)
  126. {
  127. case FlipWiFiViewAbout:
  128. if (!app->widget_info)
  129. {
  130. if (!easy_flipper_set_widget(&app->widget_info, FlipWiFiViewAbout, "FlipWiFi v1.4\n-----\nFlipperHTTP companion app.\nScan and save WiFi networks.\n-----\nwww.github.com/jblanked", callback_to_submenu_main, &app->view_dispatcher))
  131. {
  132. return false;
  133. }
  134. if (!app->widget_info)
  135. {
  136. FURI_LOG_E(TAG, "Failed to allocate widget for About");
  137. return false;
  138. }
  139. }
  140. return true;
  141. default:
  142. return false;
  143. }
  144. }
  145. static void flip_wifi_free_widgets(void *context)
  146. {
  147. FlipWiFiApp *app = (FlipWiFiApp *)context;
  148. if (!app)
  149. {
  150. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  151. return;
  152. }
  153. if (app->widget_info)
  154. {
  155. free(app->widget_info);
  156. app->widget_info = NULL;
  157. view_dispatcher_remove_view(app->view_dispatcher, FlipWiFiViewAbout);
  158. }
  159. }
  160. static bool flip_wifi_alloc_submenus(void *context, uint32_t view)
  161. {
  162. FlipWiFiApp *app = (FlipWiFiApp *)context;
  163. if (!app)
  164. {
  165. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  166. return false;
  167. }
  168. switch (view)
  169. {
  170. case FlipWiFiViewSubmenuScan:
  171. if (!app->submenu_wifi)
  172. {
  173. if (!easy_flipper_set_submenu(&app->submenu_wifi, FlipWiFiViewSubmenu, "WiFi Nearby", callback_to_submenu_main, &app->view_dispatcher))
  174. {
  175. return false;
  176. }
  177. if (!app->submenu_wifi)
  178. {
  179. FURI_LOG_E(TAG, "Failed to allocate submenu for WiFi Scan");
  180. return false;
  181. }
  182. }
  183. return true;
  184. case FlipWiFiViewSubmenuSaved:
  185. if (!app->submenu_wifi)
  186. {
  187. if (!easy_flipper_set_submenu(&app->submenu_wifi, FlipWiFiViewSubmenu, "Saved APs", callback_to_submenu_main, &app->view_dispatcher))
  188. {
  189. return false;
  190. }
  191. if (!app->submenu_wifi)
  192. {
  193. FURI_LOG_E(TAG, "Failed to allocate submenu for WiFi Saved");
  194. return false;
  195. }
  196. if (!flip_wifi_alloc_playlist(app))
  197. {
  198. FURI_LOG_E(TAG, "Failed to allocate playlist");
  199. return false;
  200. }
  201. }
  202. return true;
  203. case FlipWiFiViewSubmenuCommands:
  204. if (!app->submenu_wifi)
  205. {
  206. if (!easy_flipper_set_submenu(&app->submenu_wifi, FlipWiFiViewSubmenu, "Fast Commands", callback_to_submenu_main, &app->view_dispatcher))
  207. {
  208. return false;
  209. }
  210. if (!app->submenu_wifi)
  211. {
  212. FURI_LOG_E(TAG, "Failed to allocate submenu for Commands");
  213. return false;
  214. }
  215. // PING, LIST, WIFI/LIST, IP/ADDRESS, and WIFI/IP.
  216. submenu_add_item(app->submenu_wifi, "[CUSTOM]", FlipWiFiSubmenuIndexFastCommandStart + 0, callback_submenu_choices, app);
  217. submenu_add_item(app->submenu_wifi, "PING", FlipWiFiSubmenuIndexFastCommandStart + 1, callback_submenu_choices, app);
  218. submenu_add_item(app->submenu_wifi, "LIST", FlipWiFiSubmenuIndexFastCommandStart + 2, callback_submenu_choices, app);
  219. submenu_add_item(app->submenu_wifi, "IP/ADDRESS", FlipWiFiSubmenuIndexFastCommandStart + 3, callback_submenu_choices, app);
  220. submenu_add_item(app->submenu_wifi, "WIFI/IP", FlipWiFiSubmenuIndexFastCommandStart + 4, callback_submenu_choices, app);
  221. }
  222. return true;
  223. }
  224. return false;
  225. }
  226. static void flip_wifi_free_submenus(void *context)
  227. {
  228. FlipWiFiApp *app = (FlipWiFiApp *)context;
  229. if (!app)
  230. {
  231. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  232. return;
  233. }
  234. if (app->submenu_wifi)
  235. {
  236. free(app->submenu_wifi);
  237. app->submenu_wifi = NULL;
  238. view_dispatcher_remove_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  239. }
  240. }
  241. static void flip_wifi_custom_command_updated(void *context)
  242. {
  243. FlipWiFiApp *app = (FlipWiFiApp *)context;
  244. if (!app)
  245. {
  246. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  247. return;
  248. }
  249. if (!app->uart_text_input_temp_buffer)
  250. {
  251. FURI_LOG_E(TAG, "Text input buffer is NULL");
  252. return;
  253. }
  254. if (!app->uart_text_input_temp_buffer[0])
  255. {
  256. FURI_LOG_E(TAG, "Text input buffer is empty");
  257. return;
  258. }
  259. FlipperHTTP *fhttp = flipper_http_alloc();
  260. if (!fhttp)
  261. {
  262. FURI_LOG_E(TAG, "Failed to allocate FlipperHTTP");
  263. return;
  264. }
  265. // Send the custom command
  266. flipper_http_send_data(fhttp, app->uart_text_input_temp_buffer);
  267. while (fhttp->last_response == NULL || strlen(fhttp->last_response) == 0)
  268. {
  269. furi_delay_ms(100);
  270. }
  271. // Switch to the view
  272. char response[100];
  273. snprintf(response, sizeof(response), "%s", fhttp->last_response);
  274. easy_flipper_dialog("", response);
  275. flipper_http_free(fhttp);
  276. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  277. }
  278. static bool flip_wifi_alloc_text_inputs(void *context, uint32_t view)
  279. {
  280. FlipWiFiApp *app = (FlipWiFiApp *)context;
  281. if (!app)
  282. {
  283. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  284. return false;
  285. }
  286. app->uart_text_input_buffer_size = MAX_SSID_LENGTH;
  287. if (!app->uart_text_input_buffer)
  288. {
  289. if (!easy_flipper_set_buffer(&app->uart_text_input_buffer, app->uart_text_input_buffer_size))
  290. {
  291. FURI_LOG_E(TAG, "Failed to allocate text input buffer");
  292. return false;
  293. }
  294. if (!app->uart_text_input_buffer)
  295. {
  296. FURI_LOG_E(TAG, "Failed to allocate text input buffer");
  297. return false;
  298. }
  299. }
  300. if (!app->uart_text_input_temp_buffer)
  301. {
  302. if (!easy_flipper_set_buffer(&app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size))
  303. {
  304. FURI_LOG_E(TAG, "Failed to allocate text input temp buffer");
  305. return false;
  306. }
  307. if (!app->uart_text_input_temp_buffer)
  308. {
  309. FURI_LOG_E(TAG, "Failed to allocate text input temp buffer");
  310. return false;
  311. }
  312. }
  313. switch (view)
  314. {
  315. case FlipWiFiViewTextInputScan:
  316. if (!app->uart_text_input)
  317. {
  318. if (!easy_flipper_set_uart_text_input(&app->uart_text_input, FlipWiFiViewTextInput, "Enter WiFi Password", app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, flip_wifi_text_updated_password_scan, callback_to_submenu_scan, &app->view_dispatcher, app))
  319. {
  320. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Scan");
  321. return false;
  322. }
  323. if (!app->uart_text_input)
  324. {
  325. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Scan");
  326. return false;
  327. }
  328. }
  329. return true;
  330. case FlipWiFiViewTextInputSaved:
  331. if (!app->uart_text_input)
  332. {
  333. if (!easy_flipper_set_uart_text_input(&app->uart_text_input, FlipWiFiViewTextInput, "Enter WiFi Password", app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, flip_wifi_text_updated_password_saved, callback_to_submenu_saved, &app->view_dispatcher, app))
  334. {
  335. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved");
  336. return false;
  337. }
  338. if (!app->uart_text_input)
  339. {
  340. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved");
  341. return false;
  342. }
  343. }
  344. return true;
  345. case FlipWiFiViewTextInputSavedAddSSID:
  346. if (!app->uart_text_input)
  347. {
  348. if (!easy_flipper_set_uart_text_input(&app->uart_text_input, FlipWiFiViewTextInput, "Enter SSID", app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, flip_wifi_text_updated_add_ssid, callback_to_submenu_saved, &app->view_dispatcher, app))
  349. {
  350. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add SSID");
  351. return false;
  352. }
  353. if (!app->uart_text_input)
  354. {
  355. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add SSID");
  356. return false;
  357. }
  358. }
  359. return true;
  360. case FlipWiFiViewTextInputSavedAddPassword:
  361. if (!app->uart_text_input)
  362. {
  363. if (!easy_flipper_set_uart_text_input(&app->uart_text_input, FlipWiFiViewTextInput, "Enter Password", app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, flip_wifi_text_updated_add_password, callback_to_submenu_saved, &app->view_dispatcher, app))
  364. {
  365. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  366. return false;
  367. }
  368. if (!app->uart_text_input)
  369. {
  370. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  371. return false;
  372. }
  373. }
  374. return true;
  375. case FlipWiFiSubmenuIndexFastCommandStart:
  376. if (!app->uart_text_input)
  377. {
  378. if (!easy_flipper_set_uart_text_input(&app->uart_text_input, FlipWiFiViewTextInput, "Enter Command", app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, flip_wifi_custom_command_updated, callback_to_submenu_saved, &app->view_dispatcher, app))
  379. {
  380. FURI_LOG_E(TAG, "Failed to allocate text input for Fast Command");
  381. return false;
  382. }
  383. if (!app->uart_text_input)
  384. {
  385. FURI_LOG_E(TAG, "Failed to allocate text input for Fast Command");
  386. return false;
  387. }
  388. }
  389. return true;
  390. }
  391. return false;
  392. }
  393. static void flip_wifi_free_text_inputs(void *context)
  394. {
  395. FlipWiFiApp *app = (FlipWiFiApp *)context;
  396. if (!app)
  397. {
  398. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  399. return;
  400. }
  401. if (app->uart_text_input)
  402. {
  403. free(app->uart_text_input);
  404. app->uart_text_input = NULL;
  405. view_dispatcher_remove_view(app->view_dispatcher, FlipWiFiViewTextInput);
  406. }
  407. if (app->uart_text_input_buffer)
  408. {
  409. free(app->uart_text_input_buffer);
  410. app->uart_text_input_buffer = NULL;
  411. }
  412. if (app->uart_text_input_temp_buffer)
  413. {
  414. free(app->uart_text_input_temp_buffer);
  415. app->uart_text_input_temp_buffer = NULL;
  416. }
  417. }
  418. void flip_wifi_free_all(void *context)
  419. {
  420. FlipWiFiApp *app = (FlipWiFiApp *)context;
  421. if (!app)
  422. {
  423. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  424. return;
  425. }
  426. flip_wifi_free_views(app);
  427. flip_wifi_free_widgets(app);
  428. flip_wifi_free_submenus(app);
  429. flip_wifi_free_text_inputs(app);
  430. flip_wifi_free_playlist();
  431. }
  432. static void flip_wifi_redraw_submenu_saved(void *context)
  433. {
  434. // re draw the saved submenu
  435. FlipWiFiApp *app = (FlipWiFiApp *)context;
  436. if (!app)
  437. {
  438. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  439. return;
  440. }
  441. if (!app->submenu_wifi)
  442. {
  443. FURI_LOG_E(TAG, "Submenu is NULL");
  444. return;
  445. }
  446. if (!wifi_playlist)
  447. {
  448. FURI_LOG_E(TAG, "WiFi Playlist is NULL");
  449. return;
  450. }
  451. submenu_reset(app->submenu_wifi);
  452. submenu_set_header(app->submenu_wifi, "Saved APs");
  453. submenu_add_item(app->submenu_wifi, "[Add Network]", FlipWiFiSubmenuIndexWiFiSavedAddSSID, callback_submenu_choices, app);
  454. for (size_t i = 0; i < wifi_playlist->count; i++)
  455. {
  456. submenu_add_item(app->submenu_wifi, wifi_playlist->ssids[i], FlipWiFiSubmenuIndexWiFiSavedStart + i, callback_submenu_choices, app);
  457. }
  458. }
  459. static uint32_t callback_to_submenu_main(void *context)
  460. {
  461. UNUSED(context);
  462. ssid_index = 0;
  463. return FlipWiFiViewSubmenuMain;
  464. }
  465. static uint32_t callback_to_submenu_scan(void *context)
  466. {
  467. UNUSED(context);
  468. ssid_index = 0;
  469. return FlipWiFiViewSubmenu;
  470. }
  471. static uint32_t callback_to_submenu_saved(void *context)
  472. {
  473. UNUSED(context);
  474. ssid_index = 0;
  475. return FlipWiFiViewSubmenu;
  476. }
  477. uint32_t callback_exit_app(void *context)
  478. {
  479. UNUSED(context);
  480. return VIEW_NONE;
  481. }
  482. // Callback for drawing the main screen
  483. static void flip_wifi_view_draw_callback_scan(Canvas *canvas, void *model)
  484. {
  485. UNUSED(model);
  486. canvas_clear(canvas);
  487. canvas_set_font(canvas, FontPrimary);
  488. canvas_draw_str(canvas, 0, 10, ssid_list[ssid_index]);
  489. canvas_draw_icon(canvas, 0, 53, &I_ButtonBACK_10x8);
  490. canvas_draw_str_aligned(canvas, 12, 54, AlignLeft, AlignTop, "Back");
  491. canvas_draw_icon(canvas, 96, 53, &I_ButtonRight_4x7);
  492. canvas_draw_str_aligned(canvas, 103, 54, AlignLeft, AlignTop, "Add");
  493. }
  494. static void flip_wifi_view_draw_callback_saved(Canvas *canvas, void *model)
  495. {
  496. UNUSED(model);
  497. canvas_clear(canvas);
  498. canvas_set_font(canvas, FontPrimary);
  499. canvas_draw_str(canvas, 0, 10, current_ssid);
  500. canvas_set_font(canvas, FontSecondary);
  501. char password[72];
  502. snprintf(password, sizeof(password), "Pass: %s", current_password);
  503. canvas_draw_str(canvas, 0, 20, password);
  504. canvas_draw_icon(canvas, 0, 54, &I_ButtonLeft_4x7);
  505. canvas_draw_str_aligned(canvas, 7, 54, AlignLeft, AlignTop, "Delete");
  506. canvas_draw_icon(canvas, 37, 53, &I_ButtonBACK_10x8);
  507. canvas_draw_str_aligned(canvas, 49, 54, AlignLeft, AlignTop, "Back");
  508. canvas_draw_icon(canvas, 73, 54, &I_ButtonOK_7x7);
  509. canvas_draw_str_aligned(canvas, 81, 54, AlignLeft, AlignTop, "Set");
  510. canvas_draw_icon(canvas, 100, 54, &I_ButtonRight_4x7);
  511. canvas_draw_str_aligned(canvas, 107, 54, AlignLeft, AlignTop, "Edit");
  512. }
  513. // Input callback for the view (async input handling)
  514. static bool flip_wifi_view_input_callback_scan(InputEvent *event, void *context)
  515. {
  516. FlipWiFiApp *app = (FlipWiFiApp *)context;
  517. if (event->type == InputTypePress && event->key == InputKeyRight)
  518. {
  519. // switch to text input to set password
  520. flip_wifi_free_text_inputs(app);
  521. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiViewTextInputScan))
  522. {
  523. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  524. return false;
  525. }
  526. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  527. return true;
  528. }
  529. return false;
  530. }
  531. // Input callback for the view (async input handling)
  532. static bool flip_wifi_view_input_callback_saved(InputEvent *event, void *context)
  533. {
  534. FlipWiFiApp *app = (FlipWiFiApp *)context;
  535. if (!app)
  536. {
  537. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  538. return false;
  539. }
  540. if (event->type == InputTypePress && event->key == InputKeyRight)
  541. {
  542. // set text input buffer as the selected password
  543. strncpy(app->uart_text_input_temp_buffer, wifi_playlist->passwords[ssid_index], app->uart_text_input_buffer_size);
  544. // switch to text input to set password
  545. flip_wifi_free_text_inputs(app);
  546. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiViewTextInputSaved))
  547. {
  548. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved");
  549. return false;
  550. }
  551. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  552. return true;
  553. }
  554. else if (event->type == InputTypePress && event->key == InputKeyOk)
  555. {
  556. // save the settings
  557. save_settings(wifi_playlist->ssids[ssid_index], wifi_playlist->passwords[ssid_index]);
  558. // initialize uart
  559. FlipperHTTP *fhttp = flipper_http_alloc();
  560. if (!fhttp)
  561. {
  562. easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
  563. return false;
  564. }
  565. // clear response
  566. if (fhttp->last_response)
  567. snprintf(fhttp->last_response, RX_BUF_SIZE, "%s", "");
  568. if (!flipper_http_save_wifi(fhttp, wifi_playlist->ssids[ssid_index], wifi_playlist->passwords[ssid_index]))
  569. {
  570. easy_flipper_dialog("[ERROR]", "Failed to save WiFi settings");
  571. return false;
  572. }
  573. while (!fhttp->last_response || strlen(fhttp->last_response) == 0)
  574. {
  575. furi_delay_ms(100);
  576. }
  577. flipper_http_free(fhttp);
  578. // check success (if [SUCCESS] is in the response)
  579. if (strstr(fhttp->last_response, "[SUCCESS]") == NULL)
  580. {
  581. char response[512];
  582. snprintf(response, sizeof(response), "Failed to save WiFi settings:\n%s", fhttp->last_response);
  583. easy_flipper_dialog("[ERROR]", response);
  584. return false;
  585. }
  586. easy_flipper_dialog("[SUCCESS]", "All FlipperHTTP apps will now\nuse the selected network.");
  587. return true;
  588. }
  589. else if (event->type == InputTypePress && event->key == InputKeyLeft)
  590. {
  591. // shift the remaining ssids and passwords
  592. for (uint32_t i = ssid_index; i < wifi_playlist->count - 1; i++)
  593. {
  594. // Use strncpy to prevent buffer overflows and ensure null termination
  595. strncpy(wifi_playlist->ssids[i], wifi_playlist->ssids[i + 1], MAX_SSID_LENGTH - 1);
  596. wifi_playlist->ssids[i][MAX_SSID_LENGTH - 1] = '\0'; // Ensure null-termination
  597. strncpy(wifi_playlist->passwords[i], wifi_playlist->passwords[i + 1], MAX_SSID_LENGTH - 1);
  598. wifi_playlist->passwords[i][MAX_SSID_LENGTH - 1] = '\0'; // Ensure null-termination
  599. // Shift ssid_list
  600. ssid_list[i] = ssid_list[i + 1];
  601. }
  602. wifi_playlist->count--;
  603. // delete the last ssid and password
  604. wifi_playlist->ssids[wifi_playlist->count][0] = '\0';
  605. wifi_playlist->passwords[wifi_playlist->count][0] = '\0';
  606. // save the playlist to storage
  607. save_playlist(wifi_playlist);
  608. // re draw the saved submenu
  609. flip_wifi_redraw_submenu_saved(app);
  610. // switch back to the saved view
  611. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  612. return true;
  613. }
  614. return false;
  615. }
  616. void callback_submenu_choices(void *context, uint32_t index)
  617. {
  618. FlipWiFiApp *app = (FlipWiFiApp *)context;
  619. if (!app)
  620. {
  621. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  622. return;
  623. }
  624. // initialize uart
  625. FlipperHTTP *fhttp = flipper_http_alloc();
  626. if (!fhttp)
  627. {
  628. easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
  629. return;
  630. }
  631. switch (index)
  632. {
  633. case FlipWiFiSubmenuIndexWiFiScan:
  634. flip_wifi_free_all(app);
  635. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuScan))
  636. {
  637. easy_flipper_dialog("[ERROR]", "Failed to allocate submenus for WiFi Scan");
  638. return;
  639. }
  640. // scan for wifi ad parse the results
  641. bool _flip_wifi_scan()
  642. {
  643. // storage setup
  644. Storage *storage = furi_record_open(RECORD_STORAGE);
  645. snprintf(fhttp->file_path, sizeof(fhttp->file_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi/data/scan.txt");
  646. storage_simply_remove_recursive(storage, fhttp->file_path); // ensure the file is empty
  647. // ensure flip_wifi directory is there
  648. char directory_path[128];
  649. snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi");
  650. storage_common_mkdir(storage, directory_path);
  651. snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi/data");
  652. storage_common_mkdir(storage, directory_path);
  653. furi_record_close(RECORD_STORAGE);
  654. fhttp->just_started = true;
  655. fhttp->save_received_data = true;
  656. return flipper_http_send_command(fhttp, HTTP_CMD_SCAN);
  657. }
  658. bool _flip_wifi_handle_scan()
  659. {
  660. // load the received data from the saved file
  661. FuriString *scan_data = flipper_http_load_from_file(fhttp->file_path);
  662. if (scan_data == NULL)
  663. {
  664. FURI_LOG_E(TAG, "Failed to load received data from file.");
  665. easy_flipper_dialog("[ERROR]", "Failed to load data from /apps_data/flip_wifi/data/scan.txt");
  666. return false;
  667. }
  668. uint8_t ssid_count = 0;
  669. for (uint8_t i = 0; i < MAX_SCAN_NETWORKS; i++)
  670. {
  671. char *ssid_item = get_json_array_value("networks", i, furi_string_get_cstr(scan_data));
  672. if (ssid_item == NULL)
  673. {
  674. // end of the list
  675. break;
  676. }
  677. ssid_list[i] = malloc(MAX_SSID_LENGTH);
  678. if (ssid_list[i] == NULL)
  679. {
  680. FURI_LOG_E(TAG, "Failed to allocate memory for SSID");
  681. furi_string_free(scan_data);
  682. return false;
  683. }
  684. snprintf(ssid_list[i], MAX_SSID_LENGTH, "%s", ssid_item);
  685. free(ssid_item);
  686. ssid_count++;
  687. }
  688. // Add each SSID as a submenu item
  689. submenu_reset(app->submenu_wifi);
  690. submenu_set_header(app->submenu_wifi, "WiFi Nearby");
  691. for (uint8_t i = 0; i < ssid_count; i++)
  692. {
  693. char *ssid_item = ssid_list[i];
  694. if (ssid_item == NULL)
  695. {
  696. // end of the list
  697. break;
  698. }
  699. char ssid[64];
  700. snprintf(ssid, sizeof(ssid), "%s", ssid_item);
  701. submenu_add_item(app->submenu_wifi, ssid, FlipWiFiSubmenuIndexWiFiScanStart + i, callback_submenu_choices, app);
  702. }
  703. furi_string_free(scan_data);
  704. return true;
  705. }
  706. flipper_http_loading_task(fhttp, _flip_wifi_scan, _flip_wifi_handle_scan, FlipWiFiViewSubmenu, FlipWiFiViewSubmenuMain, &app->view_dispatcher);
  707. break;
  708. case FlipWiFiSubmenuIndexWiFiSaved:
  709. flip_wifi_free_all(app);
  710. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuSaved))
  711. {
  712. FURI_LOG_E(TAG, "Failed to allocate submenus for WiFi Saved");
  713. return;
  714. }
  715. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  716. break;
  717. case FlipWiFiSubmenuIndexAbout:
  718. flip_wifi_free_all(app);
  719. if (!flip_wifi_alloc_widgets(app, FlipWiFiViewAbout))
  720. {
  721. FURI_LOG_E(TAG, "Failed to allocate widget for About");
  722. return;
  723. }
  724. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewAbout);
  725. break;
  726. case FlipWiFiSubmenuIndexWiFiSavedAddSSID:
  727. flip_wifi_free_text_inputs(app);
  728. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiViewTextInputSavedAddSSID))
  729. {
  730. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  731. return;
  732. }
  733. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  734. break;
  735. case FlipWiFiSubmenuIndexCommands:
  736. flip_wifi_free_all(app);
  737. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuCommands))
  738. {
  739. FURI_LOG_E(TAG, "Failed to allocate submenus for Commands");
  740. return;
  741. }
  742. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  743. break;
  744. case FlipWiFiSubmenuIndexFastCommandStart ... FlipWiFiSubmenuIndexFastCommandStart + 4:
  745. // Handle fast commands
  746. switch (index)
  747. {
  748. case FlipWiFiSubmenuIndexFastCommandStart + 0:
  749. // CUSTOM - send to text input and return
  750. flip_wifi_free_text_inputs(app);
  751. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiSubmenuIndexFastCommandStart))
  752. {
  753. FURI_LOG_E(TAG, "Failed to allocate text input for Fast Command");
  754. return;
  755. }
  756. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  757. return;
  758. case FlipWiFiSubmenuIndexFastCommandStart + 1:
  759. // PING
  760. flipper_http_send_command(fhttp, HTTP_CMD_PING);
  761. break;
  762. case FlipWiFiSubmenuIndexFastCommandStart + 2:
  763. // LIST
  764. flipper_http_send_command(fhttp, HTTP_CMD_LIST_COMMANDS);
  765. break;
  766. case FlipWiFiSubmenuIndexFastCommandStart + 3:
  767. // IP/ADDRESS
  768. flipper_http_send_command(fhttp, HTTP_CMD_IP_ADDRESS);
  769. break;
  770. case FlipWiFiSubmenuIndexFastCommandStart + 4:
  771. // WIFI/IP
  772. flipper_http_send_command(fhttp, HTTP_CMD_IP_WIFI);
  773. break;
  774. default:
  775. break;
  776. }
  777. while (fhttp->last_response == NULL || strlen(fhttp->last_response) == 0)
  778. {
  779. // Wait for the response
  780. furi_delay_ms(100);
  781. }
  782. if (fhttp->last_response != NULL)
  783. {
  784. char response[100];
  785. snprintf(response, sizeof(response), "%s", fhttp->last_response);
  786. easy_flipper_dialog("", response);
  787. }
  788. break;
  789. case 100 ... 199:
  790. ssid_index = index - FlipWiFiSubmenuIndexWiFiScanStart;
  791. flip_wifi_free_views(app);
  792. if (!flip_wifi_alloc_views(app, FlipWiFiViewWiFiScan))
  793. {
  794. FURI_LOG_E(TAG, "Failed to allocate views for WiFi Scan");
  795. return;
  796. }
  797. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewGeneric);
  798. break;
  799. case 200 ... 299:
  800. ssid_index = index - FlipWiFiSubmenuIndexWiFiSavedStart;
  801. flip_wifi_free_views(app);
  802. snprintf(current_ssid, sizeof(current_ssid), "%s", wifi_playlist->ssids[ssid_index]);
  803. snprintf(current_password, sizeof(current_password), "%s", wifi_playlist->passwords[ssid_index]);
  804. if (!flip_wifi_alloc_views(app, FlipWiFiViewWiFiSaved))
  805. {
  806. FURI_LOG_E(TAG, "Failed to allocate views for WiFi Saved");
  807. return;
  808. }
  809. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewGeneric);
  810. break;
  811. default:
  812. break;
  813. }
  814. flipper_http_free(fhttp);
  815. }
  816. void flip_wifi_text_updated_password_scan(void *context)
  817. {
  818. FlipWiFiApp *app = (FlipWiFiApp *)context;
  819. if (!app)
  820. {
  821. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  822. return;
  823. }
  824. // Store the entered text with buffer size limit
  825. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size - 1);
  826. // Ensure null-termination
  827. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  828. if (!flip_wifi_alloc_playlist(app))
  829. {
  830. FURI_LOG_E(TAG, "Failed to allocate playlist");
  831. return;
  832. }
  833. // Ensure ssid_index is valid
  834. if (ssid_index >= MAX_SCAN_NETWORKS)
  835. {
  836. FURI_LOG_E(TAG, "Invalid ssid_index: %ld", ssid_index);
  837. return;
  838. }
  839. // Check if there's space in the playlist
  840. if (wifi_playlist->count >= MAX_SAVED_NETWORKS)
  841. {
  842. FURI_LOG_E(TAG, "Playlist is full. Cannot add more entries.");
  843. return;
  844. }
  845. // Add the SSID and password to the playlist
  846. snprintf(wifi_playlist->ssids[wifi_playlist->count], MAX_SSID_LENGTH, "%s", ssid_list[ssid_index]);
  847. snprintf(wifi_playlist->passwords[wifi_playlist->count], MAX_SSID_LENGTH, "%s", app->uart_text_input_buffer);
  848. wifi_playlist->count++;
  849. // Save the updated playlist to storage
  850. save_playlist(wifi_playlist);
  851. // Redraw the submenu to reflect changes
  852. flip_wifi_redraw_submenu_saved(app);
  853. // Switch back to the scan view
  854. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  855. }
  856. void flip_wifi_text_updated_password_saved(void *context)
  857. {
  858. FlipWiFiApp *app = (FlipWiFiApp *)context;
  859. if (!app)
  860. {
  861. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  862. return;
  863. }
  864. // store the entered text
  865. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  866. // Ensure null-termination
  867. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  868. // update the password_saved in the playlist
  869. snprintf(wifi_playlist->passwords[ssid_index], MAX_SSID_LENGTH, app->uart_text_input_buffer);
  870. // save the playlist to storage
  871. save_playlist(wifi_playlist);
  872. // switch to back to the saved view
  873. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  874. }
  875. void flip_wifi_text_updated_add_ssid(void *context)
  876. {
  877. FlipWiFiApp *app = (FlipWiFiApp *)context;
  878. if (!app)
  879. {
  880. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  881. return;
  882. }
  883. // check if empty
  884. if (strlen(app->uart_text_input_temp_buffer) == 0)
  885. {
  886. easy_flipper_dialog("[ERROR]", "SSID cannot be empty");
  887. return;
  888. }
  889. // store the entered text
  890. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  891. // Ensure null-termination
  892. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  893. save_char("wifi-ssid", app->uart_text_input_buffer);
  894. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
  895. text_input_reset(app->uart_text_input);
  896. text_input_set_header_text(app->uart_text_input, "Enter Password");
  897. app->uart_text_input_buffer_size = MAX_SSID_LENGTH;
  898. free(app->uart_text_input_buffer);
  899. free(app->uart_text_input_temp_buffer);
  900. easy_flipper_set_buffer(&app->uart_text_input_buffer, app->uart_text_input_buffer_size);
  901. easy_flipper_set_buffer(&app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  902. text_input_set_result_callback(app->uart_text_input, flip_wifi_text_updated_add_password, app, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size, false);
  903. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  904. }
  905. void flip_wifi_text_updated_add_password(void *context)
  906. {
  907. FlipWiFiApp *app = (FlipWiFiApp *)context;
  908. if (!app)
  909. {
  910. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  911. return;
  912. }
  913. // check if empty
  914. if (strlen(app->uart_text_input_temp_buffer) == 0)
  915. {
  916. easy_flipper_dialog("[ERROR]", "Password cannot be empty");
  917. return;
  918. }
  919. // store the entered text
  920. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  921. // Ensure null-termination
  922. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  923. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
  924. save_char("wifi-password", app->uart_text_input_buffer);
  925. char wifi_ssid[64];
  926. if (!load_char("wifi-ssid", wifi_ssid, sizeof(wifi_ssid)))
  927. {
  928. FURI_LOG_E(TAG, "Failed to load wifi ssid");
  929. return;
  930. }
  931. // add the SSID and password_scan to the playlist
  932. snprintf(wifi_playlist->ssids[wifi_playlist->count], MAX_SSID_LENGTH, wifi_ssid);
  933. snprintf(wifi_playlist->passwords[wifi_playlist->count], MAX_SSID_LENGTH, app->uart_text_input_buffer);
  934. wifi_playlist->count++;
  935. // save the playlist to storage
  936. save_playlist(wifi_playlist);
  937. flip_wifi_redraw_submenu_saved(app);
  938. // switch to back to the saved view
  939. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  940. }