flip_wifi_callback.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040
  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.3\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. // Send the custom command
  260. flipper_http_send_data(app->uart_text_input_temp_buffer);
  261. while (fhttp.last_response == NULL || strlen(fhttp.last_response) == 0)
  262. {
  263. furi_delay_ms(100);
  264. }
  265. // Switch to the view
  266. char response[100];
  267. snprintf(response, sizeof(response), "%s", fhttp.last_response);
  268. easy_flipper_dialog("", response);
  269. flipper_http_deinit();
  270. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  271. }
  272. static bool flip_wifi_alloc_text_inputs(void *context, uint32_t view)
  273. {
  274. FlipWiFiApp *app = (FlipWiFiApp *)context;
  275. if (!app)
  276. {
  277. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  278. return false;
  279. }
  280. app->uart_text_input_buffer_size = MAX_SSID_LENGTH;
  281. if (!app->uart_text_input_buffer)
  282. {
  283. if (!easy_flipper_set_buffer(&app->uart_text_input_buffer, app->uart_text_input_buffer_size))
  284. {
  285. FURI_LOG_E(TAG, "Failed to allocate text input buffer");
  286. return false;
  287. }
  288. if (!app->uart_text_input_buffer)
  289. {
  290. FURI_LOG_E(TAG, "Failed to allocate text input buffer");
  291. return false;
  292. }
  293. }
  294. if (!app->uart_text_input_temp_buffer)
  295. {
  296. if (!easy_flipper_set_buffer(&app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size))
  297. {
  298. FURI_LOG_E(TAG, "Failed to allocate text input temp buffer");
  299. return false;
  300. }
  301. if (!app->uart_text_input_temp_buffer)
  302. {
  303. FURI_LOG_E(TAG, "Failed to allocate text input temp buffer");
  304. return false;
  305. }
  306. }
  307. switch (view)
  308. {
  309. case FlipWiFiViewTextInputScan:
  310. if (!app->uart_text_input)
  311. {
  312. 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))
  313. {
  314. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Scan");
  315. return false;
  316. }
  317. if (!app->uart_text_input)
  318. {
  319. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Scan");
  320. return false;
  321. }
  322. }
  323. return true;
  324. case FlipWiFiViewTextInputSaved:
  325. if (!app->uart_text_input)
  326. {
  327. 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))
  328. {
  329. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved");
  330. return false;
  331. }
  332. if (!app->uart_text_input)
  333. {
  334. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved");
  335. return false;
  336. }
  337. }
  338. return true;
  339. case FlipWiFiViewTextInputSavedAddSSID:
  340. if (!app->uart_text_input)
  341. {
  342. 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))
  343. {
  344. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add SSID");
  345. return false;
  346. }
  347. if (!app->uart_text_input)
  348. {
  349. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add SSID");
  350. return false;
  351. }
  352. }
  353. return true;
  354. case FlipWiFiViewTextInputSavedAddPassword:
  355. if (!app->uart_text_input)
  356. {
  357. 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))
  358. {
  359. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  360. return false;
  361. }
  362. if (!app->uart_text_input)
  363. {
  364. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  365. return false;
  366. }
  367. }
  368. return true;
  369. case FlipWiFiSubmenuIndexFastCommandStart:
  370. if (!app->uart_text_input)
  371. {
  372. 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))
  373. {
  374. FURI_LOG_E(TAG, "Failed to allocate text input for Fast Command");
  375. return false;
  376. }
  377. if (!app->uart_text_input)
  378. {
  379. FURI_LOG_E(TAG, "Failed to allocate text input for Fast Command");
  380. return false;
  381. }
  382. }
  383. return true;
  384. }
  385. return false;
  386. }
  387. static void flip_wifi_free_text_inputs(void *context)
  388. {
  389. FlipWiFiApp *app = (FlipWiFiApp *)context;
  390. if (!app)
  391. {
  392. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  393. return;
  394. }
  395. if (app->uart_text_input)
  396. {
  397. free(app->uart_text_input);
  398. app->uart_text_input = NULL;
  399. view_dispatcher_remove_view(app->view_dispatcher, FlipWiFiViewTextInput);
  400. }
  401. if (app->uart_text_input_buffer)
  402. {
  403. free(app->uart_text_input_buffer);
  404. app->uart_text_input_buffer = NULL;
  405. }
  406. if (app->uart_text_input_temp_buffer)
  407. {
  408. free(app->uart_text_input_temp_buffer);
  409. app->uart_text_input_temp_buffer = NULL;
  410. }
  411. }
  412. void flip_wifi_free_all(void *context)
  413. {
  414. FlipWiFiApp *app = (FlipWiFiApp *)context;
  415. if (!app)
  416. {
  417. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  418. return;
  419. }
  420. flip_wifi_free_views(app);
  421. flip_wifi_free_widgets(app);
  422. flip_wifi_free_submenus(app);
  423. flip_wifi_free_text_inputs(app);
  424. flip_wifi_free_playlist();
  425. }
  426. static void flip_wifi_redraw_submenu_saved(void *context)
  427. {
  428. // re draw the saved submenu
  429. FlipWiFiApp *app = (FlipWiFiApp *)context;
  430. if (!app)
  431. {
  432. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  433. return;
  434. }
  435. if (!app->submenu_wifi)
  436. {
  437. FURI_LOG_E(TAG, "Submenu is NULL");
  438. return;
  439. }
  440. if (!wifi_playlist)
  441. {
  442. FURI_LOG_E(TAG, "WiFi Playlist is NULL");
  443. return;
  444. }
  445. submenu_reset(app->submenu_wifi);
  446. submenu_set_header(app->submenu_wifi, "Saved APs");
  447. submenu_add_item(app->submenu_wifi, "[Add Network]", FlipWiFiSubmenuIndexWiFiSavedAddSSID, callback_submenu_choices, app);
  448. for (size_t i = 0; i < wifi_playlist->count; i++)
  449. {
  450. submenu_add_item(app->submenu_wifi, wifi_playlist->ssids[i], FlipWiFiSubmenuIndexWiFiSavedStart + i, callback_submenu_choices, app);
  451. }
  452. }
  453. static uint32_t callback_to_submenu_main(void *context)
  454. {
  455. UNUSED(context);
  456. ssid_index = 0;
  457. return FlipWiFiViewSubmenuMain;
  458. }
  459. static uint32_t callback_to_submenu_scan(void *context)
  460. {
  461. UNUSED(context);
  462. ssid_index = 0;
  463. return FlipWiFiViewSubmenu;
  464. }
  465. static uint32_t callback_to_submenu_saved(void *context)
  466. {
  467. UNUSED(context);
  468. ssid_index = 0;
  469. return FlipWiFiViewSubmenu;
  470. }
  471. uint32_t callback_exit_app(void *context)
  472. {
  473. UNUSED(context);
  474. return VIEW_NONE;
  475. }
  476. // Callback for drawing the main screen
  477. static void flip_wifi_view_draw_callback_scan(Canvas *canvas, void *model)
  478. {
  479. UNUSED(model);
  480. canvas_clear(canvas);
  481. canvas_set_font(canvas, FontPrimary);
  482. canvas_draw_str(canvas, 0, 10, ssid_list[ssid_index]);
  483. canvas_draw_icon(canvas, 0, 53, &I_ButtonBACK_10x8);
  484. canvas_draw_str_aligned(canvas, 12, 54, AlignLeft, AlignTop, "Back");
  485. canvas_draw_icon(canvas, 96, 53, &I_ButtonRight_4x7);
  486. canvas_draw_str_aligned(canvas, 103, 54, AlignLeft, AlignTop, "Add");
  487. }
  488. static void flip_wifi_view_draw_callback_saved(Canvas *canvas, void *model)
  489. {
  490. UNUSED(model);
  491. canvas_clear(canvas);
  492. canvas_set_font(canvas, FontPrimary);
  493. canvas_draw_str(canvas, 0, 10, current_ssid);
  494. canvas_set_font(canvas, FontSecondary);
  495. char password[72];
  496. snprintf(password, sizeof(password), "Pass: %s", current_password);
  497. canvas_draw_str(canvas, 0, 20, password);
  498. canvas_draw_icon(canvas, 0, 54, &I_ButtonLeft_4x7);
  499. canvas_draw_str_aligned(canvas, 7, 54, AlignLeft, AlignTop, "Delete");
  500. canvas_draw_icon(canvas, 37, 53, &I_ButtonBACK_10x8);
  501. canvas_draw_str_aligned(canvas, 49, 54, AlignLeft, AlignTop, "Back");
  502. canvas_draw_icon(canvas, 73, 54, &I_ButtonOK_7x7);
  503. canvas_draw_str_aligned(canvas, 81, 54, AlignLeft, AlignTop, "Set");
  504. canvas_draw_icon(canvas, 100, 54, &I_ButtonRight_4x7);
  505. canvas_draw_str_aligned(canvas, 107, 54, AlignLeft, AlignTop, "Edit");
  506. }
  507. // Input callback for the view (async input handling)
  508. static bool flip_wifi_view_input_callback_scan(InputEvent *event, void *context)
  509. {
  510. FlipWiFiApp *app = (FlipWiFiApp *)context;
  511. if (event->type == InputTypePress && event->key == InputKeyRight)
  512. {
  513. // switch to text input to set password
  514. flip_wifi_free_text_inputs(app);
  515. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiViewTextInputScan))
  516. {
  517. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  518. return false;
  519. }
  520. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  521. return true;
  522. }
  523. return false;
  524. }
  525. // Input callback for the view (async input handling)
  526. static bool flip_wifi_view_input_callback_saved(InputEvent *event, void *context)
  527. {
  528. FlipWiFiApp *app = (FlipWiFiApp *)context;
  529. if (!app)
  530. {
  531. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  532. return false;
  533. }
  534. if (event->type == InputTypePress && event->key == InputKeyRight)
  535. {
  536. // set text input buffer as the selected password
  537. strncpy(app->uart_text_input_temp_buffer, wifi_playlist->passwords[ssid_index], app->uart_text_input_buffer_size);
  538. // switch to text input to set password
  539. flip_wifi_free_text_inputs(app);
  540. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiViewTextInputSaved))
  541. {
  542. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved");
  543. return false;
  544. }
  545. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  546. return true;
  547. }
  548. else if (event->type == InputTypePress && event->key == InputKeyOk)
  549. {
  550. // save the settings
  551. save_settings(wifi_playlist->ssids[ssid_index], wifi_playlist->passwords[ssid_index]);
  552. flipper_http_save_wifi(wifi_playlist->ssids[ssid_index], wifi_playlist->passwords[ssid_index]);
  553. flipper_http_connect_wifi();
  554. easy_flipper_dialog("[SUCCESS]", "All FlipperHTTP apps will now\nuse the selected network.");
  555. return true;
  556. }
  557. else if (event->type == InputTypePress && event->key == InputKeyLeft)
  558. {
  559. // delete the selected ssid and password
  560. free(wifi_playlist->ssids[ssid_index]);
  561. free(wifi_playlist->passwords[ssid_index]);
  562. free(ssid_list[ssid_index]);
  563. // shift the remaining ssids and passwords
  564. for (uint32_t i = ssid_index; i < wifi_playlist->count - 1; i++)
  565. {
  566. // Use strncpy to prevent buffer overflows and ensure null termination
  567. strncpy(wifi_playlist->ssids[i], wifi_playlist->ssids[i + 1], MAX_SSID_LENGTH - 1);
  568. wifi_playlist->ssids[i][MAX_SSID_LENGTH - 1] = '\0'; // Ensure null-termination
  569. strncpy(wifi_playlist->passwords[i], wifi_playlist->passwords[i + 1], MAX_SSID_LENGTH - 1);
  570. wifi_playlist->passwords[i][MAX_SSID_LENGTH - 1] = '\0'; // Ensure null-termination
  571. // Shift ssid_list
  572. ssid_list[i] = ssid_list[i + 1];
  573. }
  574. wifi_playlist->count--;
  575. // save the playlist to storage
  576. save_playlist(wifi_playlist);
  577. // re draw the saved submenu
  578. flip_wifi_redraw_submenu_saved(app);
  579. // switch back to the saved view
  580. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  581. return true;
  582. }
  583. return false;
  584. }
  585. // Function to trim leading and trailing whitespace
  586. // Returns the trimmed start pointer and updates the length
  587. static char *trim_whitespace(char *start, size_t *length)
  588. {
  589. // Trim leading whitespace
  590. while (*length > 0 && isspace((unsigned char)*start))
  591. {
  592. start++;
  593. (*length)--;
  594. }
  595. // Trim trailing whitespace
  596. while (*length > 0 && isspace((unsigned char)start[*length - 1]))
  597. {
  598. (*length)--;
  599. }
  600. return start;
  601. }
  602. static bool flip_wifi_handle_scan(void *context)
  603. {
  604. FlipWiFiApp *app = (FlipWiFiApp *)context;
  605. if (!app)
  606. {
  607. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  608. return false;
  609. }
  610. // load the received data from the saved file
  611. FuriString *scan_data = flipper_http_load_from_file(fhttp.file_path);
  612. if (scan_data == NULL)
  613. {
  614. FURI_LOG_E(TAG, "Failed to load received data from file.");
  615. fhttp.state = ISSUE;
  616. easy_flipper_dialog("[ERROR]", "Failed to load received data from file.");
  617. return false;
  618. }
  619. char *data_cstr = (char *)furi_string_get_cstr(scan_data);
  620. if (data_cstr == NULL)
  621. {
  622. FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
  623. furi_string_free(scan_data);
  624. fhttp.state = ISSUE;
  625. free(data_cstr);
  626. easy_flipper_dialog("[ERROR]", "Failed to get C-string from FuriString.");
  627. return false;
  628. }
  629. uint32_t ssid_count = 0;
  630. char *current_position = data_cstr;
  631. char *next_comma = NULL;
  632. // Manually split the string on commas
  633. while ((next_comma = strchr(current_position, ',')) != NULL)
  634. {
  635. // Calculate length of the SSID
  636. size_t ssid_length = next_comma - current_position;
  637. // Trim leading and trailing whitespace
  638. size_t trimmed_length = ssid_length;
  639. char *trim_start = trim_whitespace(current_position, &trimmed_length);
  640. // Handle empty SSIDs resulting from consecutive commas
  641. if (trimmed_length == 0)
  642. {
  643. current_position = next_comma + 1; // Move past the comma
  644. continue;
  645. }
  646. // Allocate memory for the SSID and copy it
  647. ssid_list[ssid_count] = malloc(trimmed_length + 1);
  648. if (ssid_list[ssid_count] == NULL)
  649. {
  650. FURI_LOG_E(TAG, "Memory allocation failed");
  651. easy_flipper_dialog("[ERROR]", "Memory allocation failed");
  652. free(data_cstr);
  653. furi_string_free(scan_data);
  654. return false;
  655. }
  656. strncpy(ssid_list[ssid_count], trim_start, trimmed_length);
  657. ssid_list[ssid_count][trimmed_length] = '\0'; // Null-terminate the string
  658. ssid_count++;
  659. if (ssid_count >= MAX_SCAN_NETWORKS)
  660. {
  661. FURI_LOG_E(TAG, "Maximum SSID limit reached");
  662. break;
  663. }
  664. current_position = next_comma + 1; // Move past the comma
  665. }
  666. // Handle the last SSID after the last comma (if any)
  667. if (*current_position != '\0' && ssid_count < MAX_SCAN_NETWORKS)
  668. {
  669. size_t ssid_length = strlen(current_position);
  670. // Trim leading and trailing whitespace
  671. size_t trimmed_length = ssid_length;
  672. char *trim_start = trim_whitespace(current_position, &trimmed_length);
  673. // Handle empty SSIDs
  674. if (trimmed_length > 0)
  675. {
  676. ssid_list[ssid_count] = malloc(trimmed_length + 1);
  677. if (ssid_list[ssid_count] == NULL)
  678. {
  679. FURI_LOG_E(TAG, "Memory allocation failed for the last SSID");
  680. easy_flipper_dialog("[ERROR]", "Memory allocation failed for the last SSID");
  681. return false;
  682. }
  683. strncpy(ssid_list[ssid_count], trim_start, trimmed_length);
  684. ssid_list[ssid_count][trimmed_length] = '\0'; // Null-terminate the string
  685. ssid_count++;
  686. }
  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 (uint32_t i = 0; i < ssid_count; i++)
  692. {
  693. char *ssid_item = ssid_list[i];
  694. if (ssid_item == NULL)
  695. {
  696. // skip any NULL entries
  697. continue;
  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. free(data_cstr);
  704. furi_string_free(scan_data);
  705. return true;
  706. }
  707. void callback_submenu_choices(void *context, uint32_t index)
  708. {
  709. FlipWiFiApp *app = (FlipWiFiApp *)context;
  710. if (!app)
  711. {
  712. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  713. return;
  714. }
  715. switch (index)
  716. {
  717. case FlipWiFiSubmenuIndexWiFiScan:
  718. flip_wifi_free_all(app);
  719. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuScan))
  720. {
  721. easy_flipper_dialog("[ERROR]", "Failed to allocate submenus for WiFi Scan");
  722. return;
  723. }
  724. // initialize uart
  725. if (!flipper_http_init(flipper_http_rx_callback, app))
  726. {
  727. easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
  728. return;
  729. }
  730. bool _flip_wifi_handle_scan()
  731. {
  732. return flip_wifi_handle_scan(app);
  733. }
  734. // scan for wifi ad parse the results
  735. flipper_http_loading_task(flipper_http_scan_wifi, _flip_wifi_handle_scan, FlipWiFiViewSubmenu, FlipWiFiViewSubmenuMain, &app->view_dispatcher);
  736. flipper_http_deinit();
  737. break;
  738. case FlipWiFiSubmenuIndexWiFiSaved:
  739. flip_wifi_free_all(app);
  740. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuSaved))
  741. {
  742. FURI_LOG_E(TAG, "Failed to allocate submenus for WiFi Saved");
  743. return;
  744. }
  745. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  746. break;
  747. case FlipWiFiSubmenuIndexAbout:
  748. flip_wifi_free_all(app);
  749. if (!flip_wifi_alloc_widgets(app, FlipWiFiViewAbout))
  750. {
  751. FURI_LOG_E(TAG, "Failed to allocate widget for About");
  752. return;
  753. }
  754. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewAbout);
  755. break;
  756. case FlipWiFiSubmenuIndexWiFiSavedAddSSID:
  757. flip_wifi_free_text_inputs(app);
  758. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiViewTextInputSavedAddSSID))
  759. {
  760. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  761. return;
  762. }
  763. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  764. break;
  765. case FlipWiFiSubmenuIndexCommands:
  766. flip_wifi_free_all(app);
  767. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuCommands))
  768. {
  769. FURI_LOG_E(TAG, "Failed to allocate submenus for Commands");
  770. return;
  771. }
  772. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  773. break;
  774. case FlipWiFiSubmenuIndexFastCommandStart ... FlipWiFiSubmenuIndexFastCommandStart + 4:
  775. // initialize uart
  776. if (!flipper_http_init(flipper_http_rx_callback, app))
  777. {
  778. easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
  779. return;
  780. }
  781. // Handle fast commands
  782. switch (index)
  783. {
  784. case FlipWiFiSubmenuIndexFastCommandStart + 0:
  785. // CUSTOM - send to text input and return
  786. flip_wifi_free_text_inputs(app);
  787. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiSubmenuIndexFastCommandStart))
  788. {
  789. FURI_LOG_E(TAG, "Failed to allocate text input for Fast Command");
  790. return;
  791. }
  792. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  793. return;
  794. case FlipWiFiSubmenuIndexFastCommandStart + 1:
  795. // PING
  796. flipper_http_ping();
  797. break;
  798. case FlipWiFiSubmenuIndexFastCommandStart + 2:
  799. // LIST
  800. flipper_http_list_commands();
  801. break;
  802. case FlipWiFiSubmenuIndexFastCommandStart + 3:
  803. // IP/ADDRESS
  804. flipper_http_ip_address();
  805. break;
  806. case FlipWiFiSubmenuIndexFastCommandStart + 4:
  807. // WIFI/IP
  808. flipper_http_ip_wifi();
  809. break;
  810. default:
  811. break;
  812. }
  813. while (fhttp.last_response == NULL || strlen(fhttp.last_response) == 0)
  814. {
  815. // Wait for the response
  816. furi_delay_ms(100);
  817. }
  818. if (fhttp.last_response != NULL)
  819. {
  820. char response[100];
  821. snprintf(response, sizeof(response), "%s", fhttp.last_response);
  822. easy_flipper_dialog("", response);
  823. }
  824. flipper_http_deinit();
  825. break;
  826. case 100 ... 199:
  827. ssid_index = index - FlipWiFiSubmenuIndexWiFiScanStart;
  828. flip_wifi_free_views(app);
  829. if (!flip_wifi_alloc_views(app, FlipWiFiViewWiFiScan))
  830. {
  831. FURI_LOG_E(TAG, "Failed to allocate views for WiFi Scan");
  832. return;
  833. }
  834. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewGeneric);
  835. break;
  836. case 200 ... 299:
  837. ssid_index = index - FlipWiFiSubmenuIndexWiFiSavedStart;
  838. flip_wifi_free_views(app);
  839. snprintf(current_ssid, sizeof(current_ssid), "%s", wifi_playlist->ssids[ssid_index]);
  840. snprintf(current_password, sizeof(current_password), "%s", wifi_playlist->passwords[ssid_index]);
  841. if (!flip_wifi_alloc_views(app, FlipWiFiViewWiFiSaved))
  842. {
  843. FURI_LOG_E(TAG, "Failed to allocate views for WiFi Saved");
  844. return;
  845. }
  846. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewGeneric);
  847. break;
  848. default:
  849. break;
  850. }
  851. }
  852. void flip_wifi_text_updated_password_scan(void *context)
  853. {
  854. FlipWiFiApp *app = (FlipWiFiApp *)context;
  855. if (!app)
  856. {
  857. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  858. return;
  859. }
  860. // Store the entered text with buffer size limit
  861. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size - 1);
  862. // Ensure null-termination
  863. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  864. if (!flip_wifi_alloc_playlist(app))
  865. {
  866. FURI_LOG_E(TAG, "Failed to allocate playlist");
  867. return;
  868. }
  869. // Ensure ssid_index is valid
  870. if (ssid_index >= MAX_SCAN_NETWORKS)
  871. {
  872. FURI_LOG_E(TAG, "Invalid ssid_index: %ld", ssid_index);
  873. return;
  874. }
  875. // Check if there's space in the playlist
  876. if (wifi_playlist->count >= MAX_SAVED_NETWORKS)
  877. {
  878. FURI_LOG_E(TAG, "Playlist is full. Cannot add more entries.");
  879. return;
  880. }
  881. FURI_LOG_I(TAG, "Adding SSID: %s", ssid_list[ssid_index]);
  882. FURI_LOG_I(TAG, "Count: %d", wifi_playlist->count);
  883. // Add the SSID and password to the playlist
  884. snprintf(wifi_playlist->ssids[wifi_playlist->count], MAX_SSID_LENGTH, "%s", ssid_list[ssid_index]);
  885. snprintf(wifi_playlist->passwords[wifi_playlist->count], MAX_SSID_LENGTH, "%s", app->uart_text_input_buffer);
  886. wifi_playlist->count++;
  887. // Save the updated playlist to storage
  888. save_playlist(wifi_playlist);
  889. // Redraw the submenu to reflect changes
  890. flip_wifi_redraw_submenu_saved(app);
  891. // Switch back to the scan view
  892. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  893. }
  894. void flip_wifi_text_updated_password_saved(void *context)
  895. {
  896. FlipWiFiApp *app = (FlipWiFiApp *)context;
  897. if (!app)
  898. {
  899. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  900. return;
  901. }
  902. // store the entered text
  903. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  904. // Ensure null-termination
  905. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  906. // update the password_saved in the playlist
  907. snprintf(wifi_playlist->passwords[ssid_index], MAX_SSID_LENGTH, app->uart_text_input_buffer);
  908. // save the playlist to storage
  909. save_playlist(wifi_playlist);
  910. // switch to back to the saved view
  911. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  912. }
  913. void flip_wifi_text_updated_add_ssid(void *context)
  914. {
  915. FlipWiFiApp *app = (FlipWiFiApp *)context;
  916. if (!app)
  917. {
  918. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  919. return;
  920. }
  921. // check if empty
  922. if (strlen(app->uart_text_input_temp_buffer) == 0)
  923. {
  924. easy_flipper_dialog("[ERROR]", "SSID cannot be empty");
  925. return;
  926. }
  927. // store the entered text
  928. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  929. // Ensure null-termination
  930. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  931. save_char("wifi-ssid", app->uart_text_input_buffer);
  932. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
  933. uart_text_input_reset(app->uart_text_input);
  934. uart_text_input_set_header_text(app->uart_text_input, "Enter Password");
  935. app->uart_text_input_buffer_size = MAX_SSID_LENGTH;
  936. free(app->uart_text_input_buffer);
  937. free(app->uart_text_input_temp_buffer);
  938. easy_flipper_set_buffer(&app->uart_text_input_buffer, app->uart_text_input_buffer_size);
  939. easy_flipper_set_buffer(&app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  940. uart_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);
  941. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  942. }
  943. void flip_wifi_text_updated_add_password(void *context)
  944. {
  945. FlipWiFiApp *app = (FlipWiFiApp *)context;
  946. if (!app)
  947. {
  948. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  949. return;
  950. }
  951. // check if empty
  952. if (strlen(app->uart_text_input_temp_buffer) == 0)
  953. {
  954. easy_flipper_dialog("[ERROR]", "Password cannot be empty");
  955. return;
  956. }
  957. // store the entered text
  958. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  959. save_char("wifi-password", app->uart_text_input_buffer);
  960. // Ensure null-termination
  961. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  962. char wifi_ssid[64];
  963. if (!load_char("wifi-ssid", wifi_ssid, sizeof(wifi_ssid)))
  964. {
  965. FURI_LOG_E(TAG, "Failed to load wifi ssid");
  966. return;
  967. }
  968. // add the SSID and password_scan to the playlist
  969. snprintf(wifi_playlist->ssids[wifi_playlist->count], MAX_SSID_LENGTH, wifi_ssid);
  970. snprintf(wifi_playlist->passwords[wifi_playlist->count], MAX_SSID_LENGTH, app->uart_text_input_buffer);
  971. wifi_playlist->count++;
  972. // save the playlist to storage
  973. save_playlist(wifi_playlist);
  974. flip_wifi_redraw_submenu_saved(app);
  975. // switch to back to the saved view
  976. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  977. }