flip_social_messages.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. #include "flip_social_messages.h"
  2. FlipSocialModel2* flip_social_messages_alloc() {
  3. // Allocate memory for each username only if not already allocated
  4. FlipSocialModel2* users = malloc(sizeof(FlipSocialModel2));
  5. if(users == NULL) {
  6. FURI_LOG_E(TAG, "Failed to allocate memory for message users");
  7. return NULL;
  8. }
  9. for(size_t i = 0; i < MAX_MESSAGE_USERS; i++) {
  10. if(users->usernames[i] == NULL) {
  11. users->usernames[i] = malloc(MAX_USER_LENGTH);
  12. if(users->usernames[i] == NULL) {
  13. FURI_LOG_E(TAG, "Failed to allocate memory for username %zu", i);
  14. return NULL; // Return false on memory allocation failure
  15. }
  16. }
  17. }
  18. return users;
  19. }
  20. FlipSocialMessage* flip_social_user_messages_alloc() {
  21. // Allocate memory for each username only if not already allocated
  22. FlipSocialMessage* messages = malloc(sizeof(FlipSocialMessage));
  23. if(messages == NULL) {
  24. FURI_LOG_E(TAG, "Failed to allocate memory for messages");
  25. return NULL;
  26. }
  27. for(size_t i = 0; i < MAX_MESSAGE_USERS; i++) {
  28. if(messages->usernames[i] == NULL) {
  29. messages->usernames[i] = malloc(MAX_USER_LENGTH);
  30. if(messages->usernames[i] == NULL) {
  31. FURI_LOG_E(TAG, "Failed to allocate memory for username %zu", i);
  32. return NULL; // Return false on memory allocation failure
  33. }
  34. }
  35. if(messages->messages[i] == NULL) {
  36. messages->messages[i] = malloc(MAX_MESSAGE_LENGTH);
  37. if(messages->messages[i] == NULL) {
  38. FURI_LOG_E(TAG, "Failed to allocate memory for message %zu", i);
  39. return NULL; // Return false on memory allocation failure
  40. }
  41. }
  42. }
  43. return messages;
  44. }
  45. void flip_social_free_message_users() {
  46. if(flip_social_message_users == NULL) {
  47. FURI_LOG_E(TAG, "Message users model is NULL");
  48. return;
  49. }
  50. for(int i = 0; i < flip_social_message_users->count; i++) {
  51. if(flip_social_message_users->usernames[i]) {
  52. free(flip_social_message_users->usernames[i]);
  53. }
  54. }
  55. }
  56. void flip_social_free_messages() {
  57. if(flip_social_messages == NULL) {
  58. FURI_LOG_E(TAG, "Messages model is NULL");
  59. return;
  60. }
  61. for(int i = 0; i < flip_social_messages->count; i++) {
  62. if(flip_social_messages->usernames[i]) {
  63. free(flip_social_messages->usernames[i]);
  64. }
  65. if(flip_social_messages->messages[i]) {
  66. free(flip_social_messages->messages[i]);
  67. }
  68. }
  69. }
  70. bool flip_social_update_messages_submenu() {
  71. if(app_instance->submenu_messages == NULL) {
  72. FURI_LOG_E(TAG, "Submenu is NULL");
  73. return false;
  74. }
  75. if(flip_social_message_users == NULL) {
  76. FURI_LOG_E(TAG, "Message users model is NULL");
  77. return false;
  78. }
  79. submenu_reset(app_instance->submenu_messages);
  80. submenu_set_header(app_instance->submenu_messages, "Messages");
  81. submenu_add_item(
  82. app_instance->submenu_messages,
  83. "[New Message]",
  84. FlipSocialSubmenuLoggedInIndexMessagesNewMessage,
  85. flip_social_callback_submenu_choices,
  86. app_instance);
  87. for(int i = 0; i < flip_social_message_users->count; i++) {
  88. submenu_add_item(
  89. app_instance->submenu_messages,
  90. flip_social_message_users->usernames[i],
  91. FlipSocialSubmenuLoggedInIndexMessagesUsersStart + i,
  92. flip_social_callback_submenu_choices,
  93. app_instance);
  94. }
  95. return true;
  96. }
  97. bool flip_social_update_submenu_user_choices() {
  98. if(app_instance->submenu_messages_user_choices == NULL) {
  99. FURI_LOG_E(TAG, "Submenu is NULL");
  100. return false;
  101. }
  102. if(flip_social_explore == NULL) {
  103. FURI_LOG_E(TAG, "Explore model is NULL");
  104. return false;
  105. }
  106. submenu_reset(app_instance->submenu_messages_user_choices);
  107. submenu_set_header(app_instance->submenu_messages_user_choices, "Users");
  108. for(int i = 0; i < flip_social_explore->count; i++) {
  109. submenu_add_item(
  110. app_instance->submenu_messages_user_choices,
  111. flip_social_explore->usernames[i],
  112. FlipSocialSubmenuLoggedInIndexMessagesUserChoicesIndexStart + i,
  113. flip_social_callback_submenu_choices,
  114. app_instance);
  115. }
  116. return true;
  117. }
  118. // Get all the users that have sent messages to the logged in user
  119. bool flip_social_get_message_users() {
  120. if(app_instance->login_username_logged_out == NULL) {
  121. FURI_LOG_E(TAG, "Username is NULL");
  122. return false;
  123. }
  124. char command[128];
  125. snprintf(
  126. fhttp.file_path,
  127. sizeof(fhttp.file_path),
  128. STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/message_users.txt");
  129. fhttp.save_received_data = true;
  130. char* headers = jsmn("Content-Type", "application/json");
  131. snprintf(
  132. command,
  133. 128,
  134. "https://www.flipsocial.net/api/messages/%s/get/list/",
  135. app_instance->login_username_logged_out);
  136. bool success = flipper_http_get_request_with_headers(command, headers);
  137. free(headers);
  138. if(!success) {
  139. FURI_LOG_E(TAG, "Failed to send HTTP request for messages");
  140. fhttp.state = ISSUE;
  141. return false;
  142. }
  143. fhttp.state = RECEIVING;
  144. return true;
  145. }
  146. // Get all the messages between the logged in user and the selected user
  147. bool flip_social_get_messages_with_user() {
  148. if(app_instance->login_username_logged_out == NULL) {
  149. FURI_LOG_E(TAG, "Username is NULL");
  150. return false;
  151. }
  152. char command[128];
  153. snprintf(
  154. fhttp.file_path,
  155. sizeof(fhttp.file_path),
  156. STORAGE_EXT_PATH_PREFIX "/apps_data/flip_social/messages.txt");
  157. fhttp.save_received_data = true;
  158. char* headers = jsmn("Content-Type", "application/json");
  159. snprintf(
  160. command,
  161. 128,
  162. "https://www.flipsocial.net/api/messages/%s/get/%s/",
  163. app_instance->login_username_logged_out,
  164. flip_social_message_users->usernames[flip_social_message_users->index]);
  165. bool success = flipper_http_get_request_with_headers(command, headers);
  166. free(headers);
  167. if(!success) {
  168. FURI_LOG_E(TAG, "Failed to send HTTP request for messages");
  169. fhttp.state = ISSUE;
  170. return false;
  171. }
  172. fhttp.state = RECEIVING;
  173. return true;
  174. }
  175. // Parse the users that have sent messages to the logged-in user
  176. bool flip_social_parse_json_message_users() {
  177. // load the received data from the saved file
  178. FuriString* message_data = flipper_http_load_from_file(fhttp.file_path);
  179. if(message_data == NULL) {
  180. FURI_LOG_E(TAG, "Failed to load received data from file.");
  181. return false;
  182. }
  183. char* data_cstr = (char*)furi_string_get_cstr(message_data);
  184. if(data_cstr == NULL) {
  185. FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
  186. furi_string_free(message_data);
  187. return false;
  188. }
  189. // Allocate memory for each username only if not already allocated
  190. flip_social_message_users = flip_social_messages_alloc();
  191. if(flip_social_message_users == NULL) {
  192. FURI_LOG_E(TAG, "Failed to allocate memory for message users.");
  193. furi_string_free(message_data);
  194. free(data_cstr);
  195. return false;
  196. }
  197. // Remove newlines
  198. char* pos = data_cstr;
  199. while((pos = strchr(pos, '\n')) != NULL) {
  200. *pos = ' ';
  201. }
  202. // Initialize message users count
  203. flip_social_message_users->count = 0;
  204. // Extract the users array from the JSON
  205. char* json_users = get_json_value("users", data_cstr, MAX_TOKENS);
  206. if(json_users == NULL) {
  207. FURI_LOG_E(TAG, "Failed to parse users array.");
  208. furi_string_free(message_data);
  209. free(data_cstr);
  210. return false;
  211. }
  212. // Manual tokenization for comma-separated values
  213. char* start = json_users + 1; // Skip the opening bracket
  214. char* end;
  215. while((end = strchr(start, ',')) != NULL &&
  216. flip_social_message_users->count < MAX_MESSAGE_USERS) {
  217. *end = '\0'; // Null-terminate the current token
  218. // Remove quotes
  219. if(*start == '"') start++;
  220. if(*(end - 1) == '"') *(end - 1) = '\0';
  221. // Copy username to pre-allocated memory
  222. snprintf(
  223. flip_social_message_users->usernames[flip_social_message_users->count],
  224. MAX_USER_LENGTH,
  225. "%s",
  226. start);
  227. flip_social_message_users->count++;
  228. start = end + 1;
  229. }
  230. // Handle the last token
  231. if(*start != '\0' && flip_social_message_users->count < MAX_MESSAGE_USERS) {
  232. if(*start == '"') start++;
  233. if(*(start + strlen(start) - 1) == ']') *(start + strlen(start) - 1) = '\0';
  234. if(*(start + strlen(start) - 1) == '"') *(start + strlen(start) - 1) = '\0';
  235. snprintf(
  236. flip_social_message_users->usernames[flip_social_message_users->count],
  237. MAX_USER_LENGTH,
  238. "%s",
  239. start);
  240. flip_social_message_users->count++;
  241. }
  242. // Add submenu items for the users
  243. flip_social_update_messages_submenu();
  244. // Free the JSON data
  245. free(json_users);
  246. free(start);
  247. free(end);
  248. furi_string_free(message_data);
  249. free(data_cstr);
  250. return true;
  251. }
  252. // Parse the users that the logged in user can message
  253. bool flip_social_parse_json_message_user_choices() {
  254. // load the received data from the saved file
  255. FuriString* user_data = flipper_http_load_from_file(fhttp.file_path);
  256. if(user_data == NULL) {
  257. FURI_LOG_E(TAG, "Failed to load received data from file.");
  258. return false;
  259. }
  260. char* data_cstr = (char*)furi_string_get_cstr(user_data);
  261. if(data_cstr == NULL) {
  262. FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
  263. furi_string_free(user_data);
  264. return false;
  265. }
  266. // Allocate memory for each username only if not already allocated
  267. flip_social_explore = flip_social_explore_alloc();
  268. if(flip_social_explore == NULL) {
  269. FURI_LOG_E(TAG, "Failed to allocate memory for explore usernames.");
  270. furi_string_free(user_data);
  271. free(data_cstr);
  272. return false;
  273. }
  274. // Remove newlines
  275. char* pos = data_cstr;
  276. while((pos = strchr(pos, '\n')) != NULL) {
  277. *pos = ' ';
  278. }
  279. // Initialize explore count
  280. flip_social_explore->count = 0;
  281. // Extract the users array from the JSON
  282. char* json_users = get_json_value("users", data_cstr, MAX_TOKENS);
  283. if(json_users == NULL) {
  284. FURI_LOG_E(TAG, "Failed to parse users array.");
  285. furi_string_free(user_data);
  286. free(data_cstr);
  287. return false;
  288. }
  289. // Manual tokenization for comma-separated values
  290. char* start = json_users + 1; // Skip the opening bracket
  291. char* end;
  292. while((end = strchr(start, ',')) != NULL && flip_social_explore->count < MAX_EXPLORE_USERS) {
  293. *end = '\0'; // Null-terminate the current token
  294. // Remove quotes
  295. if(*start == '"') start++;
  296. if(*(end - 1) == '"') *(end - 1) = '\0';
  297. // Copy username to pre-allocated memory
  298. snprintf(
  299. flip_social_explore->usernames[flip_social_explore->count],
  300. MAX_USER_LENGTH,
  301. "%s",
  302. start);
  303. flip_social_explore->count++;
  304. start = end + 1;
  305. }
  306. // Handle the last token
  307. if(*start != '\0' && flip_social_explore->count < MAX_EXPLORE_USERS) {
  308. if(*start == '"') start++;
  309. if(*(start + strlen(start) - 1) == ']') *(start + strlen(start) - 1) = '\0';
  310. if(*(start + strlen(start) - 1) == '"') *(start + strlen(start) - 1) = '\0';
  311. snprintf(
  312. flip_social_explore->usernames[flip_social_explore->count],
  313. MAX_USER_LENGTH,
  314. "%s",
  315. start);
  316. flip_social_explore->count++;
  317. }
  318. // Add submenu items for the users
  319. flip_social_update_submenu_user_choices();
  320. // Free the JSON data
  321. free(json_users);
  322. free(start);
  323. free(end);
  324. furi_string_free(user_data);
  325. free(data_cstr);
  326. return true;
  327. }
  328. // parse messages between the logged in user and the selected user
  329. bool flip_social_parse_json_messages() {
  330. // load the received data from the saved file
  331. FuriString* message_data = flipper_http_load_from_file(fhttp.file_path);
  332. if(message_data == NULL) {
  333. FURI_LOG_E(TAG, "Failed to load received data from file.");
  334. return false;
  335. }
  336. char* data_cstr = (char*)furi_string_get_cstr(message_data);
  337. if(data_cstr == NULL) {
  338. FURI_LOG_E(TAG, "Failed to get C-string from FuriString.");
  339. furi_string_free(message_data);
  340. return false;
  341. }
  342. // Allocate memory for each message only if not already allocated
  343. flip_social_messages = flip_social_user_messages_alloc();
  344. if(!flip_social_messages) {
  345. FURI_LOG_E(TAG, "Failed to allocate memory for messages.");
  346. furi_string_free(message_data);
  347. free(data_cstr);
  348. return false;
  349. }
  350. // Remove newlines
  351. char* pos = data_cstr;
  352. while((pos = strchr(pos, '\n')) != NULL) {
  353. *pos = ' ';
  354. }
  355. // Initialize messages count
  356. flip_social_messages->count = 0;
  357. // Iterate through the messages array
  358. for(int i = 0; i < MAX_MESSAGES; i++) {
  359. // Parse each item in the array
  360. char* item = get_json_array_value("conversations", i, data_cstr, MAX_TOKENS);
  361. if(item == NULL) {
  362. break;
  363. }
  364. // Extract individual fields from the JSON object
  365. char* sender = get_json_value("sender", item, MAX_TOKENS);
  366. char* content = get_json_value("content", item, MAX_TOKENS);
  367. if(sender == NULL || content == NULL) {
  368. FURI_LOG_E(TAG, "Failed to parse item fields.");
  369. free(item);
  370. continue;
  371. }
  372. // Store parsed values in pre-allocated memory
  373. snprintf(flip_social_messages->usernames[i], MAX_USER_LENGTH, "%s", sender);
  374. snprintf(flip_social_messages->messages[i], MAX_MESSAGE_LENGTH, "%s", content);
  375. flip_social_messages->count++;
  376. free(item);
  377. free(sender);
  378. free(content);
  379. }
  380. furi_string_free(message_data);
  381. free(data_cstr);
  382. return true;
  383. }