diff --git a/README b/README
index 35360b354b706d39e74dc7ccac2d6ee26b814689..0cc5d19d0057b4ec712ebc828514202fc5d82b5c 100644
--- a/README
+++ b/README
@@ -10,6 +10,9 @@ Required packages
 - libncurses-dev
 - libssl-dev
 - build-essentials (gcc and GNU Make)
-- libmodbus (used for communicating with the coke machine)
+- libmodbus-dev (used for communicating with the coke machine)
+- libsqlite3-dev
+- libident-dev
+
 
 Run `make -C src/`
diff --git a/client.conf b/client.conf
new file mode 100644
index 0000000000000000000000000000000000000000..ff657ee984e38b3ecbbb46c498447d2cc7ba4eae
--- /dev/null
+++ b/client.conf
@@ -0,0 +1,5 @@
+#
+# OpenDispense2 Client config file
+#
+dispense_server merlo.ucc.asn.au
+dispense_port 11021
diff --git a/src/client/Makefile b/src/client/Makefile
index 41c23cb756cbb15eb4defc3a76ffe6e430fd1849..5045d983fc0fd97aaccc73616516f855c6d60b75 100644
--- a/src/client/Makefile
+++ b/src/client/Makefile
@@ -8,6 +8,7 @@ LDFLAGS := -g -lncurses
 
 BIN := ../../dispense
 OBJ := main.o protocol.o menu.o
+OBJ += doregex.o config.o
 
 DEPFILES := $(OBJ:%.o=%.d)
 
@@ -31,4 +32,8 @@ $(BIN): $(OBJ)
 	$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
 	$(CC) -M -MT $@ -o $*.d $< $(CPPFLAGS)
 
+%.o: ../common/%.c
+	$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
+	$(CC) -M -MT $@ -o $*.d $< $(CPPFLAGS)
+
 -include $(DEPFILES)
diff --git a/src/client/main.c b/src/client/main.c
index 2bd4312745a4a55fec20b9f8329dcd52d7261bd2..3938beaff39bcbad6a5496956024bfd5f2f7c2cb 100644
--- a/src/client/main.c
+++ b/src/client/main.c
@@ -16,6 +16,8 @@
 #include <unistd.h>	// close/getuid
 #include <limits.h>	// INT_MIN/INT_MAX
 #include "common.h"
+#include "../common/doregex.h"
+#include "../common/config.h"
 
 #define	USE_NCURSES_INTERFACE	0
 #define DEBUG_TRACE_SERVER	0
@@ -37,8 +39,12 @@ char	*trim(char *string);
 void	CompileRegex(regex_t *regex, const char *pattern, int flags);
 
 // === GLOBALS ===
-char	*gsDispenseServer = "merlo.ucc.gu.uwa.edu.au";
+const	char	*gsConfigFile = "/etc/opendispense/client.conf";
+
+const	char	*gsDispenseServer = "merlo.ucc.gu.uwa.edu.au";
  int	giDispensePort = 11020;
+ int	giDispenseServerSet = 0; // True if set by command line
+ int	giDispensePortSet = 0; // True if set by command line
 
 tItem	*gaItems;
  int	giNumItems;
@@ -143,11 +149,19 @@ void ShowUsage(void)
 			"        Show help text\n"
 			"    -G\n"
 			"        Use simple textual interface (instead of ncurses)\n"
+			"    -D\n"
+			"        Drinks only in user interface\n"
 			"    -n\n"
 			"        Dry run - Do not actually do dispenses\n"
 			"    -m <min balance>\n"
 			"    -M <max balance>\n"
 			"        Set the Maximum/Minimum balances shown in `dispense acct`\n"
+			"    -f <configfile>\n"
+			"        Set the config file path (default: `/etc/opendispense/client.conf'\n"
+			"    -H <host>\n"
+			"        Set a different dispense host\n"
+			"    -P <port>\n"
+			"        Set a different dispense port\n"
 			"Definitions:\n"
 			"    <itemid>\n"
 			"        Item ID of the form <type>:<num> where <type> is a non-empty string of alpha-numeric characters, and <num> is a non-negative integer\n"
@@ -603,6 +617,18 @@ int main(int argc, char *argv[])
 	if( ret )
 		return ret;
 
