diff --git a/exec/imapservice.js b/exec/imapservice.js
index 354231ce1046b84f40af7183db4843ea3f9ad935..b0dc0583a73a4f1f3ad6216610679d88549a26ce 100644
--- a/exec/imapservice.js
+++ b/exec/imapservice.js
@@ -889,8 +889,7 @@ var unauthenticated_command_handlers = {
 				client.socket.send("+\r\n");
 				line=client.socket.recvline(10240, 1800);
 				args=base64_decode(line).split(/\x00/);
-				if(!login(args[1],args[2])) {
-//					log(LOG_INFO, format("Attempted login: '%s', pw: '%s'", args[1], args[2]));
+				if(args === null || (!login(args[1],args[2]))) {
 					tagged(tag, "NO", "No AUTH for you.");
 					return;
 				}
diff --git a/exec/lbshell.js b/exec/lbshell.js
index d126eb92a0ce85e8b86d7792431200aec536ad74..5cdfff818a51148201eb06da2688c9d407c3f69f 100644
--- a/exec/lbshell.js
+++ b/exec/lbshell.js
@@ -707,6 +707,10 @@ while(bbs.online) {
 						handle_a_ctrlkey(x_prog);
 						continue;
 					}
+					if (xtrn_area.sec_list[curr_xtrnsec].prog_list[parseInt(x_prog)].number === undefined) {
+						console.beep();
+						continue;
+					}
 					stop_mouse();
 					clear_screen();
 
diff --git a/exec/letsyncrypt.js b/exec/letsyncrypt.js
index 7c47b521fe92a93dc0fe69cd8039577cdb0166a6..a9f5b6752940ffd6a986e973e40aa3a67296eb0f 100644
--- a/exec/letsyncrypt.js
+++ b/exec/letsyncrypt.js
@@ -7,7 +7,7 @@ var ks_fname = backslash(system.ctrl_dir)+"letsyncrypt.key";
 var setting_fname = backslash(system.ctrl_dir)+"letsyncrypt.ini";
 var sks_fname = backslash(system.ctrl_dir)+"ssl.cert";
 var maincnf_fname = backslash(system.ctrl_dir)+"main.cnf";
-var recycle_sem = backslash(system.ctrl_dir)+"recycle.web";
+var recycle_sem = backslash(system.ctrl_dir)+"recycle";
 
 function at_least_a_third()
 {
diff --git a/src/sbbs3/js_socket.c b/src/sbbs3/js_socket.c
index 8426006c8cde4df3077e372ead62a4a851620c89..10e168177beacbaec882651bcc778973062934bc 100644
--- a/src/sbbs3/js_socket.c
+++ b/src/sbbs3/js_socket.c
@@ -337,8 +337,12 @@ static ptrdiff_t js_socket_sendsocket(js_socket_private_t *p, const void *msg, s
 	int copied=0,ret;
 	char *estr;
 
-	if(p->session==-1)
+	if(p->session==-1) {
+		BOOL wr = FALSE;
+		if(!socket_check(p->sock, NULL, &wr, 0) || !wr)
+			return 0;
 		return sendsocket(p->sock, msg, len);
+	}
 	do {
 		// If we don't limit this, we occasionally get errors on large sends...
 		if((ret=cryptPushData(p->session, msg, len > 0x2000 ? 0x2000 : len, &copied))==CRYPT_OK) {
diff --git a/src/sbbs3/xtrn.cpp b/src/sbbs3/xtrn.cpp
index 3a581519a76926d31eaefbdcb0b09f06ddd7c7f7..70f651cdb80b27aecedab367a47fe7bae43380cc 100644
--- a/src/sbbs3/xtrn.cpp
+++ b/src/sbbs3/xtrn.cpp
@@ -1847,14 +1847,23 @@ int sbbs_t::external(const char* cmdline, long mode, const char* startup_dir)
 
 		if(waitpid(pid, &i, WNOHANG)==0)  {		// Child still running?
 			kill(pid, SIGHUP);					// Tell child user has hung up
-			time_t start=time(NULL);			// Wait up to 10 seconds
-			while(time(NULL)-start<10) {		// for child to terminate
+			time_t start=time(NULL);			// Wait up to 5 seconds
+			while(time(NULL)-start<5 ) {		// for child to terminate
 				if(waitpid(pid, &i, WNOHANG)!=0)
 					break;
 				mswait(500);
 			}
-			if(waitpid(pid, &i, WNOHANG)==0)	// Child still running?
-				kill(pid, SIGKILL);				// terminate child process
+			if(waitpid(pid, &i, WNOHANG)==0) {	// Child still running?
+				kill(pid, SIGTERM);				// terminate child process (gracefully)
+				start=time(NULL);				// Wait up to 5 (more) seconds
+				while(time(NULL)-start<5 ) {	// for child to terminate
+					if(waitpid(pid, &i, WNOHANG)!=0)
+						break;
+					mswait(500);
+				}
+				if(waitpid(pid, &i, WNOHANG)==0)// Child still running?
+					kill(pid, SIGKILL);			// terminate child process (ungracefully)
+			}
 		}
 		/* close unneeded descriptors */
 		if(mode&EX_STDIN)
diff --git a/xtrn/DDMsgReader/DDMsgReader.js b/xtrn/DDMsgReader/DDMsgReader.js
index 69386fe2d802741989dc6c13a329f2048119039c..82bb36807c5caeeb0f6a2be0964fac6d8bebc880 100644
--- a/xtrn/DDMsgReader/DDMsgReader.js
+++ b/xtrn/DDMsgReader/DDMsgReader.js
@@ -53,6 +53,9 @@
  *                              honors the system setting for whether users can view deleted messages.
  * 2022-08-06 Eric Oulashin     Version 1.54
  *                              Users now have a personal twit list (configurable via Ctrl-U, user settings).
+ * 2022-09-23 Eric Oulashin     Version 1.55
+ *                              Refactored how email replies are done (passing the header to the appropriate
+ *                              functions, not using ungetstr() when prompting for the message subject)
  */
 
 "use strict";
@@ -157,8 +160,8 @@ var ansiterm = require("ansiterm_lib.js", 'expand_ctrl_a');
 
 
 // Reader version information
-var READER_VERSION = "1.54";
-var READER_DATE = "2022-08-06";
+var READER_VERSION = "1.55";
+var READER_DATE = "2022-09-23";
 
 // Keyboard key codes for displaying on the screen
 var UP_ARROW = ascii(24);
@@ -7769,7 +7772,7 @@ function DigDistMsgReader_SetMsgListPauseTextAndLightbarHelpLine()
 	                           + this.colors.lightbarMsgListHelpLineHotkeyColor + "@`Q`Q@"
 							   + this.colors.lightbarMsgListHelpLineParenColor + ")"
 	                           + this.colors.lightbarMsgListHelpLineGeneralColor + "uit, "
-	                           + this.colors.lightbarMsgListHelpLineHotkeyColor + "?  ";
+							   + this.colors.lightbarMsgListHelpLineHotkeyColor + "@`?`?@  ";
 	lbHelpLineLen += 15;
 
 	// Add spaces to the end of sLightbarModeHelpLine up until one char
@@ -9891,19 +9894,20 @@ function DigDistMsgReader_DoPrivateReply(pMsgHdr, pMsgIdx, pReplyMode)
 			// message header.  Otherwise (i.e., on a networked sub-board), use
 			// username@from_net_addr.
 			var emailAddr = "";
-			if (pMsgHdr.from_net_type == NET_INTERNET)
-				emailAddr = pMsgHdr.from_net_addr;
-			else
-				emailAddr = pMsgHdr.from + "@" + pMsgHdr.from_net_addr;
+			if (typeof(pMsgHdr.from_net_addr) === "string" && pMsgHdr.from_net_addr.length > 0)
+			{
+				if (pMsgHdr.from_net_type == NET_INTERNET)
+					emailAddr = pMsgHdr.from_net_addr;
+				else
+					emailAddr = pMsgHdr.from + "@" + pMsgHdr.from_net_addr;
+			}
 			// Prompt the user to verify the receiver's email address
 			console.putmsg(bbs.text(Email), P_SAVEATR);
-			console.ungetstr(emailAddr);
-			emailAddr = console.getstr(60, K_LINE);
+			emailAddr = console.getstr(emailAddr, 60, K_LINE|K_EDIT);
 			if ((typeof(emailAddr) == "string") && (emailAddr.length > 0))
 			{
 				replyMode |= WM_NETMAIL;
-				console.ungetstr(pMsgHdr.subject);
-				retObj.sendSucceeded = bbs.netmail(emailAddr, replyMode);
+				retObj.sendSucceeded = bbs.netmail(emailAddr, replyMode, null, pMsgHdr);
 				console.pause();
 			}
 			else
@@ -9927,7 +9931,7 @@ function DigDistMsgReader_DoPrivateReply(pMsgHdr, pMsgIdx, pReplyMode)
 			// sender.  Note that if the send failed, that could be because the
 			// user aborted the message.
 			console.crlf();
-			retObj.sendSucceeded = bbs.email(userNumber, replyMode, "", pMsgHdr.subject);
+			retObj.sendSucceeded = bbs.email(userNumber, replyMode, null, null, pMsgHdr);
 			console.pause();
 		}
 		else
diff --git a/xtrn/DDMsgReader/readme.txt b/xtrn/DDMsgReader/readme.txt
index 82ba8ee50728bd48259b780ce79c448a69bbd0a8..1fc31cc95344019e0ffe57e121549ee51c2c7d36 100644
--- a/xtrn/DDMsgReader/readme.txt
+++ b/xtrn/DDMsgReader/readme.txt
@@ -1,6 +1,6 @@
                       Digital Distortion Message Reader
-                                 Version 1.54
-                           Release date: 2022-08-06
+                                 Version 1.55
+                           Release date: 2022-09-23
 
                                      by
 
diff --git a/xtrn/DDMsgReader/revision_history.txt b/xtrn/DDMsgReader/revision_history.txt
index 27ba8f5198418084e53a9c7773d48578122d11d2..e139d9dd951d5104137aa7629e620e465f5d5e76 100644
--- a/xtrn/DDMsgReader/revision_history.txt
+++ b/xtrn/DDMsgReader/revision_history.txt
@@ -5,6 +5,9 @@ Revision History (change log)
 =============================
 Version  Date         Description
 -------  ----         -----------
+1.55     2022-09-23   Refactored how email replies are done (passing the header
+                      to the appropriate functions, not using ungetstr() when
+                      prompting for the message subject)
 1.54     2022-08-06   Users now have a personal twit list, configurable via
                       user settings, with the Ctrl-U hotkey.
 1.53     2022-07-18   Deleted messages can now be un-marked for deletion from