Index: protocols/rpc/rpc.c
===================================================================
--- protocols/rpc/rpc.c	(revision 66aefeb3192e3afb906d88e5361508b6c7131d63)
+++ protocols/rpc/rpc.c	(revision 9ae7332ed056b6828775b74698bd55f815120413)
@@ -118,5 +118,6 @@
 static void rpc_logout(struct im_connection *ic) {
 	RPC_OUT_INIT("logout");
-	rpc_send(ic, rpc);
+	if (!rpc_send(ic, rpc))
+		return;
 
 	struct rpc_connection *rd = ic->proto_data;
@@ -133,7 +134,5 @@
 	json_array_append_string(params, message);
 	json_array_append_number(params, flags);
-	rpc_send(ic, rpc);
-
-	return 1; // BOGUS
+	return rpc_send(ic, rpc);
 }
 
@@ -149,7 +148,5 @@
 	json_array_append_string(params, who);
 	json_array_append_number(params, flags);
-	rpc_send(ic, rpc);
-
-	return 1; // BOGUS
+	return rpc_send(ic, rpc);
 }
 
@@ -237,5 +234,5 @@
 	rc->id = next_rpc_id;
 	rc->gc = gc;
-	return gc;
+	return gc;  // TODO: RETVAL HERE AND BELOW
 }
 
@@ -248,5 +245,5 @@
 	rpc_send(ic, rpc);
 
-	return NULL;
+	return gc; 
 }
 
@@ -263,5 +260,5 @@
 	rpc_send(ic, rpc);
 
-	return NULL;
+	return gc;
 }
 
@@ -274,9 +271,7 @@
 }
 
-static void rpc_cmd_in(const char *cmd, JSON_Array *params) {
-
-}
-
-static void rpc_in(struct im_connection *ic, JSON_Object *rpc) {
+static gboolean rpc_cmd_in(struct im_connection *ic, const char *cmd, JSON_Array *params);
+
+static gboolean rpc_in(struct im_connection *ic, JSON_Object *rpc) {
 	JSON_Object *res = json_object_get_object(rpc, "result");
 	const char *cmd = json_object_get_string(rpc, "method");
@@ -287,11 +282,19 @@
 		imcb_log(ic, "Received invalid JSON-RPC object.");
 		imc_logout(ic, TRUE);
-		return;
+		return FALSE;
 	}
 
 	if (res) {
 		// handle response. I think I mostly won't.
+		return TRUE;
 	} else {
-		rpc_cmd_in(cmd, params);
+		gboolean st = rpc_cmd_in(ic, cmd, params);
+		JSON_Value *resp = json_value_init_object();
+		json_object_set_value(json_object(resp), "id", json_value_deep_copy(id));
+		if (st)
+			json_object_set_value(json_object(resp), "result", json_value_init_object());
+		else
+			json_object_set_value(json_object(resp), "error", json_value_init_object());
+		return rpc_send(ic, resp);
 	}
 }
@@ -306,7 +309,8 @@
 		rd->buf = g_realloc(rd->buf, rd->buflen + st + 1);
 		memcpy(rd->buf + rd->buflen, buf, st);