+	// Load config file
+	Config_ParseFile(gsConfigFile);
+
+	// Parse config values
+	if (!giDispenseServerSet) {
+		gsDispenseServer	= Config_GetValue("dispense_server",0);
+	}
+	if (!giDispensePortSet) {
+		giDispensePort		= Config_GetValue_Int("dispense_port",0);
+	}
+
+
 	// Sub-commands
 	if( strcmp(gsTextArgs[0], "finger") == 0 ) {
 		return subcommand_finger();
@@ -864,6 +890,15 @@ int ParseArguments(int argc, char *argv[])
 				giMaximumBalance = atoi(argv[++i]);
 				break;
 			
+			case 'f':	// Override Config File
+				if( i + 1 >= argc ) {
+					fprintf(stderr, "%s: -f takes an argument\n", argv[0]);
+					ShowUsage();
+					return RV_ARGUMENTS;
+				}
+				gsConfigFile = argv[++i];
+				break;
+			
 			case 'u':	// Override User
 				if( i + 1 >= argc ) {
 					fprintf(stderr, "%s: -u takes an argument\n", argv[0]);
@@ -880,6 +915,7 @@ int ParseArguments(int argc, char *argv[])
 					return RV_ARGUMENTS;
 				}
 				gsDispenseServer = argv[++i];
+				giDispenseServerSet = 1;
 				break;
 			case 'P':	// Override remote port
 				if( i + 1 >= argc ) {
@@ -888,6 +924,7 @@ int ParseArguments(int argc, char *argv[])
 					return RV_ARGUMENTS;
 				}
 				giDispensePort = atoi(argv[++i]);
+				giDispensePortSet = 1;
 				break;
 			
 			// Set slot name/price
@@ -982,32 +1019,3 @@ char *trim(char *string)
 	
 	return string;
 }
-
-int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
-{
-	 int	ret;
-	
-	ret = regexec(regex, string, nMatches, matches, 0);
-	if( ret && errorMessage ) {
-		size_t  len = regerror(ret, regex, NULL, 0);
-		char    errorStr[len];
-		regerror(ret, regex, errorStr, len);
-		printf("string = '%s'\n", string);
-		fprintf(stderr, "%s\n%s", errorMessage, errorStr);
-		exit(-1);
-	}
-	
-	return ret;
-}
-
-void CompileRegex(regex_t *regex, const char *pattern, int flags)
-{
-	 int	ret = regcomp(regex, pattern, flags);
-	if( ret ) {
-		size_t	len = regerror(ret, regex, NULL, 0);
-		char    errorStr[len];
-		regerror(ret, regex, errorStr, len);
-		fprintf(stderr, "Regex compilation failed - %s\n", errorStr);
-		exit(-1);
-	}
-}
diff --git a/src/server/config.c b/src/common/config.c
similarity index 99%
rename from src/server/config.c
rename to src/common/config.c
index 4630b582e2e12eca4fba234fa973c16bc19b0584..563240af9e72a85c109c112f3255014240ef0af3 100644
--- a/src/server/config.c
+++ b/src/common/config.c
@@ -9,7 +9,8 @@
  */
 #include <stdio.h>
 #include <stdlib.h>
-#include "common.h"
+#include "config.h"
+#include "doregex.h"
 #include <regex.h>
 #include <string.h>
 #include <ctype.h>
