flip_wifi_callback.c 36 KB

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