diff --git a/RunServerTest b/RunServerTest
new file mode 100755
index 0000000000000000000000000000000000000000..d0c2fa35275381f5d0f3d4bfde9be930e3dd0835
--- /dev/null
+++ b/RunServerTest
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+LD_LIBRARY_PATH=. ./dispsrv --itemsfile items.cfg -p 11020
diff --git a/src/cokebank b/src/cokebank
new file mode 120000
index 0000000000000000000000000000000000000000..eff8399dc12c52701fb07f83b5793cf528c1aa13
--- /dev/null
+++ b/src/cokebank
@@ -0,0 +1 @@
+cokebank_basic
\ No newline at end of file
diff --git a/src/cokebank_basic/Makefile b/src/cokebank_basic/Makefile
index 8e6ea6041ff26c11f9f29d1fc8206d7285d7db63..6aa55df8e8dd176258569563bb0d42ee6c269332 100644
--- a/src/cokebank_basic/Makefile
+++ b/src/cokebank_basic/Makefile
@@ -1,6 +1,6 @@
 
 BIN := ../../cokebank.so
-OBJ := main.o
+OBJ := main.o bank.o
 
 CPPFLAGS := 
 CFLAGS := -Wall -Werror -g -fPIC
diff --git a/src/cokebank_basic/bank.c b/src/cokebank_basic/bank.c
index c9aa6b36dc7259a1883f39ff5d5ab6484f7a44fd..cc09fa5b7f3408261023fe3b3c8b0801e62c681f 100644
--- a/src/cokebank_basic/bank.c
+++ b/src/cokebank_basic/bank.c
@@ -9,18 +9,27 @@
  * for full details.
  */
 #include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include "common.h"
 
 enum {
 	FLAG_TYPEMASK    = 0x03,
-	USER_FLAG_NORMAL = 0x00,
-	USER_FLAG_COKE   = 0x01,
-	USER_FLAG_WHEEL  = 0x02,
-	USER_FLAG_GOD    = 0x03
+	USER_TYPE_NORMAL = 0x00,
+	USER_TYPE_COKE   = 0x01,
+	USER_TYPE_WHEEL  = 0x02,
+	USER_TYPE_GOD    = 0x03
 };
 
+// === GLOBALS ===
+tUser	*gaBank_Users;
+ int	giBank_NumUsers;
+FILE	*gBank_File;
+
 // === CODE ===
-int Bank_GetUserByUnixID(int UnixUID)
+int Bank_GetUserByUnixID(int UnixID)
 {
+	 int	i;
 	// Expensive search :(
 	for( i = 0; i < giBank_NumUsers; i ++ )
 	{
@@ -86,6 +95,14 @@ int Bank_GetMinAllowedBalance(int ID)
 	}
 }
 
+int Bank_GetUserUnixID(int ID)
+{
+	if( ID < 0 || ID >= giBank_NumUsers )
+		return -1;
+
+	return gaBank_Users[ID].UnixID;
+}
+
 /**
  * \brief Create a new user in our database
  */
@@ -105,7 +122,7 @@ int Bank_AddUser(int UnixID)
 	
 	// Commit to file
 	fseek(gBank_File, giBank_NumUsers*sizeof(gaBank_Users[0]), SEEK_SET);
-	fwrite(gaBank_Users[giBank_NumUsers], sizeof(gaBank_Users[0]), 1, gBank_File);
+	fwrite(&gaBank_Users[giBank_NumUsers], sizeof(gaBank_Users[0]), 1, gBank_File);
 
 	// Increment count
 	giBank_NumUsers ++;
diff --git a/src/cokebank_basic/common.h b/src/cokebank_basic/common.h
new file mode 100644
index 0000000000000000000000000000000000000000..e6e37c69771f19a2d3e5077f111e3d3037bd2300
--- /dev/null
+++ b/src/cokebank_basic/common.h
@@ -0,0 +1,19 @@
+/*
+ * OpenDispense 2 
+ * UCC (University [of WA] Computer Club) Electronic Accounting System
+ *
+ * cokebank.c - Coke-Bank management
+ *
+ * This file is licenced under the 3-clause BSD Licence. See the file COPYING
+ * for full details.
+ */
+#ifndef _COKEBANK_COMMON_H_
+#define _COKEBANK_COMMON_H_
+
+typedef struct sUser {
+	 int	UnixID;
+	 int	Balance;
+	 int	Flags;
+}	tUser;
+
+#endif
diff --git a/src/cokebank_basic/main.c b/src/cokebank_basic/main.c
index 2388be8b58c2454830570e7cb4562605325a183e..11b822cc085948aec4901d512b3f663e959be60a 100644
--- a/src/cokebank_basic/main.c
+++ b/src/cokebank_basic/main.c
@@ -11,17 +11,21 @@
 #include <stdio.h>
 #include <pwd.h>
 #include <string.h>
