Index: protocols/twitter/twitter.c
===================================================================
--- protocols/twitter/twitter.c	(revision c9603a38774fb118d4aaa96e170674412ed7328a)
+++ protocols/twitter/twitter.c	(revision 991c75fbf4c4bc0ab2ae6f8b983a092080630b14)
@@ -345,4 +345,6 @@
 		imcb_log(ic, "Getting contact list");
 		twitter_get_friends_ids(ic, -1);
+		twitter_get_mutes_ids(ic, -1);
+		twitter_get_noretweets_ids(ic, -1);
 	} else {
 		twitter_main_loop_start(ic);
@@ -955,4 +957,10 @@
 	} else if (g_strcasecmp(cmd[0], "unfollow") == 0 && cmd[1]) {
 		twitter_remove_buddy(ic, cmd[1], NULL);
+		goto eof;
+	} else if (g_strcasecmp(cmd[0], "mute") == 0 && cmd[1]) {
+		twitter_mute_create_destroy(ic, cmd[1], 1);
+		goto eof;
+	} else if (g_strcasecmp(cmd[0], "unmute") == 0 && cmd[1]) {
+		twitter_mute_create_destroy(ic, cmd[1], 0);
 		goto eof;
 	} else if ((g_strcasecmp(cmd[0], "report") == 0 ||
Index: protocols/twitter/twitter.h
===================================================================
--- protocols/twitter/twitter.h	(revision c9603a38774fb118d4aaa96e170674412ed7328a)
+++ protocols/twitter/twitter.h	(revision 991c75fbf4c4bc0ab2ae6f8b983a092080630b14)
@@ -61,4 +61,6 @@
 
 	GSList *follow_ids;
+	GSList *mutes_ids;
+	GSList *noretweets_ids;
 	GSList *filters;
 
Index: protocols/twitter/twitter_lib.c
===================================================================
--- protocols/twitter/twitter_lib.c	(revision c9603a38774fb118d4aaa96e170674412ed7328a)
+++ protocols/twitter/twitter_lib.c	(revision 991c75fbf4c4bc0ab2ae6f8b983a092080630b14)
@@ -240,4 +240,6 @@
 
 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_noretweets_ids(struct http_request *req);
 
 /**
@@ -252,4 +254,32 @@
 	args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor);
 	twitter_http(ic, TWITTER_FRIENDS_IDS_URL, twitter_http_get_friends_ids, ic, 0, args, 2);
+
+	g_free(args[1]);
+}
+
+/**
+ * Get the muted users ids.
+ */
+void twitter_get_mutes_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_MUTES_IDS_URL, twitter_http_get_mutes_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)
+{
+	char *args[2];
+
+	args[0] = "cursor";
+	args[1] = g_strdup_printf("%" G_GINT64_FORMAT, next_cursor);
+	twitter_http(ic, TWITTER_NORETWEETS_IDS_URL, twitter_http_get_noretweets_ids, ic, 0, args, 2);
 
 	g_free(args[1]);
@@ -332,4 +362,90 @@
 		twitter_get_users_lookup(ic);
 	}
+
+	txl->list = NULL;
+	txl_free(txl);
+}
+
+/**
+ * Callback for getting the mutes ids.
+ */
+static void twitter_http_get_mutes_ids(struct http_request *req)
+{
+	struct im_connection *ic = req->data;
+	json_value *parsed;
+	struct twitter_xml_list *txl;
+	struct twitter_data *td;
+
+	// Check if the connection is stil active
+	if (!g_slist_find(twitter_connections, ic)) {
+		return;
+	}
+
+	td = ic->proto_data;
+
+	// Parse the data.
+	if (!(parsed = twitter_parse_response(ic, req))) {
+		return;
+	}
+
+	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;
+	if (txl->next_cursor) {
+		/* Recurse while there are still more pages */
+		twitter_get_mutes_ids(ic, txl->next_cursor);
+	}
+
+	txl->list = NULL;
+	txl_free(txl);
+}
+
+/**
+ * Callback for getting the no-retweets ids.
+ */
+static void twitter_http_get_noretweets_ids(struct http_request *req)
+{
+	struct im_connection *ic = req->data;
+	json_value *parsed;
+	struct twitter_xml_list *txl;
+	struct twitter_data *td;
+
+	// Check if the connection is stil active
+	if (!g_slist_find(twitter_connections, ic)) {
+		return;
+	}
+
+	td = ic->proto_data;
+
+	// Parse the data.
+	if (!(parsed = twitter_parse_response(ic, req))) {
+		return;
+	}
+
+	txl = g_new0(struct twitter_xml_list, 1);
+	txl->list = td->noretweets_ids;
+	
+	// Process the retweet ids
+	txl->type = TXL_ID;
+	if (parsed->type == json_array) {
+		unsigned int i;
+		for (i = 0; i < parsed->u.array.length; i++) {
+			json_value *c = parsed->u.array.values[i];
+			if (c->type != json_integer) {
+				continue;
+			}
+			txl->list = g_slist_prepend(txl->list,
+			                            g_strdup_printf("%"PRIu64, c->u.integer));
+		}
+	}
+
+	json_value_free(parsed);
+	td->noretweets_ids = txl->list;
 
 	txl->list = NULL;
@@ -831,6 +947,25 @@
 	struct twitter_data *td = ic->proto_data;
 	char *last_id_str;
+	char *uid_str;
 
 	if (status->user == NULL || status->text == NULL) {
+		return;
+	}
+	
+	/* Check this is not a tweet that should be muted */
+	uid_str = g_strdup_printf("%" PRIu64, status->user->uid);
+	if (getenv("BITLBEE_DEBUG")) {
+		GSList *item;
+		fprintf(stderr, "Checking mutes; this uid=%s\n", uid_str);
+		for (item = td->mutes_ids; item != NULL; item = item->next) {
+			fprintf(stderr, "  id: %s\n", (char *)item->data);
+		}
+	}
+	if (g_slist_find_custom(td->mutes_ids, uid_str, (GCompareFunc)strcmp)) {
+		g_free(uid_str);
+		return;
+	}
+	if (status->id != status->rt_id && g_slist_find_custom(td->noretweets_ids, uid_str, (GCompareFunc)strcmp)) {
+		g_free(uid_str);
 		return;
 	}
@@ -857,4 +992,5 @@
 	set_setstr(&ic->acc->set, "_last_tweet", last_id_str);
 	g_free(last_id_str);
+	g_free(uid_str);
 }
 
