[gthumb] Flickr: use the OAuth based authentication process



commit eae978899b73eafe08f9313fee7142f8b4c8c981
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Wed Dec 19 12:48:29 2012 +0100

    Flickr: use the OAuth based authentication process

 extensions/23hq/actions.c                          |   14 +-
 extensions/facebook/facebook-service.c             |   12 +-
 extensions/flicker/actions.c                       |   14 +-
 extensions/flicker_utils/Makefile.am               |   12 +-
 extensions/flicker_utils/data/ui/Makefile.am       |    2 -
 .../data/ui/flicker-account-chooser.ui             |   61 --
 .../data/ui/flicker-account-manager.ui             |  115 ---
 extensions/flicker_utils/dlg-export-to-flickr.c    |  110 ++--
 extensions/flicker_utils/dlg-import-from-flickr.c  |   97 +--
 .../flicker_utils/flickr-account-chooser-dialog.c  |  236 ------
 .../flicker_utils/flickr-account-chooser-dialog.h  |   60 --
 .../flicker_utils/flickr-account-manager-dialog.c  |  219 -----
 .../flicker_utils/flickr-account-manager-dialog.h  |   58 --
 extensions/flicker_utils/flickr-account.c          |  167 +++--
 extensions/flicker_utils/flickr-account.h          |   49 +-
 extensions/flicker_utils/flickr-authentication.c   |  706 ----------------
 extensions/flicker_utils/flickr-authentication.h   |   76 --
 extensions/flicker_utils/flickr-connection.c       |  532 ------------
 extensions/flicker_utils/flickr-connection.h       |  107 ---
 extensions/flicker_utils/flickr-consumer.c         |  171 ++++
 extensions/flicker_utils/flickr-consumer.h         |   34 +
 extensions/flicker_utils/flickr-service.c          |  529 ++++++-------
 extensions/flicker_utils/flickr-service.h          |   55 +-
 extensions/flicker_utils/flickr-types.h            |   37 +-
 extensions/flicker_utils/flickr-user.c             |  211 -----
 extensions/flicker_utils/flickr-user.h             |   81 --
 extensions/oauth/Makefile.am                       |   12 +-
 extensions/oauth/oauth-account.c                   |  131 +++-
 extensions/oauth/oauth-account.h                   |   13 +
 ...n-dialog.c => oauth-ask-authorization-dialog.c} |   56 +-
 extensions/oauth/oauth-ask-authorization-dialog.h  |   64 ++
 extensions/oauth/oauth-authentication.c            |  849 --------------------
 extensions/oauth/oauth-authentication.h            |   82 --
 extensions/oauth/oauth-connection.c                |  568 -------------
 extensions/oauth/oauth-connection.h                |  139 ----
 extensions/oauth/oauth-consumer.c                  |   52 ++
 extensions/oauth/oauth-consumer.h                  |   58 ++
 extensions/oauth/oauth-service.c                   |  541 +++++++++++++
 extensions/oauth/oauth-service.h                   |   60 ++
 extensions/oauth/oauth.h                           |    6 +-
 extensions/oauth/oauth2-ask-authorization-dialog.h |   63 --
 extensions/oauth/web-service.c                     |  120 +++-
 extensions/oauth/web-service.h                     |    9 +-
 extensions/photobucket/dlg-export-to-photobucket.c |  109 ++--
 extensions/photobucket/photobucket-account.c       |   11 +-
 extensions/photobucket/photobucket-consumer.c      |  107 +--
 extensions/photobucket/photobucket-consumer.h      |    2 +-
 extensions/photobucket/photobucket-service.c       |  241 ++++--
 extensions/photobucket/photobucket-service.h       |   13 +-
 extensions/picasaweb/picasa-web-service.c          |   12 +-
 po/POTFILES.in                                     |   26 +-
 51 files changed, 2100 insertions(+), 5009 deletions(-)
---
diff --git a/extensions/23hq/actions.c b/extensions/23hq/actions.c
index 31dcb3d..553b6de 100644
--- a/extensions/23hq/actions.c
+++ b/extensions/23hq/actions.c
@@ -30,13 +30,19 @@
 
 static FlickrServer www_23hq_com = {
 	"23",
+	"23",
 	"http://www.23hq.com";,
-	"http://www.23hq.com/services/auth/";,
-	"http://www.23hq.com/services/rest";,
-	"http://www.23hq.com/services/upload/";,
-	"www.23hq.com",
+	"http",
+
+	"http://www.23hq.com/services/oauth/request_token";,
+	"http://www.23hq.com/services/oauth/authorize";,
+	"http://www.23hq.comm/services/oauth/access_token";,
 	"8960706ee7f4151e893b11837e9c24ce",
 	"1ff8d1e45c873423",
+
+	"http://www.23hq.com/services/rest";,
+	"http://www.23hq.com/services/upload";,
+	"www.23hq.com",
 	TRUE
 };
 