+#include "common.h"
 
 // === IMPORTS ===
- int	Bank_GetMinAllowedBalance(int ID);
- int	Bank_GetUserBalance(int ID);
- int	Bank_AlterUserBalance(int ID, int Delta);
- int	Bank_GetUserByUnixID(int UnixID);
- int	Bank_GetUserByName(const char *Name);
- int	Bank_AddUser(int UnixID);
+extern int	Bank_GetMinAllowedBalance(int ID);
+extern int	Bank_GetUserBalance(int ID);
+extern int	Bank_AlterUserBalance(int ID, int Delta);
+extern int	Bank_GetUserByUnixID(int UnixID);
+extern int	Bank_GetUserUnixID(int ID);
+extern int	Bank_AddUser(int UnixID);
+extern FILE	*gBank_File;
+extern tUser	*gaBank_Users;
+extern int	giBank_NumUsers;
 
 // === PROTOTYPES ===
-void	Init_Cokebank(void);
+void	Init_Cokebank(const char *Argument);
  int	Transfer(int SourceUser, int DestUser, int Ammount, const char *Reason);
  int	GetBalance(int User);
 char	*GetUserName(int User);
@@ -32,9 +36,21 @@ char	*GetUserName(int User);
 /**
  * \brief Load the cokebank database
  */
