<html lang='en'>
<head>
<meta content='text/html; charset=utf-8' http-equiv='Content-Type'>
<title>
GitLab
</title>
</meta>
</head>
<style>
  img {
    max-width: 100%;
    height: auto;
  }
  p.details {
    font-style:italic;
    color:#777
  }
  .footer p {
    font-size:small;
    color:#777
  }
  pre.commit-message {
    white-space: pre-wrap;
  }
  .file-stats a {
    text-decoration: none;
  }
  .file-stats .new-file {
    color: #090;
  }
  .file-stats .deleted-file {
    color: #B00;
  }
</style>
<body>
<div class='content'>
<h3>Justin Mitchell pushed to branch master at <a href="https://projects.sucs.org/arthur/mw">Justin Mitchell / mw</a></h3>
<h4>
Commits:
</h4>
<ul>
<li>
<strong><a href="https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888">b5193749</a></strong>
<div>
<span>by Justin Mitchell</span>
<i>at 2015-10-07T17:15:47Z</i>
</div>
<pre class='commit-message'>Remove the last of the references to who file from main client</pre>
</li>
</ul>
<h4>7 changed files:</h4>
<ul>
<li class='file-stats'>
<a href='#diff-0'>
src/client/js.c
</a>
</li>
<li class='file-stats'>
<a href='#diff-1'>
src/client/script_inst.c
</a>
</li>
<li class='file-stats'>
<a href='#diff-2'>
src/client/who.c
</a>
</li>
<li class='file-stats'>
<a href='#diff-3'>
src/client/who.h
</a>
</li>
<li class='file-stats'>
<a href='#diff-4'>
src/gags.c
</a>
</li>
<li class='file-stats'>
<a href='#diff-5'>
src/str_util.c
</a>
</li>
<li class='file-stats'>
<a href='#diff-6'>
src/str_util.h
</a>
</li>
</ul>
<h4>Changes:</h4>
<li id='diff-0'>
<a href='https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888#diff-0'>
<strong>
src/client/js.c
</strong>
</a>
<hr>
<pre class="highlight"><code><span style="color: #000000;background-color: #ffdddd">--- a/src/client/js.c
</span><span style="color: #000000;background-color: #ddffdd">+++ b/src/client/js.c
</span><span style="color: #aaaaaa">@@ -8,6 +8,8 @@
</span> #include <pwd.h>
 #include <readline/readline.h>
 #include <curl/curl.h>
<span style="color: #000000;background-color: #ddffdd">+#include <jansson.h>
+#include "who.h"
</span> 
 /* Ugly but necessary (this is how gjs shuts up the warnings,
    only gcc 4.6 has a nicer (push/pop) way to do it */
