diff --git a/src/sbbs3/userdat.c b/src/sbbs3/userdat.c
index e1ce249401eb609de76e0cdd87f269af0b9ff85c..5a783de9f972cdb594d352cf6aa551f0224e2280 100644
--- a/src/sbbs3/userdat.c
+++ b/src/sbbs3/userdat.c
@@ -193,34 +193,45 @@ BOOL DLLCALL del_lastuser(scfg_t* cfg)
 	return(TRUE);
 }
 
-
 /****************************************************************************/
-/* Fills the structure 'user' with info for user.number	from user.dat		*/
-/* Called from functions useredit, waitforcall and main_sec					*/
+/* Opens the user database returning the file descriptor or -1 on error		*/
 /****************************************************************************/
-int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
+int DLLCALL openuserdat(scfg_t* cfg)
 {
-	char userdat[U_LEN+1],str[U_LEN+1];
-	int i,file;
-	unsigned user_number;
+	char path[MAX_PATH+1];
 
-	if(user==NULL)
-		return(-1);
+	if(!VALID_CFG(cfg))
+		return(-1); 
 
-	user_number=user->number;
-	memset(user,0,sizeof(user_t));
+	SAFEPRINTF(path,"%suser/user.dat",cfg->data_dir);
+	return nopen(path,O_RDONLY|O_DENYNONE); 
+}
+
+/****************************************************************************/
+/* Locks and reads a single user record from an open user.dat file into a	*/
+/* buffer of U_LEN+1 in size.												*/
+/* Returns 0 on success.													*/
+/****************************************************************************/
+int DLLCALL readuserdat(scfg_t* cfg, unsigned user_number, char* userdat, int infile)
+{
+	int i,file;
 
 	if(!VALID_CFG(cfg) || user_number<1)
 		return(-1); 
 
-	SAFEPRINTF(userdat,"%suser/user.dat",cfg->data_dir);
-	if((file=nopen(userdat,O_RDONLY|O_DENYNONE))==-1)
-		return(errno); 
+	if(infile > 0)
+		file = infile;
+	else {
+		if((file = openuserdat(cfg)) < 0)
+			return file;
+	}
 
 	if(user_number > (unsigned)(filelength(file)/U_LEN)) {
-		close(file);
+		if(file != infile)
+			close(file);
 		return(-1);	/* no such user record */
 	}
+
 	lseek(file,(long)((long)(user_number-1)*U_LEN),SEEK_SET);
 	i=0;
 	while(i<LOOP_NODEDAB
@@ -229,21 +240,43 @@ int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
 			mswait(100);
 		i++; 
 	}
-
 	if(i>=LOOP_NODEDAB) {
-		close(file);
+		if(file != infile)
+			close(file);
 		return(-2); 
 	}
 
 	if(read(file,userdat,U_LEN)!=U_LEN) {
 		unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
-		close(file);
+		if(file != infile)
+			close(file);
 		return(-3); 
 	}
-
 	unlock(file,(long)((long)(user_number-1)*U_LEN),U_LEN);
-	close(file);
+	if(file != infile)
+		close(file);
+	return 0;
+}
+
+/****************************************************************************/
+/* Fills the structure 'user' with info for user.number	from userdat		*/
+/* (a buffer representing a single user 'record' from the user.dat file		*/
+/****************************************************************************/
+int DLLCALL parseuserdat(scfg_t* cfg, char *userdat, user_t *user)
+{
+	char str[U_LEN+1];
+	int i;
+	unsigned user_number;
+
+	if(user==NULL)
+		return(-1);
+
+	user_number=user->number;
+	memset(user,0,sizeof(user_t));
 
+	if(!VALID_CFG(cfg) || user_number < 1)
+		return(-1); 
+	
 	/* The user number needs to be set here
 	   before calling chk_ar() below for user-number comparisons in AR strings to function correctly */
 	user->number=user_number;	/* Signal of success */
@@ -352,7 +385,6 @@ int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
 
 	getrec(userdat,U_CHAT,8,str);
 	user->chat=ahtoul(str);
-
 	/* Reset daily stats if not already logged on today */
 	if(user->ltoday || user->etoday || user->ptoday || user->ttoday) {
 		time_t		now;
@@ -368,10 +400,34 @@ int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
 				resetdailyuserdat(cfg,user,/* write: */FALSE);
 		}
 	}
