diff options
Diffstat (limited to 'protocols/twitter/twitter_lib.c')
-rw-r--r-- | protocols/twitter/twitter_lib.c | 226 |
1 files changed, 221 insertions, 5 deletions
diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 718867a7..c8956606 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -50,6 +50,7 @@ struct twitter_xml_list { }; struct twitter_xml_user { + guint64 uid; char *name; char *screen_name; }; @@ -60,6 +61,7 @@ struct twitter_xml_status { struct twitter_xml_user *user; guint64 id, rt_id; /* Usually equal, with RTs id == *original* id */ guint64 reply_to; + gboolean from_filter; }; /** @@ -391,11 +393,15 @@ static void twitter_http_get_users_lookup(struct http_request *req) struct twitter_xml_user *twitter_xt_get_user(const json_value *node) { struct twitter_xml_user *txu; + json_value *jv; txu = g_new0(struct twitter_xml_user, 1); 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; } @@ -656,6 +662,44 @@ static char *twitter_msg_add_id(struct im_connection *ic, } /** + * Function that is called to see the filter statuses in groupchat windows. + */ +static void twitter_status_show_filter(struct im_connection *ic, struct twitter_xml_status *status) +{ + struct twitter_data *td = ic->proto_data; + char *msg = twitter_msg_add_id(ic, status, ""); + struct twitter_filter *tf; + GSList *f; + GSList *l; + + for (f = td->filters; f; f = g_slist_next(f)) { + tf = f->data; + + switch (tf->type) { + case TWITTER_FILTER_TYPE_FOLLOW: + if (status->user->uid != tf->uid) + continue; + break; + + case TWITTER_FILTER_TYPE_TRACK: + if (strcasestr(status->text, tf->text) == NULL) + continue; + break; + + default: + continue; + } + + for (l = tf->groupchats; l; l = g_slist_next(l)) { + imcb_chat_msg(l->data, status->user->screen_name, + msg ? msg : status->text, 0, 0); + } + } + + g_free(msg); +} + +/** * Function that is called to see the statuses in a groupchat window. */ static void twitter_status_show_chat(struct im_connection *ic, struct twitter_xml_status *status) @@ -730,7 +774,9 @@ static void twitter_status_show(struct im_connection *ic, struct twitter_xml_sta if (set_getbool(&ic->acc->set, "strip_newlines")) strip_newlines(status->text); - if (td->flags & TWITTER_MODE_CHAT) + if (status->from_filter) + twitter_status_show_filter(ic, status); + else if (td->flags & TWITTER_MODE_CHAT) twitter_status_show_chat(ic, status); else twitter_status_show_msg(ic, status); @@ -744,7 +790,7 @@ static void twitter_status_show(struct im_connection *ic, struct twitter_xml_sta g_free(last_id_str); } -static gboolean twitter_stream_handle_object(struct im_connection *ic, json_value *o); +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) { @@ -753,6 +799,7 @@ static void twitter_http_stream(struct http_request *req) json_value *parsed; int len = 0; char c, *nl; + gboolean from_filter; if (!g_slist_find(twitter_connections, ic)) return; @@ -761,7 +808,11 @@ static void twitter_http_stream(struct http_request *req) td = ic->proto_data; if ((req->flags & HTTPC_EOF) || !req->reply_body) { - td->stream = NULL; + if (req == td->stream) + td->stream = NULL; + else if (req == td->filter_stream) + td->filter_stream = NULL; + imcb_error(ic, "Stream closed (%s)", req->status_string); imc_logout(ic, TRUE); return; @@ -778,7 +829,8 @@ static void twitter_http_stream(struct http_request *req) req->reply_body[len] = '\0'; if ((parsed = json_parse(req->reply_body, req->body_size))) { - twitter_stream_handle_object(ic, parsed); + from_filter = (req == td->filter_stream); + twitter_stream_handle_object(ic, parsed, from_filter); } json_value_free(parsed); req->reply_body[len] = c; @@ -794,13 +846,14 @@ static void twitter_http_stream(struct http_request *req) 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_value *o) +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_value *c; if ((txs = twitter_xt_get_status(o))) { + txs->from_filter = from_filter; gboolean ret = twitter_stream_handle_status(ic, txs); txs_free(txs); return ret; @@ -898,6 +951,169 @@ gboolean twitter_open_stream(struct im_connection *ic) return FALSE; } +static gboolean twitter_filter_stream(struct im_connection *ic) +{ + struct twitter_data *td = ic->proto_data; + char *args[4] = {"follow", NULL, "track", NULL}; + GString *followstr = g_string_new(""); + GString *trackstr = g_string_new(""); + gboolean ret = FALSE; + struct twitter_filter *tf; + GSList *l; + + for (l = td->filters; l; l = g_slist_next(l)) { + tf = l->data; + + switch (tf->type) { + case TWITTER_FILTER_TYPE_FOLLOW: + if (followstr->len > 0) + g_string_append_c(followstr, ','); + + g_string_append_printf(followstr, "%" G_GUINT64_FORMAT, + tf->uid); + break; + + case TWITTER_FILTER_TYPE_TRACK: + if (trackstr->len > 0) + g_string_append_c(trackstr, ','); + + g_string_append(trackstr, tf->text); + break; + + default: + continue; + } + } + + args[1] = followstr->str; + args[3] = trackstr->str; + + if (td->filter_stream) + http_close(td->filter_stream); + + if ((td->filter_stream = twitter_http(ic, TWITTER_FILTER_STREAM_URL, + twitter_http_stream, ic, 0, + args, 4))) { + /* This flag must be enabled or we'll get no data until EOF + (which err, kind of, defeats the purpose of a streaming API). */ + td->filter_stream->flags |= HTTPC_STREAMING; + ret = TRUE; + } + + g_string_free(followstr, TRUE); + g_string_free(trackstr, TRUE); + + return ret; +} + +static void twitter_filter_users_post(struct http_request *req) +{ + struct im_connection *ic = req->data; + struct twitter_data *td; + struct twitter_filter *tf; + GList *users = NULL; + json_value *parsed; + json_value *id; + const char *name; + GString *fstr; + GSList *l; + GList *u; + int i; + + // Check if the connection is still active. + if (!g_slist_find(twitter_connections, ic)) + return; + + td = ic->proto_data; + + if (!(parsed = twitter_parse_response(ic, req))) + return; + + for (l = td->filters; l; l = g_slist_next(l)) { + tf = l->data; + + if (tf->type == TWITTER_FILTER_TYPE_FOLLOW) + users = g_list_prepend(users, tf); + } + + if (parsed->type != json_array) + goto finish; + + 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; + + for (u = users; u; u = g_list_next(u)) { + tf = u->data; + + if (g_strcasecmp(tf->text, name) == 0) { + tf->uid = id->u.integer; + users = g_list_delete_link(users, u); + break; + } + } + } + +finish: + json_value_free(parsed); + twitter_filter_stream(ic); + + if (!users) + return; + + fstr = g_string_new(""); + + for (u = users; u; u = g_list_next(u)) { + if (fstr->len > 0) + g_string_append(fstr, ", "); + + g_string_append(fstr, tf->text); + } + + imcb_error(ic, "Failed UID acquisitions: %s", fstr->str); + + g_string_free(fstr, TRUE); + g_list_free(users); +} + +gboolean twitter_open_filter_stream(struct im_connection *ic) +{ + struct twitter_data *td = ic->proto_data; + char *args[2] = {"screen_name", NULL}; + GString *ustr = g_string_new(""); + struct twitter_filter *tf; + struct http_request *req; + GSList *l; + + for (l = td->filters; l; l = g_slist_next(l)) { + tf = l->data; + + if (tf->type != TWITTER_FILTER_TYPE_FOLLOW || tf->uid != 0) + continue; + + if (ustr->len > 0) + g_string_append_c(ustr, ','); + + g_string_append(ustr, tf->text); + } + + if (ustr->len == 0) { + g_string_free(ustr, TRUE); + return twitter_filter_stream(ic); + } + + args[1] = ustr->str; + req = twitter_http(ic, TWITTER_USERS_LOOKUP_URL, + twitter_filter_users_post, + ic, 0, args, 2); + + g_string_free(ustr, TRUE); + return req != NULL; +} + static void twitter_get_home_timeline(struct im_connection *ic, gint64 next_cursor); static void twitter_get_mentions(struct im_connection *ic, gint64 next_cursor); |