Index: protocols/twitter/twitter_lib.c
===================================================================
--- protocols/twitter/twitter_lib.c	(revision f81d8b84296c11c0a5a7f2727f3cd8c80178a76a)
+++ protocols/twitter/twitter_lib.c	(revision 1201fcb6272cdba734594f9358ba2d08db1afec9)
@@ -36,5 +36,5 @@
 #include "base64.h"
 #include "twitter_lib.h"
-#include "parson.h"
+#include "json_util.h"
 #include <ctype.h>
 #include <errno.h>
@@ -64,8 +64,4 @@
 	gboolean from_filter;
 };
-
-#define JSON_O_FOREACH(o, k, v) \
-    const char *k; const JSON_Value *v; int __i; \
-    for (__i = 0; json_object_get_tuple(o, __i, &k, &v); __i++)
 
 /**
@@ -170,5 +166,5 @@
 {
 	static char *ret = NULL;
-	JSON_Value *root, *err;
+	json_value *root, *err;
 
 	g_free(ret);
@@ -176,10 +172,9 @@
 
 	if (req->body_size > 0) {
-		root = json_parse_string(req->reply_body);
-		err = json_object_get_value(json_object(root), "errors");
-		if (err && json_type(err) == JSONArray &&
-		    (err = json_array_get_value(json_array(err), 0)) &&
-		    json_type(err) == JSONObject) {
-			const char *msg = json_object_get_string(json_object(err), "message");
+		root = json_parse(req->reply_body, req->body_size);
+		err = json_o_get(root, "errors");
+		if (err && err->type == json_array && (err = err->u.array.values[0]) &&
+		    err->type == json_object) {
+			const char *msg = json_o_str(err, "message");
 			if (msg) {
 				ret = g_strdup_printf("%s (%s)", req->status_string, msg);
@@ -194,10 +189,10 @@
 /* WATCH OUT: This function might or might not destroy your connection.
    Sub-optimal indeed, but just be careful when this returns NULL! */
-static JSON_Value *twitter_parse_response(struct im_connection *ic, struct http_request *req)
+static json_value *twitter_parse_response(struct im_connection *ic, struct http_request *req)
 {
 	gboolean logging_in = !(ic->flags & OPT_LOGGED_IN);
 	gboolean periodic;
 	struct twitter_data *td = ic->proto_data;
-	JSON_Value *ret;
+	json_value *ret;
 	char path[64] = "", *s;
 
@@ -237,5 +232,5 @@
 	}
 
