diff --git a/src/sbbs3/js_socket.c b/src/sbbs3/js_socket.c
index 7a2b24b8f39d04acecf1abd8443ea18d3c49ee17..6807402eaf1f76cc3669ea1495bec59d28619cf7 100644
--- a/src/sbbs3/js_socket.c
+++ b/src/sbbs3/js_socket.c
@@ -203,6 +203,9 @@ static BOOL js_socket_peek_byte(js_socket_private_t *p)
 	return FALSE;
 }
 
+/* Returns > 0 upon successful data received (even if there was an error or disconnection) */
+/* Returns -1 upon error (and no data received) */
+/* Returns 0 upon timeout or disconnection (and no data received) */
 static ptrdiff_t js_socket_recv(js_socket_private_t *p, void *buf, size_t len, int flags, int timeout)
 {
 	ptrdiff_t	total=0;
@@ -1332,6 +1335,10 @@ js_peek(JSContext *cx, uintN argc, jsval *arglist)
 	return(JS_TRUE);
 }
 
+/* Returns 0 if there is rx data waiting */
+/* Returns 1 if the 'timeout' period has elapsed (with no data waiting) */
+/* Returns 2 if the socket has been disconnected (regardless of any data waiting) */
+/* Returns 3 if there was no rx data waiting and the 'timeout' period has not yet elapsed */
 static int
 js_sock_read_check(js_socket_private_t *p, time_t start, int32 timeout, int i)
 {
@@ -1344,9 +1351,6 @@ js_sock_read_check(js_socket_private_t *p, time_t start, int32 timeout, int i)
 
 	if(!socket_check(p->sock,&rd,NULL,1000)) {
 		p->last_error=ERROR_VALUE;
-		if(i==0) {
-			return 1;
-		}
 		return 2;
 	}
 
@@ -1360,6 +1364,7 @@ js_sock_read_check(js_socket_private_t *p, time_t start, int32 timeout, int i)
 	return 0;
 }
 
+/* This method is to return null on error/timeout, not void/undefined */
 static JSBool
 js_recvline(JSContext *cx, uintN argc, jsval *arglist)
 {
@@ -1375,7 +1380,7 @@ js_recvline(JSContext *cx, uintN argc, jsval *arglist)
 	js_socket_private_t*	p;
 	jsrefcount	rc;
 
-	JS_SET_RVAL(cx, arglist, JSVAL_VOID);
+	JS_SET_RVAL(cx, arglist, JSVAL_NULL);
 
 	if((p=(js_socket_private_t*)JS_GetPrivate(cx,obj))==NULL) {
 		JS_ReportError(cx,getprivate_failure,WHERE);
@@ -1398,34 +1403,30 @@ js_recvline(JSContext *cx, uintN argc, jsval *arglist)
 	for(i=0;i<len;) {
 		if(p->session==-1) {
 			switch(js_sock_read_check(p,start,timeout,i)) {
-				case 1:
-					JS_SET_RVAL(cx, arglist, JSVAL_NULL);
+				case 1:	// time-out */
+				case 2: // disconnected
+					if(i) {		// some data was received before the error/disconnection
+						len=0;	// so break the loop
+						continue;
+					}
+					// no data received, so just return null
 					JS_RESUMEREQUEST(cx, rc);
 					free(buf);
-					return(JS_TRUE);	/* time-out */
-				case 2:
-					len=0;
-					continue;
-				case 3:
+					return JS_TRUE;
+				case 3:	// no data and no time-out... yet
 					continue;
 			}
 		}
 
 		if((got=js_socket_recv(p, &ch, 1, 0, i?1:timeout))!=1) {
-			if(p->session==-1) {
-				p->last_error=ERROR_VALUE;
-				break;
-			}
-			else {
-				if (got == 0) {
-					free(buf);
-					return(JS_TRUE);	/* time-out */
-				}
-				if (got == -1) {
-					len = 0;
-					continue;
-				}
+			if(p->session == -1)
+				p->last_error = ERROR_VALUE;
+			if (i == 0) {			// no data received
+				JS_RESUMEREQUEST(cx, rc);
+				free(buf);			// so return null (not an empty string)
+				return(JS_TRUE);
 			}
+			break;
 		}
 
 		if(ch=='\n' /* && i>=1 */) /* Mar-9-2003: terminate on sole LF */