Index: protocols/twitter/twitter.c
===================================================================
--- protocols/twitter/twitter.c	(revision 3bd4a9327bb2c7c662e6d385b3bf6903ca8ca09a)
+++ protocols/twitter/twitter.c	(revision f4b0911d037c02f8b9190518b5efda4368dcc25b)
@@ -23,9 +23,9 @@
 
 #include "nogaim.h"
+#include "oauth.h"
 #include "twitter.h"
 #include "twitter_http.h"
 #include "twitter_lib.h"
 
-
 /**
  * Main loop function
@@ -41,5 +41,5 @@
 	// If the user uses multiple private message windows we need to get the 
 	// users buddies.
-	if (!set_getbool( &ic->acc->set, "use_groupchat" ))
+	if (g_strcasecmp(set_getstr(&ic->acc->set, "mode"), "many") == 0)
 		twitter_get_statuses_friends(ic, -1);
 
@@ -51,29 +51,8 @@
 }
 
-
-static void twitter_init( account_t *acc )
-{
-	set_t *s;
-	s = set_add( &acc->set, "use_groupchat", "false", set_eval_bool, acc );
-	s->flags |= ACC_SET_OFFLINE_ONLY;
-}
-
-/**
- * Login method. Since the twitter API works with seperate HTTP request we 
- * only save the user and pass to the twitter_data object.
- */
-static void twitter_login( account_t *acc )
-{
-	struct im_connection *ic = imcb_new( acc );
-	struct twitter_data *td = g_new0( struct twitter_data, 1 );
-
-	twitter_connections = g_slist_append( twitter_connections, ic );
-
-	td->user = acc->user;
-	td->pass = acc->pass;
-	td->home_timeline_id = 0;
-
-	ic->proto_data = td;
-
+static void twitter_main_loop_start( struct im_connection *ic )
+{
+	struct twitter_data *td = ic->proto_data;
+	
 	imcb_log( ic, "Connecting to Twitter" );
 
@@ -86,4 +65,124 @@
 }
 
+
+static struct oauth_service twitter_oauth =
+{
+	"http://api.twitter.com/oauth/request_token",
+	"http://api.twitter.com/oauth/access_token",
+	"http://api.twitter.com/oauth/authorize",
+	.consumer_key = "xsDNKJuNZYkZyMcu914uEA",
+	.consumer_secret = "FCxqcr0pXKzsF9ajmP57S3VQ8V6Drk4o2QYtqMcOszo",
+};
+
+static gboolean twitter_oauth_callback( struct oauth_info *info );
+
+static void twitter_oauth_start( struct im_connection *ic )
+{
+	struct twitter_data *td = ic->proto_data;
+	
+	imcb_log( ic, "Requesting OAuth request token" );
+
+	td->oauth_info = oauth_request_token( &twitter_oauth, twitter_oauth_callback, ic );
+}
+
+static gboolean twitter_oauth_callback( struct oauth_info *info )
+{
+	struct im_connection *ic = info->data;
+	struct twitter_data *td;
+	
+	if( !g_slist_find( twitter_connections, ic ) )
+		return FALSE;
+	
+	td = ic->proto_data;
+	if( info->stage == OAUTH_REQUEST_TOKEN )
+	{
+		char name[strlen(ic->acc->user)+9], *msg;
+		
+		if( info->request_token == NULL )
+		{
+			imcb_error( ic, "OAuth error: %s", info->http->status_string );
+			imc_logout( ic, TRUE );
+			return FALSE;
+		}
+		
+		sprintf( name, "twitter_%s", ic->acc->user );
+		msg = g_strdup_printf( "To finish OAuth authentication, please visit "
+		                       "%s and respond with the resulting PIN code.",
+		                       info->auth_url );
+		imcb_buddy_msg( ic, name, msg, 0, 0 );
+		g_free( msg );
+	}
+	else if( info->stage == OAUTH_ACCESS_TOKEN )
+	{
+		if( info->token == NULL )
+		{
+			imcb_error( ic, "OAuth error: %s", info->http->status_string );
+			imc_logout( ic, TRUE );
+			return FALSE;
+		}
+		
+		/* IM mods didn't do this so far and it's ugly but I should
+		   be able to get away with it... */
+		g_free( ic->acc->pass );
+		ic->acc->pass = oauth_to_string( info );
+		
+		twitter_main_loop_start( ic );
+	}
+	
+	return TRUE;
+}
+
+
+static char *set_eval_mode( set_t *set, char *value )
+{
+	if( g_strcasecmp( value, "one" ) == 0 ||
+	    g_strcasecmp( value, "many" ) == 0 ||
+	    g_strcasecmp( value, "chat" ) == 0 )
+		return value;
+	else
+		return NULL;
+}
+
+static void twitter_init( account_t *acc )
+{
+	set_t *s;
+	
+	s = set_add( &acc->set, "mode", "one", set_eval_mode, acc );
+	s->flags |= ACC_SET_OFFLINE_ONLY;
+	
+	s = set_add( &acc->set, "oauth", "true", set_eval_bool, acc );
+}
+
+/**
+ * Login method. Since the twitter API works with seperate HTTP request we 
+ * only save the user and pass to the twitter_data object.
+ */
+static void twitter_login( account_t *acc )
+{
+	struct im_connection *ic = imcb_new( acc );
+	struct twitter_data *td = g_new0( struct twitter_data, 1 );
+	char name[strlen(acc->user)+9];
+
+	twitter_connections = g_slist_append( twitter_connections, ic );
+	ic->proto_data = td;
+	ic->flags |= OPT_DOES_HTML;
+	
+	td->user = acc->user;
+	if( !set_getbool( &acc->set, "oauth" ) )
+		td->pass = g_strdup( acc->pass );
+	else if( strstr( acc->pass, "oauth_token=" ) )
+		td->oauth_info = oauth_from_string( acc->pass, &twitter_oauth );
+	td->home_timeline_id = 0;
+	
+	sprintf( name, "twitter_%s", acc->user );
+	imcb_add_buddy( ic, name, NULL );
+	imcb_buddy_status( ic, name, OPT_LOGGED_IN, NULL, NULL );
+	
+	if( td->pass || td->oauth_info )
+		twitter_main_loop_start( ic );
+	else
+		twitter_oauth_start( ic );
+}
+
 /**
  * Logout method. Just free the twitter_data.
@@ -104,4 +203,6 @@
 	if( td )
 	{
+		oauth_info_free( td->oauth_info );
+		g_free( td->pass );
 		g_free( td );
 	}
@@ -115,9 +216,26 @@
 static int twitter_buddy_msg( struct im_connection *ic, char *who, char *message, int away )
 {
-	// Let's just update the status.
-//	if ( g_strcasecmp(who, ic->acc->user) == 0 )
-		twitter_post_status(ic, message);
-//	else
-//		twitter_direct_messages_new(ic, who, message);
+	struct twitter_data *td = ic->proto_data;
+	
+	if (g_strncasecmp(who, "twitter_", 8) == 0 &&
+	    g_strcasecmp(who + 8, ic->acc->user) == 0)
+	{
+		if( set_getbool( &ic->acc->set, "oauth" ) &&
+		    td->oauth_info && td->oauth_info->token == NULL )
+		{
+			if( !oauth_access_token( message, td->oauth_info ) )
+			{
+				imcb_error( ic, "OAuth error: %s", "Failed to send access token request" );
+				imc_logout( ic, TRUE );
+				return FALSE;
+			}
+		}
+		else
+			twitter_post_status(ic, message);
+	}
+	else
+	{
+		twitter_direct_messages_new(ic, who, message);
+	}
 	return( 0 );
 }