@@ -993,4 +1129,6 @@
 	json_value *target = json_o_get(o, "target");
 	const char *type = json_o_str(o, "event");
+	struct twitter_xml_user *us = NULL;
+	struct twitter_xml_user *ut = NULL;
 
 	if (!type || !source || source->type != json_object
@@ -1000,12 +1138,42 @@
 
 	if (strcmp(type, "follow") == 0) {
-		struct twitter_xml_user *us = twitter_xt_get_user(source);
-		struct twitter_xml_user *ut = twitter_xt_get_user(target);
+		us = twitter_xt_get_user(source);
+		ut = twitter_xt_get_user(target);
 		if (g_strcasecmp(us->screen_name, td->user) == 0) {
 			twitter_add_buddy(ic, ut->screen_name, ut->name);
 		}
-		txu_free(us);
-		txu_free(ut);
-	}
+	} else if (strcmp(type, "mute") == 0) {
+		GSList *found;
+		char *uid_str;
+		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);
+		if (getenv("BITLBEE_DEBUG")) {
+			fprintf(stderr, "New mute: %s %"PRIu64"\n",
+			        ut->screen_name, ut->uid);
+		}
+	} else if (strcmp(type, "unmute") == 0) {
+		GSList *found;
+		char *uid_str;
+		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_remove(td->mutes_ids, found);
+		}
+		g_free(uid_str);
+		twitter_log(ic, "Unmuted user %s", ut->screen_name);
+		if (getenv("BITLBEE_DEBUG")) {
+			fprintf(stderr, "New unmute: %s %"PRIu64"\n",
+			        ut->screen_name, ut->uid);
+		}
+	}
+
+	txu_free(us);
+	txu_free(ut);
 
 	return TRUE;
@@ -1524,4 +1692,17 @@
 }
 
+/**
+ * Mute or unmute a user
+ */
+void twitter_mute_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_MUTES_CREATE_URL : TWITTER_MUTES_DESTROY_URL,
+		     twitter_http_post, ic, 1, args, 2);
+}
+
 void twitter_status_destroy(struct im_connection *ic, guint64 id)
 {
Index: protocols/twitter/twitter_lib.h
===================================================================
--- protocols/twitter/twitter_lib.h	(revision c9603a38774fb118d4aaa96e170674412ed7328a)
+++ protocols/twitter/twitter_lib.h	(revision 991c75fbf4c4bc0ab2ae6f8b983a092080630b14)
@@ -63,4 +63,6 @@
 #define TWITTER_FRIENDS_IDS_URL "/friends/ids.json"
 #define TWITTER_FOLLOWERS_IDS_URL "/followers/ids.json"
+#define TWITTER_MUTES_IDS_URL "/mutes/users/ids.json"
+#define TWITTER_NORETWEETS_IDS_URL "/friendships/no_retweets/ids.json"
 
 /* Account URLs */
@@ -76,4 +78,8 @@
 #define TWITTER_BLOCKS_DESTROY_URL "/blocks/destroy/"
 
+/* Mute URLs */
+#define TWITTER_MUTES_CREATE_URL "/mutes/users/create.json"
+#define TWITTER_MUTES_DESTROY_URL "/mutes/users/destroy.json"
+
 /* Report spam */
 #define TWITTER_REPORT_SPAM_URL "/users/report_spam.json"
@@ -87,4 +93,6 @@
 gboolean twitter_get_timeline(struct im_connection *ic, gint64 next_cursor);
 void twitter_get_friends_ids(struct im_connection *ic, gint64 next_cursor);
+void twitter_get_mutes_ids(struct im_connection *ic, gint64 next_cursor);
+void twitter_get_noretweets_ids(struct im_connection *ic, gint64 next_cursor);
 void twitter_get_statuses_friends(struct im_connection *ic, gint64 next_cursor);
 
@@ -92,4 +100,5 @@
 void twitter_direct_messages_new(struct im_connection *ic, char *who, char *message);
 void twitter_friendships_create_destroy(struct im_connection *ic, char *who, int create);
+void twitter_mute_create_destroy(struct im_connection *ic, char *who, int create);
 void twitter_status_destroy(struct im_connection *ic, guint64 id);
 void twitter_status_retweet(struct im_connection *ic, guint64 id);
