$ git clone http://socialnetwork.ion.nu/socialnetwork-web.git
commit 9886013c41852c1d823905ef671397b455090ebc
Author: Alicia <...>
Date:   Fri Jul 21 06:15:49 2017 +0200

    Initial user page implementation.

diff --git a/Makefile b/Makefile
index 1371525..6677b19 100644
--- a/Makefile
+++ b/Makefile
@@ -4,10 +4,11 @@ EMSCRIPTVERSION=1.37.12
 GMPVERSION=6.1.2
 NETTLEVERSION=3.3
 GNUTLSVERSION=3.5.12
-SOCIALNETWORKREVISION=c76b97a476bf6899bd775e298f9ed5fad650304e
+SOCIALNETWORKREVISION=f5e92db17a617d4777df4b7a1107d67114d3b6f9
 REVISION=$(shell git log | sed -n -e 's/^commit //p;q')
 JSLIBS=$(shell PKG_CONFIG_PATH=toolchain/usr/lib/pkgconfig pkg-config --libs gnutls nettle hogweed) -lgmp
 JSCFLAGS=$(shell PKG_CONFIG_PATH=toolchain/usr/lib/pkgconfig pkg-config --cflags gnutls)
+JSSYMBOLS='_social_init','_peer_handlesocket','_peer_new_unique','_websockproxy_read','_websockproxy_setwrite','_getcirclecount','_newcircle','_circle_getcount','_circle_getname','_circle_setname','_social_addfriend','_circle_getid','_social_finduser','_self_getid','_user_getupdatecount','_user_getupdatetype','_user_getupdatetimestamp'
 
 all: webpeer libsocial.js
 
@@ -21,7 +22,7 @@ toolchain/usr/lib/libsocial.so: toolchain/usr/bin/emcc
  ./buildlibs.sh '$(GMPVERSION)' '$(NETTLEVERSION)' '$(GNUTLSVERSION)'
 
 libsocial.js: jsglue.c toolchain/usr/lib/libsocial.so
- toolchain/usr/bin/emcc -O3 -s EXPORTED_FUNCTIONS="['_social_init','_peer_handlesocket','_peer_new_unique','_websockproxy_read','_websockproxy_setwrite','_getcirclecount','_newcircle','_circle_getcount','_circle_getname','_circle_setname','_social_addfriend','_circle_getid']" -s RESERVED_FUNCTION_POINTERS=1 -s NO_EXIT_RUNTIME=1 -s NODEJS_CATCH_EXIT=0 -s EXPORTED_RUNTIME_METHODS="['ccall','cwrap','readFile','writeFile']" -s INVOKE_RUN=0 $(JSCFLAGS) $^ $(JSLIBS) -o $@
+ toolchain/usr/bin/emcc -O3 -s EXPORTED_FUNCTIONS="[$(JSSYMBOLS)]" -s RESERVED_FUNCTION_POINTERS=1 -s NO_EXIT_RUNTIME=1 -s NODEJS_CATCH_EXIT=0 -s EXPORTED_RUNTIME_METHODS="['ccall','cwrap','readFile','writeFile']" -s INVOKE_RUN=0 $(JSCFLAGS) $^ $(JSLIBS) -o $@
  ./squeezeandcomment.sh '$@' 'This code was built from gmp $(GMPVERSION), nettle $(NETTLEVERSION), gnutls $(GNUTLSVERSION) and socialnetwork git revision $(SOCIALNETWORKREVISION) with tweaks from socialnetwork-web git revision $(REVISION) using emscripten (fastcomp) $(EMSCRIPTVERSION)'
 
 # Download all external sources we'll need
diff --git a/jsglue.c b/jsglue.c
index 858f6af..bf0b858 100644
--- a/jsglue.c
+++ b/jsglue.c
@@ -23,6 +23,7 @@
 #include <libsocial/udpstream_private.h>
 #include <libsocial/udpstream.h>
 #include <libsocial/social.h>
+#include <libsocial/update.h>
 #include "jsglue.h"
 extern struct udpstream* stream_new(int sock, struct sockaddr_storage* addr, socklen_t addrlen);
 
@@ -95,3 +96,27 @@ void circle_setname(unsigned int i, const char* name)
   free(social_self->circles[i].name);
   social_self->circles[i].name=strdup(name);
 }
