/* * Copyright (c) 2022 joshua stein * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include "subtext.h" #include "db.h" #include "logger.h" #include "main_menu.h" struct main_menu_option *main_menu_options = NULL; struct main_menu_option * main_menu_parse(char *opts, size_t len) { char *line = NULL, *action = NULL, *menu_key = NULL, *all_keys = NULL, *label = NULL; size_t n, m, linelen, lastsep, linenum, ret_size; short actionid, ret_count; struct main_menu_option *ret = NULL; ret_count = 0; ret_size = 0; #define LINESIZE 1024 line = xmalloc(LINESIZE); if (line == NULL) goto parse_done; action = xmalloc(LINESIZE); if (action == NULL) goto parse_done; menu_key = xmalloc(LINESIZE); if (menu_key == NULL) goto parse_done; all_keys = xmalloc(LINESIZE); if (all_keys == NULL) goto parse_done; label = xmalloc(LINESIZE); if (label == NULL) goto parse_done; for (n = 0, lastsep = 0, linenum = 0; n <= len; n++) { if (!(n == len || opts[n] == '\r')) continue; linenum++; linelen = MIN(n - lastsep, LINESIZE - 1); if (n == len && linelen) linelen--; memcpy(line, opts + lastsep, linelen); line[linelen] = '\0'; lastsep = n + 1; if (line[0] == '\0' || line[0] == '#' || line[0] == '\r') continue; /* BOARD_SHOW_FIRST:B:Bb:Message Board */ /* sscanf won't match %[^:] for an empty section ("A::Aa:aa") */ action[0] = '\0'; for (m = 0; m < linelen; m++) { if (line[m] == ':') { memcpy(action, line, m); action[m] = '\0'; linelen -= m + 1; memmove(line, line + m + 1, linelen + 1); break; } } if (action[0] == '\0') { logger_printf("[views] Error parsing main_menu.txt on line " "%ld: no action found", linenum); ret_count = 0; break; } actionid = ACTION_NONE; if (strcmp(action, "BOARD_LIST_BOARDS") == 0) actionid = ACTION_BOARD_LIST_BOARDS; else if (strcmp(action, "BOARD_LIST_FTN_AREAS") == 0) actionid = ACTION_BOARD_LIST_FTN_AREAS; else if (strcmp(action, "BOARD_SHOW_FIRST") == 0) actionid = ACTION_BOARD_SHOW_FIRST; else if (strcmp(action, "BOARD_SHOW_1") == 0) actionid = ACTION_BOARD_SHOW_1; else if (strcmp(action, "BOARD_SHOW_2") == 0) actionid = ACTION_BOARD_SHOW_2; else if (strcmp(action, "BOARD_SHOW_3") == 0) actionid = ACTION_BOARD_SHOW_3; else if (strcmp(action, "BOARD_SHOW_4") == 0) actionid = ACTION_BOARD_SHOW_4; else if (strcmp(action, "BOARD_SHOW_5") == 0) actionid = ACTION_BOARD_SHOW_5; else if (strcmp(action, "BOARD_SHOW_6") == 0) actionid = ACTION_BOARD_SHOW_6; else if (strcmp(action, "BOARD_SHOW_7") == 0) actionid = ACTION_BOARD_SHOW_7; else if (strcmp(action, "BOARD_SHOW_8") == 0) actionid = ACTION_BOARD_SHOW_8; else if (strcmp(action, "BOARD_SHOW_9") == 0) actionid = ACTION_BOARD_SHOW_9; else if (strcmp(action, "BOARD_SHOW_10") == 0) actionid = ACTION_BOARD_SHOW_10; else if (strcmp(action, "CHAT") == 0) actionid = ACTION_CHAT; else if (strcmp(action, "FILES_MENU") == 0) actionid = ACTION_FILES_MENU; else if (strcmp(action, "GOODBYE") == 0) actionid = ACTION_GOODBYE; else if (strcmp(action, "RECENT_LOGINS") == 0) actionid = ACTION_RECENT_LOGINS; else if (strcmp(action, "MAIL_COMPOSE") == 0) actionid = ACTION_MAIL_COMPOSE; else if (strcmp(action, "MAIL_MENU") == 0) actionid = ACTION_MAIL_MENU; else if (strcmp(action, "MOTD") == 0) actionid = ACTION_MOTD; else if (strcmp(action, "PAGE_SEND_OR_ANSWER") == 0) actionid = ACTION_PAGE_SEND_OR_ANSWER; else if (strcmp(action, "SETTINGS_OR_SIGNUP") == 0) actionid = ACTION_SETTINGS_OR_SIGNUP; else if (strcmp(action, "SHOW_MENU") == 0) actionid = ACTION_SHOW_MENU; else if (strcmp(action, "SYSOP_MENU") == 0) actionid = ACTION_SYSOP_MENU; else if (strcmp(action, "WHOS_ONLINE") == 0) actionid = ACTION_WHOS_ONLINE; else { logger_printf("[views] Error parsing main_menu.txt on line " "%ld: invalid action \"%s\"", linenum, action); ret_count = 0; break; } menu_key[0] = '\0'; for (m = 0; m < linelen; m++) { if (line[m] == ':') { memcpy(menu_key, line, m); menu_key[m] = '\0'; linelen -= m + 1; memmove(line, line + m + 1, linelen + 1); break; } } /* menu_key can be 1 or 0 characters */ if (strlen(menu_key) > 1) { logger_printf("[views] Error parsing main_menu.txt on line " "%ld: Menu Key can only be 1 character", linenum); ret_count = 0; break; } all_keys[0] = '\0'; for (m = 0; m < linelen; m++) { if (line[m] == ':') { memcpy(all_keys, line, m); all_keys[m] = '\0'; linelen -= m + 1; memmove(line, line + m + 1, linelen + 1); break; } } if (all_keys[0] == '\0') { logger_printf("[views] Error parsing main_menu.txt on line " "%ld: All Keys field cannot be empty", linenum); ret_count = 0; break; } if (line[0] == '\0') { logger_printf("[views] Error parsing main_menu.txt on line " "%ld: Label cannot be empty", linenum); ret_count = 0; break; } strlcpy(label, line, LINESIZE); if (!grow_to_fit(&ret, &ret_size, sizeof(struct main_menu_option) * ret_count, sizeof(struct main_menu_option), 4)) { ret_count = 0; break; } ret[ret_count].action = actionid; ret[ret_count].menu_key = menu_key[0]; strlcpy(ret[ret_count].all_keys, all_keys, sizeof(ret[ret_count].all_keys)); strlcpy(ret[ret_count].label, label, sizeof(ret[ret_count].label)); ret_count++; } parse_done: if (line) xfree(&line); if (action) xfree(&action); if (menu_key) xfree(&menu_key); if (all_keys) xfree(&all_keys); if (label) xfree(&label); if (ret_count == 0) { if (ret) xfree(&ret); return NULL; } if (!grow_to_fit(&ret, &ret_size, sizeof(struct main_menu_option) * ret_count, sizeof(struct main_menu_option), 1)) { if (ret) xfree(&ret); return NULL; } ret[ret_count].action = ACTION_NONE; ret[ret_count].menu_key = 0; ret[ret_count].all_keys[0] = '\0'; ret[ret_count].label[0] = '\0'; return ret; #undef LINESIZE }