-	if ((ret = json_parse_string(req->reply_body)) == NULL) {
+	if ((ret = json_parse(req->reply_body, req->body_size)) == NULL) {
 		imcb_error(ic, "Could not retrieve %s: %s",
 		           path, "XML parse error");
@@ -264,7 +259,7 @@
  * Fill a list of ids.
  */
-static gboolean twitter_xt_get_friends_id_list(JSON_Value *node, struct twitter_xml_list *txl)
-{
-	JSON_Array *c;
+static gboolean twitter_xt_get_friends_id_list(json_value *node, struct twitter_xml_list *txl)
+{
+	json_value *c;
 	int i;
 
@@ -272,18 +267,21 @@
 	txl->type = TXL_ID;
 
-	if (!(c = json_object_get_array(json_object(node), "ids"))) {
+	c = json_o_get(node, "ids");
+	if (!c || c->type != json_array) {
 		return FALSE;
 	}
 
-	for (i = 0; i < json_array_get_count(c); i++) {
-		jint id = json_array_get_integer(c, i);
+	for (i = 0; i < c->u.array.length; i++) {
+		if (c->u.array.values[i]->type != json_integer) {
+			continue;
+		}
 
 		txl->list = g_slist_prepend(txl->list,
-		                            g_strdup_printf("%lld", id));
-	}
-
-	JSON_Value *next = json_object_get_value(json_object(node), "next_cursor");
-	if (next && json_type(next) == JSONInteger) {
-		txl->next_cursor = json_integer(next);
+		                            g_strdup_printf("%" PRIu64, c->u.array.values[i]->u.integer));
+	}
+
+	c = json_o_get(node, "next_cursor");
+	if (c && c->type == json_integer) {
+		txl->next_cursor = c->u.integer;
 	} else {
 		txl->next_cursor = -1;
@@ -301,5 +299,5 @@
 {
 	struct im_connection *ic;
-	JSON_Value *parsed;
+	json_value *parsed;
 	struct twitter_xml_list *txl;
 	struct twitter_data *td;
@@ -339,5 +337,5 @@
 }
 
-static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl);
+static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl);
 static void twitter_http_get_users_lookup(struct http_request *req);
 
@@ -380,5 +378,5 @@
 {
 	struct im_connection *ic = req->data;
-	JSON_Value *parsed;
+	json_value *parsed;
 	struct twitter_xml_list *txl;
 	GSList *l = NULL;
@@ -412,15 +410,15 @@
 }
 
-struct twitter_xml_user *twitter_xt_get_user(const JSON_Object *node)
+struct twitter_xml_user *twitter_xt_get_user(const json_value *node)
 {
 	struct twitter_xml_user *txu;
-	
-	if (!node)
-		return NULL;
+	json_value *jv;
 
 	txu = g_new0(struct twitter_xml_user, 1);
-	txu->name = g_strdup(json_object_get_string(node, "name"));
-	txu->screen_name = g_strdup(json_object_get_string(node, "screen_name"));
-	txu->uid = json_object_get_integer(node, "id");
+	txu->name = g_strdup(json_o_str(node, "name"));
+	txu->screen_name = g_strdup(json_o_str(node, "screen_name"));
+
+	jv = json_o_get(node, "id");
+	txu->uid = jv->u.integer;
 
 	return txu;
@@ -432,5 +430,5 @@
  *  - all <user>s from the <users> element.
  */
-static gboolean twitter_xt_get_users(JSON_Value *node, struct twitter_xml_list *txl)
+static gboolean twitter_xt_get_users(json_value *node, struct twitter_xml_list *txl)
 {
 	struct twitter_xml_user *txu;
@@ -440,16 +438,12 @@
 	txl->type = TXL_USER;
 
-	if (json_type(node) != JSONArray) {
+	if (!node || node->type != json_array) {
 		return FALSE;
 	}
-	
+
 	// The root <users> node should hold the list of users <user>
 	// Walk over the nodes children.
-	JSON_Array *arr = json_array(node);
-	for (i = 0; i < json_array_get_count(arr); i++) {
-		JSON_Object *o = json_array_get_object(arr, i);
-		if (!o)
-			continue;
-		txu = twitter_xt_get_user(o);
+	for (i = 0; i < node->u.array.length; i++) {
+		txu = twitter_xt_get_user(node->u.array.values[i]);
 		if (txu) {
 			txl->list = g_slist_prepend(txl->list, txu);
@@ -466,5 +460,5 @@
 #endif
 
-static void expand_entities(char **text, const JSON_Object *node);
+static void expand_entities(char **text, const json_value *node);
 
 /**
@@ -476,10 +470,10 @@
  *  - the user in a twitter_xml_user struct.
  */
-static struct twitter_xml_status *twitter_xt_get_status(const JSON_Object *node)
+static struct twitter_xml_status *twitter_xt_get_status(const json_value *node)
 {
 	struct twitter_xml_status *txs;
-	const JSON_Object *rt = NULL;
-
-	if (!node) {
+	const json_value *rt = NULL;
+
+	if (node->type != json_object) {
 		return FALSE;
 	}
@@ -487,10 +481,10 @@
 
 	JSON_O_FOREACH(node, k, v) {
-		if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) {
-			// TODO: Huh strip html? In json? Not sure whether I have to..
+		if (strcmp("text", k) == 0 && v->type == json_string) {
+			txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
 			strip_html(txs->text);
-		} else if (strcmp("retweeted_status", k) == 0 && (rt = json_object(v))) {
-			// Handling below.
-		} else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
+		} else if (strcmp("retweeted_status", k) == 0 && v->type == json_object) {
+			rt = v;
+		} else if (strcmp("created_at", k) == 0 && v->type == json_string) {
 			struct tm parsed;
 
@@ -498,13 +492,13 @@
 			   this field. :-( Also assumes the timezone used
 			   is UTC since C time handling functions suck. */
-			if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
+			if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
 				txs->created_at = mktime_utc(&parsed);
 			}
-		} else if (strcmp("user", k) == 0 && json_type(v) == JSONObject) {
-			txs->user = twitter_xt_get_user(json_object(v));
-		} else if (strcmp("id", k) == 0 && json_type(v) == JSONInteger) {
-			txs->rt_id = txs->id = json_integer(v);
-		} else if (strcmp("in_reply_to_status_id", k) == 0 && json_type(v) == JSONInteger) {
-			txs->reply_to = json_integer(v);
+		} else if (strcmp("user", k) == 0 && v->type == json_object) {
+			txs->user = twitter_xt_get_user(v);
+		} else if (strcmp("id", k) == 0 && v->type == json_integer) {
+			txs->rt_id = txs->id = v->u.integer;
+		} else if (strcmp("in_reply_to_status_id", k) == 0 && v->type == json_integer) {
+			txs->reply_to = v->u.integer;
 		}
 	}
@@ -535,9 +529,9 @@
  * Function to fill a twitter_xml_status struct (DM variant).
  */
-static struct twitter_xml_status *twitter_xt_get_dm(const JSON_Object *node)
+static struct twitter_xml_status *twitter_xt_get_dm(const json_value *node)
 {
 	struct twitter_xml_status *txs;
 
-	if (!node) {
+	if (node->type != json_object) {
 		return FALSE;
 	}
@@ -545,7 +539,8 @@
 
 	JSON_O_FOREACH(node, k, v) {
-		if (strcmp("text", k) == 0 && (txs->text = g_strdup(json_string(v)))) {
+		if (strcmp("text", k) == 0 && v->type == json_string) {
+			txs->text = g_memdup(v->u.string.ptr, v->u.string.length + 1);
 			strip_html(txs->text);
-		} else if (strcmp("created_at", k) == 0 && json_type(v) == JSONString) {
+		} else if (strcmp("created_at", k) == 0 && v->type == json_string) {
 			struct tm parsed;
 
@@ -553,11 +548,11 @@
 			   this field. :-( Also assumes the timezone used
 			   is UTC since C time handling functions suck. */
-			if (strptime(json_string(v), TWITTER_TIME_FORMAT, &parsed) != NULL) {
+			if (strptime(v->u.string.ptr, TWITTER_TIME_FORMAT, &parsed) != NULL) {
 				txs->created_at = mktime_utc(&parsed);
 			}
-		} else if (strcmp("sender", k) == 0 && json_type(v) == JSONObject) {
-			txs->user = twitter_xt_get_user(json_object(v));
-		} else if (strcmp("id", k) == 0 && json_type(v) == JSONInteger) {
-			txs->id = json_integer(v);
+		} else if (strcmp("sender", k) == 0 && v->type == json_object) {
+			txs->user = twitter_xt_get_user(v);
+		} else if (strcmp("id", k) == 0 && v->type == json_integer) {
+			txs->id = v->u.integer;
 		}
 	}
@@ -573,12 +568,12 @@
 }
 
-static void expand_entities(char **text, const JSON_Object *node)
-{
-	JSON_Object *entities, *quoted;
+static void expand_entities(char **text, const json_value *node)
+{
+	json_value *entities, *quoted;
 	char *quote_url = NULL, *quote_text = NULL;
 
-	if (!(entities = json_object_get_object(node, "entities")))
-		return;
-	if ((quoted = json_object_get_object(node, "quoted_status"))) {
+	if (!((entities = json_o_get(node, "entities")) && entities->type == json_object))
+		return;
+	if ((quoted = json_o_get(node, "quoted_status")) && quoted->type == json_object) {
 		/* New "retweets with comments" feature. Note that this info
 		 * seems to be included in the streaming API only! Grab the
@@ -596,5 +591,5 @@
 		int i;
 
-		if (json_type(v) != JSONArray) {
+		if (v->type != json_array) {
 			continue;
 		}
@@ -603,15 +598,14 @@
 		}
 
-		for (i = 0; i < json_array_get_count(json_array(v)); i++) {
+		for (i = 0; i < v->u.array.length; i++) {
 			const char *format = "%s%s <%s>%s";
-			JSON_Object *r = json_array_get_object(json_array(v), i);
-
-			if (!r) {
+
+			if (v->u.array.values[i]->type != json_object) {
 				continue;
 			}
 
-			const char *kort = json_object_get_string(r, "url");
-			const char *disp = json_object_get_string(r, "display_url");
-			const char *full = json_object_get_string(r, "expanded_url");
+			const char *kort = json_o_str(v->u.array.values[i], "url");
+			const char *disp = json_o_str(v->u.array.values[i], "display_url");
+			const char *full = json_o_str(v->u.array.values[i], "expanded_url");
 			char *pos, *new;
 
@@ -642,5 +636,5 @@
  *  - the next_cursor.
  */
-static gboolean twitter_xt_get_status_list(struct im_connection *ic, const JSON_Value *node,
+static gboolean twitter_xt_get_status_list(struct im_connection *ic, const json_value *node,
                                            struct twitter_xml_list *txl)
 {
@@ -651,5 +645,5 @@
 	txl->type = TXL_STATUS;
 
-	if (json_type(node) != JSONArray) {
+	if (node->type != json_array) {
 		return FALSE;
 	}
@@ -657,6 +651,6 @@
 	// The root <statuses> node should hold the list of statuses <status>
 	// Walk over the nodes children.
-	for (i = 0; i < json_array_get_count(json_array(node)); i++) {
-		txs = twitter_xt_get_status(json_array_get_object(json_array(node), i));
+	for (i = 0; i < node->u.array.length; i++) {
+		txs = twitter_xt_get_status(node->u.array.values[i]);
 		if (!txs) {
 			continue;
@@ -864,5 +858,5 @@
 }
 
-static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter);
+static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter);
 
 static void twitter_http_stream(struct http_request *req)
@@ -870,5 +864,5 @@
 	struct im_connection *ic = req->data;
 	struct twitter_data *td;
-	JSON_Value *parsed;
+	json_value *parsed;
 	int len = 0;
 	char c, *nl;
@@ -908,7 +902,7 @@
 		req->reply_body[len] = '\0';
 
-		if ((parsed = json_parse_string(req->reply_body))) {
+		if ((parsed = json_parse(req->reply_body, req->body_size))) {
 			from_filter = (req == td->filter_stream);
-			twitter_stream_handle_object(ic, json_object(parsed), from_filter);
+			twitter_stream_handle_object(ic, parsed, from_filter);
 		}
 		json_value_free(parsed);
@@ -924,12 +918,12 @@
 }
 
-static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o);
+static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o);
 static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs);
 
-static gboolean twitter_stream_handle_object(struct im_connection *ic, JSON_Object *o, gboolean from_filter)
+static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o, gboolean from_filter)
 {
 	struct twitter_data *td = ic->proto_data;
 	struct twitter_xml_status *txs;
-	JSON_Object *c;
+	json_value *c;
 
 	if ((txs = twitter_xt_get_status(o))) {
@@ -938,5 +932,5 @@
 		txs_free(txs);
 		return ret;
-	} else if ((c = json_object_get_object(o, "direct_message")) &&
+	} else if ((c = json_o_get(o, "direct_message")) &&
 	           (txs = twitter_xt_get_dm(c))) {
 		if (g_strcasecmp(txs->user->screen_name, td->user) != 0) {
@@ -946,12 +940,12 @@
 		txs_free(txs);
 		return TRUE;
-	} else if (json_object_get_string(o, "event")) {
+	} else if ((c = json_o_get(o, "event")) && c->type == json_string) {
 		twitter_stream_handle_event(ic, o);
 		return TRUE;
-	} else if ((c = json_object_get_object(o, "disconnect"))) {
+	} else if ((c = json_o_get(o, "disconnect")) && c->type == json_object) {
 		/* HACK: Because we're inside an event handler, we can't just
 		   disconnect here. Instead, just change the HTTP status string
 		   into a Twitter status string. */
-		char *reason = g_strdup(json_object_get_string(c, "reason"));
+		char *reason = json_o_strdup(c, "reason");
 		if (reason) {
 			g_free(td->stream->status_string);
@@ -992,12 +986,13 @@
 }
 
-static gboolean twitter_stream_handle_event(struct im_connection *ic, JSON_Object *o)
-{
-	struct twitter_data *td = ic->proto_data;
-	JSON_Object *source = json_object_get_object(o, "source");
-	JSON_Object *target = json_object_get_object(o, "target");
-	const char *type = json_object_get_string(o, "event");
-
-	if (!type || !source || !target) {
+static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value *o)
+{
+	struct twitter_data *td = ic->proto_data;
+	json_value *source = json_o_get(o, "source");
+	json_value *target = json_o_get(o, "target");
+	const char *type = json_o_str(o, "event");
+
+	if (!type || !source || source->type != json_object
+	    || !target || target->type != json_object) {
 		return FALSE;
 	}
@@ -1096,5 +1091,7 @@
 	struct twitter_filter *tf;
 	GList *users = NULL;
-	JSON_Value *parsed;
+	json_value *parsed;
+	json_value *id;
+	const char *name;
 	GString *fstr;
 	GSList *l;
@@ -1121,14 +1118,13 @@
 	}
 
-	if (json_type(parsed) != JSONArray) {
+	if (parsed->type != json_array) {
 		goto finish;
 	}
 
-	for (i = 0; i < json_array_get_count(json_array(parsed)); i++) {
-		JSON_Object *o = json_array_get_object(json_array(parsed), i);
-		jint id = json_object_get_integer(o, "id");
-		const char *name = json_object_get_string(o, "screen_name");
-
-		if (!name || !id) {
+	for (i = 0; i < parsed->u.array.length; i++) {
+		id = json_o_get(parsed->u.array.values[i], "id");
+		name = json_o_str(parsed->u.array.values[i], "screen_name");
+
+		if (!name || !id || id->type != json_integer) {
 			continue;
 		}
@@ -1138,5 +1134,5 @@
 
 			if (g_strcasecmp(tf->text, name) == 0) {
-				tf->uid = id;
+				tf->uid = id->u.integer;
 				users = g_list_delete_link(users, u);
 				break;
@@ -1379,5 +1375,5 @@
 	struct im_connection *ic = req->data;
 	struct twitter_data *td;
-	JSON_Value *parsed;
+	json_value *parsed;
 	struct twitter_xml_list *txl;
 
@@ -1418,5 +1414,5 @@
 	struct im_connection *ic = req->data;
 	struct twitter_data *td;
-	JSON_Value *parsed;
+	json_value *parsed;
 	struct twitter_xml_list *txl;
 
@@ -1458,6 +1454,5 @@
 	struct im_connection *ic = req->data;
 	struct twitter_data *td;
-	JSON_Value *parsed;
-	jint id;
+	json_value *parsed, *id;
 
 	// Check if the connection is still active.
@@ -1473,6 +1468,6 @@
 	}
 
-	if ((id = json_object_get_integer(json_object(parsed), "id"))) {
-		td->last_status_id = id;
+	if ((id = json_o_get(parsed, "id")) && id->type == json_integer) {
+		td->last_status_id = id->u.integer;
 	}
 
@@ -1578,2 +1573,41 @@
 	g_free(args[1]);
 }
+
+static void twitter_http_status_show_url(struct http_request *req)
+{
+	struct im_connection *ic = req->data;
+	json_value *parsed, *id;
+	const char *name;
+
+	// Check if the connection is still active.
+	if (!g_slist_find(twitter_connections, ic)) {
+		return;
+	}
+
+	if (!(parsed = twitter_parse_response(ic, req))) {
+		return;
+	}
+
+	/* for the parson branch:
+	name = json_object_dotget_string(json_object(parsed), "user.screen_name");
+	id = json_object_get_integer(json_object(parsed), "id");
+	*/
+
+	name = json_o_str(json_o_get(parsed, "user"), "screen_name");
+	id = json_o_get(parsed, "id");
+
+	if (name && id && id->type == json_integer) {
+		twitter_log(ic, "https://twitter.com/%s/status/%" G_GUINT64_FORMAT, name, id->u.integer);
+	} else {
+		twitter_log(ic, "Error: could not fetch tweet url.");
+	}
+
+	json_value_free(parsed);
+}
+
+void twitter_status_show_url(struct im_connection *ic, guint64 id)
+{
+	char *url = g_strdup_printf("%s%" G_GUINT64_FORMAT "%s", TWITTER_STATUS_SHOW_URL, id, ".json");
+	twitter_http(ic, url, twitter_http_status_show_url, ic, 0, NULL, 0);
+	g_free(url);
+}
