jcs
/subtext
/amendments
/99
settings: Move to interactive text-based menu for sysops
This will allow remote administration and have a reusable component
for editing structs for users, boards, etc.
jcs made amendment 99 over 2 years ago
--- db.c Wed Apr 20 21:59:38 2022
+++ db.c Thu May 12 15:29:53 2022
@@ -24,6 +24,34 @@
#include "user.h"
#include "util.h"
+struct struct_field config_fields[] = {
+ { "BBS Name", CONFIG_TYPE_STRING,
+ offsetof(struct config, name),
+ 1, member_size(struct config, name) },
+ { "Phone Number", CONFIG_TYPE_STRING,
+ offsetof(struct config, phone_number),
+ 1, member_size(struct config, phone_number) },
+ { "Location", CONFIG_TYPE_STRING,
+ offsetof(struct config, location),
+ 1, member_size(struct config, location) },
+ { "Hostname", CONFIG_TYPE_STRING,
+ offsetof(struct config, hostname),
+ 1, member_size(struct config, hostname) },
+ { "Telnet Port", CONFIG_TYPE_SHORT,
+ offsetof(struct config, telnet_port),
+ 0, 65535 },
+ { "Modem Port", CONFIG_TYPE_SHORT,
+ offsetof(struct config, modem_port),
+ 0, 2 },
+ { "Modem Init String", CONFIG_TYPE_STRING,
+ offsetof(struct config, modem_init),
+ 1, member_size(struct config, modem_init) },
+ { "Max Idle Minutes", CONFIG_TYPE_SHORT,
+ offsetof(struct config, max_idle_minutes),
+ 1, 65535 },
+};
+size_t nconfig_fields = nitems(config_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);
--- db.h Sun Apr 10 09:19:45 2022
+++ db.h Thu May 12 15:30:48 2022
@@ -19,10 +19,6 @@
#include <time.h>
-#include "subtext.h"
-#include "bile.h"
-#include "sha2.h"
-
#define SUBTEXT_CREATOR 'SUBT'
#define DB_TYPE 'STDB'
@@ -46,9 +42,17 @@
#define DB_USERNAME_LENGTH 16
+#define DB_BOARD_NAME_LENGTH 32
+#define DB_BOARD_DESCR_LENGTH 100
+
#define SL_TYPE 'STSL'
#define SL_LOG_RTYPE 'SLOG'
+#include "subtext.h"
+#include "settings.h"
+#include "bile.h"
+#include "sha2.h"
+
struct config {
char name[32];
char phone_number[32];
@@ -60,6 +64,9 @@ struct config {
short max_idle_minutes;
};
+extern struct struct_field config_fields[];
+extern size_t nconfig_fields;
+
struct user {
/* keep this first so we can quickly read it during caching */
char username_key[DB_USERNAME_LENGTH + 1];
@@ -71,6 +78,17 @@ struct user {
unsigned long created_at;
unsigned long last_seen_at;
short is_sysop;
+};
+
+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;
+ unsigned long last_post_at;
+ unsigned long post_count;
};
struct user_map {
--- mail.c Thu Apr 28 17:05:12 2022
+++ mail.c Mon May 9 15:48:26 2022
@@ -78,7 +78,7 @@ short
mail_get_message_id(struct session *s, size_t nmsgs, char *prompt,
short initial)
{
- char *tmp;
+ char *tmp = NULL;
char start_s[10] = { 0 };
short ret;
@@ -87,22 +87,26 @@ mail_get_message_id(struct session *s, size_t nmsgs, c
get_id:
if (prompt)
- session_printf(s, "{{B}}%s:{{/}} ", prompt);
+ session_printf(s, "{{B}}%s:{{/B}} ", prompt);
tmp = session_field_input(s, 5, 5, start_s, 0);
- if (tmp == NULL)
- return -1;
+ 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{{/}} (^C to cancel)\r\n");
+ session_printf(s, "{{B}}Invalid message ID{{/B}} (^C to cancel)\r\n");
session_flush(s);
free(tmp);
goto get_id;
}
-
- free(tmp);
+
+get_id_done:
+ if (tmp)
+ free(tmp);
return ret;
}
@@ -124,15 +128,15 @@ mail_menu(struct session *s)
return;
}
- session_output_template(s, "{{B}}Private Mail{{/}} "
- "('{{B}}?{{/}}' for help)\r\n"
- "{{B}}--------------------{{/}}\r\n");
+ 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);
while (!done) {
- session_output_template(s, "{{B}}Mail>{{/}} ");
+ session_output_template(s, "{{B}}Mail>{{/B}} ");
session_flush(s);
get_menu_option:
@@ -195,7 +199,7 @@ get_menu_option:
break;
default:
session_output_template(s,
- "Invalid option ({{B}}?{{/}} for help)\r\n");
+ "Invalid option ({{B}}?{{/B}} for help)\r\n");
session_flush(s);
}
}
@@ -205,12 +209,12 @@ void
mail_help(struct session *s)
{
session_output_template(s,
- "{{B}}L{{/}}: List mail messages\r\n"
- "{{B}}#{{/}}: Read mail message [#]\r\n"
- "{{B}}D #{{/}}: Delete mail message [#]\r\n"
- "{{B}}U #{{/}}: Mark mail message [#] unread\r\n"
- "{{B}}C{{/}}: Compose new mail message\r\n"
- "{{B}}Q{{/}}: Return to main menu\r\n");
+ "{{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);
}
@@ -230,14 +234,14 @@ mail_compose(struct session *s, char *initial_to, char
if (initial_body)
msg.body = xstrdup(initial_body);
- session_output_template(s, "{{B}}Compose New Private Mail{{/}}\r\n"
- "{{B}}------------{{/}}\r\n");
- session_printf(s, "{{B}}From: {{/}} %s\r\n", s->user->username);
+ session_output_template(s, "{{B}}Compose New Private Mail{{/B}}\r\n"
+ "{{B}}------------{{/B}}\r\n");
+ session_printf(s, "{{B}}From: {{/B}} %s\r\n", s->user->username);
session_flush(s);
mail_compose_start:
for (;;) {
- session_output_template(s, "{{B}}To: {{/}} ");
+ session_output_template(s, "{{B}}To: {{/B}} ");
session_flush(s);
tmp = session_field_input(s, DB_USERNAME_LENGTH + 1,
@@ -252,7 +256,7 @@ mail_compose_start:
to_user = user_find_by_username(to_username);
if (to_user == NULL) {
- session_printf(s, "{{B}}Error:{{/}} No such user \"%s\" "
+ session_printf(s, "{{B}}Error:{{/B}}{{#}} No such user \"%s\" "
"(^C to cancel)\r\n", to_username);
session_flush(s);
free(to_username);
@@ -265,7 +269,7 @@ mail_compose_start:
}
for (;;) {
- session_output_template(s, "{{B}}Subject:{{/}} ");
+ session_output_template(s, "{{B}}Subject:{{/B}} ");
session_flush(s);
tmp = session_field_input(s, 50, 50, msg.subject, 0);
@@ -277,7 +281,7 @@ mail_compose_start:
if (msg.subject == NULL)
goto mail_compose_done;
if (msg.subject[0] == '\0') {
- session_output_template(s, "{{B}}Error:{{/}} Subject cannot "
+ session_output_template(s, "{{B}}Error:{{/B}} Subject cannot "
"be blank (^C to cancel)\r\n");
session_flush(s);
free(msg.subject);
@@ -290,7 +294,7 @@ mail_compose_start:
for (;;) {
session_output_template(s,
- "{{B}}Message (^D when finished):{{/}}\r\n");
+ "{{B}}Message (^D when finished):{{/B}}\r\n");
session_flush(s);
tmp = session_multiline_input(s, s->terminal_columns - 1,
@@ -303,7 +307,7 @@ mail_compose_start:
if (msg.body == NULL)
goto mail_compose_done;
if (msg.body[0] == '\0') {
- session_output_template(s, "{{B}}Error:{{/}} Message cannot "
+ session_output_template(s, "{{B}}Error:{{/B}} Message cannot "
"be blank (^C to cancel)\r\n");
session_flush(s);
free(msg.body);
@@ -315,8 +319,8 @@ mail_compose_start:
}
for (;;) {
- session_output_template(s, "\r\n{{B}}(S){{/}}end message, "
- "{{B}}(E){{/}}dit again, or {{B}}(C){{/}}ancel? ");
+ session_output_template(s, "\r\n{{B}}(S){{/B}}end message, "
+ "{{B}}(E){{/B}}dit again, or {{B}}(C){{/B}}ancel? ");
session_flush(s);
c = session_input_char(s);
@@ -393,7 +397,7 @@ mail_list(struct session *s, bool sent, unsigned long
strftime(time, sizeof(time), "%Y-%m-%d %H:%M",
localtime(&msg.time));
- session_printf(s, "%s%c [%- 3ld] %s %- 10s %- 40s%s\r\n",
+ session_printf(s, "%s%c [%- 3ld] %s %- 10s {{#}}%- 40s%s\r\n",
msg.read ? "" : ansi(s, ANSI_BOLD, ANSI_END),
msg.read ? ' ' : 'N',
n + 1,
@@ -426,12 +430,12 @@ mail_read(struct session *s, unsigned long id)
strftime(time, sizeof(time), "%Y-%m-%d %H:%M:%S",
localtime(&msg.time));
- session_printf(s, "{{B}}From:{{/}} %s\r\n",
+ session_printf(s, "{{B}}From:{{/B}} %s\r\n",
sender ? sender->username : "(unknown)");
- session_printf(s, "{{B}}To:{{/}} %s\r\n",
+ session_printf(s, "{{B}}To:{{/B}} %s\r\n",
recipient ? recipient->username : "(unknown)");
- session_printf(s, "{{B}}Date:{{/}} %s\r\n", time);
- session_printf(s, "{{B}}Subject:{{/}} %s\r\n", msg.subject);
+ session_printf(s, "{{B}}Date:{{/B}} %s\r\n", time);
+ session_printf(s, "{{B}}Subject:{{/B}}{{#}} %s\r\n", msg.subject);
session_flush(s);
session_output_string(s, "\r\n");
session_output(s, msg.body, msg.body_size);
@@ -455,14 +459,14 @@ mail_delete(struct session *s, unsigned long idx)
nmsgs = mail_find_for_user_id(s->user->id, &mail_ids);
if (idx > nmsgs) {
- session_printf(s, "Invalid message id {{B}}%ld{{/}}\r\n", idx);
+ session_printf(s, "Invalid message id {{B}}%ld{{/B}}\r\n", idx);
goto delete_done;
}
if (bile_delete(db->bile, DB_MESSAGE_RTYPE, mail_ids[idx - 1]) == 0)
- session_printf(s, "Deleted message {{B}}%ld{{/}}\r\n", idx);
+ session_printf(s, "Deleted message {{B}}%ld{{/B}}\r\n", idx);
else
- session_printf(s, "Failed deleting message {{B}}%ld{{/}}! "
+ session_printf(s, "Failed deleting message {{B}}%ld{{/B}}! "
"(%d)\r\n", idx, bile_error(db->bile));
delete_done:
@@ -480,7 +484,7 @@ mail_mark_unread(struct session *s, unsigned long idx)
nmsgs = mail_find_for_user_id(s->user->id, &mail_ids);
if (idx > nmsgs) {
- session_printf(s, "Invalid message id {{B}}%ld{{/}}\r\n", idx);
+ session_printf(s, "Invalid message id {{B}}%ld{{/B}}\r\n", idx);
goto unread_done;
}
@@ -490,10 +494,10 @@ mail_mark_unread(struct session *s, unsigned long idx)
nitems(mail_object_fields), data, size, &msg);
msg.read = 0;
if (mail_save(s, &msg) == 0)
- session_printf(s, "Marked message {{B}}%ld{{/}} unread\r\n",
+ session_printf(s, "Marked message {{B}}%ld{{/B}} unread\r\n",
idx);
else
- session_printf(s, "Failed marking message {{B}}%ld{{/}} "
+ session_printf(s, "Failed marking message {{B}}%ld{{/B}} "
"unread!\r\n", idx);
mail_free_message_strings(&msg);
--- main.c Thu Apr 14 15:33:17 2022
+++ main.c Mon May 9 15:39:21 2022
@@ -279,9 +279,6 @@ handle_menu(long menu_id)
break;
case BBS_MENU_ID:
switch (LoWord(menu_id)) {
- case BBS_MENU_SETTINGS_ID:
- settings_edit();
- break;
case BBS_MENU_OPEN_CONSOLE_ID:
console_init();
break;
--- session.c Wed Apr 27 17:41:47 2022
+++ session.c Thu May 12 17:40:55 2022
@@ -20,10 +20,12 @@
#include <string.h>
#include "ansi.h"
+#include "board.h"
#include "chat.h"
#include "mail.h"
#include "subtext.h"
#include "session.h"
+#include "settings.h"
#include "signup.h"
#include "user.h"
#include "user_settings.h"
@@ -40,7 +42,11 @@ char sessions_tally_day[9] = { 0 };
void session_run(struct uthread *uthread, void *arg);
short session_login(struct session *s);
-size_t session_expand_var(struct session *session, char *ivar, char **ret);
+size_t session_expand_var(struct session *session, char *ivar, char **ret,
+ bool *end_expansion);
+void session_page_sysop(struct session *s);
+void session_answer_page(struct session *s);
+void sysop_edit_settings(struct session *s);
struct session *
session_create(char *node, char *via, struct node_funcs *node_funcs)
@@ -81,7 +87,7 @@ session_run(struct uthread *uthread, void *arg)
/* until we negotiate otherwise */
s->terminal_columns = DEFAULT_TERMINAL_COLUMNS;
s->terminal_lines = DEFAULT_TERMINAL_LINES;
- snprintf(s->terminal_type, sizeof(s->terminal_type), "xterm-color");
+ snprintf(s->terminal_type, sizeof(s->terminal_type), "vt100");
if (s->node_funcs->setup)
s->node_funcs->setup(s);
@@ -124,7 +130,7 @@ session_run(struct uthread *uthread, void *arg)
sessions_tally++;
session_printf(s, "\r\n"
- "Welcome, {{B}}%s{{/}}, you are the %d%s caller today.\r\n",
+ "Welcome, {{B}}%s{{/B}}, you are the %d%s caller today.\r\n",
s->user ? s->user->username : GUEST_USERNAME,
sessions_tally, ordinal(sessions_tally));
session_flush(s);
@@ -135,7 +141,7 @@ main_menu:
session_flush(s);
while (!done && !s->ending) {
- session_printf(s, "{{B}}Main Menu>{{/}} ");
+ session_printf(s, "{{B}}Main Menu>{{/B}} ");
session_flush(s);
get_another_char:
@@ -170,13 +176,20 @@ get_another_char:
case 'M':
mail_menu(s);
break;
+ case 'p':
+ case 'P':
+ if (s->user && s->user->is_sysop)
+ session_answer_page(s);
+ else
+ session_page_sysop(s);
+ break;
case 's':
case 'S':
if (s->user)
user_settings_menu(s);
else if ((s->user = signup(s))) {
session_printf(s, "\r\n"
- "Welcome, {{B}}%s{{/}}!\r\n", s->user->username);
+ "Welcome, {{B}}%s{{/B}}!\r\n", s->user->username);
goto main_menu;
}
break;
@@ -185,6 +198,26 @@ get_another_char:
/* who's 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_view(s, c - '0');
+ break;
+ case '!':
+ if (!s->user || !s->user->is_sysop) {
+ session_output_string(s, "Invalid option\r\n");
+ session_flush(s);
+ break;
+ }
+ sysop_edit_settings(s);
+ break;
case '?':
/* short menu */
if (!session_output_view(s, DB_TEXT_SHORTMENU_ID)) {
@@ -427,7 +460,7 @@ wait_for_char:
return 0;
}
- if (session->ibuf[0] == '\33') {
+ if (session->ibuf[0] == ESC) {
/* look for a VT100 escape sequence */
if (session->ibuflen == 1) {
waiting_for = 2;
@@ -723,7 +756,7 @@ session_login(struct session *s)
session_output_string(s, "login: ");
if (s->autologin_username[0]) {
- session_printf(s, "%s\r\n", s->autologin_username);
+ session_printf(s, "{{#}}%s\r\n", s->autologin_username);
session_flush(s);
username = xstrdup(s->autologin_username);
} else {
@@ -900,6 +933,7 @@ session_expand_template(struct session *session, const
size_t vallen;
short n, quote, invar = 0, varlen = 0, doif, sep;
char *varseek, *curvarpos, *val;
+ bool end_expansion = false;
retsize = 0;
retpos = 0;
@@ -915,7 +949,7 @@ session_expand_template(struct session *session, const
goto expand_var;
} else if (varlen < sizeof(curvar) - 2)
curvar[varlen++] = tmpl[n];
- } else if (tmpl[n] == '{' && tmpl[n + 1] == '{') {
+ } else if (!end_expansion && tmpl[n] == '{' && tmpl[n + 1] == '{') {
invar = 1;
varlen = 0;
n++;
@@ -983,9 +1017,11 @@ expand_var:
while (matchvar[sep - 1] == ' ')
matchvar[--sep] = '\0';
- vallen = session_expand_var(session, matchvar, &val);
+ vallen = session_expand_var(session, matchvar, &val,
+ &end_expansion);
} else {
- vallen = session_expand_var(session, curvar, &val);
+ vallen = session_expand_var(session, curvar, &val,
+ &end_expansion);
}
if (vallen) {
@@ -1000,7 +1036,8 @@ expand_var:
}
size_t
-session_expand_var(struct session *session, char *ivar, char **ret)
+session_expand_var(struct session *session, char *ivar, char **ret,
+ bool *end_expansion)
{
static char var[128], retval[128];
size_t retsize, retlen, varlen, mcount;
@@ -1034,9 +1071,12 @@ session_expand_var(struct session *session, char *ivar
if (strcmp(var, "B") == 0) {
retlen = strlcpy(retval,
ansi(session, ANSI_BOLD, ANSI_END), retsize);
- } else if (strcmp(var, "/") == 0) {
+ } else if (strcmp(var, "/B") == 0) {
retlen = strlcpy(retval,
ansi(session, ANSI_RESET, ANSI_END), retsize);
+ } else if (strcmp(var, "#") == 0) {
+ *end_expansion = true;
+ retlen = 0;
} else if (strcmp(var, "node") == 0) {
retlen = strlcpy(retval, session->node, retsize);
} else if (strcmp(var, "phone_number") == 0) {
@@ -1080,7 +1120,7 @@ session_pause_return(struct session *s, short enforce,
{
unsigned char c;
- session_output_template(s, "{{/}}Press {{B}}<Enter>{{/}} ");
+ session_output_template(s, "{{/B}}Press {{B}}<Enter>{{/B}} ");
if (msg)
session_output_string(s, msg);
else
@@ -1099,6 +1139,44 @@ session_pause_return(struct session *s, short enforce,
}
void
+session_page_sysop(struct session *s)
+{
+ char *message = NULL;
+
+ session_output_template(s, "{{B}}Page Sysop{{/B}} "
+ "(^C to cancel)\r\n"
+ "{{B}}-------------------------{{/B}}\r\n");
+ session_output_view(s, VIEWS_SUBMENU_PAGE_SYSOP_ID);
+ session_flush(s);
+
+ session_output_template(s, "{{B}}Message:{{/B}} ");
+ session_flush(s);
+ message = session_field_input(s, 64, 64, NULL, 0);
+ session_output(s, "\r\n", 2);
+ session_flush(s);
+
+ if (message == NULL || s->ending)
+ goto page_done;
+
+ /* TODO: show message on the screen */
+
+ /* TODO: enter chat with sysop */
+
+ session_output_template(s, "{{B}}TODO!{{/B}}\r\n");
+ session_flush(s);
+
+page_done:
+ if (message)
+ free(message);
+}
+
+void
+session_answer_page(struct session *s)
+{
+ /* TODO */
+}
+
+void
session_recents(struct session *s)
{
struct bile_object *slog_obj;
@@ -1109,9 +1187,9 @@ session_recents(struct session *s)
char sdate[12];
short printed;
- session_output_template(s, "{{B}}Recent Logins{{/}}\r\n");
+ session_output_template(s, "{{B}}Recent Logins{{/B}}\r\n");
session_output_template(s,
- "{{B}}Date Node User Via Speed{{/}}\r\n");
+ "{{B}}Date Node User Via Speed{{/B}}\r\n");
session_flush(s);
scount = bile_sorted_ids_by_type(db->sessions_bile, SL_LOG_RTYPE,
@@ -1152,9 +1230,9 @@ session_who(struct session *s)
unsigned long idle;
short n;
- session_output_template(s, "{{B}}Who's Online{{/}}\r\n");
+ session_output_template(s, "{{B}}Who's Online{{/B}}\r\n");
session_output_template(s,
- "{{B}}Node User Via Speed Idle{{/}}\r\n");
+ "{{B}}Node User Via Speed Idle{{/B}}\r\n");
session_flush(s);
for (n = 0; n < nsessions; n++) {
@@ -1180,4 +1258,27 @@ session_who(struct session *s)
session_output(s, "\r\n", 2);
session_flush(s);
session_pause_return(s, 0, NULL);
-}
+}
+
+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");
+ 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_printf(s, "Successfully saved changes to BBS Settings\r\n");
+ free(new_config);
+}
--- settings.c Thu Apr 14 16:36:54 2022
+++ settings.c Thu May 12 16:56:04 2022
@@ -24,53 +24,6 @@
#include "tetab.h"
#include "util.h"
-enum {
- CONFIG_TYPE_STRING,
- CONFIG_TYPE_SHORT
-};
-
-struct config_field {
- char name[32];
- short type;
- unsigned short off;
- unsigned short min;
- unsigned short max;
- short ditl_id;
-} config_fields[] = {
- { "BBS Name", CONFIG_TYPE_STRING,
- offsetof(struct config, name),
- 1, member_size(struct config, name),
- SETTINGS_BBS_NAME_ID },
- { "Phone Number", CONFIG_TYPE_STRING,
- offsetof(struct config, phone_number),
- 1, member_size(struct config, phone_number),
- SETTINGS_PHONE_ID },
- { "Location", CONFIG_TYPE_STRING,
- offsetof(struct config, location),
- 1, member_size(struct config, location),
- SETTINGS_LOCATION_ID },
- { "Hostname", CONFIG_TYPE_STRING,
- offsetof(struct config, hostname),
- 1, member_size(struct config, hostname),
- SETTINGS_HOSTNAME_ID },
- { "Telnet Port", CONFIG_TYPE_SHORT,
- offsetof(struct config, telnet_port),
- 0, 65535,
- SETTINGS_TELNET_PORT_ID },
- { "Modem Port", CONFIG_TYPE_SHORT,
- offsetof(struct config, modem_port),
- 0, 2,
- SETTINGS_MODEM_PORT_ID },
- { "Modem Init String", CONFIG_TYPE_STRING,
- offsetof(struct config, modem_init),
- 1, member_size(struct config, modem_init),
- SETTINGS_MODEM_INIT_ID },
- { "Max Idle Minutes", CONFIG_TYPE_SHORT,
- offsetof(struct config, max_idle_minutes),
- 1, 65535,
- SETTINGS_MAX_IDLE_MINS_ID },
-};
-
struct view_editor {
WindowPtr win;
size_t view_id;
@@ -87,103 +40,173 @@ void view_editor_update(struct focusable *focusable, E
void view_editor_close(struct focusable *focusable, EventRecord *event);
void view_editor_save(struct focusable *focusable, EventRecord *event);
-void
-settings_edit(void)
+short
+struct_editor(struct session *s, struct struct_field *fields,
+ size_t nfields, void *data, size_t dsize, void **result, char *title)
{
- Str255 txt;
Handle ihandle;
- struct config new_config;
+ struct struct_field *sf;
size_t len;
- DialogPtr dlg;
- Rect irect;
- short done = 0, itype, hit, n;
+ long lval;
+ char co, initial[20];
+ char *input = NULL, *new_data;
+ short itype, hit, n, sval;
+ bool found, any_changes = false;
+ unsigned short c;
- new_config = db->config;
+ session_printf(s, "{{B}}Editor: %s{{/B}}\r\n", title);
+ session_flush(s);
- if ((dlg = GetNewDialog(SETTINGS_DLOG_ID, nil, (WindowPtr)-1)) == NULL)
- panic("Can't find settings DLOG %d", SETTINGS_DLOG_ID);
-
- for (n = 0; n < nitems(config_fields); n++) {
- struct config_field *cf = &config_fields[n];
- short sval;
-
- GetDItem(dlg, cf->ditl_id, &itype, &ihandle, &irect);
+ new_data = xmalloc(dsize);
+ memcpy(new_data, data, dsize);
+
+print_options:
+ for (n = 0; n < nfields; n++) {
+ sf = &fields[n];
- switch (cf->type) {
+ if (n > 9)
+ co = 'A' + (n - 9);
+ else
+ co = '0' + n;
+
+ session_printf(s, "{{B}}%c{{/B}}: %s [", co, sf->name);
+
+ switch (sf->type) {
case CONFIG_TYPE_STRING:
- strlcpy((char *)&txt, (char *)&new_config + cf->off,
- sizeof(txt));
+ session_output_string(s, new_data + sf->off);
break;
case CONFIG_TYPE_SHORT:
- sval = (((char *)&new_config)[cf->off] << 8) |
- ((char *)&new_config)[cf->off + 1];
- snprintf((char *)&txt, sizeof(txt), "%d", sval);
+ sval = (new_data[sf->off] << 8) | new_data[sf->off + 1];
+ session_printf(s, "%d", sval);
break;
}
- CtoPstr(txt);
- SetIText(ihandle, txt);
+ session_output_string(s, "]\r\n");
}
-
- ShowWindow(dlg);
- while (!done) {
-get_input:
- ModalDialog(ModalDialogFilter, &hit);
- switch (hit) {
- case OK:
- done = 1;
+ session_printf(s, "{{B}}S{{/B}}: Save and return to main menu\r\n");
+ session_printf(s, "{{B}}Q{{/B}}: Discard changes and return to main menu\r\n");
+ session_printf(s, "{{B}}?{{/B}}: Print menu of options\r\n");
+
+ for (;;) {
+ session_output_template(s, "{{B}}Editor>{{/B}} ");
+ session_flush(s);
+
+get_menu_option:
+ c = session_input_char(s);
+ if (s->ending) {
+ any_changes = false;
+ goto done;
+ }
+ if (c == '\r' || c == 0 || c > 255)
+ goto get_menu_option;
+
+ session_printf(s, "%c\r\n", c);
+ session_flush(s);
+
+ if (c == '?')
+ goto print_options;
+ if (c == 'S' || c == 's')
break;
- case Cancel:
- goto cancel;
+ if (c == 'Q' || c == 'q') {
+ any_changes = false;
+ goto done;
}
+
+ found = false;
+ sf = NULL;
+ for (n = 0; n < nfields; n++) {
+ sf = &fields[n];
- if (!done)
+ if (n > 9)
+ co = 'A' + (n - 9);
+ else
+ co = '0' + n;
+
+ if (c == co) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ session_output_template(s,
+ "Invalid option ({{B}}?{{/B}} for help)\r\n");
+ session_flush(s);
continue;
+ }
- for (n = 0; n < nitems(config_fields); n++) {
- struct config_field *cf = &config_fields[n];
- long lval;
- short sval;
-
- GetDItem(dlg, cf->ditl_id, &itype, &ihandle, &irect);
- GetIText(ihandle, txt);
- PtoCstr(txt);
+get_input:
+ session_printf(s, "{{B}}%s:{{/B}} ", sf->name);
+ session_flush(s);
- switch (cf->type) {
- case CONFIG_TYPE_STRING:
- if (strlen((char *)txt) >= cf->max) {
- warn("%s is too long (%d max)", cf->name, cf->max - 1);
- done = 0;
- goto get_input;
- }
- strlcpy((char *)&new_config + cf->off, (char *)&txt,
- cf->max);
+ switch (sf->type) {
+ case CONFIG_TYPE_STRING:
+ input = session_field_input(s, sf->max, 50, new_data + sf->off,
+ 0);
+ session_output(s, "\r\n", 2);
+ session_flush(s);
+ if (input == NULL || s->ending)
break;
- case CONFIG_TYPE_SHORT:
- lval = atol((char *)txt);
- if (lval < cf->min) {
- warn("%s must be at least %d", cf->name, cf->min);
- done = 0;
- goto get_input;
- }
- if (lval > cf->max) {
- warn("%s must be less than %d", cf->name, cf->max);
- done = 0;
- goto get_input;
- }
- sval = lval;
- memcpy((char *)&new_config + cf->off, &sval, sizeof(short));
+
+ if (strlen(input) >= sf->max) {
+ session_printf(s,
+ "%s is too long (%d max, ^C to cancel)", sf->name,
+ sf->max - 1);
+ free(input);
+ goto get_input;
+ }
+ strlcpy(new_data + sf->off, input, sf->max);
+ 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);
+ input = session_field_input(s, 10, 10, initial, 0);
+ session_output(s, "\r\n", 2);
+ session_flush(s);
+ if (input == NULL || s->ending)
break;
+
+ lval = atol(input);
+ if (lval < sf->min) {
+ session_printf(s,
+ "%s must be at least %d (^C to cancel)\r\n", sf->name,
+ sf->min);
+ free(input);
+ goto get_input;
}
+ if (lval > sf->max) {
+ session_printf(s,
+ "%s must be less than %d (^C to cancel)\r\n", sf->name,
+ sf->max);
+ free(input);
+ goto get_input;
+ }
+ sval = lval;
+ new_data[sf->off] = (sval >> 8) & 0xff;
+ new_data[sf->off + 1] = sval & 0xff;
+ any_changes = true;
+ break;
}
+
+ if (input != NULL)
+ free(input);
+ if (s->ending) {
+ any_changes = false;
+ goto done;
+ }
}
-
- db->config = new_config;
- db_config_save(db);
-cancel:
- DisposeDialog(dlg);
+done:
+ if (any_changes) {
+ *result = new_data;
+ return 0;
+ } else {
+ free(new_data);
+ *result = NULL;
+ return -1;
+ }
}
void
--- settings.h Tue Jan 18 08:07:32 2022
+++ settings.h Tue May 10 15:45:23 2022
@@ -17,7 +17,23 @@
#ifndef __SETTINGS_H__
#define __SETTINGS_H__
-void settings_edit(void);
+#include "session.h"
+
+enum {
+ CONFIG_TYPE_STRING,
+ CONFIG_TYPE_SHORT
+};
+
+struct struct_field {
+ char name[32];
+ short type;
+ unsigned short off;
+ unsigned short min;
+ 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);
void view_editor_show(size_t id, char *title);
#endif
--- signup.c Tue Apr 26 15:40:07 2022
+++ signup.c Mon May 9 15:49:09 2022
@@ -37,13 +37,14 @@ signup(struct session *s)
session_log(s, "Signing up for an account");
- session_output_template(s, "{{B}}Create Account{{/}} "
+ session_output_template(s, "{{B}}Create Account{{/B}} "
"(^C to cancel)\r\n"
- "{{B}}----------------------------{{/}}\r\n");
+ "{{B}}----------------------------{{/B}}\r\n");
+ session_output_view(s, VIEWS_SUBMENU_SIGNUP_ID);
session_flush(s);
for (;;) {
- session_printf(s, "{{B}}Username{{/}} (Up to %d letters/numbers): ",
+ session_printf(s, "{{B}}Username{{/B}} (Up to %d letters/numbers): ",
DB_USERNAME_LENGTH);
session_flush(s);
@@ -56,7 +57,7 @@ signup(struct session *s)
goto signup_done;
if (user_valid_username(username, &error) != 1) {
- session_printf(s, "{{B}}Error:{{/}} %s\r\n", error);
+ session_printf(s, "{{B}}Error:{{/B}} %s\r\n", error);
free(error);
continue;
}
@@ -65,7 +66,7 @@ signup(struct session *s)
}
for (;;) {
- session_output_template(s, "{{B}}Password:{{/}} ");
+ session_output_template(s, "{{B}}Password:{{/B}} ");
session_flush(s);
password = session_field_input(s, 64, 64, NULL, '*');
session_output(s, "\r\n", 2);
@@ -75,13 +76,13 @@ signup(struct session *s)
goto signup_done;
if (password[0] == '\0') {
- session_printf(s, "{{B}}Error:{{/}} "
+ session_printf(s, "{{B}}Error:{{/B}} "
"Password cannot be blank\r\n");
free(password);
continue;
}
- session_output_template(s, "{{B}}Password (again):{{/}} ");
+ session_output_template(s, "{{B}}Password (again):{{/B}} ");
session_flush(s);
password_confirm = session_field_input(s, 64, 64, NULL, '*');
session_output(s, "\r\n", 2);
@@ -91,7 +92,7 @@ signup(struct session *s)
goto signup_done;
if (strcmp(password_confirm, password) != 0) {
- session_printf(s, "{{B}}Error:{{/}} "
+ session_printf(s, "{{B}}Error:{{/B}} "
"Passwords do not match\r\n");
free(password);
free(password_confirm);
--- subtext.π.r Wed Jan 5 21:02:58 2022
+++ subtext.π.r Thu May 12 17:46:17 2022
@@ -9,8 +9,33 @@ data 'MENU' (129) {
$"696C 6504 5175 6974 0051 0000 00" /* ile.Quit.Q... */
};
+data 'MENU' (130) {
+ $"0082 0000 0000 0000 0000 FFFF FFF7 0342" /* .Ç.............B */
+ $"4253 0855 7365 7273 2E2E 2E00 5500 0005" /* BS.Users....U... */
+ $"5669 6577 7300 1B84 0001 2D00 0000 000C" /* Views..Ñ..-..... */
+ $"4F70 656E 2043 6F6E 736F 6C65 004E 0000" /* Open Console.N.. */
+ $"00" /* . */
+};
+
+data 'MENU' (131) {
+ $"0083 0000 0000 0000 0000 FFFF FFFF 0445" /* .É.............E */
+ $"6469 7403 4375 7400 5800 0004 436F 7079" /* dit.Cut.X...Copy */
+ $"0043 0000 0550 6173 7465 0056 0000 00" /* .C...Paste.V... */
+};
+
+data 'MENU' (132) {
+ $"0084 0000 0000 0000 0000 FFFF FFFF 0556" /* .Ñ.............V */
+ $"6965 7773 1450 7265 2D4C 6F67 696E 2028" /* iews.Pre-Login ( */
+ $"4973 7375 6529 2E2E 2E00 0000 000C 4D61" /* Issue)........Ma */
+ $"696E 204D 656E 752E 2E2E 0000 0000 0D53" /* in Menu.......¬S */
+ $"686F 7274 204D 656E 752E 2E2E 0000 0000" /* hort Menu....... */
+ $"1141 6363 6F75 6E74 2053 6967 6E75 702E" /* .Account Signup. */
+ $"2E2E 0000 0000 0D50 6167 6520 5379 736F" /* ......¬Page Syso */
+ $"702E 2E2E 0000 0000 00" /* p........ */
+};
+
data 'MBAR' (128) {
- $"0002 0080 0081" /* ...Ä.Å */
+ $"0004 0080 0081 0083 0082" /* ...Ä.Å.É.Ç */
};
data 'ALRT' (129) {
--- subtext.h Tue Apr 12 16:35:04 2022
+++ subtext.h Mon May 9 15:37:21 2022
@@ -35,17 +35,16 @@
#define EDIT_MENU_PASTE_ID 3
#define BBS_MENU_ID 130
-#define BBS_MENU_BOARDS_ID 1
-#define BBS_MENU_FILES_ID 2
-#define BBS_MENU_USERS_ID 3
-#define BBS_MENU_VIEWS_ID 4
-#define BBS_MENU_SETTINGS_ID 5
-#define BBS_MENU_OPEN_CONSOLE_ID 7
+#define BBS_MENU_USERS_ID 1
+#define BBS_MENU_VIEWS_ID 2
+#define BBS_MENU_OPEN_CONSOLE_ID 4
#define VIEWS_SUBMENU_ID 132
-#define VIEWS_SUBMENU_MAIN_MENU_ID 1
-#define VIEWS_SUBMENU_SHORT_MENU_ID 2
-#define VIEWS_SUBMENU_ISSUE_ID 3
+#define VIEWS_SUBMENU_ISSUE_ID 1
+#define VIEWS_SUBMENU_MAIN_MENU_ID 2
+#define VIEWS_SUBMENU_SHORT_MENU_ID 3
+#define VIEWS_SUBMENU_SIGNUP_ID 4
+#define VIEWS_SUBMENU_PAGE_SYSOP_ID 5
#define STR_LAST_DB 128
@@ -59,7 +58,13 @@
#define SETTINGS_MODEM_INIT_ID 9
#define SETTINGS_MAX_IDLE_MINS_ID 10
-#define SETTINGS_EDIT_VIEW_DLOG_ID 131
+#define BOARD_DLOG_ID 131
+#define BOARD_BOARD_ID 3
+#define BOARD_NAME_ID 4
+#define BOARD_DESCRIPTION_ID 5
+#define BOARD_RESTRICTED_POSTING_ID 6
+#define BOARD_RESTRICTED_VIEWING_ID 7
+#define BOARD_RETENTION_ID 8
#include "db.h"
#include "logger.h"
--- tetab.c Fri Oct 29 17:17:44 2021
+++ tetab.c Mon May 9 15:55:04 2022
@@ -214,6 +214,7 @@ TETabHitTestHook(void)
if (poffset <= (wpos * cwidth)) {
found = 1;
+ cpos++;
break;
}
}
--- user_settings.c Thu Apr 28 14:13:17 2022
+++ user_settings.c Mon May 9 15:49:26 2022
@@ -34,13 +34,13 @@ void
user_settings_help(struct session *s)
{
session_output_template(s,
- "{{B}}R{{/}}: Renegotiate terminal\r\n");
+ "{{B}}R{{/B}}: Renegotiate terminal\r\n");
if (s->user)
- session_output_template(s, "{{B}}P{{/}}: Change password\r\n");
+ session_output_template(s, "{{B}}P{{/B}}: Change password\r\n");
session_output_template(s,
- "{{B}}Q{{/}}: Return to main menu\r\n");
+ "{{B}}Q{{/B}}: Return to main menu\r\n");
session_flush(s);
}
@@ -107,13 +107,16 @@ get_terminal_size:
return;
session_output(s, "\r\n", 2);
session_flush(s);
- if (tsize[0] == '\0')
+ if (tsize[0] == '\0') {
+ free(tsize);
return;
+ }
if (sscanf(tsize, "%dx%d", &cols, &lines) != 2) {
session_printf(s, "Invalid response, must be in format %dx%d\r\n",
s->terminal_columns, s->terminal_lines);
session_flush(s);
+ free(tsize);
goto get_terminal_size;
}
@@ -121,6 +124,7 @@ get_terminal_size:
session_printf(s, "Terminal too small, must be at least "
"%dx%d\r\n", MIN_TERMINAL_COLUMNS, MIN_TERMINAL_LINES);
session_flush(s);
+ free(tsize);
goto get_terminal_size;
}
@@ -135,13 +139,13 @@ user_settings_password(struct session *s)
char *password = NULL, *password_confirm = NULL;
if (!s->user) {
- session_output_template(s, "{{B}}Error{{/}}: Guest accounts "
+ session_output_template(s, "{{B}}Error{{/B}}: Guest accounts "
"cannot change passwords\r\n");
return;
}
for (;;) {
- session_output_template(s, "{{B}}New Password:{{/}} ");
+ session_output_template(s, "{{B}}New Password:{{/B}} ");
session_flush(s);
password = session_field_input(s, 64, 64, NULL, '*');
session_output(s, "\r\n", 2);
@@ -151,13 +155,13 @@ user_settings_password(struct session *s)
break;
if (password[0] == '\0') {
- session_output_template(s, "{{B}}Error:{{/}} "
+ session_output_template(s, "{{B}}Error:{{/B}} "
"Password cannot be blank\r\n");
free(password);
continue;
}
- session_output_template(s, "{{B}}New Password (again):{{/}} ");
+ session_output_template(s, "{{B}}New Password (again):{{/B}} ");
session_flush(s);
password_confirm = session_field_input(s, 64, 64, NULL, '*');
session_output(s, "\r\n", 2);
@@ -167,7 +171,7 @@ user_settings_password(struct session *s)
break;
if (strcmp(password_confirm, password) != 0) {
- session_output_template(s, "{{B}}Error:{{/}} "
+ session_output_template(s, "{{B}}Error:{{/B}} "
"Passwords do not match\r\n");
free(password);
free(password_confirm);
@@ -177,7 +181,7 @@ user_settings_password(struct session *s)
user_set_password(s->user, password);
user_save(s->user);
session_output_template(s, "{{B}}Your password has been "
- "changed{{/}}\r\n");
+ "changed{{/B}}\r\n");
break;
}
@@ -195,12 +199,12 @@ user_settings_menu(struct session *s)
session_log(s, "User settings menu");
- session_output_template(s, "{{B}}Settings{{/}}\r\n"
- "{{B}}--------{{/}}\r\n");
+ 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>{{/}} ");
+ session_output_template(s, "{{B}}Settings>{{/B}} ");
session_flush(s);
get_another_char: