diff --git a/apps/sam/c/Makefile b/apps/sam/c/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..72fa21cd237c0ebcc288adf4bbb76cb4f9da0b43
--- /dev/null
+++ b/apps/sam/c/Makefile
@@ -0,0 +1,64 @@
+FLAGS+=-g
+CFLAGS+=$(FLAGS)
+LDFLAGS+=$(FLAGS)
+
+OBJS:=obj/sam.lo obj/strl.lo obj/parse.lo obj/tinystring.lo
+DEPS:=$(patsubst obj/%.lo, .deps/%.d, $(OBJS))
+DESTDIR:=$(if $(DESTDIR),$(DESTDIR)/lib,/usr/lib)
+
+MAKEFLAGS=-s -r
+
+PERL=$(shell which perl 2>/dev/null)
+ifneq ($(PERL),)
+STATUS=$(PERL) ./status
+else
+STATUS=echo
+endif
+
+LIBTOOL_LOG=libtool.log
+
+all:: cleanlog .deps/finish
+
+cleanlog:
+	echo >$(LIBTOOL_LOG)
+
+lib/libsam.so: obj/libsam.la
+	libtool --mode=install install $^ `pwd`/$@ >>$(LIBTOOL_LOG)
+
+obj/libsam-static.la: $(OBJS)
+	$(STATUS) library '(static)'
+	libtool --mode=link gcc -static $(LDFLAGS) -o $@ $^ >>$(LIBTOOL_LOG)
+
+obj/libsam.la: $(OBJS)
+	$(STATUS) library '(shared)'
+	libtool --mode=link gcc -rpath  $(DESTDIR) $(LDFLAGS) -o $@ $^ >>$(LIBTOOL_LOG)
+
+obj/%.lo: src/%.c
+	$(STATUS) compile $*
+	libtool --mode=compile gcc $(CFLAGS) -Iinc/ -c -o $@ $< >>$(LIBTOOL_LOG)
+
+$(OBJS):|obj
+obj:
+	$(STATUS) MKDIR $@
+	mkdir -p $@
+
+.deps/%.d: src/%.c
+	$(STATUS) deps $*
+	gcc -Iinc/ -MM -MT obj/$*.o $< -o $@
+
+-include $(DEPS)
+
+DEPS+=.deps/finish
+.deps/finish: lib/libsam.so
+	libtool --finish $(DESTDIR) >>$(LIBTOOL_LOG) && touch $@
+$(DEPS):|.deps
+.deps:
+	$(STATUS) MKDIR $@
+	mkdir -p $@
+
+clean:
+	$(STATUS) clean
+	libtool --mode=clean rm -f obj/*.l* lib/*.l* lib/*.so* lib/*.a >>$(LIBTOOL_LOG)
+	rm -Rf .deps libtool.log
+
+.PHONY: all cleanlog clean
\ No newline at end of file
diff --git a/apps/sam/c/Makefile.common b/apps/sam/c/Makefile.common
deleted file mode 100644
index a8b2a1a725b7154b2acb846a550c3717dcc50762..0000000000000000000000000000000000000000
--- a/apps/sam/c/Makefile.common
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# This Makefile contains instructions common to all platforms
-#
-
-#
-# Build rules
-#
-
-all: clean depend libsam
-
-depend:
-	$(CC) $(CFLAGS) -MM $(SRCDIR)/*.c > .depend
-
-$(OBJDIR)/%.o: $(SRCDIR)/%.c
-	$(CC) $(CFLAGS) -o $@ -c $<
-
-libsam: $(OBJS)
-	$(AR) rcs $(LIBDIR)/libsam.a $(OBJS)
-
-#
-# Cleanup rules
-#
-
-clean:
-	-$(RM) -f $(LIBDIR)/libsam.a $(OBJDIR)/*.o .depend
diff --git a/apps/sam/c/Makefile.cygwin b/apps/sam/c/Makefile.cygwin
deleted file mode 100644
index 3ffb2539096bde9ff8fbeb42b3039ff895f36ce5..0000000000000000000000000000000000000000
--- a/apps/sam/c/Makefile.cygwin
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# This Makefile is compatible with GNU Make and should work on Cygwin
-#
-
-#
-# Your operating system
-#
-
-OS = CYGWIN
-
-#
-# Directories
-#
-
-INCDIR = inc
-LIBDIR = lib
-OBJDIR = obj
-SRCDIR = src
-
-#
-# Programs
-#
-
-AR = ar
-CC = gcc
-RM = rm
-
-#
-# Flags
-#
-
-CFLAGS = -g -O2 -pipe -std=c99 -Wall
-CFLAGS += -DOS=$(OS)
-CFLAGS += -I$(INCDIR)
-
-#
-# Object files
-#
-
-OBJS =	$(OBJDIR)/sam.o \
-		$(OBJDIR)/snprintf.o \
-		$(OBJDIR)/strl.o
-
-#
-# Include the make instructions common to all platforms
-#
-
-include Makefile.common
diff --git a/apps/sam/c/Makefile.freebsd b/apps/sam/c/Makefile.freebsd
deleted file mode 100644
index 3fdf8f315e801af2d53d3f229f997c5582c8fcee..0000000000000000000000000000000000000000
--- a/apps/sam/c/Makefile.freebsd
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# This Makefile is compatible with GNU Make and should work on FreeBSD
-#
-
-#
-# Your operating system
-#
-
-OS = FREEBSD
-
-#
-# Directories
-#
-
-INCDIR = inc
-LIBDIR = lib
-OBJDIR = obj
-SRCDIR = src
-
-#
-# Programs
-#
-
-AR = ar
-CC = gcc
-RM = rm
-
-#
-# Flags
-#
-
-CFLAGS = -g -O2 -pipe -std=c99 -Wall
-CFLAGS += -DOS=$(OS)
-CFLAGS += -I$(INCDIR)
-
-#
-# Object files
-#
-
-OBJS =	$(OBJDIR)/sam.o
-
-#
-# Include the make instructions common to all platforms
-#
-
-include Makefile.common
diff --git a/apps/sam/c/Makefile.linux b/apps/sam/c/Makefile.linux
deleted file mode 100644
index 7eddeed32d115df162147c5c688f03844f2389bc..0000000000000000000000000000000000000000
--- a/apps/sam/c/Makefile.linux
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# This Makefile is compatible with GNU Make and should work on Linux
-#
-
-#
-# Your operating system
-#
-
-OS = LINUX
-
-#
-# Directories
-#
-
-INCDIR = inc
-LIBDIR = lib
-OBJDIR = obj
-SRCDIR = src
-
-#
-# Programs
-#
-
-AR = ar
-CC = gcc
-RM = rm
-
-#
-# Flags
-#
-
-CFLAGS = -g -O2 -pipe -std=c99 -Wall
-CFLAGS += -DOS=$(OS)
-CFLAGS += -I$(INCDIR)
-
-#
-# Object files
-#
-
-OBJS =	$(OBJDIR)/sam.o \
-		$(OBJDIR)/strl.o
-
-#
-# Include the make instructions common to all platforms
-#
-
-include Makefile.common
diff --git a/apps/sam/c/Makefile.mingw b/apps/sam/c/Makefile.mingw
deleted file mode 100644
index d418f175a6a42bcbf1b1cdd55e2e271399aaef7b..0000000000000000000000000000000000000000
--- a/apps/sam/c/Makefile.mingw
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# This Makefile is compatible with GNU Make and should work on Windows (MingW)
-#
-
-#
-# Your operating system
-#
-
-OS = MINGW
-
-#
-# Directories
-#
-
-INCDIR = inc
-LIBDIR = lib
-OBJDIR = obj
-SRCDIR = src
-
-#
-# Programs
-#
-
-AR = C:\MinGW\bin\ar
-CC = C:\MinGW\bin\gcc
-RM = C:\MinGW\bin\rm
-
-#
-# Flags
-#
-
-CFLAGS = -g -O2 -pipe -std=c99 -Wall
-CFLAGS += -DOS=$(OS)
-CFLAGS += -I$(INCDIR)
-
-#
-# Object files
-#
-
-OBJS =	$(OBJDIR)/sam.o \
-		$(OBJDIR)/strl.o
-
-#
-# Include the make instructions common to all platforms
-#
-
-include Makefile.common
diff --git a/apps/sam/c/examples/i2p-ping/Makefile b/apps/sam/c/examples/i2p-ping/Makefile
index b1ce9ddb96d3be2eb3acfb3ba2bd77c8e8ea67e4..9f5c27b5e2a4e7da06e992262cca68ede99c39cc 100644
--- a/apps/sam/c/examples/i2p-ping/Makefile
+++ b/apps/sam/c/examples/i2p-ping/Makefile
@@ -1,39 +1,54 @@
-#
-# This Makefile is compatible with GNU Make and should work on POSIX systems
-#
+FLAGS+=-g
 
-#
-# Programs
-#
+CFLAGS = $(FLAGS) -pipe -std=c99 -Wall
+CFLAGS += -I../../inc
+LDFLAGS = $(FLAGS) -L../../lib -lsam
 
-CC = gcc
-INSTALL = install
-RM = rm
+OBJS:=i2p-ping.lo
+DEPS:=$(patsubst obj/%.lo, .deps/%.d, $(OBJS))
+DESTDIR:=$(if $(DESTDIR),$(DESTDIR)/lib,/usr/lib)
 
-#
-# Flags
-#
+MAKEFLAGS=-s -r
+PERL=$(shell which perl 2>/dev/null)
+ifneq ($(PERL),)
+STATUS=$(PERL) ../../status
+else
+STATUS=echo
+endif
 
-CFLAGS = -g -O2 -pipe -std=c99 -Wall
-CFLAGS += -I../../inc -L../../lib
-LIBS = -lsam
+LIBTOOL_LOG=libtool.log
 
-#
-# Build rules
-#
+all:: cleanlog i2p-ping
 
-all: clean i2p-ping
+cleanlog:
+	>$(LIBTOOL_LOG)
 
-i2p-ping: i2p-ping.c
-	$(CC) $(CFLAGS) -o i2p-ping.o -c i2p-ping.c
-	$(CC) $(CFLAGS) -o i2p-ping i2p-ping.o $(LIBS)
+i2p-ping: $(OBJS)
+	$(STATUS) link
+	libtool --mode=link gcc $(LDFLAGS) -o $@ $^ >>$(LIBTOOL_LOG)
 
-install: i2p-ping
-	$(INSTALL) i2p-ping $(HOME)/bin
-
-#
-# Cleanup rules
-#
+%.lo: %.c
+	$(STATUS) compile $*
+	libtool --mode=compile gcc $(CFLAGS) -Iinc/ -c -o $@ $< >>$(LIBTOOL_LOG)
+.deps/%.d: src/%.c
+	$(STATUS) deps $*
+	gcc -Iinc/ -MM -MT obj/$*.o $^ -o $@
 
 clean:
-	-$(RM) -f i2p-ping *.o
+	$(STATUS) clean
+	rm -Rf .deps obj libtool.log
+	libtool --mode=clean rm -f i2p-ping i2p-ping.lo >>$(LIBTOOL_LOG)
+
+$(OBJS):|obj
+obj:
+	$(STATUS) MKDIR $@
+	mkdir -p $@
+
+-include $(DEPS)
+$(DEPS):|.deps
+.deps:
+	$(STATUS) MKDIR $@
+	mkdir -p $@
+
+
+.PHONY: all cleanlog clean
\ No newline at end of file
diff --git a/apps/sam/c/inc/parse.h b/apps/sam/c/inc/parse.h
new file mode 100644
index 0000000000000000000000000000000000000000..960f2d8ca2da96f9aa205bd1ef891e1d6cf59848
--- /dev/null
+++ b/apps/sam/c/inc/parse.h
@@ -0,0 +1,24 @@
+#ifndef _PARSE_HEADER_FEEP
+#define _PARSE_HEADER_FEEP
+
+#include "tinystring.h"
+
+typedef struct arg_s {
+  string_t name;
+  string_t value;
+  //  int pos;
+} arg_t;
+
+typedef struct {
+  arg_t* arg;
+  int num;
+} args_t;
+
+args_t arg_parse(const char*);
+void arg_done(args_t);
+arg_t* arg_get(args_t,int);
+arg_t* arg_find(args_t,string_t);
+
+#define AG(a,b) arg_get(a,b)
+
+#endif /* _PARSE_HEADER_FEEP */
diff --git a/apps/sam/c/inc/sam.h b/apps/sam/c/inc/sam.h
index 32cce31566f64a7c4dbbc529e0dd53c5ff9e5038..29f5139f2754ebb7ece7afe1f2b216456cc435f1 100644
--- a/apps/sam/c/inc/sam.h
+++ b/apps/sam/c/inc/sam.h
@@ -121,9 +121,9 @@ bool		sam_read_buffer(sam_sess_t *session);
 const char *sam_strerror(samerr_t code);
 /* SAM controls - callbacks */
 void		(*sam_diedback)(sam_sess_t *session);