diff --git a/src/common/config.h b/src/common/config.h
new file mode 100644
index 0000000000000000000000000000000000000000..901cad849255beded2ccec1a5e8105627e8c79d5
--- /dev/null
+++ b/src/common/config.h
@@ -0,0 +1,28 @@
+/*
+ * OpenDispense2
+ *
+ * This code is published under the terms of the Acess licence.
+ * See the file COPYING for details.
+ *
+ * config.h - Config Header
+ */
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+// === HELPER MACROS ===
+#define _EXPSTR(x)      #x
+#define EXPSTR(x)       _EXPSTR(x)
+
+#define ASSERT(cnd) do{if(!(cnd)){fprintf(stderr, "ASSERT failed at "__FILE__":"EXPSTR(__LINE__)" - "EXPSTR(cnd)"\n");exit(-1);}}while(0)
+
+
+
+// --- Config Database ---
+extern void	Config_ParseFile(const char *Filename);
+extern void	Config_AddValue(const char *Key, const char *Value);
+extern int	Config_GetValueCount(const char *KeyName);
+extern const char	*Config_GetValue(const char *KeyName, int Index);
+extern int	Config_GetValue_Bool(const char *KeyName, int Index);
+extern int	Config_GetValue_Int(const char *KeyName, int Index);
+
+#endif
diff --git a/src/common/doregex.c b/src/common/doregex.c
new file mode 100644
index 0000000000000000000000000000000000000000..f4242db3803d40d8898a7e7e3099c8b4acd031a1
--- /dev/null
+++ b/src/common/doregex.c
@@ -0,0 +1,48 @@
+/*
+ * OpenDispense 2 
+ * UCC (University [of WA] Computer Club) Electronic Accounting System
+ *
+ * doregex.c - Initialisation Code
+ *
+ * This file is licenced under the 3-clause BSD Licence. See the file
+ * COPYING for full details.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include "doregex.h"
+
+// === CODE ===
+int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
+{
+	int	ret = -1;
+	
+	ret = regexec(regex, string, nMatches, matches, 0);
+	if( ret == REG_NOMATCH ) {
+		return -1;
+	}
+	if( ret ) {
+		size_t  len = regerror(ret, regex, NULL, 0);
+		char    errorStr[len];
+		regerror(ret, regex, errorStr, len);
+		printf("string = '%s'\n", string);
+		fprintf(stderr, "%s\n%s", errorMessage, errorStr);
+		exit(-1);
+	}
+	
+	return ret;
+}
+
+void CompileRegex(regex_t *regex, const char *pattern, int flags)
+{
+	int	ret = -1;
+	
+	ret = regcomp(regex, pattern, flags);
+	if( ret ) {
+		size_t	len = regerror(ret, regex, NULL, 0);
+		char    errorStr[len];
+		regerror(ret, regex, errorStr, len);
+		fprintf(stderr, "Regex compilation failed - %s\n%s\n", errorStr, pattern);
+		exit(-1);
+	}
+}
+
diff --git a/src/common/doregex.h b/src/common/doregex.h
new file mode 100644
index 0000000000000000000000000000000000000000..62c685945bbce8812691e6b3b4387d993ebc05f7
--- /dev/null
+++ b/src/common/doregex.h
@@ -0,0 +1,16 @@
+/*
+ * OpenDispense2
+ *
+ * This code is published under the terms of the Acess licence.
+ * See the file COPYING for details.
+ *
+ * doregex.h - Regex Header
+ */
+#ifndef _DOREGEX_H_
+#define _DOREGEX_H_
+
+#include <regex.h>
+extern void	CompileRegex(regex_t *Regex, const char *Pattern, int Flags);
+extern int	RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage);
+
+#endif
diff --git a/src/server/Makefile b/src/server/Makefile
index f2ca96826b8f27f96f8d2ab9bf419fd9512cddd8..5034bf93b550a3ea5ed8921a7a4a5ec226d25535 100644
--- a/src/server/Makefile
+++ b/src/server/Makefile
@@ -3,9 +3,10 @@
 
 INSTALLDIR := /usr/local/opendispense2
 
-OBJ := main.o server.o logging.o config.o
+OBJ := main.o server.o logging.o 
 OBJ += dispense.o itemdb.o
 OBJ += handler_coke.o handler_snack.o handler_door.o
+OBJ += config.o doregex.o
 BIN := ../../dispsrv
 
 OBJ := $(OBJ:%=obj/%)
@@ -29,10 +30,16 @@ install: $(BIN)
 $(BIN): $(OBJ)
 	$(CC) -o $(BIN) $(OBJ) $(LINKFLAGS)
 
-obj/%.o: %.c
+obj/%.o: %.c 
 	@mkdir -p $(dir $@)
 	$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
 	@cpp $< -MM -MF $@.d
 	
+
+obj/%.o: ../common/%.c 
+	@mkdir -p $(dir $@)
+	$(CC) -c $< -o $@ $(CFLAGS) $(CPPFLAGS)
+	@cpp $< -MM -MF $@.d
+
 -include $(DEPFILES)
 
diff --git a/src/server/common.h b/src/server/common.h
index 8a804972fff38e6b1707084e75da0e031ae4b5e8..1bdca84275dc4ad392bce589b0c536d00f9f9ffe 100644
--- a/src/server/common.h
+++ b/src/server/common.h
@@ -17,12 +17,8 @@
 #define	DEFAULT_ITEM_FILE	"/etc/opendispense/items.cfg"
 
 // === HELPER MACROS ===
-#define _EXPSTR(x)	#x
-#define EXPSTR(x)	_EXPSTR(x)
 
-#define UNUSED(var)	unused__##var __attribute__((__unused__))
-
-#define ASSERT(cnd) do{if(!(cnd)){fprintf(stderr, "ASSERT failed at "__FILE__":"EXPSTR(__LINE__)" - "EXPSTR(cnd)"\n");exit(-1);}}while(0)
+#define UNUSED(var)    unused__##var __attribute__((__unused__))
 
 // === STRUCTURES ===
 typedef struct sItem	tItem;
@@ -103,12 +99,4 @@ extern void	Log_Info(const char *Format, ...);
 #define Debug_Notice(msg, v...)	fprintf(stderr, "%08llun: "msg"\n", (unsigned long long)time(NULL) ,##v)
 #define Debug_Debug(msg, v...)	fprintf(stderr, "%08llud: "msg"\n", (unsigned long long)time(NULL) ,##v)
 
-// --- Config Database ---
-extern void	Config_ParseFile(const char *Filename);
-extern void	Config_AddValue(const char *Key, const char *Value);
-extern int	Config_GetValueCount(const char *KeyName);
-extern const char	*Config_GetValue(const char *KeyName, int Index);
-extern int	Config_GetValue_Bool(const char *KeyName, int Index);
-extern int	Config_GetValue_Int(const char *KeyName, int Index);
-
 #endif
diff --git a/src/server/handler_coke.c b/src/server/handler_coke.c
index ff051c8400b283f9a4239b85f824784bd03220e4..b9a9cf3271bbbd6e0a30e8441d7eee1ef165855b 100644
--- a/src/server/handler_coke.c
+++ b/src/server/handler_coke.c
@@ -11,6 +11,7 @@
  * - Remember, the coke machine echoes your text back to you!
  */
 #include "common.h"
+#include "../common/config.h"
 #include <stdio.h>
 #include <string.h>
 #include <stdarg.h>
diff --git a/src/server/main.c b/src/server/main.c
index 284002b487ac66315c5392300576ff05ba376a3d..cbebee28e92f2de0bc0a4979a60b4cef3ec61b6a 100644
--- a/src/server/main.c
+++ b/src/server/main.c
@@ -21,6 +21,7 @@
 #include <syslog.h>
 #include <pthread.h>
 #include "../cokebank.h"
+#include "../common/config.h"
 
 // === IMPORTS ===
 extern void	Init_Handlers(void);
@@ -187,38 +188,6 @@ void AddPeriodicFunction(void (*Fcn)(void))
 	fprintf(stderr, "Error: No space for %p in periodic list\n", Fcn);
 }
 
-int RunRegex(regex_t *regex, const char *string, int nMatches, regmatch_t *matches, const char *errorMessage)
-{
-	 int	ret;
-	
-	ret = regexec(regex, string, nMatches, matches, 0);
-	if( ret == REG_NOMATCH ) {
-		return -1;
-	}
-	if( ret ) {
-		size_t  len = regerror(ret, regex, NULL, 0);
-		char    errorStr[len];
-		regerror(ret, regex, errorStr, len);
-		printf("string = '%s'\n", string);
-		fprintf(stderr, "%s\n%s", errorMessage, errorStr);
-		exit(-1);
-	}
-	
-	return ret;
-}
-
-void CompileRegex(regex_t *regex, const char *pattern, int flags)
-{
-	 int	ret = regcomp(regex, pattern, flags);
-	if( ret ) {
-		size_t	len = regerror(ret, regex, NULL, 0);
-		char    errorStr[len];
-		regerror(ret, regex, errorStr, len);
-		fprintf(stderr, "Regex compilation failed - %s\n%s\n", errorStr, pattern);
-		exit(-1);
-	}
-}
-
 // Serial helper
 int InitSerial(const char *File, int BaudRate)
 {
diff --git a/src/server/server.c b/src/server/server.c
index c41cc2c30e899ce1ccca3a56ebca1a0b2450dc74..11846bb21fceb1836dba743e28f60e3bdfbddd76 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -10,6 +10,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include "common.h"
+#include "../common/config.h"
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>