diff options
Diffstat (limited to 'protocols/twitter/twitter_lib.c')
| -rw-r--r-- | protocols/twitter/twitter_lib.c | 238 | 
1 files changed, 196 insertions, 42 deletions
diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index c66c1d89..a0580ed9 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -240,6 +240,7 @@ static json_value *twitter_parse_response(struct im_connection *ic, struct http_  static void twitter_http_get_friends_ids(struct http_request *req);  static void twitter_http_get_mutes_ids(struct http_request *req); +static void twitter_http_get_blocks_ids(struct http_request *req);  static void twitter_http_get_noretweets_ids(struct http_request *req);  /** @@ -272,6 +273,20 @@ void twitter_get_mutes_ids(struct im_connection *ic, gint64 next_cursor)  }  /** + * Get the blocked users ids. + */ +void twitter_get_blocks_ids(struct im_connection *ic, gint64 next_cursor) +{ +	char *args[2]; + +	args[0] = "cursor"; +	args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor); +	twitter_http(ic, TWITTER_BLOCKS_IDS_URL, twitter_http_get_blocks_ids, ic, 0, args, 2); + +	g_free(args[1]); +} + +/**   * Get the ids for users from whom we should ignore retweets.   */  void twitter_get_noretweets_ids(struct im_connection *ic, gint64 next_cursor) @@ -367,14 +382,15 @@ static void twitter_http_get_friends_ids(struct http_request *req)  }  /** - * Callback for getting the mutes ids. + * Callback for getting the blocks and mutes ids.   */ -static void twitter_http_get_mutes_ids(struct http_request *req) +static void twitter_http_get_mutes_blocks_ids(struct http_request *req, int blocks)  {  	struct im_connection *ic = req->data;  	json_value *parsed;  	struct twitter_xml_list *txl;  	struct twitter_data *td; +	GSList *elem;  	// Check if the connection is stil active  	if (!g_slist_find(twitter_connections, ic)) { @@ -394,24 +410,45 @@ static void twitter_http_get_mutes_ids(struct http_request *req)  	}  	txl = g_new0(struct twitter_xml_list, 1); -	txl->list = td->mutes_ids;  	/* mute ids API response is similar enough to friends response  	   to reuse this method */  	twitter_xt_get_friends_id_list(parsed, txl);  	json_value_free(parsed); -	td->mutes_ids = txl->list; +	for (elem = txl->list; elem; elem = elem->next) { +		g_hash_table_add(blocks ? td->blocks_ids : td->mutes_ids, elem->data); +	} +  	if (txl->next_cursor) {  		/* Recurse while there are still more pages */ -		twitter_get_mutes_ids(ic, txl->next_cursor); +		if (blocks) { +			twitter_get_blocks_ids(ic, txl->next_cursor); +		} else { +			twitter_get_mutes_ids(ic, txl->next_cursor); +		}  	} -	txl->list = NULL;  	txl_free(txl);  }  /** + * Callback for getting the mutes ids. + */ +static void twitter_http_get_mutes_ids(struct http_request *req) +{ +	twitter_http_get_mutes_blocks_ids(req, 0); +} + +/** + * Callback for  getting the blocks ids. + */ +static void twitter_http_get_blocks_ids(struct http_request *req) +{ +	twitter_http_get_mutes_blocks_ids(req, 1); +} + +/**   * Callback for getting the no-retweets ids.   */  static void twitter_http_get_noretweets_ids(struct http_request *req) @@ -420,6 +457,7 @@ static void twitter_http_get_noretweets_ids(struct http_request *req)  	json_value *parsed;  	struct twitter_xml_list *txl;  	struct twitter_data *td; +	GSList *elem;  	// Check if the connection is stil active  	if (!g_slist_find(twitter_connections, ic)) { @@ -439,7 +477,6 @@ static void twitter_http_get_noretweets_ids(struct http_request *req)  	}  	txl = g_new0(struct twitter_xml_list, 1); -	txl->list = td->noretweets_ids;  	// Process the retweet ids  	txl->type = TXL_ID; @@ -455,10 +492,12 @@ static void twitter_http_get_noretweets_ids(struct http_request *req)  		}  	} +	for (elem = txl->list; elem; elem = elem->next) { +		g_hash_table_add(td->noretweets_ids, elem->data); +	} +  	json_value_free(parsed); -	td->noretweets_ids = txl->list; -	txl->list = NULL;  	txl_free(txl);  } @@ -814,7 +853,7 @@ static char *twitter_msg_add_id(struct im_connection *ic,  	if (txs->reply_to) {  		int i; -		for (i = 0; i < TWITTER_LOG_LENGTH; i++) { +		for (i = 0; i < td->log_length; i++) {  			if (td->log[i].id == txs->reply_to) {  				reply_to = i;  				break; @@ -832,26 +871,39 @@ static char *twitter_msg_add_id(struct im_connection *ic,  		}  	} -	td->log_id = (td->log_id + 1) % TWITTER_LOG_LENGTH; -	td->log[td->log_id].id = txs->id; -	td->log[td->log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name); +	if (txs->from_filter) { +		td->filter_log_id = (td->filter_log_id + 1) % td->log_length; +		td->filter_log[td->filter_log_id].id = txs->id; +		td->filter_log[td->filter_log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name); +	} else { +		td->log_id = (td->log_id + 1) % td->log_length; +		td->log[td->log_id].id = txs->id; +		td->log[td->log_id].bu = bee_user_by_handle(ic->bee, ic, txs->user->screen_name); +	}  	/* This is all getting hairy. :-( If we RT'ed something ourselves,  	   remember OUR id instead so undo will work. In other cases, the  	   original tweet's id should be remembered for deduplicating. */  	if (g_strcasecmp(txs->user->screen_name, td->user) == 0) { -		td->log[td->log_id].id = txs->rt_id; -		/* More useful than NULL. */ -		td->log[td->log_id].bu = &twitter_log_local_user; +		if (txs->from_filter) { +			td->filter_log[td->filter_log_id].id = txs->rt_id; +			/* More useful than NULL. */ +			td->filter_log[td->filter_log_id].bu = &twitter_log_local_user; +		} else { +			td->log[td->log_id].id = txs->rt_id; +			/* More useful than NULL. */ +			td->log[td->log_id].bu = &twitter_log_local_user; +		}  	}  	if (set_getbool(&ic->acc->set, "show_ids")) {  		if (reply_to != -1) { -			return g_strdup_printf("\002[\002%02x->%02x\002]\002 %s%s", -			                       td->log_id, reply_to, prefix, txs->text); +			return g_strdup_printf("\002[\002%0*x->%0*x\002]\002 %s%s", +			                       td->id_length, td->log_id, td->id_length, +					       reply_to, prefix, txs->text);  		} else { -			return g_strdup_printf("\002[\002%02x\002]\002 %s%s", -			                       td->log_id, prefix, txs->text); +			return g_strdup_printf("\002[\002%0*x\002]\002 %s%s", +			                       td->id_length, td->log_id, prefix, txs->text);  		}  	} else {  		if (*prefix) { @@ -979,11 +1031,12 @@ static void twitter_status_show(struct im_connection *ic, struct twitter_xml_sta  	/* Check this is not a tweet that should be muted */  	uid_str = g_strdup_printf("%" PRIu64, status->user->uid); -	if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) { +	if (g_hash_table_lookup(td->mutes_ids, uid_str) || +			g_hash_table_lookup(td->blocks_ids, uid_str)) {  		g_free(uid_str);  		return;  	} -	if (status->id != status->rt_id && g_slist_find_custom(td->noretweets_ids, uid_str, (GCompareFunc)strcmp)) { +	if (status->id != status->rt_id && g_hash_table_lookup(td->noretweets_ids, uid_str)) {  		g_free(uid_str);  		return;  	} @@ -1032,8 +1085,23 @@ static void twitter_http_stream(struct http_request *req)  	if ((req->flags & HTTPC_EOF) || !req->reply_body) {  		if (req == td->stream) {  			td->stream = NULL; + +			if (req->status_code == 200 && +			    td->stream_opentime + 3 < time(NULL)) { +				debug("Reconnecting to twitter stream."); +				twitter_open_stream(ic); +				twitter_get_timeline(ic, -1); +				return; +			}  		} else if (req == td->filter_stream) {  			td->filter_stream = NULL; + +			if (req->status_code == 200 && +			    td->filter_stream_opentime + 3 < time(NULL)) { +				debug("Reconnecting to twitter filter stream."); +				twitter_open_filter_stream(ic); +				return; +			}  		}  		imcb_error(ic, "Stream closed (%s)", req->status_string); @@ -1092,8 +1160,12 @@ static gboolean twitter_stream_handle_object(struct im_connection *ic, json_valu  	} 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) { -			imcb_buddy_msg(ic, txs->user->screen_name, -			               txs->text, 0, txs->created_at); +			char *uid_str = g_strdup_printf("%" PRIu64, txs->user->uid); +			if (!g_hash_table_lookup(td->blocks_ids, uid_str)) { +				imcb_buddy_msg(ic, txs->user->screen_name, +					       txs->text, 0, txs->created_at); +			} +			g_free(uid_str);  		}  		txs_free(txs);  		return TRUE; @@ -1117,10 +1189,12 @@ static gboolean twitter_stream_handle_object(struct im_connection *ic, json_valu  static gboolean twitter_stream_handle_status(struct im_connection *ic, struct twitter_xml_status *txs)  {  	struct twitter_data *td = ic->proto_data; +	struct twitter_log_data *tl;  	int i; -	for (i = 0; i < TWITTER_LOG_LENGTH; i++) { -		if (td->log[i].id == txs->id) { +	tl = txs->from_filter ? td->filter_log : td->log; +	for (i = 0; i < td->log_length; i++) { +		if (tl[i].id == txs->id) {  			/* Got a duplicate (RT, probably). Drop it. */  			return TRUE;  		} @@ -1163,33 +1237,25 @@ static gboolean twitter_stream_handle_event(struct im_connection *ic, json_value  		if (g_strcasecmp(us->screen_name, td->user) == 0) {  			twitter_add_buddy(ic, ut->screen_name, ut->name);  		} -	} else if (strcmp(type, "mute") == 0) { -		GSList *found; +	} else if (strcmp(type, "mute") == 0 || strcmp(type, "block") == 0) {  		char *uid_str; +		int mute = strcmp(type, "mute") == 0;  		ut = twitter_xt_get_user(target);  		uid_str = g_strdup_printf("%" PRIu64, ut->uid); -		if (!(found = g_slist_find_custom(td->mutes_ids, uid_str, -		                                  (GCompareFunc)strcmp))) { -			td->mutes_ids = g_slist_prepend(td->mutes_ids, uid_str); -		} -		twitter_log(ic, "Muted user %s", ut->screen_name); +		g_hash_table_add(mute ? td->mutes_ids : td->blocks_ids, uid_str); +		twitter_log(ic, "%s user %s", mute ? "Muted" : "Blocked", ut->screen_name);  		if (getenv("BITLBEE_DEBUG")) {  			fprintf(stderr, "New mute: %s %"PRIu64"\n",  			        ut->screen_name, ut->uid);  		} -	} else if (strcmp(type, "unmute") == 0) { -		GSList *found; +	} else if (strcmp(type, "unmute") == 0 || strcmp(type, "unblock") == 0) {  		char *uid_str; +		int unmute = strcmp(type, "unmute") == 0;  		ut = twitter_xt_get_user(target);  		uid_str = g_strdup_printf("%" PRIu64, ut->uid); -		if ((found = g_slist_find_custom(td->mutes_ids, uid_str, -		                                (GCompareFunc)strcmp))) { -			char *found_str = found->data; -			td->mutes_ids = g_slist_delete_link(td->mutes_ids, found); -			g_free(found_str); -		} +		g_hash_table_remove(unmute ? td->mutes_ids : td->blocks_ids, uid_str);  		g_free(uid_str); -		twitter_log(ic, "Unmuted user %s", ut->screen_name); +		twitter_log(ic, "%s user %s", unmute ? "Unmuted" : "Blocked", ut->screen_name);  		if (getenv("BITLBEE_DEBUG")) {  			fprintf(stderr, "New unmute: %s %"PRIu64"\n",  			        ut->screen_name, ut->uid); @@ -1212,6 +1278,7 @@ gboolean twitter_open_stream(struct im_connection *ic)  		/* 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->stream->flags |= HTTPC_STREAMING; +		td->stream_opentime = time(NULL);  		return TRUE;  	} @@ -1267,6 +1334,7 @@ static gboolean twitter_filter_stream(struct im_connection *ic)  		/* 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; +		td->filter_stream_opentime = time(NULL);  		ret = TRUE;  	} @@ -1731,6 +1799,32 @@ void twitter_mute_create_destroy(struct im_connection *ic, char *who, int create  		     twitter_http_post, ic, 1, args, 2);  } +/** + * Block or unblock a user + */ +void twitter_block_create_destroy(struct im_connection *ic, char *who, int create) +{ +	char *args[2]; + +	args[0] = "screen_name"; +	args[1] = who; +	twitter_http(ic, create ? TWITTER_BLOCKS_CREATE_URL : TWITTER_BLOCKS_DESTROY_URL, +			twitter_http_post, ic, 1, args, 2); +} + +/** + * Enable or disable retweets for user + */ +void twitter_retweet_enable_disable(struct im_connection *ic, char *who, int enable) +{ +	char *args[4]; +	args[0] = "screen_name"; +	args[1] = who; +	args[2] = "retweets"; +	args[3] = enable ? "true" : "false"; +	twitter_http(ic, TWITTER_FRIENDSHIPS_UPDATE_URL, twitter_http_post, ic, 1, args, 4); +} +  void twitter_status_destroy(struct im_connection *ic, guint64 id)  {  	char *url; @@ -1822,3 +1916,63 @@ void twitter_status_show_url(struct im_connection *ic, guint64 id)  	twitter_http(ic, url, twitter_http_status_show_url, ic, 0, NULL, 0);  	g_free(url);  } + +struct twitter_http_msg { +	struct im_connection *ic; +	char *message; +}; + +static void twitter_http_status_quote_post(struct http_request *req) +{ +	struct twitter_http_msg *thm = req->data; +	struct im_connection *ic = thm->ic; +	struct twitter_data *td = ic->proto_data; +	char *message; +	const char *name; +	json_value *parsed, *id; + +	if (!g_slist_find(twitter_connections, ic)) { +		goto eof; +	} + +	if (!(parsed = twitter_parse_response(ic, req))) { +		goto eof; +	} + +	name = json_o_str(json_o_get(parsed, "user"), "screen_name"); +	id = json_o_get(parsed, "id"); + +	if (name && id && id->type == json_integer) { +		message = g_strdup_printf("%s https://twitter.com/%s/status/%" G_GUINT64_FORMAT, thm->message, name, id->u.integer); + +		/*if (!twitter_length_check(ic, message)) { +			goto eof; +		}*/ + +		td->last_status_id = 0; +		twitter_post_status(ic, message, 0); +	} else { +		twitter_log(ic, "Error: could not fetch url for quoted tweet."); +	} + +	json_value_free(parsed); + +eof: +	g_free(thm->message); +	g_free(thm); +} + +void twitter_status_quote_post(struct im_connection *ic, guint64 id, char *message) +{ +	struct twitter_http_msg *thm; +	char *url; + +	thm = g_new0(struct twitter_http_msg, 1); + +	thm->ic = ic; +	thm->message = g_strdup(message); + +	url = g_strdup_printf("%s%" G_GUINT64_FORMAT "%s", TWITTER_STATUS_SHOW_URL, id, ".json"); +	twitter_http(ic, url, twitter_http_status_quote_post, thm, 0, NULL, 0); +	g_free(url); +}  | 