-void		(*sam_logback)(char *str);
-void		(*sam_namingback)(sam_sess_t *session, char *name,
-				sam_pubkey_t pubkey, samerr_t result);
+void		(*sam_logback)(const char *str);
+void            (*sam_namingback)(sam_sess_t *session, const char *name, 
+                                  sam_pubkey_t pubkey, samerr_t result, const char* message);
 
 /* Stream commands */
 void		sam_stream_close(sam_sess_t *session, sam_sid_t stream_id);
@@ -131,14 +131,15 @@ sam_sid_t	sam_stream_connect(sam_sess_t *session, const sam_pubkey_t dest);
 samerr_t	sam_stream_send(sam_sess_t *session, sam_sid_t stream_id,
 				const void *data, size_t size);
 /* Stream commands - callbacks */
-void		(*sam_closeback)(sam_sess_t *session, sam_sid_t stream_id,
-				samerr_t reason);
+void            (*sam_closeback)(sam_sess_t *session, sam_sid_t stream_id, 
+                                 samerr_t reason, const char* message);
+
 void		(*sam_connectback)(sam_sess_t *session, sam_sid_t stream_id,
-				sam_pubkey_t dest);
-void		(*sam_databack)(sam_sess_t *session, sam_sid_t stream_id,
+                                   sam_pubkey_t dest);
+    void		(*sam_databack)(sam_sess_t *session, sam_sid_t stream_id,
 				void *data, size_t size);