-	}
-
-	if (st == 0 || (st == -1 && !sockerr_again())) {
+		rd->buflen += st;
+	}
+
+	if (st == 0 || (st == -1 && !(sockerr_again() || errno == EAGAIN))) {
 		imcb_log(ic, "Read error");
 		imc_logout(ic, TRUE);
@@ -318,6 +322,9 @@
 	const char *end;
 	while ((parsed = json_parse_first(rd->buf, &end))) {
-		rpc_in(ic, json_object(parsed));
+		st = rpc_in(ic, json_object(parsed));
 		json_value_free(parsed);
+
+		if (!st)
+			return FALSE;
 
 		if (end == rd->buf + rd->buflen) {
@@ -330,4 +337,5 @@
 			rd->buf = g_realloc(rd->buf, newlen + 1);
 			memcpy(rd->buf, new, newlen);
+			rd->buflen = newlen;
 			rd->buf[rd->buflen] = '\0';
 		}
@@ -337,15 +345,113 @@
 }
 
-static void rpc_imcb_buddy_typing(struct im_connection *ic, const char *cmd, JSON_Array *params) {
-	const char *handle = json_array_get_string(params, 0);
-	int flags = json_array_get_number(params, 1);
-	imcb_buddy_typing(ic, handle, flags);
+static void rpc_imcb_log(struct im_connection *ic, void *func_, JSON_Array *params) {
+	void (*func)(struct im_connection*, char*, ...) = func_;
+	func(ic, "%s", json_array_get_string(params, 0));
+}
+
+static void rpc_imcb_connected(struct im_connection *ic, void *func_, JSON_Array *params) {
+	void (*func)(struct im_connection*) = func_;
+	func(ic);
+}
+
+static void rpc_imc_logout(struct im_connection *ic, void *func_, JSON_Array *params) {
+	void (*func)(struct im_connection*, gboolean) = func_;
+	func(ic, json_array_get_boolean(params, 0));
+}
+
+static void rpc_imcb_add_buddy(struct im_connection *ic, void *func_, JSON_Array *params) {
+	void (*func)(struct im_connection*, const char*, const char*) = func_;
+	func(ic, json_array_get_string(params, 0), json_array_get_string(params, 1));
+}
+
+static void rpc_imcb_buddy_status(struct im_connection *ic, void *func_, JSON_Array *params) {
+	void (*func)(struct im_connection*, const char*, int, const char*, const char*) = func_;
+	func(ic, json_array_get_string(params, 0), json_array_get_number(params, 1),
+	         json_array_get_string(params, 2), json_array_get_string(params, 3));
+}
+
+static void rpc_imcb_buddy_times(struct im_connection *ic, void *func_, JSON_Array *params) {
+	void (*func)(struct im_connection*, const char*, int, int) = func_;
+	func(ic, json_array_get_string(params, 0), json_array_get_number(params, 1),
+	         json_array_get_number(params, 2));
+}
+
+static void rpc_imcb_buddy_msg(struct im_connection *ic, void *func_, JSON_Array *params) {
+	void (*func)(struct im_connection*, const char*, const char*, int, int) = func_;
+	func(ic, json_array_get_string(params, 0), json_array_get_string(params, 1),
+	         json_array_get_number(params, 2), json_array_get_number(params, 3));
+}
+
+static void rpc_imcb_buddy_typing(struct im_connection *ic, void *func_, JSON_Array *params) {
+	void (*func)(struct im_connection*, char*, int) = func_;
+	func(ic, (char*) json_array_get_string(params, 0), json_array_get_number(params, 1));
 }
 
 struct rpc_in_method {
 	char *name;
-	void (* func) (struct im_connection *ic, const char *cmd, JSON_Array *params);
-	char *args;
+	void *func;
+	void (* wfunc) (struct im_connection *ic, void *cmd, JSON_Array *params);
+	char args[8];
 };
+
+static const struct rpc_in_method methods[] = {
+	{ "imcb_log", imcb_log, rpc_imcb_log, "s" },
+	{ "imcb_error", imcb_error, rpc_imcb_log, "s" },
+	{ "imcb_connected", imcb_connected, rpc_imcb_connected, "" },
+	{ "imc_logout", imc_logout, rpc_imc_logout, "b" },
+	{ "imcb_add_buddy", imcb_add_buddy, rpc_imcb_add_buddy, "ss" },
+	{ "imcb_remove_buddy", imcb_remove_buddy, rpc_imcb_add_buddy, "ss" },
+	{ "imcb_rename_buddy", imcb_rename_buddy, rpc_imcb_add_buddy, "ss" },
+	{ "imcb_buddy_nick_hint", imcb_buddy_nick_hint, rpc_imcb_add_buddy, "ss" },
+	{ "imcb_buddy_status", imcb_buddy_status, rpc_imcb_buddy_status, "snss" },
+	{ "imcb_buddy_status_msg", imcb_buddy_status_msg, rpc_imcb_add_buddy, "ss" },
+	{ "imcb_buddy_times", imcb_buddy_times, rpc_imcb_buddy_times, "snn" },
+	{ "imcb_buddy_msg", imcb_buddy_msg, rpc_imcb_buddy_msg, "ssnn" },
+	{ "imcb_buddy_typing", imcb_buddy_typing, rpc_imcb_buddy_typing, "sn" },
+	{ NULL },
+};
+
+static gboolean rpc_cmd_in(struct im_connection *ic, const char *cmd, JSON_Array *params) {
+	int i;
+
+	for (i = 0; methods[i].name; i++) {
+		if (strcmp(cmd, methods[i].name) == 0) {
+			if (json_array_get_count(params) != strlen(methods[i].args)) {
+				imcb_error(ic, "Invalid argument count to method %s: %d, wanted %zd", cmd, (int) json_array_get_count(params), strlen(methods[i].args));
+				return FALSE;
+			}
+			int j;
+			for (j = 0; methods[i].args[j]; j++) {
+				JSON_Value_Type type = json_value_get_type(json_array_get_value(params, j));
+				gboolean ok = FALSE;
+				switch (methods[i].args[j]) {
+				case 's':
+					ok = type == JSONString;
+					break;
+				case 'n':
+					ok = type == JSONNumber;
+					break;
+				case 'o':
+					ok = type == JSONObject;
+					break;
+				case 'a':
+					ok = type == JSONArray;
+					break;
+				case 'b':
+					ok = type == JSONBoolean;
+					break;
+				}
+				if (!ok) {
+					// This error sucks, but just get your types right!
+					imcb_error(ic, "Invalid argument type, %s parameter %d: %d not %c", cmd, j, type, methods[i].args[j]);
+					return FALSE;
+				}
+			}
+			methods[i].wfunc(ic, methods[i].func, params);
+			return TRUE;
+		}
+	}
+	return FALSE;
+}
 
 #define RPC_ADD_FUNC(func) \
