flip_wifi_callback.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035
  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 data from /apps_data/flip_wifi/data/scan.txt");
  617. return false;
  618. }
  619. uint32_t ssid_count = 0;
  620. char *current_position = (char *)furi_string_get_cstr(scan_data);
  621. char *next_comma = NULL;
  622. // Manually split the string on commas
  623. while ((next_comma = strchr(current_position, ',')) != NULL)
  624. {
  625. // Calculate length of the SSID
  626. size_t ssid_length = next_comma - current_position;
  627. // Trim leading and trailing whitespace
  628. size_t trimmed_length = ssid_length;
  629. char *trim_start = trim_whitespace(current_position, &trimmed_length);
  630. // Handle empty SSIDs resulting from consecutive commas
  631. if (trimmed_length == 0)
  632. {
  633. current_position = next_comma + 1; // Move past the comma
  634. continue;
  635. }
  636. // Allocate memory for the SSID and copy it
  637. ssid_list[ssid_count] = malloc(trimmed_length + 1);
  638. if (ssid_list[ssid_count] == NULL)
  639. {
  640. FURI_LOG_E(TAG, "Memory allocation failed");
  641. easy_flipper_dialog("[ERROR]", "Memory allocation failed");
  642. furi_string_free(scan_data);
  643. return false;
  644. }
  645. strncpy(ssid_list[ssid_count], trim_start, trimmed_length);
  646. ssid_list[ssid_count][trimmed_length] = '\0'; // Null-terminate the string
  647. ssid_count++;
  648. if (ssid_count >= MAX_SCAN_NETWORKS)
  649. {
  650. FURI_LOG_E(TAG, "Maximum SSID limit reached");
  651. break;
  652. }
  653. current_position = next_comma + 1; // Move past the comma
  654. }
  655. // Handle the last SSID after the last comma (if any)
  656. if (*current_position != '\0' && ssid_count < MAX_SCAN_NETWORKS)
  657. {
  658. size_t ssid_length = strlen(current_position);
  659. // Trim leading and trailing whitespace
  660. size_t trimmed_length = ssid_length;
  661. char *trim_start = trim_whitespace(current_position, &trimmed_length);
  662. // Handle empty SSIDs
  663. if (trimmed_length > 0)
  664. {
  665. ssid_list[ssid_count] = malloc(trimmed_length + 1);
  666. if (ssid_list[ssid_count] == NULL)
  667. {
  668. FURI_LOG_E(TAG, "Memory allocation failed for the last SSID");
  669. easy_flipper_dialog("[ERROR]", "Memory allocation failed for the last SSID");
  670. return false;
  671. }
  672. strncpy(ssid_list[ssid_count], trim_start, trimmed_length);
  673. ssid_list[ssid_count][trimmed_length] = '\0'; // Null-terminate the string
  674. ssid_count++;
  675. }
  676. }
  677. // Add each SSID as a submenu item
  678. submenu_reset(app->submenu_wifi);
  679. submenu_set_header(app->submenu_wifi, "WiFi Nearby");
  680. for (uint32_t i = 0; i < ssid_count; i++)
  681. {
  682. char *ssid_item = ssid_list[i];
  683. if (ssid_item == NULL)
  684. {
  685. // skip any NULL entries
  686. continue;
  687. }
  688. char ssid[64];
  689. snprintf(ssid, sizeof(ssid), "%s", ssid_item);
  690. submenu_add_item(app->submenu_wifi, ssid, FlipWiFiSubmenuIndexWiFiScanStart + i, callback_submenu_choices, app);
  691. }
  692. furi_string_free(scan_data);
  693. return true;
  694. }
  695. void callback_submenu_choices(void *context, uint32_t index)
  696. {
  697. FlipWiFiApp *app = (FlipWiFiApp *)context;
  698. if (!app)
  699. {
  700. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  701. return;
  702. }
  703. switch (index)
  704. {
  705. case FlipWiFiSubmenuIndexWiFiScan:
  706. flip_wifi_free_all(app);
  707. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuScan))
  708. {
  709. easy_flipper_dialog("[ERROR]", "Failed to allocate submenus for WiFi Scan");
  710. return;
  711. }
  712. // initialize uart
  713. if (!flipper_http_init(flipper_http_rx_callback, app))
  714. {
  715. easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
  716. return;
  717. }
  718. bool _flip_wifi_handle_scan()
  719. {
  720. return flip_wifi_handle_scan(app);
  721. }
  722. // ensure directory is there for saving scan data
  723. char directory_path[128];
  724. snprintf(directory_path, sizeof(directory_path), STORAGE_EXT_PATH_PREFIX "/apps_data/flip_wifi/data");
  725. Storage *storage = furi_record_open(RECORD_STORAGE);
  726. storage_common_mkdir(storage, directory_path);
  727. furi_record_close(RECORD_STORAGE);
  728. // scan for wifi ad parse the results
  729. flipper_http_loading_task(flipper_http_scan_wifi, _flip_wifi_handle_scan, FlipWiFiViewSubmenu, FlipWiFiViewSubmenuMain, &app->view_dispatcher);
  730. flipper_http_deinit();
  731. break;
  732. case FlipWiFiSubmenuIndexWiFiSaved:
  733. flip_wifi_free_all(app);
  734. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuSaved))
  735. {
  736. FURI_LOG_E(TAG, "Failed to allocate submenus for WiFi Saved");
  737. return;
  738. }
  739. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  740. break;
  741. case FlipWiFiSubmenuIndexAbout:
  742. flip_wifi_free_all(app);
  743. if (!flip_wifi_alloc_widgets(app, FlipWiFiViewAbout))
  744. {
  745. FURI_LOG_E(TAG, "Failed to allocate widget for About");
  746. return;
  747. }
  748. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewAbout);
  749. break;
  750. case FlipWiFiSubmenuIndexWiFiSavedAddSSID:
  751. flip_wifi_free_text_inputs(app);
  752. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiViewTextInputSavedAddSSID))
  753. {
  754. FURI_LOG_E(TAG, "Failed to allocate text input for WiFi Saved Add Password");
  755. return;
  756. }
  757. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  758. break;
  759. case FlipWiFiSubmenuIndexCommands:
  760. flip_wifi_free_all(app);
  761. if (!flip_wifi_alloc_submenus(app, FlipWiFiViewSubmenuCommands))
  762. {
  763. FURI_LOG_E(TAG, "Failed to allocate submenus for Commands");
  764. return;
  765. }
  766. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  767. break;
  768. case FlipWiFiSubmenuIndexFastCommandStart ... FlipWiFiSubmenuIndexFastCommandStart + 4:
  769. // initialize uart
  770. if (!flipper_http_init(flipper_http_rx_callback, app))
  771. {
  772. easy_flipper_dialog("[ERROR]", "Failed to initialize flipper http");
  773. return;
  774. }
  775. // Handle fast commands
  776. switch (index)
  777. {
  778. case FlipWiFiSubmenuIndexFastCommandStart + 0:
  779. // CUSTOM - send to text input and return
  780. flip_wifi_free_text_inputs(app);
  781. if (!flip_wifi_alloc_text_inputs(app, FlipWiFiSubmenuIndexFastCommandStart))
  782. {
  783. FURI_LOG_E(TAG, "Failed to allocate text input for Fast Command");
  784. return;
  785. }
  786. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  787. return;
  788. case FlipWiFiSubmenuIndexFastCommandStart + 1:
  789. // PING
  790. flipper_http_ping();
  791. break;
  792. case FlipWiFiSubmenuIndexFastCommandStart + 2:
  793. // LIST
  794. flipper_http_list_commands();
  795. break;
  796. case FlipWiFiSubmenuIndexFastCommandStart + 3:
  797. // IP/ADDRESS
  798. flipper_http_ip_address();
  799. break;
  800. case FlipWiFiSubmenuIndexFastCommandStart + 4:
  801. // WIFI/IP
  802. flipper_http_ip_wifi();
  803. break;
  804. default:
  805. break;
  806. }
  807. while (fhttp.last_response == NULL || strlen(fhttp.last_response) == 0)
  808. {
  809. // Wait for the response
  810. furi_delay_ms(100);
  811. }
  812. if (fhttp.last_response != NULL)
  813. {
  814. char response[100];
  815. snprintf(response, sizeof(response), "%s", fhttp.last_response);
  816. easy_flipper_dialog("", response);
  817. }
  818. flipper_http_deinit();
  819. break;
  820. case 100 ... 199:
  821. ssid_index = index - FlipWiFiSubmenuIndexWiFiScanStart;
  822. flip_wifi_free_views(app);
  823. if (!flip_wifi_alloc_views(app, FlipWiFiViewWiFiScan))
  824. {
  825. FURI_LOG_E(TAG, "Failed to allocate views for WiFi Scan");
  826. return;
  827. }
  828. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewGeneric);
  829. break;
  830. case 200 ... 299:
  831. ssid_index = index - FlipWiFiSubmenuIndexWiFiSavedStart;
  832. flip_wifi_free_views(app);
  833. snprintf(current_ssid, sizeof(current_ssid), "%s", wifi_playlist->ssids[ssid_index]);
  834. snprintf(current_password, sizeof(current_password), "%s", wifi_playlist->passwords[ssid_index]);
  835. if (!flip_wifi_alloc_views(app, FlipWiFiViewWiFiSaved))
  836. {
  837. FURI_LOG_E(TAG, "Failed to allocate views for WiFi Saved");
  838. return;
  839. }
  840. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewGeneric);
  841. break;
  842. default:
  843. break;
  844. }
  845. }
  846. void flip_wifi_text_updated_password_scan(void *context)
  847. {
  848. FlipWiFiApp *app = (FlipWiFiApp *)context;
  849. if (!app)
  850. {
  851. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  852. return;
  853. }
  854. // Store the entered text with buffer size limit
  855. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size - 1);
  856. // Ensure null-termination
  857. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  858. if (!flip_wifi_alloc_playlist(app))
  859. {
  860. FURI_LOG_E(TAG, "Failed to allocate playlist");
  861. return;
  862. }
  863. // Ensure ssid_index is valid
  864. if (ssid_index >= MAX_SCAN_NETWORKS)
  865. {
  866. FURI_LOG_E(TAG, "Invalid ssid_index: %ld", ssid_index);
  867. return;
  868. }
  869. // Check if there's space in the playlist
  870. if (wifi_playlist->count >= MAX_SAVED_NETWORKS)
  871. {
  872. FURI_LOG_E(TAG, "Playlist is full. Cannot add more entries.");
  873. return;
  874. }
  875. FURI_LOG_I(TAG, "Adding SSID: %s", ssid_list[ssid_index]);
  876. FURI_LOG_I(TAG, "Count: %d", wifi_playlist->count);
  877. // Add the SSID and password to the playlist
  878. snprintf(wifi_playlist->ssids[wifi_playlist->count], MAX_SSID_LENGTH, "%s", ssid_list[ssid_index]);
  879. snprintf(wifi_playlist->passwords[wifi_playlist->count], MAX_SSID_LENGTH, "%s", app->uart_text_input_buffer);
  880. wifi_playlist->count++;
  881. // Save the updated playlist to storage
  882. save_playlist(wifi_playlist);
  883. // Redraw the submenu to reflect changes
  884. flip_wifi_redraw_submenu_saved(app);
  885. // Switch back to the scan view
  886. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  887. }
  888. void flip_wifi_text_updated_password_saved(void *context)
  889. {
  890. FlipWiFiApp *app = (FlipWiFiApp *)context;
  891. if (!app)
  892. {
  893. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  894. return;
  895. }
  896. // store the entered text
  897. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  898. // Ensure null-termination
  899. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  900. // update the password_saved in the playlist
  901. snprintf(wifi_playlist->passwords[ssid_index], MAX_SSID_LENGTH, app->uart_text_input_buffer);
  902. // save the playlist to storage
  903. save_playlist(wifi_playlist);
  904. // switch to back to the saved view
  905. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  906. }
  907. void flip_wifi_text_updated_add_ssid(void *context)
  908. {
  909. FlipWiFiApp *app = (FlipWiFiApp *)context;
  910. if (!app)
  911. {
  912. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  913. return;
  914. }
  915. // check if empty
  916. if (strlen(app->uart_text_input_temp_buffer) == 0)
  917. {
  918. easy_flipper_dialog("[ERROR]", "SSID cannot be empty");
  919. return;
  920. }
  921. // store the entered text
  922. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  923. // Ensure null-termination
  924. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  925. save_char("wifi-ssid", app->uart_text_input_buffer);
  926. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
  927. uart_text_input_reset(app->uart_text_input);
  928. uart_text_input_set_header_text(app->uart_text_input, "Enter Password");
  929. app->uart_text_input_buffer_size = MAX_SSID_LENGTH;
  930. free(app->uart_text_input_buffer);
  931. free(app->uart_text_input_temp_buffer);
  932. easy_flipper_set_buffer(&app->uart_text_input_buffer, app->uart_text_input_buffer_size);
  933. easy_flipper_set_buffer(&app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  934. 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);
  935. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewTextInput);
  936. }
  937. void flip_wifi_text_updated_add_password(void *context)
  938. {
  939. FlipWiFiApp *app = (FlipWiFiApp *)context;
  940. if (!app)
  941. {
  942. FURI_LOG_E(TAG, "FlipWiFiApp is NULL");
  943. return;
  944. }
  945. // check if empty
  946. if (strlen(app->uart_text_input_temp_buffer) == 0)
  947. {
  948. easy_flipper_dialog("[ERROR]", "Password cannot be empty");
  949. return;
  950. }
  951. // store the entered text
  952. strncpy(app->uart_text_input_buffer, app->uart_text_input_temp_buffer, app->uart_text_input_buffer_size);
  953. // Ensure null-termination
  954. app->uart_text_input_buffer[app->uart_text_input_buffer_size - 1] = '\0';
  955. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenuMain);
  956. save_char("wifi-password", app->uart_text_input_buffer);
  957. char wifi_ssid[64];
  958. if (!load_char("wifi-ssid", wifi_ssid, sizeof(wifi_ssid)))
  959. {
  960. FURI_LOG_E(TAG, "Failed to load wifi ssid");
  961. return;
  962. }
  963. // add the SSID and password_scan to the playlist
  964. snprintf(wifi_playlist->ssids[wifi_playlist->count], MAX_SSID_LENGTH, wifi_ssid);
  965. snprintf(wifi_playlist->passwords[wifi_playlist->count], MAX_SSID_LENGTH, app->uart_text_input_buffer);
  966. wifi_playlist->count++;
  967. // save the playlist to storage
  968. save_playlist(wifi_playlist);
  969. flip_wifi_redraw_submenu_saved(app);
  970. // switch to back to the saved view
  971. view_dispatcher_switch_to_view(app->view_dispatcher, FlipWiFiViewSubmenu);
  972. }