Index: protocols/twitter/twitter.c
===================================================================
--- protocols/twitter/twitter.c	(revision 5983eca9ac1187eb1407eece7d7ad72ef5e091b0)
+++ protocols/twitter/twitter.c	(revision de923d59e15bb650c2cb98a6254c79aa7c6af96e)
@@ -83,5 +83,6 @@
 		 !(td->flags & TWITTER_HAVE_FRIENDS)) {
 		imcb_log(ic, "Getting contact list");
-		twitter_get_statuses_friends(ic, -1);
+		twitter_get_friends_ids(ic, -1);
+		//twitter_get_statuses_friends(ic, -1);
 	} else
 		twitter_main_loop_start(ic);
@@ -168,4 +169,6 @@
 					 "instead of %s.", sn, ic->acc->user);
 			}
+			g_free(td->user);
+			td->user = g_strdup(sn);
 		}
 
@@ -257,4 +260,5 @@
 	td = g_new0(struct twitter_data, 1);
 	ic->proto_data = td;
+	td->user = g_strdup(acc->user);
 
 	td->url_ssl = url.proto == PROTO_HTTPS;
@@ -270,6 +274,4 @@
 		td->prefix = g_strdup(url.host);
 
-	td->flags |= TWITTER_HAVE_FRIENDS;
-	td->user = acc->user;
 	if (strstr(acc->pass, "oauth_token="))
 		td->oauth_info = oauth_from_string(acc->pass, get_oauth_service(ic));