-void Init_Cokebank(void)
+void Init_Cokebank(const char *Argument)
 {
-	
+	gBank_File = fopen(Argument, "rb+");
+	if( !gBank_File ) {
+		gBank_File = fopen(Argument, "wb+");
+	}
+	if( !gBank_File ) {
+		perror("Opening coke bank");
+	}
+
+	fseek(gBank_File, 0, SEEK_END);
+	giBank_NumUsers = ftell(gBank_File) / sizeof(gaBank_Users[0]);
+	fseek(gBank_File, 0, SEEK_SET);
+	gaBank_Users = malloc( giBank_NumUsers * sizeof(gaBank_Users[0]) );
+	fread(gaBank_Users, sizeof(gaBank_Users[0]), giBank_NumUsers, gBank_File);
 }
 
 /**
@@ -69,7 +85,19 @@ int GetBalance(int User)
  */
 char *GetUserName(int User)
 {
-	return NULL;
+	struct passwd	*pwd;
+	 int	unixid = Bank_GetUserUnixID(User);
+	
+	if( unixid == -1 )
+		return strdup(">sales");
+
+	if( unixid == -2 )
+		return strdup(">liability");
+
+	pwd = getpwuid(unixid);
+	if( !pwd )	return NULL;
+
+	return strdup(pwd->pw_name);
 }
 
 /**
@@ -77,19 +105,26 @@ char *GetUserName(int User)
  */
 int GetUserID(const char *Username)
 {
-	struct passwd	*pwd;
-	 int	ret;
+	 int	ret, uid;
 
-	// Get user ID
-	pwd = getpwnam(Username);
-	if( !pwd ) {
-		return -1;
+	if( strcmp(Username, ">sales") == 0 ) {	// Pseudo account that sales are made into
+		uid = -1;
+	}
+	else if( strcmp(Username, ">liability") == 0 ) {	// Pseudo acount that money is added from
+		uid = -2;
+	}
+	else {
+		struct passwd	*pwd;
+		// Get user ID
+		pwd = getpwnam(Username);
+		if( !pwd )	return -1;
+		uid = pwd->pw_uid;
 	}
 
 	// Get internal ID (or create new user)
-	ret = Bank_GetUserByUnixID(pwd->pw_uid);
+	ret = Bank_GetUserByUnixID(uid);
 	if( ret == -1 ) {
-		ret = Bank_AddUser(pwd->pw_uid);
+		ret = Bank_AddUser(uid);
 	}
 
 	return ret;
@@ -101,8 +136,10 @@ int GetUserID(const char *Username)
  */
 int GetUserAuth(const char *Username, const char *Password)
 {
-	if( strcmp(Username, "test") == 0 )
-		return Bank_GetUserByName("test");
+	#if HACK_TPG_NOAUTH
+	if( strcmp(Username, "tpg") == 0 )
+		return GetUserID("tpg");
+	#endif
 	return -1;
 }
 
diff --git a/src/server/dispense.c b/src/server/dispense.c
index 32e6647d6343f12b3054aba1409ee653cb4b0356..f851731d22e2de8c0f4758b03bf8cc934271843c 100644
--- a/src/server/dispense.c
+++ b/src/server/dispense.c
@@ -29,7 +29,7 @@ int DispenseItem(int User, int Item)
 	if(!ret)	return ret;
 	
 	// Subtract the balance
-	ret = AlterBalance( User, -item->Price );
+	ret = Transfer( User, GetUserID(">sales"), item->Price, "" );
 	// What value should I use for this error?
 	// AlterBalance should return the final user balance
 	if(ret == 0)	return 1;
@@ -42,7 +42,7 @@ int DispenseItem(int User, int Item)
 	if(ret) {
 		Log_Error("Dispense failed after deducting cost (%s dispensing %s - %ic)",
 			username, item->Name, item->Price);
-		AlterBalance( User, item->Price );
+		Transfer( GetUserID(">sales"), User, item->Price, "rollback" );
 		free( username );
 		return 1;
 	}
diff --git a/src/server/handler_coke.c b/src/server/handler_coke.c
index f8ed1682786fd255d2d5cb6846ac10b12e42a5d4..493212e38296f0b3ada78ccc63c1c79dfa0f1f21 100644
--- a/src/server/handler_coke.c
+++ b/src/server/handler_coke.c
@@ -36,7 +36,7 @@ regex_t	gCoke_StatusRegex;
 int Coke_InitHandler()
 {
 	giCoke_SerialFD = open(gsCoke_SerialPort, O_RDWR);
-	regexc(&gCoke_StatusRegex, "^$", REG_EXTENDED);
+	regcomp(&gCoke_StatusRegex, "^$", REG_EXTENDED);
 	return 0;
 }
 
@@ -54,7 +54,7 @@ int Coke_CanDispense(int User, int Item)
 
 	// Read the response
 	read(giCoke_SerialFD, tmp, sizeof(tmp)-1);
-	regexec(&gCoke_StatusRegex, tmp, sizeof(matches)/sizeof(matches[0]), matches);
+	regexec(&gCoke_StatusRegex, tmp, sizeof(matches)/sizeof(matches[0]), matches, 0);
 
 	printf("s%i response '%s'\n", Item, tmp);
 
@@ -67,6 +67,7 @@ int Coke_CanDispense(int User, int Item)
 int Coke_DoDispense(int User, int Item)
 {
 	char	tmp[32];
+	regmatch_t	matches[4];
 
 	// Sanity please
 	if( Item < 0 || Item > 6 )	return -1;
@@ -77,7 +78,7 @@ int Coke_DoDispense(int User, int Item)
 
 	// Get status
 	read(giCoke_SerialFD, tmp, sizeof(tmp)-1);
-	regexec(&gCoke_StatusRegex, tmp, sizeof(matches)/sizeof(matches[0]), matches);
+	regexec(&gCoke_StatusRegex, tmp, sizeof(matches)/sizeof(matches[0]), matches, 0);
 	
 	printf("d%i response '%s'\n", Item, tmp);
 
diff --git a/src/server/main.c b/src/server/main.c
index e789b1306115e4c52701532ace86ec43386fd541..d327db38ee67abaf8f5e5693e038491cce28d8f6 100644
--- a/src/server/main.c
+++ b/src/server/main.c
@@ -13,7 +13,7 @@
 #include "common.h"
 
 // === IMPORTS ===
-extern void	Init_Cokebank(void);	// cokebank.c
+extern void	Init_Cokebank(const char *Argument);	// cokebank.c
 extern void	Load_Itemlist(void);
 extern void	Server_Start(void);
 extern int	giServer_Port;
@@ -22,6 +22,7 @@ extern char*	gsCoke_SerialPort;
 
 // === GLOBALS ===
  int	giDebugLevel = 0;
+char	*gsCokebankPath = "cokebank.db";
 
 // === CODE ===
 int main(int argc, char *argv[])
@@ -63,7 +64,7 @@ int main(int argc, char *argv[])
 		}
 	}
 	
-	Init_Cokebank();
+	Init_Cokebank(gsCokebankPath);
 	
 	Load_Itemlist();