-void		(*sam_statusback)(sam_sess_t *session, sam_sid_t stream_id,
-				samerr_t result);
+void            (*sam_statusback)(sam_sess_t *session, sam_sid_t stream_id,
+                                  samerr_t result, const char* message);
 
 /* Stream send queue (experimental) */
 void		sam_sendq_add(sam_sess_t *session, sam_sid_t stream_id,
diff --git a/apps/sam/c/inc/tinystring.h b/apps/sam/c/inc/tinystring.h
new file mode 100644
index 0000000000000000000000000000000000000000..f518e0ebc62f362f29d35bb1569d9774f9578065
--- /dev/null
+++ b/apps/sam/c/inc/tinystring.h
@@ -0,0 +1,48 @@
+#ifndef TINYSTRING_HEADER
+#define TINYSTRING_HEADER
+
+#include <sys/types.h>
+
+#ifndef bool
+#define bool short int
+#endif
+
+struct string_s;
+#define string_t struct string_s*
+//Mysteeeerious *waggles mysteriously*
+
+/*{
+  char* data;
+  long int size;
+} *string_t;
+*/
+
+string_t string_create(const char*);
+string_t string_ncreate(const char* cstr,long int length);
+
+string_t string_wrap(const char*); 
+//Does not malloc, do NOT pass to string_free
+
+string_t string_fmt(const char* fmt, ...);
+string_t string_cat(string_t,string_t);
+
+/* Source Dest */
+void string_copy(string_t,string_t);
+void string_copy_raw(string_t,void*,size_t);
+
+const char* string_data(string_t);
+long int string_size(string_t);
+
+void string_free(string_t);
+
+bool string_equal(string_t,string_t);
+bool string_equali(string_t,string_t);
+int string_cmp(string_t,string_t);
+int string_cmpi(string_t,string_t);
+
+#define _sw(a) string_wrap(a)
+#define _scr(a,b,c) string_copy_raw(a,b,c)
+
+#define string_is(a,b) (! strncmp(string_data(a),(b),string_size(a)))
+
+#endif /* TINYSTRING_HEADER */
diff --git a/apps/sam/c/src/parse.c b/apps/sam/c/src/parse.c
new file mode 100644
index 0000000000000000000000000000000000000000..6fcb33fc63b86903d2f390d5d0353b3eb8ce2353
--- /dev/null
+++ b/apps/sam/c/src/parse.c
@@ -0,0 +1,78 @@
+#include "parse.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <malloc.h>
+#define _GNU_SOURCE
+#include <string.h>
+
+args_t arg_parse(const char* line_raw) {
+    args_t self;
+    int numargs = 0;
+    const char *end, *last;
+    /* First pass to count how many args... */
+    end = line_raw;
+    while(*end && isspace(*end)) ++end;
+    //Skip initial space...
+    for(;;) {
+        while(*end && !isspace(*end)) ++end;
+        //Go to end of argument
+        ++numargs;
+        while(*end && isspace(*end)) ++end;
+        //Go to end of space after argument
+        if(!*end) break;
+    }
+    self.num = numargs; // One more # args than spaces.
+    self.arg = malloc(sizeof(arg_t)*numargs);
+
+    /* Second pass to assign args.  (Lemee alone, is more efficient than a linked list!) */
+    last = line_raw;
+    numargs = 0; //Now numargs is which current arg.
+    end = line_raw;
+    while(*end && isspace(*end)) ++end;
+    //Skip initial space...
+    for(;;) {
+        arg_t* nextarg = self.arg + numargs;;
+        const char* isbinary;
+        while(*end && !isspace(*end)) ++end;
+        //Go to end of argument
+        isbinary = strchr(last,'='); //Is there a value?
+        
+        //Make sure not to pass end in our search for =
+        if(isbinary && (isbinary < end)) {
+            nextarg->name = string_ncreate(last,isbinary-last);
+            nextarg->value = string_ncreate(isbinary+1,end-isbinary-1);
+        } else {
+            nextarg->name = string_ncreate(last,end-last);
+            nextarg->value = string_create(NULL);
+        }
+        ++numargs;
+        while(*end && isspace(*end)) ++end;
+        //Go to end of space after argument
+        if(!*end) break;
+        last = end;
+    }
+    return self;
+}
+
+void arg_done(args_t self) {
+    free(self.arg);
+    self.arg = NULL;
+    self.num = 0;
+}
+
+arg_t* arg_get(args_t self, int index) {
+    if(index >= self.num) return NULL;
+    return self.arg + index;
+}
+
+arg_t* arg_find(args_t self,string_t testname) {
+    int index;
+    for(index=0;index<self.num;++index) {
+        if(string_equali(self.arg[index].name,testname)) {
+            return self.arg + index;
+        }
+    }
+
+    return NULL;
+}
diff --git a/apps/sam/c/src/sam.c b/apps/sam/c/src/sam.c
index 9fe35486edd0f79f8ecb51a66f086230e9b0542f..d9535588576a710acd9e25226623d73091b9c085 100644
--- a/apps/sam/c/src/sam.c
+++ b/apps/sam/c/src/sam.c
@@ -30,6 +30,10 @@
 
 #include "sam.h"
 #include "platform.h"
+#include "parse.h"
+#include "tinystring.h"
+
+#include <assert.h>
 
 static bool			sam_hello(sam_sess_t *session);
 static void			sam_log(const char *format, ...);
@@ -57,7 +61,7 @@ static ssize_t		sam_write(sam_sess_t *session, const void *buf, size_t n);
  */
 
 /* a peer closed the connection */
-void (*sam_closeback)(sam_sess_t *session, sam_sid_t stream_id, samerr_t reason)
+void (*sam_closeback)(sam_sess_t *session, sam_sid_t stream_id, samerr_t reason, const char* message)
 	= NULL;
 
 /* a peer connected to us */
@@ -76,15 +80,14 @@ void (*sam_dgramback)(sam_sess_t *session, sam_pubkey_t dest, void *data,
 void (*sam_diedback)(sam_sess_t *session) = NULL;
 
 /* logging callback */
-void (*sam_logback)(char *str) = NULL;
+void (*sam_logback)(const char *str) = NULL;
 
 /* naming lookup reply - `pubkey' will be NULL if `result' isn't SAM_OK */
-void (*sam_namingback)(sam_sess_t *session, char *name, sam_pubkey_t pubkey,
-	samerr_t result) = NULL;
+void (*sam_namingback)(sam_sess_t *session, const char *name, sam_pubkey_t pubkey, samerr_t result, const char* message) = NULL;
 
 /* our connection to a peer has completed */
 void (*sam_statusback)(sam_sess_t *session, sam_sid_t stream_id,
-	samerr_t result) = NULL;
+	samerr_t result, const char* message) = NULL;
 
 /* a peer sent some raw data (`data' MUST be freed) */
 void (*sam_rawback)(sam_sess_t *session, void *data, size_t size) = NULL;
@@ -290,13 +293,13 @@ static void sam_log(const char *format, ...)
  */
 void sam_naming_lookup(sam_sess_t *session, const char *name)
 {
-	assert(session != NULL);
-	char cmd[SAM_CMD_LEN];
+    assert(session != NULL);
+    char cmd[SAM_CMD_LEN];
 
-	snprintf(cmd, sizeof cmd, "NAMING LOOKUP NAME=%s\n", name);
-	sam_write(session, cmd, strlen(cmd));
+    snprintf(cmd, sizeof cmd, "NAMING LOOKUP NAME=%s\n", name);
+    sam_write(session, cmd, strlen(cmd));
 
-	return;
+    return;
 }
 
 /*
@@ -304,241 +307,192 @@ void sam_naming_lookup(sam_sess_t *session, const char *name)
  *
  * s - string of data that we read (read past tense)
  */
+bool sam_parse_args(sam_sess_t *session, args_t args);
 static void sam_parse(sam_sess_t *session, char *s)
 {
-	assert(session != NULL);
-#define SAM_DGRAM_RECEIVED_REPLY "DATAGRAM RECEIVED"
-#define SAM_NAMING_REPLY "NAMING REPLY"
-#define SAM_NAMING_REPLY_OK "NAMING REPLY RESULT=OK"
-#define SAM_NAMING_REPLY_IK "NAMING REPLY RESULT=INVALID_KEY"
-#define SAM_NAMING_REPLY_KNF "NAMING REPLY RESULT=KEY_NOT_FOUND"
-#define SAM_RAW_RECEIVED_REPLY "RAW RECEIVED"
-#define SAM_STREAM_CLOSED_REPLY "STREAM CLOSED"
-#define SAM_STREAM_CONNECTED_REPLY "STREAM CONNECTED"
-#define SAM_STREAM_RECEIVED_REPLY "STREAM RECEIVED"
-#define SAM_STREAM_STATUS_REPLY "STREAM STATUS"
-#define SAM_STREAM_STATUS_REPLY_OK "STREAM STATUS RESULT=OK"
-#define SAM_STREAM_STATUS_REPLY_CRP "STREAM STATUS RESULT=CANT_REACH_PEER"
-#define SAM_STREAM_STATUS_REPLY_I2E "STREAM STATUS RESULT=I2P_ERROR"
-#define SAM_STREAM_STATUS_REPLY_IK "STREAM STATUS RESULT=INVALID_KEY"
-#define SAM_STREAM_STATUS_REPLY_TO "STREAM STATUS RESULT=TIMEOUT"
+    //Wrapper for ease of memory management
+    args_t args;
+    assert(session != NULL);
+    args = arg_parse(s);
+    if(!sam_parse_args(session, args)) {
+        SAMLOG("Unknown SAM command received: %s", s);
+    }
+    arg_done(args);
+}
 
-	/*
-	 * TODO: add raw parsing
-	 */
+long int strtol_checked(const char* str) {
+    static char* end = NULL;
+    long int ret = strtol(str,&end,10);
+    assert(str != end || "No number found at all!");    
+    return ret;
+}
 
-	if (strncmp(s, SAM_DGRAM_RECEIVED_REPLY,
-			strlen(SAM_DGRAM_RECEIVED_REPLY)) == 0) {
-		char *p;
+bool sam_parse_args(sam_sess_t *session, args_t args)
+{
+    arg_t* arg; // The current argument being examined...
+    const char* message = NULL; // Almost EVERYTHING can have a message...
+	
+    if(args.num <= 0) return 0;
+
+#define ARG_IS(a,b) string_equal(AG(args,a)->name,string_wrap(b))
+#define ARG_FIND(a) arg_find(args,_sw(a))
+
+    // Almost EVERYTHING can have a message...
+    arg = ARG_FIND("MESSAGE");
+    if(arg) {
+        message = string_data(arg->value);
+    }
+
+    if(ARG_IS(0,"DATAGRAM") &&
+       ARG_IS(1,"RECEIVED")) {
+        sam_pubkey_t dest;
+        size_t size;
+        void *data;
+
+        arg = ARG_FIND("DESTINATION");
+        assert(arg != NULL);
+        _scr(arg->value, dest, sizeof dest);
+
+        arg = ARG_FIND("SIZE");
+        assert(arg != NULL);
+        size = strtol_checked(string_data(arg->value));
+
+        data = malloc(size + 1);  
+        /* +1 for NUL termination, so when we are
+           receiving a string it will just work and it
+           won't be necessary to send NUL.  When binary
+           data is sent, the extra NUL character will
+           just be ignored by the client program,
+           because it is not added to the size */
+        if (data == NULL) {
+	    SAMLOGS("Out of memory");
+	    abort();
+        }
+        if (sam_read2(session, data, size) != -1) {
+	    char* p = data + size;
+	    *p = '\0';  /* see above NUL note */
+	    sam_dgramback(session, dest, data, size); /* `data' must be freed */
+        } else
+	    free(data);
+	  
+    } else if (ARG_IS(0,"NAMING") &&
+               ARG_IS(1, "REPLY")) {
+        if(NULL == (arg = ARG_FIND("RESULT"))) {
+            SAMLOGS("Naming reply with no result");
+            return 0;
+        }
+
+        if (string_is(arg->value,"OK")) {
+            sam_pubkey_t pubkey;
+            arg = ARG_FIND("VALUE");
+            assert(arg != NULL);
+            _scr(arg->value, pubkey, sizeof pubkey);
+            arg = ARG_FIND("NAME");
+            assert(arg != NULL);
+
+            sam_namingback(session, string_data(arg->value), pubkey, SAM_OK, message);
+        } else if(string_is(arg->value,"INVALID_KEY")) {
+            arg_t* namearg = ARG_FIND("NAME");
+            assert(namearg != NULL);
+            sam_namingback(session, string_data(namearg->value), NULL,
+                           SAM_INVALID_KEY, message);
+        } else if(string_is(arg->value,"KEY_NOT_FOUND")) {
+            arg_t* namearg = ARG_FIND("NAME");
+            assert(namearg != NULL);
+            sam_namingback(session, string_data(namearg->value), NULL,
+                           SAM_KEY_NOT_FOUND, message);
+        } else {
+            arg_t* namearg = ARG_FIND("NAME");
+            assert(namearg != NULL);
+            sam_namingback(session, string_data(namearg->value), NULL,
+                           SAM_UNKNOWN, message);
+        }
+        
+    } else if (ARG_IS(0,"STREAM")) {
+        sam_sid_t stream_id;
+        arg = ARG_FIND("ID");
+        assert(arg != 0);
+        stream_id = strtol_checked(string_data(arg->value));
+
+        if(ARG_IS(1,"CLOSED")) {
+            arg = ARG_FIND("RESULT");
+            assert(arg != NULL);
+            if (string_is(arg->value,"OK")) {
+                sam_closeback(session, stream_id, SAM_OK, message);
+            } else if (string_is(arg->value,"CANT_REACH_PEER")) {
+                sam_closeback(session, stream_id, SAM_CANT_REACH_PEER, message);
+            } else if (string_is(arg->value,"I2P_ERROR")) {
+                sam_closeback(session, stream_id, SAM_I2P_ERROR, message);
+            } else if (string_is(arg->value,"PEER_NOT_FOUND")) {
+                sam_closeback(session, stream_id, SAM_PEER_NOT_FOUND, message);
+            } else if (string_is(arg->value,"TIMEOUT")) {
+                sam_closeback(session, stream_id, SAM_TIMEOUT, message);
+            } else {
+                sam_closeback(session, stream_id, SAM_UNKNOWN, message);
+            }
+
+	} else if(ARG_IS(1,"CONNECTED")) {
 		sam_pubkey_t dest;
-		size_t size;
-		void *data;
-
-		p = strchr(s, '=');  /* DESTINATION= */
-		assert(p != NULL);
-		p++;
-		strlcpy(dest, p, sizeof dest);
-		p = strchr(p, '=');  /* SIZE= */
-		assert(p != NULL);
-		p++;
-		size = strtol(p, NULL, 10);
-		assert(size != 0);
-		data = malloc(size + 1);  /* +1 for NUL termination, so when we are
-									receiving a string it will just work and it
-									won't be necessary to send NUL.  When binary
-									data is sent, the extra NUL character will
-									just be ignored by the client program,
-									because it is not added to the size */
-		if (data == NULL) {
-			SAMLOGS("Out of memory");
-			abort();
-		}
-		if (sam_read2(session, data, size) != -1) {
-			p = data + size;
-			*p = '\0';  /* see above NUL note */
-			sam_dgramback(session, dest, data, size); /* `data' must be freed */
-		} else
-			free(data);
-
-		return;
-
-	} else if (strncmp(s, SAM_NAMING_REPLY, strlen(SAM_NAMING_REPLY)) == 0) {
-		char *p;
-		char *q;
-		char name[SAM_NAME_LEN];
 
-		p = strchr(s, '=');  /* can't use strrchar because of option
-								MESSAGE= */
-		assert(p != NULL);  /* RESULT= */
-		p++;
-		p = strchr(p, '=');  /* NAME= */
-		assert(p != NULL);
-		p++;
+                arg = ARG_FIND("DESTINATION");
+                assert(arg != NULL);
+                _scr(arg->value, dest, sizeof dest);
 
-		if (strncmp(s, SAM_NAMING_REPLY_OK, strlen(SAM_NAMING_REPLY_OK)) == 0) {
-			sam_pubkey_t pubkey;
-
-			q = strchr(p, ' ');  /* ' 'VAL.. */
-			assert(q != NULL);
-			*q = '\0';
-			q++;
-			q = strchr(q, '=');  /* VALUE= */
-			assert(q != NULL);
-			q++;
-			strlcpy(name, p, sizeof name);
-			strlcpy(pubkey, q, sizeof pubkey);
-			sam_namingback(session, name, pubkey, SAM_OK);
-
-		} else if (strncmp(s, SAM_NAMING_REPLY_IK,
-				strlen(SAM_NAMING_REPLY_IK)) == 0) {
-			q = strchr(p, ' ');  /* ' 'MES.. (optional) */
-			if (q != NULL)
-				*q = '\0';
-			strlcpy(name, p, sizeof name);
-			sam_namingback(session, name, NULL, SAM_INVALID_KEY);
-
-		} else if (strncmp(s, SAM_NAMING_REPLY_KNF,
-				strlen(SAM_NAMING_REPLY_KNF)) == 0) {
-			q = strchr(p, ' ');  /* ' 'MES.. (optional) */
-			if (q != NULL)
-				*q = '\0';
-			strlcpy(name, p, sizeof name);
-			sam_namingback(session, name, NULL, SAM_KEY_NOT_FOUND);
-
-		} else {
-			q = strchr(p, ' ');  /* ' 'MES.. (optional) */
-			if (q != NULL)
-				*q = '\0';
-			strlcpy(name, p, sizeof name);
-			sam_namingback(session, name, NULL, SAM_UNKNOWN);
-		}
-
-		return;
-
-	} else if (strncmp(s, SAM_STREAM_CLOSED_REPLY,
-			strlen(SAM_STREAM_CLOSED_REPLY)) == 0) {
-		char *p;
-		sam_sid_t stream_id;
-
-		p = strchr(s, '=');  /* can't use strrchar because of option MESSAGE= */
-		assert(p != NULL);  /* ID= */
-		p++;
-		stream_id = strtol(p, NULL, 10);
-		assert(stream_id != 0);
-		p = strchr(p, '=');  /* RESULT= */
-		assert(p != NULL);
-		p++;
-		if (strncmp(p, "OK", strlen("OK")) == 0)
-			sam_closeback(session, stream_id, SAM_OK);
-		else if (strncmp(p, "CANT_REACH_PEER", strlen("CANT_REACH_PEER")) == 0)
-			sam_closeback(session, stream_id, SAM_CANT_REACH_PEER);
-		else if (strncmp(p, "I2P_ERROR", strlen("I2P_ERROR")) == 0)
-			sam_closeback(session, stream_id, SAM_I2P_ERROR);
-		else if (strncmp(p, "PEER_NOT_FOUND", strlen("PEER_NOT_FOUND")) == 0)
-			sam_closeback(session, stream_id, SAM_PEER_NOT_FOUND);
-		else if (strncmp(p, "TIMEOUT", strlen("TIMEOUT")) == 0)
-			sam_closeback(session, stream_id, SAM_TIMEOUT);
-		else
-			sam_closeback(session, stream_id, SAM_UNKNOWN);
-
-		return;
-
-	} else if (strncmp(s, SAM_STREAM_CONNECTED_REPLY,
-			strlen(SAM_STREAM_CONNECTED_REPLY)) == 0) {
-		char *p;
-		sam_sid_t stream_id;
-		sam_pubkey_t dest;
-
-		p = strrchr(s, '=');  /* ID= */
-		assert(p != NULL);
-		*p = '\0';
-		p++;
-		stream_id = strtol(p, NULL, 10);
-		assert(stream_id != 0);
-		p = strstr(s, "N=");  /* DESTINATION= */
-		p += 2;
-		strlcpy(dest, p, sizeof dest);
 		sam_connectback(session, stream_id, dest);
-	
-		return;
 
-	} else if (strncmp(s, SAM_STREAM_RECEIVED_REPLY,
-			strlen(SAM_STREAM_RECEIVED_REPLY)) == 0) {
-		char *p;
-		sam_sid_t stream_id;
+	} else if(ARG_IS(1,"RECEIVED")) {
 		size_t size;
 		void *data;
 
-		p = strrchr(s, '=');  /* SIZE= */
-		assert(p != NULL);
-		p++;
-		size = strtol(p, NULL, 10);
-		assert(size != 0);
-		p -= 6;
-		*p = '\0';
-		p = strrchr(s, '=');  /* ID= */
-		assert(p != NULL);
-		p++;
-		stream_id = strtol(p, NULL, 10);
-		assert(stream_id != 0);
-		data = malloc(size + 1);  /* +1 for NUL termination, so when we are
-									receiving a string it will just work and it
-									won't be necessary to send NUL.  When binary
-									data is sent, the extra NUL character will
-									just be ignored by the client program,
-									because it is not added to the size */
+                arg = ARG_FIND("SIZE");
+                assert(arg != NULL);
+                size = strtol_checked(string_data(arg->value));
+
+		data = malloc(size + 1);  
+                /* +1 for NUL termination, so when we are
+                   receiving a string it will just work and it
+                   won't be necessary to send NUL.  When binary
+                   data is sent, the extra NUL character will
+                   just be ignored by the client program,
+                   because it is not added to the size */
 		if (data == NULL) {
 			SAMLOGS("Out of memory");
 			abort();
 		}
 		if (sam_read2(session, data, size) != -1) {
-			p = data + size;
+			char* p = data + size;
 			*p = '\0';  /* see above NUL note */
 			sam_databack(session, stream_id, data, size);
 			/* ^^^ `data' must be freed ^^^*/
 		} else
 			free(data);
 
-		return;
-
-	} else if (strncmp(s, SAM_STREAM_STATUS_REPLY,
-			strlen(SAM_STREAM_STATUS_REPLY)) == 0) {
-		char *p;
-		sam_sid_t stream_id;
-
-		p = strchr(s, '=');  /* can't use strrchar because of option MESSAGE= */
-		assert(p != NULL);  /* RESULT= */
-		p++;
-		p = strchr(p, '=');  /* ID= */
-		assert(p != NULL);
-		p++;
-		stream_id = strtol(p, NULL, 10);
-		assert(stream_id != 0);
-		if (strncmp(s, SAM_STREAM_STATUS_REPLY_OK,
-				strlen(SAM_STREAM_STATUS_REPLY_OK)) == 0)
-			sam_statusback(session, stream_id, SAM_OK);
-		else if (strncmp(s, SAM_STREAM_STATUS_REPLY_CRP,
-				strlen(SAM_STREAM_STATUS_REPLY_CRP)) == 0)
-			sam_statusback(session, stream_id, SAM_CANT_REACH_PEER);
-		else if (strncmp(s, SAM_STREAM_STATUS_REPLY_I2E,
-				strlen(SAM_STREAM_STATUS_REPLY_I2E)) == 0)
-			sam_statusback(session, stream_id, SAM_I2P_ERROR);
-		else if (strncmp(s, SAM_STREAM_STATUS_REPLY_IK,
-				strlen(SAM_STREAM_STATUS_REPLY_IK)) == 0)
-			sam_statusback(session, stream_id, SAM_INVALID_KEY);
-		else if (strncmp(s, SAM_STREAM_STATUS_REPLY_TO,
-				strlen(SAM_STREAM_STATUS_REPLY_TO)) == 0)
-			sam_statusback(session, stream_id, SAM_TIMEOUT);
-		else
-			sam_statusback(session, stream_id, SAM_UNKNOWN);
+	} else if(ARG_IS(1,"STATUS")) {
+            arg = ARG_FIND("RESULT");
+            assert(arg != NULL);
+            if (string_is(arg->value,"OK")) {
+                sam_statusback(session, stream_id, SAM_OK, message);
+            } else if (string_is(arg->value,"CANT_REACH_PEER")) {
+                sam_statusback(session, stream_id, 
+                               SAM_CANT_REACH_PEER, message);
+            } else if (string_is(arg->value,"I2P_ERROR")) {
+                sam_statusback(session, stream_id, SAM_I2P_ERROR, message);
+            } else if (string_is(arg->value,"INVALID_KEY")) {
+                sam_statusback(session, stream_id, SAM_INVALID_KEY, message);
+            } else if (string_is(arg->value,"TIMEOUT")) {
+                sam_statusback(session, stream_id, SAM_TIMEOUT, message);
+            } else {
+                sam_statusback(session, stream_id, SAM_UNKNOWN, message);
+            }
+	}
+    } else
+        return 0;
+    return -1;
+}
 
-		return;
+#undef ARG_IS
+#undef ARG_FIND
 
-	} else
-		SAMLOG("Unknown SAM command received: %s", s);
-
-	return;
-}
 
 /*
  * Sends data to a destination in a raw packet
diff --git a/apps/sam/c/src/tinystring.c b/apps/sam/c/src/tinystring.c
new file mode 100644
index 0000000000000000000000000000000000000000..395a50a88507a77df45fd12098503eee2535bad2
--- /dev/null
+++ b/apps/sam/c/src/tinystring.c
@@ -0,0 +1,128 @@
+#include "tinystring.h"
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <malloc.h>
+#define _GNU_SOURCE
+#include <string.h>
+
+#ifndef min
+#define min(a,b) ((a) > (b) ? (b) : (a))
+#endif
+
+extern char *strndup(const char *s, size_t n);
+
+
+struct string_s {
+    const char* data;
+    long int size;
+    bool _no_del; //SIGH...
+};
+
+string_t string_ncreate(const char* cstr,long int length) {
+    string_t self = malloc(sizeof(struct string_s));
+    self->size = length;
+    if(cstr) self->data = strndup(cstr,length);
+    else self->data = NULL;
+    self->_no_del = 0;
+    return self;
+}
+
+string_t string_create(const char* cstr) {
+    if(!cstr)
+        return string_ncreate(NULL, 0);
+    return string_ncreate(cstr, strlen(cstr));
+}
+
+string_t string_nwrap(const char* cstr, long int length) {
+    static struct string_s self;
+    self.size = length;
+    self.data = cstr;
+    self._no_del = 1;
+    return &self;
+}
+
+string_t string_wrap(const char* cstr) {
+    if(!cstr)
+        return string_nwrap(NULL, 0);
+    return string_nwrap(cstr, strlen(cstr));
+}
+
+string_t string_fmt(const char* fmt, ...) {
+    va_list args;
+    FILE* tmp = tmpfile();
+    string_t self = malloc(sizeof(struct string_s));
+    char* data;
+    va_start(args, fmt);
+    vfprintf(tmp, fmt, args);
+    va_end(args);
+
+    self->size = ftell(tmp);
+
+    rewind(tmp);
+    data = malloc(self->size);
+    fread(data, self->size, sizeof(char), tmp);
+
+    fclose(tmp);
+    self->data = data;
+    return self;
+}
+
+string_t string_cat(string_t head,string_t tail) {
+    //There are two ways to skin a cat...
+    string_t self = malloc(sizeof(struct string_s));
+    char* data;
+    self->size = head->size+tail->size;
+    data = malloc(self->size);
+    memcpy(data, head->data, head->size);
+    memcpy(data+head->size,tail->data,tail->size);
+    self->data = data;
+    return self;
+}
+
+/* Source Dest */
+void string_copy(string_t src,string_t dest) {
+    dest->data = realloc((char*)dest->data,src->size);
+    memcpy((char*)dest->data,src->data,dest->size);
+}
+
+void string_copy_raw(string_t src, void* dest,size_t size) {
+    size = min(src->size,size);
+    memcpy(dest,src->data,size);
+}
+
+const char* string_data(string_t self) {
+    return self->data;
+}
+
+long int string_size(string_t self) {
+    return self->size;
+}
+
+void string_free(string_t self) {
+    if(!self->_no_del)
+        free((char*)self->data);
+
+    free(self);
+}
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+bool string_equal(string_t this,string_t that) {
+    return !memcmp(this->data,that->data,min(this->size,that->size));
+}
+
+bool string_equali(string_t this,string_t that) {
+    return !strncasecmp(this->data,that->data,min(this->size,that->size));
+}
+
+int string_cmp(string_t this,string_t that) {
+    return memcmp(this->data,that->data,min(this->size,that->size));
+}
+
+int string_cmpi(string_t this,string_t that) {
+    return strncasecmp(this->data,that->data,min(this->size,that->size));
+}
diff --git a/apps/sam/c/status b/apps/sam/c/status
new file mode 100644
index 0000000000000000000000000000000000000000..519f653d1c6097bf71e81be06c13500bf4d49201
--- /dev/null
+++ b/apps/sam/c/status
@@ -0,0 +1,4 @@
+#!/usr/bin/env perl
+
+printf "%-8s ",uc(shift @ARGV);
+print join(' ', @ARGV),"\n";