@@ -305,8 +307,8 @@
 	if (td) {
 		oauth_info_free(td->oauth_info);
+		g_free(td->user);
 		g_free(td->prefix);
 		g_free(td->url_host);
 		g_free(td->url_path);
-		g_free(td->pass);
 		g_free(td->log);
 		g_free(td);
Index: protocols/twitter/twitter.h
===================================================================
--- protocols/twitter/twitter.h	(revision 5983eca9ac1187eb1407eece7d7ad72ef5e091b0)
+++ protocols/twitter/twitter.h	(revision de923d59e15bb650c2cb98a6254c79aa7c6af96e)
@@ -43,6 +43,7 @@
 {
 	char* user;
-	char* pass;
 	struct oauth_info *oauth_info;
+	GSList *follow_ids;
+	
 	guint64 home_timeline_id;
 	guint64 last_status_id; /* For undo */
@@ -52,4 +53,5 @@
 	twitter_flags_t flags;
 	
+	/* set base_url */
 	gboolean url_ssl;
 	int url_port;
@@ -59,4 +61,5 @@
 	char *prefix; /* Used to generate contact + channel name. */
 	
+	/* set show_ids */
 	struct twitter_log_data *log;
 	int log_id;
Index: protocols/twitter/twitter_lib.c
===================================================================
--- protocols/twitter/twitter_lib.c	(revision 5983eca9ac1187eb1407eece7d7ad72ef5e091b0)
+++ protocols/twitter/twitter_lib.c	(revision de923d59e15bb650c2cb98a6254c79aa7c6af96e)
@@ -55,5 +55,4 @@
 	gint64 next_cursor;
 	GSList *list;
-	gpointer data;
 };
 
@@ -109,4 +108,6 @@
 		else if (txl->type == TXL_ID)
 			g_free(l->data);
+		else if (txl->type == TXL_USER)
+			txu_free(l->data);
 	g_slist_free(txl->list);
 	g_free(txl);
@@ -120,5 +121,5 @@
 	struct twitter_data *td = ic->proto_data;
 
-	// Check if the buddy is allready in the buddy list.
+	// Check if the buddy is already in the buddy list.
 	if (!bee_user_by_handle(ic->bee, ic, name)) {
 		char *mode = set_getstr(&ic->acc->set, "mode");
@@ -138,5 +139,5 @@
 
 /* Warning: May return a malloc()ed value, which will be free()d on the next
-   call. Only for short-term use. */
+   call. Only for short-term use. NOT THREADSAFE!  */
 char *twitter_parse_error(struct http_request *req)
 {
@@ -151,9 +152,10 @@
 		xp = xt_new(NULL, NULL);
 		xt_feed(xp, req->reply_body, req->body_size);
-
-		if ((node = xt_find_node(xp->root, "hash")) &&
-		    (node = xt_find_node(node->children, "error")) && node->text_len > 0) {
-			ret = g_strdup_printf("%s (%s)", req->status_string, node->text);
-		}
+		
+		for (node = xp->root; node; node = node->next)
+			if ((node = xt_find_node(node->children, "error")) && node->text_len > 0) {
+				ret = g_strdup_printf("%s (%s)", req->status_string, node->text);
+				break;
+			}
 
 		xt_free(xp);
@@ -207,8 +209,10 @@
 	// Walk over the nodes children.
 	for (child = node->children; child; child = child->next) {
-		if (g_strcasecmp("id", child->name) == 0) {
-			// Add the item to the list.
-			txl->list =
-			    g_slist_append(txl->list, g_memdup(child->text, child->text_len + 1));
+		if (g_strcasecmp("ids", child->name) == 0) {
+			struct xt_node *idc;
+			for (idc = child->children; idc; idc = idc->next)
+				if (g_strcasecmp(idc->name, "id") == 0)
+					txl->list = g_slist_prepend(txl->list,
+						g_memdup(idc->text, idc->text_len + 1));
 		} else if (g_strcasecmp("next_cursor", child->name) == 0) {
 			twitter_xt_next_cursor(child, txl);
@@ -218,4 +222,6 @@
 	return XT_HANDLED;
 }
+
+static void twitter_get_users_lookup(struct im_connection *ic);
 
 /**
@@ -237,10 +243,15 @@
 	td = ic->proto_data;
 
-	// Check if the HTTP request went well.
-	if (req->status_code != 200) {
+	// Check if the HTTP request went well. More strict checks as this is
+	// the first request we do in a session.
+	if (req->status_code == 401) {
+		imcb_error(ic, "Authentication failure");
+		imc_logout(ic, FALSE);
+		return;
+	} else if (req->status_code != 200) {
 		// It didn't go well, output the error and return.
-		if (++td->http_fails >= 5)
-			imcb_error(ic, "Could not retrieve friends: %s", twitter_parse_error(req));
-
+		imcb_error(ic, "Could not retrieve %s: %s",
+			   TWITTER_FRIENDS_IDS_URL, twitter_parse_error(req));
+		imc_logout(ic, TRUE);
 		return;
 	} else {
@@ -248,5 +259,10 @@
 	}
 
+	/* Create the room now that we "logged in". */
+	if (!td->home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
+		twitter_groupchat_init(ic);
+
 	txl = g_new0(struct twitter_xml_list, 1);
+	txl->list = td->follow_ids;
 
 	// Parse the data.
@@ -256,8 +272,101 @@
 	xt_free(parser);
 
+	td->follow_ids = txl->list;
 	if (txl->next_cursor)
+		/* These were just numbers. Up to 4000 in a response AFAIK so if we get here
+		   we may be using a spammer account. \o/ */
 		twitter_get_friends_ids(ic, txl->next_cursor);
-
+	else
+		/* Now to convert all those numbers into names.. */
+		twitter_get_users_lookup(ic);
+
+	txl->list = NULL;
 	txl_free(txl);
+}
+
+static xt_status twitter_xt_get_users(struct xt_node *node, struct twitter_xml_list *txl);
+static void twitter_http_get_users_lookup(struct http_request *req);
+
+static void twitter_get_users_lookup(struct im_connection *ic)
+{
+	struct twitter_data *td = ic->proto_data;
+	char *args[2] = {
+		"user_id",
+		NULL,
+	};
+	GString *ids = g_string_new("");
+	int i;
+	
+	/* We can request up to 100 users at a time. */
+	for (i = 0; i < 100 && td->follow_ids; i ++) {
+		g_string_append_printf(ids, ",%s", (char*) td->follow_ids->data);
+		g_free(td->follow_ids->data);
+		td->follow_ids = g_slist_remove(td->follow_ids, td->follow_ids->data);
+	}
+	if (ids->len > 0) {
+		args[1] = ids->str + 1;
+		/* POST, because I think ids can be up to 1KB long. */
+		twitter_http(ic, TWITTER_USERS_LOOKUP_URL, twitter_http_get_users_lookup, ic, 1, args, 2);
+	} else {
+		/* We have all users. Continue with login. (Get statuses.) */
+		td->flags |= TWITTER_HAVE_FRIENDS;
+		twitter_login_finish(ic);
+	}
+	g_string_free(ids, TRUE);
+}
+
+/**
+ * Callback for getting (twitter)friends...
+ *
+ * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has 
+ * hundreds of friends?" you wonder? You probably not, since you are reading the source of 
+ * BitlBee... Get a life and meet new people!
+ */
+static void twitter_http_get_users_lookup(struct http_request *req)
+{
+	struct im_connection *ic = req->data;
+	struct twitter_data *td;
+	struct xt_parser *parser;
+	struct twitter_xml_list *txl;
+	GSList *l = NULL;
+	struct twitter_xml_user *user;
+
+	// Check if the connection is still active.
+	if (!g_slist_find(twitter_connections, ic))
+		return;
+
+	td = ic->proto_data;
+
+	if (req->status_code != 200) {
+		// It didn't go well, output the error and return.
+		imcb_error(ic, "Could not retrieve %s: %s",
+			   TWITTER_USERS_LOOKUP_URL, twitter_parse_error(req));
+		imc_logout(ic, TRUE);
+		return;
+	} else {
+		td->http_fails = 0;
+	}
+
+	txl = g_new0(struct twitter_xml_list, 1);
+	txl->list = NULL;
+
+	// Parse the data.
+	parser = xt_new(NULL, txl);
+	xt_feed(parser, req->reply_body, req->body_size);
+
+	// Get the user list from the parsed xml feed.
+	twitter_xt_get_users(parser->root, txl);
+	xt_free(parser);
+
+	// Add the users as buddies.
+	for (l = txl->list; l; l = g_slist_next(l)) {
+		user = l->data;
+		twitter_add_buddy(ic, user->screen_name, user->name);
+	}
+
+	// Free the structure.
+	txl_free(txl);
+
+	twitter_get_users_lookup(ic);
 }
 
@@ -304,30 +413,4 @@
 			// Put the item in the front of the list.
 			txl->list = g_slist_prepend(txl->list, txu);
-		}
-	}
-
-	return XT_HANDLED;
-}
-
-/**
- * Function to fill a twitter_xml_list struct.
- * It calls twitter_xt_get_users to get the <user>s from a <users> element.
- * It sets:
- *  - the next_cursor.
- */
-static xt_status twitter_xt_get_user_list(struct xt_node *node, struct twitter_xml_list *txl)
-{
-	struct xt_node *child;
-
-	// Set the type of the list.
-	txl->type = TXL_USER;
-
-	// The root <user_list> node should hold a users <users> element
-	// Walk over the nodes children.
-	for (child = node->children; child; child = child->next) {
-		if (g_strcasecmp("users", child->name) == 0) {
-			twitter_xt_get_users(child, txl);
-		} else if (g_strcasecmp("next_cursor", child->name) == 0) {
-			twitter_xt_next_cursor(child, txl);
 		}
 	}
@@ -634,6 +717,6 @@
 		// It didn't go well, output the error and return.
 		if (++td->http_fails >= 5)
-			imcb_error(ic, "Could not retrieve " TWITTER_HOME_TIMELINE_URL ": %s",
-				   twitter_parse_error(req));
+			imcb_error(ic, "Could not retrieve %s: %s",
+				   TWITTER_HOME_TIMELINE_URL, twitter_parse_error(req));
 
 		return;
@@ -662,89 +745,6 @@
 
 /**
- * Callback for getting (twitter)friends...
- *
- * Be afraid, be very afraid! This function will potentially add hundreds of "friends". "Who has 
- * hundreds of friends?" you wonder? You probably not, since you are reading the source of 
- * BitlBee... Get a life and meet new people!
- */
-static void twitter_http_get_statuses_friends(struct http_request *req)
-{
-	struct im_connection *ic = req->data;
-	struct twitter_data *td;
-	struct xt_parser *parser;
-	struct twitter_xml_list *txl;
-	GSList *l = NULL;
-	struct twitter_xml_user *user;
-
-	// Check if the connection is still active.
-	if (!g_slist_find(twitter_connections, ic))
-		return;
-
-	td = ic->proto_data;
-
-	// Check if the HTTP request went well.
-	if (req->status_code == 401) {
-		imcb_error(ic, "Authentication failure");
-		imc_logout(ic, FALSE);
-		return;
-	} else if (req->status_code != 200) {
-		// It didn't go well, output the error and return.
-		imcb_error(ic, "Could not retrieve " TWITTER_SHOW_FRIENDS_URL ": %s",
-			   twitter_parse_error(req));
-		imc_logout(ic, TRUE);
-		return;
-	} else {
-		td->http_fails = 0;
-	}
-
-	if (!td->home_timeline_gc && g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "chat") == 0)
-		twitter_groupchat_init(ic);
-
-	txl = g_new0(struct twitter_xml_list, 1);
-	txl->list = NULL;
-
-	// Parse the data.
-	parser = xt_new(NULL, txl);
-	xt_feed(parser, req->reply_body, req->body_size);
-
-	// Get the user list from the parsed xml feed.
-	twitter_xt_get_user_list(parser->root, txl);
-	xt_free(parser);
-
-	// Add the users as buddies.
-	for (l = txl->list; l; l = g_slist_next(l)) {
-		user = l->data;
-		twitter_add_buddy(ic, user->screen_name, user->name);
-	}
-
-	// if the next_cursor is set to something bigger then 0 there are more friends to gather.
-	if (txl->next_cursor > 0) {
-		twitter_get_statuses_friends(ic, txl->next_cursor);
-	} else {
-		td->flags |= TWITTER_HAVE_FRIENDS;
-		twitter_login_finish(ic);
-	}
-
-	// Free the structure.
-	txl_free(txl);
-}
-
-/**
- * Get the friends.
- */
-void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor)
-{
-	char *args[2];
-	args[0] = "cursor";
-	args[1] = g_strdup_printf("%lld", (long long) next_cursor);
-
-	twitter_http(ic, TWITTER_SHOW_FRIENDS_URL, twitter_http_get_statuses_friends, ic, 0, args,
-		     2);
-
-	g_free(args[1]);
-}
-
-/**
- * Callback to use after sending a post request to twitter.
+ * Callback to use after sending a POST request to twitter.
+ * (Generic, used for a few kinds of queries.)
  */
 static void twitter_http_post(struct http_request *req)
@@ -810,6 +810,4 @@
 	// Use the same callback as for twitter_post_status, since it does basically the same.
 	twitter_http(ic, TWITTER_DIRECT_MESSAGES_NEW_URL, twitter_http_post, ic, 1, args, 4);
-//      g_free(args[1]);
-//      g_free(args[3]);
 }
 