diff --git a/extensions/facebook/facebook-service.c b/extensions/facebook/facebook-service.c
index 16b76d4..2d30e21 100644
--- a/extensions/facebook/facebook-service.c
+++ b/extensions/facebook/facebook-service.c
@@ -246,13 +246,13 @@ facebook_utils_parse_response (SoupMessage  *msg,
 
 
 static void
-ask_authorization_dialog_redirected_cb (OAuth2AskAuthorizationDialog *dialog,
-					gpointer                      user_data)
+ask_authorization_dialog_redirected_cb (OAuthAskAuthorizationDialog *dialog,
+					gpointer                     user_data)
 {
 	FacebookService *self = user_data;
 	const char      *uri;
 
-	uri = oauth2_ask_authorization_dialog_get_uri (dialog);
+	uri = oauth_ask_authorization_dialog_get_uri (dialog);
 	if (g_str_has_prefix (uri, FACEBOOK_REDIRECT_URI)) {
 		const char *uri_data;
 		GHashTable *data;
@@ -279,11 +279,11 @@ facebook_service_ask_authorization (WebService *base)
 
 	gth_task_dialog (GTH_TASK (self), TRUE, NULL);
 
-	dialog = oauth2_ask_authorization_dialog_new (facebook_utils_get_authorization_url (WEB_AUTHORIZATION_WRITE));
+	dialog = oauth_ask_authorization_dialog_new (facebook_utils_get_authorization_url (WEB_AUTHORIZATION_WRITE));
 	gtk_window_set_default_size (GTK_WINDOW (dialog), 800, 600);
 	_web_service_set_auth_dialog (WEB_SERVICE (self), GTK_DIALOG (dialog));
 
-	g_signal_connect (OAUTH2_ASK_AUTHORIZATION_DIALOG (dialog),
+	g_signal_connect (OAUTH_ASK_AUTHORIZATION_DIALOG (dialog),
 			  "redirected",
 			  G_CALLBACK (ask_authorization_dialog_redirected_cb),
 			  self);
@@ -315,8 +315,6 @@ facebook_service_get_user_info_ready_cb (SoupSession *session,
 			      "token", _facebook_service_get_access_token (self),
 			      "token-secret", _facebook_service_get_access_token (self),
 			      NULL);
-		web_service_set_current_account (WEB_SERVICE (self), account);
-
 		g_simple_async_result_set_op_res_gpointer (result,
 							   g_object_ref (account),
 							   (GDestroyNotify) g_object_unref);
diff --git a/extensions/flicker/actions.c b/extensions/flicker/actions.c
index 1e180ff..302b205 100644
--- a/extensions/flicker/actions.c
+++ b/extensions/flicker/actions.c
@@ -30,13 +30,19 @@
 
 static FlickrServer www_flickr_com = {
 	"Flickr",
+	"flickr",
 	"http://www.flickr.com";,
-	"http://www.flickr.com/services/auth/";,
-	"http://api.flickr.com/services/rest";,
-	"http://api.flickr.com/services/upload/";,
-	"static.flickr.com",
+	"http",
+
+	"http://www.flickr.com/services/oauth/request_token";,
+	"http://www.flickr.com/services/oauth/authorize";,
+	"http://www.flickr.com/services/oauth/access_token";,
 	"8960706ee7f4151e893b11837e9c24ce",
 	"1ff8d1e45c873423",
+
+	"http://api.flickr.com/services/rest";,
+	"http://api.flickr.com/services/upload";,
+	"static.flickr.com",
 	FALSE
 };
 
diff --git a/extensions/flicker_utils/Makefile.am b/extensions/flicker_utils/Makefile.am
index e2a89bc..5aaad47 100644
--- a/extensions/flicker_utils/Makefile.am
+++ b/extensions/flicker_utils/Makefile.am
@@ -12,14 +12,8 @@ libflicker_utils_la_SOURCES = 			\
 	dlg-import-from-flickr.h		\
 	flickr-account.c			\
 	flickr-account.h			\
-	flickr-account-chooser-dialog.c		\
-	flickr-account-chooser-dialog.h		\
-	flickr-account-manager-dialog.c		\
-	flickr-account-manager-dialog.h		\
-	flickr-authentication.c			\
-	flickr-authentication.h			\
-	flickr-connection.c			\
-	flickr-connection.h			\
+	flickr-consumer.c			\
+	flickr-consumer.h			\
 	flickr-photo.c				\
 	flickr-photo.h				\
 	flickr-photoset.c			\
@@ -27,8 +21,6 @@ libflicker_utils_la_SOURCES = 			\
 	flickr-service.c			\
 	flickr-service.h			\
 	flickr-types.h				\
-	flickr-user.c				\
-	flickr-user.h				\
 	main.c					\
 	preferences.h
 
diff --git a/extensions/flicker_utils/data/ui/Makefile.am b/extensions/flicker_utils/data/ui/Makefile.am
index 7bbbce8..822fa53 100644
--- a/extensions/flicker_utils/data/ui/Makefile.am
+++ b/extensions/flicker_utils/data/ui/Makefile.am
@@ -1,8 +1,6 @@
 uidir = $(pkgdatadir)/ui
 ui_DATA = 					\
 	export-to-flickr.ui			\
-	flicker-account-chooser.ui		\
-	flicker-account-manager.ui		\
 	flicker-ask-authorization.ui		\
 	flicker-complete-authorization.ui	\
 	flicker-export-completed.ui		\
diff --git a/extensions/flicker_utils/dlg-export-to-flickr.c b/extensions/flicker_utils/dlg-export-to-flickr.c
index a15c5c8..a44c550 100644
--- a/extensions/flicker_utils/dlg-export-to-flickr.c
+++ b/extensions/flicker_utils/dlg-export-to-flickr.c
@@ -23,10 +23,9 @@
 #include <gtk/gtk.h>
 #include <gthumb.h>
 #include "dlg-export-to-flickr.h"
-#include "flickr-authentication.h"
+#include "flickr-account.h"
 #include "flickr-photoset.h"
 #include "flickr-service.h"
-#include "flickr-user.h"
 #include "preferences.h"
 
 
@@ -59,10 +58,7 @@ typedef struct {
 	GtkWidget            *list_view;
 	GtkWidget            *progress_dialog;
 	GtkWidget            *photoset_combobox;
-	FlickrConnection     *conn;
-	FlickrAuthentication *auth;
 	FlickrService        *service;
-	FlickrUser           *user;
 	GList                *photosets;
 	FlickrPhotoset       *photoset;
 	GList                *photos_ids;
@@ -75,16 +71,13 @@ destroy_dialog (DialogData *data)
 {
 	if (data->dialog != NULL)
 		gtk_widget_destroy (data->dialog);
-	if (data->conn != NULL)
-		gth_task_completed (GTH_TASK (data->conn), NULL);
+	if (data->service != NULL)
+		gth_task_completed (GTH_TASK (data->service), NULL);
 	_g_object_unref (data->cancellable);
 	_g_string_list_free (data->photos_ids);
 	_g_object_unref (data->photoset);
 	_g_object_list_unref (data->photosets);
-	_g_object_unref (data->user);
 	_g_object_unref (data->service);
-	_g_object_unref (data->auth);
-	_g_object_unref (data->conn);
 	_g_object_unref (data->builder);
 	_g_object_list_unref (data->file_list);
 	_g_object_unref (data->location);
@@ -109,13 +102,16 @@ completed_messagedialog_response_cb (GtkDialog *dialog,
 
 	case _OPEN_IN_BROWSER_RESPONSE:
 		{
-			GdkScreen *screen;
-			char      *url = NULL;
-			GError    *error = NULL;
+			GdkScreen    *screen;
+			OAuthAccount *account;
+			char         *url = NULL;
+			GError       *error = NULL;
 
 			screen = gtk_widget_get_screen (GTK_WIDGET (dialog));
 			gtk_widget_destroy (GTK_WIDGET (dialog));
 
+			account = web_service_get_current_account (WEB_SERVICE (data->service));
+
 			if (data->photoset == NULL) {
 				GString *ids;
 				GList   *scan;
@@ -133,11 +129,11 @@ completed_messagedialog_response_cb (GtkDialog *dialog,
 			else if (data->photoset->url != NULL)
 				url = g_strdup (data->photoset->url);
 			else if (data->photoset->id != NULL)
-				url = g_strconcat (data->server->url, "/photos/", data->user->id, "/sets/", data->photoset->id, NULL);
+				url = g_strconcat (data->server->url, "/photos/", account->id, "/sets/", data->photoset->id, NULL);
 
 			if ((url != NULL) && ! gtk_show_uri (screen, url, 0, &error)) {
-				if (data->conn != NULL)
-					gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+				if (data->service != NULL)
+					gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 				_gtk_error_dialog_from_gerror_run (GTK_WINDOW (data->browser), _("Could not connect to the server"), error);
 				g_clear_error (&error);
 			}
@@ -159,7 +155,7 @@ export_completed_with_success (DialogData *data)
 	GtkBuilder *builder;
 	GtkWidget  *dialog;
 
-	gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+	gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 
 	builder = _gtk_builder_new_from_file ("flicker-export-completed.ui", "flicker_utils");
 	dialog = _gtk_builder_get_widget (builder, "completed_messagedialog");
@@ -308,7 +304,7 @@ export_dialog_response_cb (GtkDialog *dialog,
 			int         max_height;
 
 			gtk_widget_hide (data->dialog);
-			gth_task_dialog (GTH_TASK (data->conn), FALSE, NULL);
+			gth_task_dialog (GTH_TASK (data->service), FALSE, NULL);
 
 			data->photoset = NULL;
 			photoset_title = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (data->photoset_combobox))));
@@ -361,40 +357,40 @@ export_dialog_response_cb (GtkDialog *dialog,
 static void
 update_account_list (DialogData *data)
 {
-	int            current_account_idx;
-	FlickrAccount *current_account;
-	int            idx;
-	GList         *scan;
-	GtkTreeIter    iter;
-	char          *free_space;
+	int           current_account_idx;
+	OAuthAccount *current_account;
+	int           idx;
+	GList        *scan;
+	GtkTreeIter   iter;
+	char         *free_space;
 
 	gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("account_liststore")));
 
 	current_account_idx = 0;
-	current_account = flickr_authentication_get_account (data->auth);
-	for (scan = flickr_authentication_get_accounts (data->auth), idx = 0; scan; scan = scan->next, idx++) {
-		FlickrAccount *account = scan->data;
+	current_account = web_service_get_current_account (WEB_SERVICE (data->service));
+	for (scan = web_service_get_accounts (WEB_SERVICE (data->service)), idx = 0; scan; scan = scan->next, idx++) {
+		OAuthAccount *account = scan->data;
 
-		if ((current_account != NULL) && (g_strcmp0 (current_account->username, account->username) == 0))
+		if (oauth_account_cmp (current_account, account) == 0)
 			current_account_idx = idx;
 
 		gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("account_liststore")), &iter);
 		gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("account_liststore")), &iter,
 				    ACCOUNT_DATA_COLUMN, account,
-				    ACCOUNT_NAME_COLUMN, account->username,
+				    ACCOUNT_NAME_COLUMN, account->name,
 				    -1);
 	}
 	gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("account_combobox")), current_account_idx);
 
-	free_space = g_format_size (data->user->max_bandwidth - data->user->used_bandwidth);
+	free_space = g_format_size (FLICKR_ACCOUNT (current_account)->max_bandwidth - FLICKR_ACCOUNT (current_account)->used_bandwidth);
 	gtk_label_set_text (GTK_LABEL (GET_WIDGET ("free_space_label")), free_space);
 	g_free (free_space);
 }
 
 
 static void
-authentication_accounts_changed_cb (FlickrAuthentication *auth,
-				    gpointer              user_data)
+authentication_accounts_changed_cb (WebService *service,
+				    gpointer    user_data)
 {
 	update_account_list ((DialogData *) user_data);
 }
@@ -412,8 +408,8 @@ photoset_list_ready_cb (GObject      *source_object,
 	_g_object_list_unref (data->photosets);
 	data->photosets = flickr_service_list_photosets_finish (FLICKR_SERVICE (source_object), res, &error);
 	if (error != NULL) {
-		if (data->conn != NULL)
-			gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+		if (data->service != NULL)
+			gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 		_gtk_error_dialog_from_gerror_run (GTK_WINDOW (data->browser), _("Could not connect to the server"), error);
 		g_clear_error (&error);
 		gtk_dialog_response (GTK_DIALOG (data->dialog), GTK_RESPONSE_DELETE_EVENT);
@@ -441,7 +437,7 @@ photoset_list_ready_cb (GObject      *source_object,
 
 	gtk_widget_set_sensitive (GET_WIDGET ("upload_button"), TRUE);
 
-	gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+	gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 
 	gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (data->browser));
 	gtk_window_set_modal (GTK_WINDOW (data->dialog), FALSE);
@@ -450,16 +446,11 @@ photoset_list_ready_cb (GObject      *source_object,
 
 
 static void
-authentication_ready_cb (FlickrAuthentication *auth,
-			 FlickrUser           *user,
-			 DialogData           *data)
+authentication_ready_cb (WebService *service,
+			 DialogData *data)
 {
-	_g_object_unref (data->user);
-	data->user = g_object_ref (user);
 	update_account_list (data);
-
 	flickr_service_list_photosets (data->service,
-				       NULL,
 				       data->cancellable,
 				       photoset_list_ready_cb,
 				       data);
@@ -470,7 +461,7 @@ static void
 edit_accounts_button_clicked_cb (GtkButton  *button,
 				 DialogData *data)
 {
-	flickr_authentication_edit_accounts (data->auth, GTK_WINDOW (data->dialog));
+	web_service_edit_accounts (WEB_SERVICE (data->service), GTK_WINDOW (data->dialog));
 }
 
 
@@ -478,9 +469,9 @@ static void
 account_combobox_changed_cb (GtkComboBox *widget,
 			     gpointer     user_data)
 {
-	DialogData    *data = user_data;
-	GtkTreeIter    iter;
-	FlickrAccount *account;
+	DialogData   *data = user_data;
+	GtkTreeIter   iter;
+	OAuthAccount *account;
 
 	if (! gtk_combo_box_get_active_iter (widget, &iter))
 		return;
@@ -490,8 +481,8 @@ account_combobox_changed_cb (GtkComboBox *widget,
 			    ACCOUNT_DATA_COLUMN, &account,
 			    -1);
 
-	if (flickr_account_cmp (account, flickr_authentication_get_account (data->auth)) != 0)
-		flickr_authentication_connect (data->auth, account);
+	if (oauth_account_cmp (account, web_service_get_current_account (WEB_SERVICE (data->service))) != 0)
+		web_service_connect (WEB_SERVICE (data->service), OAUTH_ACCOUNT (account));
 
 	g_object_unref (account);
 }
@@ -656,24 +647,21 @@ dlg_export_to_flickr (FlickrServer *server,
 
 	update_sensitivity (data);
 
-	data->conn = flickr_connection_new (data->server);
-	data->service = flickr_service_new (data->conn);
-	data->auth = flickr_authentication_new (data->conn,
-						data->service,
-						data->cancellable,
-						GTK_WIDGET (data->browser),
-						data->dialog);
-	g_signal_connect (data->auth,
-			  "ready",
+	data->service = flickr_service_new (server,
+					    data->cancellable,
+					    GTK_WIDGET (data->browser),
+					    data->dialog);
+	g_signal_connect (data->service,
+			  "account-ready",
 			  G_CALLBACK (authentication_ready_cb),
 			  data);
-	g_signal_connect (data->auth,
-			  "accounts_changed",
+	g_signal_connect (data->service,
+			  "accounts-changed",
 			  G_CALLBACK (authentication_accounts_changed_cb),
 			  data);
 
 	data->progress_dialog = gth_progress_dialog_new (GTK_WINDOW (data->browser));
-	gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (data->progress_dialog), GTH_TASK (data->conn));
+	gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (data->progress_dialog), GTH_TASK (data->service));
 
-	flickr_authentication_auto_connect (data->auth);
+	web_service_autoconnect (WEB_SERVICE (data->service));
 }
diff --git a/extensions/flicker_utils/dlg-import-from-flickr.c b/extensions/flicker_utils/dlg-import-from-flickr.c
index 7615fc1..3ca344c 100644
--- a/extensions/flicker_utils/dlg-import-from-flickr.c
+++ b/extensions/flicker_utils/dlg-import-from-flickr.c
@@ -25,12 +25,11 @@
 #include <gthumb.h>
 #include <extensions/importer/importer.h>
 #include "dlg-import-from-flickr.h"
-#include "flickr-authentication.h"
+#include "flickr-account.h"
 #include "flickr-photo.h"
 #include "flickr-photoset.h"
 #include "flickr-service.h"
 #include "flickr-types.h"
-#include "flickr-user.h"
 
 
 #define GET_WIDGET(x) (_gtk_builder_get_widget (data->builder, (x)))
@@ -59,11 +58,8 @@ typedef struct {
 	GtkWidget            *dialog;
 	GtkWidget            *preferences_dialog;
 	GtkWidget            *progress_dialog;
-	FlickrConnection     *conn;
-	FlickrAuthentication *auth;
 	FlickrService        *service;
 	GtkWidget            *file_list;
-	FlickrUser           *user;
 	GList                *photosets;
 	FlickrPhotoset       *photoset;
 	GList                *photos;
@@ -75,13 +71,10 @@ static void
 import_dialog_destroy_cb (GtkWidget  *widget,
 			  DialogData *data)
 {
-	if (data->conn != NULL)
-		gth_task_completed (GTH_TASK (data->conn), NULL);
+	if (data->service != NULL)
+		gth_task_completed (GTH_TASK (data->service), NULL);
 	_g_object_unref (data->cancellable);
-	_g_object_unref (data->conn);
 	_g_object_unref (data->service);
-	_g_object_unref (data->auth);
-	_g_object_unref (data->user);
 	_g_object_list_unref (data->photosets);
 	_g_object_unref (data->photoset);
 	_g_object_list_unref (data->photos);
@@ -194,26 +187,26 @@ import_dialog_response_cb (GtkDialog *dialog,
 static void
 update_account_list (DialogData *data)
 {
-	int            current_account_idx;
-	FlickrAccount *current_account;
-	int            idx;
-	GList         *scan;
-	GtkTreeIter    iter;
+	int           current_account_idx;
+	OAuthAccount *current_account;
+	int           idx;
+	GList        *scan;
+	GtkTreeIter   iter;
 
 	gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("account_liststore")));
 
 	current_account_idx = 0;
-	current_account = flickr_authentication_get_account (data->auth);
-	for (scan = flickr_authentication_get_accounts (data->auth), idx = 0; scan; scan = scan->next, idx++) {
-		FlickrAccount *account = scan->data;
+	current_account = web_service_get_current_account (WEB_SERVICE (data->service));
+	for (scan = web_service_get_accounts (WEB_SERVICE (data->service)), idx = 0; scan; scan = scan->next, idx++) {
+		OAuthAccount *account = scan->data;
 
-		if ((current_account != NULL) && (g_strcmp0 (current_account->username, account->username) == 0))
+		if (oauth_account_cmp (current_account, account) == 0)
 			current_account_idx = idx;
 
 		gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("account_liststore")), &iter);
 		gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("account_liststore")), &iter,
 				    ACCOUNT_DATA_COLUMN, account,
-				    ACCOUNT_NAME_COLUMN, account->username,
+				    ACCOUNT_NAME_COLUMN, account->name,
 				    -1);
 	}
 	gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("account_combobox")), current_account_idx);
@@ -232,8 +225,8 @@ photoset_list_ready_cb (GObject      *source_object,
 	_g_object_list_unref (data->photosets);
 	data->photosets = flickr_service_list_photosets_finish (FLICKR_SERVICE (source_object), res, &error);
 	if (error != NULL) {
-		if (data->conn != NULL)
-			gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+		if (data->service != NULL)
+			gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 		_gtk_error_dialog_from_gerror_run (GTK_WINDOW (data->browser), _("Could not connect to the server"), error);
 		g_clear_error (&error);
 		gtk_widget_destroy (data->dialog);
@@ -259,7 +252,7 @@ photoset_list_ready_cb (GObject      *source_object,
 		g_free (n_photos);
 	}
 
-	gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+	gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 
 	gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (data->browser));
 	gtk_window_set_modal (GTK_WINDOW (data->dialog), FALSE);
@@ -268,16 +261,11 @@ photoset_list_ready_cb (GObject      *source_object,
 
 
 static void
-authentication_ready_cb (FlickrAuthentication *auth,
-			 FlickrUser           *user,
-			 DialogData           *data)
+authentication_ready_cb (WebService *service,
+			 DialogData *data)
 {
-	_g_object_unref (data->user);
-	data->user = g_object_ref (user);
 	update_account_list (data);
-
 	flickr_service_list_photosets (data->service,
-				       NULL,
 				       data->cancellable,
 				       photoset_list_ready_cb,
 				       data);
@@ -285,10 +273,10 @@ authentication_ready_cb (FlickrAuthentication *auth,
 
 
 static void
-authentication_accounts_changed_cb (FlickrAuthentication *auth,
-				    gpointer              user_data)
+authentication_accounts_changed_cb (WebService *service,
+				    DialogData *data)
 {
-	update_account_list ((DialogData *) user_data);
+	update_account_list (data);
 }
 
 
@@ -296,7 +284,7 @@ static void
 edit_accounts_button_clicked_cb (GtkButton  *button,
 				 DialogData *data)
 {
-	flickr_authentication_edit_accounts (data->auth, GTK_WINDOW (data->dialog));
+	web_service_edit_accounts (WEB_SERVICE (data->service), GTK_WINDOW (data->dialog));
 }
 
 
@@ -304,9 +292,9 @@ static void
 account_combobox_changed_cb (GtkComboBox *widget,
 			     gpointer     user_data)
 {
-	DialogData    *data = user_data;
-	GtkTreeIter    iter;
-	FlickrAccount *account;
+	DialogData   *data = user_data;
+	GtkTreeIter   iter;
+	OAuthAccount *account;
 
 	if (! gtk_combo_box_get_active_iter (widget, &iter))
 		return;
@@ -316,8 +304,8 @@ account_combobox_changed_cb (GtkComboBox *widget,
 			    ACCOUNT_DATA_COLUMN, &account,
 			    -1);
 
-	if (flickr_account_cmp (account, flickr_authentication_get_account (data->auth)) != 0)
-		flickr_authentication_connect (data->auth, account);
+	if (oauth_account_cmp (account, web_service_get_current_account (WEB_SERVICE (data->service))) != 0)
+		web_service_connect (WEB_SERVICE (data->service), account);
 
 	g_object_unref (account);
 }
@@ -350,13 +338,13 @@ list_photos_ready_cb (GObject      *source_object,
 	GList      *list;
 	GList      *scan;
 
-	gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+	gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 
 	_g_object_list_unref (data->photos);
 	data->photos = flickr_service_list_photos_finish (data->service, result, &error);
 	if (error != NULL) {
-		if (data->conn != NULL)
-			gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+		if (data->service != NULL)
+			gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not get the photo list"), error);
 		g_clear_error (&error);
 		gtk_widget_destroy (data->dialog);
@@ -406,7 +394,7 @@ photoset_combobox_changed_cb (GtkComboBox *widget,
 
 	gth_import_preferences_dialog_set_event (GTH_IMPORT_PREFERENCES_DIALOG (data->preferences_dialog), data->photoset->title);
 
-	gth_task_dialog (GTH_TASK (data->conn), FALSE, NULL);
+	gth_task_dialog (GTH_TASK (data->service), FALSE, NULL);
 	flickr_service_list_photos (data->service,
 				    data->photoset,
 				    "original_format, url_sq, url_t, url_s, url_m, url_z, url_b, url_o",
@@ -617,24 +605,21 @@ dlg_import_from_flickr (FlickrServer *server,
 	update_selection_status (data);
 	gth_import_preferences_dialog_set_event (GTH_IMPORT_PREFERENCES_DIALOG (data->preferences_dialog), "");
 
-	data->conn = flickr_connection_new (data->server);
-	data->service = flickr_service_new (data->conn);
-	data->auth = flickr_authentication_new (data->conn,
-						data->service,
-						data->cancellable,
-						GTK_WIDGET (data->browser),
-						data->dialog);
-	g_signal_connect (data->auth,
-			  "ready",
+	data->service = flickr_service_new (server,
+					    data->cancellable,
+					    GTK_WIDGET (data->browser),
+					    data->dialog);
+	g_signal_connect (data->service,
+			  "account-ready",
 			  G_CALLBACK (authentication_ready_cb),
 			  data);
-	g_signal_connect (data->auth,
-			  "accounts_changed",
+	g_signal_connect (data->service,
+			  "accounts-changed",
 			  G_CALLBACK (authentication_accounts_changed_cb),
 			  data);
 
 	data->progress_dialog = gth_progress_dialog_new (GTK_WINDOW (data->browser));
-	gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (data->progress_dialog), GTH_TASK (data->conn));
+	gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (data->progress_dialog), GTH_TASK (data->service));
 
-	flickr_authentication_auto_connect (data->auth);
+	web_service_autoconnect (WEB_SERVICE (data->service));
 }
diff --git a/extensions/flicker_utils/flickr-account.c b/extensions/flicker_utils/flickr-account.c
index b6b8aa0..a9ed6b8 100644
--- a/extensions/flicker_utils/flickr-account.c
+++ b/extensions/flicker_utils/flickr-account.c
@@ -3,7 +3,7 @@
 /*
  *  GThumb
  *
- *  Copyright (C) 2010 Free Software Foundation, Inc.
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -22,10 +22,7 @@
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
-#ifdef HAVE_LIBSECRET
-#include <libsecret/secret.h>
-#endif /* HAVE_LIBSECRET */
-#include <gthumb.h>
+#include <extensions/oauth/oauth.h>
 #include "flickr-account.h"
 
 
@@ -34,7 +31,7 @@ static void flickr_account_dom_domizable_interface_init (DomDomizableInterface *
 
 G_DEFINE_TYPE_WITH_CODE (FlickrAccount,
 			 flickr_account,
-			 G_TYPE_OBJECT,
+			 OAUTH_TYPE_ACCOUNT,
 			 G_IMPLEMENT_INTERFACE (DOM_TYPE_DOMIZABLE,
 					        flickr_account_dom_domizable_interface_init))
 
@@ -46,8 +43,7 @@ flickr_account_finalize (GObject *obj)
 
 	self = FLICKR_ACCOUNT (obj);
 
-	g_free (self->username);
-	g_free (self->token);
+	g_free (self->accountname);
 
 	G_OBJECT_CLASS (flickr_account_parent_class)->finalize (obj);
 }
@@ -60,50 +56,22 @@ flickr_account_class_init (FlickrAccountClass *klass)
 }
 
 
-static DomElement*
-flickr_account_create_element (DomDomizable *base,
+static DomElement *
+flickr_account_create_element (DomDomizable *self,
 			       DomDocument  *doc)
 {
-	FlickrAccount *self;
-	DomElement    *element;
-	gboolean       set_token;
-
-	self = FLICKR_ACCOUNT (base);
-
-	element = dom_document_create_element (doc, "account", NULL);
-	if (self->username != NULL)
-		dom_element_set_attribute (element, "username", self->username);
-
-	/* Don't save the token in the configuration file if the keyring is
-	 * available. */
-
-#ifdef HAVE_LIBSECRET
-	set_token = FALSE;
-#else
-	set_token = TRUE;
-#endif
-
-	if (set_token && (self->token != NULL))
-		dom_element_set_attribute (element, "token", self->token);
-
-	if (self->is_default)
-		dom_element_set_attribute (element, "default", "1");
-
-	return element;
+	return oauth_account_create_element (self, doc);
 }
 
 
 static void
 flickr_account_load_from_element (DomDomizable *base,
-			          DomElement   *element)
+				  DomElement   *element)
 {
-	FlickrAccount *self;
-
-	self = FLICKR_ACCOUNT (base);
+	FlickrAccount *self = FLICKR_ACCOUNT (base);
 
-	flickr_account_set_username (self, dom_element_get_attribute (element, "username"));
-	flickr_account_set_token (self, dom_element_get_attribute (element, "token"));
-	self->is_default = (g_strcmp0 (dom_element_get_attribute (element, "default"), "1") == 0);
+	oauth_account_load_from_element (base, element);
+	flickr_account_load_extra_data (self, element);
 }
 
 
@@ -118,11 +86,18 @@ flickr_account_dom_domizable_interface_init (DomDomizableInterface *iface)
 static void
 flickr_account_init (FlickrAccount *self)
 {
-	/* void */
+	self->is_pro = FALSE;
+	self->accountname = NULL;
+	self->max_bandwidth = 0;
+	self->used_bandwidth = 0;
+	self->max_filesize = 0;
+	self->max_videosize = 0;
+	self->n_sets = 0;
+	self->n_videos = 0;
 }
 
 
-FlickrAccount *
+OAuthAccount *
 flickr_account_new (void)
 {
 	return g_object_new (FLICKR_TYPE_ACCOUNT, NULL);
@@ -130,39 +105,103 @@ flickr_account_new (void)
 
 
 void
-flickr_account_set_username (FlickrAccount *self,
-			     const char    *value)
+flickr_account_set_is_pro (FlickrAccount *self,
+			   const char    *value)
+{
+	self->is_pro = (g_strcmp0 (value, "1") == 0);
+}
+
+
+void
+flickr_account_set_accountname (FlickrAccount *self,
+				const char    *value)
+{
+	_g_strset (&self->accountname, value);
+}
+
+
+void
+flickr_account_set_max_bandwidth (FlickrAccount *self,
+				  const char    *value)
+{
+	self->max_bandwidth = g_ascii_strtoull (value, NULL, 10);
+}
+
+
+void
+flickr_account_set_used_bandwidth (FlickrAccount *self,
+				   const char    *value)
+{
+	self->used_bandwidth = g_ascii_strtoull (value, NULL, 10);
+}
+
+
+void
+flickr_account_set_max_filesize (FlickrAccount *self,
+				 const char    *value)
 {
-	_g_strset (&self->username, value);
+	self->max_filesize = g_ascii_strtoull (value, NULL, 10);
 }
 
 
 void
-flickr_account_set_token (FlickrAccount *self,
-			  const char    *value)
+flickr_account_set_max_videosize (FlickrAccount *self,
+				  const char    *value)
 {
-	_g_strset (&self->token, value);
+	self->max_videosize = g_ascii_strtoull (value, NULL, 10);
 }
 
 
 void
-flickr_account_reset (FlickrAccount *self)
+flickr_account_set_n_sets (FlickrAccount *self,
+			   const char    *value)
 {
-	flickr_account_set_username (self, NULL);
-	flickr_account_set_token (self, NULL);
+	if (value != NULL)
+		self->n_sets = atoi (value);
+	else
+		self->n_sets = 0;
 }
 
 
-int
-flickr_account_cmp (FlickrAccount *a,
-		    FlickrAccount *b)
+void
+flickr_account_set_n_videos (FlickrAccount *self,
+			     const char    *value)
 {
-	if ((a == NULL) && (b == NULL))
-		return 0;
-	else if (a == NULL)
-		return 1;
-	else if (b == NULL)
-		return -1;
+	if (value != NULL)
+		self->n_videos = atoi (value);
 	else
-		return g_strcmp0 (a->username, b->username);
+		self->n_videos = 0;
+}
+
+
+void
+flickr_account_load_extra_data (FlickrAccount *self,
+				DomElement    *element)
+{
+	DomElement *node;
+
+	flickr_account_set_is_pro (self, dom_element_get_attribute (element, "ispro"));
+
+	for (node = element->first_child; node; node = node->next_sibling) {
+		if (g_strcmp0 (node->tag_name, "accountname") == 0) {
+			flickr_account_set_accountname (self, dom_element_get_inner_text (node));
+		}
+		else if (g_strcmp0 (node->tag_name, "bandwidth") == 0) {
+			flickr_account_set_max_bandwidth (self, dom_element_get_attribute (node, "maxbytes"));
+			flickr_account_set_used_bandwidth (self, dom_element_get_attribute (node, "usedbytes"));
+		}
+		else if (g_strcmp0 (node->tag_name, "filesize") == 0) {
+			flickr_account_set_max_filesize (self, dom_element_get_attribute (node, "maxbytes"));
+		}
+		else if (g_strcmp0 (node->tag_name, "videosize") == 0) {
+			flickr_account_set_max_videosize (self, dom_element_get_attribute (node, "maxbytes"));
+		}
+		else if (g_strcmp0 (node->tag_name, "sets") == 0) {
+			flickr_account_set_n_sets (self, dom_element_get_attribute (node, "created"));
+		}
+		else if (g_strcmp0 (node->tag_name, "videos") == 0) {
+			flickr_account_set_n_videos (self, dom_element_get_attribute (node, "uploaded"));
+		}
+	}
+
 }
diff --git a/extensions/flicker_utils/flickr-account.h b/extensions/flicker_utils/flickr-account.h
index 712ad5c..f060412 100644
--- a/extensions/flicker_utils/flickr-account.h
+++ b/extensions/flicker_utils/flickr-account.h
@@ -3,7 +3,7 @@
 /*
  *  GThumb
  *
- *  Copyright (C) 2010 Free Software Foundation, Inc.
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
+#include <extensions/oauth/oauth.h>
 
 G_BEGIN_DECLS
 
@@ -36,30 +37,44 @@ G_BEGIN_DECLS
 
 typedef struct _FlickrAccount FlickrAccount;
 typedef struct _FlickrAccountClass FlickrAccountClass;
-typedef struct _FlickrAccountPrivate FlickrAccountPrivate;
 
 struct _FlickrAccount {
-	GObject parent_instance;
-	FlickrAccountPrivate *priv;
+	OAuthAccount parent_instance;
 
-	char     *username;
-	char     *token;
-	gboolean  is_default;
+	gboolean  is_pro;
+	char     *accountname;
+	goffset   max_bandwidth;
+	goffset   used_bandwidth;
+	goffset   max_filesize;
+	goffset   max_videosize;
+	int       n_sets;
+	int       n_videos;
 };
 
 struct _FlickrAccountClass {
-	GObjectClass parent_class;
+	OAuthAccountClass parent_class;
 };
 
-GType             flickr_account_get_type       (void);
-FlickrAccount *   flickr_account_new            (void);
-void              flickr_account_set_username   (FlickrAccount *self,
-						 const char    *value);
-void              flickr_account_set_token      (FlickrAccount *self,
-						 const char    *value);
-void              flickr_account_reset          (FlickrAccount *self);
-int               flickr_account_cmp            (FlickrAccount *a,
-						 FlickrAccount *b);
+GType             flickr_account_get_type		(void);
+OAuthAccount *    flickr_account_new			(void);
+void              flickr_account_set_is_pro		(FlickrAccount *self,
+							 const char    *value);
+void              flickr_account_set_accountname	(FlickrAccount *self,
+							 const char    *value);
+void              flickr_account_set_max_bandwidth	(FlickrAccount *self,
+							 const char    *value);
+void              flickr_account_set_used_bandwidth	(FlickrAccount *self,
+							 const char    *value);
+void              flickr_account_set_max_filesize	(FlickrAccount *self,
+							 const char    *value);
+void              flickr_account_set_max_videosize	(FlickrAccount *self,
+							 const char    *value);
+void              flickr_account_set_n_sets		(FlickrAccount *self,
+							 const char    *value);
+void              flickr_account_set_n_videos		(FlickrAccount *self,
+							 const char    *value);
+void              flickr_account_load_extra_data        (FlickrAccount *self,
+							 DomElement    *element);
 
 G_END_DECLS
 
diff --git a/extensions/flicker_utils/flickr-consumer.c b/extensions/flicker_utils/flickr-consumer.c
new file mode 100644
index 0000000..5273f86
--- /dev/null
+++ b/extensions/flicker_utils/flickr-consumer.c
@@ -0,0 +1,171 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gthumb.h>
+#include "flickr-account.h"
+#include "flickr-consumer.h"
+#include "flickr-service.h"
+
+
+gboolean
+flickr_utils_parse_response (SoupBuffer   *body,
+			     DomDocument **doc_p,
+			     GError      **error)
+{
+	DomDocument *doc;
+	DomElement  *node;
+
+	doc = dom_document_new ();
+	if (! dom_document_load (doc, body->data, body->length, error)) {
+		g_object_unref (doc);
+		return FALSE;
+	}
+
+	for (node = DOM_ELEMENT (doc)->first_child; node; node = node->next_sibling) {
+		if (g_strcmp0 (node->tag_name, "rsp") == 0) {
+			if (g_strcmp0 (dom_element_get_attribute (node, "stat"), "ok") != 0) {
+				DomElement *child;
+
+				for (child = node->first_child; child; child = child->next_sibling) {
+					if (g_strcmp0 (child->tag_name, "err") == 0) {
+						*error = g_error_new_literal (WEB_SERVICE_ERROR,
+									      atoi (dom_element_get_attribute (child, "code")),
+									      dom_element_get_attribute (child, "msg"));
+					}
+				}
+
+				g_object_unref (doc);
+				return FALSE;
+			}
+		}
+	}
+
+	*doc_p = doc;
+
+	return TRUE;
+}
+
+
+static void
+flickr_request_token_response (OAuthService       *self,
+			       SoupMessage        *msg,
+			       SoupBuffer         *body,
+			       GSimpleAsyncResult *result)
+{
+	GHashTable *values;
+	char       *token;
+	char       *token_secret;
+
+	values = soup_form_decode (body->data);
+	token = g_hash_table_lookup (values, "oauth_token");
+	token_secret = g_hash_table_lookup (values, "oauth_token_secret");
+	if ((token != NULL) && (token_secret != NULL)) {
+		oauth_service_set_token (self, token);
+		oauth_service_set_token_secret (self, token_secret);
+		g_simple_async_result_set_op_res_gboolean (result, TRUE);
+	}
+	else {
+		GError *error;
+
+		error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
+		g_simple_async_result_set_from_error (result, error);
+	}
+
+	g_hash_table_destroy (values);
+}
+
+
+static char *
+flickr_get_authorization_url (OAuthService *self)
+{
+	FlickrServer *server;
+	char         *escaped_token;
+	char         *uri;
+
+	server = flickr_service_get_server (FLICKR_SERVICE (self));
+	escaped_token = soup_uri_encode (oauth_service_get_token (self), NULL);
+	uri = g_strconcat (server->authorization_url,
+			   "?oauth_token=", escaped_token,
+			   "&perms=write",
+			   NULL);
+
+	g_free (escaped_token);
+
+	return uri;
+}
+
+
+static void
+flickr_access_token_response (OAuthService       *self,
+			      SoupMessage        *msg,
+			      SoupBuffer         *body,
+			      GSimpleAsyncResult *result)
+{
+	GHashTable *values;
+	char       *username;
+	char       *token;
+	char       *token_secret;
+
+	values = soup_form_decode (body->data);
+
+	username = g_hash_table_lookup (values, "username");
+	token = g_hash_table_lookup (values, "oauth_token");
+	token_secret = g_hash_table_lookup (values, "oauth_token_secret");
+	if ((username != NULL) && (token != NULL) && (token_secret != NULL)) {
+		FlickrAccount *account;
+
+		oauth_service_set_token (OAUTH_SERVICE (self), token);
+		oauth_service_set_token_secret (OAUTH_SERVICE (self), token_secret);
+
+		account = g_object_new (FLICKR_TYPE_ACCOUNT,
+					"id", g_hash_table_lookup (values, "user_nsid"),
+					"name", username,
+					"token", token,
+					"token-secret", token_secret,
+					NULL);
+		web_service_set_current_account (WEB_SERVICE (self), OAUTH_ACCOUNT (account));
+
+		g_simple_async_result_set_op_res_gpointer (result, account, g_object_unref);
+	}
+	else {
+		GError *error;
+
+		error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
+		g_simple_async_result_set_from_error (result, error);
+	}
+
+	g_hash_table_destroy (values);
+}
+
+
+OAuthConsumer flickr_consumer = {
+	NULL,
+	NULL,
+	NULL,
+	flickr_request_token_response,
+	flickr_get_authorization_url,
+	NULL,
+	flickr_access_token_response
+};
diff --git a/extensions/flicker_utils/flickr-consumer.h b/extensions/flicker_utils/flickr-consumer.h
new file mode 100644
index 0000000..ac14659
--- /dev/null
+++ b/extensions/flicker_utils/flickr-consumer.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FLICKR_CONSUMER_H
+#define FLICKR_CONSUMER_H
+
+#include <gthumb.h>
+#include <extensions/oauth/oauth.h>
+
+extern OAuthConsumer flickr_consumer;
+
+gboolean  flickr_utils_parse_response (SoupBuffer   *body,
+				       DomDocument **doc_p,
+				       GError      **error);
+
+#endif /* FLICKR_CONSUMER_H */
diff --git a/extensions/flicker_utils/flickr-service.c b/extensions/flicker_utils/flickr-service.c
index f63b47c..9950eae 100644
--- a/extensions/flicker_utils/flickr-service.c
+++ b/extensions/flicker_utils/flickr-service.c
@@ -24,22 +24,28 @@
 #include <glib/gi18n.h>
 #include <gthumb.h>
 #include "flickr-account.h"
-#include "flickr-connection.h"
+#include "flickr-consumer.h"
 #include "flickr-photo.h"
 #include "flickr-photoset.h"
 #include "flickr-service.h"
-#include "flickr-user.h"
 
 
 #define IMAGES_PER_PAGE 500
+#define RESPONSE_FORMAT "rest"
 
 
-G_DEFINE_TYPE (FlickrService, flickr_service, G_TYPE_OBJECT)
+G_DEFINE_TYPE (FlickrService, flickr_service, OAUTH_TYPE_SERVICE)
+
+
+enum {
+        PROP_0,
+        PROP_SERVER
+};
 
 
 typedef struct {
-	FlickrPrivacyType    privacy_level;
-	FlickrSafetyType     safety_level;
+	FlickrPrivacy        privacy_level;
+	FlickrSafety         safety_level;
 	gboolean             hidden;
 	int                  max_width;
 	int                  max_height;
@@ -93,72 +99,86 @@ add_photos_data_free (AddPhotosData *add_photos)
 }
 
 
-struct _FlickrServicePrivate
-{
-	FlickrConnection *conn;
-	FlickrUser       *user;
-	PostPhotosData   *post_photos;
-	AddPhotosData    *add_photos;
+/* -- flickr_service -- */
+
+
+struct _FlickrServicePrivate {
+	PostPhotosData *post_photos;
+	AddPhotosData  *add_photos;
+	FlickrServer   *server;
+	OAuthConsumer  *consumer;
 };
 
 
 static void
-flickr_service_finalize (GObject *object)
+flickr_service_set_property (GObject      *object,
+			     guint         property_id,
+			     const GValue *value,
+			     GParamSpec   *pspec)
 {
 	FlickrService *self;
 
-	self = FLICKR_SERVICE (object);
-
-	_g_object_unref (self->priv->conn);
-	_g_object_unref (self->priv->user);
-	post_photos_data_free (self->priv->post_photos);
-	add_photos_data_free (self->priv->add_photos);
-
-	G_OBJECT_CLASS (flickr_service_parent_class)->finalize (object);
+        self = FLICKR_SERVICE (object);
+
+	switch (property_id) {
+	case PROP_SERVER:
+		self->priv->server = g_value_get_pointer (value);
+		self->priv->consumer = oauth_consumer_copy (&flickr_consumer);
+		self->priv->consumer->request_token_url = self->priv->server->request_token_url;
+		self->priv->consumer->access_token_url = self->priv->server->access_token_url;
+		self->priv->consumer->consumer_key = self->priv->server->consumer_key;
+		self->priv->consumer->consumer_secret = self->priv->server->consumer_secret;
+		g_object_set (self, "consumer", self->priv->consumer, NULL);
+		break;
+	default:
+		break;
+	}
 }
 
 
 static void
-flickr_service_class_init (FlickrServiceClass *klass)
+flickr_service_get_property (GObject    *object,
+			     guint       property_id,
+			     GValue     *value,
+			     GParamSpec *pspec)
 {
-	GObjectClass *object_class;
+	FlickrService *self;
 
-	g_type_class_add_private (klass, sizeof (FlickrServicePrivate));
+        self = FLICKR_SERVICE (object);
 
-	object_class = (GObjectClass*) klass;
-	object_class->finalize = flickr_service_finalize;
+	switch (property_id) {
+	case PROP_SERVER:
+		g_value_set_pointer (value, self->priv->server);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
 }
 
 
 static void
-flickr_service_init (FlickrService *self)
-{
-	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, FLICKR_TYPE_SERVICE, FlickrServicePrivate);
-	self->priv->conn = NULL;
-	self->priv->user = NULL;
-	self->priv->post_photos = NULL;
-}
-
-
-FlickrService *
-flickr_service_new (FlickrConnection *conn)
+flickr_service_finalize (GObject *object)
 {
 	FlickrService *self;
 
-	self = (FlickrService *) g_object_new (FLICKR_TYPE_SERVICE, NULL);
-	self->priv->conn = g_object_ref (conn);
+	self = FLICKR_SERVICE (object);
 
-	return self;
+	post_photos_data_free (self->priv->post_photos);
+	add_photos_data_free (self->priv->add_photos);
+	oauth_consumer_free (self->priv->consumer);
+
+	G_OBJECT_CLASS (flickr_service_parent_class)->finalize (object);
 }
 
 
-/* -- flickr_service_get_upload_status -- */
+/* -- flickr_service_get_user_info -- */
 
 
 static void
-get_upload_status_ready_cb (SoupSession *session,
-			    SoupMessage *msg,
-			    gpointer     user_data)
+get_user_info_ready_cb (SoupSession *session,
+			SoupMessage *msg,
+			gpointer     user_data)
 {
 	FlickrService      *self = user_data;
 	GSimpleAsyncResult *result;
@@ -166,7 +186,7 @@ get_upload_status_ready_cb (SoupSession *session,
 	DomDocument        *doc = NULL;
 	GError             *error = NULL;
 
-	result = flickr_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 
 	if (msg->status_code != 200) {
 		g_simple_async_result_set_error (result,
@@ -180,24 +200,33 @@ get_upload_status_ready_cb (SoupSession *session,
 
 	body = soup_message_body_flatten (msg->response_body);
 	if (flickr_utils_parse_response (body, &doc, &error)) {
-		DomElement *response;
-		DomElement *node;
-		FlickrUser *user = NULL;
+		OAuthAccount *account;
+		DomElement   *response;
+		DomElement   *node;
+		gboolean      success = FALSE;
+
+		account = web_service_get_current_account (WEB_SERVICE (self));
+		if (account == NULL)
+			account = g_object_new (FLICKR_TYPE_ACCOUNT,
+						"token", oauth_service_get_token (OAUTH_SERVICE (self)),
+						"token-secret", oauth_service_get_token_secret (OAUTH_SERVICE (self)),
+						NULL);
 
 		response = DOM_ELEMENT (doc)->first_child;
 		for (node = response->first_child; node; node = node->next_sibling) {
 			if (g_strcmp0 (node->tag_name, "user") == 0) {
-				user = flickr_user_new ();
-				dom_domizable_load_from_element (DOM_DOMIZABLE (user), node);
-				g_simple_async_result_set_op_res_gpointer (result, user, (GDestroyNotify) g_object_unref);
+				success = TRUE;
+				flickr_account_load_extra_data (FLICKR_ACCOUNT (account), node);
+				g_simple_async_result_set_op_res_gpointer (result, account, (GDestroyNotify) g_object_unref);
 			}
 		}
 
-		if (user == NULL) {
-			error = g_error_new_literal (FLICKR_CONNECTION_ERROR, 0, _("Unknown error"));
+		if (! success) {
+			error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
 			g_simple_async_result_set_from_error (result, error);
 		}
 
+		g_object_unref (account);
 		g_object_unref (doc);
 	}
 	else
@@ -209,43 +238,103 @@ get_upload_status_ready_cb (SoupSession *session,
 }
 
 
-void
-flickr_service_get_upload_status (FlickrService       *self,
-				  GCancellable        *cancellable,
-				  GAsyncReadyCallback  callback,
-				  gpointer             user_data)
+static void
+flickr_service_get_user_info (WebService          *base,
+			      GCancellable        *cancellable,
+			      GAsyncReadyCallback  callback,
+			      gpointer             user_data)
 {
-	GHashTable  *data_set;
-	SoupMessage *msg;
+	FlickrService *self = FLICKR_SERVICE (base);
+	OAuthAccount  *account;
+	GHashTable    *data_set;
+	SoupMessage   *msg;
 
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Connecting to the server"), _("Getting account information"), TRUE, 0.0);
+	account = web_service_get_current_account (WEB_SERVICE (self));
+	if (account != NULL) {
+		oauth_service_set_token (OAUTH_SERVICE (self), account->token);
+		oauth_service_set_token_secret (OAUTH_SERVICE (self), account->token_secret);
+	}
 
 	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "format", RESPONSE_FORMAT);
 	g_hash_table_insert (data_set, "method", "flickr.people.getUploadStatus");
-	flickr_connection_add_api_sig (self->priv->conn, data_set);
-	msg = soup_form_request_new_from_hash ("GET", self->priv->conn->server->rest_url, data_set);
-	flickr_connection_send_message (self->priv->conn,
-					msg,
-					cancellable,
-					callback,
-					user_data,
-					flickr_service_get_upload_status,
-					get_upload_status_ready_cb,
-					self);
+	oauth_service_add_signature (OAUTH_SERVICE (self), "GET", self->priv->server->rest_url, data_set);
+	msg = soup_form_request_new_from_hash ("GET", self->priv->server->rest_url, data_set);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   cancellable,
+				   callback,
+				   user_data,
+				   flickr_service_get_user_info,
+				   get_user_info_ready_cb,
+				   self);
 
 	g_hash_table_destroy (data_set);
 }
 
 
-FlickrUser *
-flickr_service_get_upload_status_finish (FlickrService  *self,
-					 GAsyncResult   *result,
-					 GError        **error)
+static void
+flickr_service_class_init (FlickrServiceClass *klass)
 {
-	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
-		return NULL;
-	else
-		return g_object_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
+	GObjectClass    *object_class;
+	WebServiceClass *service_class;
+
+	g_type_class_add_private (klass, sizeof (FlickrServicePrivate));
+
+	object_class = (GObjectClass*) klass;
+	object_class->set_property = flickr_service_set_property;
+	object_class->get_property = flickr_service_get_property;
+	object_class->finalize = flickr_service_finalize;
+
+	service_class = (WebServiceClass*) klass;
+	service_class->get_user_info = flickr_service_get_user_info;
+
+	/* properties */
+
+	g_object_class_install_property (object_class,
+					 PROP_SERVER,
+					 g_param_spec_pointer ("server",
+                                                               "Server",
+                                                               "",
+                                                               G_PARAM_READWRITE));
+}
+
+
+static void
+flickr_service_init (FlickrService *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, FLICKR_TYPE_SERVICE, FlickrServicePrivate);
+	self->priv->post_photos = NULL;
+	self->priv->add_photos = NULL;
+	self->priv->server = NULL;
+}
+
+
+FlickrService *
+flickr_service_new (FlickrServer  *server,
+		    GCancellable  *cancellable,
+		    GtkWidget     *browser,
+		    GtkWidget     *dialog)
+{
+	g_return_val_if_fail (server != NULL, NULL);
+
+	return g_object_new (FLICKR_TYPE_SERVICE,
+			     "service-name", server->name,
+			     "service-address", server->url,
+			     "service-protocol", server->protocol,
+			     "account-type", FLICKR_TYPE_ACCOUNT,
+			     "cancellable", cancellable,
+			     "browser", browser,
+			     "dialog", dialog,
+			     "server", server,
+			     NULL);
+}
+
+
+FlickrServer *
+flickr_service_get_server (FlickrService *self)
+{
+	return self->priv->server;
 }
 
 
@@ -263,7 +352,7 @@ list_photosets_ready_cb (SoupSession *session,
 	DomDocument        *doc = NULL;
 	GError             *error = NULL;
 
-	result = flickr_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 
 	if (msg->status_code != 200) {
 		g_simple_async_result_set_error (result,
@@ -314,7 +403,6 @@ list_photosets_ready_cb (SoupSession *session,
 
 void
 flickr_service_list_photosets (FlickrService       *self,
-			       const char          *user_id,
 			       GCancellable        *cancellable,
 			       GAsyncReadyCallback  callback,
 			       gpointer             user_data)
@@ -322,22 +410,21 @@ flickr_service_list_photosets (FlickrService       *self,
 	GHashTable  *data_set;
 	SoupMessage *msg;
 
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Getting the album list"), NULL, TRUE, 0.0);
+	gth_task_progress (GTH_TASK (self), _("Getting the album list"), NULL, TRUE, 0.0);
 
 	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "format", RESPONSE_FORMAT);
 	g_hash_table_insert (data_set, "method", "flickr.photosets.getList");
-	if (user_id != NULL)
-		g_hash_table_insert (data_set, "user_id", (char *) user_id);
-	flickr_connection_add_api_sig (self->priv->conn, data_set);
-	msg = soup_form_request_new_from_hash ("GET", self->priv->conn->server->rest_url, data_set);
-	flickr_connection_send_message (self->priv->conn,
-					msg,
-					cancellable,
-					callback,
-					user_data,
-					flickr_service_list_photosets,
-					list_photosets_ready_cb,
-					self);
+	oauth_service_add_signature (OAUTH_SERVICE (self), "GET", self->priv->server->rest_url, data_set);
+	msg = soup_form_request_new_from_hash ("GET", self->priv->server->rest_url, data_set);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   cancellable,
+				   callback,
+				   user_data,
+				   flickr_service_list_photosets,
+				   list_photosets_ready_cb,
+				   self);
 
 	g_hash_table_destroy (data_set);
 }
@@ -369,7 +456,7 @@ create_photoset_ready_cb (SoupSession *session,
 	DomDocument        *doc = NULL;
 	GError             *error = NULL;
 
-	result = flickr_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 
 	if (msg->status_code != 200) {
 		g_simple_async_result_set_error (result,
@@ -397,7 +484,7 @@ create_photoset_ready_cb (SoupSession *session,
 		}
 
 		if (photoset == NULL) {
-			error = g_error_new_literal (FLICKR_CONNECTION_ERROR, 0, _("Unknown error"));
+			error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
 			g_simple_async_result_set_from_error (result, error);
 		}
 
@@ -425,22 +512,23 @@ flickr_service_create_photoset (FlickrService       *self,
 	g_return_if_fail (photoset != NULL);
 	g_return_if_fail (photoset->primary != NULL);
 
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Creating the new album"), NULL, TRUE, 0.0);
+	gth_task_progress (GTH_TASK (self), _("Creating the new album"), NULL, TRUE, 0.0);
 
 	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "format", RESPONSE_FORMAT);
 	g_hash_table_insert (data_set, "method", "flickr.photosets.create");
 	g_hash_table_insert (data_set, "title", photoset->title);
 	g_hash_table_insert (data_set, "primary_photo_id", photoset->primary);
-	flickr_connection_add_api_sig (self->priv->conn, data_set);
-	msg = soup_form_request_new_from_hash ("GET", self->priv->conn->server->rest_url, data_set);
-	flickr_connection_send_message (self->priv->conn,
-					msg,
-					cancellable,
-					callback,
-					user_data,
-					flickr_service_create_photoset,
-					create_photoset_ready_cb,
-					self);
+	oauth_service_add_signature (OAUTH_SERVICE (self), "GET", self->priv->server->rest_url, data_set);
+	msg = soup_form_request_new_from_hash ("GET", self->priv->server->rest_url, data_set);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   cancellable,
+				   callback,
+				   user_data,
+				   flickr_service_create_photoset,
+				   create_photoset_ready_cb,
+				   self);
 
 	g_hash_table_destroy (data_set);
 }
@@ -467,7 +555,8 @@ add_photos_to_set_done (FlickrService *self,
 {
 	GSimpleAsyncResult *result;
 
-	result = flickr_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
+
 	if (result == NULL)
 		result = g_simple_async_result_new (G_OBJECT (self),
 						    self->priv->add_photos->callback,
@@ -506,7 +595,7 @@ add_current_photo_to_set_ready_cb (SoupSession *session,
 	DomDocument        *doc = NULL;
 	GError             *error = NULL;
 
-	result = flickr_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 
 	if (msg->status_code != 200) {
 		g_simple_async_result_set_error (result,
@@ -544,7 +633,7 @@ add_current_photo_to_set (FlickrService *self)
 		return;
 	}
 
-	gth_task_progress (GTH_TASK (self->priv->conn),
+	gth_task_progress (GTH_TASK (self),
 			   _("Creating the new album"),
 			   "",
 			   FALSE,
@@ -557,19 +646,20 @@ add_current_photo_to_set (FlickrService *self)
 	}
 
 	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "format", RESPONSE_FORMAT);
 	g_hash_table_insert (data_set, "method", "flickr.photosets.addPhoto");
 	g_hash_table_insert (data_set, "photoset_id", self->priv->add_photos->photoset->id);
 	g_hash_table_insert (data_set, "photo_id", photo_id);
-	flickr_connection_add_api_sig (self->priv->conn, data_set);
-	msg = soup_form_request_new_from_hash ("POST", self->priv->conn->server->rest_url, data_set);
-	flickr_connection_send_message (self->priv->conn,
-					msg,
-					self->priv->add_photos->cancellable,
-					self->priv->add_photos->callback,
-					self->priv->add_photos->user_data,
-					flickr_service_add_photos_to_set,
-					add_current_photo_to_set_ready_cb,
-					self);
+	oauth_service_add_signature (OAUTH_SERVICE (self), "POST", self->priv->server->rest_url, data_set);
+	msg = soup_form_request_new_from_hash ("POST", self->priv->server->rest_url, data_set);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   self->priv->add_photos->cancellable,
+				   self->priv->add_photos->callback,
+				   self->priv->add_photos->user_data,
+				   flickr_service_add_photos_to_set,
+				   add_current_photo_to_set_ready_cb,
+				   self);
 
 	g_hash_table_destroy (data_set);
 }
@@ -583,7 +673,7 @@ flickr_service_add_photos_to_set (FlickrService        *self,
 				  GAsyncReadyCallback   callback,
 				  gpointer              user_data)
 {
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Creating the new album"), NULL, TRUE, 0.0);
+	gth_task_progress (GTH_TASK (self), _("Creating the new album"), NULL, TRUE, 0.0);
 
 	add_photos_data_free (self->priv->add_photos);
 	self->priv->add_photos = g_new0 (AddPhotosData, 1);
@@ -596,7 +686,7 @@ flickr_service_add_photos_to_set (FlickrService        *self,
 	self->priv->add_photos->current = self->priv->add_photos->photo_ids;
 	self->priv->add_photos->n_current = 1;
 
-	flickr_connection_reset_result (self->priv->conn);
+	_web_service_reset_result (WEB_SERVICE (self));
 	add_current_photo_to_set (self);
 }
 
@@ -622,7 +712,7 @@ post_photos_done (FlickrService *self,
 {
 	GSimpleAsyncResult *result;
 
-	result = flickr_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 	if (error == NULL) {
 		self->priv->post_photos->ids = g_list_reverse (self->priv->post_photos->ids);
 		g_simple_async_result_set_op_res_gpointer (result, self->priv->post_photos->ids, (GDestroyNotify) _g_string_list_free);
@@ -703,7 +793,7 @@ post_photo_ready_cb (SoupSession *session,
 
 
 static char *
-get_safety_value (FlickrSafetyType safety_level)
+get_safety_value (FlickrSafety safety_level)
 {
 	char *value = NULL;
 
@@ -746,7 +836,7 @@ upload_photo_wrote_body_data_cb (SoupMessage *msg,
 	/* Translators: %s is a filename */
 	details = g_strdup_printf (_("Uploading '%s'"), g_file_info_get_display_name (file_data->info));
 	current_file_fraction = (double) self->priv->post_photos->wrote_body_data_size / msg->request_body->length;
-	gth_task_progress (GTH_TASK (self->priv->conn),
+	gth_task_progress (GTH_TASK (self),
 			   NULL,
 			   details,
 			   FALSE,
@@ -791,6 +881,7 @@ post_photo_file_buffer_ready_cb (void     **buffer,
 		GList      *scan;
 
 		data_set = g_hash_table_new (g_str_hash, g_str_equal);
+		g_hash_table_insert (data_set, "format", RESPONSE_FORMAT);
 
 		title = gth_file_data_get_attribute_as_string (file_data, "general::title");
 		if (title != NULL)
@@ -812,7 +903,7 @@ post_photo_file_buffer_ready_cb (void     **buffer,
 		g_hash_table_insert (data_set, "is_family", ((self->priv->post_photos->privacy_level == FLICKR_PRIVACY_FAMILY) || (self->priv->post_photos->privacy_level == FLICKR_PRIVACY_FRIENDS_FAMILY)) ? "1" : "0");
 		g_hash_table_insert (data_set, "safety_level", get_safety_value (self->priv->post_photos->safety_level));
 		g_hash_table_insert (data_set, "hidden", self->priv->post_photos->hidden ? "2" : "1");
-		flickr_connection_add_api_sig (self->priv->conn, data_set);
+		oauth_service_add_signature (OAUTH_SERVICE (self), "POST", self->priv->server->upload_url, data_set);
 
 		keys = g_hash_table_get_keys (data_set);
 		for (scan = keys; scan; scan = scan->next) {
@@ -861,20 +952,20 @@ post_photo_file_buffer_ready_cb (void     **buffer,
 	/* send the file */
 
 	self->priv->post_photos->wrote_body_data_size = 0;
-	msg = soup_form_request_new_from_multipart (self->priv->conn->server->upload_url, multipart);
+	msg = soup_form_request_new_from_multipart (self->priv->server->upload_url, multipart);
 	g_signal_connect (msg,
 			  "wrote-body-data",
 			  (GCallback) upload_photo_wrote_body_data_cb,
 			  self);
 
-	flickr_connection_send_message (self->priv->conn,
-					msg,
-					self->priv->post_photos->cancellable,
-					self->priv->post_photos->callback,
-					self->priv->post_photos->user_data,
-					flickr_service_post_photos,
-					post_photo_ready_cb,
-					self);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   self->priv->post_photos->cancellable,
+				   self->priv->post_photos->callback,
+				   self->priv->post_photos->user_data,
+				   flickr_service_post_photos,
+				   post_photo_ready_cb,
+				   self);
 
 	soup_multipart_free (multipart);
 }
@@ -927,8 +1018,8 @@ post_photos_info_ready_cb (GList    *files,
 
 void
 flickr_service_post_photos (FlickrService       *self,
-			    FlickrPrivacyType    privacy_level,
-			    FlickrSafetyType     safety_level,
+			    FlickrPrivacy    privacy_level,
+			    FlickrSafety     safety_level,
 			    gboolean             hidden,
 			    int                  max_width,
 			    int                  max_height,
@@ -937,7 +1028,11 @@ flickr_service_post_photos (FlickrService       *self,
 			    GAsyncReadyCallback  callback,
 			    gpointer             user_data)
 {
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Uploading the files to the server"), NULL, TRUE, 0.0);
+	gth_task_progress (GTH_TASK (self),
+			   _("Uploading the files to the server"),
+			   NULL,
+			   TRUE,
+			   0.0);
 
 	post_photos_data_free (self->priv->post_photos);
 	self->priv->post_photos = g_new0 (PostPhotosData, 1);
@@ -1016,7 +1111,7 @@ flickr_service_list_photoset_paged_ready_cb (SoupSession *session,
 	DomDocument          *doc = NULL;
 	GError               *error = NULL;
 
-	result = flickr_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 
 	if (msg->status_code != 200) {
 		g_simple_async_result_set_error (result,
@@ -1045,7 +1140,7 @@ flickr_service_list_photoset_paged_ready_cb (SoupSession *session,
 					if (g_strcmp0 (child->tag_name, "photo") == 0) {
 						FlickrPhoto *photo;
 
-						photo = flickr_photo_new (self->priv->conn->server);
+						photo = flickr_photo_new (self->priv->server);
 						dom_domizable_load_from_element (DOM_DOMIZABLE (photo), child);
 						photo->position = data->position++;
 						data->photos = g_list_prepend (data->photos, photo);
@@ -1102,9 +1197,14 @@ flickr_service_list_photoset_page (FlickrListPhotosData *data,
 
 	g_return_if_fail (data->photoset != NULL);
 
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Getting the photo list"), NULL, TRUE, 0.0);
+	gth_task_progress (GTH_TASK (self),
+			   _("Getting the photo list"),
+			   NULL,
+			   TRUE,
+			   0.0);
 
 	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "format", RESPONSE_FORMAT);
 	g_hash_table_insert (data_set, "method", "flickr.photosets.getPhotos");
 	g_hash_table_insert (data_set, "photoset_id", data->photoset->id);
 	if (data->extras != NULL)
@@ -1118,16 +1218,16 @@ flickr_service_list_photoset_page (FlickrListPhotosData *data,
 		g_hash_table_insert (data_set, "page", per_page);
 	}
 
-	flickr_connection_add_api_sig (self->priv->conn, data_set);
-	msg = soup_form_request_new_from_hash ("GET", self->priv->conn->server->rest_url, data_set);
-	flickr_connection_send_message (self->priv->conn,
-					msg,
-					data->cancellable,
-					data->callback,
-					data->user_data,
-					flickr_service_list_photos,
-					flickr_service_list_photoset_paged_ready_cb,
-					data);
+	oauth_service_add_signature (OAUTH_SERVICE (self), "GET", self->priv->server->rest_url, data_set);
+	msg = soup_form_request_new_from_hash ("GET", self->priv->server->rest_url, data_set);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   data->cancellable,
+				   data->callback,
+				   data->user_data,
+				   flickr_service_list_photos,
+				   flickr_service_list_photoset_paged_ready_cb,
+				   data);
 
 	g_free (per_page);
 	g_free (page);
@@ -1169,132 +1269,3 @@ flickr_service_list_photos_finish (FlickrService  *self,
 	else
 		return _g_object_list_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
 }
-
-
-/* utilities */
-
-
-/* Used for compatibility with the original Flickr uploader that used
- * flickr.xml as filename */
-static char *
-get_server_accounts_filename (const char *server_name)
-{
-	char *name;
-	char *filename;
-
-	name = g_ascii_strdown (server_name, -1);
-	filename = g_strconcat (name, ".xml", NULL);
-
-	g_free (name);
-
-	return filename;
-}
-
-
-GList *
-flickr_accounts_load_from_file (const char *server_name)
-{
-	GList       *accounts = NULL;
-	GFile       *file;
-	char        *buffer;
-	char        *accounts_filename;
-	gsize        len;
-	DomDocument *doc;
-
-	accounts_filename = get_server_accounts_filename (server_name);
-	file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, "accounts", accounts_filename, NULL);
-	g_free (accounts_filename);
-
-	if (! _g_file_load_in_buffer (file, (void **) &buffer, &len, NULL, NULL)) {
-		g_object_unref (file);
-		return NULL;
-	}
-
-	doc = dom_document_new ();
-	if (dom_document_load (doc, buffer, len, NULL)) {
-		DomElement *node;
-
-		node = DOM_ELEMENT (doc)->first_child;
-		if ((node != NULL) && (g_strcmp0 (node->tag_name, "accounts") == 0)) {
-			DomElement *child;
-
-			for (child = node->first_child;
-			     child != NULL;
-			     child = child->next_sibling)
-			{
-				if (strcmp (child->tag_name, "account") == 0) {
-					FlickrAccount *account;
-
-					account = flickr_account_new ();
-					dom_domizable_load_from_element (DOM_DOMIZABLE (account), child);
-
-					accounts = g_list_prepend (accounts, account);
-				}
-			}
-
-			accounts = g_list_reverse (accounts);
-		}
-	}
-
-	g_object_unref (doc);
-	g_free (buffer);
-	g_object_unref (file);
-
-	return accounts;
-}
-
-
-FlickrAccount *
-flickr_accounts_find_default (GList *accounts)
-{
-	GList *scan;
-
-	for (scan = accounts; scan; scan = scan->next) {
-		FlickrAccount *account = scan->data;
-
-		if (account->is_default)
-			return g_object_ref (account);
-	}
-
-	return NULL;
-}
-
-
-void
-flickr_accounts_save_to_file (const char    *server_name,
-			      GList         *accounts,
-			      FlickrAccount *default_account)
-{
-	DomDocument *doc;
-	DomElement  *root;
-	GList       *scan;
-	char        *buffer;
-	gsize        len;
-	char        *accounts_filename;
-	GFile       *file;
-
-	doc = dom_document_new ();
-	root = dom_document_create_element (doc, "accounts", NULL);
-	dom_element_append_child (DOM_ELEMENT (doc), root);
-	for (scan = accounts; scan; scan = scan->next) {
-		FlickrAccount *account = scan->data;
-		DomElement    *node;
-
-		if ((default_account != NULL) && g_strcmp0 (account->username, default_account->username) == 0)
-			account->is_default = TRUE;
-		else
-			account->is_default = FALSE;
-		node = dom_domizable_create_element (DOM_DOMIZABLE (account), doc);
-		dom_element_append_child (root, node);
-	}
-
-	accounts_filename = get_server_accounts_filename (server_name);
-	file = gth_user_dir_get_file_for_write (GTH_DIR_CONFIG, GTHUMB_DIR, "accounts", accounts_filename, NULL);
-	buffer = dom_document_dump (doc, &len);
-	_g_file_write (file, FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, buffer, len, NULL, NULL);
-
-	g_free (buffer);
-	g_object_unref (file);
-	g_free (accounts_filename);
-	g_object_unref (doc);
-}
diff --git a/extensions/flicker_utils/flickr-service.h b/extensions/flicker_utils/flickr-service.h
index 8eb89ac..ae53bf2 100644
--- a/extensions/flicker_utils/flickr-service.h
+++ b/extensions/flicker_utils/flickr-service.h
@@ -22,25 +22,10 @@
 #ifndef FLICKR_SERVICE_H
 #define FLICKR_SERVICE_H
 
-#include <glib-object.h>
-#include "flickr-account.h"
-#include "flickr-connection.h"
+#include <gthumb.h>
+#include <extensions/oauth/oauth.h>
 #include "flickr-photoset.h"
-#include "flickr-user.h"
-
-typedef enum {
-	FLICKR_PRIVACY_PUBLIC,
-	FLICKR_PRIVACY_FRIENDS_FAMILY,
-	FLICKR_PRIVACY_FRIENDS,
-	FLICKR_PRIVACY_FAMILY,
-	FLICKR_PRIVACY_PRIVATE
-} FlickrPrivacyType;
-
-typedef enum {
-	FLICKR_SAFETY_SAFE,
-	FLICKR_SAFETY_MODERATE,
-	FLICKR_SAFETY_RESTRICTED
-} FlickrSafetyType;
+#include "flickr-types.h"
 
 #define FLICKR_TYPE_SERVICE         (flickr_service_get_type ())
 #define FLICKR_SERVICE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), FLICKR_TYPE_SERVICE, FlickrService))
@@ -53,28 +38,22 @@ typedef struct _FlickrService         FlickrService;
 typedef struct _FlickrServicePrivate  FlickrServicePrivate;
 typedef struct _FlickrServiceClass    FlickrServiceClass;
 
-struct _FlickrService
-{
-	GObject __parent;
+struct _FlickrService {
+	OAuthService __parent;
 	FlickrServicePrivate *priv;
 };
 
-struct _FlickrServiceClass
-{
-	GObjectClass __parent_class;
+struct _FlickrServiceClass {
+	OAuthServiceClass __parent_class;
 };
 
 GType             flickr_service_get_type                 (void) G_GNUC_CONST;
-FlickrService *   flickr_service_new                      (FlickrConnection     *conn);
-void              flickr_service_get_upload_status        (FlickrService        *self,
+FlickrService *   flickr_service_new                      (FlickrServer         *server,
 							   GCancellable         *cancellable,
-							   GAsyncReadyCallback   callback,
-							   gpointer              user_data);
-FlickrUser *      flickr_service_get_upload_status_finish (FlickrService        *self,
-						           GAsyncResult         *result,
-						           GError              **error);
+							   GtkWidget            *browser,
+							   GtkWidget            *dialog);
+FlickrServer *    flickr_service_get_server               (FlickrService        *self);
 void              flickr_service_list_photosets           (FlickrService        *self,
-							   const char           *user_id,
 						           GCancellable         *cancellable,
 						           GAsyncReadyCallback   callback,
 						           gpointer              user_data);
@@ -99,8 +78,8 @@ gboolean          flickr_service_add_photos_to_set_finish (FlickrService
 						           GAsyncResult         *result,
 						           GError              **error);
 void              flickr_service_post_photos              (FlickrService        *self,
-							   FlickrPrivacyType     privacy_level,
-							   FlickrSafetyType      safety_level,
+							   FlickrPrivacy         privacy_level,
+							   FlickrSafety          safety_level,
 							   gboolean              hidden,
 							   int                   max_width,
 							   int                   max_height,
@@ -121,12 +100,4 @@ GList *           flickr_service_list_photos_finish       (FlickrService
 						           GAsyncResult         *result,
 						           GError              **error);
 
-/* utilities */
-
-GList *          flickr_accounts_load_from_file  (const char    *server_name);
-FlickrAccount *  flickr_accounts_find_default    (GList         *accounts);
-void             flickr_accounts_save_to_file    (const char    *server_name,
-						  GList         *accounts,
-						  FlickrAccount *default_account);
-
 #endif /* FLICKR_SERVICE_H */
diff --git a/extensions/flicker_utils/flickr-types.h b/extensions/flicker_utils/flickr-types.h
index a20bbbf..466f3a5 100644
--- a/extensions/flicker_utils/flickr-types.h
+++ b/extensions/flicker_utils/flickr-types.h
@@ -22,11 +22,22 @@
 #ifndef FLICKR_TYPES_H
 #define FLICKR_TYPES_H
 
-typedef enum  {
-	FLICKR_SAFETY_LEVEL_SAFE = 1,
-	FLICKR_SAFETY_LEVEL_MODERATE = 2,
-	FLICKR_SAFETY_LEVEL_RESTRICTED = 3
-} FlickrSafetyLevel;
+
+typedef enum {
+	FLICKR_PRIVACY_PUBLIC,
+	FLICKR_PRIVACY_FRIENDS_FAMILY,
+	FLICKR_PRIVACY_FRIENDS,
+	FLICKR_PRIVACY_FAMILY,
+	FLICKR_PRIVACY_PRIVATE
+} FlickrPrivacy;
+
+
+typedef enum {
+	FLICKR_SAFETY_SAFE = 1,
+	FLICKR_SAFETY_MODERATE = 2,
+	FLICKR_SAFETY_RESTRICTED = 3
+} FlickrSafety;
+
 
 typedef enum  {
 	FLICKR_CONTENT_TYPE_PHOTO = 1,
@@ -34,11 +45,13 @@ typedef enum  {
 	FLICKR_CONTENT_TYPE_OTHER = 3
 } FlickrContentType;
 
+
 typedef enum  {
 	FLICKR_HIDDEN_PUBLIC = 1,
 	FLICKR_HIDDEN_HIDDEN = 2,
 } FlickrHiddenType;
 
+
 typedef enum {
 	FLICKR_SIZE_SMALL_SQUARE = 75,
 	FLICKR_SIZE_THUMBNAIL = 100,
@@ -47,16 +60,24 @@ typedef enum {
 	FLICKR_SIZE_LARGE = 1024
 } FlickrSize;
 
+
 typedef struct {
+	const char *display_name;
 	const char *name;
 	const char *url;
-	const char *authentication_url;
+	const char *protocol;
+
+	const char *request_token_url;
+	const char *authorization_url;
+	const char *access_token_url;
+	const char *consumer_key;
+	const char *consumer_secret;
+
 	const char *rest_url;
 	const char *upload_url;
 	const char *static_url;
-	const char *api_key;
-	const char *shared_secret;
 	gboolean    automatic_urls;
 } FlickrServer;
 
+
 #endif /* FLICKR_TYPES_H */
diff --git a/extensions/oauth/Makefile.am b/extensions/oauth/Makefile.am
index 309fe22..20efceb 100644
--- a/extensions/oauth/Makefile.am
+++ b/extensions/oauth/Makefile.am
@@ -8,18 +8,18 @@ extension_LTLIBRARIES = liboauth.la
 liboauth_la_SOURCES = 				\
 	main.c					\
 	oauth.h					\
-	oauth2-ask-authorization-dialog.c	\
-	oauth2-ask-authorization-dialog.h	\
+	oauth-ask-authorization-dialog.c	\
+	oauth-ask-authorization-dialog.h	\
 	oauth-account.c				\
 	oauth-account.h				\
 	oauth-account-chooser-dialog.c		\
 	oauth-account-chooser-dialog.h		\
 	oauth-account-manager-dialog.c		\
 	oauth-account-manager-dialog.h		\
-	oauth-authentication.c			\
-	oauth-authentication.h			\
-	oauth-connection.c			\
-	oauth-connection.h			\
+	oauth-consumer.c			\
+	oauth-consumer.h			\
+	oauth-service.c				\
+	oauth-service.h				\
 	web-service.c				\
 	web-service.h
 
diff --git a/extensions/oauth/oauth-account.c b/extensions/oauth/oauth-account.c
index 39ee4e5..f2ade2d 100644
--- a/extensions/oauth/oauth-account.c
+++ b/extensions/oauth/oauth-account.c
@@ -29,6 +29,9 @@
 #include "oauth-account.h"
 
 
+#define ACCOUNTS_FORMAT_VERSION "2.0"
+
+
 enum {
         PROP_0,
         PROP_ID,
@@ -197,13 +200,13 @@ oauth_account_class_init (OAuthAccountClass *klass)
 }
 
 
-static DomElement *
+DomElement *
 oauth_account_create_element (DomDomizable *base,
 			      DomDocument  *doc)
 {
 	OAuthAccount *self;
-	DomElement    *element;
-	gboolean       set_token;
+	DomElement   *element;
+	gboolean      set_token;
 
 	self = OAUTH_ACCOUNT (base);
 
@@ -234,7 +237,7 @@ oauth_account_create_element (DomDomizable *base,
 }
 
 
-static void
+void
 oauth_account_load_from_element (DomDomizable *base,
 			         DomElement   *element)
 {
@@ -320,3 +323,123 @@ oauth_account_cmp (OAuthAccount *a,
 	else
 		return g_strcmp0 (a->name, b->name);
 }
+
+
+GList *
+oauth_accounts_load_from_file (const char *service_name,
+			       GType       account_type)
+{
+	GList       *accounts = NULL;
+	char        *filename;
+	GFile       *file;
+	char        *buffer;
+	gsize        len;
+	GError      *error = NULL;
+	DomDocument *doc;
+
+	if (account_type == 0)
+		account_type = OAUTH_TYPE_ACCOUNT;
+
+	filename = g_strconcat (service_name, ".xml", NULL);
+	file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, GTHUMB_DIR, "accounts", filename, NULL);
+	if (! _g_file_load_in_buffer (file, (void **) &buffer, &len, NULL, &error)) {
+		g_error_free (error);
+		g_object_unref (file);
+		g_free (filename);
+		return NULL;
+	}
+
+	doc = dom_document_new ();
+	if (dom_document_load (doc, buffer, len, NULL)) {
+		DomElement *node;
+
+		node = DOM_ELEMENT (doc)->first_child;
+		if ((node != NULL)
+		    && (g_strcmp0 (node->tag_name, "accounts") == 0)
+		    && (g_strcmp0 (dom_element_get_attribute (node, "version"), ACCOUNTS_FORMAT_VERSION) == 0))
+		{
+			DomElement *child;
+
+			for (child = node->first_child;
+			     child != NULL;
+			     child = child->next_sibling)
+			{
+				if (strcmp (child->tag_name, "account") == 0) {
+					OAuthAccount *account;
+
+					account = g_object_new (account_type, NULL);
+					dom_domizable_load_from_element (DOM_DOMIZABLE (account), child);
+
+					accounts = g_list_prepend (accounts, account);
+				}
+			}
+
+			accounts = g_list_reverse (accounts);
+		}
+	}
+
+	g_object_unref (doc);
+	g_free (buffer);
+	g_object_unref (file);
+	g_free (filename);
+
+	return accounts;
+}
+
+
+OAuthAccount *
+oauth_accounts_find_default (GList *accounts)
+{
+	GList *scan;
+
+	for (scan = accounts; scan; scan = scan->next) {
+		OAuthAccount *account = scan->data;
+
+		if (account->is_default)
+			return g_object_ref (account);
+	}
+
+	return NULL;
+}
+
+
+void
+oauth_accounts_save_to_file (const char   *service_name,
+			     GList        *accounts,
+			     OAuthAccount *default_account)
+{
+	DomDocument *doc;
+	DomElement  *root;
+	GList       *scan;
+	char        *buffer;
+	gsize        len;
+	char        *filename;
+	GFile       *file;
+
+	doc = dom_document_new ();
+	root = dom_document_create_element (doc, "accounts",
+					    "version", ACCOUNTS_FORMAT_VERSION,
+					    NULL);
+	dom_element_append_child (DOM_ELEMENT (doc), root);
+	for (scan = accounts; scan; scan = scan->next) {
+		OAuthAccount *account = scan->data;
+		DomElement    *node;
+
+		if ((default_account != NULL) && g_strcmp0 (account->username, default_account->username) == 0)
+			account->is_default = TRUE;
+		else
+			account->is_default = FALSE;
+		node = dom_domizable_create_element (DOM_DOMIZABLE (account), doc);
+		dom_element_append_child (root, node);
+	}
+
+	filename = g_strconcat (service_name, ".xml", NULL);
+	file = gth_user_dir_get_file_for_write (GTH_DIR_CONFIG, GTHUMB_DIR, "accounts", filename, NULL);
+	buffer = dom_document_dump (doc, &len);
+	_g_file_write (file, FALSE, G_FILE_CREATE_PRIVATE | G_FILE_CREATE_REPLACE_DESTINATION, buffer, len, NULL, NULL);
+
+	g_free (buffer);
+	g_object_unref (file);
+	g_free (filename);
+	g_object_unref (doc);
+}
diff --git a/extensions/oauth/oauth-account.h b/extensions/oauth/oauth-account.h
index b3f04d8..ecc711f 100644
--- a/extensions/oauth/oauth-account.h
+++ b/extensions/oauth/oauth-account.h
@@ -65,6 +65,19 @@ void              oauth_account_set_token_secret   (OAuthAccount *self,
 						    const char   *value);
 int               oauth_account_cmp                (OAuthAccount *a,
 						    OAuthAccount *b);
+DomElement *      oauth_account_create_element     (DomDomizable *base,
+						    DomDocument  *doc);
+void              oauth_account_load_from_element  (DomDomizable *base,
+						    DomElement   *element);
+
+/* -- utilities -- */
+
+GList *           oauth_accounts_load_from_file    (const char   *service_name,
+						    GType         account_type);
+OAuthAccount *    oauth_accounts_find_default      (GList        *accounts);
+void              oauth_accounts_save_to_file      (const char   *service_name,
+						    GList        *accounts,
+						    OAuthAccount *default_account);
 
 G_END_DECLS
 
diff --git a/extensions/oauth/oauth2-ask-authorization-dialog.c b/extensions/oauth/oauth-ask-authorization-dialog.c
similarity index 61%
rename from extensions/oauth/oauth2-ask-authorization-dialog.c
rename to extensions/oauth/oauth-ask-authorization-dialog.c
index e4bb2f2..ea63d24 100644
--- a/extensions/oauth/oauth2-ask-authorization-dialog.c
+++ b/extensions/oauth/oauth-ask-authorization-dialog.c
@@ -22,50 +22,60 @@
 #include <config.h>
 #include <glib/gi18n.h>
 #include <webkit2/webkit2.h>
-#include "oauth2-ask-authorization-dialog.h"
+#include "oauth-ask-authorization-dialog.h"
 
 
 #define GET_WIDGET(x) (_gtk_builder_get_widget (self->priv->builder, (x)))
 
 
-G_DEFINE_TYPE (OAuth2AskAuthorizationDialog, oauth2_ask_authorization_dialog, GTK_TYPE_DIALOG)
+G_DEFINE_TYPE (OAuthAskAuthorizationDialog, oauth_ask_authorization_dialog, GTK_TYPE_DIALOG)
 
 
 /* Signals */
 enum {
+	LOAD_REQUEST,
 	LOADED,
 	REDIRECTED,
 	LAST_SIGNAL
 };
 
 
-static guint oauth2_ask_authorization_dialog_signals[LAST_SIGNAL] = { 0 };
+static guint oauth_ask_authorization_dialog_signals[LAST_SIGNAL] = { 0 };
 
 
-struct _OAuth2AskAuthorizationDialogPrivate {
+struct _OAuthAskAuthorizationDialogPrivate {
 	GtkWidget *view;
 };
 
 
 static void
-oauth2_ask_authorization_dialog_class_init (OAuth2AskAuthorizationDialogClass *klass)
+oauth_ask_authorization_dialog_class_init (OAuthAskAuthorizationDialogClass *klass)
 {
-	g_type_class_add_private (klass, sizeof (OAuth2AskAuthorizationDialogPrivate));
+	g_type_class_add_private (klass, sizeof (OAuthAskAuthorizationDialogPrivate));
 
-	oauth2_ask_authorization_dialog_signals[LOADED] =
+	oauth_ask_authorization_dialog_signals[LOAD_REQUEST] =
+		g_signal_new ("load-request",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (OAuthAskAuthorizationDialogClass, load_request),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+	oauth_ask_authorization_dialog_signals[LOADED] =
 		g_signal_new ("loaded",
 			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (OAuth2AskAuthorizationDialogClass, loaded),
+			      G_STRUCT_OFFSET (OAuthAskAuthorizationDialogClass, loaded),
 			      NULL, NULL,
 			      g_cclosure_marshal_VOID__VOID,
 			      G_TYPE_NONE,
 			      0);
-	oauth2_ask_authorization_dialog_signals[REDIRECTED] =
+	oauth_ask_authorization_dialog_signals[REDIRECTED] =
 		g_signal_new ("redirected",
 			      G_TYPE_FROM_CLASS (klass),
 			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (OAuth2AskAuthorizationDialogClass, redirected),
+			      G_STRUCT_OFFSET (OAuthAskAuthorizationDialogClass, redirected),
 			      NULL, NULL,
 			      g_cclosure_marshal_VOID__VOID,
 			      G_TYPE_NONE,
@@ -78,14 +88,18 @@ webkit_view_load_changed_cb (WebKitWebView   *web_view,
                 	     WebKitLoadEvent  load_event,
                 	     gpointer         user_data)
 {
-	OAuth2AskAuthorizationDialog *self = user_data;
+	OAuthAskAuthorizationDialog *self = user_data;
 
 	switch (load_event) {
+	case WEBKIT_LOAD_STARTED:
+	case WEBKIT_LOAD_COMMITTED:
+		g_signal_emit (self, oauth_ask_authorization_dialog_signals[LOAD_REQUEST], 0);
+		break;
 	case WEBKIT_LOAD_REDIRECTED:
-		g_signal_emit (self, oauth2_ask_authorization_dialog_signals[REDIRECTED], 0);
+		g_signal_emit (self, oauth_ask_authorization_dialog_signals[REDIRECTED], 0);
 		break;
 	case WEBKIT_LOAD_FINISHED:
-		g_signal_emit (self, oauth2_ask_authorization_dialog_signals[LOADED], 0);
+		g_signal_emit (self, oauth_ask_authorization_dialog_signals[LOADED], 0);
 		break;
 	default:
 		break;
@@ -94,11 +108,11 @@ webkit_view_load_changed_cb (WebKitWebView   *web_view,
 
 
 static void
-oauth2_ask_authorization_dialog_init (OAuth2AskAuthorizationDialog *self)
+oauth_ask_authorization_dialog_init (OAuthAskAuthorizationDialog *self)
 {
 	GtkWidget *box;
 
-	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, OAUTH2_TYPE_ASK_AUTHORIZATION_DIALOG, OAuth2AskAuthorizationDialogPrivate);
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, OAUTH_TYPE_ASK_AUTHORIZATION_DIALOG, OAuthAskAuthorizationDialogPrivate);
 
 	gtk_window_set_default_size (GTK_WINDOW (self), 500, 500);
 	gtk_window_set_resizable (GTK_WINDOW (self), TRUE);
@@ -126,11 +140,11 @@ oauth2_ask_authorization_dialog_init (OAuth2AskAuthorizationDialog *self)
 
 
 GtkWidget *
-oauth2_ask_authorization_dialog_new (const char *uri)
+oauth_ask_authorization_dialog_new (const char *uri)
 {
-	OAuth2AskAuthorizationDialog *self;
+	OAuthAskAuthorizationDialog *self;
 
-	self = g_object_new (OAUTH2_TYPE_ASK_AUTHORIZATION_DIALOG,
+	self = g_object_new (OAUTH_TYPE_ASK_AUTHORIZATION_DIALOG,
 			     "title", _("Authorization Required"),
 			     NULL);
 	webkit_web_view_load_uri (WEBKIT_WEB_VIEW (self->priv->view), uri);
@@ -140,21 +154,21 @@ oauth2_ask_authorization_dialog_new (const char *uri)
 
 
 GtkWidget *
-oauth2_ask_authorization_dialog_get_view (OAuth2AskAuthorizationDialog *self)
+oauth_ask_authorization_dialog_get_view (OAuthAskAuthorizationDialog *self)
 {
 	return self->priv->view;
 }
 
 
 const char *
-oauth2_ask_authorization_dialog_get_uri (OAuth2AskAuthorizationDialog *self)
+oauth_ask_authorization_dialog_get_uri (OAuthAskAuthorizationDialog *self)
 {
 	return webkit_web_view_get_uri (WEBKIT_WEB_VIEW (self->priv->view));
 }
 
 
 const char *
-oauth2_ask_authorization_dialog_get_title (OAuth2AskAuthorizationDialog *self)
+oauth_ask_authorization_dialog_get_title (OAuthAskAuthorizationDialog *self)
 {
 	return webkit_web_view_get_title (WEBKIT_WEB_VIEW (self->priv->view));
 }
diff --git a/extensions/oauth/oauth-ask-authorization-dialog.h b/extensions/oauth/oauth-ask-authorization-dialog.h
new file mode 100644
index 0000000..b3478a7
--- /dev/null
+++ b/extensions/oauth/oauth-ask-authorization-dialog.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OAUTH_ASK_AUTHORIZATION_DIALOG_H
+#define OAUTH_ASK_AUTHORIZATION_DIALOG_H
+
+#include <gtk/gtk.h>
+#include <gthumb.h>
+
+G_BEGIN_DECLS
+
+#define OAUTH_TYPE_ASK_AUTHORIZATION_DIALOG            (oauth_ask_authorization_dialog_get_type ())
+#define OAUTH_ASK_AUTHORIZATION_DIALOG(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), OAUTH_TYPE_ASK_AUTHORIZATION_DIALOG, OAuthAskAuthorizationDialog))
+#define OAUTH_ASK_AUTHORIZATION_DIALOG_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), OAUTH_TYPE_ASK_AUTHORIZATION_DIALOG, OAuthAskAuthorizationDialogClass))
+#define OAUTH_IS_ASK_AUTHORIZATION_DIALOG(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OAUTH_TYPE_ASK_AUTHORIZATION_DIALOG))
+#define OAUTH_IS_ASK_AUTHORIZATION_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), OAUTH_TYPE_ASK_AUTHORIZATION_DIALOG))
+#define OAUTH_ASK_AUTHORIZATION_DIALOG_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), OAUTH_TYPE_ASK_AUTHORIZATION_DIALOG, OAuthAskAuthorizationDialogClass))
+
+typedef struct _OAuthAskAuthorizationDialog OAuthAskAuthorizationDialog;
+typedef struct _OAuthAskAuthorizationDialogClass OAuthAskAuthorizationDialogClass;
+typedef struct _OAuthAskAuthorizationDialogPrivate OAuthAskAuthorizationDialogPrivate;
+
+struct _OAuthAskAuthorizationDialog {
+	GtkDialog parent_instance;
+	OAuthAskAuthorizationDialogPrivate *priv;
+};
+
+struct _OAuthAskAuthorizationDialogClass {
+	GtkDialogClass parent_class;
+
+	/*< signals >*/
+
+	void  (*load_request)	(OAuthAskAuthorizationDialog *self);
+	void  (*loaded)		(OAuthAskAuthorizationDialog *self);
+	void  (*redirected)	(OAuthAskAuthorizationDialog *self);
+};
+
+GType          oauth_ask_authorization_dialog_get_type     (void);
+GtkWidget *    oauth_ask_authorization_dialog_new          (const char                  *url);
+GtkWidget *    oauth_ask_authorization_dialog_get_view     (OAuthAskAuthorizationDialog *self);
+const char *   oauth_ask_authorization_dialog_get_uri      (OAuthAskAuthorizationDialog *self);
+const char *   oauth_ask_authorization_dialog_get_title    (OAuthAskAuthorizationDialog *self);
+
+G_END_DECLS
+
+#endif /* OAUTH_ASK_AUTHORIZATION_DIALOG_H */
diff --git a/extensions/oauth/oauth-consumer.c b/extensions/oauth/oauth-consumer.c
new file mode 100644
index 0000000..5cc740f
--- /dev/null
+++ b/extensions/oauth/oauth-consumer.c
@@ -0,0 +1,52 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include "oauth-consumer.h"
+
+
+OAuthConsumer *
+oauth_consumer_copy (OAuthConsumer *consumer)
+{
+	OAuthConsumer *consumer_2;
+
+	consumer_2 = g_new0 (OAuthConsumer, 1);
+	consumer_2->consumer_key = consumer->consumer_key;
+	consumer_2->consumer_secret = consumer->consumer_secret;
+	consumer_2->request_token_url = consumer->request_token_url;
+	consumer_2->request_token_response = consumer->request_token_response;
+	consumer_2->get_authorization_url = consumer->get_authorization_url;
+	consumer_2->access_token_url = consumer->access_token_url;
+	consumer_2->access_token_response = consumer->access_token_response;
+
+	return consumer_2;
+}
+
+
+void
+oauth_consumer_free (OAuthConsumer *consumer)
+{
+	if (consumer == NULL)
+		return;
+	g_free (consumer);
+}
diff --git a/extensions/oauth/oauth-consumer.h b/extensions/oauth/oauth-consumer.h
new file mode 100644
index 0000000..9dccf33
--- /dev/null
+++ b/extensions/oauth/oauth-consumer.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OAUTH_CONSUMER_H
+#define OAUTH_CONSUMER_H
+
+
+#include <glib.h>
+#ifdef HAVE_LIBSOUP_GNOME
+#include <libsoup/soup-gnome.h>
+#else
+#include <libsoup/soup.h>
+#endif /* HAVE_LIBSOUP_GNOME */
+#include "oauth-account.h"
+#include "oauth-service.h"
+
+
+typedef void   (*OAuthResponseFunc)	(OAuthService       *self,
+				 	 SoupMessage        *msg,
+				 	 SoupBuffer         *body,
+				 	 GSimpleAsyncResult *result);
+typedef char * (*OAuthStringFunc)      (OAuthService        *self);
+
+
+typedef struct {
+	const char               *consumer_key;
+	const char               *consumer_secret;
+	const char               *request_token_url;
+	OAuthResponseFunc         request_token_response;
+	OAuthStringFunc           get_authorization_url;
+	const char               *access_token_url;
+	OAuthResponseFunc         access_token_response;
+} OAuthConsumer;
+
+
+OAuthConsumer *   oauth_consumer_copy  (OAuthConsumer *consumer);
+void              oauth_consumer_free  (OAuthConsumer *consumer);
+
+
+#endif /* OAUTH_CONSUMER_H */
diff --git a/extensions/oauth/oauth-service.c b/extensions/oauth/oauth-service.c
new file mode 100644
index 0000000..1c4a58e
--- /dev/null
+++ b/extensions/oauth/oauth-service.c
@@ -0,0 +1,541 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gthumb.h>
+#include "oauth-ask-authorization-dialog.h"
+#include "oauth-consumer.h"
+#include "oauth-service.h"
+
+
+#define OAUTH_VERSION "1.0"
+#define OAUTH_SIGNATURE_METHOD "HMAC-SHA1"
+#define OAUTH_CALLBACK "http://localhost/";
+
+
+G_DEFINE_TYPE (OAuthService, oauth_service, WEB_TYPE_SERVICE)
+
+
+enum {
+        PROP_0,
+        PROP_CONSUMER
+};
+
+
+struct _OAuthServicePrivate {
+	OAuthConsumer *consumer;
+	char          *timestamp;
+	char          *nonce;
+	char          *signature;
+	char          *token;
+	char          *token_secret;
+	char          *verifier;
+};
+
+
+static void
+oauth_service_set_property (GObject      *object,
+			    guint         property_id,
+			    const GValue *value,
+			    GParamSpec   *pspec)
+{
+	OAuthService *self;
+
+        self = OAUTH_SERVICE (object);
+
+	switch (property_id) {
+	case PROP_CONSUMER:
+		self->priv->consumer = g_value_get_pointer (value);
+		break;
+	default:
+		break;
+	}
+}
+
+
+static void
+oauth_service_get_property (GObject    *object,
+			    guint       property_id,
+			    GValue     *value,
+			    GParamSpec *pspec)
+{
+	OAuthService *self;
+
+        self = OAUTH_SERVICE (object);
+
+	switch (property_id) {
+	case PROP_CONSUMER:
+		g_value_set_pointer (value, self->priv->consumer);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+
+static void
+oauth_service_finalize (GObject *object)
+{
+	OAuthService *self;
+
+	self = OAUTH_SERVICE (object);
+
+	g_free (self->priv->verifier);
+	g_free (self->priv->token);
+	g_free (self->priv->token_secret);
+	g_free (self->priv->signature);
+	g_free (self->priv->nonce);
+	g_free (self->priv->timestamp);
+
+	G_OBJECT_CLASS (oauth_service_parent_class)->finalize (object);
+}
+
+
+/* -- oauth_service_get_request_token -- */
+
+
+static void
+_oauth_service_get_request_token_ready_cb (SoupSession *session,
+					   SoupMessage *msg,
+					   gpointer     user_data)
+{
+	OAuthService       *self = user_data;
+	GSimpleAsyncResult *result;
+	SoupBuffer         *body;
+
+	result = _web_service_get_result (WEB_SERVICE (self));
+
+	if (msg->status_code != 200) {
+		g_simple_async_result_set_error (result,
+						 SOUP_HTTP_ERROR,
+						 msg->status_code,
+						 "%s",
+						 soup_status_get_phrase (msg->status_code));
+		g_simple_async_result_complete_in_idle (result);
+		return;
+	}
+
+	body = soup_message_body_flatten (msg->response_body);
+	self->priv->consumer->request_token_response (self, msg, body, result);
+	g_simple_async_result_complete_in_idle (result);
+
+	soup_buffer_free (body);
+}
+
+
+static void
+_oauth_service_get_request_token (OAuthService        *self,
+				  GCancellable        *cancellable,
+				  GAsyncReadyCallback  callback,
+				  gpointer             user_data)
+{
+	GHashTable  *data_set;
+	SoupMessage *msg;
+
+	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "oauth_callback", OAUTH_CALLBACK);
+	oauth_service_add_signature (self, "POST", self->priv->consumer->request_token_url, data_set);
+	msg = soup_form_request_new_from_hash ("POST", self->priv->consumer->request_token_url, data_set);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   cancellable,
+				   callback,
+				   user_data,
+				   _oauth_service_get_request_token,
+				   _oauth_service_get_request_token_ready_cb,
+				   self);
+
+	g_hash_table_destroy (data_set);
+}
+
+
+gboolean
+oauth_service_get_request_token_finish (OAuthService  *self,
+					GAsyncResult  *result,
+					GError       **error)
+{
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+	else
+		return TRUE;
+}
+
+
+/* -- _oauth_service_get_access_token -- */
+
+
+static void
+_oauth_service_get_access_token_ready_cb (SoupSession *session,
+					  SoupMessage *msg,
+					  gpointer     user_data)
+{
+	OAuthService       *self = user_data;
+	GSimpleAsyncResult *result;
+	SoupBuffer         *body;
+
+	result = _web_service_get_result (WEB_SERVICE (self));
+
+	if (msg->status_code != 200) {
+		g_simple_async_result_set_error (result,
+						 SOUP_HTTP_ERROR,
+						 msg->status_code,
+						 "%s",
+						 soup_status_get_phrase (msg->status_code));
+		g_simple_async_result_complete_in_idle (result);
+		return;
+	}
+
+	body = soup_message_body_flatten (msg->response_body);
+	self->priv->consumer->access_token_response (self, msg, body, result);
+	g_simple_async_result_complete_in_idle (result);
+
+	soup_buffer_free (body);
+}
+
+
+static void
+_oauth_service_get_access_token (OAuthService        *self,
+				 const char          *verifier,
+				 GCancellable        *cancellable,
+				 GAsyncReadyCallback  callback,
+				 gpointer             user_data)
+{
+	GHashTable  *data_set;
+	SoupMessage *msg;
+
+	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	g_hash_table_insert (data_set, "oauth_verifier", (gpointer) verifier);
+	oauth_service_add_signature (self, "POST", self->priv->consumer->access_token_url, data_set);
+	msg = soup_form_request_new_from_hash ("POST", self->priv->consumer->access_token_url, data_set);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   cancellable,
+				   callback,
+				   user_data,
+				   _oauth_service_get_access_token,
+				   _oauth_service_get_access_token_ready_cb,
+				   self);
+
+	g_hash_table_destroy (data_set);
+}
+
+
+static OAuthAccount *
+_oauth_service_get_access_token_finish (OAuthService  *self,
+					GAsyncResult  *result,
+					GError       **error)
+{
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+	else
+		return g_object_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)));
+}
+
+
+/* -- oauth_service_ask_authorization  -- */
+
+
+static void
+get_access_token_ready_cb (GObject      *source_object,
+			   GAsyncResult *result,
+			   gpointer      user_data)
+{
+	OAuthService *self = user_data;
+	GError       *error = NULL;
+	GtkWidget    *dialog;
+
+	dialog = _web_service_get_auth_dialog (WEB_SERVICE (self));
+
+	if (! _oauth_service_get_access_token_finish (self, result, &error)) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+}
+
+
+static void
+ask_authorization_dialog_load_request_cb (OAuthAskAuthorizationDialog *dialog,
+					  gpointer                     user_data)
+{
+	OAuthService *self = user_data;
+	const char   *uri;
+
+	uri = oauth_ask_authorization_dialog_get_uri (dialog);
+	if (uri == NULL)
+		return;
+
+	g_print ("--> %s\n", oauth_ask_authorization_dialog_get_uri (dialog));
+	g_print (" `--> %s\n", oauth_ask_authorization_dialog_get_title (dialog));
+
+	if (g_str_has_prefix (uri, OAUTH_CALLBACK)) {
+		const char *uri_data;
+		GHashTable *data;
+		gboolean    success = FALSE;
+
+		uri_data = uri + strlen (OAUTH_CALLBACK "?");
+
+		data = soup_form_decode (uri_data);
+		_g_strset (&self->priv->token, g_hash_table_lookup (data, "oauth_token"));
+
+		if (self->priv->token != NULL) {
+			const char *oauth_verifier;
+
+			oauth_verifier = g_hash_table_lookup (data, "oauth_verifier");
+			if (oauth_verifier != NULL) {
+				success = TRUE;
+				_oauth_service_get_access_token (self,
+								 oauth_verifier,
+								 gth_task_get_cancellable (GTH_TASK (self)),
+								 get_access_token_ready_cb,
+								 self);
+			}
+		}
+
+		if (! success)
+			gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_CANCEL);
+
+		g_hash_table_destroy (data);
+	}
+}
+
+
+static void
+get_request_token_ready_cb (GObject      *source_object,
+	        	    GAsyncResult *result,
+	        	    gpointer      user_data)
+{
+	OAuthService *self = user_data;
+	GError       *error = NULL;
+	char         *url;
+	GtkWidget    *dialog;
+
+	if (! oauth_service_get_request_token_finish (self, result, &error)) {
+		gth_task_completed (GTH_TASK (self), error);
+		return;
+	}
+
+	gth_task_dialog (GTH_TASK (self), TRUE, NULL);
+
+	url = self->priv->consumer->get_authorization_url (self);
+	dialog = oauth_ask_authorization_dialog_new (url);
+	_gtk_window_resize_to_fit_screen_height (dialog, 800);
+	_web_service_set_auth_dialog (WEB_SERVICE (self), GTK_DIALOG (dialog));
+	g_signal_connect (OAUTH_ASK_AUTHORIZATION_DIALOG (dialog),
+			  "load-request",
+			  G_CALLBACK (ask_authorization_dialog_load_request_cb),
+			  self);
+	gtk_widget_show (dialog);
+
+	g_free (url);
+}
+
+
+static void
+oauth_service_ask_authorization (WebService *base)
+{
+	OAuthService *self = OAUTH_SERVICE (base);
+
+	oauth_service_set_token (self, NULL);
+	oauth_service_set_token_secret (self, NULL);
+	_oauth_service_get_request_token (self,
+					  gth_task_get_cancellable (GTH_TASK (self)),
+					  get_request_token_ready_cb,
+					  self);
+}
+
+
+static void
+oauth_service_class_init (OAuthServiceClass *klass)
+{
+	GObjectClass    *object_class;
+	WebServiceClass *service_class;
+
+	g_type_class_add_private (klass, sizeof (OAuthServicePrivate));
+
+	object_class = (GObjectClass*) klass;
+	object_class->set_property = oauth_service_set_property;
+	object_class->get_property = oauth_service_get_property;
+	object_class->finalize = oauth_service_finalize;
+
+	service_class = (WebServiceClass*) klass;
+	service_class->ask_authorization = oauth_service_ask_authorization;
+
+	/* properties */
+
+	g_object_class_install_property (object_class,
+					 PROP_CONSUMER,
+					 g_param_spec_pointer ("consumer",
+                                                               "Consumer",
+                                                               "",
+                                                               G_PARAM_READWRITE));
+}
+
+
+static void
+oauth_service_init (OAuthService *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, OAUTH_TYPE_SERVICE, OAuthServicePrivate);
+	self->priv->consumer = NULL;
+	self->priv->timestamp = NULL;
+	self->priv->nonce = NULL;
+	self->priv->signature = NULL;
+	self->priv->token = NULL;
+	self->priv->token_secret = NULL;
+	self->priv->verifier = NULL;
+}
+
+
+/* -- oauth_service_add_signature -- */
+
+
+static char *
+oauth_create_timestamp (GTimeVal *t)
+{
+	return g_strdup_printf ("%ld", t->tv_sec);
+}
+
+
+static char *
+oauth_create_nonce (GTimeVal *t)
+{
+	char *s;
+	char *v;
+
+	s = g_strdup_printf ("%ld%u", t->tv_usec, g_random_int ());
+	v = g_compute_checksum_for_string (G_CHECKSUM_MD5, s, -1);
+
+	g_free (s);
+
+	return v;
+}
+
+
+void
+oauth_service_add_signature (OAuthService *self,
+			     const char   *method,
+			     const char   *url,
+			     GHashTable   *parameters)
+{
+	GTimeVal  t;
+	GString  *param_string;
+	GList    *keys;
+	GList    *scan;
+	GString  *base_string;
+	GString  *signature_key;
+
+	/* Add the OAuth specific parameters */
+
+	g_get_current_time (&t);
+
+	g_free (self->priv->timestamp);
+	self->priv->timestamp = oauth_create_timestamp (&t);
+	g_hash_table_insert (parameters, "oauth_timestamp", self->priv->timestamp);
+
+	g_free (self->priv->nonce);
+	self->priv->nonce = oauth_create_nonce (&t);
+	g_hash_table_insert (parameters, "oauth_nonce", self->priv->nonce);
+	g_hash_table_insert (parameters, "oauth_version", OAUTH_VERSION);
+	g_hash_table_insert (parameters, "oauth_signature_method", OAUTH_SIGNATURE_METHOD);
+	g_hash_table_insert (parameters, "oauth_consumer_key", (gpointer) self->priv->consumer->consumer_key);
+	if (self->priv->token != NULL)
+		g_hash_table_insert (parameters, "oauth_token", self->priv->token);
+
+	/* Create the parameter string */
+
+	param_string = g_string_new ("");
+	keys = g_hash_table_get_keys (parameters);
+	keys = g_list_sort (keys, (GCompareFunc) strcmp);
+	for (scan = keys; scan; scan = scan->next) {
+		char *key = scan->data;
+		char *value = g_hash_table_lookup (parameters, key);
+
+		g_string_append_uri_escaped (param_string, key, NULL, FALSE);
+		g_string_append (param_string, "=");
+		g_string_append_uri_escaped (param_string, value, NULL, FALSE);
+		if (scan->next != NULL)
+			g_string_append (param_string, "&");
+	}
+
+	/* Create the Base String */
+
+	base_string = g_string_new ("");
+	g_string_append_uri_escaped (base_string, method, NULL, FALSE);
+	g_string_append (base_string, "&");
+	g_string_append_uri_escaped (base_string, url, NULL, FALSE);
+	g_string_append (base_string, "&");
+	g_string_append_uri_escaped (base_string, param_string->str, NULL, FALSE);
+
+	/* Calculate the signature value */
+
+	signature_key = g_string_new ("");
+	g_string_append_uri_escaped (signature_key, self->priv->consumer->consumer_secret, NULL, FALSE);
+	g_string_append (signature_key, "&");
+	if (self->priv->token_secret != NULL)
+		g_string_append_uri_escaped (signature_key, self->priv->token_secret, NULL, FALSE);
+	g_free (self->priv->signature);
+	self->priv->signature = g_compute_signature_for_string (G_CHECKSUM_SHA1,
+								G_SIGNATURE_ENC_BASE64,
+							        signature_key->str,
+							        signature_key->len,
+							        base_string->str,
+							        base_string->len);
+	g_hash_table_insert (parameters, "oauth_signature", self->priv->signature);
+
+	g_string_free (signature_key, TRUE);
+	g_string_free (base_string, TRUE);
+	g_list_free (keys);
+	g_string_free (param_string, TRUE);
+}
+
+
+void
+oauth_service_set_token (OAuthService *self,
+			 const char   *token)
+{
+	_g_strset (&self->priv->token, token);
+}
+
+
+const char *
+oauth_service_get_token (OAuthService *self)
+{
+	return self->priv->token;
+}
+
+
+void
+oauth_service_set_token_secret (OAuthService *self,
+				const char   *token_secret)
+{
+	_g_strset (&self->priv->token_secret, token_secret);
+}
+
+
+const char *
+oauth_service_get_token_secret (OAuthService *self)
+{
+	return self->priv->token_secret;
+}
diff --git a/extensions/oauth/oauth-service.h b/extensions/oauth/oauth-service.h
new file mode 100644
index 0000000..4c600be
--- /dev/null
+++ b/extensions/oauth/oauth-service.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  GThumb
+ *
+ *  Copyright (C) 2012 Free Software Foundation, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef OAUTH_SERVICE_H
+#define OAUTH_SERVICE_H
+
+#include <glib-object.h>
+#include "web-service.h"
+
+#define OAUTH_TYPE_SERVICE         (oauth_service_get_type ())
+#define OAUTH_SERVICE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), OAUTH_TYPE_SERVICE, OAuthService))
+#define OAUTH_SERVICE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), OAUTH_TYPE_SERVICE, OAuthServiceClass))
+#define OAUTH_IS_SERVICE(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), OAUTH_TYPE_SERVICE))
+#define OAUTH_IS_SERVICE_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), OAUTH_TYPE_SERVICE))
+#define OAUTH_SERVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), OAUTH_TYPE_SERVICE, OAuthServiceClass))
+
+typedef struct _OAuthService         OAuthService;
+typedef struct _OAuthServicePrivate  OAuthServicePrivate;
+typedef struct _OAuthServiceClass    OAuthServiceClass;
+
+struct _OAuthService {
+	WebService __parent;
+	OAuthServicePrivate *priv;
+};
+
+struct _OAuthServiceClass {
+	WebServiceClass __parent_class;
+};
+
+GType		oauth_service_get_type		(void) G_GNUC_CONST;
+void		oauth_service_add_signature	(OAuthService *self,
+						 const char   *method,
+						 const char   *url,
+						 GHashTable   *parameters);
+void            oauth_service_set_token         (OAuthService *self,
+					         const char   *token);
+const char *    oauth_service_get_token         (OAuthService *self);
+void            oauth_service_set_token_secret  (OAuthService *self,
+						 const char   *token_secret);
+const char *    oauth_service_get_token_secret  (OAuthService *self);
+
+#endif /* OAUTH_SERVICE_H */
diff --git a/extensions/oauth/oauth.h b/extensions/oauth/oauth.h
index 6b0f5a3..42bde07 100644
--- a/extensions/oauth/oauth.h
+++ b/extensions/oauth/oauth.h
@@ -22,12 +22,12 @@
 #ifndef OAUTH_H
 #define OAUTH_H
 
-#include <extensions/oauth/oauth2-ask-authorization-dialog.h>
 #include <extensions/oauth/oauth-account.h>
 #include <extensions/oauth/oauth-account-chooser-dialog.h>
 #include <extensions/oauth/oauth-account-manager-dialog.h>
-#include <extensions/oauth/oauth-authentication.h>
-#include <extensions/oauth/oauth-connection.h>
+#include <extensions/oauth/oauth-ask-authorization-dialog.h>
+#include <extensions/oauth/oauth-consumer.h>
+#include <extensions/oauth/oauth-service.h>
 #include <extensions/oauth/web-service.h>
 
 #endif /* OAUTH_H */
diff --git a/extensions/oauth/web-service.c b/extensions/oauth/web-service.c
index 0c7aba4..6ccb383 100644
--- a/extensions/oauth/web-service.c
+++ b/extensions/oauth/web-service.c
@@ -30,6 +30,8 @@
 #ifdef HAVE_LIBSECRET
 #include <libsecret/secret.h>
 #endif /* HAVE_LIBSECRET */
+#include "oauth-account-manager-dialog.h"
+#include "oauth-account-chooser-dialog.h"
 #include "web-service.h"
 
 
@@ -57,6 +59,7 @@ enum {
         PROP_SERVICE_NAME,
         PROP_SERVICE_ADDRESS,
         PROP_SERVICE_PROTOCOL,
+        PROP_ACCOUNT_TYPE,
 	PROP_CANCELLABLE,
 	PROP_BROWSER,
 	PROP_DIALOG
@@ -79,6 +82,7 @@ struct _WebServicePrivate
 	char               *service_name;
 	char               *service_address;
 	char               *service_protocol;
+	GType               account_type;
 	SoupSession        *session;
 	SoupMessage        *msg;
 	GCancellable       *cancellable;
@@ -127,6 +131,9 @@ web_service_set_property (GObject      *object,
 	case PROP_SERVICE_PROTOCOL:
 		_g_strset (&self->priv->service_protocol, g_value_get_string (value));
 		break;
+	case PROP_ACCOUNT_TYPE:
+		self->priv->account_type = g_value_get_gtype (value);
+		break;
 	case PROP_CANCELLABLE:
 		_g_object_unref (self->priv->cancellable);
 		self->priv->cancellable = g_value_dup_object (value);
@@ -161,6 +168,9 @@ web_service_get_property (GObject    *object,
 	case PROP_SERVICE_PROTOCOL:
 		g_value_set_string (value, self->priv->service_protocol);
 		break;
+	case PROP_ACCOUNT_TYPE:
+		g_value_set_gtype (value, self->priv->account_type);
+		break;
 	case PROP_CANCELLABLE:
 		g_value_set_object (value, self->priv->cancellable);
 		break;
@@ -182,7 +192,7 @@ web_service_constructed (GObject *object)
 {
 	WebService *self = WEB_SERVICE (object);
 
-	self->priv->accounts = oauth_accounts_load_from_file (self->priv->service_name, 0);
+	self->priv->accounts = oauth_accounts_load_from_file (self->priv->service_name, self->priv->account_type);
 	self->priv->account = oauth_accounts_find_default (self->priv->accounts);
 
 	if (G_OBJECT_CLASS (web_service_parent_class)->constructed != NULL)
@@ -253,6 +263,13 @@ web_service_class_init (WebServiceClass *klass)
                                                               NULL,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 	g_object_class_install_property (object_class,
+					 PROP_ACCOUNT_TYPE,
+					 g_param_spec_gtype ("account-type",
+                                                             "Account type",
+                                                             "",
+                                                             OAUTH_TYPE_ACCOUNT,
+                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+	g_object_class_install_property (object_class,
 					 PROP_CANCELLABLE,
 					 g_param_spec_object ("cancellable",
                                                               "Cancellable",
@@ -299,13 +316,16 @@ static void
 web_service_init (WebService *self)
 {
 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, WEB_TYPE_SERVICE, WebServicePrivate);
+	self->priv->service_name = NULL;
+	self->priv->service_address = NULL;
+	self->priv->service_protocol = NULL;
+	self->priv->account_type = OAUTH_TYPE_ACCOUNT;
 	self->priv->session = NULL;
 	self->priv->msg = NULL;
 	self->priv->cancellable = NULL;
 	self->priv->result = NULL;
 	self->priv->accounts = NULL;
 	self->priv->account = NULL;
-	self->priv->cancellable = NULL;
 	self->priv->browser = NULL;
 	self->priv->dialog = NULL;
 	self->priv->auth_dialog = NULL;
@@ -382,11 +402,14 @@ show_authentication_error_dialog (WebService  *self,
 
 
 static void
-set_current_account (WebService *self,
-		     OAuthAccount    *account)
+set_current_account (WebService   *self,
+		     OAuthAccount *account)
 {
 	GList *link;
 
+	if (self->priv->account == account)
+		return;
+
 	link = g_list_find_custom (self->priv->accounts, self->priv->account, (GCompareFunc) oauth_account_cmp);
 	if (link != NULL) {
 		self->priv->accounts = g_list_remove_link (self->priv->accounts, link);
@@ -404,6 +427,54 @@ set_current_account (WebService *self,
 
 
 #ifdef HAVE_LIBSECRET
+
+
+static char *
+serialize_secret (const char *token,
+		  const char *token_secret)
+{
+	GVariantBuilder *builder;
+	GVariant        *variant;
+	char            *secret;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+	g_variant_builder_add (builder, "ms", token);
+	g_variant_builder_add (builder, "ms", token_secret);
+	variant = g_variant_builder_end (builder);
+	secret = g_variant_print (variant, TRUE);
+
+	g_variant_unref (variant);
+
+	return secret;
+}
+
+
+static gboolean
+deserialize_secret (const char  *secret,
+		    char       **token,
+		    char       **token_secret)
+{
+	GError   *error = NULL;
+	GVariant *variant;
+
+	variant = g_variant_parse (NULL, secret, NULL, NULL, &error);
+	if (variant == NULL) {
+		g_warning ("%s", error->message);
+		g_clear_error (&error);
+		return FALSE;
+	}
+
+	if (token != NULL)
+		g_variant_get_child (variant, 0, "ms", token, NULL);
+	if (token_secret != NULL)
+		g_variant_get_child (variant, 1, "ms", token_secret, NULL);
+
+	g_variant_unref (variant);
+
+	return TRUE;
+}
+
+
 static void
 password_store_ready_cb (GObject      *source_object,
 			 GAsyncResult *result,
@@ -414,6 +485,8 @@ password_store_ready_cb (GObject      *source_object,
 	secret_password_store_finish (result, NULL);
 	web_service_account_ready (self);
 }
+
+
 #endif
 
 
@@ -439,10 +512,13 @@ get_user_info_ready_cb (GObject      *source_object,
 
 #ifdef HAVE_LIBSECRET
 	{
+		char *secret;
+
+		secret = serialize_secret (account->token, account->token_secret);
 		secret_password_store (SECRET_SCHEMA_COMPAT_NETWORK,
 				       NULL,
 				       self->priv->service_name,
-				       account->token_secret,
+				       secret,
 				       self->priv->cancellable,
 				       password_store_ready_cb,
 				       self,
@@ -450,6 +526,8 @@ get_user_info_ready_cb (GObject      *source_object,
 				       "server", self->priv->service_address,
 				       "protocol", self->priv->service_protocol,
 				       NULL);
+
+		g_free (secret);
 	}
 #else
 	web_service_account_ready (self);
@@ -462,7 +540,7 @@ get_user_info_ready_cb (GObject      *source_object,
 static void
 connect_to_server_step2 (WebService *self)
 {
-	if (self->priv->account->token_secret == NULL) {
+	if ((self->priv->account->token == NULL) && (self->priv->account->token_secret == NULL)) {
 		web_service_ask_authorization (self);
 		return;
 	}
@@ -474,6 +552,8 @@ connect_to_server_step2 (WebService *self)
 
 
 #ifdef HAVE_LIBSECRET
+
+
 static void
 password_lookup_ready_cb (GObject      *source_object,
 			  GAsyncResult *result,
@@ -484,12 +564,26 @@ password_lookup_ready_cb (GObject      *source_object,
 
 	secret = secret_password_lookup_finish (result, NULL);
 	if (secret != NULL) {
-		g_object_set (G_OBJECT (self->priv->account), "token-secret", secret, NULL);
+		char *token;
+		char *token_secret;
+
+		if (deserialize_secret (secret, &token, &token_secret)) {
+			g_object_set (G_OBJECT (self->priv->account),
+				      "token", token,
+				      "token-secret", token_secret,
+				      NULL);
+
+			g_free (token);
+			g_free (token_secret);
+		}
+
 		g_free (secret);
 	}
 
 	connect_to_server_step2 (self);
 }
+
+
 #endif
 
 
@@ -609,10 +703,7 @@ void
 web_service_set_current_account (WebService   *self,
 				 OAuthAccount *account)
 {
-	if (account == self->priv->account)
-		return;
-	_g_object_unref (self->priv->account);
-	self->priv->account = _g_object_ref (account);
+	set_current_account (self, account);
 }
 
 
@@ -795,6 +886,13 @@ _web_service_get_result (WebService *self)
 }
 
 
+void
+_web_service_reset_result (WebService *self)
+{
+	self->priv->result = NULL;
+}
+
+
 SoupMessage *
 _web_service_get_message (WebService *self)
 {
diff --git a/extensions/oauth/web-service.h b/extensions/oauth/web-service.h
index d2c0559..18f0b2f 100644
--- a/extensions/oauth/web-service.h
+++ b/extensions/oauth/web-service.h
@@ -24,7 +24,7 @@
 
 #include <gtk/gtk.h>
 #include <gthumb.h>
-#include "oauth.h"
+#include "oauth-account.h"
 
 #define WEB_SERVICE_ERROR web_service_error_quark()
 GQuark web_service_error_quark (void);
@@ -50,14 +50,12 @@ typedef struct _WebService         WebService;
 typedef struct _WebServicePrivate  WebServicePrivate;
 typedef struct _WebServiceClass    WebServiceClass;
 
-struct _WebService
-{
+struct _WebService {
 	GthTask __parent;
 	WebServicePrivate *priv;
 };
 
-struct _WebServiceClass
-{
+struct _WebServiceClass {
 	GthTaskClass __parent_class;
 
 	/*< signals >*/
@@ -106,6 +104,7 @@ void            _web_service_send_message	(WebService		 *self,
 						 gpointer		  soup_session_cb_data);
 GSimpleAsyncResult *
 		_web_service_get_result		(WebService		 *self);
+void            _web_service_reset_result       (WebService		 *self);
 SoupMessage *	_web_service_get_message	(WebService		 *self);
 void            _web_service_set_auth_dialog	(WebService		 *self,
 						 GtkDialog               *dialog);
diff --git a/extensions/photobucket/dlg-export-to-photobucket.c b/extensions/photobucket/dlg-export-to-photobucket.c
index 1411186..9d8658a 100644
--- a/extensions/photobucket/dlg-export-to-photobucket.c
+++ b/extensions/photobucket/dlg-export-to-photobucket.c
@@ -22,7 +22,7 @@
 #include <config.h>
 #include <gtk/gtk.h>
 #include <gthumb.h>
-#include <extensions/oauth/oauth-authentication.h>
+#include <extensions/oauth/oauth.h>
 #include "dlg-export-to-photobucket.h"
 #include "photobucket-account.h"
 #include "photobucket-album-properties-dialog.h"
@@ -62,10 +62,7 @@ typedef struct {
 	GtkWidget           *dialog;
 	GtkWidget           *progress_dialog;
 	GtkWidget           *list_view;
-	OAuthConnection     *conn;
-	OAuthAuthentication *auth;
 	PhotobucketService  *service;
-	PhotobucketAccount  *account;
 	GList               *albums;
 	PhotobucketAlbum    *album;
 	GCancellable        *cancellable;
@@ -77,14 +74,11 @@ destroy_dialog (DialogData *data)
 {
 	if (data->dialog != NULL)
 		gtk_widget_destroy (data->dialog);
-	if (data->conn != NULL)
-		gth_task_completed (GTH_TASK (data->conn), NULL);
+	if (data->service != NULL)
+		gth_task_completed (GTH_TASK (data->service), NULL);
 	_g_object_unref (data->cancellable);
 	_g_object_unref (data->album);
 	_g_object_list_unref (data->albums);
-	_g_object_unref (data->account);
-	_g_object_unref (data->auth);
-	_g_object_unref (data->conn);
 	_g_object_unref (data->builder);
 	_g_object_list_unref (data->file_list);
 	_g_object_unref (data->location);
@@ -108,28 +102,31 @@ completed_messagedialog_response_cb (GtkDialog *dialog,
 
 	case _OPEN_IN_BROWSER_RESPONSE:
 		{
-			GdkScreen *screen;
-			char      *url = NULL;
-			GError    *error = NULL;
+			GdkScreen    *screen;
+			OAuthAccount *account;
+			char         *url = NULL;
+			GError       *error = NULL;
 
 			screen = gtk_widget_get_screen (GTK_WIDGET (dialog));
 			gtk_widget_destroy (GTK_WIDGET (dialog));
 
-			if (data->account->album_url != NULL) {
+			account = web_service_get_current_account (WEB_SERVICE (data->service));
+
+			if (PHOTOBUCKET_ACCOUNT (account)->album_url != NULL) {
 				char *username;
 
-				username = OAUTH_ACCOUNT (data->account)->username;
+				username = account->username;
 				if (g_str_equal (data->album->name, username))
-					url = g_strdup (data->account->album_url);
+					url = g_strdup (PHOTOBUCKET_ACCOUNT (account)->album_url);
 				else
-					url = g_strconcat (data->account->album_url,
+					url = g_strconcat (PHOTOBUCKET_ACCOUNT (account)->album_url,
 							   data->album->name + strlen (username) + 1,
 							   NULL);
 			}
 
 			if ((url != NULL) && ! gtk_show_uri (screen, url, 0, &error)) {
-				if (data->conn != NULL)
-					gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+				if (data->service != NULL)
+					gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 				_gtk_error_dialog_from_gerror_run (GTK_WINDOW (data->browser), _("Could not connect to the server"), error);
 				g_clear_error (&error);
 			}
@@ -152,7 +149,7 @@ export_completed_with_success (DialogData *data)
 	GtkBuilder *builder;
 	GtkWidget  *dialog;
 
-	gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+	gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 
 	builder = _gtk_builder_new_from_file ("photobucket-export-completed.ui", "photobucket");
 	dialog = _gtk_builder_get_widget (builder, "completed_messagedialog");
@@ -215,7 +212,7 @@ export_dialog_response_cb (GtkDialog *dialog,
 			int          size;
 
 			gtk_widget_hide (data->dialog);
-			gth_task_dialog (GTH_TASK (data->conn), FALSE, NULL);
+			gth_task_dialog (GTH_TASK (data->service), FALSE, NULL);
 
 			_g_clear_object (&data->album);
 			if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (GET_WIDGET ("album_combobox")), &iter)) {
@@ -235,7 +232,6 @@ export_dialog_response_cb (GtkDialog *dialog,
 
 			file_list = gth_file_data_list_to_file_list (data->file_list);
 			photobucket_service_upload_photos (data->service,
-							   data->account,
 							   data->album,
 							   size,
 							   gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (GET_WIDGET ("scramble_checkbutton"))),
@@ -267,11 +263,11 @@ update_account_list (DialogData *data)
 	gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("account_liststore")));
 
 	current_account_idx = 0;
-	current_account = oauth_authentication_get_account (data->auth);
-	for (scan = oauth_authentication_get_accounts (data->auth), idx = 0; scan; scan = scan->next, idx++) {
+	current_account = web_service_get_current_account (WEB_SERVICE (data->service));
+	for (scan = web_service_get_accounts (WEB_SERVICE (data->service)), idx = 0; scan; scan = scan->next, idx++) {
 		OAuthAccount *account = scan->data;
 
-		if ((current_account != NULL) && (g_strcmp0 (current_account->username, account->username) == 0))
+		if (oauth_account_cmp (current_account, account) == 0)
 			current_account_idx = idx;
 
 		gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("account_liststore")), &iter);
@@ -282,11 +278,11 @@ update_account_list (DialogData *data)
 	}
 	gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("account_combobox")), current_account_idx);
 
-	free_space = g_format_size ((data->account->megabytes_allowed - data->account->megabytes_used) * (1024 * 1024));
+	free_space = g_format_size ((PHOTOBUCKET_ACCOUNT (current_account)->megabytes_allowed - PHOTOBUCKET_ACCOUNT (current_account)->megabytes_used) * (1024 * 1024));
 	gtk_label_set_text (GTK_LABEL (GET_WIDGET ("free_space_label")), free_space);
 	g_free (free_space);
 
-	if (data->account != NULL) {
+	if (current_account != NULL) {
 		struct {
 			char *name;
 			int   size;
@@ -307,7 +303,7 @@ update_account_list (DialogData *data)
 		int i;
 
 		gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("resize_liststore")));
-		for (i = 0; i <= (data->account->is_premium ? 13 : 6); i++) {
+		for (i = 0; i <= (PHOTOBUCKET_ACCOUNT (current_account)->is_premium ? 13 : 6); i++) {
 			gtk_list_store_append (GTK_LIST_STORE (GET_WIDGET ("resize_liststore")), &iter);
 			gtk_list_store_set (GTK_LIST_STORE (GET_WIDGET ("resize_liststore")), &iter,
 					    RESIZE_NAME_COLUMN, _(sizes[i].name),
@@ -315,16 +311,16 @@ update_account_list (DialogData *data)
 					    -1);
 		}
 
-		gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("resize_combobox")), (data->account->is_premium ? 13 : 5));
+		gtk_combo_box_set_active (GTK_COMBO_BOX (GET_WIDGET ("resize_combobox")), (PHOTOBUCKET_ACCOUNT (current_account)->is_premium ? 13 : 5));
 	}
 }
 
 
 static void
-authentication_accounts_changed_cb (OAuthAuthentication *auth,
-				    gpointer             user_data)
+authentication_accounts_changed_cb (WebService *service,
+				    DialogData *data)
 {
-	update_account_list ((DialogData *) user_data);
+	update_account_list (data);
 }
 
 
@@ -373,8 +369,8 @@ album_list_ready_cb (GObject      *source_object,
 	_g_object_list_unref (data->albums);
 	data->albums = photobucket_service_get_albums_finish (data->service, res, &error);
 	if (error != NULL) {
-		if (data->conn != NULL)
-			gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+		if (data->service != NULL)
+			gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 		_gtk_error_dialog_from_gerror_run (GTK_WINDOW (data->browser), _("Could not connect to the server"), error);
 		g_clear_error (&error);
 		gtk_widget_destroy (data->dialog);
@@ -382,7 +378,7 @@ album_list_ready_cb (GObject      *source_object,
 	}
 	update_album_list (data);
 
-	gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+	gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 
 	gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (data->browser));
 	gtk_window_set_modal (GTK_WINDOW (data->dialog), FALSE);
@@ -391,15 +387,11 @@ album_list_ready_cb (GObject      *source_object,
 
 
 static void
-authentication_ready_cb (OAuthAuthentication *auth,
-			 DialogData          *data)
+authentication_ready_cb (WebService *service,
+			 DialogData *data)
 {
-	_g_object_unref (data->account);
-	data->account = g_object_ref (oauth_authentication_get_account (auth));
 	update_account_list (data);
-
 	photobucket_service_get_albums (data->service,
-					data->account,
 				        data->cancellable,
 				        album_list_ready_cb,
 				        data);
@@ -410,7 +402,7 @@ static void
 edit_accounts_button_clicked_cb (GtkButton  *button,
 				 DialogData *data)
 {
-	oauth_authentication_edit_accounts (data->auth, GTK_WINDOW (data->dialog));
+	web_service_edit_accounts (WEB_SERVICE (data->service), GTK_WINDOW (data->dialog));
 }
 
 
@@ -430,8 +422,8 @@ account_combobox_changed_cb (GtkComboBox *widget,
 			    ACCOUNT_DATA_COLUMN, &account,
 			    -1);
 
-	if (oauth_account_cmp (account, oauth_authentication_get_account (data->auth)) != 0)
-		oauth_authentication_connect (data->auth, account);
+	if (oauth_account_cmp (account, web_service_get_current_account (WEB_SERVICE (data->service))) != 0)
+		web_service_connect (WEB_SERVICE (data->service), account);
 
 	g_object_unref (account);
 }
@@ -459,8 +451,8 @@ create_album_ready_cb (GObject      *source_object,
 	_g_object_unref (data->album);
 	data->album = photobucket_service_create_album_finish (data->service, result, &error);
 	if (error != NULL) {
-		if (data->conn != NULL)
-			gth_task_dialog (GTH_TASK (data->conn), TRUE, NULL);
+		if (data->service != NULL)
+			gth_task_dialog (GTH_TASK (data->service), TRUE, NULL);
 		_gtk_error_dialog_from_gerror_show (GTK_WINDOW (data->browser), _("Could not create the album"), error);
 		g_clear_error (&error);
 		return;
@@ -496,7 +488,6 @@ new_album_dialog_response_cb (GtkDialog *dialog,
 			album = photobucket_album_new ();
 			photobucket_album_set_name (album, photobucket_album_properties_dialog_get_name (PHOTOBUCKET_ALBUM_PROPERTIES_DIALOG (dialog)));
 			photobucket_service_create_album (data->service,
-							  data->account,
 							  parent_album,
 						          album,
 						          data->cancellable,
@@ -640,7 +631,7 @@ dlg_export_to_photobucket (GthBrowser *browser,
 
 	gtk_widget_set_sensitive (GET_WIDGET ("upload_button"), FALSE);
 
-	title = g_strdup_printf (_("Export to %s"), photobucket_consumer.display_name);
+	title = g_strdup_printf (_("Export to %s"), "Photobucket");
 	gtk_window_set_title (GTK_WINDOW (data->dialog), title);
 	g_free (title);
 
@@ -671,25 +662,21 @@ dlg_export_to_photobucket (GthBrowser *browser,
 			  G_CALLBACK (album_combobox_changed_cb),
 			  data);
 
-	data->conn = oauth_connection_new (&photobucket_consumer);
-	data->auth = oauth_authentication_new (data->conn,
-					       PHOTOBUCKET_TYPE_ACCOUNT,
-					       data->cancellable,
-					       GTK_WIDGET (data->browser),
-					       data->dialog);
-	g_signal_connect (data->auth,
-			  "ready",
+
+	data->service = photobucket_service_new (data->cancellable,
+						 GTK_WIDGET (data->browser),
+						 data->dialog);
+	g_signal_connect (data->service,
+			  "account-ready",
 			  G_CALLBACK (authentication_ready_cb),
 			  data);
-	g_signal_connect (data->auth,
-			  "accounts_changed",
+	g_signal_connect (data->service,
+			  "accounts-changed",
 			  G_CALLBACK (authentication_accounts_changed_cb),
 			  data);
 
-	data->service = photobucket_service_new (data->conn);
-
 	data->progress_dialog = gth_progress_dialog_new (GTK_WINDOW (data->browser));
-	gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (data->progress_dialog), GTH_TASK (data->conn));
+	gth_progress_dialog_add_task (GTH_PROGRESS_DIALOG (data->progress_dialog), GTH_TASK (data->service));
 
-	oauth_authentication_auto_connect (data->auth);
+	web_service_autoconnect (WEB_SERVICE (data->service));
 }
diff --git a/extensions/photobucket/photobucket-account.c b/extensions/photobucket/photobucket-account.c
index db7bf75..98049bf 100644
--- a/extensions/photobucket/photobucket-account.c
+++ b/extensions/photobucket/photobucket-account.c
@@ -62,11 +62,10 @@ static DomElement*
 photobucket_account_create_element (DomDomizable *base,
 				    DomDocument  *doc)
 {
-	PhotobucketAccount *self;
+	PhotobucketAccount *self = PHOTOBUCKET_ACCOUNT (base);
 	DomElement         *element;
 
-	self = PHOTOBUCKET_ACCOUNT (base);
-	element = dom_domizable_create_element (DOM_DOMIZABLE (self), doc);
+	element = oauth_account_create_element (base, doc);
 	if (self->subdomain != NULL)
 		dom_element_set_attribute (element, "subdomain", self->subdomain);
 
@@ -78,9 +77,7 @@ static void
 photobucket_account_load_from_element (DomDomizable *base,
 				       DomElement   *element)
 {
-	PhotobucketAccount *self;
-
-	self = PHOTOBUCKET_ACCOUNT (base);
+	PhotobucketAccount *self = PHOTOBUCKET_ACCOUNT (base);
 
 	if (g_str_equal (element->tag_name, "content")) {
 		DomElement *node;
@@ -104,7 +101,7 @@ photobucket_account_load_from_element (DomDomizable *base,
 		}
 	}
 	else if (g_str_equal (element->tag_name, "account")) {
-		dom_domizable_load_from_element (DOM_DOMIZABLE (self), element);
+		oauth_account_load_from_element (base, element);
 		photobucket_account_set_subdomain (self, dom_element_get_attribute (element, "subdomain"));
 	}
 }
diff --git a/extensions/photobucket/photobucket-consumer.c b/extensions/photobucket/photobucket-consumer.c
index 41cda6f..8788adb 100644
--- a/extensions/photobucket/photobucket-consumer.c
+++ b/extensions/photobucket/photobucket-consumer.c
@@ -71,10 +71,10 @@ photobucket_utils_parse_response (SoupMessage         *msg,
 			}
 
 			if (status == NULL) {
-				*error = g_error_new_literal (OAUTH_CONNECTION_ERROR, 999, _("Unknown error"));
+				*error = g_error_new_literal (WEB_SERVICE_ERROR, 999, _("Unknown error"));
 			}
 			else if (strcmp (status, "Exception") == 0) {
-				*error = g_error_new_literal (OAUTH_CONNECTION_ERROR,
+				*error = g_error_new_literal (WEB_SERVICE_ERROR,
 							      (code != NULL) ? atoi (code) : 999,
 							      (message != NULL) ? message : _("Unknown error"));
 			}
@@ -93,7 +93,7 @@ photobucket_utils_parse_response (SoupMessage         *msg,
 
 
 static void
-photobucket_login_request_response (OAuthConnection    *self,
+photobucket_request_token_response (OAuthService       *self,
 				    SoupMessage        *msg,
 				    SoupBuffer         *body,
 				    GSimpleAsyncResult *result)
@@ -106,13 +106,14 @@ photobucket_login_request_response (OAuthConnection    *self,
 	token = g_hash_table_lookup (values, "oauth_token");
 	token_secret = g_hash_table_lookup (values, "oauth_token_secret");
 	if ((token != NULL) && (token_secret != NULL)) {
-		oauth_connection_set_token (self, token, token_secret);
+		oauth_service_set_token (self, token);
+		oauth_service_set_token_secret (self, token_secret);
 		g_simple_async_result_set_op_res_gboolean (result, TRUE);
 	}
 	else {
 		GError *error;
 
-		error = g_error_new_literal (OAUTH_CONNECTION_ERROR, 0, _("Unknown error"));
+		error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
 		g_simple_async_result_set_from_error (result, error);
 	}
 
@@ -121,25 +122,27 @@ photobucket_login_request_response (OAuthConnection    *self,
 
 
 static char *
-photobucket_get_login_link (OAuthConnection *self)
+photobucket_get_authorization_url (OAuthService *self)
 {
-	char *token;
+	char *escaped_token;
 	char *uri;
 
-	token = soup_uri_encode (oauth_connection_get_token (self), NULL);
-	uri = g_strconcat ("http://photobucket.com/apilogin/login?oauth_token=";, token, NULL);
+	escaped_token = soup_uri_encode (oauth_service_get_token (self), NULL);
+	uri = g_strconcat ("http://photobucket.com/apilogin/login?oauth_token=";,
+			   escaped_token,
+			   NULL);
 
-	g_free (token);
+	g_free (escaped_token);
 
 	return uri;
 }
 
 
 static void
-photobucket_get_access_token_response (OAuthConnection    *self,
-				       SoupMessage        *msg,
-				       SoupBuffer         *body,
-				       GSimpleAsyncResult *result)
+photobucket_access_token_response (OAuthService       *self,
+				   SoupMessage        *msg,
+				   SoupBuffer         *body,
+				   GSimpleAsyncResult *result)
 {
 	GHashTable *values;
 	char       *username;
@@ -154,15 +157,15 @@ photobucket_get_access_token_response (OAuthConnection    *self,
 	if ((username != NULL) && (token != NULL) && (token_secret != NULL)) {
 		OAuthAccount *account;
 
-		oauth_connection_set_token (self, token, token_secret);
+		oauth_service_set_token (self, token);
+		oauth_service_set_token_secret (self, token_secret);
 
-		account = photobucket_account_new ();
-		g_object_set (account,
-			      "name", username,
-			      "username", username,
-			      "token", token,
-			      "token-secret", token_secret,
-			      NULL);
+		account = g_object_new (PHOTOBUCKET_TYPE_ACCOUNT,
+					"name", username,
+					"username", username,
+					"token", token,
+					"token-secret", token_secret,
+					NULL);
 		photobucket_account_set_subdomain (PHOTOBUCKET_ACCOUNT (account), g_hash_table_lookup (values, "subdomain"));
 		photobucket_account_set_home_url (PHOTOBUCKET_ACCOUNT (account), g_hash_table_lookup (values, "homeurl"));
 		g_simple_async_result_set_op_res_gpointer (result, account, g_object_unref);
@@ -170,7 +173,7 @@ photobucket_get_access_token_response (OAuthConnection    *self,
 	else {
 		GError *error;
 
-		error = g_error_new_literal (OAUTH_CONNECTION_ERROR, 0, _("Unknown error"));
+		error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
 		g_simple_async_result_set_from_error (result, error);
 	}
 
@@ -178,64 +181,12 @@ photobucket_get_access_token_response (OAuthConnection    *self,
 }
 
 
-static char *
-photobucket_get_check_token_url (OAuthConnection *self,
-				 OAuthAccount    *account,
-			         gboolean         for_signature)
-{
-	if (for_signature)
-		return g_strconcat ("http://api.photobucket.com/user/";, account->username, NULL);
-	else
-		return g_strconcat ("http://";, PHOTOBUCKET_ACCOUNT (account)->subdomain, "/user/", account->username, NULL);
-}
-
-
-static void
-photobucket_check_token_response (OAuthConnection    *self,
-				  SoupMessage        *msg,
-				  GSimpleAsyncResult *result,
-				  OAuthAccount       *account)
-{
-	DomDocument *doc = NULL;
-	GError      *error = NULL;
-
-	if (photobucket_utils_parse_response (msg, &doc, &error)) {
-		DomElement *node;
-
-		for (node = DOM_ELEMENT (doc)->first_child; node; node = node->next_sibling) {
-			if (g_strcmp0 (node->tag_name, "response") == 0) {
-				DomElement *child;
-
-				for (child = DOM_ELEMENT (node)->first_child; child; child = child->next_sibling) {
-					if (g_strcmp0 (child->tag_name, "content") == 0) {
-						dom_domizable_load_from_element (DOM_DOMIZABLE (account), child);
-						break;
-					}
-				}
-				break;
-			}
-		}
-
-		g_simple_async_result_set_op_res_gboolean (result, TRUE);
-		g_object_unref (doc);
-	}
-	else
-		g_simple_async_result_set_from_error (result, error);
-}
-
-
 OAuthConsumer photobucket_consumer = {
-	"Photobucket",
-	"photobucket",
-	"http://www.photobucket.com";,
-	"http",
 	"149829931",
 	"b4e542229836cc59b66489c6d2d8ca04",
 	"http://api.photobucket.com/login/request";,
-	photobucket_login_request_response,
-	photobucket_get_login_link,
+	photobucket_request_token_response,
+	photobucket_get_authorization_url,
 	"http://api.photobucket.com/login/access";,
-	photobucket_get_access_token_response,
-	photobucket_get_check_token_url,
-	photobucket_check_token_response
+	photobucket_access_token_response
 };
diff --git a/extensions/photobucket/photobucket-consumer.h b/extensions/photobucket/photobucket-consumer.h
index 494fdf9..2522924 100644
--- a/extensions/photobucket/photobucket-consumer.h
+++ b/extensions/photobucket/photobucket-consumer.h
@@ -23,7 +23,7 @@
 #define PHOTOBUCKET_CONSUMER_H
 
 #include <gthumb.h>
-#include <extensions/oauth/oauth-connection.h>
+#include <extensions/oauth/oauth.h>
 
 extern OAuthConsumer photobucket_consumer;
 
diff --git a/extensions/photobucket/photobucket-service.c b/extensions/photobucket/photobucket-service.c
index a48af6a..03e49a6 100644
--- a/extensions/photobucket/photobucket-service.c
+++ b/extensions/photobucket/photobucket-service.c
@@ -3,7 +3,7 @@
 /*
  *  GThumb
  *
- *  Copyright (C) 2010 Free Software Foundation, Inc.
+ *  Copyright (C) 2010-2012 Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -29,11 +29,10 @@
 #include "photobucket-service.h"
 
 
-G_DEFINE_TYPE (PhotobucketService, photobucket_service, G_TYPE_OBJECT)
+G_DEFINE_TYPE (PhotobucketService, photobucket_service, OAUTH_TYPE_SERVICE)
 
 
 typedef struct {
-	PhotobucketAccount  *account;
 	PhotobucketAlbum    *album;
 	int                  size;
 	gboolean             scramble;
@@ -58,14 +57,11 @@ post_photos_data_free (PostPhotosData *post_photos)
 	_g_object_unref (post_photos->cancellable);
 	_g_object_list_unref (post_photos->file_list);
 	_g_object_unref (post_photos->album);
-	g_object_unref (post_photos->account);
 	g_free (post_photos);
 }
 
 
-struct _PhotobucketServicePrivate
-{
-	OAuthConnection *conn;
+struct _PhotobucketServicePrivate {
 	PostPhotosData  *post_photos;
 };
 
@@ -77,22 +73,121 @@ photobucket_service_finalize (GObject *object)
 
 	self = PHOTOBUCKET_SERVICE (object);
 
-	_g_object_unref (self->priv->conn);
 	post_photos_data_free (self->priv->post_photos);
 
 	G_OBJECT_CLASS (photobucket_service_parent_class)->finalize (object);
 }
 
 
+/* -- flickr_service_get_user_info -- */
+
+
+static void
+get_user_info_ready_cb (SoupSession *session,
+			SoupMessage *msg,
+			gpointer     user_data)
+{
+	PhotobucketService *self = user_data;
+	GSimpleAsyncResult *result;
+	DomDocument        *doc = NULL;
+	GError             *error = NULL;
+
+	result = _web_service_get_result (WEB_SERVICE (self));
+
+	if (msg->status_code != 200) {
+		g_simple_async_result_set_error (result,
+						 SOUP_HTTP_ERROR,
+						 msg->status_code,
+						 "%s",
+						 soup_status_get_phrase (msg->status_code));
+		g_simple_async_result_complete_in_idle (result);
+		return;
+	}
+
+	if (photobucket_utils_parse_response (msg, &doc, &error)) {
+		OAuthAccount *account;
+		gboolean      success;
+		DomElement   *node;
+
+		account = web_service_get_current_account (WEB_SERVICE (self));
+		success = FALSE;
+
+		for (node = DOM_ELEMENT (doc)->first_child; node; node = node->next_sibling) {
+			if (g_strcmp0 (node->tag_name, "response") == 0) {
+				DomElement *child;
+
+				for (child = DOM_ELEMENT (node)->first_child; child; child = child->next_sibling) {
+					if (g_strcmp0 (child->tag_name, "content") == 0) {
+						success = TRUE;
+						dom_domizable_load_from_element (DOM_DOMIZABLE (account), child);
+						g_simple_async_result_set_op_res_gpointer (result, account, (GDestroyNotify) g_object_unref);
+						break;
+					}
+				}
+				break;
+			}
+		}
+
+		if (! success) {
+			error = g_error_new_literal (WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_GENERIC, _("Unknown error"));
+			g_simple_async_result_set_from_error (result, error);
+		}
+
+		g_object_unref (doc);
+	}
+	else
+		g_simple_async_result_set_from_error (result, error);
+
+	g_simple_async_result_complete_in_idle (result);
+}
+
+
+static void
+photobucket_service_get_user_info (WebService          *base,
+				   GCancellable        *cancellable,
+				   GAsyncReadyCallback  callback,
+				   gpointer             user_data)
+{
+	PhotobucketService *self = PHOTOBUCKET_SERVICE (base);
+	OAuthAccount       *account;
+	char               *url;
+	GHashTable         *data_set;
+	SoupMessage        *msg;
+
+	account = web_service_get_current_account (WEB_SERVICE (self));
+	if (account != NULL)
+		url = g_strconcat ("http://api.photobucket.com/user/";, account->username, NULL);
+
+	data_set = g_hash_table_new (g_str_hash, g_str_equal);
+	oauth_service_add_signature (OAUTH_SERVICE (self), "GET", url, data_set);
+	msg = soup_form_request_new_from_hash ("GET", url, data_set);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   cancellable,
+				   callback,
+				   user_data,
+				   photobucket_service_get_user_info,
+				   get_user_info_ready_cb,
+				   self);
+
+	g_hash_table_destroy (data_set);
+	g_free (url);
+}
+
+
 static void
 photobucket_service_class_init (PhotobucketServiceClass *klass)
 {
-	GObjectClass *object_class;
+	GObjectClass    *object_class;
+	WebServiceClass *service_class;
 
 	g_type_class_add_private (klass, sizeof (PhotobucketServicePrivate));
 
 	object_class = (GObjectClass*) klass;
 	object_class->finalize = photobucket_service_finalize;
+
+	service_class = (WebServiceClass*) klass;
+	service_class->get_user_info = photobucket_service_get_user_info;
 }
 
 
@@ -100,20 +195,24 @@ static void
 photobucket_service_init (PhotobucketService *self)
 {
 	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, PHOTOBUCKET_TYPE_SERVICE, PhotobucketServicePrivate);
-	self->priv->conn = NULL;
 	self->priv->post_photos = NULL;
 }
 
 
 PhotobucketService *
-photobucket_service_new (OAuthConnection *conn)
+photobucket_service_new (GCancellable  *cancellable,
+			 GtkWidget     *browser,
+			 GtkWidget     *dialog)
 {
-	PhotobucketService *self;
-
-	self = (PhotobucketService *) g_object_new (PHOTOBUCKET_TYPE_SERVICE, NULL);
-	self->priv->conn = g_object_ref (conn);
-
-	return self;
+	return g_object_new (PHOTOBUCKET_TYPE_SERVICE,
+			     "service-name", "photobucket",
+			     "service-address", "www.photobucket.com",
+			     "service-protocol", "http",
+			     "account-type", PHOTOBUCKET_TYPE_ACCOUNT,
+			     "cancellable", cancellable,
+			     "browser", browser,
+			     "dialog", dialog,
+			     NULL);
 }
 
 
@@ -172,7 +271,7 @@ get_albums_ready_cb (SoupSession *session,
 	DomDocument        *doc = NULL;
 	GError             *error = NULL;
 
-	result = oauth_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 
 	if (photobucket_utils_parse_response (msg, &doc, &error)) {
 		GList *albums = NULL;
@@ -192,38 +291,43 @@ get_albums_ready_cb (SoupSession *session,
 
 void
 photobucket_service_get_albums (PhotobucketService  *self,
-			        PhotobucketAccount  *account,
 			        GCancellable        *cancellable,
 			        GAsyncReadyCallback  callback,
 			        gpointer             user_data)
 {
-	GHashTable  *data_set;
-	char        *url;
-	SoupMessage *msg;
+	OAuthAccount *account;
+	GHashTable   *data_set;
+	char         *url;
+	SoupMessage  *msg;
 
+	account = web_service_get_current_account (WEB_SERVICE (self));
 	g_return_if_fail (account != NULL);
-	g_return_if_fail (account->subdomain != NULL);
+	g_return_if_fail (PHOTOBUCKET_ACCOUNT (account)->subdomain != NULL);
 
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Getting the album list"), NULL, TRUE, 0.0);
+	gth_task_progress (GTH_TASK (self),
+			   _("Getting the album list"),
+			   NULL,
+			   TRUE,
+			   0.0);
 
 	data_set = g_hash_table_new (g_str_hash, g_str_equal);
 	g_hash_table_insert (data_set, "recurse", "true");
 	g_hash_table_insert (data_set, "view", "nested");
 	g_hash_table_insert (data_set, "media", "none");
-	url = g_strconcat ("http://api.photobucket.com/album/";, OAUTH_ACCOUNT (account)->username, NULL);
-	oauth_connection_add_signature (self->priv->conn, "GET", url, data_set);
+	url = g_strconcat ("http://api.photobucket.com/album/";, account->username, NULL);
+	oauth_service_add_signature (OAUTH_SERVICE (self), "GET", url, data_set);
 	g_free (url);
 
-	url = g_strconcat ("http://";, account->subdomain, "/album/", OAUTH_ACCOUNT (account)->username, NULL);
+	url = g_strconcat ("http://";, PHOTOBUCKET_ACCOUNT (account)->subdomain, "/album/", account->username, NULL);
 	msg = soup_form_request_new_from_hash ("GET", url, data_set);
-	oauth_connection_send_message (self->priv->conn,
-				       msg,
-				       cancellable,
-				       callback,
-				       user_data,
-				       photobucket_service_get_albums,
-				       get_albums_ready_cb,
-				       self);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   cancellable,
+				   callback,
+				   user_data,
+				   photobucket_service_get_albums,
+				   get_albums_ready_cb,
+				   self);
 
 	g_free (url);
 	g_hash_table_destroy (data_set);
@@ -271,7 +375,7 @@ create_album_ready_cb (SoupSession *session,
 	DomDocument        *doc = NULL;
 	GError             *error = NULL;
 
-	result = oauth_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 
 	if (photobucket_utils_parse_response (msg, &doc, &error)) {
 		g_simple_async_result_set_op_res_gpointer (result, g_object_ref (create_album_data->album), g_object_unref);
@@ -288,7 +392,6 @@ create_album_ready_cb (SoupSession *session,
 
 void
 photobucket_service_create_album (PhotobucketService  *self,
-				  PhotobucketAccount  *account,
 				  const char          *parent_album,
 			          PhotobucketAlbum    *album,
 			          GCancellable        *cancellable,
@@ -299,6 +402,7 @@ photobucket_service_create_album (PhotobucketService  *self,
 	char            *path;
 	GHashTable      *data_set;
 	char            *identifier;
+	OAuthAccount    *account;
 	char            *url;
 	SoupMessage     *msg;
 
@@ -313,27 +417,33 @@ photobucket_service_create_album (PhotobucketService  *self,
 	photobucket_album_set_name (create_album_data->album, path);
 	g_free (path);
 
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Creating the new album"), NULL, TRUE, 0.0);
+	gth_task_progress (GTH_TASK (self),
+			   _("Creating the new album"),
+			   NULL,
+			   TRUE,
+			   0.0);
 
 	data_set = g_hash_table_new (g_str_hash, g_str_equal);
 	g_hash_table_insert (data_set, "name", album->name);
 	identifier = soup_uri_encode (parent_album, NULL);
 	url = g_strconcat ("http://api.photobucket.com/album/";, identifier, NULL);
-	oauth_connection_add_signature (self->priv->conn, "POST", url, data_set);
+	oauth_service_add_signature (OAUTH_SERVICE (self), "POST", url, data_set);
 
 	g_free (identifier);
 	g_free (url);
 
-	url = g_strconcat ("http://";, account->subdomain, "/album/", parent_album, NULL);
+	account = web_service_get_current_account (WEB_SERVICE (self));
+
+	url = g_strconcat ("http://";, PHOTOBUCKET_ACCOUNT (account)->subdomain, "/album/", parent_album, NULL);
 	msg = soup_form_request_new_from_hash ("POST", url, data_set);
-	oauth_connection_send_message (self->priv->conn,
-				       msg,
-				       cancellable,
-				       callback,
-				       user_data,
-				       photobucket_service_create_album,
-				       create_album_ready_cb,
-				       create_album_data);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   cancellable,
+				   callback,
+				   user_data,
+				   photobucket_service_create_album,
+				   create_album_ready_cb,
+				   create_album_data);
 
 	g_free (url);
 	g_hash_table_destroy (data_set);
@@ -361,7 +471,7 @@ upload_photos_done (PhotobucketService *self,
 {
 	GSimpleAsyncResult *result;
 
-	result = oauth_connection_get_result (self->priv->conn);
+	result = _web_service_get_result (WEB_SERVICE (self));
 	if (error == NULL) {
 		g_simple_async_result_set_op_res_gboolean (result, TRUE);
 	}
@@ -429,7 +539,7 @@ upload_photo_wrote_body_data_cb (SoupMessage *msg,
 	/* Translators: %s is a filename */
 	details = g_strdup_printf (_("Uploading '%s'"), g_file_info_get_display_name (file_data->info));
 	current_file_fraction = (double) self->priv->post_photos->wrote_body_data_size / msg->request_body->length;
-	gth_task_progress (GTH_TASK (self->priv->conn),
+	gth_task_progress (GTH_TASK (self),
 			   NULL,
 			   details,
 			   FALSE,
@@ -449,6 +559,7 @@ upload_photo_file_buffer_ready_cb (void     **buffer,
 	GthFileData        *file_data;
 	SoupMultipart      *multipart;
 	char               *identifier;
+	OAuthAccount       *account;
 	char               *uri;
 	SoupBuffer         *body;
 	char               *url;
@@ -489,7 +600,7 @@ upload_photo_file_buffer_ready_cb (void     **buffer,
 		if (self->priv->post_photos->scramble)
 			g_hash_table_insert (data_set, "scramble", "true");
 		url = g_strconcat ("http://api.photobucket.com";, "/album/", identifier, "/upload", NULL);
-		oauth_connection_add_signature (self->priv->conn, "POST", url, data_set);
+		oauth_service_add_signature (OAUTH_SERVICE (self), "POST", url, data_set);
 
 		keys = g_hash_table_get_keys (data_set);
 		for (scan = keys; scan; scan = scan->next) {
@@ -518,22 +629,24 @@ upload_photo_file_buffer_ready_cb (void     **buffer,
 
 	/* send the file */
 
+	account = web_service_get_current_account (WEB_SERVICE (self));
+
 	self->priv->post_photos->wrote_body_data_size = 0;
-	url = g_strconcat ("http://";, self->priv->post_photos->account->subdomain, "/album/", identifier, "/upload", NULL);
+	url = g_strconcat ("http://";, PHOTOBUCKET_ACCOUNT (account)->subdomain, "/album/", identifier, "/upload", NULL);
 	msg = soup_form_request_new_from_multipart (url, multipart);
 	g_signal_connect (msg,
 			  "wrote-body-data",
 			  (GCallback) upload_photo_wrote_body_data_cb,
 			  self);
 
-	oauth_connection_send_message (self->priv->conn,
-				       msg,
-				       self->priv->post_photos->cancellable,
-				       self->priv->post_photos->callback,
-				       self->priv->post_photos->user_data,
-				       photobucket_service_upload_photos,
-				       upload_photo_ready_cb,
-				       self);
+	_web_service_send_message (WEB_SERVICE (self),
+				   msg,
+				   self->priv->post_photos->cancellable,
+				   self->priv->post_photos->callback,
+				   self->priv->post_photos->user_data,
+				   photobucket_service_upload_photos,
+				   upload_photo_ready_cb,
+				   self);
 
 	g_free (url);
 	soup_multipart_free (multipart);
@@ -587,7 +700,6 @@ upload_photos_info_ready_cb (GList    *files,
 
 void
 photobucket_service_upload_photos (PhotobucketService  *self,
-				   PhotobucketAccount  *account,
 				   PhotobucketAlbum    *album,
 				   int                  size,
 				   gboolean             scramble,
@@ -596,11 +708,14 @@ photobucket_service_upload_photos (PhotobucketService  *self,
 				   GAsyncReadyCallback  callback,
 				   gpointer             user_data)
 {
-	gth_task_progress (GTH_TASK (self->priv->conn), _("Uploading the files to the server"), NULL, TRUE, 0.0);
+	gth_task_progress (GTH_TASK (self),
+			   _("Uploading the files to the server"),
+			   NULL,
+			   TRUE,
+			   0.0);
 
 	post_photos_data_free (self->priv->post_photos);
 	self->priv->post_photos = g_new0 (PostPhotosData, 1);
-	self->priv->post_photos->account = g_object_ref (account);
 	self->priv->post_photos->album = _g_object_ref (album);
 	self->priv->post_photos->size = size;
 	self->priv->post_photos->scramble = scramble;
diff --git a/extensions/photobucket/photobucket-service.h b/extensions/photobucket/photobucket-service.h
index 0022a7b..9cd6876 100644
--- a/extensions/photobucket/photobucket-service.h
+++ b/extensions/photobucket/photobucket-service.h
@@ -23,7 +23,7 @@
 #define PHOTOBUCKET_SERVICE_H
 
 #include <glib-object.h>
-#include <extensions/oauth/oauth-connection.h>
+#include <extensions/oauth/oauth.h>
 #include "photobucket-album.h"
 #include "photobucket-account.h"
 
@@ -40,19 +40,20 @@ typedef struct _PhotobucketServiceClass    PhotobucketServiceClass;
 
 struct _PhotobucketService
 {
-	GObject __parent;
+	OAuthService __parent;
 	PhotobucketServicePrivate *priv;
 };
 
 struct _PhotobucketServiceClass
 {
-	GObjectClass __parent_class;
+	OAuthServiceClass __parent_class;
 };
 
 GType                photobucket_service_get_type                   (void) G_GNUC_CONST;
-PhotobucketService * photobucket_service_new                        (OAuthConnection        *conn);
+PhotobucketService * photobucket_service_new                        (GCancellable           *cancellable,
+								     GtkWidget              *browser,
+								     GtkWidget              *dialog);
 void                 photobucket_service_get_albums                 (PhotobucketService     *self,
-								     PhotobucketAccount     *account,
 							             GCancellable           *cancellable,
 							             GAsyncReadyCallback     callback,
 							             gpointer                user_data);
@@ -60,7 +61,6 @@ GList *              photobucket_service_get_albums_finish          (Photobucket
 							             GAsyncResult           *result,
 							             GError                **error);
 void                 photobucket_service_create_album               (PhotobucketService     *self,
-								     PhotobucketAccount     *account,
 								     const char             *parent_album,
 						                     PhotobucketAlbum       *album,
 						                     GCancellable           *cancellable,
@@ -70,7 +70,6 @@ PhotobucketAlbum *   photobucket_service_create_album_finish        (Photobucket
 						                     GAsyncResult           *result,
 						                     GError                **error);
 void                 photobucket_service_upload_photos              (PhotobucketService     *self,
-								     PhotobucketAccount     *account,
 							             PhotobucketAlbum       *album,
 							             int                     size,
 							             gboolean                scramble,
diff --git a/extensions/picasaweb/picasa-web-service.c b/extensions/picasaweb/picasa-web-service.c
index 1127f02..dfa59d1 100644
--- a/extensions/picasaweb/picasa-web-service.c
+++ b/extensions/picasaweb/picasa-web-service.c
@@ -260,13 +260,13 @@ refresh_token_ready_cb (GObject      *source_object,
 
 
 static void
-ask_authorization_dialog_loaded_cb (OAuth2AskAuthorizationDialog *dialog,
-				    gpointer                      user_data)
+ask_authorization_dialog_loaded_cb (OAuthAskAuthorizationDialog *dialog,
+				    gpointer                     user_data)
 {
 	PicasaWebService *self = user_data;
 	const char       *title;
 
-	title = oauth2_ask_authorization_dialog_get_title (dialog);
+	title = oauth_ask_authorization_dialog_get_title (dialog);
 	if (title == NULL)
 		return;
 
@@ -331,11 +331,11 @@ picasa_web_service_ask_authorization (WebService *base)
 
 	gth_task_dialog (GTH_TASK (self), TRUE, NULL);
 
-	dialog = oauth2_ask_authorization_dialog_new (picasa_web_service_get_authorization_url (self));
+	dialog = oauth_ask_authorization_dialog_new (picasa_web_service_get_authorization_url (self));
 	gtk_window_set_default_size (GTK_WINDOW (dialog), 680, 580);
 	_web_service_set_auth_dialog (WEB_SERVICE (self), GTK_DIALOG (dialog));
 
-	g_signal_connect (OAUTH2_ASK_AUTHORIZATION_DIALOG (dialog),
+	g_signal_connect (OAUTH_ASK_AUTHORIZATION_DIALOG (dialog),
 			  "loaded",
 			  G_CALLBACK (ask_authorization_dialog_loaded_cb),
 			  self);
@@ -443,8 +443,6 @@ picasa_web_service_get_user_info_ready_cb (SoupSession *session,
 			      "token", self->priv->access_token,
 			      "token-secret", self->priv->refresh_token,
 			      NULL);
-		web_service_set_current_account (WEB_SERVICE (self), account);
-
 		g_simple_async_result_set_op_res_gpointer (result,
 							   g_object_ref (account),
 							   (GDestroyNotify) g_object_unref);
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d372a8f..efa0b6e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -337,8 +337,6 @@ extensions/flicker/callbacks.h
 [type: gettext/ini]extensions/flicker/flicker.extension.in.in
 extensions/flicker/main.c
 [type: gettext/glade]extensions/flicker_utils/data/ui/export-to-flickr.ui
-[type: gettext/glade]extensions/flicker_utils/data/ui/flicker-account-chooser.ui
-[type: gettext/glade]extensions/flicker_utils/data/ui/flicker-account-manager.ui
 [type: gettext/glade]extensions/flicker_utils/data/ui/flicker-ask-authorization.ui
 [type: gettext/glade]extensions/flicker_utils/data/ui/flicker-complete-authorization.ui
 [type: gettext/glade]extensions/flicker_utils/data/ui/flicker-export-completed.ui
@@ -349,15 +347,9 @@ extensions/flicker_utils/dlg-import-from-flickr.c
 extensions/flicker_utils/dlg-import-from-flickr.h
 [type: gettext/ini]extensions/flicker_utils/flicker_utils.extension.in.in
 extensions/flicker_utils/flickr-account.c
-extensions/flicker_utils/flickr-account-chooser-dialog.c
-extensions/flicker_utils/flickr-account-chooser-dialog.h
 extensions/flicker_utils/flickr-account.h
-extensions/flicker_utils/flickr-account-manager-dialog.c
-extensions/flicker_utils/flickr-account-manager-dialog.h
-extensions/flicker_utils/flickr-authentication.c
-extensions/flicker_utils/flickr-authentication.h
-extensions/flicker_utils/flickr-connection.c
-extensions/flicker_utils/flickr-connection.h
+extensions/flicker_utils/flickr-consumer.c
+extensions/flicker_utils/flickr-consumer.h
 extensions/flicker_utils/flickr-photo.c
 extensions/flicker_utils/flickr-photo.h
 extensions/flicker_utils/flickr-photoset.c
@@ -365,8 +357,6 @@ extensions/flicker_utils/flickr-photoset.h
 extensions/flicker_utils/flickr-service.c
 extensions/flicker_utils/flickr-service.h
 extensions/flicker_utils/flickr-types.h
-extensions/flicker_utils/flickr-user.c
-extensions/flicker_utils/flickr-user.h
 extensions/flicker_utils/main.c
 extensions/flicker_utils/preferences.h
 extensions/gstreamer_tools/actions.c
@@ -480,20 +470,20 @@ extensions/map_view/main.c
 [type: gettext/glade]extensions/oauth/data/ui/oauth-ask-authorization.ui
 [type: gettext/glade]extensions/oauth/data/ui/oauth-complete-authorization.ui
 extensions/oauth/main.c
-extensions/oauth/oauth2-ask-authorization-dialog.c
-extensions/oauth/oauth2-ask-authorization-dialog.h
 extensions/oauth/oauth-account.c
 extensions/oauth/oauth-account-chooser-dialog.c
 extensions/oauth/oauth-account-chooser-dialog.h
 extensions/oauth/oauth-account.h
 extensions/oauth/oauth-account-manager-dialog.c
 extensions/oauth/oauth-account-manager-dialog.h
-extensions/oauth/oauth-authentication.c
-extensions/oauth/oauth-authentication.h
-extensions/oauth/oauth-connection.c
-extensions/oauth/oauth-connection.h
+extensions/oauth/oauth-ask-authorization-dialog.c
+extensions/oauth/oauth-ask-authorization-dialog.h
+extensions/oauth/oauth-consumer.c
+extensions/oauth/oauth-consumer.h
 [type: gettext/ini]extensions/oauth/oauth.extension.in.in
 extensions/oauth/oauth.h
+extensions/oauth/oauth-service.c
+extensions/oauth/oauth-service.h
 extensions/oauth/web-service.c
 extensions/oauth/web-service.h
 extensions/photobucket/actions.c



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]