From c0370d3c9f21b362570d134eedf4b5c45ccaf23c Mon Sep 17 00:00:00 2001
From: "Rob Swindell (on Windows)" <rob@synchro.net>
Date: Mon, 11 Sep 2023 17:53:37 -0700
Subject: [PATCH] Allow JS 'user.editor' and '.shell' to be set for non-users
 (e.g. user #0)

The request from Nightfox and Accession via DOVE-Net was to be able to set
a user's external editor even if there's no user logged-in.

These 2 user class properties in the JS object model were a bit special in
that they *only* wrote to the user database and did not immediately modify
the in-memory copy of the user_t structure, depending on the re-reading of
the user.dat/tab file to re-populate the current user_t structure when needed.
This didn't work if the current user is user #0 (no user).

So, set the current user_t.xedit and user_t.shell accordingly whenever those
JS properties are assigned a value (a string, the appropriate internal code).
---
 src/sbbs3/js_user.c  |  2 ++
 src/sbbs3/scfglib.h  |  2 ++
 src/sbbs3/scfglib1.c | 24 ++++++++++++++++++++++++
 src/sbbs3/userdat.c  | 14 ++------------
 4 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/src/sbbs3/js_user.c b/src/sbbs3/js_user.c
index 0bc0568696..87e774dc58 100644
--- a/src/sbbs3/js_user.c
+++ b/src/sbbs3/js_user.c
@@ -574,9 +574,11 @@ static JSBool js_user_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict,
 			putuserstr(scfg, p->user->number, USER_CURXTRN, str);
 			break;
 		case USER_PROP_XEDIT:
+			p->user->xedit = getxeditnum(scfg, str);
 			putuserstr(scfg, p->user->number, USER_XEDIT, str);
 			break;
 		case USER_PROP_SHELL:
+			p->user->shell = getshellnum(scfg, str);
 			putuserstr(scfg, p->user->number, USER_SHELL, str);
 			break;
 		case USER_PROP_MISC:
diff --git a/src/sbbs3/scfglib.h b/src/sbbs3/scfglib.h
index 36df5f4964..aa3e089d07 100644
--- a/src/sbbs3/scfglib.h
+++ b/src/sbbs3/scfglib.h
@@ -63,6 +63,8 @@ int		getgrpnum_from_name(scfg_t*, const char* name);
 int		getxtrnsec(scfg_t*, const char* code);
 int		getgurunum(scfg_t*, const char* code);
 int		getchatactset(scfg_t*, const char* name);
+int		getxeditnum(scfg_t*, const char* code);
+int		getshellnum(scfg_t*, const char* code);
 
 DLLEXPORT BOOL	is_valid_dirnum(scfg_t*, int);
 DLLEXPORT BOOL	is_valid_libnum(scfg_t*, int);
diff --git a/src/sbbs3/scfglib1.c b/src/sbbs3/scfglib1.c
index d0abdcb375..2daba463ee 100644
--- a/src/sbbs3/scfglib1.c
+++ b/src/sbbs3/scfglib1.c
@@ -791,6 +791,30 @@ int getchatactset(scfg_t* cfg, const char* name)
 	return i;
 }
 
+// Returns 0 (internal editor) or 1-based external editor index
+int getxeditnum(scfg_t* cfg, const char* code)
+{
+	int i;
+
+	for(i = 0; i < cfg->total_xedits; ++i) {
+		if(stricmp(cfg->xedit[i]->code, code) == 0)
+			return i + 1;
+	}
+	return 0;
+}
+
+// Returns 0 (first shell) if shell code isn't valid
+int getshellnum(scfg_t* cfg, const char* code)
+{
+	int i;
+
+	for(i = 0; i < cfg->total_shells; ++i) {
+		if(stricmp(cfg->shell[i]->code, code) == 0)
+			return i;
+	}
+	return 0;
+}
+
 BOOL is_valid_dirnum(scfg_t* cfg, int dirnum)
 {
 	return (dirnum >= 0) && (cfg != NULL) && (dirnum < cfg->total_dirs);
diff --git a/src/sbbs3/userdat.c b/src/sbbs3/userdat.c
index cbc10bd805..81b1d7b0b8 100644
--- a/src/sbbs3/userdat.c
+++ b/src/sbbs3/userdat.c
@@ -419,18 +419,8 @@ int parseuserdat(scfg_t* cfg, char *userdat, user_t *user, char* field[])
 	user->rows = strtoul(field[USER_ROWS], NULL, 0);
 	user->cols = strtoul(field[USER_COLS], NULL, 0);
 
-	for(int i = 0; i < cfg->total_xedits; i++) {
-		if(stricmp(field[USER_XEDIT], cfg->xedit[i]->code) == 0) {
-			user->xedit = i + 1;
-			break;
-		}
-	}
-	for(int i=0; i < cfg->total_shells; i++) {
-		if(stricmp(field[USER_SHELL], cfg->shell[i]->code) == 0) {
-			user->shell = i;
-			break;
-		}
-	}
+	user->xedit = getxeditnum(cfg, field[USER_XEDIT]);
+	user->shell = getshellnum(cfg, field[USER_SHELL]);
 
 	SAFECOPY(user->tmpext, field[USER_TMPEXT]);
 	user->prot = *field[USER_PROT];
-- 
GitLab