[mw-devel] [Git][arthur/mw][master] 10 commits: Replace get_person with thread-safe iterator-style functions

Andrew Price welshbyte at sucs.org
Sat Nov 7 15:16:35 GMT 2015


Andrew Price pushed to branch master at Justin Mitchell / mw


Commits:
0292a1e6 by Andrew Price at 2015-11-07T00:51:48Z
Replace get_person with thread-safe iterator-style functions

- - - - -
15f92520 by Andrew Price at 2015-11-07T01:07:43Z
Operate on a struct user in {get,set}_subscribe()

- - - - -
31afed91 by Andrew Price at 2015-11-07T01:32:01Z
Remove now-unused err_open()

- - - - -
8078c218 by Andrew Price at 2015-11-07T02:49:03Z
Remove some bits related to force

- - - - -
7a234519 by Andrew Price at 2015-11-07T03:08:56Z
Move loggedin into struct user

- - - - -
14623ddc by Andrew Price at 2015-11-07T04:47:50Z
Fix part_user()

Don't start at the beginning of the user db each time.

- - - - -
db46c150 by Andrew Price at 2015-11-07T05:31:25Z
Remove the 'unforceable' bit filter from commands

And tidy up command.c a bit

- - - - -
8ef4e073 by Andrew Price at 2015-11-07T05:32:17Z
Move the global 'fold' variable into struct user

- - - - -
1e64c155 by Andrew Price at 2015-11-07T06:27:40Z
Put the client's global user on the stack

Make it static but add a convenience pointer to it to take the place of
the previous user pointer. Make the pointer itself const so that the
compiler complains if anything besides the original user's address is
assigned to it.

- - - - -
d881fc86 by Andrew Price at 2015-11-07T07:24:21Z
Make the autofree stuff more generic

(And less shouty.)

- - - - -


35 changed files:

- src/client/Parse.c
- src/client/colour.c
- src/client/command.c
- src/client/edit.c
- src/client/folders.c
- src/client/incoming.c
- src/client/init.c
- src/client/js.c
- src/client/log.c
- src/client/main.c
- src/client/mesg.c
- src/client/new.c
- src/client/newmain.c
- src/client/script.c
- src/client/script_inst.c
- src/client/strings.c
- src/client/strings.h
- src/client/talker.c
- src/client/talker_privs.c
- src/client/uri.c
- src/client/user.c
- src/client/user.h
- src/client/who.c
- src/folders.h
- src/perms.c
- src/perms.h
- src/server/actions.c
- src/server/mwserv.c
- src/server/servsock.c
- src/socket.c
- src/user.c
- src/user.h
- src/util.h
- src/webclient/comms.c
- src/webclient/import.c


Changes:

=====================================
src/client/Parse.c
=====================================
--- a/src/client/Parse.c
+++ b/src/client/Parse.c
@@ -11,7 +11,7 @@
 
 extern unsigned long rights;
 extern CommandList chattable[];
-extern struct user *user;
+extern struct user * const user;
 
 #include "alias.h"
 extern Alias alias_list;


=====================================
src/client/colour.c
=====================================
--- a/src/client/colour.c
+++ b/src/client/colour.c
@@ -20,7 +20,7 @@ static  char *colour_chart[COLOUR_LIMIT];
 static char *colour_set=NULL;
 
 /* the current user template */
-extern struct user *user;
+extern struct user * const user;
 
 /* return colour code sequence */
 char *colour(char *text, int *concealed)


