[gthumb] facebook: moved some code to a generic WebService class
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] facebook: moved some code to a generic WebService class
- Date: Sat, 22 Dec 2012 16:08:34 +0000 (UTC)
commit f13f9079260645771fb15e849379e599cb5bf1fa
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sat Dec 15 16:57:01 2012 +0100
facebook: moved some code to a generic WebService class
extensions/facebook/Makefile.am | 6 -
extensions/facebook/dlg-export-to-facebook.c | 75 +--
extensions/facebook/facebook-authentication.c | 619 --------------
extensions/facebook/facebook-authentication.h | 78 --
extensions/facebook/facebook-connection.c | 329 --------
extensions/facebook/facebook-connection.h | 94 ---
extensions/facebook/facebook-service.c | 438 ++++++++---
extensions/facebook/facebook-service.h | 21 +-
extensions/facebook/facebook-user.c | 173 ----
extensions/facebook/facebook-user.h | 58 --
extensions/oauth/Makefile.am | 4 +-
extensions/oauth/oauth-account.c | 8 +-
extensions/oauth/oauth.h | 1 +
extensions/oauth/oauth2-ask-authorization-dialog.c | 5 +-
extensions/oauth/oauth2-ask-authorization-dialog.h | 3 +-
extensions/oauth/web-service.c | 852 ++++++++++++++++++++
extensions/oauth/web-service.h | 111 +++
17 files changed, 1332 insertions(+), 1543 deletions(-)
---
diff --git a/extensions/facebook/Makefile.am b/extensions/facebook/Makefile.am
index 3795a91..3fb505a 100644
--- a/extensions/facebook/Makefile.am
+++ b/extensions/facebook/Makefile.am
@@ -16,17 +16,11 @@ libfacebook_la_SOURCES = \
facebook-album.h \
facebook-album-properties-dialog.c \
facebook-album-properties-dialog.h \
- facebook-authentication.c \
- facebook-authentication.h \
- facebook-connection.c \
- facebook-connection.h \
facebook-photo.c \
facebook-photo.h \
facebook-service.c \
facebook-service.h \
facebook-types.h \
- facebook-user.c \
- facebook-user.h \
main.c \
preferences.h
diff --git a/extensions/facebook/dlg-export-to-facebook.c b/extensions/facebook/dlg-export-to-facebook.c
index 855689d..1ec8d54 100644
--- a/extensions/facebook/dlg-export-to-facebook.c
+++ b/extensions/facebook/dlg-export-to-facebook.c
@@ -24,11 +24,9 @@
#include <gthumb.h>
#include <extensions/oauth/oauth.h>
#include "dlg-export-to-facebook.h"
-#include "facebook-authentication.h"
#include "facebook-album.h"
#include "facebook-album-properties-dialog.h"
#include "facebook-service.h"
-#include "facebook-user.h"
#include "preferences.h"
@@ -65,10 +63,7 @@ typedef struct {
GtkWidget *dialog;
GtkWidget *list_view;
GtkWidget *progress_dialog;
- FacebookConnection *conn;
- FacebookAuthentication *auth;
FacebookService *service;
- OAuthAccount *account;
GList *albums;
FacebookAlbum *album;
GList *photos_ids;
@@ -81,16 +76,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->album);
_g_object_list_unref (data->albums);
- _g_object_unref (data->account);
_g_object_unref (data->service);
- _g_object_unref (data->auth);
- _g_object_unref (data->conn);
_g_object_unref (data->settings);
_g_object_unref (data->builder);
_g_object_list_unref (data->file_list);
@@ -126,8 +118,7 @@ completed_messagedialog_response_cb (GtkDialog *dialog,
url = g_strdup (data->album->link);
if ((url != NULL) && ! gtk_show_uri (screen, url, 0, &error)) {
- if (data->conn != NULL)
- gth_task_dialog (GTH_TASK (data->conn), TRUE, 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);
}
@@ -150,7 +141,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 ("facebook-export-completed.ui", "facebook");
dialog = _gtk_builder_get_widget (builder, "completed_messagedialog");
@@ -221,7 +212,7 @@ export_dialog_response_cb (GtkDialog *dialog,
return;
gtk_widget_hide (data->dialog);
- gth_task_dialog (GTH_TASK (data->conn), FALSE, NULL);
+ gth_task_dialog (GTH_TASK (data->service), FALSE, NULL);
max_resolution = 0;
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (GET_WIDGET ("resize_combobox")), &iter)) {
@@ -264,8 +255,8 @@ update_account_list (DialogData *data)
gtk_list_store_clear (GTK_LIST_STORE (GET_WIDGET ("account_liststore")));
current_account_idx = 0;
- current_account = facebook_authentication_get_account (data->auth);
- for (scan = facebook_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))
@@ -282,8 +273,8 @@ update_account_list (DialogData *data)
static void
-authentication_accounts_changed_cb (FacebookAuthentication *auth,
- gpointer user_data)
+service_accounts_changed_cb (FacebookService *service,
+ gpointer user_data)
{
update_account_list ((DialogData *) user_data);
}
@@ -330,8 +321,7 @@ get_albums_ready_cb (GObject *source_object,
_g_object_list_unref (data->albums);
data->albums = facebook_service_get_albums_finish (data->service, res, &error);
if (error != NULL) {
- if (data->conn != NULL)
- gth_task_dialog (GTH_TASK (data->conn), TRUE, 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);
@@ -340,7 +330,7 @@ get_albums_ready_cb (GObject *source_object,
update_album_list (data, NULL);
- 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);
gtk_window_present (GTK_WINDOW (data->dialog));
@@ -348,13 +338,10 @@ get_albums_ready_cb (GObject *source_object,
static void
-authentication_ready_cb (FacebookAuthentication *auth,
- DialogData *data)
+service_account_ready_cb (FacebookService *service,
+ DialogData *data)
{
- _g_object_unref (data->account);
- data->account = _g_object_ref (facebook_authentication_get_account (auth));
update_account_list (data);
-
facebook_service_get_albums (data->service,
data->cancellable,
get_albums_ready_cb,
@@ -366,7 +353,7 @@ static void
edit_accounts_button_clicked_cb (GtkButton *button,
DialogData *data)
{
- facebook_authentication_edit_accounts (data->auth, GTK_WINDOW (data->dialog));
+ web_service_edit_accounts (WEB_SERVICE (data->service), GTK_WINDOW (data->dialog));
}
@@ -386,8 +373,8 @@ account_combobox_changed_cb (GtkComboBox *widget,
ACCOUNT_DATA_COLUMN, &account,
-1);
- if (oauth_account_cmp (account, facebook_authentication_get_account (data->auth)) != 0)
- facebook_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);
}
@@ -404,8 +391,8 @@ create_album_ready_cb (GObject *source_object,
album = facebook_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;
@@ -655,24 +642,20 @@ dlg_export_to_facebook (GthBrowser *browser,
G_CALLBACK (album_combobox_changed_cb),
data);
- data->conn = facebook_connection_new ();
- data->service = facebook_service_new (data->conn);
- data->auth = facebook_authentication_new (data->conn,
- data->service,
- data->cancellable,
- GTK_WIDGET (data->browser),
- data->dialog);
- g_signal_connect (data->auth,
- "ready",
- G_CALLBACK (authentication_ready_cb),
+ data->service = facebook_service_new (data->cancellable,
+ GTK_WIDGET (data->browser),
+ data->dialog);
+ g_signal_connect (data->service,
+ "account-ready",
+ G_CALLBACK (service_account_ready_cb),
data);
- g_signal_connect (data->auth,
- "accounts_changed",
- G_CALLBACK (authentication_accounts_changed_cb),
+ g_signal_connect (data->service,
+ "accounts-changed",
+ G_CALLBACK (service_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));
- facebook_authentication_auto_connect (data->auth);
+ web_service_autoconnect (WEB_SERVICE (data->service));
}
diff --git a/extensions/facebook/facebook-service.c b/extensions/facebook/facebook-service.c
index 2b4c4bb..c5ae554 100644
--- a/extensions/facebook/facebook-service.c
+++ b/extensions/facebook/facebook-service.c
@@ -26,13 +26,23 @@
#include <gthumb.h>
#include <extensions/oauth/oauth.h>
#include "facebook-album.h"
-#include "facebook-connection.h"
#include "facebook-photo.h"
#include "facebook-service.h"
-#include "facebook-user.h"
-#define FACEBOOK_MIN_IMAGE_SIZE 720
+
+#define FACEBOOK_API_VERSION "1.0"
+#define FACEBOOK_AUTHENTICATION_RESPONSE_CHOOSE_ACCOUNT 2
+#define FACEBOOK_HTTP_SERVER "https://www.facebook.com"
#define FACEBOOK_MAX_IMAGE_SIZE 2048
+#define FACEBOOK_MIN_IMAGE_SIZE 720
+#define FACEBOOK_REDIRECT_URI "https://www.facebook.com/connect/login_success.html"
+#define FACEBOOK_SERVICE_ERROR_TOKEN_EXPIRED 190
+#define GTHUMB_FACEBOOK_API_KEY "1536ca726857c69843423d0312b9b356"
+#define GTHUMB_FACEBOOK_SHARED_SECRET "8c0b99672a9bbc159ebec3c9a8240679"
+
+
+/* -- post_photos_data -- */
+
typedef struct {
FacebookAlbum *album;
@@ -64,63 +74,211 @@ post_photos_data_free (PostPhotosData *post_photos)
}
-struct _FacebookServicePrivate
-{
- FacebookConnection *conn;
- FacebookUser *user;
- PostPhotosData *post_photos;
-};
+/* -- facebook_service -- */
-G_DEFINE_TYPE (FacebookService, facebook_service, G_TYPE_OBJECT)
+G_DEFINE_TYPE (FacebookService, facebook_service, WEB_TYPE_SERVICE)
+
+
+struct _FacebookServicePrivate {
+ char *token;
+ PostPhotosData *post_photos;
+};
static void
facebook_service_finalize (GObject *object)
{
- FacebookService *self;
-
- self = FACEBOOK_SERVICE (object);
+ FacebookService *self = FACEBOOK_SERVICE (object);
- _g_object_unref (self->priv->conn);
- _g_object_unref (self->priv->user);
post_photos_data_free (self->priv->post_photos);
+ g_free (self->priv->token);
G_OBJECT_CLASS (facebook_service_parent_class)->finalize (object);
}
+/* -- connection utilities -- */
+
+
static void
-facebook_service_class_init (FacebookServiceClass *klass)
+_facebook_service_set_access_token (FacebookService *self,
+ const char *token)
{
- GObjectClass *object_class;
+ _g_strset (&self->priv->token, token);
+}
- g_type_class_add_private (klass, sizeof (FacebookServicePrivate));
- object_class = (GObjectClass*) klass;
- object_class->finalize = facebook_service_finalize;
+static const char *
+_facebook_service_get_access_token (FacebookService *self)
+{
+ return self->priv->token;
}
static void
-facebook_service_init (FacebookService *self)
+_facebook_service_add_access_token (FacebookService *self,
+ GHashTable *data_set)
{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, FACEBOOK_TYPE_SERVICE, FacebookServicePrivate);
- self->priv->conn = NULL;
- self->priv->user = NULL;
- self->priv->post_photos = NULL;
+ g_return_if_fail (self->priv->token != NULL);
+
+ g_hash_table_insert (data_set, "access_token", self->priv->token);
}
-FacebookService *
-facebook_service_new (FacebookConnection *conn)
+static char *
+get_access_type_name (WebAuthorizationType access_type)
+{
+ char *name = NULL;
+
+ switch (access_type) {
+ case WEB_AUTHORIZATION_READ:
+ name = "";
+ break;
+
+ case WEB_AUTHORIZATION_WRITE:
+ name = "publish_actions";
+ break;
+ }
+
+ return name;
+}
+
+
+static char *
+facebook_utils_get_authorization_url (WebAuthorizationType access_type)
{
- FacebookService *self;
+ GHashTable *data_set;
+ GString *link;
+ GList *keys;
+ GList *scan;
+
+ data_set = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (data_set, "client_id", GTHUMB_FACEBOOK_API_KEY);
+ g_hash_table_insert (data_set, "redirect_uri", FACEBOOK_REDIRECT_URI);
+ g_hash_table_insert (data_set, "scope", get_access_type_name (access_type));
+ g_hash_table_insert (data_set, "response_type", "token");
+
+ link = g_string_new ("https://www.facebook.com/dialog/oauth?");
+ keys = g_hash_table_get_keys (data_set);
+ for (scan = keys; scan; scan = scan->next) {
+ char *key = scan->data;
+ char *encoded;
+
+ if (scan != keys)
+ g_string_append (link, "&");
+ g_string_append (link, key);
+ g_string_append (link, "=");
+ encoded = soup_uri_encode (g_hash_table_lookup (data_set, key), NULL);
+ g_string_append (link, encoded);
+
+ g_free (encoded);
+ }
- self = (FacebookService *) g_object_new (FACEBOOK_TYPE_SERVICE, NULL);
- self->priv->conn = _g_object_ref (conn);
+ g_list_free (keys);
+ g_hash_table_destroy (data_set);
- return self;
+ return g_string_free (link, FALSE);
+}
+
+
+static gboolean
+facebook_utils_parse_response (SoupMessage *msg,
+ JsonNode **node,
+ GError **error)
+{
+ JsonParser *parser;
+ SoupBuffer *body;
+
+ g_return_val_if_fail (msg != NULL, FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ *node = NULL;
+
+ if ((msg->status_code != 200) && (msg->status_code != 400)) {
+ *error = g_error_new (SOUP_HTTP_ERROR,
+ msg->status_code,
+ "%s",
+ soup_status_get_phrase (msg->status_code));
+ return FALSE;
+ }
+
+ body = soup_message_body_flatten (msg->response_body);
+ parser = json_parser_new ();
+ if (json_parser_load_from_data (parser, body->data, body->length, error)) {
+ JsonObject *obj;
+
+ *node = json_node_copy (json_parser_get_root (parser));
+
+ obj = json_node_get_object (*node);
+ if (json_object_has_member (obj, "error")) {
+ JsonObject *error_obj;
+
+ error_obj = json_object_get_object_member (obj, "error");
+ *error = g_error_new (WEB_SERVICE_ERROR,
+ json_object_get_int_member (error_obj, "code"),
+ "%s",
+ json_object_get_string_member (error_obj, "message"));
+
+ json_node_free (*node);
+ *node = NULL;
+ }
+ }
+
+ g_object_unref (parser);
+ soup_buffer_free (body);
+
+ return *node != NULL;
+}
+
+
+/* -- facebook_service_ask_authorization -- */
+
+
+static void
+ask_authorization_dialog_redirected_cb (OAuth2AskAuthorizationDialog *dialog,
+ gpointer user_data)
+{
+ FacebookService *self = user_data;
+ const char *uri;
+
+ uri = oauth2_ask_authorization_dialog_get_uri (dialog);
+ if (g_str_has_prefix (uri, FACEBOOK_REDIRECT_URI)) {
+ const char *uri_data;
+ GHashTable *data;
+ const char *access_token;
+
+ uri_data = uri + strlen (FACEBOOK_REDIRECT_URI "#");
+
+ data = soup_form_decode (uri_data);
+ access_token = g_hash_table_lookup (data, "access_token");
+ _facebook_service_set_access_token (self, access_token);
+ gtk_dialog_response (GTK_DIALOG (dialog),
+ (access_token != NULL) ? GTK_RESPONSE_OK : GTK_RESPONSE_CANCEL);
+
+ g_hash_table_destroy (data);
+ }
+}
+
+
+static void
+facebook_service_ask_authorization (WebService *base)
+{
+ FacebookService *self = FACEBOOK_SERVICE (base);
+ GtkWidget *dialog;
+
+ gth_task_dialog (GTH_TASK (self), TRUE, NULL);
+
+ dialog = oauth2_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),
+ "redirected",
+ G_CALLBACK (ask_authorization_dialog_redirected_cb),
+ self);
+
+ gtk_widget_show (dialog);
}
@@ -128,24 +286,32 @@ facebook_service_new (FacebookConnection *conn)
static void
-facebook_service_get_user_ready_cb (SoupSession *session,
- SoupMessage *msg,
- gpointer user_data)
+facebook_service_get_user_info_ready_cb (SoupSession *session,
+ SoupMessage *msg,
+ gpointer user_data)
{
FacebookService *self = user_data;
GSimpleAsyncResult *result;
GError *error = NULL;
JsonNode *node;
- result = facebook_connection_get_result (self->priv->conn);
+ result = _web_service_get_result (WEB_SERVICE (self));
if (facebook_utils_parse_response (msg, &node, &error)) {
- _g_object_unref (self->priv->user);
- self->priv->user = (FacebookUser *) json_gobject_deserialize (FACEBOOK_TYPE_USER, node);
+ OAuthAccount *account;
+
+ account = (OAuthAccount *) json_gobject_deserialize (OAUTH_TYPE_ACCOUNT, node);
+ g_object_set (account,
+ "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 (self->priv->user),
+ g_object_ref (account),
(GDestroyNotify) g_object_unref);
+ _g_object_unref (account);
json_node_free (node);
}
else
@@ -155,46 +321,75 @@ facebook_service_get_user_ready_cb (SoupSession *session,
}
-void
-facebook_service_get_user (FacebookService *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+static void
+facebook_service_get_user_info (WebService *base,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- GHashTable *data_set;
- SoupMessage *msg;
+ FacebookService *self = FACEBOOK_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));
+ _facebook_service_set_access_token (self, account->token_secret);
data_set = g_hash_table_new (g_str_hash, g_str_equal);
- facebook_connection_add_access_token (self->priv->conn, data_set);
+ _facebook_service_add_access_token (self, data_set);
msg = soup_form_request_new_from_hash ("GET", "https://graph.facebook.com/me", data_set);
- facebook_connection_send_message (self->priv->conn,
- msg,
- cancellable,
- callback,
- user_data,
- facebook_service_get_user,
- facebook_service_get_user_ready_cb,
- self);
+ _web_service_send_message (WEB_SERVICE (self),
+ msg,
+ cancellable,
+ callback,
+ user_data,
+ facebook_service_get_user_info,
+ facebook_service_get_user_info_ready_cb,
+ self);
g_hash_table_destroy (data_set);
}
-FacebookUser *
-facebook_service_get_user_finish (FacebookService *self,
- GAsyncResult *result,
- GError **error)
+static void
+facebook_service_class_init (FacebookServiceClass *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 (FacebookServicePrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->finalize = facebook_service_finalize;
+
+ service_class = (WebServiceClass*) klass;
+ service_class->ask_authorization = facebook_service_ask_authorization;
+ service_class->get_user_info = facebook_service_get_user_info;
+}
+
+
+static void
+facebook_service_init (FacebookService *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, FACEBOOK_TYPE_SERVICE, FacebookServicePrivate);
+ self->priv->token = NULL;
+ self->priv->post_photos = NULL;
+}
+
+
+FacebookService *
+facebook_service_new (GCancellable *cancellable,
+ GtkWidget *browser,
+ GtkWidget *dialog)
+{
+ return g_object_new (FACEBOOK_TYPE_SERVICE,
+ "service-name", "facebook",
+ "service-address", "https://www.facebook.com",
+ "service-protocol", "https",
+ "cancellable", cancellable,
+ "browser", browser,
+ "dialog", dialog,
+ NULL);
}
@@ -211,7 +406,7 @@ facebook_service_get_albums_ready_cb (SoupSession *session,
JsonNode *node;
GError *error = NULL;
- result = facebook_connection_get_result (self->priv->conn);
+ result = _web_service_get_result (WEB_SERVICE (self));
if (facebook_utils_parse_response (msg, &node, &error)) {
GList *albums = NULL;
@@ -248,30 +443,32 @@ facebook_service_get_albums (FacebookService *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GHashTable *data_set;
- char *uri;
- SoupMessage *msg;
+ OAuthAccount *account;
+ GHashTable *data_set;
+ char *uri;
+ SoupMessage *msg;
- g_return_if_fail (self->priv->user != NULL);
+ account = web_service_get_current_account (WEB_SERVICE (self));
+ g_return_if_fail (account != NULL);
- gth_task_progress (GTH_TASK (self->priv->conn),
+ gth_task_progress (GTH_TASK (self),
_("Getting the album list"),
NULL,
TRUE,
0.0);
- uri = g_strdup_printf ("https://graph.facebook.com/%s/albums", self->priv->user->id);
+ uri = g_strdup_printf ("https://graph.facebook.com/%s/albums", account->id);
data_set = g_hash_table_new (g_str_hash, g_str_equal);
- facebook_connection_add_access_token (self->priv->conn, data_set);
+ _facebook_service_add_access_token (self, data_set);
msg = soup_form_request_new_from_hash ("GET", uri, data_set);
- facebook_connection_send_message (self->priv->conn,
- msg,
- cancellable,
- callback,
- user_data,
- facebook_service_get_albums,
- facebook_service_get_albums_ready_cb,
- self);
+ _web_service_send_message (WEB_SERVICE (self),
+ msg,
+ cancellable,
+ callback,
+ user_data,
+ facebook_service_get_albums,
+ facebook_service_get_albums_ready_cb,
+ self);
g_free (uri);
g_hash_table_destroy (data_set);
@@ -333,7 +530,7 @@ facebook_service_create_album_ready_cb (SoupSession *session,
JsonNode *node;
GError *error = NULL;
- result = facebook_connection_get_result (self->priv->conn);
+ result = _web_service_get_result (WEB_SERVICE (self));
if (facebook_utils_parse_response (msg, &node, &error)) {
FacebookAlbum *album;
@@ -364,36 +561,43 @@ facebook_service_create_album (FacebookService *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ OAuthAccount *account;
CreateAlbumData *ca_data;
char *uri;
GHashTable *data_set;
SoupMessage *msg;
- g_return_if_fail (self->priv->user != NULL);
+ account = web_service_get_current_account (WEB_SERVICE (self));
+ g_return_if_fail (account != NULL);
+
g_return_if_fail (album != NULL);
g_return_if_fail (album->name != 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);
ca_data = create_album_data_new (self, album);
- uri = g_strdup_printf ("https://graph.facebook.com/%s/albums", self->priv->user->id);
+ uri = g_strdup_printf ("https://graph.facebook.com/%s/albums", account->id);
data_set = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_insert (data_set, "name", album->name);
if (album->description != NULL)
g_hash_table_insert (data_set, "message", album->description);
if (album->privacy != NULL)
g_hash_table_insert (data_set, "privacy", album->privacy);
- facebook_connection_add_access_token (self->priv->conn, data_set);
+ _facebook_service_add_access_token (self, data_set);
msg = soup_form_request_new_from_hash ("POST", uri, data_set);
- facebook_connection_send_message (self->priv->conn,
- msg,
- cancellable,
- callback,
- user_data,
- facebook_service_create_album,
- facebook_service_create_album_ready_cb,
- ca_data);
+ _web_service_send_message (WEB_SERVICE (self),
+ msg,
+ cancellable,
+ callback,
+ user_data,
+ facebook_service_create_album,
+ facebook_service_create_album_ready_cb,
+ ca_data);
g_hash_table_destroy (data_set);
}
@@ -420,7 +624,7 @@ upload_photos_done (FacebookService *self,
{
GSimpleAsyncResult *result;
- result = facebook_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);
@@ -498,7 +702,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,
@@ -547,7 +751,7 @@ upload_photo_file_buffer_ready_cb (void **buffer,
else if (title != NULL)
g_hash_table_insert (data_set, "message", title);
- facebook_connection_add_access_token (self->priv->conn, data_set);
+ _facebook_service_add_access_token (self, data_set);
keys = g_hash_table_get_keys (data_set);
for (scan = keys; scan; scan = scan->next) {
@@ -639,14 +843,14 @@ upload_photo_file_buffer_ready_cb (void **buffer,
"wrote-body-data",
(GCallback) upload_photo_wrote_body_data_cb,
self);
- facebook_connection_send_message (self->priv->conn,
- msg,
- self->priv->post_photos->cancellable,
- self->priv->post_photos->callback,
- self->priv->post_photos->user_data,
- facebook_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,
+ facebook_service_upload_photos,
+ upload_photo_ready_cb,
+ self);
g_free (uri);
soup_multipart_free (multipart);
@@ -707,7 +911,7 @@ facebook_service_upload_photos (FacebookService *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- gth_task_progress (GTH_TASK (self->priv->conn),
+ gth_task_progress (GTH_TASK (self),
_("Uploading the files to the server"),
NULL,
TRUE,
@@ -760,7 +964,7 @@ list_photos_ready_cb (SoupSession *session,
DomDocument *doc = NULL;
GError *error = NULL;
- result = facebook_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,
@@ -847,14 +1051,14 @@ facebook_service_list_photos (FacebookService *self,
}
facebook_connection_add_api_sig (self->priv->conn, data_set);
msg = soup_form_request_new_from_hash ("GET", "http://api.facebook.com/services/rest", data_set);
- facebook_connection_send_message (self->priv->conn,
- msg,
- cancellable,
- callback,
- user_data,
- facebook_service_list_photos,
- list_photos_ready_cb,
- self);
+ _web_service_send_message (self,
+ msg,
+ cancellable,
+ callback,
+ user_data,
+ facebook_service_list_photos,
+ list_photos_ready_cb,
+ self);
g_hash_table_destroy (data_set);
}
diff --git a/extensions/facebook/facebook-service.h b/extensions/facebook/facebook-service.h
index 8f065d2..800bf84 100644
--- a/extensions/facebook/facebook-service.h
+++ b/extensions/facebook/facebook-service.h
@@ -22,11 +22,11 @@
#ifndef FACEBOOK_SERVICE_H
#define FACEBOOK_SERVICE_H
-#include <glib-object.h>
-#include "facebook-connection.h"
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include <extensions/oauth/oauth.h>
#include "facebook-album.h"
#include "facebook-types.h"
-#include "facebook-user.h"
#define FACEBOOK_TYPE_SERVICE (facebook_service_get_type ())
#define FACEBOOK_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), FACEBOOK_TYPE_SERVICE, FacebookService))
@@ -41,24 +41,19 @@ typedef struct _FacebookServiceClass FacebookServiceClass;
struct _FacebookService
{
- GObject __parent;
+ WebService __parent;
FacebookServicePrivate *priv;
};
struct _FacebookServiceClass
{
- GObjectClass __parent_class;
+ WebServiceClass __parent_class;
};
GType facebook_service_get_type (void) G_GNUC_CONST;
-FacebookService * facebook_service_new (FacebookConnection *conn);
-void facebook_service_get_user (FacebookService *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-FacebookUser * facebook_service_get_user_finish (FacebookService *self,
- GAsyncResult *result,
- GError **error);
+FacebookService * facebook_service_new (GCancellable *cancellable,
+ GtkWidget *browser,
+ GtkWidget *dialog);
void facebook_service_get_albums (FacebookService *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
diff --git a/extensions/oauth/Makefile.am b/extensions/oauth/Makefile.am
index f22c444..309fe22 100644
--- a/extensions/oauth/Makefile.am
+++ b/extensions/oauth/Makefile.am
@@ -19,7 +19,9 @@ liboauth_la_SOURCES = \
oauth-authentication.c \
oauth-authentication.h \
oauth-connection.c \
- oauth-connection.h
+ oauth-connection.h \
+ web-service.c \
+ web-service.h
liboauth_la_CFLAGS = $(GTHUMB_CFLAGS) $(LIBSOUP_CFLAGS) $(LIBSECRET_CFLAGS) $(WEBKIT2_CFLAGS) -I$(top_srcdir) -I$(top_builddir)/gthumb
liboauth_la_LDFLAGS = $(EXTENSION_LIBTOOL_FLAGS)
diff --git a/extensions/oauth/oauth-account.c b/extensions/oauth/oauth-account.c
index 39b3a5a..39ee4e5 100644
--- a/extensions/oauth/oauth-account.c
+++ b/extensions/oauth/oauth-account.c
@@ -215,7 +215,7 @@ oauth_account_create_element (DomDomizable *base,
if (self->name != NULL)
dom_element_set_attribute (element, "name", self->name);
- /* Don't save the token in the configuration file if the keyring is
+ /* Do not save the token in the configuration file if the keyring is
* available. */
#ifdef HAVE_LIBSECRET
@@ -224,8 +224,8 @@ oauth_account_create_element (DomDomizable *base,
set_token = TRUE;
#endif
- if (set_token && (self->token != NULL))
- dom_element_set_attribute (element, "token", self->token);
+ if (set_token && (self->token_secret != NULL))
+ dom_element_set_attribute (element, "token-secret", self->token_secret);
if (self->is_default)
dom_element_set_attribute (element, "default", "1");
@@ -246,7 +246,7 @@ oauth_account_load_from_element (DomDomizable *base,
"id", dom_element_get_attribute (element, "id"),
"username", dom_element_get_attribute (element, "username"),
"name", dom_element_get_attribute (element, "name"),
- "token", dom_element_get_attribute (element, "token"),
+ "token-secret", dom_element_get_attribute (element, "token-secret"),
"is-default", (g_strcmp0 (dom_element_get_attribute (element, "default"), "1") == 0),
NULL);
}
diff --git a/extensions/oauth/oauth.h b/extensions/oauth/oauth.h
index 7db1151..6b0f5a3 100644
--- a/extensions/oauth/oauth.h
+++ b/extensions/oauth/oauth.h
@@ -28,5 +28,6 @@
#include <extensions/oauth/oauth-account-manager-dialog.h>
#include <extensions/oauth/oauth-authentication.h>
#include <extensions/oauth/oauth-connection.h>
+#include <extensions/oauth/web-service.h>
#endif /* OAUTH_H */
diff --git a/extensions/oauth/oauth2-ask-authorization-dialog.c b/extensions/oauth/oauth2-ask-authorization-dialog.c
index e3fef64..21cb092 100644
--- a/extensions/oauth/oauth2-ask-authorization-dialog.c
+++ b/extensions/oauth/oauth2-ask-authorization-dialog.c
@@ -108,13 +108,12 @@ oauth2_ask_authorization_dialog_init (OAuth2AskAuthorizationDialog *self)
GtkWidget *
-oauth2_ask_authorization_dialog_new (const char *title,
- const char *uri)
+oauth2_ask_authorization_dialog_new (const char *uri)
{
OAuth2AskAuthorizationDialog *self;
self = g_object_new (OAUTH2_TYPE_ASK_AUTHORIZATION_DIALOG,
- "title", title,
+ "title", _("Authorization Required"),
NULL);
webkit_web_view_load_uri (WEBKIT_WEB_VIEW (self->priv->view), uri);
diff --git a/extensions/oauth/oauth2-ask-authorization-dialog.h b/extensions/oauth/oauth2-ask-authorization-dialog.h
index 5c19239..31067ba 100644
--- a/extensions/oauth/oauth2-ask-authorization-dialog.h
+++ b/extensions/oauth/oauth2-ask-authorization-dialog.h
@@ -52,8 +52,7 @@ struct _OAuth2AskAuthorizationDialogClass {
};
GType oauth2_ask_authorization_dialog_get_type (void);
-GtkWidget * oauth2_ask_authorization_dialog_new (const char *title,
- const char *url);
+GtkWidget * oauth2_ask_authorization_dialog_new (const char *url);
GtkWidget * oauth2_ask_authorization_dialog_get_view (OAuth2AskAuthorizationDialog *self);
const char * oauth2_ask_authorization_dialog_get_uri (OAuth2AskAuthorizationDialog *self);
diff --git a/extensions/oauth/web-service.c b/extensions/oauth/web-service.c
new file mode 100644
index 0000000..b7c8b8f
--- /dev/null
+++ b/extensions/oauth/web-service.c
@@ -0,0 +1,852 @@
+/* -*- 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>
+#ifdef HAVE_LIBSOUP_GNOME
+#include <libsoup/soup-gnome.h>
+#else
+#include <libsoup/soup.h>
+#endif /* HAVE_LIBSOUP_GNOME */
+#ifdef HAVE_LIBSECRET
+#include <libsecret/secret.h>
+#endif /* HAVE_LIBSECRET */
+#include "web-service.h"
+
+
+#undef DEBUG_WEB_CONNECTION
+#define WEB_AUTHENTICATION_RESPONSE_CHOOSE_ACCOUNT 2
+
+
+GQuark
+web_service_error_quark (void)
+{
+ static GQuark quark;
+
+ if (! quark)
+ quark = g_quark_from_static_string ("web-service-error");
+
+ return quark;
+}
+
+
+G_DEFINE_TYPE (WebService, web_service, GTH_TYPE_TASK)
+
+
+enum {
+ PROP_0,
+ PROP_SERVICE_NAME,
+ PROP_SERVICE_ADDRESS,
+ PROP_SERVICE_PROTOCOL,
+ PROP_CANCELLABLE,
+ PROP_BROWSER,
+ PROP_DIALOG
+};
+
+
+/* Signals */
+enum {
+ ACCOUNT_READY,
+ ACCOUNTS_CHANGED,
+ LAST_SIGNAL
+};
+
+
+static guint web_service_signals[LAST_SIGNAL] = { 0 };
+
+
+struct _WebServicePrivate
+{
+ char *service_name;
+ char *service_address;
+ char *service_protocol;
+ SoupSession *session;
+ SoupMessage *msg;
+ GCancellable *cancellable;
+ GSimpleAsyncResult *result;
+ GList *accounts;
+ OAuthAccount *account;
+ GtkWidget *browser;
+ GtkWidget *dialog;
+};
+
+
+static void
+web_service_finalize (GObject *object)
+{
+ WebService *self = WEB_SERVICE (object);
+
+ _g_object_unref (self->priv->account);
+ _g_object_list_unref (self->priv->accounts);
+ _g_object_unref (self->priv->result);
+ _g_object_unref (self->priv->cancellable);
+ _g_object_unref (self->priv->session);
+ g_free (self->priv->service_protocol);
+ g_free (self->priv->service_address);
+ g_free (self->priv->service_name);
+
+ G_OBJECT_CLASS (web_service_parent_class)->finalize (object);
+}
+
+
+static void
+web_service_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ WebService *self = WEB_SERVICE (object);
+
+ switch (property_id) {
+ case PROP_SERVICE_NAME:
+ _g_strset (&self->priv->service_name, g_value_get_string (value));
+ break;
+ case PROP_SERVICE_ADDRESS:
+ _g_strset (&self->priv->service_address, g_value_get_string (value));
+ break;
+ case PROP_SERVICE_PROTOCOL:
+ _g_strset (&self->priv->service_protocol, g_value_get_string (value));
+ break;
+ case PROP_CANCELLABLE:
+ _g_object_unref (self->priv->cancellable);
+ self->priv->cancellable = g_value_dup_object (value);
+ break;
+ case PROP_BROWSER:
+ self->priv->browser = g_value_get_pointer (value);
+ break;
+ case PROP_DIALOG:
+ self->priv->dialog = g_value_get_pointer (value);
+ break;
+ default:
+ break;
+ }
+}
+
+
+static void
+web_service_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ WebService *self = WEB_SERVICE (object);
+
+ switch (property_id) {
+ case PROP_SERVICE_NAME:
+ g_value_set_string (value, self->priv->service_name);
+ break;
+ case PROP_SERVICE_ADDRESS:
+ g_value_set_string (value, self->priv->service_address);
+ break;
+ case PROP_SERVICE_PROTOCOL:
+ g_value_set_string (value, self->priv->service_protocol);
+ break;
+ case PROP_CANCELLABLE:
+ g_value_set_object (value, self->priv->cancellable);
+ break;
+ case PROP_BROWSER:
+ g_value_set_pointer (value, self->priv->browser);
+ break;
+ case PROP_DIALOG:
+ g_value_set_pointer (value, self->priv->dialog);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+static void
+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->account = oauth_accounts_find_default (self->priv->accounts);
+
+ if (G_OBJECT_CLASS (web_service_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (web_service_parent_class)->constructed (object);
+}
+
+
+static void
+web_service_exec (GthTask *base)
+{
+ /* void */
+}
+
+
+static void
+web_service_cancelled (GthTask *base)
+{
+ WebService *self = WEB_SERVICE (base);
+
+ if ((self->priv->session == NULL) || (self->priv->msg == NULL))
+ return;
+
+ soup_session_cancel_message (self->priv->session,
+ self->priv->msg,
+ SOUP_STATUS_CANCELLED);
+}
+
+
+static void
+web_service_class_init (WebServiceClass *klass)
+{
+ GObjectClass *object_class;
+ GthTaskClass *task_class;
+
+ g_type_class_add_private (klass, sizeof (WebServicePrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->finalize = web_service_finalize;
+ object_class->set_property = web_service_set_property;
+ object_class->get_property = web_service_get_property;
+ object_class->constructed = web_service_constructed;
+
+ task_class = (GthTaskClass*) klass;
+ task_class->exec = web_service_exec;
+ task_class->cancelled = web_service_cancelled;
+
+ /* properties */
+
+ g_object_class_install_property (object_class,
+ PROP_SERVICE_NAME,
+ g_param_spec_string ("service-name",
+ "Service Name",
+ "",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_SERVICE_ADDRESS,
+ g_param_spec_string ("service-address",
+ "Service Address",
+ "",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_SERVICE_PROTOCOL,
+ g_param_spec_string ("service-protocol",
+ "Service Protocol",
+ "",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_CANCELLABLE,
+ g_param_spec_object ("cancellable",
+ "Cancellable",
+ "",
+ G_TYPE_CANCELLABLE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_BROWSER,
+ g_param_spec_pointer ("browser",
+ "Browser",
+ "",
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_DIALOG,
+ g_param_spec_pointer ("dialog",
+ "Dialog",
+ "",
+ G_PARAM_READWRITE));
+
+ /* signals */
+
+ web_service_signals[ACCOUNT_READY] =
+ g_signal_new ("account-ready",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (WebServiceClass, account_ready),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ web_service_signals[ACCOUNTS_CHANGED] =
+ g_signal_new ("accounts-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (WebServiceClass, accounts_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+
+static void
+web_service_init (WebService *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, WEB_TYPE_SERVICE, WebServicePrivate);
+ 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;
+}
+
+
+/* -- authentication error dialog -- */
+
+
+static void show_choose_account_dialog (WebService *self);
+
+
+static void
+authentication_error_dialog_response_cb (GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
+{
+ WebService *self = user_data;
+
+ switch (response_id) {
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CANCEL:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ gtk_dialog_response (GTK_DIALOG (self->priv->dialog), GTK_RESPONSE_DELETE_EVENT);
+ break;
+
+ case WEB_AUTHENTICATION_RESPONSE_CHOOSE_ACCOUNT:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ show_choose_account_dialog (self);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static void
+show_authentication_error_dialog (WebService *self,
+ GError **error)
+{
+ GtkWidget *dialog;
+
+ if (g_error_matches (*error, WEB_SERVICE_ERROR, WEB_SERVICE_ERROR_TOKEN_EXPIRED)) {
+ web_service_ask_authorization (self);
+ return;
+ }
+
+ dialog = _gtk_message_dialog_new (GTK_WINDOW (self->priv->browser),
+ GTK_DIALOG_MODAL,
+ GTK_STOCK_DIALOG_ERROR,
+ _("Could not connect to the server"),
+ (*error)->message,
+ _("Choose _Account..."), WEB_AUTHENTICATION_RESPONSE_CHOOSE_ACCOUNT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NULL);
+ gth_task_dialog (GTH_TASK (self), TRUE, dialog);
+
+ g_signal_connect (dialog,
+ "delete-event",
+ G_CALLBACK (gtk_true),
+ NULL);
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (authentication_error_dialog_response_cb),
+ self);
+ gtk_widget_show (dialog);
+
+ g_clear_error (error);
+}
+
+
+/* -- web_service_autoconnect -- */
+
+
+static void
+set_current_account (WebService *self,
+ OAuthAccount *account)
+{
+ GList *link;
+
+ 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);
+ _g_object_list_unref (link);
+ }
+
+ _g_object_unref (self->priv->account);
+ self->priv->account = NULL;
+
+ if (account != NULL) {
+ self->priv->account = g_object_ref (account);
+ self->priv->accounts = g_list_prepend (self->priv->accounts, g_object_ref (self->priv->account));
+ }
+}
+
+
+#ifdef HAVE_LIBSECRET
+static void
+password_store_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ WebService *self = user_data;
+
+ secret_password_store_finish (result, NULL);
+ web_service_account_ready (self);
+}
+#endif
+
+
+static void
+get_user_info_ready_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ WebService *self = user_data;
+ GError *error = NULL;
+ OAuthAccount *account;
+
+ account = web_service_get_user_info_finish (self, res, &error);
+ if (account == NULL) {
+ show_authentication_error_dialog (self, &error);
+ return;
+ }
+
+ set_current_account (self, account);
+ oauth_accounts_save_to_file (self->priv->service_name,
+ self->priv->accounts,
+ self->priv->account);
+
+#ifdef HAVE_LIBSECRET
+ {
+ secret_password_store (SECRET_SCHEMA_COMPAT_NETWORK,
+ NULL,
+ "Web",
+ account->token_secret,
+ self->priv->cancellable,
+ password_store_ready_cb,
+ self,
+ "user", account->id,
+ "server", self->priv->service_address,
+ "protocol", self->priv->service_protocol,
+ NULL);
+ }
+#else
+ web_service_account_ready (self);
+#endif
+
+ g_object_unref (account);
+}
+
+
+static void
+connect_to_server_step2 (WebService *self)
+{
+ if (self->priv->account->token_secret == NULL) {
+ web_service_ask_authorization (self);
+ return;
+ }
+ web_service_get_user_info (self,
+ self->priv->cancellable,
+ get_user_info_ready_cb,
+ self);
+}
+
+
+#ifdef HAVE_LIBSECRET
+static void
+password_lookup_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ WebService *self = user_data;
+ char *secret;
+
+ secret = secret_password_lookup_finish (result, NULL);
+ if (secret != NULL) {
+ g_object_set (G_OBJECT (self->priv->account), "token-secret", secret, NULL);
+ g_free (secret);
+ }
+
+ connect_to_server_step2 (self);
+}
+#endif
+
+
+static void
+connect_to_server (WebService *self)
+{
+ g_return_if_fail (self->priv->account != NULL);
+ g_return_if_fail (self->priv->account->id != NULL);
+
+#ifdef HAVE_LIBSECRET
+ if (self->priv->account->token_secret == NULL) {
+ secret_password_lookup (SECRET_SCHEMA_COMPAT_NETWORK,
+ self->priv->cancellable,
+ password_lookup_ready_cb,
+ self,
+ "user", self->priv->account->id,
+ "server", self->priv->service_address,
+ "protocol", self->priv->service_protocol,
+ NULL);
+ return;
+ }
+#endif
+
+ connect_to_server_step2 (self);
+}
+
+
+static void
+account_chooser_dialog_response_cb (GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
+{
+ WebService *self = user_data;
+
+ switch (response_id) {
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CANCEL:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ gtk_dialog_response (GTK_DIALOG (self->priv->dialog), GTK_RESPONSE_DELETE_EVENT);
+ break;
+
+ case GTK_RESPONSE_OK:
+ _g_object_unref (self->priv->account);
+ self->priv->account = oauth_account_chooser_dialog_get_active (OAUTH_ACCOUNT_CHOOSER_DIALOG (dialog));
+ if (self->priv->account != NULL) {
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ connect_to_server (self);
+ }
+ break;
+
+ case OAUTH_ACCOUNT_CHOOSER_RESPONSE_NEW:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ web_service_ask_authorization (self);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static void
+show_choose_account_dialog (WebService *self)
+{
+ GtkWidget *dialog;
+
+ gth_task_dialog (GTH_TASK (self), TRUE, NULL);
+ dialog = oauth_account_chooser_dialog_new (self->priv->accounts, self->priv->account);
+ g_signal_connect (dialog,
+ "delete-event",
+ G_CALLBACK (gtk_true),
+ NULL);
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (account_chooser_dialog_response_cb),
+ self);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Choose Account"));
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (self->priv->browser));
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+
+void
+web_service_autoconnect (WebService *self)
+{
+ gtk_widget_hide (self->priv->dialog);
+ gth_task_dialog (GTH_TASK (self), FALSE, NULL);
+
+ if (self->priv->accounts != NULL) {
+ if (self->priv->account != NULL) {
+ connect_to_server (self);
+ }
+ else if (self->priv->accounts->next == NULL) {
+ self->priv->account = g_object_ref (self->priv->accounts->data);
+ connect_to_server (self);
+ }
+ else
+ show_choose_account_dialog (self);
+ }
+ else
+ web_service_ask_authorization (self);
+}
+
+
+void
+web_service_connect (WebService *self,
+ OAuthAccount *account)
+{
+ set_current_account (self, account);
+ web_service_autoconnect (self);
+}
+
+
+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);
+}
+
+
+OAuthAccount *
+web_service_get_current_account (WebService *self)
+{
+ return self->priv->account;
+}
+
+
+GList *
+web_service_get_accounts (WebService *self)
+{
+ return self->priv->accounts;
+}
+
+
+/* -- web_service_edit_accounts -- */
+
+
+static void
+account_manager_dialog_response_cb (GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
+{
+ WebService *self = user_data;
+
+ switch (response_id) {
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CANCEL:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ break;
+
+ case GTK_RESPONSE_OK:
+ _g_object_list_unref (self->priv->accounts);
+ self->priv->accounts = oauth_account_manager_dialog_get_accounts (OAUTH_ACCOUNT_MANAGER_DIALOG (dialog));
+ if (! g_list_find_custom (self->priv->accounts, self->priv->account, (GCompareFunc) oauth_account_cmp)) {
+ _g_object_unref (self->priv->account);
+ self->priv->account = NULL;
+ web_service_autoconnect (self);
+ }
+ else
+ g_signal_emit (self, web_service_signals[ACCOUNTS_CHANGED], 0);
+ oauth_accounts_save_to_file (self->priv->service_name, self->priv->accounts, self->priv->account);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ break;
+
+ case OAUTH_ACCOUNT_CHOOSER_RESPONSE_NEW:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ web_service_ask_authorization (self);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void
+web_service_edit_accounts (WebService *self,
+ GtkWindow *parent)
+{
+ GtkWidget *dialog;
+
+ dialog = oauth_account_manager_dialog_new (self->priv->accounts);
+ g_signal_connect (dialog,
+ "delete-event",
+ G_CALLBACK (gtk_true),
+ NULL);
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (account_manager_dialog_response_cb),
+ self);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Edit Accounts"));
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (self->priv->dialog));
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+
+void
+web_service_account_ready (WebService *self)
+{
+ g_signal_emit (self, web_service_signals[ACCOUNT_READY], 0);
+}
+
+
+void
+web_service_ask_authorization (WebService *self)
+{
+ WEB_SERVICE_GET_CLASS (self)->ask_authorization (self);
+}
+
+
+void
+web_service_get_user_info (WebService *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ gth_task_progress (GTH_TASK (self),
+ _("Connecting to the server"),
+ _("Getting account information"),
+ TRUE,
+ 0.0);
+
+ WEB_SERVICE_GET_CLASS (self)->get_user_info (self, cancellable, callback, user_data);
+}
+
+
+OAuthAccount *
+web_service_get_user_info_finish (WebService *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ 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)));
+}
+
+
+/* -- connection utilities -- */
+
+
+void
+_web_service_send_message (WebService *self,
+ SoupMessage *msg,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ gpointer source_tag,
+ SoupSessionCallback soup_session_cb,
+ gpointer soup_session_cb_data)
+{
+ if (self->priv->session == NULL) {
+ self->priv->session = soup_session_async_new_with_options (
+#ifdef HAVE_LIBSOUP_GNOME
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_GNOME,
+#endif
+ NULL);
+
+#ifdef DEBUG_WEB_CONNECTION
+ {
+ SoupLogger *logger;
+
+ logger = soup_logger_new (SOUP_LOGGER_LOG_BODY, -1);
+ soup_session_add_feature (self->priv->session, SOUP_SESSION_FEATURE (logger));
+
+ g_object_unref (logger);
+ }
+#endif
+ }
+
+ _g_object_unref (self->priv->cancellable);
+ self->priv->cancellable = _g_object_ref (cancellable);
+
+ _g_object_unref (self->priv->result);
+ self->priv->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ source_tag);
+
+ self->priv->msg = msg;
+ g_object_add_weak_pointer (G_OBJECT (msg), (gpointer *) &self->priv->msg);
+
+ soup_session_queue_message (self->priv->session,
+ msg,
+ soup_session_cb,
+ soup_session_cb_data);
+}
+
+
+GSimpleAsyncResult *
+_web_service_get_result (WebService *self)
+{
+ return self->priv->result;
+}
+
+
+SoupMessage *
+_web_service_get_message (WebService *self)
+{
+ return self->priv->msg;
+}
+
+
+/* -- _web_service_set_auth_dialog -- */
+
+
+static void
+ask_authorization_dialog_response_cb (GtkDialog *dialog,
+ int response_id,
+ gpointer user_data)
+{
+ WebService *self = user_data;
+
+ switch (response_id) {
+ case GTK_RESPONSE_DELETE_EVENT:
+ case GTK_RESPONSE_CANCEL:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ gtk_dialog_response (GTK_DIALOG (self->priv->dialog), GTK_RESPONSE_DELETE_EVENT);
+ break;
+
+ case GTK_RESPONSE_OK:
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ gth_task_dialog (GTH_TASK (self), FALSE, NULL);
+ web_service_get_user_info (self,
+ self->priv->cancellable,
+ get_user_info_ready_cb,
+ self);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void
+_web_service_set_auth_dialog (WebService *self,
+ GtkDialog *dialog)
+{
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ if (gtk_widget_get_visible (self->priv->dialog))
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (self->priv->dialog));
+ else
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (self->priv->browser));
+
+ g_signal_connect (dialog,
+ "delete-event",
+ G_CALLBACK (gtk_true),
+ NULL);
+ g_signal_connect (dialog,
+ "response",
+ G_CALLBACK (ask_authorization_dialog_response_cb),
+ self);
+}
diff --git a/extensions/oauth/web-service.h b/extensions/oauth/web-service.h
new file mode 100644
index 0000000..8526555
--- /dev/null
+++ b/extensions/oauth/web-service.h
@@ -0,0 +1,111 @@
+/* -*- 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 WEB_SERVICE_H
+#define WEB_SERVICE_H
+
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include "oauth.h"
+
+#define WEB_SERVICE_ERROR web_service_error_quark()
+#define WEB_SERVICE_ERROR_TOKEN_EXPIRED 1
+
+GQuark web_service_error_quark (void);
+
+typedef enum {
+ WEB_AUTHORIZATION_READ,
+ WEB_AUTHORIZATION_WRITE
+} WebAuthorizationType;
+
+#define WEB_TYPE_SERVICE (web_service_get_type ())
+#define WEB_SERVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), WEB_TYPE_SERVICE, WebService))
+#define WEB_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), WEB_TYPE_SERVICE, WebServiceClass))
+#define WEB_IS_SERVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), WEB_TYPE_SERVICE))
+#define WEB_IS_SERVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), WEB_TYPE_SERVICE))
+#define WEB_SERVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), WEB_TYPE_SERVICE, WebServiceClass))
+
+typedef struct _WebService WebService;
+typedef struct _WebServicePrivate WebServicePrivate;
+typedef struct _WebServiceClass WebServiceClass;
+
+struct _WebService
+{
+ GthTask __parent;
+ WebServicePrivate *priv;
+};
+
+struct _WebServiceClass
+{
+ GthTaskClass __parent_class;
+
+ /*< signals >*/
+
+ void (*account_ready) (WebService *self);
+ void (*accounts_changed) (WebService *self);
+
+ /*< virtual functions >*/
+
+ void (*ask_authorization) (WebService *self);
+ void (*get_user_info) (WebService *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+};
+
+GType web_service_get_type (void) G_GNUC_CONST;
+void web_service_autoconnect (WebService *self);
+void web_service_connect (WebService *self,
+ OAuthAccount *account);
+void web_service_set_current_account (WebService *self,
+ OAuthAccount *account);
+OAuthAccount * web_service_get_current_account (WebService *self);
+GList * web_service_get_accounts (WebService *self);
+void web_service_edit_accounts (WebService *self,
+ GtkWindow *parent);
+void web_service_account_ready (WebService *self);
+void web_service_ask_authorization (WebService *self);
+void web_service_get_user_info (WebService *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+OAuthAccount * web_service_get_user_info_finish(WebService *self,
+ GAsyncResult *result,
+ GError **error);
+
+/* -- utilities -- */
+
+void _web_service_send_message (WebService *self,
+ SoupMessage *msg,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ gpointer source_tag,
+ SoupSessionCallback soup_session_cb,
+ gpointer soup_session_cb_data);
+GSimpleAsyncResult *
+ _web_service_get_result (WebService *self);
+SoupMessage * _web_service_get_message (WebService *self);
+void _web_service_set_auth_dialog (WebService *self,
+ GtkDialog *dialog);
+
+#endif /* WEB_SERVICE_H */
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]