jcs
/subtext
/amendments
/566
*: Move views out of database to flat files
Remove half-baked view editor and cache file contents in memory.
Add a sysop menu option to reload them.
When opening the database, if the command key is held down, prevent
opening the last-opened database and prompt for a different one.
jcs made amendment 566 11 months ago
--- db.c Mon Nov 27 20:44:33 2023
+++ db.c Tue Nov 28 11:25:42 2023
@@ -25,6 +25,7 @@
#include "folder.h"
#include "logger.h"
#include "mail.h"
+#include "main_menu.h"
#include "user.h"
#include "util.h"
@@ -153,9 +154,10 @@ 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, Str255 basepath);
void db_config_load(struct db *tdb);
+const char * db_view_filename(short id);
struct db *
-db_open(Str255 file, short vrefnum)
+db_open(Str255 file, short vrefnum, bool ignore_last)
{
Str255 filepath;
struct stat sb;
@@ -173,7 +175,7 @@ db_open(Str255 file, short vrefnum)
warn("Failed to open %s", PtoCstr(file));
}
- if ((lastfileh = GetString(STR_LAST_DB))) {
+ if (!ignore_last && (lastfileh = GetString(STR_LAST_DB))) {
HLock(lastfileh);
memcpy(filepath, *lastfileh, sizeof(filepath));
HUnlock(lastfileh);
@@ -227,10 +229,11 @@ db_create(void)
struct db *
db_init(Str255 path, short vrefnum, struct bile *bile)
{
- Str255 fullpath, newfullpath;
+ Str255 fullpath, newfullpath, viewsdir;
struct db *tdb;
Handle lastfileh;
- short was_new;
+ short was_new, error;
+ long dirid;
was_new = (bile != NULL);
@@ -273,6 +276,19 @@ db_init(Str255 path, short vrefnum, struct bile *bile)
if (tdb == NULL)
panic("Can't create db");
tdb->bile = bile;
+
+ /* create views directory if it doesn't exist */
+ if (getpath(tdb->bile->vrefnum, tdb->bile->filename, viewsdir,
+ false) != 0)
+ panic("getpath failed on %s", PtoCstr(tdb->bile->filename));
+ PtoCstr(viewsdir);
+ strlcat((char *)viewsdir, ":views", sizeof(Str255));
+ CtoPstr(viewsdir);
+ if (!FIsDir(viewsdir)) {
+ error = DirCreate(tdb->bile->vrefnum, 0, viewsdir, &dirid);
+ if (error)
+ panic("Failed creating %s: %d", PtoCstr(viewsdir), error);
+ }
if (db_migrate(tdb, was_new, fullpath) != 0) {
bile_close(tdb->bile);
@@ -417,153 +433,11 @@ db_migrate(struct db *tdb, short is_new, Str255 fullpa
progress("Migrating from version %d to %d...", (short)ver,
(short)(ver + 1));
+ if (ver < 18)
+ panic("This Subtext database is too old to upgrade. Please "
+ "run an older Subtext release first to upgrade it.");
+
switch (ver) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- case 11:
- panic("This version of Subtext is too old to upgrade, please "
- "upgrade to a previous release first.");
- break;
- case 12: {
- /* 12->13, added ftn/binkp fields */
- struct config new_config = { 0 };
-
- bile_read(tdb->bile, DB_CONFIG_RTYPE, 1, (char *)&new_config,
- sizeof(new_config));
-
- new_config.ftn_network[0] = '\0';
- new_config.ftn_node_addr[0] = '\0';
- new_config.ftn_hub_addr[0] = '\0';
- new_config.ftn_hub_pkt_password[0] = '\0';
- new_config.binkp_hostname[0] = '\0';
- new_config.binkp_port = 24554;
- new_config.binkp_password[0] = '\0';
- new_config.binkp_interval_seconds = (60 * 60 * 3);
- new_config.binkp_delete_done = 0;
-
- bile_write(tdb->bile, DB_CONFIG_RTYPE, 1, &new_config,
- sizeof(new_config));
- break;
- }
- case 13: {
- /* 13->14, move mail to separate db, add ftn fields */
- Str255 newfullpath;
- struct bile *mail_bile;
- size_t nids, n, size;
- unsigned long *ids;
- char *data;
-
- memcpy(&newfullpath, fullpath, sizeof(newfullpath));
- PtoCstr(newfullpath);
- strlcat((char *)&newfullpath, "-mail", sizeof(newfullpath));
- CtoPstr(newfullpath);
-
- mail_bile = bile_create(newfullpath, tdb->bile->vrefnum,
- SUBTEXT_CREATOR, MAIL_SPOOL_TYPE);
- if (mail_bile == NULL)
- panic("Couldn't create %s: %d", PtoCstr(newfullpath),
- bile_error(NULL));
-
- nids = bile_ids_by_type(tdb->bile, MAIL_SPOOL_MESSAGE_RTYPE,
- &ids);
- for (n = 0; n < nids; n++) {
- progress("Copying mail message %ld...", ids[n]);
- size = bile_read_alloc(tdb->bile, MAIL_SPOOL_MESSAGE_RTYPE,
- ids[n], &data);
- bile_write(mail_bile, MAIL_SPOOL_MESSAGE_RTYPE, ids[n],
- data, size);
- xfree(&data);
-
- size += (sizeof(struct mail_message) -
- offsetof(struct mail_message, ftn_msgid));
- if (bile_resize(mail_bile, MAIL_SPOOL_MESSAGE_RTYPE,
- ids[n], size) != size)
- panic("failed resizing message %ld", ids[n]);
- }
-
- bile_flush(mail_bile, true);
-
- /* now we can actually delete mail */
- for (n = 0; n < nids; n++) {
- progress("Deleting old mail message %ld...", ids[n]);
- bile_delete(tdb->bile, MAIL_SPOOL_MESSAGE_RTYPE, ids[n], 0);
- }
- bile_write_map(tdb->bile);
- bile_close(mail_bile);
-
- break;
- }
- case 14: {
- /* 14->15, boards get an ftn field */
- struct bile_object *o;
- size_t nids, grow, size, n;
- unsigned long *ids;
-
- grow = member_size(struct board, ftn_area);
-
- nids = bile_ids_by_type(tdb->bile, DB_BOARD_RTYPE, &ids);
- for (n = 0; n < nids; n++) {
- o = bile_find(tdb->bile, DB_BOARD_RTYPE, ids[n]);
- progress("Growing board %ld/%ld...", n + 1, nids);
- size = o->size + grow;
- if (bile_resize(tdb->bile, o->type, o->id, size) != size)
- panic("failed resizing board %ld", o->id);
- xfree(&o);
- }
- xfree(&ids);
-
- db_cache_boards(tdb);
-
- break;
- }
- case 15: {
- /* 15->16, timezone UTC offset */
- struct config new_config = { 0 };
-
- bile_read(tdb->bile, DB_CONFIG_RTYPE, 1, (char *)&new_config,
- sizeof(new_config));
-
- new_config.timezone_utcoff = 0;
-
- bile_write(tdb->bile, DB_CONFIG_RTYPE, 1, &new_config,
- sizeof(new_config));
- break;
- }
- case 16: {
- /* 16->17, mail_prune_days */
- struct config new_config = { 0 };
-
- bile_read(tdb->bile, DB_CONFIG_RTYPE, 1, (char *)&new_config,
- sizeof(new_config));
-
- new_config.mail_prune_days = 180;
-
- bile_write(tdb->bile, DB_CONFIG_RTYPE, 1, &new_config,
- sizeof(new_config));
- break;
- }
- case 17: {
- /* 17->18, more config fields */
- struct config new_config = { 0 };
-
- bile_read(tdb->bile, DB_CONFIG_RTYPE, 1, (char *)&new_config,
- sizeof(new_config));
-
- new_config.ftn_max_tossed_message_size = 16 * 1024;
- new_config.max_sysop_idle_minutes = 60;
-
- bile_write(tdb->bile, DB_CONFIG_RTYPE, 1, &new_config,
- sizeof(new_config));
- break;
- }
case 18: {
/* 18->19, ipdb_path, add session_log.location */
struct config new_config = { 0 };
@@ -620,7 +494,79 @@ db_migrate(struct db *tdb, short is_new, Str255 fullpa
sizeof(new_config));
break;
}
+ case 20: {
+ /* 20->21, move views out of db */
+ size_t size;
+ char *data;
+
+#define DB_TEXT_TYPE 'TEXT'
+#define DB_TEXT_MENU_ID 1
+#define DB_TEXT_SHORTMENU_ID 2
+#define DB_TEXT_ISSUE_ID 3
+#define DB_TEXT_SIGNUP_ID 4
+#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
+
+ progress("Migrating views out of database...");
+
+ if ((size = bile_read_alloc(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_MENU_ID, &data))) {
+ db_view_write(tdb, DB_VIEW_MENU, data, size);
+ xfree(&data);
+ bile_delete(tdb->bile, DB_TEXT_TYPE, DB_TEXT_MENU_ID, 0);
+ }
+ if ((size = bile_read_alloc(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_SHORTMENU_ID, &data))) {
+ db_view_write(tdb, DB_VIEW_SHORTMENU, data, size);
+ xfree(&data);
+ bile_delete(tdb->bile, DB_TEXT_TYPE, DB_TEXT_SHORTMENU_ID,
+ 0);
+ }
+ if ((size = bile_read_alloc(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_ISSUE_ID, &data))) {
+ db_view_write(tdb, DB_VIEW_ISSUE, data, size);
+ xfree(&data);
+ bile_delete(tdb->bile, DB_TEXT_TYPE, DB_TEXT_ISSUE_ID, 0);
+ }
+ if ((size = bile_read_alloc(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_SIGNUP_ID, &data))) {
+ db_view_write(tdb, DB_VIEW_SIGNUP, data, size);
+ xfree(&data);
+ bile_delete(tdb->bile, DB_TEXT_TYPE, DB_TEXT_SIGNUP_ID, 0);
+ }
+ if ((size = bile_read_alloc(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_PAGE_SYSOP_ID, &data))) {
+ db_view_write(tdb, DB_VIEW_PAGE_SYSOP, data, size);
+ xfree(&data);
+ bile_delete(tdb->bile, DB_TEXT_TYPE, DB_TEXT_PAGE_SYSOP_ID,
+ 0);
+ }
+ if ((size = bile_read_alloc(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_NO_FREE_NODES_ID, &data))) {
+ db_view_write(tdb, DB_VIEW_NO_FREE_NODES, data, size);
+ xfree(&data);
+ bile_delete(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_NO_FREE_NODES_ID, 0);
+ }
+ if ((size = bile_read_alloc(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_SIGNOFF_ID, &data))) {
+ db_view_write(tdb, DB_VIEW_SIGNOFF, data, size);
+ xfree(&data);
+ bile_delete(tdb->bile, DB_TEXT_TYPE, DB_TEXT_SIGNOFF_ID, 0);
+ }
+ if ((size = bile_read_alloc(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_MENU_OPTIONS_ID, &data))) {
+ db_view_write(tdb, DB_VIEW_MENU_OPTIONS, data, size);
+ xfree(&data);
+ bile_delete(tdb->bile, DB_TEXT_TYPE,
+ DB_TEXT_MENU_OPTIONS_ID, 0);
+ }
+
+ break;
}
+ }
ver++;
}
@@ -977,4 +923,154 @@ db_folder_delete(struct db *tdb, struct folder *folder
return;
}
bile_close(folder->bile);
+}
+
+const char *
+db_view_filename(short id)
+{
+ switch (id) {
+ case DB_VIEW_MENU:
+ return "menu.txt";
+ case DB_VIEW_SHORTMENU:
+ return "short_menu.txt";
+ case DB_VIEW_ISSUE:
+ return "issue.txt";
+ case DB_VIEW_SIGNUP:
+ return "signup.txt";
+ case DB_VIEW_PAGE_SYSOP:
+ return "page_sysop.txt";
+ case DB_VIEW_NO_FREE_NODES:
+ return "no_free_nodes.txt";
+ case DB_VIEW_SIGNOFF:
+ return "signoff.txt";
+ case DB_VIEW_MENU_OPTIONS:
+ return "menu_options.txt";
+ default:
+ panic("db_view_filename: unknown id %d", id);
+ }
+}
+
+void
+db_cache_views(struct db *tdb)
+{
+ Str255 viewdir, viewpath;
+ struct stat sb;
+ struct main_menu_option *opts;
+ Handle default_menu;
+ short n;
+ size_t size;
+ short error, frefnum;
+
+ logger_printf("[db] Caching views");
+
+ if (getpath(tdb->bile->vrefnum, tdb->bile->filename, viewdir,
+ false) != 0)
+ panic("getpath failed on %s", PtoCstr(tdb->bile->filename));
+ PtoCstr(viewdir);
+ strlcat((char *)viewdir, ":views:", sizeof(Str255));
+
+ for (n = 0; n < DB_VIEW_COUNT; n++) {
+ if (tdb->views[n])
+ xfree(&tdb->views[n]);
+ tdb->views[n] = NULL;
+
+ strlcpy((char *)viewpath, (char *)viewdir, sizeof(Str255));
+ strlcat((char *)viewpath, db_view_filename(n), sizeof(Str255));
+ CtoPstr(viewpath);
+
+ if (FStat(viewpath, &sb) != 0) {
+ if (n == DB_VIEW_MENU_OPTIONS) {
+ default_menu = GetResource('TEXT', MENU_DEFAULTS_ID);
+ if (default_menu == NULL)
+ panic("Failed to find TEXT resource %d for menu options",
+ MENU_DEFAULTS_ID);
+ size = GetHandleSize(default_menu);
+ HLock(default_menu);
+ db_view_write(tdb, n, *default_menu, size);
+ HUnlock(default_menu);
+ ReleaseResource(default_menu);
+ FStat(viewpath, &sb);
+ } else {
+ /* create a blank file so the sysop knows what to edit */
+ db_view_write(tdb, n, "", 0);
+
+ /* but leave the view NULL */
+ continue;
+ }
+ }
+
+ if (sb.st_size == 0)
+ continue;
+
+ tdb->views[n] = xmalloc(sb.st_size + 1);
+ if (tdb->views[n] == NULL)
+ panic("Failed allocating %ld for view %s",
+ sb.st_size, PtoCstr(viewpath));
+
+ error = FSOpen(viewpath, 0, &frefnum);
+ if (error)
+ panic("Error opening view %s: %d", PtoCstr(viewpath),
+ error);
+
+ size = sb.st_size;
+ error = FSRead(frefnum, &size, tdb->views[n]);
+ FSClose(frefnum);
+
+ tdb->views[n][sb.st_size] = '\0';
+
+ if (error && error != eofErr)
+ panic("Error reading view %s: %d", PtoCstr(viewpath),
+ error);
+
+ if (n == DB_VIEW_MENU_OPTIONS) {
+ opts = main_menu_parse(tdb->views[n], sb.st_size);
+ if (opts) {
+ if (main_menu_options != NULL)
+ xfree(&main_menu_options);
+ main_menu_options = opts;
+ }
+ }
+ }
+}
+
+void
+db_view_write(struct db *tdb, short id, char *str, size_t size)
+{
+ Str255 viewpath;
+ size_t len;
+ short error, frefnum;
+
+ if (getpath(tdb->bile->vrefnum, tdb->bile->filename, viewpath,
+ false) != 0)
+ panic("getpath failed on %s", PtoCstr(tdb->bile->filename));
+ PtoCstr(viewpath);
+ strlcat((char *)viewpath, ":views:", sizeof(Str255));
+ strlcat((char *)viewpath, db_view_filename(id), sizeof(Str255));
+ logger_printf("[db] Writing default view %s", viewpath);
+ CtoPstr(viewpath);
+
+ error = Create(viewpath, 0, 'ttxt', 'TEXT');
+ if (error == dupFNErr)
+ panic("View file already exists: %s", PtoCstr(viewpath));
+ if (error)
+ panic("Failed creating %s: %d", PtoCstr(viewpath), error);
+
+ if ((error = FSOpen(viewpath, 0, &frefnum)))
+ panic("Failed opening newly-created %s: %d", PtoCstr(viewpath),
+ error);
+
+ len = size;
+ if ((error = Allocate(frefnum, &len)))
+ panic("Failed setting %s to size %ld: %d", PtoCstr(viewpath),
+ size, error);
+
+ len = size;
+ if ((error = FSWrite(frefnum, &len, str)))
+ panic("Failed writing view to file %s: %d", PtoCstr(viewpath),
+ error);
+ if (len != size)
+ panic("Short write of view to file %s: %ld != %ld",
+ PtoCstr(viewpath), len, size);
+
+ FSClose(frefnum);
}
--- db.h Wed Nov 8 20:43:00 2023
+++ db.h Tue Nov 28 10:43:34 2023
@@ -19,7 +19,7 @@
#include <time.h>
-#define DB_CUR_VERS 20
+#define DB_CUR_VERS 21
#define SUBTEXT_CREATOR 'SUBT'
#define DB_TYPE 'STDB'
@@ -34,16 +34,6 @@
#define DB_VERS_RTYPE 'VERS'
#define DB_MOTD_RTYPE 'MOTD'
-#define DB_TEXT_TYPE 'TEXT'
-#define DB_TEXT_MENU_ID 1
-#define DB_TEXT_SHORTMENU_ID 2
-#define DB_TEXT_ISSUE_ID 3
-#define DB_TEXT_SIGNUP_ID 4
-#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
#define SL_TYPE 'STSL'
@@ -111,6 +101,19 @@ struct config {
extern struct struct_field config_fields[];
extern size_t nconfig_fields;
+enum {
+ DB_VIEW_MENU = 0,
+ DB_VIEW_SHORTMENU,
+ DB_VIEW_ISSUE,
+ DB_VIEW_SIGNUP,
+ DB_VIEW_PAGE_SYSOP,
+ DB_VIEW_NO_FREE_NODES,
+ DB_VIEW_SIGNOFF,
+ DB_VIEW_MENU_OPTIONS,
+
+ DB_VIEW_COUNT
+};
+
struct db {
struct bile *bile;
short fh;
@@ -124,9 +127,10 @@ struct db {
short nfolders;
struct bile *mail_bile;
struct ipdb_file *ipdb;
+ char *views[DB_VIEW_COUNT];
};
-struct db * db_open(Str255 file, short vrefnum);
+struct db * db_open(Str255 file, short vrefnum, bool ignore_last);
struct db * db_create(void);
void db_close(struct db *tdb);
void db_config_save(struct db *tdb);
@@ -140,5 +144,8 @@ void db_cache_folders(struct db *tdb);
struct bile * db_folder_create(struct db *tdb, struct folder *folder,
bool delete_first);
void db_folder_delete(struct db *tdb, struct folder *folder);
+
+void db_cache_views(struct db *tdb);
+void db_view_write(struct db *tdb, short id, char *str, size_t size);
#endif
--- main.c Wed Nov 22 08:25:51 2023
+++ main.c Tue Nov 28 11:03:32 2023
@@ -57,7 +57,8 @@ main(void)
struct focusable *found_focusable;
unsigned long zone_size, stack_size, heap_size;
short event_in, n, finder_action, finder_count;
- char key;
+ char key, none = 0;
+ bool ignore = false;
uthread_init();
@@ -81,7 +82,6 @@ main(void)
AddResMenu(apple_menu, 'DRVR');
if (!(file_menu = GetMHandle(FILE_MENU_ID)))
panic("no file menu");
- InsertMenu(GetMenu(VIEWS_SUBMENU_ID), -1);
DrawMenuBar();
/* see if we were started by double-clicking a .bbs file */
@@ -90,10 +90,14 @@ main(void)
GetAppFiles(1, &finder_file);
ClrAppFiles(1);
finder_count = 0;
- db = db_open(finder_file.fName, finder_file.vRefNum);
+ db = db_open(finder_file.fName, finder_file.vRefNum, false);
} else {
- char none = 0;
- db = db_open(*((Str255 *)&none), 0);
+ GetNextEvent(everyEvent, &event);
+ if (event.modifiers & cmdKey)
+ /* don't open last-opened database */
+ ignore = true;
+
+ db = db_open(*((Str255 *)&none), 0, ignore);
}
if (!db)
@@ -111,17 +115,16 @@ main(void)
"%d threads, %ldKB heap", zone_size / 1024L, stack_size / 1024L,
NUM_UTHREADS, heap_size / 1024L);
- db_cache_boards(db);
- db_cache_folders(db);
-
- main_menu_init();
-
logger_printf("[db] Updating username cache");
user_cache_usernames();
if (db->config.ipdb_path[0])
db->ipdb = ipdb_open(db->config.ipdb_path);
+ db_cache_views(db);
+ db_cache_boards(db);
+ db_cache_folders(db);
+
binkp_init();
telnet_init();
serial_init();
@@ -345,34 +348,8 @@ handle_menu(long menu_id)
case BBS_MENU_OPEN_CONSOLE_ID:
console_init();
break;
- case BBS_MENU_EDIT_MENUS_ID:
- main_menu_edit();
- break;
- }
- ret = true;
- break;
- case VIEWS_SUBMENU_ID:
- switch (LoWord(menu_id)) {
- case VIEWS_SUBMENU_ISSUE_ID:
- view_editor_show(DB_TEXT_ISSUE_ID, "Edit: Pre-login view");
- break;
- case VIEWS_SUBMENU_MAIN_MENU_ID:
- view_editor_show(DB_TEXT_MENU_ID, "Edit: Main menu");
- break;
- case VIEWS_SUBMENU_SHORT_MENU_ID:
- view_editor_show(DB_TEXT_SHORTMENU_ID, "Edit: Short menu");
- break;
- case VIEWS_SUBMENU_SIGNUP_ID:
- view_editor_show(DB_TEXT_SIGNUP_ID, "Edit: Signup view");
- break;
- case VIEWS_SUBMENU_PAGE_SYSOP_ID:
- view_editor_show(DB_TEXT_PAGE_SYSOP_ID, "Edit: Page Sysop view");
- break;
- case VIEWS_SUBMENU_NO_FREE_NODES_ID:
- view_editor_show(DB_TEXT_NO_FREE_NODES_ID, "Edit: No Free Nodes view");
- break;
- case VIEWS_SUBMENU_SIGNOFF_ID:
- view_editor_show(DB_TEXT_SIGNOFF_ID, "Edit: Session Signoff view");
+ case BBS_MENU_RELOAD_VIEWS_ID:
+ db_cache_views(db);
break;
}
ret = true;
--- main_menu.c Thu Apr 6 17:02:59 2023
+++ main_menu.c Tue Nov 28 09:39:27 2023
@@ -19,60 +19,11 @@
#include "subtext.h"
#include "db.h"
+#include "logger.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;
- 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);
- if (menu == NULL)
- panic("No memory for main menu");
- 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);
- xfree(&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)
{
@@ -130,7 +81,8 @@ main_menu_parse(char *opts, size_t len)
}
}
if (action[0] == '\0') {
- warn("Error on line %ld: no action found", linenum);
+ logger_printf("[views] Error parsing main_menu.txt on line "
+ "%ld: no action found", linenum);
ret_count = 0;
break;
}
@@ -187,8 +139,8 @@ main_menu_parse(char *opts, size_t len)
else if (strcmp(action, "WHOS_ONLINE") == 0)
actionid = ACTION_WHOS_ONLINE;
else {
- warn("Error on line %ld: invalid action \"%s\"", linenum,
- action);
+ logger_printf("[views] Error parsing main_menu.txt on line "
+ "%ld: invalid action \"%s\"", linenum, action);
ret_count = 0;
break;
}
@@ -205,8 +157,8 @@ main_menu_parse(char *opts, size_t len)
}
/* 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);
+ logger_printf("[views] Error parsing main_menu.txt on line "
+ "%ld: Menu Key can only be 1 character", linenum);
ret_count = 0;
break;
}
@@ -222,15 +174,15 @@ main_menu_parse(char *opts, size_t len)
}
}
if (all_keys[0] == '\0') {
- warn("Error on line %ld: All Keys field cannot be empty",
- linenum);
+ 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') {
- warn("Error on line %ld: Label cannot be empty",
- linenum);
+ logger_printf("[views] Error parsing main_menu.txt on line "
+ "%ld: Label cannot be empty", linenum);
ret_count = 0;
break;
}
--- main_menu.h Thu Apr 6 17:03:16 2023
+++ main_menu.h Tue Nov 28 09:40:29 2023
@@ -59,8 +59,6 @@ struct main_menu_option {
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 Fri Nov 17 14:04:55 2023
+++ session.c Mon Nov 27 21:19:34 2023
@@ -162,7 +162,7 @@ session_run(struct uthread *uthread, void *arg)
}
}
- session_output_view_or_printf(s, DB_TEXT_ISSUE_ID,
+ session_output_view_or_printf(s, DB_VIEW_ISSUE,
"\r\nWelcome to %s (%s)\r\n\r\n", db->config.name, s->node);
session_flush(s);
uthread_yield();
@@ -323,7 +323,7 @@ get_another_char:
folder_list(s);
break;
case ACTION_GOODBYE:
- session_output_view_or_printf(s, DB_TEXT_SIGNOFF_ID,
+ session_output_view_or_printf(s, DB_VIEW_SIGNOFF,
"Goodbye!\r\n");
session_flush(s);
done = true;
@@ -459,10 +459,10 @@ session_print_menu(struct session *session, bool short
char *output = NULL;
if (short_menu && session_output_view_or_printf(session,
- DB_TEXT_SHORTMENU_ID, NULL) != 0)
+ DB_VIEW_SHORTMENU, NULL) != 0)
return;
- if (session_output_view_or_printf(session, DB_TEXT_MENU_ID, NULL) != 0)
+ if (session_output_view_or_printf(session, DB_VIEW_MENU, NULL) != 0)
return;
for (i = 0; ; i++) {
@@ -786,16 +786,11 @@ session_output_view_or_printf(struct session *session,
const char *format, ...)
{
size_t size;
- struct bile_object *o;
- char *view, *output;
+ char *output;
va_list ap;
/* can't use bile_read_alloc because we need to null terminate */
- o = bile_find(db->bile, DB_TEXT_TYPE, id);
- if (o == NULL || o->size == 0) {
- if (o)
- xfree(&o);
-
+ if (db->views[id] == NULL || strlen(db->views[id]) == 0) {
if (format == NULL)
return 0;
@@ -806,24 +801,12 @@ session_output_view_or_printf(struct session *session,
return size;
}
- view = xmalloc(o->size + 1);
- if (view == NULL) {
- xfree(&o);
+ size = session_expand_template(session, db->views[id], &output);
+ if (!size)
return 0;
- }
- size = bile_read_object(db->bile, o, view, o->size);
- view[size] = '\0';
- xfree(&o);
- size = session_expand_template(session, view, &output);
- if (!size) {
- xfree(&view);
- return 0;
- }
-
size = session_output(session, output, size);
xfree(&output);
- xfree(&view);
return size;
}
@@ -1597,7 +1580,7 @@ session_page_sysop(struct session *s)
session_printf(s, "{{B}}Page Sysop{{/B}} "
"(^C to cancel)\r\n"
"{{B}}-------------------------{{/B}}\r\n");
- session_output_view_or_printf(s, DB_TEXT_PAGE_SYSOP_ID,
+ session_output_view_or_printf(s, DB_VIEW_PAGE_SYSOP,
"(Instructions missing)\r\n");
session_flush(s);
--- settings.c Fri Nov 17 12:08:22 2023
+++ settings.c Mon Nov 27 22:00:57 2023
@@ -24,25 +24,8 @@
#include "main_menu.h"
#include "settings.h"
#include "tcp.h" /* for long2ip/ip2long */
-#include "tetab.h"
#include "util.h"
-struct view_editor {
- WindowPtr win;
- size_t view_id;
- TEHandle te;
- ControlHandle vert_scroller;
- ControlHandle horiz_scroller;
- ControlHandle save_button;
-};
-
-void view_editor_key_down(struct focusable *focusable, EventRecord *event);
-void view_editor_mouse_down(struct focusable *focusable,
- EventRecord *event);
-void view_editor_update(struct focusable *focusable, EventRecord *event);
-void view_editor_close(struct focusable *focusable, EventRecord *event);
-void view_editor_save(struct focusable *focusable, EventRecord *event);
-
short
struct_editor(struct session *s, const struct struct_field *fields,
const size_t nfields, const struct session_menu_option *extra_opts,
@@ -342,287 +325,3 @@ done:
}
}
-void
-view_editor_show(size_t id, char *title)
-{
- struct focusable *focusable;
- struct view_editor *view_editor;
- Rect bounds, te_bounds;
- TextStyle style;
- short width, height;
- size_t vsize;
- char *view = NULL;
- short padding = 10;
-
- width = 480;
- height = 250;
-
- bounds.left = (screenBits.bounds.right - screenBits.bounds.left -
- width) / 2;
- bounds.right = bounds.left + width;
- bounds.top = GetMBarHeight() +
- ((screenBits.bounds.bottom - height) / 2);
- bounds.bottom = bounds.top + height;
-
- view_editor = xmalloczero(sizeof(struct view_editor));
- if (view_editor == NULL)
- return;
- view_editor->view_id = id;
-
- CtoPstr(title);
- view_editor->win = NewWindow(0L, &bounds, title, false, noGrowDocProc,
- (WindowPtr)-1L, true, 0);
- PtoCstr(title);
- if (!view_editor->win) {
- warn("Can't create window");
- xfree(&view_editor);
- return;
- }
- SetPort(view_editor->win);
-
- /* add save button */
- TextFont(applFont);
- TextSize(11);
- bounds.left = view_editor->win->portRect.right - padding - 100;
- bounds.right = bounds.left + 100;
- bounds.bottom = view_editor->win->portRect.bottom - padding;
- bounds.top = bounds.bottom - 20;
- view_editor->save_button = NewControl(view_editor->win, &bounds,
- "\pSave", true, 1, 1, 1, pushButProc, 0L);
- if (view_editor->save_button == NULL) {
- warn("Failed to create save button");
- goto fail;
- }
-
- /* add text box */
- bounds.bottom = bounds.top - padding - SCROLLBAR_WIDTH;
- bounds.top = padding;
- bounds.left = padding;
- bounds.right = view_editor->win->portRect.right - SCROLLBAR_WIDTH -
- padding;
- te_bounds = bounds;
- InsetRect(&te_bounds, 2, 2);
- TextFont(monaco);
- TextSize(9);
- view_editor->te = TEStylNew(&te_bounds, &bounds);
- if (view_editor->te == NULL) {
- warn("Failed to create TE");
- goto fail;
- }
- style.tsFont = monaco;
- style.tsSize = 9;
- TESetStyle(doFont | doSize, &style, false, view_editor->te);
- TEAutoView(true, view_editor->te);
- TETabWidth = 8;
- TETabEnable(view_editor->te);
- TEActivate(view_editor->te);
-
- vsize = bile_read_alloc(db->bile, DB_TEXT_TYPE, id, &view);
- if (bile_error(db->bile) == BILE_ERR_NO_MEMORY)
- goto fail;
- if (view) {
- TESetText(view, vsize, view_editor->te);
- HLock(view_editor->te);
- InvalRect(&(*(view_editor->te))->viewRect);
- HUnlock(view_editor->te);
- xfree(&view);
- }
-
- bounds.left = bounds.right;
- bounds.right += SCROLLBAR_WIDTH;
- bounds.bottom++;
- bounds.top--;
- view_editor->vert_scroller = NewControl(view_editor->win, &bounds,
- "\p", true, 1, 1, 1, scrollBarProc, 0L);
- if (view_editor->vert_scroller == NULL) {
- warn("Failed to create scroller");
- goto fail;
- }
-
- bounds.left = (*(view_editor->te))->viewRect.left - 1;
- bounds.right = (*(view_editor->te))->viewRect.right + 1;
- bounds.top = (*(view_editor->te))->viewRect.bottom;
- bounds.bottom = bounds.top + SCROLLBAR_WIDTH;
- view_editor->horiz_scroller = NewControl(view_editor->win, &bounds,
- "\p", true, 1, 1, 1, scrollBarProc, 0L);
- if (view_editor->horiz_scroller == NULL) {
- warn("Failed to create scroller");
- goto fail;
- }
-
- focusable = xmalloczero(sizeof(struct focusable));
- if (focusable == NULL)
- goto fail;
- focusable->win = view_editor->win;
- focusable->cookie = view_editor;
- focusable->key_down = view_editor_key_down;
- focusable->mouse_down = view_editor_mouse_down;
- focusable->update = view_editor_update;
- focusable->close = view_editor_close;
- if (!add_focusable(focusable))
- goto fail;
-
- UpdateScrollbarForTE(view_editor->win, view_editor->vert_scroller,
- view_editor->te, false);
- UpdateScrollbarForTE(view_editor->win, view_editor->horiz_scroller,
- view_editor->te, false);
-
- return;
-
-fail:
- if (focusable)
- xfree(&focusable);
- if (view_editor->te)
- TEDispose(view_editor->te);
- DisposeWindow(view_editor);
- xfree(&view_editor);
-}
-
-void
-view_editor_key_down(struct focusable *focusable, EventRecord *event)
-{
- struct view_editor *view_editor =
- (struct view_editor *)focusable->cookie;
- char k = (event->message & charCodeMask);
-
- if ((event->modifiers & cmdKey) != 0) {
- switch (k) {
- case 'c':
- TECopy(view_editor->te);
- break;
- case 'v':
- TEPaste(view_editor->te);
- break;
- case 'x':
- TECut(view_editor->te);
- break;
- }
- } else
- TEKey(k, view_editor->te);
-
- UpdateScrollbarForTE(view_editor->win, view_editor->vert_scroller,
- view_editor->te, false);
- UpdateScrollbarForTE(view_editor->win, view_editor->horiz_scroller,
- view_editor->te, false);
-}
-
-void
-view_editor_mouse_down(struct focusable *focusable, EventRecord *event)
-{
- struct view_editor *view_editor =
- (struct view_editor *)focusable->cookie;
- Point p;
- ControlHandle control;
- Rect r;
- short val, adj;
-
- p = event->where;
- GlobalToLocal(&p);
-
- r = (*(view_editor->te))->viewRect;
- if (PtInRect(p, &r)) {
- TEClick(p, ((event->modifiers & shiftKey) != 0),
- view_editor->te);
- return;
- }
-
- switch (FindControl(p, view_editor->win, &control)) {
- case inButton:
- if (TrackControl(control, p, 0L)) {
- if (control == view_editor->save_button)
- view_editor_save(focusable, NULL);
- }
- break;
- case inUpButton:
- case inDownButton:
- case inPageUp:
- case inPageDown:
- if (control != view_editor->vert_scroller &&
- control != view_editor->horiz_scroller)
- break;
-
- SetTrackControlTE(view_editor->te);
- TrackControl(control, p, TrackMouseDownInControl);
- break;
- case inThumb:
- val = GetCtlValue(control);
- if (TrackControl(control, p, 0L) == 0)
- break;
- adj = val - GetCtlValue(control);
- if (adj != 0) {
- val -= adj;
- if (control == view_editor->vert_scroller)
- TEScroll(0, adj * TEGetHeight(0, 0, view_editor->te),
- view_editor->te);
- else if (control == view_editor->horiz_scroller)
- TEScroll(adj * TEGetWidth(0, view_editor->te), 0,
- view_editor->te);
- SetCtlValue(control, val);
- }
- break;
- }
-}
-
-void
-view_editor_update(struct focusable *focusable, EventRecord *event)
-{
- struct view_editor *view_editor =
- (struct view_editor *)focusable->cookie;
- Rect r;
-
- r = (*(view_editor->te))->viewRect;
- FillRect(&r, white);
- TEUpdate(&r, view_editor->te);
- InsetRect(&r, -1, -1);
- FrameRect(&r);
-
- UpdtControl(view_editor->win, view_editor->win->visRgn);
-}
-
-void
-view_editor_save(struct focusable *focusable, EventRecord *event)
-{
- struct view_editor *view_editor =
- (struct view_editor *)focusable->cookie;
- size_t len;
-
- HLock(view_editor->te);
- 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 doesn't like zero-sized objects */
- if (len == 0)
- bile_delete(db->bile, DB_TEXT_TYPE, view_editor->view_id,
- BILE_DELETE_FLAG_PURGE);
- else
- 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);
-}
-
-void
-view_editor_close(struct focusable *focusable, EventRecord *event)
-{
- struct view_editor *view_editor =
- (struct view_editor *)focusable->cookie;
-
- TEDispose(view_editor->te);
- destroy_focusable(focusable);
- xfree(&view_editor);
-}
--- settings.h Thu Nov 9 09:22:06 2023
+++ settings.h Mon Nov 27 21:04:22 2023
@@ -49,6 +49,5 @@ short struct_editor(struct session *s, const struct st
const size_t nfields, const struct session_menu_option *extra_opts,
size_t nextra_opts, void *data, size_t dsize, void **result,
char *title, char *prompt);
-void view_editor_show(size_t id, char *title);
#endif
--- signup.c Wed Mar 1 17:05:57 2023
+++ signup.c Mon Nov 27 21:14:30 2023
@@ -37,7 +37,7 @@ signup(struct session *s)
session_printf(s, "{{B}}Create Account{{/B}} "
"(^C to cancel)\r\n"
"{{B}}----------------------------{{/B}}\r\n");
- session_output_view_or_printf(s, DB_TEXT_SIGNUP_ID,
+ session_output_view_or_printf(s, DB_VIEW_SIGNUP,
"[ Signup instructions missing ]\r\n\r\n");
session_flush(s);
--- subtext.h Tue Mar 14 15:22:58 2023
+++ subtext.h Mon Nov 27 21:01:02 2023
@@ -36,18 +36,8 @@
#define EDIT_MENU_PASTE_ID 3
#define BBS_MENU_ID 130
-#define BBS_MENU_VIEWS_ID 1
-#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
-#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 VIEWS_SUBMENU_NO_FREE_NODES_ID 6
-#define VIEWS_SUBMENU_SIGNOFF_ID 7
+#define BBS_MENU_RELOAD_VIEWS_ID 1
+#define BBS_MENU_OPEN_CONSOLE_ID 3
#define MENU_DEFAULTS_ID 128
--- sysop.c Thu Nov 16 13:12:20 2023
+++ sysop.c Tue Nov 28 10:07:43 2023
@@ -48,12 +48,13 @@ sysop_menu(struct session *s)
{ 'f', "Ff", "Manage file folders" },
{ 'u', "Uu", "Manage users" },
{ 's', "Ss", "Change BBS settings" },
+ { 'v', "Vv", "Reload views" },
{ 'r', "Rr", "Reboot system" },
{ 'q', "QqXx", "Return to main menu" },
{ '?', "?", "List menu options" },
};
static const char prompt_help[] =
- "M:MOTD I:Binkp H:Hang Up B:Boards F:Folders U:Users S:Settings";
+ "M:MOTD I:Binkp H:Hang Up B:Boards F:Folders U:Users S:Settings V:Views";
char c;
bool show_help = true;
bool done = false;
@@ -91,12 +92,6 @@ sysop_menu(struct session *s)
case 'm':
sysop_edit_motd(s);
break;
- case 's':
- sysop_edit_settings(s);
- break;
- case 'u':
- sysop_edit_users(s);
- break;
case 'r': {
IOParam pb;
long m;
@@ -126,6 +121,17 @@ sysop_menu(struct session *s)
ExitToShell();
break;
}
+ case 's':
+ sysop_edit_settings(s);
+ break;
+ case 'u':
+ sysop_edit_users(s);
+ break;
+ case 'v':
+ session_printf(s, "Reloading views...\r\n");
+ session_flush(s);
+ db_cache_views(db);
+ break;
case '?':
show_help = true;
break;
--- telnet.c Wed Nov 22 08:27:30 2023
+++ telnet.c Mon Nov 27 21:17:05 2023
@@ -957,18 +957,19 @@ telnet_print_busy(struct telnet_node *node)
short error;
char *data = NULL;
- if ((len = bile_read_alloc(db->bile, DB_TEXT_TYPE,
- DB_TEXT_NO_FREE_NODES_ID, &data)) == 0) {
- len = snprintf((char *)&node->obuf, sizeof(node->obuf),
- "No free nodes, please call back later.\r\n");
- } else {
+ /* manually print to node without session_output */
+ if (db->views[DB_VIEW_NO_FREE_NODES]) {
+ data = db->views[DB_VIEW_NO_FREE_NODES];
+ len = strlen(data);
for (n = 0, olen = 0; n < len && olen < sizeof(node->obuf) - 1;
n++) {
node->obuf[olen++] = data[n];
if (data[n] == '\r' && data[n + 1] != '\n')
node->obuf[olen++] = '\n';
}
- xfree(&data);
+ } else {
+ len = snprintf((char *)&node->obuf, sizeof(node->obuf),
+ "No free nodes, please call back later.\r\n");
}
node->tcp_wds[0].ptr = (Ptr)&node->obuf;