aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilmer van der Gaast <wilmer@gaast.net>2011-06-11 18:11:08 +0100
committerWilmer van der Gaast <wilmer@gaast.net>2011-06-11 18:11:08 +0100
commitde923d59e15bb650c2cb98a6254c79aa7c6af96e (patch)
treeb41b74c1ea7e086ac04746267c6955a3c26bb846
parent5f74987ee76bf4bdf94f5ea3017078ad65f97aa7 (diff)
Use /friends/ids and /users/lookup instead of /statuses/friends to get a
list of contacts at login time. Still depends on adding an API version number to base_url though.
-rw-r--r--protocols/twitter/twitter.c10
-rw-r--r--protocols/twitter/twitter.h5
-rw-r--r--protocols/twitter/twitter_lib.c272
-rw-r--r--protocols/twitter/twitter_lib.h4
4 files changed, 145 insertions, 146 deletions
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c
index 56c7269e..50a7cc0a 100644
--- a/protocols/twitter/twitter.c
+++ b/protocols/twitter/twitter.c
@@ -82,7 +82,8 @@ void twitter_login_finish(struct im_connection *ic)
else if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "one") != 0 &&
!(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);
}
@@ -167,6 +168,8 @@ static gboolean twitter_oauth_callback(struct oauth_info *info)
imcb_log(ic, "Warning: You logged in via OAuth as %s "
"instead of %s.", sn, ic->acc->user);
}
+ g_free(td->user);
+ td->user = g_strdup(sn);
}
/* IM mods didn't do this so far and it's ugly but I should
@@ -256,6 +259,7 @@ static void twitter_login(account_t * acc)
twitter_connections = g_slist_append(twitter_connections, ic);
td = g_new0(struct twitter_data, 1);
ic->proto_data = td;
+ td->user = g_strdup(acc->user);
td->url_ssl = url.proto == PROTO_HTTPS;
td->url_port = url.port;
@@ -269,8 +273,6 @@ static void twitter_login(account_t * acc)
else
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));
@@ -304,10 +306,10 @@ static void twitter_logout(struct im_connection *ic)
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);
}
diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h
index a3b21a07..c38d9b86 100644
--- a/protocols/twitter/twitter.h
+++ b/protocols/twitter/twitter.h
@@ -42,8 +42,9 @@ struct twitter_log_data;
struct twitter_data
{
char* user;
- char* pass;
struct oauth_info *oauth_info;
+ GSList *follow_ids;
+
guint64 home_timeline_id;
guint64 last_status_id; /* For undo */
gint main_loop_id;
@@ -51,6 +52,7 @@ struct twitter_data
gint http_fails;
twitter_flags_t flags;
+ /* set base_url */
gboolean url_ssl;
int url_port;
char *url_host;
@@ -58,6 +60,7 @@ struct twitter_data
char *prefix; /* Used to generate contact + channel name. */
+ /* set show_ids */
struct twitter_log_data *log;
int log_id;
};
diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c
index cdff9895..cc817d45 100644
--- a/protocols/twitter/twitter_lib.c
+++ b/protocols/twitter/twitter_lib.c
@@ -54,7 +54,6 @@ struct twitter_xml_list {
int type;
gint64 next_cursor;
GSList *list;
- gpointer data;
};
struct twitter_xml_user {
@@ -108,6 +107,8 @@ static void txl_free(struct twitter_xml_list *txl)
txs_free((struct twitter_xml_status *) l->data);
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);
}
@@ -119,7 +120,7 @@ static void twitter_add_buddy(struct im_connection *ic, char *name, const char *
{
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");
@@ -137,7 +138,7 @@ static void twitter_add_buddy(struct im_connection *ic, char *name, const char *
}
/* 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)
{
static char *ret = NULL;
@@ -150,11 +151,12 @@ char *twitter_parse_error(struct http_request *req)
if (req->body_size > 0) {
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);
}
@@ -206,10 +208,12 @@ static xt_status twitter_xt_get_friends_id_list(struct xt_node *node, struct twi
// The root <statuses> node should hold the list of statuses <status>
// 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,6 +222,8 @@ static xt_status twitter_xt_get_friends_id_list(struct xt_node *node, struct twi
return XT_HANDLED;
}
+static void twitter_get_users_lookup(struct im_connection *ic);
+
/**
* Callback for getting the friends ids.
*/
@@ -236,18 +242,28 @@ static void twitter_http_get_friends_ids(struct http_request *req)
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 {
td->http_fails = 0;
}
+ /* 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.
parser = xt_new(NULL, txl);
@@ -255,10 +271,103 @@ static void twitter_http_get_friends_ids(struct http_request *req)
twitter_xt_get_friends_id_list(parser->root, txl);
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);
}
/**
@@ -309,32 +418,6 @@ static xt_status twitter_xt_get_users(struct xt_node *node, struct twitter_xml_l
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);
- }
- }
-
- return XT_HANDLED;
-}
-
#ifdef __GLIBC__
#define TWITTER_TIME_FORMAT "%a %b %d %H:%M:%S %z %Y"
#else
@@ -633,8 +716,8 @@ static void twitter_http_get_home_timeline(struct http_request *req)
} else {
// 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;
}
@@ -661,91 +744,8 @@ static void twitter_http_get_home_timeline(struct http_request *req)
}
/**
- * 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)
{
@@ -809,8 +809,6 @@ void twitter_direct_messages_new(struct im_connection *ic, char *who, char *msg)
args[3] = msg;
// 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]);
}
void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create)
@@ -825,9 +823,8 @@ void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int
void twitter_status_destroy(struct im_connection *ic, guint64 id)
{
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);
}
@@ -835,9 +832,8 @@ void twitter_status_destroy(struct im_connection *ic, guint64 id)
void twitter_status_retweet(struct im_connection *ic, guint64 id)
{
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);
}
diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h
index 24b4a089..fa039ede 100644
--- a/protocols/twitter/twitter_lib.h
+++ b/protocols/twitter/twitter_lib.h
@@ -46,9 +46,7 @@
#define TWITTER_USER_TIMELINE_URL "/statuses/user_timeline.xml"
/* 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 */
#define TWITTER_DIRECT_MESSAGES_URL "/direct_messages.xml"