diff options
Diffstat (limited to 'protocols/twitter')
| -rw-r--r-- | protocols/twitter/twitter.c | 71 | ||||
| -rw-r--r-- | protocols/twitter/twitter.h | 8 | ||||
| -rw-r--r-- | protocols/twitter/twitter_lib.c | 118 | ||||
| -rw-r--r-- | protocols/twitter/twitter_lib.h | 1 | 
4 files changed, 179 insertions, 19 deletions
diff --git a/protocols/twitter/twitter.c b/protocols/twitter/twitter.c index b2039171..0c075c77 100644 --- a/protocols/twitter/twitter.c +++ b/protocols/twitter/twitter.c @@ -304,7 +304,7 @@ static void twitter_main_loop_start(struct im_connection *ic)  struct groupchat *twitter_groupchat_init(struct im_connection *ic)  { -	char *name_hint; +	char *name_hint, *tmp;  	struct groupchat *gc;  	struct twitter_data *td = ic->proto_data;  	GSList *l; @@ -315,7 +315,14 @@ struct groupchat *twitter_groupchat_init(struct im_connection *ic)  	td->timeline_gc = gc = imcb_chat_new(ic, "twitter/timeline"); -	name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user); +	tmp = set_getstr(&ic->acc->set, "channel_name"); +	 +	if (tmp == NULL || strlen(tmp) == 0) { +		name_hint = g_strdup_printf("%s_%s", td->prefix, ic->acc->user); +	} else { +		name_hint = g_strdup(tmp); +	} +  	imcb_chat_name_hint(gc, name_hint);  	g_free(name_hint); @@ -518,6 +525,23 @@ static char *set_eval_commands(set_t * set, char *value)  	}  } +static char *set_eval_channel_name(set_t * set, char *value) +{ +	size_t len; + +	if (value == NULL) { +		return NULL; +	} + +	len = strlen(value); + +	if (len < MAX_NICK_LENGTH && len > 0) { +		return value; +	} else { +		return NULL; +	} +} +  static char *set_eval_mode(set_t * set, char *value)  {  	if (g_strcasecmp(value, "one") == 0 || @@ -528,6 +552,15 @@ static char *set_eval_mode(set_t * set, char *value)  	}  } +static char *set_eval_id_length(set_t * set, char *value) +{ +	int len = atoi(value); +	if (len >= 1 || len <= 4) +		return value; + +	return SET_INVALID; +} +  static void twitter_init(account_t * acc)  {  	set_t *s; @@ -572,6 +605,12 @@ static void twitter_init(account_t * acc)  	s = set_add(&acc->set, "strip_newlines", "false", set_eval_bool, acc); +	s = set_add(&acc->set, "id_length", "2", set_eval_id_length, acc); +	s->flags |= ACC_SET_OFFLINE_ONLY; + +	s = set_add(&acc->set, "channel_name", NULL, set_eval_channel_name, acc); +	s->flags |= ACC_SET_OFFLINE_ONLY; +  	s = set_add(&acc->set, "_last_tweet", "0", NULL, acc);  	s->flags |= SET_HIDDEN | SET_NOSAVE; @@ -592,6 +631,7 @@ static void twitter_login(account_t * acc)  	char name[strlen(acc->user) + 9];  	url_t url;  	char *s; +	size_t i;  	if (!url_set(&url, set_getstr(&ic->acc->set, "base_url")) ||  	    (url.proto != PROTO_HTTP && url.proto != PROTO_HTTPS)) { @@ -649,8 +689,17 @@ static void twitter_login(account_t * acc)  	imcb_add_buddy(ic, name, NULL);  	imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL); -	td->log = g_new0(struct twitter_log_data, TWITTER_LOG_LENGTH); +	td->id_length = set_getint(&ic->acc->set, "id_length"); +	td->log_length = 0; +	for (i = 0; i < td->id_length; i++) { +		td->log_length = (td->log_length << 4) + 0x0F; +	} +	td->log_length += 1; + +	td->log = g_new0(struct twitter_log_data, td->log_length); +	td->filter_log = g_new0(struct twitter_log_data, td->log_length);  	td->log_id = -1; +	td->filter_log_id = -1;  	s = set_getstr(&ic->acc->set, "mode");  	if (g_strcasecmp(s, "one") == 0) { @@ -894,7 +943,7 @@ static guint64 twitter_message_id_from_command_arg(struct im_connection *ic, cha  		if (arg[0] == '#') {  			arg++;  		} -		if (parse_int64(arg, 16, &id) && id < TWITTER_LOG_LENGTH) { +		if (parse_int64(arg, 16, &id) && id < td->log_length) {  			bu = td->log[id].bu;  			id = td->log[id].id;  		} else if (parse_int64(arg, 10, &id)) { @@ -985,7 +1034,8 @@ static void twitter_handle_command(struct im_connection *ic, char *message)  		twitter_report_spam(ic, screen_name);  		goto eof; -	} else if (g_strcasecmp(cmd[0], "rt") == 0 && cmd[1]) { +	} else if ((g_strcasecmp(cmd[0], "rt") == 0 || +		    g_strcasecmp(cmd[0], "retweet") == 0) && cmd[1]) {  		id = twitter_message_id_from_command_arg(ic, cmd[1], NULL);  		td->last_status_id = 0; @@ -1024,7 +1074,18 @@ static void twitter_handle_command(struct im_connection *ic, char *message)  			twitter_status_show_url(ic, id);  		}  		goto eof; +	} else if (g_strcasecmp(cmd[0], "quote") == 0 && cmd[1]) { +		id = twitter_message_id_from_command_arg(ic, cmd[1], NULL); + +		td->last_status_id = 0; +		if (id) { +			twitter_status_quote_post(ic, id, cmd[2]); +		} else { +			twitter_log(ic, "User '%s' does not exist or didn't " +				    "post any statuses recently", cmd[1]); +		} +		goto eof;  	} else if (g_strcasecmp(cmd[0], "post") == 0) {  		message += 5;  		allow_post = TRUE; diff --git a/protocols/twitter/twitter.h b/protocols/twitter/twitter.h index 86c88262..6b7c0c0c 100644 --- a/protocols/twitter/twitter.h +++ b/protocols/twitter/twitter.h @@ -68,7 +68,9 @@ struct twitter_data {  	gint main_loop_id;  	gint filter_update_id;  	struct http_request *stream; +	time_t stream_opentime;  	struct http_request *filter_stream; +	time_t filter_stream_opentime;  	struct groupchat *timeline_gc;  	gint http_fails;  	twitter_flags_t flags; @@ -84,6 +86,11 @@ struct twitter_data {  	/* set show_ids */  	struct twitter_log_data *log;  	int log_id; +	struct twitter_log_data *filter_log; +	int filter_log_id; + +	int id_length; +	int log_length;  };  #define TWITTER_FILTER_UPDATE_WAIT 3000 @@ -99,7 +106,6 @@ struct twitter_user_data {  	time_t last_time;  }; -#define TWITTER_LOG_LENGTH 256  struct twitter_log_data {  	guint64 id;  	/* DANGER: bu can be a dead pointer. Check it first. diff --git a/protocols/twitter/twitter_lib.c b/protocols/twitter/twitter_lib.c index 41d95db8..4ef22345 100644 --- a/protocols/twitter/twitter_lib.c +++ b/protocols/twitter/twitter_lib.c @@ -800,7 +800,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; @@ -818,26 +818,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) { @@ -1019,8 +1032,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); @@ -1100,10 +1128,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;  		} @@ -1195,6 +1225,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;  	} @@ -1250,6 +1281,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;  	} @@ -1801,3 +1833,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); +} diff --git a/protocols/twitter/twitter_lib.h b/protocols/twitter/twitter_lib.h index 6833d23d..d3b6ae9e 100644 --- a/protocols/twitter/twitter_lib.h +++ b/protocols/twitter/twitter_lib.h @@ -105,6 +105,7 @@ void twitter_status_retweet(struct im_connection *ic, guint64 id);  void twitter_report_spam(struct im_connection *ic, char *screen_name);  void twitter_favourite_tweet(struct im_connection *ic, guint64 id);  void twitter_status_show_url(struct im_connection *ic, guint64 id); +void twitter_status_quote_post(struct im_connection *ic, guint64 id, char *message);  #endif //_TWITTER_LIB_H  | 