-
 	return(0);
 }
 
+/****************************************************************************/
+/* Fills the structure 'user' with info for user.number	from user.dat file	*/
+/****************************************************************************/
+int DLLCALL getuserdat(scfg_t* cfg, user_t *user)
+{
+	int		retval;
+	int		file;
+	char	userdat[U_LEN+1];
+
+	if(!VALID_CFG(cfg) || user==NULL || user->number < 1)
+		return(-1); 
+
+	if((file = openuserdat(cfg)) < 0)
+		return file;
+
+	memset(userdat, 0, sizeof(userdat));
+	if((retval = readuserdat(cfg, user->number, userdat, file)) != 0) {
+		close(file);
+		return retval;
+	}
+	retval = parseuserdat(cfg, userdat, user);
+	close(file);
+	return retval;
+}
+
 /****************************************************************************/
 /****************************************************************************/
 static void dirtyuserdat(scfg_t* cfg, uint usernumber)
diff --git a/src/sbbs3/userdat.h b/src/sbbs3/userdat.h
index 0e02a5e86b6dd7da987badf31f36e5b23ade70a7..0f8496aad49697565bec8e949b176cc07cd792a3 100644
--- a/src/sbbs3/userdat.h
+++ b/src/sbbs3/userdat.h
@@ -77,33 +77,36 @@ extern "C" {
 extern char* crlf;
 extern char* nulstr;
 
-DLLEXPORT int	DLLCALL getuserdat(scfg_t* cfg, user_t* user); 	/* Fill userdat struct with user data   */
-DLLEXPORT int	DLLCALL putuserdat(scfg_t* cfg, user_t* user);	/* Put userdat struct into user file	*/
-DLLEXPORT int	DLLCALL newuserdat(scfg_t* cfg, user_t* user);	/* Create new userdat in user file */
-DLLEXPORT uint	DLLCALL matchuser(scfg_t* cfg, const char *str, BOOL sysop_alias); /* Checks for a username match */
-DLLEXPORT char* DLLCALL alias(scfg_t* cfg, const char* name, char* buf);
-DLLEXPORT int	DLLCALL putusername(scfg_t* cfg, int number, char * name);
-DLLEXPORT uint	DLLCALL total_users(scfg_t* cfg);
-DLLEXPORT uint	DLLCALL lastuser(scfg_t* cfg);
-DLLEXPORT BOOL	DLLCALL del_lastuser(scfg_t* cfg);
-DLLEXPORT uint	DLLCALL getage(scfg_t* cfg, char *birthdate);
-DLLEXPORT char*	DLLCALL username(scfg_t* cfg, int usernumber, char * str);
-DLLEXPORT char* DLLCALL usermailaddr(scfg_t* cfg, char* addr, const char* name);
-DLLEXPORT int	DLLCALL getnodedat(scfg_t* cfg, uint number, node_t *node, int* file);
-DLLEXPORT int	DLLCALL putnodedat(scfg_t* cfg, uint number, node_t *node, int file);
-DLLEXPORT char* DLLCALL nodestatus(scfg_t* cfg, node_t* node, char* buf, size_t buflen);
-DLLEXPORT void	DLLCALL printnodedat(scfg_t* cfg, uint number, node_t* node);
+DLLEXPORT int	DLLCALL openuserdat(scfg_t*);
+DLLEXPORT int	DLLCALL readuserdat(scfg_t*, unsigned user_number, char* userdat, int infile);
+DLLEXPORT int	DLLCALL parseuserdat(scfg_t*, char* userdat, user_t*);
+DLLEXPORT int	DLLCALL getuserdat(scfg_t*, user_t*); 	/* Fill userdat struct with user data   */
+DLLEXPORT int	DLLCALL putuserdat(scfg_t*, user_t*);	/* Put userdat struct into user file	*/
+DLLEXPORT int	DLLCALL newuserdat(scfg_t*, user_t*);	/* Create new userdat in user file */
+DLLEXPORT uint	DLLCALL matchuser(scfg_t*, const char *str, BOOL sysop_alias); /* Checks for a username match */
+DLLEXPORT char* DLLCALL alias(scfg_t*, const char* name, char* buf);
+DLLEXPORT int	DLLCALL putusername(scfg_t*, int number, char * name);
+DLLEXPORT uint	DLLCALL total_users(scfg_t*);
+DLLEXPORT uint	DLLCALL lastuser(scfg_t*);
+DLLEXPORT BOOL	DLLCALL del_lastuser(scfg_t*);
+DLLEXPORT uint	DLLCALL getage(scfg_t*, char *birthdate);
+DLLEXPORT char*	DLLCALL username(scfg_t*, int usernumber, char * str);
+DLLEXPORT char* DLLCALL usermailaddr(scfg_t*, char* addr, const char* name);
+DLLEXPORT int	DLLCALL getnodedat(scfg_t*, uint number, node_t *node, int* file);
+DLLEXPORT int	DLLCALL putnodedat(scfg_t*, uint number, node_t *node, int file);
+DLLEXPORT char* DLLCALL nodestatus(scfg_t*, node_t* node, char* buf, size_t buflen);
+DLLEXPORT void	DLLCALL printnodedat(scfg_t*, uint number, node_t* node);
 DLLEXPORT void	DLLCALL packchatpass(char *pass, node_t* node);
 DLLEXPORT char* DLLCALL unpackchatpass(char *pass, node_t* node);
-DLLEXPORT char* DLLCALL getsmsg(scfg_t* cfg, int usernumber);
-DLLEXPORT int	DLLCALL putsmsg(scfg_t* cfg, int usernumber, char *strin);
-DLLEXPORT char* DLLCALL getnmsg(scfg_t* cfg, int node_num);
-DLLEXPORT int	DLLCALL putnmsg(scfg_t* cfg, int num, char *strin);
+DLLEXPORT char* DLLCALL getsmsg(scfg_t*, int usernumber);
+DLLEXPORT int	DLLCALL putsmsg(scfg_t*, int usernumber, char *strin);
+DLLEXPORT char* DLLCALL getnmsg(scfg_t*, int node_num);
+DLLEXPORT int	DLLCALL putnmsg(scfg_t*, int num, char *strin);
 
-DLLEXPORT uint	DLLCALL userdatdupe(scfg_t* cfg, uint usernumber, uint offset, uint datlen, char *dat
+DLLEXPORT uint	DLLCALL userdatdupe(scfg_t*, uint usernumber, uint offset, uint datlen, char *dat
 							,BOOL del, BOOL next);
 
-DLLEXPORT BOOL	DLLCALL chk_ar(scfg_t* cfg, uchar* str, user_t*, client_t*); /* checks access requirements */
+DLLEXPORT BOOL	DLLCALL chk_ar(scfg_t*, uchar* str, user_t*, client_t*); /* checks access requirements */
 
 DLLEXPORT int	DLLCALL getuserrec(scfg_t*, int usernumber, int start, int length, char *str);
 DLLEXPORT int	DLLCALL putuserrec(scfg_t*, int usernumber, int start, uint length, const char *str);
@@ -112,13 +115,13 @@ DLLEXPORT BOOL	DLLCALL logoutuserdat(scfg_t*, user_t*, time_t now, time_t logont
 DLLEXPORT void	DLLCALL resetdailyuserdat(scfg_t*, user_t*, BOOL write);
 DLLEXPORT void	DLLCALL subtract_cdt(scfg_t*, user_t*, long amt);
 DLLEXPORT int	DLLCALL user_rec_len(int offset);
-DLLEXPORT BOOL	DLLCALL can_user_access_sub(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
-DLLEXPORT BOOL	DLLCALL can_user_read_sub(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
-DLLEXPORT BOOL	DLLCALL can_user_post(scfg_t* cfg, uint subnum, user_t* user, client_t* client, uint* reason);
-DLLEXPORT BOOL	DLLCALL can_user_send_mail(scfg_t* cfg, enum smb_net_type, uint usernumber, user_t* user, uint* reason);
-DLLEXPORT BOOL	DLLCALL is_user_subop(scfg_t* cfg, uint subnum, user_t* user, client_t* client);
-DLLEXPORT BOOL	DLLCALL is_download_free(scfg_t* cfg, uint dirnum, user_t* user, client_t* client);
-DLLEXPORT BOOL	DLLCALL filter_ip(scfg_t* cfg, const char* prot, const char* reason, const char* host
+DLLEXPORT BOOL	DLLCALL can_user_access_sub(scfg_t*, uint subnum, user_t*, client_t* client);
+DLLEXPORT BOOL	DLLCALL can_user_read_sub(scfg_t*, uint subnum, user_t*, client_t* client);
+DLLEXPORT BOOL	DLLCALL can_user_post(scfg_t*, uint subnum, user_t*, client_t* client, uint* reason);
+DLLEXPORT BOOL	DLLCALL can_user_send_mail(scfg_t*, enum smb_net_type, uint usernumber, user_t*, uint* reason);
+DLLEXPORT BOOL	DLLCALL is_user_subop(scfg_t*, uint subnum, user_t*, client_t* client);
+DLLEXPORT BOOL	DLLCALL is_download_free(scfg_t*, uint dirnum, user_t*, client_t* client);
+DLLEXPORT BOOL	DLLCALL filter_ip(scfg_t*, const char* prot, const char* reason, const char* host
 								  ,const char* ip_addr, const char* username, const char* fname);
 
 /* New-message-scan pointer functions: */
@@ -129,16 +132,16 @@ DLLEXPORT BOOL	DLLCALL initmsgptrs(scfg_t*, subscan_t*, unsigned days);
 
 
 /* New atomic numeric user field adjustment functions: */
-DLLEXPORT BOOL	DLLCALL user_posted_msg(scfg_t* cfg, user_t* user, int count);
-DLLEXPORT BOOL	DLLCALL user_sent_email(scfg_t* cfg, user_t* user, int count, BOOL feedback);
-DLLEXPORT BOOL	DLLCALL user_downloaded(scfg_t* cfg, user_t* user, int files, long bytes);
-DLLEXPORT BOOL	DLLCALL user_uploaded(scfg_t* cfg, user_t* user, int files, long bytes);
-DLLEXPORT BOOL	DLLCALL user_adjust_credits(scfg_t* cfg, user_t* user, long amount);
-DLLEXPORT BOOL	DLLCALL user_adjust_minutes(scfg_t* cfg, user_t* user, long amount);
+DLLEXPORT BOOL	DLLCALL user_posted_msg(scfg_t*, user_t*, int count);
+DLLEXPORT BOOL	DLLCALL user_sent_email(scfg_t*, user_t*, int count, BOOL feedback);
+DLLEXPORT BOOL	DLLCALL user_downloaded(scfg_t*, user_t*, int files, long bytes);
+DLLEXPORT BOOL	DLLCALL user_uploaded(scfg_t*, user_t*, int files, long bytes);
+DLLEXPORT BOOL	DLLCALL user_adjust_credits(scfg_t*, user_t*, long amount);
+DLLEXPORT BOOL	DLLCALL user_adjust_minutes(scfg_t*, user_t*, long amount);
 
-DLLEXPORT time_t DLLCALL gettimeleft(scfg_t* cfg, user_t* user, time_t starttime);
+DLLEXPORT time_t DLLCALL gettimeleft(scfg_t*, user_t*, time_t starttime);
 
-DLLEXPORT BOOL	DLLCALL check_name(scfg_t* cfg, const char* name);
+DLLEXPORT BOOL	DLLCALL check_name(scfg_t*, const char* name);
 
 /* Login attempt/hack tracking */
 typedef struct {