Index: protocols/twitter/twitter.c
===================================================================
--- protocols/twitter/twitter.c	(revision daae10fbfe16bac26f74af91faf253d377f1b166)
+++ protocols/twitter/twitter.c	(revision 7b87539aedd967884d4e4eed75d1052a233720eb)
@@ -189,4 +189,6 @@
 	s->flags |= ACC_SET_OFFLINE_ONLY;
 	
+	s = set_add( &acc->set, "commands", "true", set_eval_bool, acc );
+	
 	s = set_add( &acc->set, "message_length", "140", set_eval_int, acc );
 	
@@ -273,4 +275,6 @@
 	twitter_connections = g_slist_remove( twitter_connections, ic );
 }
+
+static void twitter_handle_command( struct im_connection *ic, char *message );
 
 /**
@@ -302,6 +306,6 @@
 			}
 		}
-		else if( twitter_length_check(ic, message) )
-			twitter_post_status(ic, message);
+		else
+			twitter_handle_command(ic, message);
 	}
 	else
@@ -335,26 +339,6 @@
 static void twitter_chat_msg( struct groupchat *c, char *message, int flags )
 {
-	if( c && message && twitter_length_check( c->ic, message ) )
-	{
-		char *s, *new = NULL;
-		
-		if( ( s = strchr( message, ':' ) ) ||
-		    ( s = strchr( message, ',' ) ) )
-		{
-			bee_user_t *bu;
-			
-			new = g_strdup( message );
-			new[s-message] = '\0';
-			if( ( bu = bee_user_by_handle( c->ic->bee, c->ic, new ) ) )
-			{
-				sprintf( new, "@%s", bu->handle );
-				new[s-message+1] = ' ';
-				message = new;
-			}
-		}
-		
-		twitter_post_status( c->ic, message );
-		g_free( new );
-	}
+	if( c && message )
+		twitter_handle_command( c->ic, message );
 }
 
@@ -410,4 +394,77 @@
 //	return value;
 //}
+
+static void twitter_handle_command( struct im_connection *ic, char *message )
+{
+	struct twitter_data *td = ic->proto_data;
+	char *cmds, **cmd;
+	
+	cmds = g_strdup( message );
+	cmd = split_command_parts( cmds );
+	
+	if( cmd[0] == NULL )
+	{
+		g_free( cmds );
+		return;
+	}
+	else if( !set_getbool( &ic->set, "commands" ) )
+	{
+		/* Not supporting commands. */
+	}
+	else if( g_strcasecmp( cmd[0], "undo" ) == 0 )
+	{
+		guint64 id;
+		
+		if( cmd[1] )
+		{
+			char *end = NULL;
+			
+			id = g_ascii_strtoull( cmd[1], &end, 10 );
+			if( end == NULL )
+				id = 0;
+		}
+		else
+			id = td->last_status_id;
+		
+		/* TODO: User feedback. */
+		if( id )
+			twitter_status_destroy( ic, id );
+		
+		g_free( cmds );
+		return;
+	}
+	else if( g_strcasecmp( cmd[0], "post" ) == 0 )
+	{
+		message += 5;
+	}
+	
+	{
+		char *s, *new = NULL;
+		bee_user_t *bu;
+		
+		if( !twitter_length_check( ic, message ) )
+		{
+			g_free( cmds );
+		  	return;
+		}
+		
+		s = cmd[0] + strlen( cmd[0] ) - 1;
+		if( s > cmd[0] && ( *s == ':' || *s == ',' ) )
+		{
+			*s = '\0';
+			
+			if( ( bu = bee_user_by_handle( ic->bee, ic, cmd[0] ) ) )
+			{
+				new = g_strdup_printf( "@%s %s", bu->handle,
+				                       message + ( s - cmd[0] ) + 2 );
+				message = new;
+			}
+		}
+		
+		twitter_post_status( ic, message );
+		g_free( new );
+	}
+	g_free( cmds );
+}
 
 void twitter_initmodule()
Index: protocols/twitter/twitter.h
===================================================================
--- protocols/twitter/twitter.h	(revision daae10fbfe16bac26f74af91faf253d377f1b166)
+++ protocols/twitter/twitter.h	(revision 7b87539aedd967884d4e4eed75d1052a233720eb)
@@ -44,4 +44,5 @@
 	struct oauth_info *oauth_info;
 	guint64 home_timeline_id;
+	guint64 last_status_id; /* For undo */
 	gint main_loop_id;
 	struct groupchat *home_timeline_gc;
Index: protocols/twitter/twitter_lib.c
===================================================================
--- protocols/twitter/twitter_lib.c	(revision daae10fbfe16bac26f74af91faf253d377f1b166)
+++ protocols/twitter/twitter_lib.c	(revision 7b87539aedd967884d4e4eed75d1052a233720eb)
@@ -736,4 +736,5 @@
 {
 	struct im_connection *ic = req->data;
+	struct twitter_data *td;
 
 	// Check if the connection is still active.
@@ -741,4 +742,7 @@
 		return;
 
+	td = ic->proto_data;
+	td->last_status_id = 0;
+	
 	// Check if the HTTP request went well.
 	if (req->status_code != 200) {
@@ -746,4 +750,19 @@
 		imcb_error(ic, "HTTP error: %s", twitter_parse_error(req));
 		return;
+	}
+	
+	if (req->body_size > 0)
+	{
+		struct xt_parser *xp = NULL;
+		struct xt_node *node;
+		
+		xp = xt_new(NULL, NULL);
+		xt_feed(xp, req->reply_body, req->body_size);
+		
+		if ((node = xt_find_node(xp->root, "status")) &&
+		    (node = xt_find_node(node->children, "id")) && node->text)
+			td->last_status_id = g_ascii_strtoull( node->text, NULL, 10 );
+		
+		xt_free(xp);
 	}
 }
@@ -785,2 +804,10 @@
 	twitter_http(ic, create ? TWITTER_FRIENDSHIPS_CREATE_URL : TWITTER_FRIENDSHIPS_DESTROY_URL, twitter_http_post, ic, 1, args, 2);
 }
+
+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");
+	twitter_http(ic, url, twitter_http_post, ic, 1, NULL, 0);
+	g_free(url);
+}
Index: protocols/twitter/twitter_lib.h
===================================================================
--- protocols/twitter/twitter_lib.h	(revision daae10fbfe16bac26f74af91faf253d377f1b166)
+++ protocols/twitter/twitter_lib.h	(revision 7b87539aedd967884d4e4eed75d1052a233720eb)
@@ -84,4 +84,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_status_destroy(struct im_connection *ic, guint64 id);
 
 #endif //_TWITTER_LIB_H