+unsigned int user_getupdatecount(struct user* user){return user->updatecount;}
+const char* user_getupdatetype(struct user* user, unsigned int index)
+{
+  switch(user->updates[index].type)
+  {
+  case UPDATE_FIELD: return "Field";
+  case UPDATE_POST: return "Post";
+  case UPDATE_MEDIA: return "Media";
+  case UPDATE_FRIENDS: return "Friends";
+  case UPDATE_CIRCLE: return "Circle";
+  }
+  return "Unknown";
+}
+uint64_t user_getupdatetimestamp(struct user* user, unsigned int index)
+{
+  return user->updates[index].timestamp;
+}
+const char* self_getid(void)
+{
+  unsigned char* bin=social_self->id;
+  static char id[ID_SIZE*2+1];
+  sprintf(id, PEERFMT, PEERARG(social_self->id));
+  return id;
+}
diff --git a/libsocialjs.js b/libsocialjs.js
index 77021c5..2f65c8c 100644
--- a/libsocialjs.js
+++ b/libsocialjs.js
@@ -25,10 +25,18 @@ function websockwrite(addr, addrlen, buf, size)
 
 var websockproxy_read;
 var peer_new_unique;
+var getcirclecount;
+var newcircle;
+var circle_getcount;
 var circle_getname;
 var circle_setname;
 var circle_getid;
 var social_addfriend;
+var social_finduser;
+var user_getupdatecount;
+var user_getupdatetype;
+var user_getupdatetimestamp;
+var self_getid;
 
 var websockproxy_to=false;
 var firstpacket=true;
@@ -71,6 +79,11 @@ function init(privkey)
   circle_setname=Module.cwrap('circle_setname', null, ['number', 'string']);
   circle_getid=Module.cwrap('circle_getid', 'string', ['number','number']);
   social_addfriend=Module.cwrap('social_addfriend', null, ['array', 'number']);
+  social_finduser=Module.cwrap('social_finduser', 'number', ['array']);
+  user_getupdatecount=Module.cwrap('user_getupdatecount', 'number', ['number']);
+  user_getupdatetype=Module.cwrap('user_getupdatetype', 'string', ['number','number']);
+  user_getupdatetimestamp=Module.cwrap('user_getupdatetimestamp', 'number', ['number','number']);
+  self_getid=Module.cwrap('self_getid', 'string', []);
 
   _websockproxy_setwrite(Runtime.addFunction(websockwrite));
   FS.writeFile('privkey.pem', privkey, {});
@@ -112,3 +125,22 @@ function hextobin(hex)
   }
   return new Uint8Array(bin);
 }
+function getuser(id)
+{
+  var userptr=social_finduser(hextobin(id));
+  if(!userptr){return false;}
+  var user=new Object();
+  user.ptr=userptr;
+  user.id=id;
+// TODO: Gather more user data? No need to store updates themselves in user objects though
+  user.updatecount=user_getupdatecount(userptr);
+  return user;
+}
+function user_getupdate(user, index)
+{
+  var update=new Object();
+  update.type=user_getupdatetype(user.ptr, index);
+  update.timestamp=user_getupdatetimestamp(user.ptr, index);
+// TODO: Get type-specific data
+  return update;
+}
diff --git a/websocial.html b/websocial.html
index fc59b39..26a9885 100644
--- a/websocial.html
+++ b/websocial.html
@@ -55,7 +55,7 @@
   </div>
   <!-- Main interface -->
   <div class="menu">
-    <a href="#" onclick="return false;">Feed</a><a href="#" onclick="page_friends();return false;">Friends</a><a href="#" onclick="return false;">Self</a>
+    <a href="#" onclick="return false;">Feed</a><a href="#" onclick="page_friends();return false;">Friends</a><a href="#" onclick="page_user(false);return false;">Self</a>
   </div>
   <div id="display"></div>
 </body>
diff --git a/websocial.js b/websocial.js
index 9c7a80b..78e6890 100644
--- a/websocial.js
+++ b/websocial.js
@@ -139,6 +139,28 @@ function page_friends()
   }
 }
 
+function page_user(id)
+{
+  if(!id){id=self_getid();} // No ID = show our own page
+  var display=document.getElementById('display');
+  dom_clear(display);
+  // TODO: Get and present fields
+  var user=getuser(id);
+  display.appendChild(document.createTextNode(id+':'));
+  display.appendChild(document.createElement('br'));
+  display.appendChild(document.createTextNode(user.updatecount+' updates'));
+  for(var i=1; i<=user.updatecount && i<=20; ++i)
+  {
+    var update=user_getupdate(user, user.updatecount-i);
+    var box=document.createElement('div');
+    box.appendChild(document.createTextNode('Posted at: '+update.timestamp));
+    box.appendChild(document.createElement('br'));
+    box.appendChild(document.createTextNode('Update type: '+update.type));
+    display.appendChild(box);
+  }
+// TODO: Option to load more updates
+}
+
 var configcircle_index;
 var configcircle_option=false;
 function circle_openconfig(index)