AmendHub

Download:

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 about 1 year 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;