=====================================
src/client/command.c
=====================================
--- a/src/client/command.c
+++ b/src/client/command.c
@@ -2,88 +2,86 @@
 #include "talker.h"
 
 /*
-	0x001 - superuser,	(1)
-	0x002 - Wizchat,	(2)
+	0x001 - superuser,      (1)
+	0x002 - Wizchat,        (2)
 	0x004 - Special Wizard, (4)
-	0x008 - Moderator,	(8)
-	0x010 - On Machine	(16)
-	0x020 - registered	(32)
-	0x040 - Timeout		(64)
-	0x080 - force		(128)	- Obsolete
-	0x100 - unforceable	(256)	- Obsolete
+	0x008 - Moderator,      (8)
+	0x010 - On Machine      (16)
+	0x020 - registered      (32)
+	0x040 - Timeout         (64)
 */
 
 CommandList table[]={
-{"addfol",   	0x101,	0, "Usage: addfol", "Create a folder", c_addfol, 1},
-{"alias",	0x100,	2, "Usage: alias <alias> <command>", "Add the alias to the current session", c_alias, 1},
-{"autosub",   	0x101,	2, "Usage: autosub <folder> <yes | no>", "Force everyone's subscription to <folder>", c_autosub, 1},
-{"backward",  	0x000,	0, "Usage: backward", "Display preceeding message", c_prev, 1},
-{"beep",   	0x000,	1, "Usage: beep <on | off>", "Toggle audible beeps", c_beep, 1},
-{"board",   	0x101,	1, "Usage: board [un]lock", "[un]lock the bbs to normal users", c_board, 1},
-{"catchup",   	0x000,	0, "Usage: catchup <folder | all>", "Mark this or selected folder as read", c_catchup, 1},
-{"cd",   	0x000,	1, "Usage: cd <folder>", "Change to a folder", c_cd, 1},
-{"changeinfo",	0x001,	1, "Usage: changeinfo <on|off>", "Toggle user status change messages", c_changeinfo, 1},
-{"charset",	0x000,	0, "Usage: charset <charset>", "Change character set", c_charset, 1},
-{"chat",	0x020,	0, "Usage: chat", "Enter chat mode", c_chatmode, 1},
-{"colour",   	0x000,	0, "Usage: colour <on | off | list | n>", "Colour mode options", c_colouroff, 1},
-{"contact",	0x120,	0, "Usage: contact", "Changes your contact address", c_contact, 1},
-{"credits",   	0x000,	0, "Usage: credits", "Display the credits", c_credits, 1},
-{"date",   	0x000,	0, "Usage: date", "Display the current system date", c_date, 1},
-{"doing",   	0x000,	0, "Usage: doing <message>", "Set <doing> field of who", c_doing, 1},			/* privs were 0x001 */
-{"emote", 	0x002,	1, "Usage: emote <message>", "Send emotion to all wizchat users",c_emote, 1},
-{"first",	0x000,	0, "Usage: first", "Display first message in current folder", c_first, 1},
-{"folder",	0x101,	2, "Usage: folder <com> <name>", "Folder editing functions", c_folder, 1},
-{"forward",   	0x000,	0, "Usage: forward", "Display following message", c_next, 1},
-{"help",	0x000,	0, "Usage: help [topic]", "List functions and their usage", c_help, 1},
-{"inform",	0x000,	1, "Usage: inform <on | off>", "Toggle user login messages", c_inform, 1},
-{"last",	0x000,	0, "Usage: last", "Display last message in current folder", c_last, 1},
-{"latest",	0x000,	0, "Usage: latest", "List last message in all folders", c_latest, 1},
-{"list",   	0x000,	0, "Usage: list", "List all folders", c_listall, 1},
-{"listall",   	0x000,	0, "Usage: listall", "List all folders", c_listall, 1},
-{"listnew",   	0x000,	0, "Usage: listnew", "List available new messages", c_listnew, 1},
-{"listusers",  	0x000,	0, "Usage: listusers", "List all users known", c_listusers, 1},
-{"locale",	0x000,	0, "Usage: locale <locale>", "Change locale", c_locale, 1},
-{"ls",   	0x000,	0, "Usage: ls [[-]many]", "List messages in this folder [[last] many]", c_ls, 1},
-{"mesg",   	0x100,	2, "Usage: mesg <com> <id>", "Edit message <id> in this folder", c_mesg, 1},
-{"mod",   	0x108,	0, "Usage: mod", "Process new moderated messages for this folder", c_mod, 1},
-{"msg",   	0x000,	1, "Usage: msg <on | off>", "Toggle tell messages", c_msg, 1},
-{"n",   	0x000,	0, "Usage: next", "Alias for next", c_next, 1},
-{"new",   	0x000,	0, "Usage: new", "Display new messages", c_new, 1},
-{"newusers",   	0x001,	0, "Usage: newusers", "List known unregistered users", c_newusers, 1},
-{"next",   	0x000,	0, "Usage: next", "Display following message", c_next, 1},
-{"p",   	0x000,	0, "Usage: previous", "Alias for previous", c_prev, 1},
-{"passwd",   	0x100,	0, "Usage: passwd", "Change current password", c_passwd, 1},
-{"postinfo",	0x000,	1, "Usage: postinfo <on | off>", "Inform you of all new postings", c_postinfo, 1},
-{"previous",   	0x000,	0, "Usage: previous", "Display preceeding message", c_prev, 1},
-{"pwd", 	0x000,	0, "Usage: pwd", "Name the current folder", c_pwd, 1},
-{"qq", 		0x000,	0, "Usage: qq", "Finish the session", c_quit, 1},
-{"quit", 	0x000,	0, "Usage: quit", "Finish the session", c_quit, 1},
-{"qw", 		0x000,	0, "Usage: who", "List current users", c_who, 1},
-{"r", 		0x000,	1, "Usage: read <mesg id>", "Alias for read", c_read, 1},
-{"read", 	0x000,	1, "Usage: read <mesg id>", "Read the identified message", c_read, 1},
-{"reply", 	0x100,	0, "Usage: reply ", "Reply to the last read message", c_reply, 1},
-{"resubscribe",	0x000,	0, "Usage: resubscribe", "Resubscribe to the current folder", c_resub, 1},
-{"save",	0x110,	2, "Usage: save mesg file", "Save mesg in /tmp/file", c_save, 1},
-{"search", 	0x001,	2, "Usage: search <type> <flags>", "List users with <flags> of <type>", c_search, 1},
-{"since", 	0x000,	0, "Usage: since", "List users logged in since your last login", c_since, 1},
-{"status", 	0x000,	0, "Usage: status", "Display user status", c_status, 1},
-{"su",		0x104,	1, "Usage: su <on | off>", "Toggle superuser powers", c_su, 1},
-{"talker",	0x020,	0, "Usage: talker", "Enter chat mode", c_chatmode, 1},
-{"tell",	0x020,	2, "Usage: tell <user> <message>", "Send message to user", c_tell, 1},
-{"tidyup",	0x101,	2, "Usage: tidyup <foldername> <mesg no>", "Remove messages from a folder upto message number", c_tidyup, 1},
-{"timeout",	0x040,	1, "Usage: timeout <time>", "Set your idle time logout", c_timeout, 1},
-{"timestamp",	0x000,	1, "Usage: timestamp <on | off>", "Print timestamps on messages", c_timestamp, 1},
-{"topten",	0x001,	1, "Usage: topten <foldername>", "List heaviest users of a folder", c_topten, 1},
-{"unalias",	0x100,	1, "Usage: unalias <alias | *>", "Remove the alias from the current session", c_unalias, 1},
-{"unsubscribe",	0x000,	0, "Usage: unsubscribe", "Unsubscribe from current folder", c_unsub, 1},
-{"user", 	0x101,	2, "Usage: user <com> <name>", "User editing functions", c_user, 1},
-{"version", 	0x000,	0, "Usage: version", "Display Version Info", c_version, 1},
-{"w", 		0x100,	0, "Usage: write", "Alias for write", c_write, 1},
-{"wall", 	0x001,	1, "Usage: wall <message...>", "Send message to ALL users", c_wall, 1},
-{"what", 	0x000,	0, "Usage: what", "List current users status", t_what, 1},
-{"who", 	0x000,	0, "Usage: who", "List current users", c_who, 1},
-{"wiz", 	0x002,	1, "Usage: wiz <message>", "Send message to all wizchat users", c_wiz, 1},
-{"wizchat", 	0x002,	1, "Usage: wizchat on|off", "Toggle wizchat", c_wizchat, 1},
-{"write", 	0x100,	0, "Usage: write", "Post a message to the current folder", c_write, 1},
-{NULL,		0x000,	0, NULL, NULL, 0}
+{"addfol",     0x001, 0, "Usage: addfol", "Create a folder", c_addfol, 1},
+{"alias",      0x000, 2, "Usage: alias <alias> <command>", "Add the alias to the current session", c_alias, 1},
+{"autosub",    0x001, 2, "Usage: autosub <folder> <yes | no>", "Force everyone's subscription to <folder>", c_autosub, 1},
+{"backward",   0x000, 0, "Usage: backward", "Display preceeding message", c_prev, 1},
+{"beep",       0x000, 1, "Usage: beep <on | off>", "Toggle audible beeps", c_beep, 1},
+{"board",      0x001, 1, "Usage: board [un]lock", "[un]lock the bbs to normal users", c_board, 1},
+{"catchup",    0x000, 0, "Usage: catchup <folder | all>", "Mark this or selected folder as read", c_catchup, 1},
+{"cd",         0x000, 1, "Usage: cd <folder>", "Change to a folder", c_cd, 1},
+{"changeinfo", 0x001, 1, "Usage: changeinfo <on|off>", "Toggle user status change messages", c_changeinfo, 1},
+{"charset",    0x000, 0, "Usage: charset <charset>", "Change character set", c_charset, 1},
+{"chat",       0x020, 0, "Usage: chat", "Enter chat mode", c_chatmode, 1},
+{"colour",     0x000, 0, "Usage: colour <on | off | list | n>", "Colour mode options", c_colouroff, 1},
+{"contact",    0x020, 0, "Usage: contact", "Changes your contact address", c_contact, 1},
+{"credits",    0x000, 0, "Usage: credits", "Display the credits", c_credits, 1},
+{"date",       0x000, 0, "Usage: date", "Display the current system date", c_date, 1},
+{"doing",      0x000, 0, "Usage: doing <message>", "Set <doing> field of who", c_doing, 1},
+{"emote",      0x002, 1, "Usage: emote <message>", "Send emotion to all wizchat users",c_emote, 1},
+{"first",      0x000, 0, "Usage: first", "Display first message in current folder", c_first, 1},
+{"folder",     0x001, 2, "Usage: folder <com> <name>", "Folder editing functions", c_folder, 1},
+{"forward",    0x000, 0, "Usage: forward", "Display following message", c_next, 1},
+{"help",       0x000, 0, "Usage: help [topic]", "List functions and their usage", c_help, 1},
+{"inform",     0x000, 1, "Usage: inform <on | off>", "Toggle user login messages", c_inform, 1},
+{"last",       0x000, 0, "Usage: last", "Display last message in current folder", c_last, 1},
+{"latest",     0x000, 0, "Usage: latest", "List last message in all folders", c_latest, 1},
+{"list",       0x000, 0, "Usage: list", "List all folders", c_listall, 1},
+{"listall",    0x000, 0, "Usage: listall", "List all folders", c_listall, 1},
+{"listnew",    0x000, 0, "Usage: listnew", "List available new messages", c_listnew, 1},
+{"listusers",  0x000, 0, "Usage: listusers", "List all users known", c_listusers, 1},
+{"locale",     0x000, 0, "Usage: locale <locale>", "Change locale", c_locale, 1},
+{"ls",         0x000, 0, "Usage: ls [[-]many]", "List messages in this folder [[last] many]", c_ls, 1},
+{"mesg",       0x000, 2, "Usage: mesg <com> <id>", "Edit message <id> in this folder", c_mesg, 1},
+{"mod",        0x008, 0, "Usage: mod", "Process new moderated messages for this folder", c_mod, 1},
+{"msg",        0x000, 1, "Usage: msg <on | off>", "Toggle tell messages", c_msg, 1},
+{"n",          0x000, 0, "Usage: next", "Alias for next", c_next, 1},
+{"new",        0x000, 0, "Usage: new", "Display new messages", c_new, 1},
+{"newusers",   0x001, 0, "Usage: newusers", "List known unregistered users", c_newusers, 1},
+{"next",       0x000, 0, "Usage: next", "Display following message", c_next, 1},
+{"p",          0x000, 0, "Usage: previous", "Alias for previous", c_prev, 1},
+{"passwd",     0x000, 0, "Usage: passwd", "Change current password", c_passwd, 1},
+{"postinfo",   0x000, 1, "Usage: postinfo <on | off>", "Inform you of all new postings", c_postinfo, 1},
+{"previous",   0x000, 0, "Usage: previous", "Display preceeding message", c_prev, 1},
+{"pwd",        0x000, 0, "Usage: pwd", "Name the current folder", c_pwd, 1},
+{"qq",         0x000, 0, "Usage: qq", "Finish the session", c_quit, 1},
+{"quit",       0x000, 0, "Usage: quit", "Finish the session", c_quit, 1},
+{"qw",         0x000, 0, "Usage: who", "List current users", c_who, 1},
+{"r",          0x000, 1, "Usage: read <mesg id>", "Alias for read", c_read, 1},
+{"read",       0x000, 1, "Usage: read <mesg id>", "Read the identified message", c_read, 1},
+{"reply",      0x000, 0, "Usage: reply ", "Reply to the last read message", c_reply, 1},
+{"resubscribe",0x000, 0, "Usage: resubscribe", "Resubscribe to the current folder", c_resub, 1},
+{"save",       0x010, 2, "Usage: save mesg file", "Save mesg in /tmp/file", c_save, 1},
+{"search",     0x001, 2, "Usage: search <type> <flags>", "List users with <flags> of <type>", c_search, 1},
+{"since",      0x000, 0, "Usage: since", "List users logged in since your last login", c_since, 1},
+{"status",     0x000, 0, "Usage: status", "Display user status", c_status, 1},
+{"su",         0x004, 1, "Usage: su <on | off>", "Toggle superuser powers", c_su, 1},
+{"talker",     0x020, 0, "Usage: talker", "Enter chat mode", c_chatmode, 1},
+{"tell",       0x020, 2, "Usage: tell <user> <message>", "Send message to user", c_tell, 1},
+{"tidyup",     0x001, 2, "Usage: tidyup <foldername> <mesg no>", "Remove messages from a folder upto message number", c_tidyup, 1},
+{"timeout",    0x040, 1, "Usage: timeout <time>", "Set your idle time logout", c_timeout, 1},
+{"timestamp",  0x000, 1, "Usage: timestamp <on | off>", "Print timestamps on messages", c_timestamp, 1},
+{"topten",     0x001, 1, "Usage: topten <foldername>", "List heaviest users of a folder", c_topten, 1},
+{"unalias",    0x000, 1, "Usage: unalias <alias | *>", "Remove the alias from the current session", c_unalias, 1},
+{"unsubscribe",0x000, 0, "Usage: unsubscribe", "Unsubscribe from current folder", c_unsub, 1},
+{"user",       0x001, 2, "Usage: user <com> <name>", "User editing functions", c_user, 1},
+{"version",    0x000, 0, "Usage: version", "Display Version Info", c_version, 1},
+{"w",          0x000, 0, "Usage: write", "Alias for write", c_write, 1},
+{"wall",       0x001, 1, "Usage: wall <message...>", "Send message to ALL users", c_wall, 1},
+{"what",       0x000, 0, "Usage: what", "List current users status", t_what, 1},
+{"who",        0x000, 0, "Usage: who", "List current users", c_who, 1},
+{"wiz",        0x002, 1, "Usage: wiz <message>", "Send message to all wizchat users", c_wiz, 1},
+{"wizchat",    0x002, 1, "Usage: wizchat on|off", "Toggle wizchat", c_wizchat, 1},
+{"write",      0x000, 0, "Usage: write", "Post a message to the current folder", c_write, 1},
+{NULL,         0x000, 0, NULL, NULL, 0}
 };