<span style="color: #aaaaaa">@@ -655,63 +657,63 @@ static JSBool js_termsize(JSContext *cx, unsigned int argc, jsval *vp)
</span> 
 // Provides a javascript function to query the wholist
 static JSBool js_wholist(JSContext *cx, unsigned int argc, jsval *vp) {
-       struct person u;
-       struct who w;
-       int ufile, wfile;
        JSObject *res;
        int n=0;
 
-       wfile=who_open(O_RDWR);
-       ufile=userdb_open(O_RDONLY);
-       if (wfile<0 || ufile<0) {
-               JS_ReportError(cx, "wholist() could not open userdb.");
-       
<span style="color: #000000;background-color: #ddffdd">+        json_t * wlist = grab_wholist();
+       if (wlist == NULL) {
+               JS_ReportError(cx, "Could not grab wholist, try again");
</span>           return JS_FALSE;
        }
<span style="color: #000000;background-color: #ddffdd">+
</span>   res = JS_NewArrayObject(cx, 0, NULL);
        JS_AddObjectRoot(cx, &res);
 
-       while (read(wfile,&w,sizeof(w))) {
<span style="color: #000000;background-color: #ddffdd">+        size_t wi;
+       json_t *entry;
+       time_t now = time(0);
+       json_array_foreach(wlist, wi, entry) {
+               json_t * perms = json_object_get(entry, "perms");
+
</span>           JSObject *user_record;
                JSString *jsstr;
                jsval jv, user_jv;
 
-               if (w.posn < 0) continue;
-               lseek(ufile,w.posn,SEEK_SET);
-               read(ufile,&u,sizeof(u));
-
                /* make a new row and populate it */
                user_record = JS_NewObject(cx, &js_userrecordclass, NULL, NULL);
                user_jv = OBJECT_TO_JSVAL(user_record);
                /* user name */
-               jsstr = JS_NewStringCopyZ(cx, u.name);
<span style="color: #000000;background-color: #ddffdd">+                jsstr = JS_NewStringCopyZ(cx, json_getstring(entry, "name"));
</span>           jv = STRING_TO_JSVAL(jsstr);
                JS_DefineProperty(cx, user_record, "username", jv, NULL, NULL, 0);
                /* room number */
-               jv = INT_TO_JSVAL(u.room);
<span style="color: #000000;background-color: #ddffdd">+                jv = INT_TO_JSVAL( json_getint(entry, "channel") );
</span>           JS_DefineProperty(cx, user_record, "room", jv, NULL, NULL, 0);
                /* idle time */
-               jv = INT_TO_JSVAL(time(0)-u.idletime);
<span style="color: #000000;background-color: #ddffdd">+                jv = INT_TO_JSVAL(now - json_getint(entry, "idletime"));
</span>           JS_DefineProperty(cx, user_record, "idle", jv, NULL, NULL, 0);
                /* chat modes */
-               jsstr = JS_NewStringCopyZ(cx, display_cmflags(u.chatmode));
<span style="color: #000000;background-color: #ddffdd">+                jsstr = JS_NewStringCopyZ(cx, json_getstring(entry, "chatmode"));
</span>           jv = STRING_TO_JSVAL(jsstr);
                JS_DefineProperty(cx, user_record, "chatmodes", jv, NULL, NULL, 0);
                /* protection level */
-               jv = INT_TO_JSVAL((u.chatmode & CM_PROTMASK) >> CM_PROTSHIFT);
<span style="color: #000000;background-color: #ddffdd">+                const char * prot = json_getstring(perms, "protection");
+               jv = INT_TO_JSVAL( prot[0] - '0');
</span>           JS_DefineProperty(cx, user_record, "protection_level", jv, NULL, NULL, 0);
-               jv = INT_TO_JSVAL((u.chatprivs & CP_PROTMASK) >> CP_PROTSHIFT);
<span style="color: #000000;background-color: #ddffdd">+                jv = INT_TO_JSVAL( prot[2] - '0');
</span>           JS_DefineProperty(cx, user_record, "protection_power", jv, NULL, NULL, 0);
-               /* chat privs */
-               jsstr = JS_NewStringCopyZ(cx, display_cpflags(u.chatprivs & user->chatprivs));
<span style="color: #000000;background-color: #ddffdd">+                /* chat perms */
+               jsstr = JS_NewStringCopyZ(cx, json_getstring(perms, "chatprivs") );
</span>           jv = STRING_TO_JSVAL(jsstr);
                JS_DefineProperty(cx, user_record, "chatprivs", jv, NULL, NULL, 0);
                /* status string */
-               jsstr = JS_NewStringCopyZ(cx, u.doing);
<span style="color: #000000;background-color: #ddffdd">+                jsstr = JS_NewStringCopyZ(cx, json_getstring(entry, "doing"));
</span>           jv = STRING_TO_JSVAL(jsstr);
                JS_DefineProperty(cx, user_record, "doing", jv, NULL, NULL, 0);
-               if (u.dowhen)
-                       jv = INT_TO_JSVAL(time(0)-u.dowhen);
<span style="color: #000000;background-color: #ddffdd">+
+               int dowhen = json_getint(entry, "dowhen");
+               if (dowhen)
+                       jv = INT_TO_JSVAL(now - dowhen);
</span>           else
                        jv = INT_TO_JSVAL(0);
                JS_DefineProperty(cx, user_record, "since", jv, NULL, NULL, 0);
<span style="color: #aaaaaa">@@ -719,11 +721,10 @@ static JSBool js_wholist(JSContext *cx, unsigned int argc, jsval *vp) {
</span>           /* stick line into master array */
                JS_SetElement(cx, res, n++, &user_jv);
        }
-       close(wfile);
-       close(ufile);
 
        JS_RemoveObjectRoot(cx, &res);
        JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(res));
<span style="color: #000000;background-color: #ddffdd">+        json_decref(wlist);
</span>   return JS_TRUE;
 }
 
</code></pre>

<br>
</li>
<li id='diff-1'>
<a href='https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888#diff-1'>
<strong>
src/client/script_inst.c
</strong>
</a>
<hr>
<pre class="highlight"><code><span style="color: #000000;background-color: #ffdddd">--- a/src/client/script_inst.c
</span><span style="color: #000000;background-color: #ddffdd">+++ b/src/client/script_inst.c
</span><span style="color: #aaaaaa">@@ -25,6 +25,8 @@
</span> #include "main.h"
 #include "user.h"
 #include "mesg.h"
<span style="color: #000000;background-color: #ddffdd">+#include "util.h"
+#include "who.h"
</span> 
 extern struct person *user;
 extern long userposn;
<span style="color: #aaaaaa">@@ -139,8 +141,9 @@ Instruction inst_table[]={
</span> 
 void scr_time( struct code *pc, int fargc, char **fargv )
 {
-       char *what;
-       char value[MAXTEXTLENGTH];
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
+       AUTOFREE_BUFFER value = NULL;
+       time_t now = time(0);
</span> 
        if (pc->argc < 1) {
                if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
<span style="color: #aaaaaa">@@ -150,31 +153,23 @@ void scr_time( struct code *pc, int fargc, char **fargv )
</span> 
        if (!strcasecmp(pc->inst->name, "unixtime"))
        {
-               snprintf(value,MAXTEXTLENGTH-1,"%d",(int)time(NULL));
<span style="color: #000000;background-color: #ddffdd">+                string_add(&value, "%ld", now);
</span>   }
        else if (!strcasecmp(pc->inst->name, "idletime"))
        {
-               snprintf(value, MAXTEXTLENGTH - 1, "%ld", (long)time(0) - user->idletime);
-               if (script_debug) printf("- Idle time is %ld\n", (long)time(0) - user->idletime);
<span style="color: #000000;background-color: #ddffdd">+                string_add(&value, "%ld", now - user->idletime);
+               if (script_debug) printf("- Idle time is %ld\n", now - user->idletime);
</span>   }
        else if (!strcasecmp(pc->inst->name, "useridle"))
        {
-               struct person u2;
-               struct who w;
-               int ufile,wfile;
-               char *uname;
-
-               uname=eval_arg(pc->argv[1], fargc, fargv);
<span style="color: #000000;background-color: #ddffdd">+                AUTOFREE_BUFFER uname = eval_arg(pc->argv[1], fargc, fargv);
</span> 
                if (script_debug) escprintf("- %s: Getting idletime of user '%s'.\n", pc->inst->name, uname); 
 
-               wfile=who_open(O_RDWR);
-               ufile=userdb_open(O_RDONLY);
-               if (wfile<0 || ufile<0)
<span style="color: #000000;background-color: #ddffdd">+                json_t * wlist = grab_wholist();
+               if (wlist == NULL)
</span>           {
                        /* hideous problems with user info files */
-                       free(what);
-                       free(uname);
                        printf("- %s: Can't open user/who information files\n", pc->inst->name);
                        return;
                }
<span style="color: #aaaaaa">@@ -182,36 +177,25 @@ void scr_time( struct code *pc, int fargc, char **fargv )
</span>           /* set default idle time to zero */
                snprintf(value, MAXTEXTLENGTH - 1, "0");
 
-               while (read(wfile,&w,sizeof(w)))
-               {
-                       /* Skip invalid entries */
-                       if (w.posn < 0)
-                               continue;
-
-                       lseek(ufile,w.posn,0);
-                       read(ufile,&u2,sizeof(u2));
<span style="color: #000000;background-color: #ddffdd">+                size_t wi;
+               json_t *entry;
+               json_array_foreach(wlist, wi, entry) {
+                       const char *name = json_getstring(entry, "name");
+                       time_t idletime = json_getint(entry, "idletime");
</span> 
-                       if (!strcasecmp(u2.name, uname))
<span style="color: #000000;background-color: #ddffdd">+                        if (!strcasecmp(name, uname))
</span>                   {
-                               /* check they are still alive and show info */
-                               if (w.pid>-1 )
-                               {
-                                       snprintf(value, MAXTEXTLENGTH - 1, "%ld", (long)time(0) - u2.idletime);
-                                       if (script_debug) printf("- %s: Idletime is %ld\n", pc->inst->name, (long)time(0) - u2.idletime);
-                               }
<span style="color: #000000;background-color: #ddffdd">+                                snprintf(value, MAXTEXTLENGTH - 1, "%ld", now - idletime);
+                               if (script_debug) printf("- %s: Idletime is %ld\n", pc->inst->name, now - idletime);
</span>                   }
                }
-               free(uname);
-               close(wfile);
-               close(ufile);
<span style="color: #000000;background-color: #ddffdd">+                json_decref(wlist);
</span>   }
        else if (!strcasecmp(pc->inst->name, "whenami"))
        {
-               time_t t;
                struct tm *tt;
 
-               t=time(0);
-               tt=localtime(&t);
<span style="color: #000000;background-color: #ddffdd">+                tt=localtime(&now);
</span>           strftime(value, MAXTEXTLENGTH-1, "%H:%M", tt);
        }
        else if (!strcasecmp(pc->inst->name, "date"))
<span style="color: #aaaaaa">@@ -224,16 +208,16 @@ void scr_time( struct code *pc, int fargc, char **fargv )
</span>           t = localtime(&oldt);
 
                /* print date information into the string in the format "dd/mm/yyyy HH:MM:SS" */
-               snprintf(value, MAXTEXTLENGTH - 1, "%02d/%02d/%04d %02d:%02d:%02d", t->tm_mday, t->tm_mon + 1, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec);
<span style="color: #000000;background-color: #ddffdd">+                string_add(&value, "%02d/%02d/%04d %02d:%02d:%02d", t->tm_mday, t->tm_mon + 1, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec);
</span>   }
        var_str_force_2(what, value);
-       free(what);
 }
 
 void scr_say( struct code *pc, int fargc, char **fargv )
 {
        int i, size, count;
-       char *tmp, *p;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER tmp = NULL;
+       AUTOFREE_BUFFER p = NULL;
</span>   char utf8buff[MAXTEXTLENGTH];
        int conversion_result;
        
<span style="color: #aaaaaa">@@ -257,7 +241,6 @@ void scr_say( struct code *pc, int fargc, char **fargv )
</span>           count+=strlen(p);
                if (count>=size) { size=count+512; tmp=realloc(tmp, size); }
                strcat(tmp, p);
-               free(p);
        }
 
        flood++;
<span style="color: #aaaaaa">@@ -265,7 +248,6 @@ void scr_say( struct code *pc, int fargc, char **fargv )
</span>   {
                printf("FLOOD: This script has flooded the room. Terminating.\n");
                script_terminate = 2;
-               free(tmp);
                return;
        }
 
<span style="color: #aaaaaa">@@ -273,13 +255,11 @@ void scr_say( struct code *pc, int fargc, char **fargv )
</span>   if(conversion_result < 0)
        {
                printf("Error %d occured trying to clean up the script output.\n", conversion_result);
-               free(tmp);
                return;
        }
        if(conversion_result & WINVALIDCHARS)
        {
                printf("Error: Your script produced invalid utf-8 which has not been sent.\n");
-               free(tmp);
                return;
        }               
        if(conversion_result & WOUTPUTTOOSHORT)
<span style="color: #aaaaaa">@@ -305,7 +285,6 @@ void scr_say( struct code *pc, int fargc, char **fargv )
</span>   {
                talk_send_raw(utf8buff, user->room);
        }
-       free(tmp);
 }
 
 void scr_beep( struct code *pc, int fargc, char **fargv )
<span style="color: #aaaaaa">@@ -320,7 +299,7 @@ void scr_showrunaway( struct code *pc, int fargc, char **fargv )
</span> 
 void scr_output( struct code *pc, int fargc, char **fargv )
 {
-       char *what;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
</span>   int i;
 
        if (event_user==NULL)
<span style="color: #aaaaaa">@@ -340,51 +319,36 @@ void scr_output( struct code *pc, int fargc, char **fargv )
</span>           if (script_debug) printf("- OUTPUT: Error, invalid argument\n");
        }
        else script_output = i;
-
-       free(what);
 }
 
 void scr_wholist( struct code *pc, int fargc, char **fargv )
 {
-       struct person u2;
-       struct who w;
-       int ufile,wfile;
-       char *what;
-       char buff[2048];
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
+       AUTOFREE_BUFFER buff = NULL;
</span>   
        if (pc->argc < 1) {
                if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
                return;
        }
-       what=eval_arg(pc->argv[0], fargc, fargv);
<span style="color: #000000;background-color: #ddffdd">+        what = eval_arg(pc->argv[0], fargc, fargv);
</span> 
-       wfile=who_open(O_RDWR);
-       ufile=userdb_open(O_RDONLY);
-       if (wfile<0 || ufile<0) return; /* whoops */
<span style="color: #000000;background-color: #ddffdd">+        json_t * wlist = grab_wholist();
+       if (wlist == NULL) return;
</span> 
-       buff[0] = 0;
<span style="color: #000000;background-color: #ddffdd">+        size_t wi;
+       json_t *entry;
+       json_array_foreach(wlist, wi, entry) {
+               json_t * perms = json_object_get(entry, "perms");
+               const char *name = json_getstring(entry, "name");
+               const char *chatmode = NULL;
+               if (perms!=NULL) chatmode=json_getstring(perms, "chatmode");
</span> 
-       while (read(wfile,&w,sizeof(w)))
-       {
-               /* Skip invalid entries */
-               if (w.posn < 0)
-                       continue;
-
-               lseek(ufile,w.posn,0);
-               read(ufile,&u2,sizeof(u2));
-
-               /* check they are still alive and show info */
-               if (w.pid>-1 )
<span style="color: #000000;background-color: #ddffdd">+                if (chatmode != NULL && strchr(chatmode, 'c')!=NULL)
</span>           {
-                       if (cm_flags(u2.chatmode,CM_ONCHAT,CM_MODE_ANY))
-                       {
-                               strcat(buff, u2.name);
-                               strcat(buff, " ");
-                       }
<span style="color: #000000;background-color: #ddffdd">+                        string_add(&buff, "%s ", name);
</span>           }
        }
-       close(wfile);
-       close(ufile);
<span style="color: #000000;background-color: #ddffdd">+        json_decref(wlist);
</span>   
        {
                char *p;
<span style="color: #aaaaaa">@@ -392,12 +356,11 @@ void scr_wholist( struct code *pc, int fargc, char **fargv )
</span>   }
 
        var_str_force_2(what, buff);
-       free(what);
 }
 
 void scr_roomnum( struct code *pc, int fargc, char **fargv )
 {
-       char *what;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
</span>   char rn[10];
 
        /* set initial room to -1 for unknown */
<span style="color: #aaaaaa">@@ -439,53 +402,34 @@ void scr_roomnum( struct code *pc, int fargc, char **fargv )
</span>   }
        else if (!strcasecmp(pc->inst->name, "userroom"))
        {
-               struct person u2;
-               struct who w;
-               int ufile,wfile;
-               char *uname;
<span style="color: #000000;background-color: #ddffdd">+                AUTOFREE_BUFFER uname = NULL;
</span>           int rnum = -1;
 
                uname=eval_arg(pc->argv[1], fargc, fargv);
 
                if (script_debug) escprintf("- %s: Getting room of user '%s'.\n", pc->inst->name, uname); 
 
-               wfile=who_open(O_RDWR);
-               ufile=userdb_open(O_RDONLY);
-               if (wfile<0 || ufile<0)
-               {
-                       /* hideous problems with user info files */
-                       free(what);
-                       free(uname);
-                       printf("- %s: Can't open user/who information files\n", pc->inst->name);
-                       return;
<span style="color: #000000;background-color: #ddffdd">+                json_t * wlist = grab_wholist();
+               if (wlist == NULL) return;
+
+               size_t wi;
+               json_t *entry;
+               json_array_foreach(wlist, wi, entry) {
+                       json_t * perms = json_object_get(entry, "perms");
+                       const char *name = json_getstring(entry, "name");
+                       const char *chatmode = NULL;
+                       if (perms!=NULL) chatmode=json_getstring(perms, "chatmode");
+                       int room = json_getint(entry, "room");
+
+                       /* wrong person */
+                       if (strcasecmp(name, uname)!=0) continue;
+                       /* wasnt on chat */
+                       if (chatmode != NULL && strchr(chatmode, 'c')==NULL) continue;
+                       rnum = room;
</span>           }
<span style="color: #000000;background-color: #ddffdd">+                json_decref(wlist);
</span> 
-               while (read(wfile,&w,sizeof(w)))
-               {
-                       /* Skip invalid entries */
-                       if (w.posn < 0)
-                               continue;
-
-                       lseek(ufile,w.posn,0);
-                       read(ufile,&u2,sizeof(u2));
-
-                       if (!strcasecmp(u2.name, uname))
-                       {
-                               /* check they are still alive and show info */
-                               if (w.pid>-1 )
-                               {
-                                       /* do validity checks */
-                                       if (cm_flags(u2.chatmode,CM_ONCHAT,CM_MODE_ANY))
-                                       {
-                                               rnum = u2.room;
-                                               snprintf(rn, 9, "%d", rnum);
-                                       }
-                               }
-                       }
-               }
-               free(uname);
-               close(wfile);
-               close(ufile);
<span style="color: #000000;background-color: #ddffdd">+                snprintf(rn, 9, "%d", rnum);
</span>   }
 
        var_str_force_2(what, rn);
<span style="color: #aaaaaa">@@ -494,15 +438,15 @@ void scr_roomnum( struct code *pc, int fargc, char **fargv )
</span> 
 void scr_talkpriv( struct code *pc, int fargc, char **fargv )
 {
-       char *what;
-       char *buff;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
+       AUTOFREE_BUFFER buff = NULL;
</span>   unsigned long mask = 0xffffffff;
 
        if (pc->argc < 1) {
                if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
                return;
        }
-       what=eval_arg(pc->argv[0], fargc, fargv);
<span style="color: #000000;background-color: #ddffdd">+        what = eval_arg(pc->argv[0], fargc, fargv);
</span> 
        /* Empty string "" means no privs. For every extra priv/mode available, the following character is added:
         *  T     - Timestamps enabled
<span style="color: #aaaaaa">@@ -514,14 +458,12 @@ void scr_talkpriv( struct code *pc, int fargc, char **fargv )
</span> 
        mask &= ~(CM_ONCHAT);
        mask &= ~(CM_STICKY);
-       if (s_timestamp(user->special)) buff = strdup("T"); else buff = strdup("");
<span style="color: #000000;background-color: #ddffdd">+        if (s_timestamp(user->special)) string_add(&buff, "T");
</span>   if (!u_beep(user->status)) string_add(&buff, "B");
        if (u_god(user->status)) string_add(&buff, "S");
-       string_add(&buff, display_cmflags(user->chatmode & mask));
<span style="color: #000000;background-color: #ddffdd">+        string_add(&buff, "%s", display_cmflags(user->chatmode & mask));
</span> 
        var_str_force_2(what, buff);
-       free(what);
-       free(buff);
 }
 
 void scr_quit( struct code *pc, int fargc, char **fargv )
<span style="color: #aaaaaa">@@ -667,7 +609,8 @@ int isanumul(const char *a, unsigned long *result, int onlydecimal)
</span> 
 void scr_compare( struct code *pc, int fargc, char **fargv ) 
 {
-       char *a, *b;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER a = NULL;
+       AUTOFREE_BUFFER b = NULL;
</span>   int aa=0, bb=0;
        int numeric=0;
 
<span style="color: #aaaaaa">@@ -739,14 +682,13 @@ void scr_compare( struct code *pc, int fargc, char **fargv )
</span>                   if (strcasecmp(a,b) >=0) compare_match++;
                }
        }
-       free(a);
-       free(b);
 }
 
 void scr_math( struct code *pc, int fargc, char **fargv )
 {
        int a, b;
-       char *aa, *bb;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER aa = NULL;
+       AUTOFREE_BUFFER bb = NULL;
</span>   var_op_t var;
        int result=0;
 
<span style="color: #aaaaaa">@@ -760,7 +702,6 @@ void scr_math( struct code *pc, int fargc, char **fargv )
</span>   if (!eval_var(aa, &var))
        {
                scr_devel_msg(pc, "Invalid variable name '%s'", aa);
-               free(aa);
        }
 
        if (!VAR_FOUND(&var)) {
<span style="color: #aaaaaa">@@ -775,15 +716,11 @@ void scr_math( struct code *pc, int fargc, char **fargv )
</span>   }else
        { /* looks like their not numbers, cant math strings */
                if (script_debug) escprintf("- math: either $%s (%s) or '%s' were not numbers\n", aa, var_str_val(&var), bb);
-               free(aa);
-               free(bb);
                VAR_KEY_FREE(&var);
                return;
        }
-       free(bb);
 
        if (script_debug) escprintf("- math operation on $%s (%d) and %d\n", aa, a, b);
-       free(aa);
        
        if (!strcasecmp(pc->inst->name, "add"))
                result = a+b;
<span style="color: #aaaaaa">@@ -819,7 +756,8 @@ void scr_math( struct code *pc, int fargc, char **fargv )
</span> void scr_math2( struct code *pc, int fargc, char **fargv )
 {
        int a;
-       char *aa, *bb;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER aa = NULL;
+       AUTOFREE_BUFFER bb = NULL;
</span>   var_op_t var;
        int result=0;
 
<span style="color: #aaaaaa">@@ -833,7 +771,6 @@ void scr_math2( struct code *pc, int fargc, char **fargv )
</span>   if (!eval_var(aa, &var))
        {
                scr_devel_msg(pc, "Invalid variable name '%s'", aa);
-               free(aa);
        }
 
        if (!VAR_FOUND(&var)) {
<span style="color: #aaaaaa">@@ -849,15 +786,11 @@ void scr_math2( struct code *pc, int fargc, char **fargv )
</span>   {
                /* looks like arg2 is not a number, cant math string */
                if (script_debug) escprintf("- math: '%s' is not a number\n", bb);
-               free(aa);
-               free(bb);
                VAR_KEY_FREE(&var);
                return;
        }
-       free(bb);
 
        if (script_debug) printf("- math operation on %d\n", a);
-       free(aa);
        
        if (!strcasecmp(pc->inst->name, "abs"))
        {
<span style="color: #aaaaaa">@@ -870,7 +803,7 @@ void scr_math2( struct code *pc, int fargc, char **fargv )
</span> 
 void scr_sleep( struct code *pc, int fargc, char **fargv )
 {
-       char    *aa;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER aa = NULL;
</span>   int     a;
        struct timeval delay;
 
<span style="color: #aaaaaa">@@ -892,13 +825,14 @@ void scr_sleep( struct code *pc, int fargc, char **fargv )
</span>   }
        else
                if (script_debug) escprintf("- Sleep input not number '%s'\n", aa);
-       free(aa);
 }
 
 void scr_rand( struct code *pc, int fargc, char **fargv )
 {
        char    buff[20];
-       char    *aa, *bb, *what;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER aa = NULL;
+       AUTOFREE_BUFFER bb = NULL;
+       AUTOFREE_BUFFER what = NULL;
</span>   int     a, b;
 
        if (pc->argc<3) {
<span style="color: #aaaaaa">@@ -915,20 +849,14 @@ void scr_rand( struct code *pc, int fargc, char **fargv )
</span>           /* looks like they're not numbers, cant math strings */
                var_str_force_2(what, "-1");
                if (script_debug) escprintf("- rand: either '%s' or '%s' were not numbers\n", aa, bb);
-               free(aa);
-               free(bb);
-               free(what);
                return;
        }
-       free(aa);
-       free(bb);
 
        /* bad min/max */
        if (b < a)
        {
                var_str_force_2(what, "-1");
                if (script_debug) printf("- rand operation. second argument (%d) smaller than first (%d)\n", b, a);
-               free(what);
                return;
        }
        /* not positive */
<span style="color: #aaaaaa">@@ -936,7 +864,6 @@ void scr_rand( struct code *pc, int fargc, char **fargv )
</span>   {
                var_str_force_2(what, "-1");
                if (script_debug) printf("- rand operation. arguments (%d, %d) must be positive", a, b);
-               free(what);
                return;
        }
 
<span style="color: #aaaaaa">@@ -944,12 +871,14 @@ void scr_rand( struct code *pc, int fargc, char **fargv )
</span> 
        snprintf(buff, 19, "%d", get_rand(a,b));
        var_str_force_2(what, buff);
-       free(what);
 }
 
 void scr_makestr( struct code *pc, int fargc, char **fargv )
 {
-       char *aa, *bb, *cc, *out;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER aa=NULL;
+       AUTOFREE_BUFFER bb=NULL;
+       AUTOFREE_BUFFER cc=NULL;
+       AUTOFREE_BUFFER out=NULL;
</span>   var_op_t var;
        int i, j;
 
<span style="color: #aaaaaa">@@ -966,44 +895,34 @@ void scr_makestr( struct code *pc, int fargc, char **fargv )
</span> 
        VAR_STR_PREPARE_2(&var, local_vars, &var_list, aa, NULL);
 
-       free(aa);
-
        if (!isanum(bb, &i, 0)) {
                if (script_debug) escprintf("- %s: cant make string because arg2 '%s' is not a number\n", pc->inst->name, bb);
-               free(bb);
-               free(cc);
                return;
        }
        if (i < 1) {
                if (script_debug) printf("- %s: cant make string because arg2 '%d' is less than 1\n", pc->inst->name, i);
-               free(bb);
-               free(cc);
                return;
        }
        if (!strcmp(cc, "")) {
                if (script_debug) printf("- %s: cant make string because arg3 is empty\n", pc->inst->name);
-               free(bb);
-               free(cc);
                return;
        }
 
-       out = strdup("");
        for (j = 0; j < i; j++) {
-               string_add(&out, cc);
<span style="color: #000000;background-color: #ddffdd">+                string_add(&out, "%s", cc);
</span>   }
 
        VAR_STR_UPDATE(&var, out);
 
        if (script_debug) escprintf("- %s: '%d' x '%s' --> '%s'\n", pc->inst->name, i, cc, var_str_val(&var));
-
-       free(bb);
-       free(cc);
-       free(out);
 }
 
 void scr_split( struct code *pc, int fargc, char **fargv )
 {
-       char *aa, *bb, *cc, *text;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER aa=NULL;
+       AUTOFREE_BUFFER bb=NULL;
+       AUTOFREE_BUFFER cc=NULL;
+       AUTOFREE_BUFFER text=NULL;
</span>   var_op_t var1, var2;
 
        if (pc->argc<3) {
<span style="color: #aaaaaa">@@ -1020,13 +939,9 @@ void scr_split( struct code *pc, int fargc, char **fargv )
</span>   VAR_STR_PREPARE_2(&var1, local_vars, &var_list, bb, NULL);
        VAR_STR_PREPARE_2(&var2, local_vars, &var_list, cc, NULL);
 
-       free(bb);
-       free(cc);
-
        /* source string was empty */
        if (!strcmp(aa, "")) {
                if (script_debug) printf("- Source string to %s empty, returning blank head and tail.\n", pc->inst->name);
-               free(aa);
                VAR_STR_UPDATE(&var1, "");
                VAR_STR_UPDATE(&var2, "");
                return;
<span style="color: #aaaaaa">@@ -1034,11 +949,11 @@ void scr_split( struct code *pc, int fargc, char **fargv )
</span> 
        /* skip spaces at start of string */
        text = strdup(aa);
-       cc = text;
-       while ((cc != NULL) && isspace(*cc)) cc++;
<span style="color: #000000;background-color: #ddffdd">+        char *ccp = text;
+       while ((ccp != NULL) && isspace(*ccp)) ccp++;
</span> 
        /* if all spaces at start of string, then return the spaces as head, and tail as nothing */
-       if (cc == NULL)
<span style="color: #000000;background-color: #ddffdd">+        if (ccp == NULL)
</span>   {
                VAR_STR_UPDATE(&var1, aa);
                VAR_STR_UPDATE(&var2, "");
<span style="color: #aaaaaa">@@ -1046,32 +961,31 @@ void scr_split( struct code *pc, int fargc, char **fargv )
</span>   /* if there were spaces at the front of the string, ignore them, and split about next space */
        else
        {
-               if ((bb = strchr(cc, ' ')) == NULL)
<span style="color: #000000;background-color: #ddffdd">+                char *bbp;
+               if ((bbp = strchr(ccp, ' ')) == NULL)
</span>           {
                        VAR_STR_UPDATE(&var1, cc);
                        VAR_STR_UPDATE(&var2, "");
                }
                else
                {
-                       char *dd = bb;
-                       dd++;
-                       VAR_STR_UPDATE(&var2, dd);
<span style="color: #000000;background-color: #ddffdd">+                        bbp = bb;
+                       bbp++;
+                       VAR_STR_UPDATE(&var2, bbp);
</span>                   *bb=0;
                        VAR_STR_UPDATE(&var1, cc);
                }
        }
 
        if (script_debug) escprintf("- %s: '%s' --> <'%s','%s'>\n", pc->inst->name, aa, var_str_val(&var1), var_str_val(&var2));
-
-       free(aa);
-       free(text);
 }
 
 void scr_strcat( struct code *pc, int fargc, char **fargv )
 {
        var_op_t var;
-       char *a, *b, *new;
-       int i;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER a=NULL;
+       AUTOFREE_BUFFER b=NULL;
+       AUTOFREE_BUFFER nbuff=NULL;
</span> 
        if (pc->argc<2) {
                if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
<span style="color: #aaaaaa">@@ -1086,28 +1000,20 @@ void scr_strcat( struct code *pc, int fargc, char **fargv )
</span> 
        if (VAR_FOUND(&var))
        {
-               i=strlen(var_str_val(&var)) + strlen(b);
-               new=(char *)malloc(i+1);
-               *new=0;
-               strcpy(new, var_str_val(&var));
-               strcat(new, b);
-               VAR_STR_UPDATE(&var, new);
-               free(new);
-               free(b);
<span style="color: #000000;background-color: #ddffdd">+                string_add(&nbuff, "%s", var_str_val(&var));
+               string_add(&nbuff, "%s", b);
+               VAR_STR_UPDATE(&var, nbuff);
</span>   } else
        {
                VAR_STR_CREATE(&var, b);
        }
-
-       free(a);
 }
 
 void scr_set(struct code *pc, int fargc, char **fargv)
 {
        var_op_t var;
-       char *what;
-       char *a, *text;
-       int i, len, size;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
+       AUTOFREE_BUFFER text = NULL;
</span> 
        if (pc->argc < 2) {
                if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
<span style="color: #aaaaaa">@@ -1122,24 +1028,10 @@ void scr_set(struct code *pc, int fargc, char **fargv)
</span>           return;
        }
 
-       size=0;
-       for (i=1; i<pc->argc; i++) {
-               size+=strlen(pc->argv[i])+1;
-       }
-
-       size=size*2;
-       text=(char *)malloc(size);
-
-       *text=0;
-       for (i=1; i<pc->argc; i++) {
-               a=eval_arg(pc->argv[i], fargc, fargv);
-               len=strlen(a);
-               if (strlen(text)+len+5 >= size) {
-                       size+=len+80;
-                       text=realloc(text, size);
-               }
-               strcat(text, a);
-               if (i>0 && i<pc->argc-1) strcat(text, " ");
<span style="color: #000000;background-color: #ddffdd">+        for (int i=1; i<pc->argc; i++) {
+               char * a = eval_arg(pc->argv[i], fargc, fargv);
+               string_add(&text, "%s", a);
+               if (i>0 && i<pc->argc-1) string_add(&text, " ");
</span>           free(a);
        }
 
<span style="color: #aaaaaa">@@ -1151,16 +1043,14 @@ void scr_set(struct code *pc, int fargc, char **fargv)
</span>           if (script_debug) escprintf("- set: creating var $%s setting to '%s'\n", what, text);
        }
 
-       free(text);
        VAR_KEY_FREE(&var);
-       free(what);
 }
 
 void scr_getvar(struct code *pc, int fargc, char **fargv)
 {
        var_op_t var, var2;
-       char *what;
-       char *value=NULL;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
+       AUTOFREE_BUFFER value=NULL;
</span> 
        if (pc->argc < 2) {
                if (script_debug) printf("Error in %s at %s too few arguments.\n", pc->inst->name, pc->debug);
<span style="color: #aaaaaa">@@ -1171,7 +1061,6 @@ void scr_getvar(struct code *pc, int fargc, char **fargv)
</span>   if (!eval_var(what, &var))
        {
                scr_devel_msg(pc, "'%s' is not a valid variable name", what);
-               free(what);
                return;
        }
 
<span style="color: #aaaaaa">@@ -1204,15 +1093,13 @@ void scr_getvar(struct code *pc, int fargc, char **fargv)
</span>           VAR_STR_CREATE(&var, value);
                if (script_debug) escprintf("- set: creating var $%s setting to '%s'\n", what, value);
        }
-       if (value!=NULL) free(value);
        VAR_KEY_FREE(&var);
-       free(what);
 }
 
 void scr_unset(struct code *pc, int fargc, char **fargv)
 {
        var_op_t var;
-       char *what;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
</span> 
        if (pc->argc < 1)
        {
<span style="color: #aaaaaa">@@ -1231,16 +1118,14 @@ void scr_unset(struct code *pc, int fargc, char **fargv)
</span>           else if (script_debug) escprintf("- unset: %s was not a variable.\n", what);
                VAR_KEY_FREE(&var);
        }
-
-       free(what);
 }
 
 void scr_clearvars(struct code *pc, int fargc, char **fargv)
 {
        var_op_t iter;
        var_op_t op;
-       char *what = NULL;
-       char *key;
<span style="color: #000000;background-color: #ddffdd">+        AUTOFREE_BUFFER what = NULL;
+       AUTOFREE_BUFFER key = NULL;
</span> 
        if (pc->argc > 1) {
                if (script_debug) printf("Error in %s at %s too many arguments.\n", pc->inst->name, pc->debug);
<span style="color: #aaaaaa">@@ -1263,7 +1148,6 @@ void scr_clearvars(struct code *pc, int fargc, char **fargv)
</span>           {
                        VAR_LIST_NEXT(&iter);
                }
-               free(key);
        }
 
        /* 2nd pass garbage-collects hashes (does nothing with lists)
<span style="color: #aaaaaa">@@ -1271,8 +1155,6 @@ void scr_clearvars(struct code *pc, int fargc, char **fargv)
</span>    */
        VAR_LIST_ITERATE(&iter, &var_list);
        while (VAR_FOUND(&iter)) VAR_LIST_NEXT(&iter);
-
-       if (what != NULL) free(what);
 }
 
 void scr_local(struct code *pc, int fargc, char **fargv )
</code></pre>

<br>
</li>
<li id='diff-2'>
<a href='https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888#diff-2'>
<strong>
src/client/who.c
</strong>
</a>
<hr>
<pre class="highlight"><code><span style="color: #000000;background-color: #ffdddd">--- a/src/client/who.c
</span><span style="color: #000000;background-color: #ddffdd">+++ b/src/client/who.c
</span><span style="color: #aaaaaa">@@ -65,11 +65,6 @@ char *itime(unsigned long t)
</span>   return(out);
 }
 
-#define json_array_foreach(array, index, value) \
-       for(index = 0; \
-       index < json_array_size(array) && (value = json_array_get(array, index)); \
-       index++)
-
 static json_t * whoinfo = NULL;
 static time_t   whowhen = 0;
 static int      whotype = -1;
<span style="color: #aaaaaa">@@ -241,3 +236,19 @@ char *part_who_talk(const char *text, int status)
</span>   return NULL;
 }
 
<span style="color: #000000;background-color: #ddffdd">+/* grab a handle to the current wholist
+ * you need to json_decref it when finished
+ */
+json_t * grab_wholist(void)
+{
+       time_t now = time(NULL);
+       /* we dont have a recent cache of who list,
+        * ask for an update, then do the best you can */
+       if (whoinfo == NULL || whowhen < (now - WHOCACHE)) {
+               ipc_message_t * msg = ipcmsg_create(IPC_WHOLIST, userposn);
+               ipcmsg_transmit(msg);
+       }
+
+       if (whoinfo != NULL) json_incref(whoinfo);
+       return whoinfo;
+}
</span></code></pre>

<br>
</li>
<li id='diff-3'>
<a href='https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888#diff-3'>
<strong>
src/client/who.h
</strong>
</a>
<hr>
<pre class="highlight"><code><span style="color: #000000;background-color: #ffdddd">--- a/src/client/who.h
</span><span style="color: #000000;background-color: #ddffdd">+++ b/src/client/who.h
</span><span style="color: #aaaaaa">@@ -11,5 +11,13 @@ void update_wholist(ipc_message_t *msg);
</span> void what_list(void);
 char *part_who_talk(const char *text, int status);
 char *part_who(const char *text, int status);
<span style="color: #000000;background-color: #ddffdd">+json_t * grab_wholist(void);
+
+#ifndef json_array_foreach
+#define json_array_foreach(array, index, value) \
+       for(index = 0; \
+       index < json_array_size(array) && (value = json_array_get(array, index)); \
+       index++)
+#endif
</span> 
 #endif /* CLIENT_WHO_H */
</code></pre>

<br>
</li>
<li id='diff-4'>
<a href='https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888#diff-4'>
<strong>
src/gags.c
</strong>
</a>
<hr>
<pre class="highlight"><code><span style="color: #000000;background-color: #ffdddd">--- a/src/gags.c
</span><span style="color: #000000;background-color: #ddffdd">+++ b/src/gags.c
</span><span style="color: #aaaaaa">@@ -593,7 +593,7 @@ static char *apply_morse(char *in)
</span>   for (i=0; i<strlen(in); i++)
        {
                if (i>0) string_add(&out, " ");
-               string_add(&out, lookup_morse(in[i]));
<span style="color: #000000;background-color: #ddffdd">+                string_add(&out, "%s", lookup_morse(in[i]));
</span>   }
        string_add(&out, " .-.-.");
 
</code></pre>

<br>
</li>
<li id='diff-5'>
<a href='https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888#diff-5'>
<strong>
src/str_util.c
</strong>
</a>
<hr>
<pre class="highlight"><code><span style="color: #000000;background-color: #ffdddd">--- a/src/str_util.c
</span><span style="color: #000000;background-color: #ddffdd">+++ b/src/str_util.c
</span><span style="color: #aaaaaa">@@ -1,9 +1,12 @@
</span> #include <stdlib.h>
-#include <stdio.h>
 #include <fcntl.h>
 #include <ctype.h>
 #include <string.h>
 #include <stdarg.h>
<span style="color: #000000;background-color: #ddffdd">+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
</span> #include "bb.h"
 #include "str_util.h"
 
<span style="color: #aaaaaa">@@ -66,19 +69,25 @@ int get_rand(int min, int max)
</span>   return ((int)fValue);
 }
 
-void string_add(char **str, const char *add)
<span style="color: #000000;background-color: #ddffdd">+void string_add(char **str, const char *fmt, ...)
</span> {
-       if (add != NULL)
<span style="color: #000000;background-color: #ddffdd">+        va_list va;
+       char *text = NULL;
+       if (fmt == NULL) return;
+
+       va_start(va, fmt);
+       vasprintf(&text, fmt, va);
+       va_end(va);
+               
+       if (*str == NULL)
</span>   {
-               if (*str == NULL)
-               {
-                       *str = strdup(add);
-               }
-               else
-               {
-                       *str = realloc(*str, sizeof(char) * (strlen(*str) + strlen(add) + 1));
-                       strcat(*str, add);
-               }
<span style="color: #000000;background-color: #ddffdd">+                /* was an empty string, give it this one */
+               *str = text;
+       } else {
+               /* was not empty, append */
+               *str = realloc(*str, sizeof(char) * (strlen(*str) + strlen(text) + 1));
+               strcat(*str, text);
+               free(text);
</span>   }
 }
 
</code></pre>

<br>
</li>
<li id='diff-6'>
<a href='https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888#diff-6'>
<strong>
src/str_util.h
</strong>
</a>
<hr>
<pre class="highlight"><code><span style="color: #000000;background-color: #ffdddd">--- a/src/str_util.h
</span><span style="color: #000000;background-color: #ddffdd">+++ b/src/str_util.h
</span><span style="color: #aaaaaa">@@ -5,7 +5,7 @@
</span> int stringcmp(const char *a, const char *b, int n);
 void strip_str(char *string);
 int get_rand(int min, int max);
-void string_add(char **str, const char *add);
<span style="color: #000000;background-color: #ddffdd">+void string_add(char **str, const char *fmt, ...)  __attribute__((format(gnu_printf,2,3)));
</span> int allspace(char *in);
 void strlower(char *szString);
 void escprintf(const char *szFormat, ...);
</code></pre>

<br>
</li>

</div>
<div class='footer' style='margin-top: 10px;'>
<p>

<br>
<a href="https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888">View it on GitLab</a>
<script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","action":{"@type":"ViewAction","name":"View Commit","url":"https://projects.sucs.org/arthur/mw/commit/b5193749c154cc8177dfe8040e35ac45d6a9b888"}}</script>
</p>
</div>
</body>
</html>