AmendHub

jcs

/

subtext

/

amendments

/

100

session: Add session_menu, use it everywhere

Start on sysop board management

jcs made amendment 100 8 months ago
--- db.c Thu May 12 15:29:53 2022 +++ db.c Sun May 15 21:48:28 2022 @@ -48,13 +48,36 @@ struct struct_field config_fields[] = { 1, member_size(struct config, modem_init) }, { "Max Idle Minutes", CONFIG_TYPE_SHORT, offsetof(struct config, max_idle_minutes), - 1, 65535 }, + 1, USHRT_MAX }, }; size_t nconfig_fields = nitems(config_fields); +struct struct_field board_fields[] = { + { "Board ID", CONFIG_TYPE_LONG, + offsetof(struct board, id), + 1, ULONG_MAX }, + { "Name", CONFIG_TYPE_STRING, + offsetof(struct board, name), + 1, member_size(struct board, name) }, + { "Description", CONFIG_TYPE_STRING, + offsetof(struct board, description), + 0, member_size(struct board, description) }, + { "Restricted Posting", CONFIG_TYPE_BOOLEAN, + offsetof(struct board, restricted_posting), + 0, 0 }, + { "Restricted Viewing", CONFIG_TYPE_BOOLEAN, + offsetof(struct board, restricted_viewing), + 0, 0 }, + { "Days of Retention", CONFIG_TYPE_SHORT, + offsetof(struct board, retention_days), + 0, USHRT_MAX }, +}; +size_t nboard_fields = nitems(board_fields); + struct db * db_init(Str255 file, short vrefnum, struct bile *bile); short db_migrate(struct db *tdb, short is_new); void db_config_load(struct db *tdb); +void db_boards_load(struct db *tdb); struct db * db_open(Str255 file, short vrefnum) @@ -172,8 +195,10 @@ db_init(Str255 path, short vrefnum, struct bile *bile) return NULL; } - if (!was_new) + if (!was_new) { db_config_load(tdb); + db_boards_load(tdb); + } PtoCstr(fullpath); strlcat((char *)&fullpath, "-sessions", sizeof(fullpath)); @@ -279,4 +304,60 @@ db_config_load(struct db *tdb) memcpy(&tdb->config, newconfig, sizeof(tdb->config)); free(newconfig); +} + +void +db_boards_load(struct db *tdb) +{ + size_t n; + struct bile_object *obj; + + if (tdb->boards) { + free(tdb->boards); + tdb->boards = NULL; + } + + tdb->nboards = bile_count_by_type(tdb->bile, DB_BOARD_RTYPE); + if (!tdb->nboards) + return; + + tdb->boards = xmallocarray(tdb->nboards, sizeof(struct board)); + + for (n = 0; n < tdb->nboards; n++) { + obj = bile_get_nth_of_type(tdb->bile, n, DB_BOARD_RTYPE); + if (obj == NULL) + break; + + bile_read(tdb->bile, DB_BOARD_RTYPE, obj->id, + (char *)(&tdb->boards[n]), obj->size); + } +} + +void +db_board_create(struct db *tdb, struct board *board) +{ + Str255 db_filename, board_filename; + struct bile *board_bile; + + if (bile_write(tdb->bile, DB_BOARD_RTYPE, board->id, + board, sizeof(struct board)) != sizeof(struct board)) + panic("save of new board failed: %d", bile_error(tdb->bile)); + + if (getpath(tdb->bile->vrefnum, tdb->bile->filename, &db_filename, + false) != 0) + panic("getpath failed on %s", PtoCstr(tdb->bile->filename)); + + PtoCstr(db_filename); + + snprintf((char *)board_filename, sizeof(board_filename), "%s:%ld.brd", + db_filename, board->id); + CtoPstr(board_filename); + + board_bile = bile_create(board_filename, tdb->bile->vrefnum, + SUBTEXT_CREATOR, DB_BOARD_RTYPE); + if (board_bile == NULL) + panic("failed creating new board bile at %s: %d", + PtoCstr(board_filename), bile_error(tdb->bile)); + + db_boards_load(tdb); } --- db.h Thu May 12 15:30:48 2022 +++ db.h Sun May 15 14:54:06 2022 @@ -84,13 +84,16 @@ struct board { unsigned long id; char name[DB_BOARD_NAME_LENGTH]; char description[DB_BOARD_DESCR_LENGTH]; - short restricted_posting; - short restricted_viewing; - short retention_days; + bool restricted_posting; + bool restricted_viewing; + unsigned short retention_days; unsigned long last_post_at; unsigned long post_count; }; +extern struct struct_field board_fields[]; +extern size_t nboard_fields; + struct user_map { unsigned long id; char username_key[DB_USERNAME_LENGTH + 1]; @@ -103,11 +106,14 @@ struct db { struct user_map *user_map; short nusers; struct bile *sessions_bile; + struct board *boards; + short nboards; }; struct db * db_open(Str255 file, short vrefnum); struct db * db_create(void); void db_close(struct db *tdb); void db_config_save(struct db *tdb); +void db_board_create(struct db *tdb, struct board *board); #endif --- mail.c Mon May 9 15:48:26 2022 +++ mail.c Sat May 14 22:52:48 2022 @@ -52,7 +52,6 @@ struct bile_object_field mail_object_fields[] = { void mail_free_message_strings(struct private_message *msg); short mail_save(struct session *s, struct private_message *msg); -void mail_help(struct session *s); void mail_read(struct session *s, unsigned long idx); void mail_delete(struct session *s, unsigned long idx); void mail_mark_unread(struct session *s, unsigned long idx); @@ -90,12 +89,12 @@ get_id: session_printf(s, "{{B}}%s:{{/B}} ", prompt); tmp = session_field_input(s, 5, 5, start_s, 0); + session_output(s, "\r\n", 2); + session_flush(s); if (tmp == NULL || s->ending) { ret = -1; goto get_id_done; } - session_output(s, "\r\n", 2); - session_flush(s); if (sscanf(tmp, "%d", &ret) != 1 || ret < 1 || ret > nmsgs) { session_printf(s, "{{B}}Invalid message ID{{/B}} (^C to cancel)\r\n"); @@ -113,13 +112,20 @@ get_id_done: void mail_menu(struct session *s) { - char l[2], arg[32]; - size_t count, nmsgs, id; - bool done = false; - char *field; + static struct session_menu_option opts[] = { + { 'l', "Ll", "List mail messages" }, + { '#', "#0123456789", "Read mail message [#]" }, + { 'd', "Dd", "Delete mail message [#]" }, + { 'u', "Uu", "Mark mail message [#] unread" }, + { 'c', "Cc", "Compose new mail message" }, + { 'q', "QqXx", "Return to main menu" }, + { '?', "?", "List menu options" }, + }; + size_t nmsgs, id; unsigned long *mail_ids = NULL; - unsigned short c; - short ret; + char c; + bool show_help = false; + bool done = false; if (!s->user) { session_output_string(s, "Mail is not available to guests.\r\n" @@ -127,56 +133,30 @@ mail_menu(struct session *s) session_flush(s); return; } - - session_output_template(s, "{{B}}Private Mail{{/B}} " - "('{{B}}?{{/B}}' for help)\r\n" - "{{B}}--------------------{{/B}}\r\n"); - session_flush(s); - mail_list(s, false, &mail_ids, &nmsgs); + session_printf(s, "{{B}}Private Mail{{/B}}\r\n"); + session_flush(s); - while (!done) { - session_output_template(s, "{{B}}Mail>{{/B}} "); - session_flush(s); + mail_list(s, false, &mail_ids, &nmsgs); -get_menu_option: - c = session_input_char(s); - if (s->ending) - return; - if (c == '\r' || c == 0 || c > 255) - goto get_menu_option; - - session_printf(s, "%c\r\n", c); - session_flush(s); - + while (!done) { + c = session_menu(s, "Private Mail", "Mail", opts, nitems(opts), + show_help); + show_help = false; + switch (c) { case 'c': - case 'C': - mail_compose(s, arg, NULL, NULL); + mail_compose(s, NULL, NULL, NULL); break; case 'd': - case 'D': id = mail_get_message_id(s, nmsgs, "Message # to delete", -1); if (id != -1) mail_delete(s, id); break; - case 'h': - case 'H': - case '?': - mail_help(s); - break; case 'l': - case 'L': mail_list(s, false, &mail_ids, &nmsgs); break; - case 'q': - case 'Q': - case 'x': - case 'X': - done = true; - break; case 'u': - case 'U': id = mail_get_message_id(s, nmsgs, "Message # to mark unread", -1); if (id != -1) @@ -197,25 +177,16 @@ get_menu_option: if (id != -1) mail_read(s, mail_ids[id - 1]); break; + case '?': + show_help = true; + break; + case '#': + break; default: - session_output_template(s, - "Invalid option ({{B}}?{{/B}} for help)\r\n"); - session_flush(s); + done = true; + break; } } -} - -void -mail_help(struct session *s) -{ - session_output_template(s, - "{{B}}L{{/B}}: List mail messages\r\n" - "{{B}}#{{/B}}: Read mail message [#]\r\n" - "{{B}}D #{{/B}}: Delete mail message [#]\r\n" - "{{B}}U #{{/B}}: Mark mail message [#] unread\r\n" - "{{B}}C{{/B}}: Compose new mail message\r\n" - "{{B}}Q{{/B}}: Return to main menu\r\n"); - session_flush(s); } void --- session.c Thu May 12 17:40:55 2022 +++ session.c Sat May 14 20:06:07 2022 @@ -27,6 +27,7 @@ #include "session.h" #include "settings.h" #include "signup.h" +#include "sysop.h" #include "user.h" #include "user_settings.h" #include "uthread.h" @@ -216,7 +217,7 @@ get_another_char: session_flush(s); break; } - sysop_edit_settings(s); + sysop_menu(s); break; case '?': /* short menu */ @@ -1260,25 +1261,60 @@ session_who(struct session *s) session_pause_return(s, 0, NULL); } -void -sysop_edit_settings(struct session *s) +char +session_menu(struct session *s, char *title, char *prompt, + struct session_menu_option *opts, size_t nopts, bool show_opts) { - struct config *new_config; - short ret; + struct session_menu_option *opt; + size_t n; + short j; + unsigned short c; + + if (show_opts) { + session_printf(s, "{{B}}%s{{/B}}\r\n", title); + session_flush(s); + } - if (!s->user || !s->user->is_sysop) - return; - - ret = struct_editor(s, config_fields, nconfig_fields, &db->config, - sizeof(struct config), (void *)&new_config, "BBS Settings"); - if (ret != 0) { - session_printf(s, "No changes made\r\n"); - return; +print_options: + if (show_opts) { + for (n = 0; n < nopts; n++) { + opt = &opts[n]; + + session_printf(s, "{{B}}%c{{/B}}: %s\r\n", opt->key[0], + opt->title); + session_flush(s); + } } - memcpy(&db->config, new_config, sizeof(db->config)); - db_config_save(db); + for (;;) { + session_printf(s, "{{B}}%s>{{/B}} ", prompt); + session_flush(s); - session_printf(s, "Successfully saved changes to BBS Settings\r\n"); - free(new_config); +get_menu_option: + c = session_input_char(s); + if (s->ending) + return 0; + if (c == '\r' || c == 0 || c > 255) + goto get_menu_option; + + session_printf(s, "%c\r\n", c); + session_flush(s); + + for (n = 0; n < nopts; n++) { + opt = &opts[n]; + + for (j = 0; ; j++) { + if (opt->key[j] == '\0') + break; + if (opt->key[j] == c) { + if (opt->ret == '#') + return c; /* return actual number */ + return opt->ret; + } + } + } + + session_output_string(s, "Invalid option\r\n"); + session_flush(s); + } } --- session.h Thu Apr 28 14:02:58 2022 +++ session.h Sat May 14 20:18:01 2022 @@ -97,6 +97,12 @@ struct session { extern struct session **sessions; extern short nsessions; +struct session_menu_option { + char ret; + char key[15]; + char title[100]; +}; + struct session * session_create(char *node, char *via, struct node_funcs *node_funcs); void session_close(struct session *session); @@ -122,5 +128,7 @@ char * session_bar(struct session *s, char *left_str, void session_pause_return(struct session *s, short enforce, char *msg); void session_recents(struct session *s); void session_who(struct session *s); +char session_menu(struct session *s, char *title, char *prompt, + struct session_menu_option *opts, size_t nopts, bool show_opts); #endif /* __SESSION_H__ */ --- settings.c Thu May 12 16:56:04 2022 +++ settings.c Sun May 15 15:54:54 2022 @@ -42,7 +42,8 @@ void view_editor_save(struct focusable *focusable, Eve short struct_editor(struct session *s, struct struct_field *fields, - size_t nfields, void *data, size_t dsize, void **result, char *title) + size_t nfields, void *data, size_t dsize, void **result, char *title, + char *prompt) { Handle ihandle; struct struct_field *sf; @@ -79,6 +80,17 @@ print_options: sval = (new_data[sf->off] << 8) | new_data[sf->off + 1]; session_printf(s, "%d", sval); break; + case CONFIG_TYPE_LONG: + lval = (new_data[sf->off] << 24) | + (new_data[sf->off + 1] << 16) | + (new_data[sf->off + 2] << 8) | + new_data[sf->off + 3]; + session_printf(s, "%ld", lval); + break; + case CONFIG_TYPE_BOOLEAN: + session_printf(s, "%s", + new_data[sf->off] == 0 ? "false" : "true"); + break; } session_output_string(s, "]\r\n"); @@ -89,7 +101,7 @@ print_options: session_printf(s, "{{B}}?{{/B}}: Print menu of options\r\n"); for (;;) { - session_output_template(s, "{{B}}Editor>{{/B}} "); + session_printf(s, "{{B}}%s>{{/B}} ", prompt); session_flush(s); get_menu_option: @@ -160,8 +172,17 @@ get_input: any_changes = true; break; case CONFIG_TYPE_SHORT: - sval = (new_data[sf->off] << 8) | new_data[sf->off + 1]; - snprintf(initial, sizeof(initial), "%d", sval); + case CONFIG_TYPE_LONG: + if (sf->type == CONFIG_TYPE_LONG) { + lval = (new_data[sf->off] << 24) | + (new_data[sf->off + 1] << 16) | + (new_data[sf->off + 2] << 8) | + new_data[sf->off + 3]; + snprintf(initial, sizeof(initial), "%ld", lval); + } else { + sval = (new_data[sf->off] << 8) | new_data[sf->off + 1]; + snprintf(initial, sizeof(initial), "%d", sval); + } input = session_field_input(s, 10, 10, initial, 0); session_output(s, "\r\n", 2); session_flush(s); @@ -183,10 +204,46 @@ get_input: free(input); goto get_input; } - sval = lval; - new_data[sf->off] = (sval >> 8) & 0xff; - new_data[sf->off + 1] = sval & 0xff; + if (sf->type == CONFIG_TYPE_LONG) { + new_data[sf->off] = (lval >> 24) & 0xff; + new_data[sf->off + 1] = (lval >> 16) & 0xff; + new_data[sf->off + 2] = (lval >> 8) & 0xff; + new_data[sf->off + 3] = lval & 0xff; + } else { + sval = lval; + new_data[sf->off] = (sval >> 8) & 0xff; + new_data[sf->off + 1] = sval & 0xff; + } any_changes = true; + break; + case CONFIG_TYPE_BOOLEAN: + if (new_data[sf->off]) + session_output_string(s, "[Y/n] "); + else + session_output_string(s, "[y/N] "); + session_flush(s); + + for (;;) { + c = session_input_char(s); + if (s->ending) + break; + if (c == '\r' && new_data[sf->off]) + c = 'y'; + else if (c == '\r' && new_data[sf->off] == 0) + c = 'n'; + if (c == 'y' || c == 'Y') { + new_data[sf->off] = 1; + any_changes = true; + session_printf(s, "%c\r\n", c); + break; + } + if (c == 'n' || c == 'N') { + new_data[sf->off] = 0; + any_changes = true; + session_printf(s, "%c\r\n", c); + break; + } + } break; } --- settings.h Tue May 10 15:45:23 2022 +++ settings.h Sun May 15 15:58:58 2022 @@ -21,7 +21,9 @@ enum { CONFIG_TYPE_STRING, - CONFIG_TYPE_SHORT + CONFIG_TYPE_SHORT, + CONFIG_TYPE_LONG, + CONFIG_TYPE_BOOLEAN }; struct struct_field { @@ -33,7 +35,8 @@ struct struct_field { }; short struct_editor(struct session *s, struct struct_field *fields, - size_t nfields, void *data, size_t dsize, void **result, char *title); + size_t nfields, void *data, size_t dsize, void **result, char *title, + char *prompt); void view_editor_show(size_t id, char *title); #endif --- sysop.c Sun May 15 21:42:53 2022 +++ sysop.c Sun May 15 21:42:53 2022 @@ -0,0 +1,199 @@ +/* + * 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 "subtext.h" +#include "session.h" +#include "sysop.h" + +#include <string.h> + +void sysop_edit_boards(struct session *s); + +void +sysop_menu(struct session *s) +{ + static struct session_menu_option opts[] = { + { 'b', "Bb", "Manage Boards" }, + { 'u', "Uu", "Manage Users" }, + { 's', "Ss", "Change BBS Settings" }, + { 'q', "QqXx", "Return to main menu" }, + { '?', "?", "List menu options" }, + }; + char c; + bool show_help = true; + bool done = false; + + if (!s->user || !s->user->is_sysop) + return; + + session_log(s, "Entered sysop menu"); + + while (!done) { + c = session_menu(s, "Sysop Menu", "Sysop", opts, nitems(opts), + show_help); + show_help = false; + + switch (c) { + case 'b': + sysop_edit_boards(s); + break; + case 's': + sysop_edit_settings(s); + break; + case 'u': + break; + case '?': + show_help = true; + break; + default: + done = true; + break; + } + } +} + +void +sysop_edit_settings(struct session *s) +{ + struct config *new_config; + short ret; + + if (!s->user || !s->user->is_sysop) + return; + + ret = struct_editor(s, config_fields, nconfig_fields, &db->config, + sizeof(struct config), (void *)&new_config, "BBS Settings", + "Sysop:Settings"); + if (ret != 0) { + session_printf(s, "No changes made\r\n"); + return; + } + + memcpy(&db->config, new_config, sizeof(db->config)); + db_config_save(db); + + session_log(s, "Changed BBS settings"); + session_printf(s, "Successfully saved changes to BBS Settings\r\n"); + free(new_config); +} + +void +sysop_edit_boards(struct session *s) +{ + static struct session_menu_option opts[] = { + { 'n', "Nn", "Create new board" }, + { 'q', "QqXx", "Return to sysop menu" }, + { '?', "?", "List menu options" }, + }; + struct session_menu_option *dopts = NULL, *opt; + struct board *board, *new_board; + size_t n; + short ret; + char c; + char prompt[30]; + bool show_help = true; + bool done = false; + bool found = false; + + while (!done) { + /* + * Unfortunately we have to do this every iteration because the + * list of boards may change + */ + if (dopts != NULL) + free(dopts); + dopts = xmalloc(sizeof(opts) + + (db->nboards * sizeof(struct session_menu_option))); + for (n = 0; n < db->nboards; n++) { + board = &db->boards[n]; + opt = &dopts[n]; + opt->ret = '0' + board->id; + opt->key[0] = '0' + board->id; + opt->key[1] = '\0'; + strlcpy(opt->title, board->name, sizeof(opts[0].title)); + } + memcpy(&dopts[db->nboards], opts, sizeof(opts)); + + c = session_menu(s, "Board Editor", "Sysop:Boards", dopts, + nitems(opts) + db->nboards, show_help); + show_help = false; + + switch (c) { + case 'n': + board = xmalloczero(sizeof(struct board)); + board->id = bile_next_id(db->bile, DB_BOARD_RTYPE); + board->restricted_posting = false; + board->restricted_viewing = false; + ret = struct_editor(s, board_fields, nboard_fields, + board, sizeof(struct board), (void *)&new_board, + "New Board", "Sysop:Boards:New"); + if (ret != 0) { + free(board); + continue; + } + db_board_create(db, new_board); + session_log(s, "Created new board %ld: %s", new_board->id, + new_board->name); + free(board); + free(new_board); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + found = false; + for (n = 0; n < db->nboards; n++) { + board = &db->boards[n]; + if (board->id != c - '0') + continue; + found = true; + snprintf(prompt, sizeof(prompt), "Sysop:Boards:%ld", + board->id); + ret = struct_editor(s, board_fields, nboard_fields, + board, sizeof(struct board), (void *)&new_board, + "Edit Board", prompt); + if (ret != 0) + continue; + memcpy(&db->boards[n], new_board, sizeof(struct board)); + if (bile_write(db->bile, DB_BOARD_RTYPE, new_board->id, + new_board, sizeof(struct board)) != sizeof(struct board)) + panic("save of board %ld failed: %d", + new_board->id, bile_error(db->bile)); + session_log(s, "Saved changes to board %ld: %s", + new_board->id, new_board->name); + free(new_board); + break; + } + if (!found) { + session_printf(s, "Invalid board ID\r\n"); + session_flush(s); + } + break; + case '?': + show_help = true; + break; + default: + done = true; + break; + } + } +} --- sysop.h Sat May 14 19:48:01 2022 +++ sysop.h Sat May 14 19:48:01 2022 @@ -0,0 +1,26 @@ +/* + * 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 __SYSOP_H__ +#define __SYSOP_H__ + +#include "subtext.h" +#include "session.h" + +void sysop_menu(struct session *s); +void sysop_edit_settings(struct session *s); + +#endif --- user_settings.c Mon May 9 15:49:26 2022 +++ user_settings.c Sat May 14 21:49:20 2022 @@ -26,25 +26,10 @@ #include "user_settings.h" #include "util.h" -void user_settings_help(struct session *s); void user_settings_renegotiate(struct session *s); void user_settings_password(struct session *s); void -user_settings_help(struct session *s) -{ - session_output_template(s, - "{{B}}R{{/B}}: Renegotiate terminal\r\n"); - - if (s->user) - session_output_template(s, "{{B}}P{{/B}}: Change password\r\n"); - - session_output_template(s, - "{{B}}Q{{/B}}: Return to main menu\r\n"); - session_flush(s); -} - -void user_settings_renegotiate(struct session *s) { unsigned short c; @@ -194,52 +179,35 @@ user_settings_password(struct session *s) void user_settings_menu(struct session *s) { + static struct session_menu_option opts[] = { + { 'r', "Rr", "Renegotiate terminal" }, + { 'p', "Pp", "Change password" }, + { 'q', "QqXx", "Return to main menu" }, + { '?', "?", "List menu options" }, + }; + char c; + bool show_help = true; bool done = false; - unsigned short c; - + session_log(s, "User settings menu"); - session_output_template(s, "{{B}}Settings{{/B}}\r\n" - "{{B}}--------{{/B}}\r\n"); - user_settings_help(s); - while (!done) { - session_output_template(s, "{{B}}Settings>{{/B}} "); - session_flush(s); - -get_another_char: - c = session_input_char(s); - if (s->ending) - break; - if (c == '\r' || c == 0 || c > 255) - goto get_another_char; - - session_printf(s, "%c\r\n", c); - session_flush(s); + c = session_menu(s, "Settings", "Settings", opts, nitems(opts), + show_help); + show_help = false; switch (c) { - case 'p': - case 'P': - user_settings_password(s); - break; - case 'q': - case 'Q': - case 'x': - case 'X': - done = true; - break; case 'r': - case 'R': user_settings_renegotiate(s); break; + case 'p': + user_settings_password(s); + break; case '?': - case 'H': - case 'h': - user_settings_help(s); + show_help = true; break; default: - session_output_string(s, "Invalid option\r\n"); - session_flush(s); + done = true; break; } }