@@ -826,7 +824,6 @@
 {
 	char *url;
-	url =
-	    g_strdup_printf("%s%llu%s", TWITTER_STATUS_DESTROY_URL, (unsigned long long) id,
-			    ".xml");
+	url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_DESTROY_URL,
+	                      (unsigned long long) id, ".xml");
 	twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0);
 	g_free(url);
@@ -836,7 +833,6 @@
 {
 	char *url;
-	url =
-	    g_strdup_printf("%s%llu%s", TWITTER_STATUS_RETWEET_URL, (unsigned long long) id,
-			    ".xml");
+	url = g_strdup_printf("%s%llu%s", TWITTER_STATUS_RETWEET_URL,
+	                      (unsigned long long) id, ".xml");
 	twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0);
 	g_free(url);
Index: protocols/twitter/twitter_lib.h
===================================================================
--- protocols/twitter/twitter_lib.h	(revision 5983eca9ac1187eb1407eece7d7ad72ef5e091b0)
+++ protocols/twitter/twitter_lib.h	(revision de923d59e15bb650c2cb98a6254c79aa7c6af96e)
@@ -47,7 +47,5 @@
 
 /* Users URLs */
-#define TWITTER_SHOW_USERS_URL "/users/show.xml"
-#define TWITTER_SHOW_FRIENDS_URL "/statuses/friends.xml"
-#define TWITTER_SHOW_FOLLOWERS_URL "/statuses/followers.xml"
+#define TWITTER_USERS_LOOKUP_URL "/users/lookup.xml"
 
 /* Direct messages URLs */
