jcs
/subtext
/amendments
/281
*: Add dynamically configured main menu
The list of action->key pairs can be edited from the console menu,
and doubles as a list of each key->label that we can print for the
default main menu shown to the user when no custom menu is defined.
jcs made amendment 281 over 2 years ago
--- db.h Sat Oct 1 20:14:31 2022
+++ db.h Wed Nov 9 09:56:01 2022
@@ -44,6 +44,7 @@
#define DB_TEXT_PAGE_SYSOP_ID 5
#define DB_TEXT_NO_FREE_NODES_ID 6
#define DB_TEXT_SIGNOFF_ID 7
+#define DB_TEXT_MENU_OPTIONS_ID 8
#define DB_USERNAME_LENGTH 16
--- main.c Sat Oct 1 21:08:28 2022
+++ main.c Wed Nov 9 09:58:42 2022
@@ -22,6 +22,7 @@
#include "db.h"
#include "focusable.h"
#include "logger.h"
+#include "main_menu.h"
#include "serial_local.h"
#include "session.h"
#include "settings.h"
@@ -99,6 +100,8 @@ main(void)
logger_init();
logger_update_title();
+
+ main_menu_init();
zone_size = (unsigned long)CurStackBase - (unsigned long)ApplZone;
stack_size = (unsigned long)CurStackBase - (unsigned long)ApplLimit;
@@ -106,7 +109,7 @@ main(void)
logger_printf("Initialized with %ldKB zone, %ldKB stack for "
"%d threads, %ldKB heap", zone_size / 1024L, stack_size / 1024L,
NUM_UTHREADS, heap_size / 1024L);
-
+
logger_printf("[db] Updating username cache");
user_cache_usernames();
@@ -332,6 +335,9 @@ handle_menu(long menu_id)
switch (LoWord(menu_id)) {
case BBS_MENU_OPEN_CONSOLE_ID:
console_init();
+ break;
+ case BBS_MENU_EDIT_MENUS_ID:
+ main_menu_edit();
break;
}
ret = 1;
--- main_menu.c Fri Nov 11 21:54:35 2022
+++ main_menu.c Fri Nov 11 23:02:08 2022
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2022 joshua stein <jcs@jcs.org>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include "subtext.h"
+#include "db.h"
+#include "main_menu.h"
+
+struct main_menu_option *main_menu_options = NULL;
+
+void
+main_menu_init(void)
+{
+ struct main_menu_option *opts = NULL, *old_opts = NULL;
+ size_t size;
+ char *menu = NULL;
+ bool ok = false;
+ Handle default_menu;
+
+ size = bile_read_alloc(db->bile, DB_TEXT_TYPE, DB_TEXT_MENU_OPTIONS_ID,
+ &menu);
+ if (size == 0 || menu == NULL) {
+ /* use default menu */
+ if (menu != NULL)
+ xfree(&menu);
+ default_menu = GetResource('TEXT', MENU_DEFAULTS_ID);
+ if (default_menu == NULL)
+ panic("Failed to find TEXT resource %d", MENU_DEFAULTS_ID);
+ size = GetHandleSize(default_menu);
+ menu = xmalloc(size, "menu copy");
+ HLock(default_menu);
+ memcpy(menu, *default_menu, size);
+ HUnlock(default_menu);
+ ReleaseResource(default_menu);
+
+ bile_write(db->bile, DB_TEXT_TYPE, DB_TEXT_MENU_OPTIONS_ID,
+ menu, size);
+ }
+
+ opts = main_menu_parse(menu, size);
+ free(&menu);
+ if (opts == NULL) {
+ main_menu_edit();
+ return;
+ }
+
+ /* swap this atomically */
+ old_opts = main_menu_options;
+ main_menu_options = opts;
+ if (old_opts != NULL)
+ xfree(&old_opts);
+}
+
+void
+main_menu_edit(void)
+{
+ view_editor_show(DB_TEXT_MENU_OPTIONS_ID, "Edit: Main Menu options");
+}
+
+struct main_menu_option *
+main_menu_parse(char *opts, size_t len)
+{
+ char *line, *action, *menu_key, *all_keys, *label;
+ size_t n, m, linelen, lastsep, linenum, ret_size;
+ short count, actionid, ret_count;
+ struct main_menu_option *ret = NULL;
+
+#define LINESIZE 1024
+ line = xmalloc(LINESIZE, "parse_menu line");
+ action = xmalloc(LINESIZE, "parse_menu action");
+ menu_key = xmalloc(LINESIZE, "parse_menu menu_key");
+ all_keys = xmalloc(LINESIZE, "parse_menu all_keys");
+ label = xmalloc(LINESIZE, "parse_menu label");
+
+ ret_count = 0;
+ ret_size = 0;
+
+ 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') {
+ warn("Error on line %ld: no action found", linenum);
+ ret_count = 0;
+ break;
+ }
+
+ actionid = ACTION_NONE;
+ 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 {
+ warn("Error 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) {
+ warn("Error 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') {
+ warn("Error on line %ld: All Keys field cannot be empty",
+ linenum);
+ ret_count = 0;
+ break;
+ }
+
+ if (line[0] == '\0') {
+ warn("Error on line %ld: Label cannot be empty",
+ linenum);
+ ret_count = 0;
+ break;
+ }
+ strlcpy(label, line, LINESIZE);
+
+ EXPAND_TO_FIT(ret, ret_size,
+ sizeof(struct main_menu_option) * ret_count,
+ sizeof(struct main_menu_option), 4);
+
+ 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++;
+ }
+
+ xfree(&line);
+ xfree(&action);
+ xfree(&menu_key);
+ xfree(&all_keys);
+ xfree(&label);
+
+ if (ret_count == 0) {
+ xfree(&ret);
+ return NULL;
+ }
+
+ EXPAND_TO_FIT(ret, ret_size,
+ sizeof(struct main_menu_option) * ret_count,
+ sizeof(struct main_menu_option), 1);
+
+ 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
+}
--- main_menu.h Fri Nov 11 21:53:39 2022
+++ main_menu.h Fri Nov 11 21:53:39 2022
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022 joshua stein <jcs@jcs.org>
+ *
+ * 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.
+ */
+
+#ifndef __MAIN_MENU_H__
+#define __MAIN_MENU_H__
+
+enum main_menu_action {
+ ACTION_NONE = -1,
+ ACTION_BOARD_SHOW_FIRST,
+ ACTION_BOARD_SHOW_1,
+ ACTION_BOARD_SHOW_2,
+ ACTION_BOARD_SHOW_3,
+ ACTION_BOARD_SHOW_4,
+ ACTION_BOARD_SHOW_5,
+ ACTION_BOARD_SHOW_6,
+ ACTION_BOARD_SHOW_7,
+ ACTION_BOARD_SHOW_8,
+ ACTION_BOARD_SHOW_9,
+ ACTION_BOARD_SHOW_10,
+ ACTION_CHAT,
+ ACTION_FILES_MENU,
+ ACTION_GOODBYE,
+ ACTION_MAIL_COMPOSE,
+ ACTION_MAIL_MENU,
+ ACTION_MOTD,
+ ACTION_PAGE_ANSWER,
+ ACTION_PAGE_SEND,
+ ACTION_PAGE_SEND_OR_ANSWER,
+ ACTION_RECENT_LOGINS,
+ ACTION_SETTINGS_OR_SIGNUP,
+ ACTION_SETTINGS,
+ ACTION_SIGNUP,
+ ACTION_SHOW_MENU,
+ ACTION_SYSOP_MENU,
+ ACTION_WHOS_ONLINE
+};
+
+struct main_menu_option {
+ short action;
+ char menu_key;
+ char all_keys[20];
+ char label[200];
+};
+
+extern struct main_menu_option *main_menu_options;
+
+void main_menu_init(void);
+void main_menu_edit(void);
+struct main_menu_option * main_menu_parse(char *opts, size_t len);
+
+#endif
--- session.c Tue Oct 4 22:52:44 2022
+++ session.c Fri Nov 11 22:15:32 2022
@@ -25,6 +25,7 @@
#include "folder.h"
#include "logger.h"
#include "mail.h"
+#include "main_menu.h"
#include "subtext.h"
#include "session.h"
#include "settings.h"
@@ -46,6 +47,7 @@ static const char invalid_option_help[] =
"Invalid option (press {{B}}?{{/B}} for help)\r\n";
void session_run(struct uthread *uthread, void *arg);
+void session_print_menu(struct session *session, bool short_menu);
short session_login(struct session *s);
size_t session_log(struct session *session, const char *str);
size_t session_vprintf(struct session *session, const char *format,
@@ -107,12 +109,15 @@ session_run(struct uthread *uthread, void *arg)
struct tm *date_tm;
unsigned short c, last_c = 0;
bool done = false;
- short auth;
+ short auth, i, action;
/* until we negotiate otherwise */
s->terminal_columns = DEFAULT_TERMINAL_COLUMNS;
s->terminal_lines = DEFAULT_TERMINAL_LINES;
-
+
+ if (main_menu_options == NULL)
+ panic("No main menu!");
+
if (s->node_funcs->setup) {
s->node_funcs->setup(s);
@@ -183,9 +188,9 @@ session_run(struct uthread *uthread, void *arg)
session_print_motd(s, false);
-main_menu:
- session_output_view_or_printf(s, DB_TEXT_MENU_ID,
- "\r\n[ Menu missing! ]\r\n\r\n");
+main_menu:
+ session_output(s, "\r\n", 2);
+ session_print_menu(s, false);
session_flush(s);
while (!done && !s->ending) {
@@ -193,8 +198,10 @@ main_menu:
session_flush(s);
get_another_char:
+ action = ACTION_NONE;
+
if (auth == AUTH_USER_SIGNUP) {
- c = 's';
+ action = ACTION_SIGNUP;
auth = AUTH_USER_GUEST;
} else
c = session_input_char(s);
@@ -206,84 +213,128 @@ get_another_char:
session_printf(s, "%c\r\n", c);
session_flush(s);
+
+ if (action == ACTION_NONE) {
+ /* check each menu option's all_keys array for matching key */
+ for (i = 0; ; i++) {
+ struct main_menu_option *option = &main_menu_options[i];
+ short j;
+
+ if (option->action == ACTION_NONE)
+ break;
+
+ if (option->menu_key == 0 || option->label == NULL)
+ continue;
+
+ for (j = 0; option->all_keys[j] != '\0'; j++) {
+ if (option->all_keys[j] == c) {
+ action = option->action;
+ break;
+ }
+ }
+
+ if (action != ACTION_NONE)
+ break;
+ }
+ }
- /* TODO: make letter->command dynamic from a resource */
- switch (c) {
- case 'b':
- case 'B':
- /* first (or only) board */
+ /* change actions for conditionals */
+ if (action == ACTION_SETTINGS_OR_SIGNUP) {
+ if (s->user)
+ action = ACTION_SETTINGS;
+ else
+ action = ACTION_SIGNUP;
+ } else if (action == ACTION_PAGE_SEND_OR_ANSWER) {
+ if (s->user && s->user->is_sysop)
+ action = ACTION_PAGE_ANSWER;
+ else
+ action = ACTION_PAGE_SEND;
+ }
+
+ switch (action) {
+ case ACTION_BOARD_SHOW_FIRST:
board_show(s, 1);
break;
- case 'c':
- case 'C':
- /* chat */
+ case ACTION_CHAT:
chat_start(s, NULL);
break;
- case 'f':
- case 'F':
- /* files */
+ case ACTION_FILES_MENU:
folder_list(s);
break;
- case 'g':
- case 'G':
- /* goodbye */
+ case ACTION_GOODBYE:
session_output_view_or_printf(s, DB_TEXT_SIGNOFF_ID,
"Goodbye!\r\n");
session_flush(s);
done = true;
break;
- case 'l':
- case 'L':
+ case ACTION_RECENT_LOGINS:
session_recents(s);
break;
- case 'm':
- case 'M':
+ case ACTION_MAIL_MENU:
mail_menu(s);
break;
- case 'n':
- case 'N':
- /* send mail */
+ case ACTION_MAIL_COMPOSE:
mail_compose(s, NULL, NULL, NULL);
break;
- case 'o':
- case 'O':
+ case ACTION_MOTD:
session_print_motd(s, true);
break;
- case 'p':
- case 'P':
- if (s->user && s->user->is_sysop)
- session_answer_page(s);
- else
- session_page_sysop(s);
+ case ACTION_PAGE_ANSWER:
+ if (!s->user || !s->user->is_sysop) {
+ session_printf(s, invalid_option_help);
+ session_flush(s);
+ break;
+ }
+ session_answer_page(s);
break;
- case 's':
- case 'S':
+ case ACTION_PAGE_SEND:
+ session_page_sysop(s);
+ break;
+ case ACTION_SETTINGS:
if (s->user)
user_settings_menu(s);
- else if ((s->user = signup(s))) {
+ break;
+ case ACTION_SIGNUP:
+ if ((s->user = signup(s))) {
session_printf(s, "\r\n"
"Welcome, {{B}}%s{{/B}}!\r\n", s->user->username);
goto main_menu;
}
break;
- case 'w':
- case 'W':
- /* who's online */
+ case ACTION_WHOS_ONLINE:
session_who(s);
break;
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '0':
- board_show(s, c - '0');
+ case ACTION_BOARD_SHOW_1:
+ board_show(s, 1);
break;
- case '!':
+ case ACTION_BOARD_SHOW_2:
+ board_show(s, 2);
+ break;
+ case ACTION_BOARD_SHOW_3:
+ board_show(s, 3);
+ break;
+ case ACTION_BOARD_SHOW_4:
+ board_show(s, 4);
+ break;
+ case ACTION_BOARD_SHOW_5:
+ board_show(s, 5);
+ break;
+ case ACTION_BOARD_SHOW_6:
+ board_show(s, 6);
+ break;
+ case ACTION_BOARD_SHOW_7:
+ board_show(s, 7);
+ break;
+ case ACTION_BOARD_SHOW_8:
+ board_show(s, 8);
+ break;
+ case ACTION_BOARD_SHOW_9:
+ board_show(s, 9);
+ break;
+ case ACTION_BOARD_SHOW_10:
+ board_show(s, 10);
+ break;
+ case ACTION_SYSOP_MENU:
if (!s->user || !s->user->is_sysop) {
session_printf(s, invalid_option_help);
session_flush(s);
@@ -291,17 +342,12 @@ get_another_char:
}
sysop_menu(s);
break;
- case '?':
- if (last_c == '?') {
+ case ACTION_SHOW_MENU:
+ if (last_c == c)
/* asking twice in a row will print the full menu */
- session_output_view_or_printf(s, DB_TEXT_MENU_ID,
- "\r\n[ Menu missing! ]\r\n\r\n");
- } else {
- if (session_output_view_or_printf(s, DB_TEXT_SHORTMENU_ID,
- NULL) == 0)
- session_output_view_or_printf(s, DB_TEXT_MENU_ID,
- "\r\n[ Short and long menu missing! ]\r\n\r\n");
- }
+ session_print_menu(s, false);
+ else
+ session_print_menu(s, true);
session_flush(s);
break;
default:
@@ -314,6 +360,40 @@ get_another_char:
}
session_close(s);
+}
+
+void
+session_print_menu(struct session *session, bool short_menu)
+{
+ struct main_menu_option *option = NULL;
+ size_t size;
+ short i, j;
+ char *output = NULL;
+
+ if (short_menu && session_output_view_or_printf(session,
+ DB_TEXT_SHORTMENU_ID, NULL) != 0)
+ return;
+
+ if (session_output_view_or_printf(session, DB_TEXT_MENU_ID, NULL) != 0)
+ return;
+
+ for (i = 0; ; i++) {
+ option = &main_menu_options[i];
+
+ if (option->action == ACTION_NONE)
+ break;
+
+ if (option->menu_key == 0 || option->label == NULL)
+ continue;
+
+ size = session_expand_template(session, option->label, &output);
+ if (!size)
+ continue;
+
+ session_printf(session, "{{B}}%c{{/B}}: %s\r\n", option->menu_key,
+ output);
+ xfree(&output);
+ }
}
void
--- settings.c Thu Sep 8 22:14:05 2022
+++ settings.c Fri Nov 11 23:02:55 2022
@@ -20,6 +20,7 @@
#include "subtext.h"
#include "db.h"
#include "focusable.h"
+#include "main_menu.h"
#include "settings.h"
#include "tcp.h" /* for long2ip/ip2long */
#include "tetab.h"
@@ -42,12 +43,12 @@ void view_editor_close(struct focusable *focusable, Ev
void view_editor_save(struct focusable *focusable, EventRecord *event);
short
-struct_editor(struct session *s, struct struct_field *fields,
- size_t nfields, void *data, size_t dsize, void **result, char *title,
- char *prompt)
+struct_editor(struct session *s, const struct struct_field *fields,
+ const size_t nfields, void *data, size_t dsize, void **result,
+ char *title, char *prompt)
{
Handle ihandle;
- struct struct_field *sf;
+ const struct struct_field *sf;
long lval;
char co, initial[20];
char *input = NULL, *new_data;
@@ -522,12 +523,24 @@ view_editor_save(struct focusable *focusable, EventRec
HLock((*(view_editor->te))->hText);
len = (*(view_editor->te))->teLength;
+
+ if (view_editor->view_id == DB_TEXT_MENU_OPTIONS_ID) {
+ if (!main_menu_parse(*(*(view_editor->te))->hText, len)) {
+ HUnlock((*(view_editor->te))->hText);
+ HUnlock(view_editor->te);
+ return;
+ }
+ }
+
bile_write(db->bile, DB_TEXT_TYPE, view_editor->view_id,
*(*(view_editor->te))->hText, len);
HUnlock((*(view_editor->te))->hText);
HUnlock(view_editor->te);
+ if (view_editor->view_id == DB_TEXT_MENU_OPTIONS_ID)
+ main_menu_init();
+
view_editor_close(focusable, event);
}
--- settings.h Wed Jun 22 15:25:39 2022
+++ settings.h Tue Nov 8 14:34:51 2022
@@ -35,9 +35,9 @@ struct struct_field {
unsigned short max;
};
-short struct_editor(struct session *s, struct struct_field *fields,
- size_t nfields, void *data, size_t dsize, void **result, char *title,
- char *prompt);
+short struct_editor(struct session *s, const struct struct_field *fields,
+ const size_t nfields, void *data, size_t dsize, void **result,
+ char *title, char *prompt);
void view_editor_show(size_t id, char *title);
#endif
--- subtext.h Sat Oct 1 21:29:19 2022
+++ subtext.h Wed Nov 9 22:04:37 2022
@@ -36,7 +36,8 @@
#define BBS_MENU_ID 130
#define BBS_MENU_VIEWS_ID 1
-#define BBS_MENU_OPEN_CONSOLE_ID 3
+#define BBS_MENU_EDIT_MENUS_ID 2
+#define BBS_MENU_OPEN_CONSOLE_ID 4
#define VIEWS_SUBMENU_ID 132
#define VIEWS_SUBMENU_ISSUE_ID 1
@@ -46,6 +47,8 @@
#define VIEWS_SUBMENU_PAGE_SYSOP_ID 5
#define VIEWS_SUBMENU_NO_FREE_NODES_ID 6
#define VIEWS_SUBMENU_SIGNOFF_ID 7
+
+#define MENU_DEFAULTS_ID 128
#define STR_LAST_DB 128