jcs
/subtext
/amendments
/179
*: Hook up folders
jcs made amendment 179 over 2 years ago
--- board.c Tue Jun 28 10:06:12 2022
+++ board.c Thu Jun 30 15:42:11 2022
@@ -162,6 +162,10 @@ board_show(struct session *s, short id)
while (!done && !s->ending) {
if (find_post_ids) {
+ if (post_ids != NULL) {
+ free(post_ids);
+ post_ids = NULL;
+ }
nall_post_ids = board_find_post_ids(board, &npost_ids,
&post_ids, page * POSTS_PER_PAGE, POSTS_PER_PAGE);
/* ceil(nall_post_ids / POSTS_PER_PAGE) */
@@ -249,6 +253,9 @@ handle_opt:
break;
}
}
+
+ if (post_ids != NULL)
+ free(post_ids);
}
void
@@ -519,7 +526,7 @@ board_post_read(struct session *s, struct board *board
struct board_post post;
struct username_cache *sender, *recipient;
unsigned long new_id;
- char prompt[DB_BOARD_NAME_LENGTH + 8];
+ char prompt[BOARD_NAME_LENGTH + 8];
size_t n, size;
short ret = POST_READ_RETURN_DONE;
char c;
@@ -661,6 +668,8 @@ board_find_post_ids(struct board *board, size_t *npost
for (n = 0; o = bile_get_nth_of_type(board->bile, n,
BOARD_THREAD_RTYPE); n++) {
+ if (n >= nthreads)
+ break;
bile_read_alloc(board->bile, BOARD_THREAD_RTYPE, o->id, &data);
bile_unmarshall_object(board->bile, board_thread_object_fields,
nboard_thread_object_fields, data, o->size, &thread, false);
--- board.h Thu May 26 15:23:00 2022
+++ board.h Thu Jun 30 13:36:04 2022
@@ -19,11 +19,14 @@
#include <stddef.h>
#include "session.h"
+#include "settings.h"
struct board {
unsigned long id;
- char name[DB_BOARD_NAME_LENGTH];
- char description[DB_BOARD_DESCR_LENGTH];
+#define BOARD_NAME_LENGTH 32
+ char name[BOARD_NAME_LENGTH];
+#define BOARD_DESCR_LENGTH 100
+ char description[BOARD_DESCR_LENGTH];
bool restricted_posting;
bool restricted_viewing;
unsigned short retention_days;
--- db.c Wed Jun 22 15:21:14 2022
+++ db.c Wed Jun 29 09:35:09 2022
@@ -22,6 +22,7 @@
#include "board.h"
#include "bile.h"
#include "db.h"
+#include "folder.h"
#include "user.h"
#include "util.h"
@@ -202,6 +203,7 @@ db_init(Str255 path, short vrefnum, struct bile *bile)
if (!was_new) {
db_config_load(tdb);
db_cache_boards(tdb);
+ db_cache_folders(tdb);
}
PtoCstr(fullpath);
@@ -439,7 +441,7 @@ db_cache_boards(struct db *tdb)
for (n = 0; n < tdb->nboards; n++) {
snprintf((char *)board_filename, sizeof(board_filename),
- "%s:%ld.brd", db_filename, tdb->boards[n].id);
+ "%s:%ld.%s", db_filename, tdb->boards[n].id, BOARD_FILENAME_EXT);
CtoPstr(board_filename);
tdb->boards[n].bile = bile_open(board_filename,
tdb->bile->vrefnum);
@@ -496,8 +498,8 @@ db_board_create(struct db *tdb, struct board *board)
panic("getpath failed on %s", PtoCstr(tdb->bile->filename));
PtoCstr(db_filename);
- snprintf((char *)board_filename, sizeof(board_filename), "%s:%ld.brd",
- db_filename, board->id);
+ snprintf((char *)board_filename, sizeof(board_filename), "%s:%ld.%s",
+ db_filename, board->id, BOARD_FILENAME_EXT);
CtoPstr(board_filename);
board_bile = bile_create(board_filename, tdb->bile->vrefnum,
@@ -507,4 +509,120 @@ db_board_create(struct db *tdb, struct board *board)
PtoCstr(board_filename), bile_error(NULL));
return board_bile;
-}
+}
+
+void
+db_cache_folders(struct db *tdb)
+{
+ Str255 db_filename, folder_filename;
+ size_t n, size;
+ struct bile_object *obj;
+ char *data = NULL;
+
+ if (tdb->folders) {
+ for (n = 0; n < tdb->nfolders; n++) {
+ if (tdb->folders[n].bile)
+ bile_close(tdb->folders[n].bile);
+ }
+ free(tdb->folders);
+ }
+
+ if (getpath(tdb->bile->vrefnum, tdb->bile->filename, &db_filename,
+ false) != 0)
+ panic("getpath failed on %s", PtoCstr(tdb->bile->filename));
+ PtoCstr(db_filename);
+
+ tdb->nfolders = bile_count_by_type(tdb->bile, DB_FOLDER_RTYPE);
+ if (!tdb->nfolders)
+ return;
+ tdb->folders = xcalloc(tdb->nfolders, sizeof(struct folder));
+
+ /*
+ * Read ids first so we have a consistent order, then try to open or
+ * fix/recreate each bile, which may change their order in the map
+ */
+ for (n = 0; n < tdb->nfolders; n++) {
+ obj = bile_get_nth_of_type(tdb->bile, n, DB_FOLDER_RTYPE);
+ if (obj == NULL)
+ break;
+
+ size = bile_read_alloc(tdb->bile, DB_FOLDER_RTYPE, obj->id, &data);
+ bile_unmarshall_object(tdb->bile, folder_object_fields,
+ nfolder_object_fields, data, size, (char *)(&tdb->folders[n]),
+ true);
+ free(data);
+ }
+
+ for (n = 0; n < tdb->nfolders; n++) {
+ snprintf((char *)folder_filename, sizeof(folder_filename),
+ "%s:%ld.%s", db_filename, tdb->folders[n].id,
+ FOLDER_FILENAME_EXT);
+ CtoPstr(folder_filename);
+ tdb->folders[n].bile = bile_open(folder_filename,
+ tdb->bile->vrefnum);
+ if (tdb->folders[n].bile != NULL)
+ continue;
+
+ PtoCstr(folder_filename);
+
+ if (bile_error(NULL) != fnfErr &&
+ ask("Attempt recovery of %s with backup map?",
+ folder_filename)) {
+ CtoPstr(folder_filename);
+ tdb->folders[n].bile = bile_open_recover_map(folder_filename,
+ tdb->bile->vrefnum);
+ if (tdb->folders[n].bile == NULL)
+ panic("Failed to recover folder file %s: %d",
+ PtoCstr(folder_filename), bile_error(NULL));
+ continue;
+ }
+
+ if (ask("Failed to open folder bile %s (error %d), recreate it?",
+ folder_filename, bile_error(NULL)) == false)
+ exit(0);
+
+ tdb->folders[n].bile = db_folder_create(tdb, &tdb->folders[n]);
+ if (tdb->folders[n].bile == NULL)
+ panic("Failed to create folder file %s: %d",
+ folder_filename, bile_error(NULL));
+ }
+}
+
+struct bile *
+db_folder_create(struct db *tdb, struct folder *folder)
+{
+ Str255 db_filename, folder_filename;
+ struct bile *folder_bile;
+ size_t size;
+ short ret;
+ char *data;
+
+ ret = bile_marshall_object(tdb->bile, folder_object_fields,
+ nfolder_object_fields, folder, &data, &size);
+ if (ret != 0 || size == 0) {
+ warn("db_folder_create: failed to marshall object");
+ return;
+ }
+
+ if (bile_write(tdb->bile, DB_FOLDER_RTYPE, folder->id, data,
+ size) != size)
+ panic("save of new folder failed: %d", bile_error(tdb->bile));
+ free(data);
+
+ if (getpath(tdb->bile->vrefnum, tdb->bile->filename, &db_filename,
+ false) != 0)
+ panic("getpath failed on %s", PtoCstr(tdb->bile->filename));
+ PtoCstr(db_filename);
+
+ snprintf((char *)folder_filename, sizeof(folder_filename),
+ "%s:%ld.%s", db_filename, folder->id, FOLDER_FILENAME_EXT);
+ CtoPstr(folder_filename);
+
+ folder_bile = bile_create(folder_filename, tdb->bile->vrefnum,
+ SUBTEXT_CREATOR, DB_FOLDER_RTYPE);
+ if (folder_bile == NULL)
+ panic("Failed creating new folder bile at %s: %d",
+ PtoCstr(folder_filename), bile_error(NULL));
+
+ return folder_bile;
+}
--- db.h Wed Jun 22 15:42:33 2022
+++ db.h Thu Jun 30 13:22:19 2022
@@ -31,7 +31,7 @@
#define DB_CONFIG_RTYPE 'CONF'
#define DB_USER_RTYPE 'USER'
#define DB_BOARD_RTYPE 'BORD'
-#define DB_FILEAREA_RTYPE 'FILA'
+#define DB_FOLDER_RTYPE 'FOLD'
#define DB_VERS_RTYPE 'VERS'
#define DB_MESSAGE_RTYPE 'PMSG'
@@ -43,20 +43,23 @@
#define DB_TEXT_PAGE_SYSOP_ID 5
#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'
#define SL_TALLY_RTYPE 'STLY'
+#define BOARD_FILENAME_EXT "brd"
#define BOARD_THREAD_RTYPE 'BDTH'
#define BOARD_POST_RTYPE 'BDPS'
+#define FOLDER_FILENAME_EXT "fld"
+#define FOLDER_FILE_RTYPE 'FILE'
+
#include "subtext.h"
-#include "settings.h"
#include "bile.h"
-#include "sha2.h"
+#include "board.h"
+#include "folder.h"
+#include "settings.h"
struct config {
char name[32];
@@ -87,6 +90,8 @@ struct db {
struct bile *sessions_bile;
struct board *boards;
short nboards;
+ struct folder *folders;
+ short nfolders;
};
struct db * db_open(Str255 file, short vrefnum);
@@ -95,5 +100,7 @@ void db_close(struct db *tdb);
void db_config_save(struct db *tdb);
void db_cache_boards(struct db *tdb);
struct bile * db_board_create(struct db *tdb, struct board *board);
+void db_cache_folders(struct db *tdb);
+struct bile * db_folder_create(struct db *tdb, struct folder *folder);
#endif
--- session.c Fri Jun 24 16:25:05 2022
+++ session.c Wed Jun 29 11:22:41 2022
@@ -22,6 +22,7 @@
#include "ansi.h"
#include "board.h"
#include "chat.h"
+#include "folder.h"
#include "mail.h"
#include "subtext.h"
#include "session.h"
@@ -208,8 +209,7 @@ get_another_char:
case 'f':
case 'F':
/* files */
- session_printf(s, "Coming soon!\r\n");
- session_flush(s);
+ folder_list(s);
break;
case 'g':
case 'G':
@@ -1183,7 +1183,7 @@ session_pause_return(struct session *s, short enforce,
{
unsigned char c;
- session_output_template(s, "{{/B}}Press {{B}}<Enter>{{/B}} ");
+ session_printf(s, "{{/B}}Press {{B}}<Enter>{{/B}} ");
if (msg)
session_printf(s, msg);
else
--- sysop.c Wed Jun 8 10:31:15 2022
+++ sysop.c Tue Jun 28 11:33:14 2022
@@ -25,6 +25,7 @@
#define USERS_PER_PAGE 10
void sysop_edit_boards(struct session *s);
+void sysop_edit_folders(struct session *s);
void sysop_edit_users(struct session *s);
size_t sysop_find_user_ids(size_t nall_user_ids,
unsigned long *all_user_ids, unsigned long **user_ids, size_t offset,
@@ -36,6 +37,7 @@ sysop_menu(struct session *s)
{
static struct session_menu_option opts[] = {
{ 'b', "Bb", "Manage Boards" },
+ { 'f', "Ff", "Manage File Folders" },
{ 'u', "Uu", "Manage Users" },
{ 's', "Ss", "Change BBS Settings" },
{ 'q', "QqXx", "Return to main menu" },
@@ -59,6 +61,9 @@ sysop_menu(struct session *s)
case 'b':
sysop_edit_boards(s);
break;
+ case 'f':
+ sysop_edit_folders(s);
+ break;
case 's':
sysop_edit_settings(s);
break;
@@ -207,6 +212,127 @@ sysop_edit_boards(struct session *s)
}
if (!found) {
session_printf(s, "Invalid board ID\r\n");
+ session_flush(s);
+ }
+ break;
+ case '?':
+ show_help = true;
+ break;
+ default:
+ done = true;
+ break;
+ }
+ }
+}
+
+void
+sysop_edit_folders(struct session *s)
+{
+ static struct session_menu_option opts[] = {
+ { 'n', "Nn", "Create new folder" },
+ { 'q', "QqXx", "Return to sysop menu" },
+ { '?', "?", "List menu options" },
+ };
+ char prompt[30];
+ struct session_menu_option *dopts = NULL, *opt;
+ struct folder *folder, *new_folder;
+ struct bile *new_folder_bile;
+ size_t n, size;
+ short ret;
+ char c, *data = NULL;
+ bool show_help = true;
+ bool done = false;
+ bool found = false;
+
+ while (!done && !s->ending) {
+ /*
+ * Unfortunately we have to do this every iteration because the
+ * list of boards may change
+ */
+ if (dopts != NULL)
+ free(dopts);
+ dopts = xmalloc(sizeof(opts) +
+ (db->nboards * sizeof(struct session_menu_option)));
+ for (n = 0; n < db->nfolders; n++) {
+ folder = &db->folders[n];
+ opt = &dopts[n];
+ opt->ret = '0' + folder->id;
+ opt->key[0] = '0' + folder->id;
+ opt->key[1] = '\0';
+ strlcpy(opt->title, folder->name, sizeof(opts[0].title));
+ }
+ memcpy(&dopts[db->nfolders], opts, sizeof(opts));
+
+ c = session_menu(s, "Folder Editor", "Sysop:Folders", dopts,
+ nitems(opts) + db->nfolders, show_help);
+ show_help = false;
+
+ switch (c) {
+ case 'n':
+ folder = xmalloczero(sizeof(struct folder));
+ folder->id = bile_next_id(db->bile, DB_FOLDER_RTYPE);
+ folder->restricted_posting = false;
+ folder->restricted_viewing = false;
+ ret = struct_editor(s, folder_fields, nfolder_fields,
+ folder, sizeof(struct folder), (void *)&new_folder,
+ "New Folder", "Sysop:Folders:New");
+ if (ret != 0) {
+ free(folder);
+ continue;
+ }
+
+ new_folder_bile = db_folder_create(db, new_folder);
+ bile_close(new_folder_bile);
+ db_cache_folders(db);
+
+ session_log(s, "Created new folder %ld: %s", new_folder->id,
+ new_folder->name);
+ free(folder);
+ free(new_folder);
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ found = false;
+ for (n = 0; n < db->nfolders; n++) {
+ folder = &db->folders[n];
+ if (folder->id != c - '0')
+ continue;
+ found = true;
+ snprintf(prompt, sizeof(prompt), "Sysop:Folders:%ld",
+ folder->id);
+ ret = struct_editor(s, folder_fields, nfolder_fields,
+ folder, sizeof(struct folder), (void *)&new_folder,
+ "Edit Folder", prompt);
+ if (ret != 0)
+ continue;
+ memcpy(&db->folders[n], new_folder, sizeof(struct folder));
+
+ ret = bile_marshall_object(db->bile, folder_object_fields,
+ nfolder_object_fields, &db->folders[n], &data, &size);
+ if (ret != 0 || size == 0)
+ panic("db_folder_create: failed to marshall object");
+
+ if (bile_write(db->bile, DB_FOLDER_RTYPE, new_folder->id,
+ data, size) != size)
+ panic("save of folder failed: %d",
+ bile_error(db->bile));
+ free(data);
+
+ session_log(s, "Saved changes to folder %ld: %s",
+ new_folder->id, new_folder->name);
+ free(new_folder);
+ break;
+ }
+ if (!found) {
+ session_printf(s, "Invalid folder ID\r\n");
session_flush(s);
}
break;