=====================================
src/client/edit.c
=====================================
--- a/src/client/edit.c
+++ b/src/client/edit.c
@@ -40,7 +40,7 @@ const char *partlist_user[]={
 
 extern int busy;
 extern int mesg_waiting;
-extern struct user *user;
+extern struct user * const user;
 
 static void edit_all(struct user *_user)
 {


=====================================
src/client/folders.c
=====================================
--- a/src/client/folders.c
+++ b/src/client/folders.c
@@ -75,18 +75,18 @@ void add_folder(void)
 
 void auto_subscribe(int folnum, int state)
 {
+	int err;
 	int ufile;
 	struct user usr;
-	struct person *urec = &usr.record;
 	char buff[10];
 
 	ufile = userdb_open(O_RDWR);
 	if (ufile < 0)
 		return;
 	Lock_File(ufile); /*user file*/
-	while(get_person(ufile, &usr))
-	{
-		set_subscribe(urec, folnum, state);
+
+	for_each_user(&usr, ufile, err) {
+		set_subscribe(&usr, folnum, state);
 		update_user_fd(ufile, &usr);
 	}
 	Unlock_File(ufile);


=====================================
src/client/incoming.c
=====================================
--- a/src/client/incoming.c
+++ b/src/client/incoming.c
@@ -35,7 +35,7 @@ extern Alias rpc_list;
 extern Alias event_list;
 extern Alias onoff_list;
 extern Alias ipc_list;
-extern struct user *user;
+extern struct user * const user;
 extern int quietmode;
 extern ipc_connection_t *ipcsock;
 
@@ -646,7 +646,7 @@ static void display_content(ipc_message_t *msg)
 		if (verbose) force_text(msg, verbose, whom);
 		force_text(msg, text, whom);
 		if (reason) {
-			AUTOFREE_BUFFER excuse = NULL;
+			_autofree char *excuse = NULL;
 			if (strcasecmp(type, "mrod")==0 || strcasecmp(type, "zod")==0) {
 				asprintf(&excuse, "Zebedee says \"%s\".", reason);
 			} else {


=====================================
src/client/init.c
=====================================
--- a/src/client/init.c
+++ b/src/client/init.c
@@ -32,7 +32,7 @@ extern Alias shutdown_list;
 #include "script.h"
 #include "frl.h"
 
-extern struct user *user;
+extern struct user * const user;
 
 /* drop and restore user level privs */
 static int private_myid = -1;


=====================================
src/client/js.c
=====================================
--- a/src/client/js.c
+++ b/src/client/js.c
@@ -48,7 +48,7 @@ extern Alias force_list;
 extern Alias shutdown_list;
 extern Alias eventin_list;
 
-extern struct user *user;
+extern struct user * const user;
 extern unsigned long rights;
 extern int busy;
 extern int current_rights;
@@ -151,7 +151,7 @@ static JSBool js_print(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	unsigned int i;
 	jsval *argv = JS_ARGV(cx, vp);
-	AUTOFREE_BUFFER msg = NULL;
+	_autofree char *msg = NULL;
 	if (argc < 1) {
 		return JS_TRUE;
 	}
@@ -178,7 +178,7 @@ static JSBool js_print(JSContext *cx, unsigned int argc, jsval *vp)
 static JSBool js_mwexec(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	jsval *argv = JS_ARGV(cx, vp);
-	AUTOFREE_BUFFER msg = NULL;
+	_autofree char *msg = NULL;
 	if (argc < 1) {
 		JS_ReportError(cx, "exec() expects an argument.");
 		return JS_FALSE;
@@ -198,7 +198,7 @@ static JSBool js_mwexec(JSContext *cx, unsigned int argc, jsval *vp)
 static JSBool js_say(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	jsval *argv = JS_ARGV(cx, vp);
-	AUTOFREE_BUFFER msg = NULL;
+	_autofree char *msg = NULL;
 
 	if (argc < 1) {
 		JS_ReportError(cx, "say() expects an argument.");
@@ -225,8 +225,8 @@ static JSBool js_say(JSContext *cx, unsigned int argc, jsval *vp)
 static JSBool js_rpc(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	jsval *argv = JS_ARGV(cx, vp);
-	AUTOFREE_BUFFER msg = NULL;
-	AUTOFREE_BUFFER rpc_type = NULL;
+	_autofree char *msg = NULL;
+	_autofree char *rpc_type = NULL;
 	char username[NAMESIZE+1]="";
 	int broadcast=0;
 
@@ -262,8 +262,8 @@ static JSBool js_rpc(JSContext *cx, unsigned int argc, jsval *vp)
 static JSBool js_ipc(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	jsval *argv = JS_ARGV(cx, vp);
-	AUTOFREE_BUFFER msg = NULL;
-	AUTOFREE_BUFFER username = NULL;
+	_autofree char *msg = NULL;
+	_autofree char *username = NULL;
 	int broadcast=0;
 	if (argc < 2) {
 		JS_ReportError(cx, "Error: javascript ipc() expects 2 arguments");
@@ -386,8 +386,8 @@ static JSBool js_beep(JSContext *cx, unsigned int argc, jsval *vp)
 static JSBool js_bind(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	jsval *argv = JS_ARGV(cx, vp);
-	AUTOFREE_BUFFER jbind = NULL;
-	AUTOFREE_BUFFER function_name = NULL;
+	_autofree char *jbind = NULL;
+	_autofree char *function_name = NULL;
 	int bind_type=-1;
 	int i=1;
 	char msg[MAXTEXTLENGTH];
@@ -512,7 +512,7 @@ static JSBool js_bind(JSContext *cx, unsigned int argc, jsval *vp)
 static JSBool js_unbind(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	jsval *argv = JS_ARGV(cx, vp);
-	AUTOFREE_BUFFER jbind = NULL;
+	_autofree char *jbind = NULL;
 	char *function_name=NULL;
 	int bind_type=-1;
 	char msg[MAXTEXTLENGTH];
@@ -772,7 +772,7 @@ size_t headlimit(  void  *ptr,  size_t  size, size_t nmemb, void *stream)
 static JSBool js_urlget(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	jsval *argv = JS_ARGV(cx, vp);
-	AUTOFREE_BUFFER url = NULL;
+	_autofree char *url = NULL;
 	JSString *jsstr;
 	char msg[MAXTEXTLENGTH];
 
@@ -949,8 +949,8 @@ static JSBool js_doquery(JSContext *cx, unsigned int argc, jsval *vp)
 {
 	jsval *argv = JS_ARGV(cx, vp);
 	struct js_db_result *dbres;
-	AUTOFREE_BUFFER dbname = NULL;
-	AUTOFREE_BUFFER query = NULL;
+	_autofree char *dbname = NULL;
+	_autofree char *query = NULL;
 	jsval resobject_jsval;
 	char path[1024];
 	struct passwd *pw;
@@ -1008,7 +1008,7 @@ static JSBool js_store_get(JSContext *cx, JSHandleObject obj, JSHandleId idval, 
 	jsval sval;
 	JSBool ret = JS_IdToValue(cx, *idval._, &sval);
 	if (ret == JS_TRUE && JSVAL_IS_STRING(sval)) {
-		AUTOFREE_BUFFER key = JS_EncodeString(cx, JS_ValueToString(cx, sval));
+		_autofree char *key = JS_EncodeString(cx, JS_ValueToString(cx, sval));
 		char *val = userdb_get(USERDB_PUBLIC, user->record.name, key);
 		if (val == NULL) {
 			*vp._ = JSVAL_VOID;
@@ -1026,8 +1026,8 @@ static JSBool js_store_set(JSContext *cx, JSHandleObject obj, JSHandleId idval, 
 	jsval sval;
 	JSBool ret = JS_IdToValue(cx, *idval._, &sval);
 	if (ret == JS_TRUE && JSVAL_IS_STRING(sval) && JSVAL_IS_STRING(*vp._)) {
-		AUTOFREE_BUFFER key = JS_EncodeString(cx, JS_ValueToString(cx, sval));
-		AUTOFREE_BUFFER val = JS_EncodeString(cx, JS_ValueToString(cx, *vp._));
+		_autofree char *key = JS_EncodeString(cx, JS_ValueToString(cx, sval));
+		_autofree char *val = JS_EncodeString(cx, JS_ValueToString(cx, *vp._));
 		userdb_set(USERDB_PUBLIC, user->record.name, key, val);
 	}
 	return JS_TRUE;


=====================================
src/client/log.c
=====================================
--- a/src/client/log.c
+++ b/src/client/log.c
@@ -15,7 +15,7 @@
 #include "uri.h"
 #include "user.h"
 
-extern struct user *user;
+extern struct user * const user;
 static void *file_url(void * data);
 static void *file_tag(void * data);
 


=====================================
src/client/main.c
=====================================
--- a/src/client/main.c
+++ b/src/client/main.c
@@ -89,11 +89,9 @@ int current_rights = 0;
 
 char clear_line[]="\033[M\r";
 
-struct user *user = NULL;
-struct folder *fold = NULL;
-unsigned long loggedin; /* what time did they login */
+static struct user mwuser;
+struct user * const user = &mwuser;
 unsigned long rights=(unsigned long)0;
-unsigned long forced;
 
 /* readline stuff */
 int UseRL=0;
@@ -126,18 +124,15 @@ void set_rights(void)
 	if (!internet && getuid()!=500) rights|=16l;
 	if (u_reg(user)) rights|=32l;
 	if (s_timeout(user)) rights|=64l;
-	if (!forced) rights|=256l;
 	current_rights = RIGHTS_BBS;
 }
 
 static void set_prompt(void)
 {
-	char pre[20];
+	char pre[20] = {0};
 
-	if (UseRL)
-		sprintf(pre,"%s", "");
-		/*sprintf(pre,"%s",clear_line);*/
-	else strcpy(pre,"\r");
+	if (!UseRL)
+		pre[0] = '\r';
 
 	if (is_stacked())
 	{
@@ -149,12 +144,12 @@ static void set_prompt(void)
 			snprintf(prompt,40, "%stalk{%d}-* ", pre, user->record.room);
 		else
 		if (u_god(user))
-			snprintf(prompt,40,"%s{%s}---* ",pre,fold->name);
+			snprintf(prompt,40,"%s{%s}---* ", pre, user->folder.name);
 		else
 		if (u_reg(user))
-			snprintf(prompt,40, "%s<%s>---> ",pre,fold->name);
+			snprintf(prompt,40, "%s<%s>---> ", pre, user->folder.name);
 		else
-			snprintf(prompt,40, "%s[%s] _@/ ",pre,fold->name);
+			snprintf(prompt,40, "%s[%s] _@/ ",pre, user->folder.name);
 	}
 }
 
@@ -365,14 +360,8 @@ int main(int argc, char **argv)
 
 	/* initialise random seed */
 	srand(time(NULL));
-
 	/* initialise termcap */
 	init_termcap();
-
-	/* create client user information */
-	user = calloc(1, sizeof(*user));
-	fold = calloc(1, sizeof(*fold));
-
 	output=stdout;
 
 	if (folders_init())
@@ -479,8 +468,6 @@ int main(int argc, char **argv)
 		printf(_("\nTo view this help message, use the arguments:  -h, -help, or -?\n"));
 		printf(_("To specify arguments, you may use '--', or '/' instead of '-'.\n\n"));
 
-		free(user);
-		free(fold);
 		exit(0);
 	}
 
@@ -513,11 +500,7 @@ int main(int argc, char **argv)
 
 	/* if any 'view and quit' options specified, then quit */
 	if (view_new || view_since)
-	{
-		free(user);
-		free(fold);
 		exit(0);
-	}
 
 	if (inarg_num>-1) autoexec_arg = argv[inarg_num];
 	else autoexec_arg = "";
@@ -570,8 +553,6 @@ int main(int argc, char **argv)
 		remote=true;
 		show_new(user);
 		update_user(user);
-		free(user);
-		free(fold);
 		exit(0);
 	}
 
@@ -585,22 +566,16 @@ int main(int argc, char **argv)
 		if (currentfolder==-1)
 		{
 			fprintf(stderr,_("%s: Folder %s not found.\n"), argv[0], foldname);
-			free(user);
-			free(fold);
 			exit(-1);
 		}
 		if (!is_old(folduser, user))
 		{
 			fprintf(stderr,_("%s: User %s not found.\n"), argv[0], folduser);
-			free(user);
-			free(fold);
 			exit(-1);
 		}
 		rt = atoi(argv[folderuser_replyto]);
 		remote=true;
 		add_msg(currentfolder, user, rt);
-		free(user);
-		free(fold);
 		exit(0);
 	}
 /*
@@ -626,8 +601,6 @@ int main(int argc, char **argv)
 		{
 			printf(_("The Board has been temporarily closed.\n"));
 			printf(_("Please call again soon.\n"));
-			free(user);
-			free(fold);
 			exit(0);
 		}
 	}
@@ -636,11 +609,8 @@ int main(int argc, char **argv)
 	if (targethost == NULL)
 		targethost = "localhost";
 
-	if (ipc_connect(targethost, user) < 0) {
-		free(user);
-		free(fold);
+	if (ipc_connect(targethost, user) < 0)
 		exit(1);
-	}
 	if ((s_quiet(user) || u_god(user)) && qflag)
 	{
 		extern int talker_logontype;
@@ -681,7 +651,7 @@ int main(int argc, char **argv)
 		printf(_("Wait here for a few minutes and an administrator might register you.\n"));
 	}
 	if (!autochat) printf(_("Type 'help' for help.\n"));
-	loggedin=time(0);
+	user->loggedin = time(0);
 
 	/* initialise script variables */
 	script_init();
@@ -723,10 +693,10 @@ int main(int argc, char **argv)
 
 	/* list new BBS items */
 	list_new_items(user,true);
-	if (!get_folder_number(fold,currentfolder))
+	if (!get_folder_number(&user->folder, currentfolder))
 	{
 		currentfolder = -1;
-		fold->name[0] = '\0';
+		user->folder.name[0] = '\0';
 	}
 
 	InitParser();
@@ -752,7 +722,7 @@ int main(int argc, char **argv)
 		if (is_stacked())
 		{
 			disable_rl(1);
-			forced = pop_stack(comm,MAXTEXTLENGTH);
+			pop_stack(comm,MAXTEXTLENGTH);
 			accept_command(comm);
 			tty_timeout = 50;
 		}
@@ -886,8 +856,9 @@ void close_down(int exitmode, char *sourceuser, char *reason)
 
 
 	/* update user information */
-	user->record.timeused += time(0) - loggedin;
-	user->record.lastlogout = time(0);
+	time_t now = time(0);
+	user->record.timeused += now - user->loggedin;
+	user->record.lastlogout = now;
 	update_user(user);
 
 	destroy_colours();
@@ -921,8 +892,6 @@ void close_down(int exitmode, char *sourceuser, char *reason)
 	mwlog("LOGOUT");
 	sleep(1); //dodgy hack for race condition in checkonoff, cunningly we currently get woken by the very message we're waiting for.
 
-	free(user);
-	free(fold);
 	ipc_close();
 
 	exit(0);
@@ -1754,7 +1723,8 @@ char *part_user(const char *text, int status)
 {
 	static int file=0;
 	static int len=0;
-	struct user usr;
+	static struct user usr;
+	int err;
 
 	if (status==0)
 	{
@@ -1762,9 +1732,11 @@ char *part_user(const char *text, int status)
 		if (file < 0)
 			return NULL;
 		len=strlen(text);
-	}
+		err = fetch_first_user(file, &usr);
+	} else
+		err = fetch_next_user(file, &usr);
 
-	while (get_person(file, &usr))
+	for (; err == 0; err = fetch_next_user(file, &usr))
 	{
 		if (!u_del(&usr))
 		{


=====================================
src/client/mesg.c
=====================================
--- a/src/client/mesg.c
+++ b/src/client/mesg.c
@@ -14,7 +14,7 @@
 #include "bb.h"
 #include "user.h"
 
-extern struct user *user;
+extern struct user * const user;
 
 void send_mesg(char *from, const char *to, char *text, int wiz)
 {


=====================================
src/client/new.c
=====================================
--- a/src/client/new.c
+++ b/src/client/new.c
@@ -46,14 +46,14 @@ void list_new_items(struct user *user, int flag)
 		   || allowed_w(fol,user))) /*allowed*/
 		if (!flag || ((fol->last - user->record.lastread[count]) > 0
 		          && allowed_r(fol,user)
-		          && get_subscribe(&user->record, count))) /* subscribed */
+		          && get_subscribe(user, count))) /* subscribed */
 		{
 			printf("%*s (",FOLNAMESIZE,fol->name);
 			putchar(allowed_r(fol,user)?'r':'-');
 			putchar(allowed_w(fol,user)?'w':'-');
 			putchar(is_private(fol,user)?'p':'-');
 			putchar(is_moderated(fol,user)?'m':'-');
-			putchar(get_subscribe(&user->record, count) ? 'S' : '-');
+			putchar(get_subscribe(user, count) ? 'S' : '-');
 			line++;
 			if (flag)
 			{
@@ -156,7 +156,7 @@ static int read_new(struct user *user, struct folder *data, int folnum)
 			}else
 			if (stringcmp(tmp,"unsubscribe",5))
 			{
-				set_subscribe(urec, folnum, false);
+				set_subscribe(user, folnum, false);
 				printf(_("Unsubscribing from %s.\n"),data->name);
 				break;
 			}else
@@ -197,7 +197,7 @@ void show_new(struct user *user)
 	{
 		if (data->status&1 /*active*/
 		&& allowed_r(data,user) /* allowed to read */
-	    	&& get_subscribe(&user->record, folnum)  /* currently subscribed */
+		&& get_subscribe(user, folnum)  /* currently subscribed */
 		&& !(data->last<data->first || data->last==0)
 		&& !(data->last <= user->record.lastread[folnum]))
 		{


=====================================
src/client/newmain.c
=====================================
--- a/src/client/newmain.c
+++ b/src/client/newmain.c
@@ -45,9 +45,7 @@ extern int currentfolder,last_mesg;
 extern FILE *output;
 extern int busy; /* if true dont display messages  i.e. during new/write */
 extern unsigned long rights;
-extern struct user *user;
-extern struct folder *fold;
-extern unsigned long loggedin;
+extern struct user * const user;
 extern CommandList table[];
 extern void help_list(CommandList *cm, unsigned int hidestuff);
 
@@ -87,7 +85,7 @@ static void help(const char *topic, int wiz)
 	/* a help topic was given */
 	else
 	{
-		AUTOFREE_BUFFER x = NULL;
+		_autofree char *x = NULL;
 
 		/* find the command in the list */
 		c = table;
@@ -137,6 +135,8 @@ void c_cd(CommandList *cm, int argc, const char **argv, char *args)
 		printf(_("Unknown foldername.\n"));
     	else
     	{
+		struct folder *fold = &user->folder;
+
 		get_folder_number(fold,i);
 		if(!f_active(fold->status) || (!allowed_r(fold,user) && !allowed_w(fold,user)))
 		{
@@ -172,7 +172,7 @@ void c_new(CommandList *cm, int argc, const char **argv, char *args)
 	busy++;
 	show_new(user);
 	busy--;
-	get_folder_number(fold,currentfolder);
+	get_folder_number(&user->folder, currentfolder);
 	update_user(user);
 }
 
@@ -182,18 +182,16 @@ void c_last(CommandList *cm, int argc, const char **argv, char *args)
 		printf(_("No current folder.\n"));
 		return;
 	}
-	last_mesg=fold->last;
+	last_mesg = user->folder.last;
 	printf(_("Moved to end of folder. (message %d)\n"),last_mesg);
 	read_msg(currentfolder, last_mesg, user);
-
 }
 
 void c_first(CommandList *cm, int argc, const char **argv, char *args)
 {
-	last_mesg=fold->first;
+	last_mesg = user->folder.first;
 	printf(_("Moved to start of folder. (message %d)\n"),last_mesg);
 	read_msg(currentfolder, last_mesg, user);
-
 }
 
 void c_user(CommandList *cm, int argc, const char **argv, char *args)
@@ -469,9 +467,9 @@ void c_mesg(CommandList *cm, int argc, const char **argv, char *args)
 {
 	update_user(user);
 	busy++;
-	mesg_edit(argv[1], fold, atoi(argv[2]), user);
+	mesg_edit(argv[1], &user->folder, atoi(argv[2]), user);
 	busy--;
-	mwlog("MESSAGE %s %s:%d",argv[1], fold->name, atoi(argv[2]));
+	mwlog("MESSAGE %s %s:%d",argv[1], user->folder.name, atoi(argv[2]));
 }
 
 void c_latest(CommandList *cm, int argc, const char **argv, char *args)
@@ -556,7 +554,7 @@ void c_pwd(CommandList *cm, int argc, const char **argv, char *args)
 		printf(_("No current folder.\n"));
 		return;
 	}
-	printf(_("Current folder = %s\n"),fold->name);
+	printf(_("Current folder = %s\n"), user->folder.name);
 	if (last_mesg==0)
 		printf(_("You haven't read any messages in this folder yet.\n"));
 	else
@@ -566,7 +564,7 @@ void c_pwd(CommandList *cm, int argc, const char **argv, char *args)
 void c_ls(CommandList *cm, int argc, const char **argv, char *args)
 {
 	int many;
-	if (allowed_r(fold,user))
+	if (allowed_r(&user->folder, user))
 	{
 		if (argc>1) many=atoi(argv[1]);
 		else many=0;
@@ -838,23 +836,23 @@ void c_passwd(CommandList *cm, int argc, const char **argv, char *args)
 
 void c_resub(CommandList *cm, int argc, const char **argv, char *args)
 {
-	if (get_subscribe(&user->record, currentfolder))
-		printf(_("You are already subscribed to %s.\n"),fold->name);
+	if (get_subscribe(user, currentfolder))
+		printf(_("You are already subscribed to %s.\n"), user->folder.name);
 	else
 	{
-		set_subscribe(&user->record, currentfolder, true);
-		printf(_("Resubscribing to %s.\n"),fold->name);
+		set_subscribe(user, currentfolder, true);
+		printf(_("Resubscribing to %s.\n"), user->folder.name);
 	}
 }
 
 void c_unsub(CommandList *cm, int argc, const char **argv, char *args)
 {
-	if (!get_subscribe(&user->record, currentfolder))
-		printf(_("Already Unsubscribed from %s.\n"),fold->name);
+	if (!get_subscribe(user, currentfolder))
+		printf(_("Already Unsubscribed from %s.\n"), user->folder.name);
 	else
 	{
-		set_subscribe(&user->record, currentfolder, false);
-		printf(_("Unsubscribing from %s.\n"),fold->name);
+		set_subscribe(user, currentfolder, false);
+		printf(_("Unsubscribing from %s.\n"), user->folder.name);
 	}
 }
 
@@ -867,13 +865,15 @@ void c_read(CommandList *cm, int argc, const char **argv, char *args)
 
 void c_prev(CommandList *cm, int argc, const char **argv, char *args)
 {
-	if (last_mesg<=fold->first) printf(_("You are already at the beginning of the folder.\n"));
+	if (last_mesg <= user->folder.first)
+		printf(_("You are already at the beginning of the folder.\n"));
 	else if (read_msg(currentfolder, last_mesg-1, user)) last_mesg--;
 }
 
 void c_next(CommandList *cm, int argc, const char **argv, char *args)
 {
-	if (last_mesg>=fold->last) printf(_("You are already at the end of this folder.\n"));
+	if (last_mesg >= user->folder.last)
+		printf(_("You are already at the end of this folder.\n"));
 	else if (read_msg(currentfolder, last_mesg+1, user)) last_mesg++;
 }
 
@@ -922,14 +922,14 @@ void c_status(CommandList *cm, int argc, const char **argv, char *args)
 		printf(_("You %s informed of user status changes.\n"),
 		       s_changeinfo(user)?_("will"):_("will not"));
 	if (*gr) printf(_("You belong to the following group(s) [%s]\n"),gr);
-	printf(_("You are currently in folder %s, which you "),fold->name);
-	printf(get_subscribe(&user->record, currentfolder)?_("are"):_("are not"));
+	printf(_("You are currently in folder %s, which you "), user->folder.name);
+	printf(get_subscribe(user, currentfolder)?_("are"):_("are not"));
 	printf(_(" subscribed to.\n"));
 	if (user->record.timeout == 0)
 		printf(_("You will not be timed out for being idle.\n"));
 	else
 		printf(_("You will be timed out after being idle for %s.\n"),itime(user->record.timeout));
-	time_on(user->record.timeused+(time(0) - loggedin));
+	time_on(user->record.timeused+(time(0) - user->loggedin));
 }
 
 static void credits(void)
@@ -1005,6 +1005,8 @@ void c_catchup(CommandList *cm, int argc, const char **argv, char *args)
 	}else
 	if (argc>1)
 	{
+		struct folder *fold = &user->folder;
+
 		if ((i=foldernumber(argv[1]))<0)
 		{
 			printf(_("There is no folder '%s'\n"),argv[1]);
@@ -1019,13 +1021,13 @@ void c_catchup(CommandList *cm, int argc, const char **argv, char *args)
 		}
 	}else
 	{
-		get_folder_number(fold,currentfolder);
+		get_folder_number(&user->folder, currentfolder);
 		i=currentfolder;
 	}
-	user->record.lastread[i]=fold->last;
+	user->record.lastread[i] = user->folder.last;
 	update_user(user);
-	printf(_("Marking folder %s as read.\n"),fold->name);
-	get_folder_number(fold,currentfolder);
+	printf(_("Marking folder %s as read.\n"), user->folder.name);
+	get_folder_number(&user->folder, currentfolder);
 }
 
 void c_date(CommandList *cm, int argc, const char **argv, char *args)


=====================================
src/client/script.c
=====================================
--- a/src/client/script.c
+++ b/src/client/script.c
@@ -29,7 +29,7 @@ extern Alias bind_list;
 
 #define MAX_ARGC 128
 
-extern struct user *user;
+extern struct user * const user;
 extern unsigned long rights;
 extern int busy;
 extern int current_rights;
@@ -498,7 +498,7 @@ void scr_helpfile(const char *args)
 			printf("No general help available on scripts.\n");
 	}else
 	{
-		AUTOFREE_BUFFER x = NULL;
+		_autofree char *x = NULL;
 
 		inst=inst_table;
 		while (inst->name != NULL && strcasecmp(inst->name, args)) {


=====================================
src/client/script_inst.c
=====================================
--- a/src/client/script_inst.c
+++ b/src/client/script_inst.c
@@ -28,7 +28,7 @@
 #include "util.h"
 #include "who.h"
 
-extern struct user *user;
+extern struct user * const user;
 extern Alias alias_list;
 extern Alias bind_list;
 /* current script runaway variable */
@@ -137,8 +137,8 @@ Instruction inst_table[]={
 
 void scr_time( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER what = NULL;
-	AUTOFREE_BUFFER value = NULL;
+	_autofree char *what = NULL;
+	_autofree char *value = NULL;
 	time_t now = time(0);
 
 	if (pc->argc < 1) {
@@ -158,7 +158,7 @@ void scr_time( struct code *pc, int fargc, char **fargv )
 	}
 	else if (!strcasecmp(pc->inst->name, "useridle"))
 	{
-		AUTOFREE_BUFFER uname = eval_arg(pc->argv[1], fargc, fargv);
+		_autofree char *uname = eval_arg(pc->argv[1], fargc, fargv);
 
 		if (script_debug) escprintf("- %s: Getting idletime of user '%s'.\n", pc->inst->name, uname);
 
@@ -213,8 +213,8 @@ void scr_time( struct code *pc, int fargc, char **fargv )
 void scr_say( struct code *pc, int fargc, char **fargv )
 {
 	int i, size, count;
-	AUTOFREE_BUFFER tmp = NULL;
-	AUTOFREE_BUFFER p = NULL;
+	_autofree char *tmp = NULL;
+	_autofree char *p = NULL;
 	char utf8buff[MAXTEXTLENGTH];
 	int conversion_result;
 
@@ -296,7 +296,7 @@ void scr_showrunaway( struct code *pc, int fargc, char **fargv )
 
 void scr_output( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER what = NULL;
+	_autofree char *what = NULL;
 	int i;
 
 	if (event_user==NULL)
@@ -320,8 +320,8 @@ void scr_output( struct code *pc, int fargc, char **fargv )
 
 void scr_wholist( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER what = NULL;
-	AUTOFREE_BUFFER buff = NULL;
+	_autofree char *what = NULL;
+	_autofree char *buff = NULL;
 
 	if (pc->argc < 1) {
 		if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
@@ -357,7 +357,7 @@ void scr_wholist( struct code *pc, int fargc, char **fargv )
 
 void scr_roomnum( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER what = NULL;
+	_autofree char *what = NULL;
 	char rn[10];
 
 	/* set initial room to -1 for unknown */
@@ -399,7 +399,7 @@ void scr_roomnum( struct code *pc, int fargc, char **fargv )
 	}
 	else if (!strcasecmp(pc->inst->name, "userroom"))
 	{
-		AUTOFREE_BUFFER uname = NULL;
+		_autofree char *uname = NULL;
 		int rnum = -1;
 
 		uname=eval_arg(pc->argv[1], fargc, fargv);
@@ -435,8 +435,8 @@ void scr_roomnum( struct code *pc, int fargc, char **fargv )
 
 void scr_talkpriv( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER what = NULL;
-	AUTOFREE_BUFFER buff = NULL;
+	_autofree char *what = NULL;
+	_autofree char *buff = NULL;
 	unsigned long mask = 0xffffffff;
 
 	if (pc->argc < 1) {
@@ -606,8 +606,8 @@ int isanumul(const char *a, unsigned long *result, int onlydecimal)
 
 void scr_compare( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER a = NULL;
-	AUTOFREE_BUFFER b = NULL;
+	_autofree char *a = NULL;
+	_autofree char *b = NULL;
 	int aa=0, bb=0;
 	int numeric=0;
 
@@ -684,8 +684,8 @@ void scr_compare( struct code *pc, int fargc, char **fargv )
 void scr_math( struct code *pc, int fargc, char **fargv )
 {
 	int a, b;
-	AUTOFREE_BUFFER aa = NULL;
-	AUTOFREE_BUFFER bb = NULL;
+	_autofree char *aa = NULL;
+	_autofree char *bb = NULL;
 	var_op_t var;
 	int result=0;
 
@@ -753,8 +753,8 @@ void scr_math( struct code *pc, int fargc, char **fargv )
 void scr_math2( struct code *pc, int fargc, char **fargv )
 {
 	int a;
-	AUTOFREE_BUFFER aa = NULL;
-	AUTOFREE_BUFFER bb = NULL;
+	_autofree char *aa = NULL;
+	_autofree char *bb = NULL;
 	var_op_t var;
 	int result=0;
 
@@ -800,7 +800,7 @@ void scr_math2( struct code *pc, int fargc, char **fargv )
 
 void scr_sleep( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER	aa = NULL;
+	_autofree char *aa = NULL;
 	int	a;
 	struct timeval delay;
 
@@ -827,9 +827,9 @@ void scr_sleep( struct code *pc, int fargc, char **fargv )
 void scr_rand( struct code *pc, int fargc, char **fargv )
 {
 	char	buff[20];
-	AUTOFREE_BUFFER	aa = NULL;
-	AUTOFREE_BUFFER bb = NULL;
-	AUTOFREE_BUFFER what = NULL;
+	_autofree char *aa = NULL;
+	_autofree char *bb = NULL;
+	_autofree char *what = NULL;
 	int	a, b;
 
 	if (pc->argc<3) {
@@ -872,10 +872,10 @@ void scr_rand( struct code *pc, int fargc, char **fargv )
 
 void scr_makestr( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER aa=NULL;
-	AUTOFREE_BUFFER bb=NULL;
-	AUTOFREE_BUFFER cc=NULL;
-	AUTOFREE_BUFFER out=NULL;
+	_autofree char *aa=NULL;
+	_autofree char *bb=NULL;
+	_autofree char *cc=NULL;
+	_autofree char *out=NULL;
 	var_op_t var;
 	int i, j;
 
@@ -916,10 +916,10 @@ void scr_makestr( struct code *pc, int fargc, char **fargv )
 
 void scr_split( struct code *pc, int fargc, char **fargv )
 {
-	AUTOFREE_BUFFER aa=NULL;
-	AUTOFREE_BUFFER bb=NULL;
-	AUTOFREE_BUFFER cc=NULL;
-	AUTOFREE_BUFFER text=NULL;
+	_autofree char *aa=NULL;
+	_autofree char *bb=NULL;
+	_autofree char *cc=NULL;
+	_autofree char *text=NULL;
 	var_op_t var1, var2;
 
 	if (pc->argc<3) {
@@ -980,9 +980,9 @@ void scr_split( struct code *pc, int fargc, char **fargv )
 void scr_strcat( struct code *pc, int fargc, char **fargv )
 {
 	var_op_t var;
-	AUTOFREE_BUFFER a=NULL;
-	AUTOFREE_BUFFER b=NULL;
-	AUTOFREE_BUFFER nbuff=NULL;
+	_autofree char *a=NULL;
+	_autofree char *b=NULL;
+	_autofree char *nbuff=NULL;
 
 	if (pc->argc<2) {
 		if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
@@ -1009,8 +1009,8 @@ void scr_strcat( struct code *pc, int fargc, char **fargv )
 void scr_set(struct code *pc, int fargc, char **fargv)
 {
 	var_op_t var;
-	AUTOFREE_BUFFER what = NULL;
-	AUTOFREE_BUFFER text = NULL;
+	_autofree char *what = NULL;
+	_autofree char *text = NULL;
 
 	if (pc->argc < 2) {
 		if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
@@ -1046,8 +1046,8 @@ void scr_set(struct code *pc, int fargc, char **fargv)
 void scr_getvar(struct code *pc, int fargc, char **fargv)
 {
 	var_op_t var, var2;
-	AUTOFREE_BUFFER what = NULL;
-	AUTOFREE_BUFFER value=NULL;
+	_autofree char *what = NULL;
+	_autofree char *value=NULL;
 
 	if (pc->argc < 2) {
 		if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
@@ -1096,7 +1096,7 @@ void scr_getvar(struct code *pc, int fargc, char **fargv)
 void scr_unset(struct code *pc, int fargc, char **fargv)
 {
 	var_op_t var;
-	AUTOFREE_BUFFER what = NULL;
+	_autofree char *what = NULL;
 
 	if (pc->argc < 1)
 	{
@@ -1121,8 +1121,8 @@ void scr_clearvars(struct code *pc, int fargc, char **fargv)
 {
 	var_op_t iter;
 	var_op_t op;
-	AUTOFREE_BUFFER what = NULL;
-	AUTOFREE_BUFFER key = NULL;
+	_autofree char *what = NULL;
+	_autofree char *key = NULL;
 
 	if (pc->argc > 1) {
 		if (script_debug) printf("Error in %s at %s too many arguments.\n", pc->inst->name, pc->debug);


=====================================
src/client/strings.c
=====================================
--- a/src/client/strings.c
+++ b/src/client/strings.c
@@ -42,7 +42,7 @@ int pop_stack(char *string, int len)
 {
 	int type=0;
 	pop_cmd(string, len, &type);
-	return (type && CMD_FORCED) != 0;
+	return type;
 }
 
 void pop_cmd(char *string, int len, int *type)
@@ -62,13 +62,3 @@ void pop_cmd(char *string, int len, int *type)
 	}
 	string[len]=0;
 }
-
-/* common file functions */
-int err_open(const char *path,int type,int mode)
-{
-	int x;
-	x=open(path,type,mode);
-	if (x<0)
-		perror(path);
-	return(x);
-}


=====================================
src/client/strings.h
=====================================
--- a/src/client/strings.h
+++ b/src/client/strings.h
@@ -5,7 +5,6 @@
 #define CMD_BOARD	1	/* Always a board command, used by BOARDEXEC */
 #define CMD_TALKER	2	/* Always a talker command, used by EXEC     */
 #define CMD_TYPED	0	/* Was entered at the keyboard               */
-#define CMD_FORCED	0x100	/* Forced by another user                    */
 
 struct stacked_str {
 	char *text;
@@ -18,6 +17,5 @@ void stack_str(char *string);
 int is_stacked(void);
 void pop_cmd(char *string, int len, int *type);
 int pop_stack(char *string, int len);
-int err_open(const char *path,int type,int mode);
 
 #endif /* STRINGS_H */


=====================================
src/client/talker.c
=====================================
--- a/src/client/talker.c
+++ b/src/client/talker.c
@@ -47,9 +47,7 @@ extern Alias shutdown_list;
 extern int busy; /* if true dont display messages  i.e. during new/write */
 extern unsigned long rights;
 
-extern struct user *user;
-extern struct folder *fold;
-extern unsigned long loggedin;
+extern struct user * const user;
 extern int quietmode;
 static int runautoexec = 1;
 
@@ -911,7 +909,7 @@ void t_ungag(CommandList *cm, int argc, const char **argv, char *args)
 
 void t_zod(CommandList *cm, int argc, const char **argv, char *args)
 {
-	AUTOFREE_BUFFER excuse = remove_first_word(args);
+	_autofree char *excuse = remove_first_word(args);
 	ipc_message_t * msg = ipcmsg_create(IPC_ACTION, user->posn);
 	json_t * j = json_init(NULL);
 	json_addstring(j, "target", argv[1]);
@@ -925,7 +923,7 @@ void t_zod(CommandList *cm, int argc, const char **argv, char *args)
 
 void t_mrod(CommandList *cm, int argc, const char **argv, char *args)
 {
-	AUTOFREE_BUFFER excuse = remove_first_word(args);
+	_autofree char *excuse = remove_first_word(args);
 	ipc_message_t * msg = ipcmsg_create(IPC_ACTION, user->posn);
 	json_t * j = json_init(NULL);
 	json_addstring(j, "target", argv[1]);
@@ -939,7 +937,7 @@ void t_mrod(CommandList *cm, int argc, const char **argv, char *args)
 
 void t_kick(CommandList *cm, int argc, const char **argv, char *args)
 {
-	AUTOFREE_BUFFER excuse = remove_first_word(args);
+	_autofree char *excuse = remove_first_word(args);
 	ipc_message_t * msg = ipcmsg_create(IPC_ACTION, user->posn);
 	json_t * j = json_init(NULL);
 	json_addstring(j, "target", argv[1]);
@@ -954,7 +952,7 @@ void t_kick(CommandList *cm, int argc, const char **argv, char *args)
 
 void t_remove(CommandList *cm, int argc, const char **argv, char *args)
 {
-	AUTOFREE_BUFFER excuse = remove_first_word(args);
+	_autofree char *excuse = remove_first_word(args);
 	ipc_message_t * msg = ipcmsg_create(IPC_ACTION, user->posn);
 	json_t * j = json_init(NULL);
 	json_addstring(j, "target", argv[1]);
@@ -1051,7 +1049,7 @@ void t_linewrap(CommandList *cm, int argc, const char **argv, char *args)
 
 void t_topic(CommandList *cm, int argc, const char **argv, char *args)
 {
-	AUTOFREE_BUFFER buff=NULL;
+	_autofree char *buff=NULL;
 
 	if (argc == 1) {
 		char *topic;
@@ -1169,7 +1167,7 @@ void enter_room(int room)
 	char *topic = db_room_get(room, "topic");
 	if (topic != NULL) {
 		if (*topic != 0) {
-			AUTOFREE_BUFFER buff=NULL;
+			_autofree char *buff=NULL;
 			asprintf(&buff, "Topic: %s\n", topic);
 			display_message(buff, 0, 1);
 		}
@@ -1316,7 +1314,7 @@ void t_help(CommandList *cm, int argc, const char **argv, char *args)
 			printf("No general help available for talker commands.\n");
 	}else
 	{
-		AUTOFREE_BUFFER x = NULL;
+		_autofree char *x = NULL;
 
 		/* find the command in the list */
 		c = chattable;
@@ -1367,7 +1365,7 @@ int ChangeRoom(char *room, int quiet)
 	struct room tmp;
 	int i;
 	unsigned short oldroom = user->record.room;
-	AUTOFREE_BUFFER buff=NULL;
+	_autofree char *buff=NULL;
 
 	if (cm_test(user, CM_FROZEN))
 	{


=====================================
src/client/talker_privs.c
=====================================
--- a/src/client/talker_privs.c
+++ b/src/client/talker_privs.c
@@ -11,7 +11,7 @@
 #include <gags.h>
 #include <util.h>
 
-extern struct user *user;
+extern struct user * const user;
 extern int quietmode;
 
 unsigned long chatmode_describe(unsigned long old, unsigned long new, int ourapl, int theirapl, const char *from)
@@ -129,7 +129,7 @@ unsigned long chatmode_describe(unsigned long old, unsigned long new, int ourapl
 		if (gi!=NULL)
 		{
 			/* gag was enabled */
-			AUTOFREE_BUFFER buff=NULL;
+			_autofree char *buff=NULL;
 			asprintf(&buff, "*** %s", gi->gag);
 			display_message(buff, 1, 1);
 		}
@@ -139,7 +139,7 @@ unsigned long chatmode_describe(unsigned long old, unsigned long new, int ourapl
 			gi = gag_find(oldg);
 			if (gi!=NULL)
 			{
-				AUTOFREE_BUFFER buff=NULL;
+				_autofree char *buff=NULL;
 				asprintf(&buff, "*** %s", gi->ungag);
 				display_message(buff, 1, 1);
 			}


=====================================
src/client/uri.c
=====================================
--- a/src/client/uri.c
+++ b/src/client/uri.c
@@ -15,7 +15,7 @@
 #include "user.h"
 #include "mesg.h"
 
-extern struct user *user;
+extern struct user * const user;
 
 // uri action table
 // action, minargc, maxargc, tcmode, needs su, function


=====================================
src/client/user.c
=====================================
--- a/src/client/user.c
+++ b/src/client/user.c
@@ -31,8 +31,7 @@ const char *partlist_search[]={
 "status", "special", "groups", "chatprivs", "chatmode", "protpower",
 "protlevel", NULL};
 
-extern struct user *user;
-extern struct folder *fold;
+extern struct user * const user;
 extern int internet;
 
 char *getmylogin(void)
@@ -61,8 +60,6 @@ static int old_usr(struct user *usr)
 		if (strcmp(passwd, usr->record.passwd))
 		{
 			printf(_("Login Incorrect.\n\n"));
-			SAFE_FREE(user);
-			SAFE_FREE(fold);
 			exit(0);
 		}
 	}
@@ -70,8 +67,6 @@ static int old_usr(struct user *usr)
 	{
 		printf(_("Sorry, this username has been banned.\n"));
 		printf(_("Have a nice day. *:-)\n"));
-		SAFE_FREE(user);
-		SAFE_FREE(fold);
 		exit(0);
 	}
 	printf(_("Hello %s.\n"), usr->record.name);
@@ -117,11 +112,8 @@ gstart:
 	}
 	strip_name(name);
 	if (feof(stdin))
-	{
-		SAFE_FREE(user);
-		SAFE_FREE(fold);
 		exit(0);
-	}
+
 	if (strlen(name)<1)
 	{
 		if (lname==NULL)
@@ -136,28 +128,6 @@ gstart:
 	}
 }
 
-int get_person(int file, struct user *u)
-{
-	struct person *tmp = &u->record;
-	int no;
-
-	if (!(no=read(file,tmp,sizeof(*tmp))))
-	{
-		return false;
-	}else
-	if (no<sizeof(*tmp))
-	{
-		printf(_("Problem in get_person: my uid=%d my euid=%d"), getuid(), geteuid());
-		perror("userfile");
-		SAFE_FREE(user);
-		SAFE_FREE(fold);
-		exit(-1);
-	}
-	u->posn = lseek(file, 0, SEEK_CUR) - sizeof(*tmp);
-
-	return true;
-}
-
 void pick_salt(char *salt)
 {
 	strcpy(salt,"ab");
@@ -305,8 +275,6 @@ static int new_usr(char *name, struct user *u)
 		{
 			printf(_("User record '%s' cancelled.\n"),usr->name);
 			printf(_("Goodbye.\n"));
-			SAFE_FREE(user);
-			SAFE_FREE(fold);
 			exit(0);
 		}
 		strip_str(usr->realname);
@@ -318,7 +286,6 @@ static int new_usr(char *name, struct user *u)
 		mwlog("CREATED: %s <%s>",usr->realname, usr->contact);
 		broadcast(3, "Created user %s: %s <%s>", name, usr->realname, usr->contact);
 		set_defaults(usr);
-		user=u;
 		printf(_("Creating new user %s\n"),name);
 
 		userdb_write(u);
@@ -343,6 +310,7 @@ void login_ok(struct user *usr, int *autochat)
 
 void list_users(int newonly)
 {
+	int err;
 	int file;
 	struct user usr;
 	char stats[10],gr[10];
@@ -354,8 +322,7 @@ void list_users(int newonly)
 	if (file < 0)
 		return;
 
-	while (get_person(file, &usr))
-	{
+	for_each_user(&usr, file, err) {
 		if (!newonly || ( newonly && !u_reg(&usr) ) )
 		{
 			logout_time = usr.record.lastlogout;
@@ -385,6 +352,7 @@ void list_users(int newonly)
 
 void list_users_since(long date)
 {
+	int err;
 	int file;
 	struct user usr;
 	struct person *urec = &usr.record;
@@ -397,8 +365,7 @@ void list_users_since(long date)
 	if (file < 0)
 		return;
 
-	while (get_person(file, &usr))
-	{
+	for_each_user(&usr, file, err) {
 		if (urec->lastlogout > date)
 		{
 			logout_time = urec->lastlogout;
@@ -430,6 +397,7 @@ static void list_users_flags(int flags, int type, int inv)
 /*type: 0=status 1=special 2=group 3=chatmodes 4=chatprivs */
 /*inv: 0= with flags, 1=without flags */
 {
+	int err;
 	int file;
 	struct user usr;
 	struct person *urec = &usr.record;
@@ -443,8 +411,7 @@ static void list_users_flags(int flags, int type, int inv)
 	if (file < 0)
 		return;
 
-	while (get_person(file,&usr))
-	{
+	for_each_user(&usr, file, err) {
 		if (type==0) check=urec->status;
 		else
 		if (type==1) check=urec->special;


=====================================
src/client/user.h
=====================================
--- a/src/client/user.h
+++ b/src/client/user.h
@@ -6,7 +6,6 @@
 
 char *getmylogin(void);
 void get_login(char *name, int autochat);
-int get_person(int file, struct user *user);
 void list_users(int newonly);
 void list_users_since(long date);
 void login_ok(struct user *usr, int *autochat);


=====================================
src/client/who.c
=====================================
--- a/src/client/who.c
+++ b/src/client/who.c
@@ -26,7 +26,7 @@
 #include <util.h>
 
 extern int busy;
-extern struct user *user;
+extern struct user * const user;
 
 char *itime(unsigned long t)
 {
@@ -66,7 +66,7 @@ void display_wholist(int mode)
 	else
 		format_message("\nPID    %-*s %-*s  Idle  What...",NAMESIZE,"Name",20,"RealName");
 
-	AUTOFREE_BUFFER divider = NULL;
+	_autofree char *divider = NULL;
 	for (int i = 0; i < screen_w(); i++) string_add(&divider, "-");
 	format_message("%s", divider);
 


=====================================
src/folders.h
=====================================
--- a/src/folders.h
+++ b/src/folders.h
@@ -2,7 +2,6 @@
 #define FOLDERS_H
 
 #include <stdint.h>
-#include "user.h"
 
 #define FOLNAMESIZE 	10	/* length of folder names */
 #define TOPICSIZE 	30	/* length of the topic of the folder */


=====================================
src/perms.c
=====================================
--- a/src/perms.c
+++ b/src/perms.c
@@ -233,8 +233,10 @@ void show_fold_groups(char st, char *tmp, int flag)
 	tmp[pos] = '\0';
 }
 
-int get_subscribe(struct person *usr, int folder)
+int get_subscribe(struct user *user, int folder)
 {
+	struct person *usr = &user->record;
+
 	if (folder<=31 && folder>=0)
 	{
 		if (usr->folders[0] & (1<<folder) )
@@ -255,8 +257,10 @@ int get_subscribe(struct person *usr, int folder)
 	}
 }
 
-void set_subscribe(struct person *usr,int folder,int status)
+void set_subscribe(struct user *user,int folder,int status)
 {
+	struct person *usr = &user->record;
+
 	if (folder>=0 && folder<=31)
 	{
 		if (status==true)


=====================================
src/perms.h
=====================================
--- a/src/perms.h
+++ b/src/perms.h
@@ -21,7 +21,7 @@ int is_moderated(struct folder *fol, struct user *usr);
 char folder_stats(char *string, char stat);
 char folder_groups(const char *string, char stat);
 
-void set_subscribe(struct person *user,int folder,int status);
-int get_subscribe(struct person *user, int folder);
+void set_subscribe(struct user *user, int folder, int status);
+int get_subscribe(struct user *user, int folder);
 
 #endif


=====================================
src/server/actions.c
=====================================
--- a/src/server/actions.c
+++ b/src/server/actions.c
@@ -95,7 +95,7 @@ void accept_action(ipc_connection_t *conn, ipc_message_t *msg)
 			json_addstring(ej, "verbose", "You hear a boing in the distance, closely followed by the distant wail of a hurdy-gurdy, which is suddenly terminated by a blood curdling scream, a C major chord explosion and a few curious springing noises...");
 
 			// kick the person
-			AUTOFREE_BUFFER buff=NULL;
+			_autofree char *buff=NULL;
 			if (reason != NULL) {
 				asprintf(&buff,"mr%s", reason);
 				json_addstring(ej, "reason", reason);
@@ -136,7 +136,7 @@ void accept_action(ipc_connection_t *conn, ipc_message_t *msg)
 			json_addstring(ej, "verbose", "You hear a boing in the distance");
 
 			// kick the person
-			AUTOFREE_BUFFER buff=NULL;
+			_autofree char *buff=NULL;
 			if (reason != NULL) {
 				asprintf(&buff,"zr%s", reason);
 				json_addstring(ej, "reason", reason);
@@ -188,7 +188,7 @@ void accept_action(ipc_connection_t *conn, ipc_message_t *msg)
 			               attacker_name, victim_name, gag_type(gtnum));
 
 			// change users mode
-			AUTOFREE_BUFFER buff=NULL;
+			_autofree char *buff=NULL;
 			asprintf(&buff,"+%d", gtnum);
 			ipc_message_t *update = ipcmsg_create(IPC_GAG, msg->head.src);
 			ipcmsg_destination(update, toid);
@@ -219,7 +219,7 @@ void accept_action(ipc_connection_t *conn, ipc_message_t *msg)
 			json_addstring(ej, "text", "%s has just ungagged %s", attacker_name, victim_name);
 
 			// change users mode
-			AUTOFREE_BUFFER buff=NULL;
+			_autofree char *buff=NULL;
 			asprintf(&buff,"-");
 			ipc_message_t *update = ipcmsg_create(IPC_GAG, msg->head.src);
 			ipcmsg_destination(update, toid);


=====================================
src/server/mwserv.c
=====================================
--- a/src/server/mwserv.c
+++ b/src/server/mwserv.c
@@ -48,7 +48,7 @@ static const struct cfg_default_opt defcfgs[] = {
 
 static int config_init(void)
 {
-	AUTOFREE_BUFFER homeconf = NULL;
+	_autofree char *homeconf = NULL;
 	const char *homedir;
 	int ret;
 


=====================================
src/server/servsock.c
=====================================
--- a/src/server/servsock.c
+++ b/src/server/servsock.c
@@ -244,7 +244,7 @@ void send_error(ipc_connection_t *conn, ipc_message_t *orig, const char *format,
 {
 	va_list va;
 	va_start(va, format);
-	AUTOFREE_BUFFER text = NULL;
+	_autofree char *text = NULL;
 	vasprintf(&text, format, va);
 	va_end(va);
 
@@ -311,7 +311,7 @@ void process_msg(ipc_connection_t *conn, ipc_message_t *msg)
 
 		json_t * j = json_init(NULL);
 		json_addint(j, "uptime", now - uptime);
-		AUTOFREE_BUFFER version = NULL;
+		_autofree char *version = NULL;
 		asprintf(&version, "%s.%s.%s", VER_MAJ, VER_MIN, VER_TWK);
 		json_addstring(j, "version", version);
 		ipcmsg_json_encode(msg, j);
@@ -571,7 +571,7 @@ void msg_attach(ipc_message_t *msg, ipc_connection_t *conn)
  **/
 void msg_apply_gag(struct user *from, ipc_message_t * msg, const char * field)
 {
-	AUTOFREE_BUFFER newtext = NULL;
+	_autofree char *newtext = NULL;
 	json_t * j = json_init(msg);
 	const char * text = json_getstring(j, field);
 


=====================================
src/socket.c
=====================================
--- a/src/socket.c
+++ b/src/socket.c
@@ -307,7 +307,7 @@ int json_addstring(json_t * js, const char * key, const char * value, ...)
 	json_t * tmp;
 	va_list va;
 	va_start(va, value);
-	AUTOFREE_BUFFER text = NULL;
+	_autofree char *text = NULL;
 	vasprintf(&text, value, va);
 	va_end(va);
 


=====================================
src/user.c
=====================================
--- a/src/user.c
+++ b/src/user.c
@@ -52,21 +52,57 @@ void update_user(struct user *user)
 	close(outfile);
 }
 
+static int fetch_user_fd(int fd, struct person *rec, off_t offset)
+{
+	ssize_t bytes = pread(fd, rec, sizeof(*rec), offset);
+	if (bytes == 0)
+		return 1; /* EOF */
+
+	if (bytes == sizeof(*rec))
+		return 0; /* Done */
+
+	/* Partial read or error */
+	perror("pread");
+	return -1;
+}
+
 int fetch_user(struct user *user, int32_t userposn)
 {
-	struct person *record = &user->record;
         int outfile = userdb_open(O_RDWR|O_CREAT);
 	if (outfile < 0)
-		return 1;
+		return -1;
 
-        if (pread(outfile, record, sizeof(*record), userposn) != sizeof(*record)) {
-		perror("pread");
-		close(outfile);
-		return 1;
-	}
+	int ret = fetch_user_fd(outfile, &user->record, userposn);
         close(outfile);
-	user->posn = userposn;
-	return 0;
+	if (ret == 0)
+		user->posn = userposn;
+	return ret;
+}
+
+int fetch_first_user(int fd, struct user *user)
+{
+	int ret;
+
+	if (user == NULL)
+		return -1;
+
+	ret = fetch_user_fd(fd, &user->record, 0);
+	if (ret == 0)
+		user->posn = 0;
+	return ret;
+}
+
+int fetch_next_user(int fd, struct user *user)
+{
+	int ret;
+
+	if (user == NULL)
+		return -1;
+
+	ret = fetch_user_fd(fd, &user->record, user->posn + sizeof(user->record));
+	if (ret == 0)
+		user->posn += sizeof(user->record);
+	return ret;
 }
 
 static int user_find_name(const char *name, struct user *user, int *found)


=====================================
src/user.h
=====================================
--- a/src/user.h
+++ b/src/user.h
@@ -2,6 +2,8 @@
 #define USER_H
 
 #include <stdint.h>
+#include <time.h>
+#include "folders.h"
 #include "rooms.h"
 
 #define NAMESIZE 	16	/* username */
@@ -71,15 +73,24 @@ struct person
 struct user {
 	int32_t posn;
 	struct person record;
+	struct folder folder;
 	struct room room;
+	time_t loggedin;
 };
 
 extern int userdb_open(int flags);
 extern void userdb_write(struct user *user);
 extern int fetch_user(struct user *record, int32_t userposn);
+extern int fetch_first_user(int fd, struct user *user);
+extern int fetch_next_user(int fd, struct user *user);
 extern void update_user(struct user *user);
 extern int update_user_fd(int fd, struct user *user);
 extern int is_old(const char *name, struct user *user);
 extern struct user* user_get(const char *name);
 
+#define for_each_user(userp, fd, status) \
+	for((status) = fetch_first_user((fd), (userp)); \
+	 (status) == 0; \
+	 (status) = fetch_next_user((fd), (userp)))
+
 #endif


=====================================
src/util.h
=====================================
--- a/src/util.h
+++ b/src/util.h
@@ -2,20 +2,14 @@
 #define UTIL_H
 
 #include <stdlib.h>
+#include <unistd.h>
 
-/* TR's auto-free asprintf type stuff */
-__attribute__((unused)) static inline void cleanup_buffer(void *buffer)
+__attribute__((unused)) static inline void cleanup_free(void *x)
 {
-	char **b = buffer;
-	if (NULL != *b)
-	{
-		free(*b);
-	}
+	free(*((void **)x));
 }
-#define AUTOFREE_BUFFER __attribute__((cleanup(cleanup_buffer))) char *
-
+#define _autofree __attribute__((cleanup(cleanup_free)))
 
 #define SAFE_FREE(a)	do { if (a) { free(a); (a) = NULL; } } while(0);
 
-
 #endif /* UTIL_H */


=====================================
src/webclient/comms.c
=====================================
--- a/src/webclient/comms.c
+++ b/src/webclient/comms.c
@@ -42,7 +42,7 @@ int die = 0;
 extern time_t lastcomm;
 extern char * authtext;
 
-extern struct user *user;
+extern struct user * const user;
 
 typedef struct {
 	struct list_head list;
@@ -453,9 +453,9 @@ static int handle_command(CONNECTION *co)
                 return 1;
         }else
         if (co->authd && strncasecmp(buff, "replay ", 7)==0) {
-		AUTOFREE_BUFFER style=NULL;
-		AUTOFREE_BUFFER value=NULL;
-		AUTOFREE_BUFFER line = NULL;
+		_autofree char *style=NULL;
+		_autofree char *value=NULL;
+		_autofree char *line = NULL;
 		char *tmpu;
 		style = remove_first_word(buff);
 		value = remove_first_word(style);


=====================================
src/webclient/import.c
=====================================
--- a/src/webclient/import.c
+++ b/src/webclient/import.c
@@ -15,7 +15,7 @@
 #include <bb.h>
 #include "import.h"
 
-extern struct user *user;
+extern struct user * const user;
 int incoming_pipe = -1;
 
 #define min(a,b) a<b?a:b



View it on GitLab: https://projects.sucs.org/arthur/mw/compare/c30536af79c24adf5249ae06ad4c8e8e44b7ea67...d881fc863cfee125b72b8c07e89090b7a4dceeb6
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sucs.org/pipermail/mw-devel/attachments/20151107/b1f1a801/attachment-0001.html>


More information about the mw-devel mailing list