Blame gdata/gdata-oauth1-authorizer.c

Packit 4b6dd7
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
Packit 4b6dd7
/*
Packit 4b6dd7
 * GData Client
Packit 4b6dd7
 * Copyright (C) Philip Withnall 2011 <philip@tecnocode.co.uk>
Packit 4b6dd7
 *
Packit 4b6dd7
 * GData Client is free software; you can redistribute it and/or
Packit 4b6dd7
 * modify it under the terms of the GNU Lesser General Public
Packit 4b6dd7
 * License as published by the Free Software Foundation; either
Packit 4b6dd7
 * version 2.1 of the License, or (at your option) any later version.
Packit 4b6dd7
 *
Packit 4b6dd7
 * GData Client is distributed in the hope that it will be useful,
Packit 4b6dd7
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4b6dd7
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 4b6dd7
 * Lesser General Public License for more details.
Packit 4b6dd7
 *
Packit 4b6dd7
 * You should have received a copy of the GNU Lesser General Public
Packit 4b6dd7
 * License along with GData Client.  If not, see <http://www.gnu.org/licenses/>.
Packit 4b6dd7
 */
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * SECTION:gdata-oauth1-authorizer
Packit 4b6dd7
 * @short_description: GData OAuth 1.0 authorization interface
Packit 4b6dd7
 * @stability: Stable
Packit 4b6dd7
 * @include: gdata/gdata-oauth1-authorizer.h
Packit 4b6dd7
 *
Packit 4b6dd7
 * #GDataOAuth1Authorizer provides an implementation of the #GDataAuthorizer interface for authentication and authorization using the
Packit 4b6dd7
 * <ulink type="http" url="http://code.google.com/apis/accounts/docs/OAuthForInstalledApps.html">OAuth 1.0</ulink> process,
Packit 4b6dd7
 * which was preferred by Google until OAuth 2.0 was released — it is now
Packit 4b6dd7
 * preferred to use #GDataOAuth2Authorizer.
Packit 4b6dd7
 *
Packit 4b6dd7
 * OAuth 1.0 replaces the deprecated ClientLogin process. One of the main reasons for this is to allow two-factor authentication to be supported, by
Packit 4b6dd7
 * moving the authentication interface to a web page under Google's control.
Packit 4b6dd7
 *
Packit 4b6dd7
 * The OAuth 1.0 process as implemented by Google follows the <ulink type="http" url="http://tools.ietf.org/html/rfc5849">OAuth 1.0 protocol as
Packit 4b6dd7
 * specified by IETF in RFC 5849</ulink>, with a few additions to support scopes (implemented in libgdata by #GDataAuthorizationDomains),
Packit 4b6dd7
 * locales and custom domains. Briefly, the process is initiated by requesting an authenticated request token from the Google accounts service
Packit 4b6dd7
 * (using gdata_oauth1_authorizer_request_authentication_uri()), going to the authentication URI for the request token, authenticating and authorizing
Packit 4b6dd7
 * access to the desired scopes, then providing the verifier returned by Google to the Google accounts service again (using
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization()) to authorize the token. This results in an access token which is attached to all future requests
Packit 4b6dd7
 * to the online service.
Packit 4b6dd7
 *
Packit 4b6dd7
 * While Google supports unregistered and registered modes for OAuth 1.0 authorization, it only supports unregistered mode for installed applications.
Packit 4b6dd7
 * Consequently, libgdata also only supports unregistered mode. For this purpose, the application name to be presented to the user on the
Packit 4b6dd7
 * authentication page at the URI returned by gdata_oauth1_authorizer_request_authentication_uri() can be specified when constructing the
Packit 4b6dd7
 * #GDataOAuth1Authorizer.
Packit 4b6dd7
 *
Packit 4b6dd7
 * As described, each authentication/authorization operation is in two parts: gdata_oauth1_authorizer_request_authentication_uri() and
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization(). #GDataOAuth1Authorizer stores no state about ongoing authentication operations (i.e. ones which
Packit 4b6dd7
 * have successfully called gdata_oauth1_authorizer_request_authentication_uri(), but are yet to successfully call
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization()). Consequently, operations can be abandoned before calling
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization() without problems. The only state necessary between the calls is the request token and request token
Packit 4b6dd7
 * secret, as returned by gdata_oauth1_authorizer_request_authentication_uri() and taken as parameters to
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization().
Packit 4b6dd7
 *
Packit 4b6dd7
 * #GDataOAuth1Authorizer natively supports authorization against multiple services in a single authorization request (unlike
Packit 4b6dd7
 * #GDataClientLoginAuthorizer).
Packit 4b6dd7
 *
Packit 4b6dd7
 * Each access token is long lived, so reauthorization is rarely necessary with #GDataOAuth1Authorizer. Consequently, refreshing authorization using
Packit 4b6dd7
 * gdata_authorizer_refresh_authorization() is not supported by #GDataOAuth1Authorizer, and will immediately return %FALSE with no error set.
Packit 4b6dd7
 *
Packit 4b6dd7
 * <example>
Packit 4b6dd7
 *	<title>Authenticating Asynchronously Using OAuth 1.0</title>
Packit 4b6dd7
 *	<programlisting>
Packit 4b6dd7
 *	GDataSomeService *service;
Packit 4b6dd7
 *	GDataOAuth1Authorizer *authorizer;
Packit 4b6dd7
 *
Packit 4b6dd7
 *	/* Create an authorizer and authenticate and authorize the service we're using, asynchronously. */
Packit 4b6dd7
 *	authorizer = gdata_oauth1_authorizer_new (_("My libgdata application"), GDATA_TYPE_SOME_SERVICE);
Packit 4b6dd7
 *	gdata_oauth1_authorizer_request_authentication_uri_async (authorizer, cancellable,
Packit 4b6dd7
 *	                                                          (GAsyncReadyCallback) request_authentication_uri_cb, user_data);
Packit 4b6dd7
 *
Packit 4b6dd7
 *	/* Create a service object and link it with the authorizer */
Packit 4b6dd7
 *	service = gdata_some_service_new (GDATA_AUTHORIZER (authorizer));
Packit 4b6dd7
 *
Packit 4b6dd7
 *	static void
Packit 4b6dd7
 *	request_authentication_uri_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, gpointer user_data)
Packit 4b6dd7
 *	{
Packit 4b6dd7
 *		gchar *authentication_uri, *token, *token_secret, *verifier;
Packit 4b6dd7
 *		GError *error = NULL;
Packit 4b6dd7
 *
Packit 4b6dd7
 *		authentication_uri = gdata_oauth1_authorizer_request_authentication_uri_finish (authorizer, async_result, &token, &token_secret,
Packit 4b6dd7
 *		                                                                                &error);
Packit 4b6dd7
 *
Packit 4b6dd7
 *		if (error != NULL) {
Packit 4b6dd7
 *			/* Notify the user of all errors except cancellation errors */
Packit 4b6dd7
 *			if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
Packit 4b6dd7
 *				g_error ("Requesting a token failed: %s", error->message);
Packit 4b6dd7
 *			}
Packit 4b6dd7
 *
Packit 4b6dd7
 *			g_error_free (error);
Packit 4b6dd7
 *			goto finish;
Packit 4b6dd7
 *		}
Packit 4b6dd7
 *
Packit 4b6dd7
 *		/* (Present the page at the authentication URI to the user, either in an embedded or stand-alone web browser, and
Packit 4b6dd7
 *		 * ask them to grant access to the application and return the verifier Google gives them.) */
Packit 4b6dd7
 *		verifier = ask_user_for_verifier (authentication_uri);
Packit 4b6dd7
 *
Packit 4b6dd7
 *		gdata_oauth1_authorizer_request_authorization_async (authorizer, token, token_secret, verifier, cancellable,
Packit 4b6dd7
 *		                                                     (GAsyncReadyCallback) request_authorization_cb, user_data);
Packit 4b6dd7
 *
Packit 4b6dd7
 *	finish:
Packit 4b6dd7
 *		g_free (verifier);
Packit 4b6dd7
 *		g_free (authentication_uri);
Packit 4b6dd7
 *		g_free (token);
Packit 4b6dd7
 *
Packit 4b6dd7
 *		/* Zero out the secret before freeing. */
Packit 4b6dd7
 *		if (token_secret != NULL) {
Packit 4b6dd7
 *			memset (token_secret, 0, strlen (token_secret));
Packit 4b6dd7
 *		}
Packit 4b6dd7
 *
Packit 4b6dd7
 *		g_free (token_secret);
Packit 4b6dd7
 *	}
Packit 4b6dd7
 *
Packit 4b6dd7
 *	static void
Packit 4b6dd7
 *	request_authorization_cb (GDataOAuth1Authorizer *authorizer, GAsyncResult *async_result, gpointer user_data)
Packit 4b6dd7
 *	{
Packit 4b6dd7
 *		GError *error = NULL;
Packit 4b6dd7
 *
Packit 4b6dd7
 *		if (gdata_oauth1_authorizer_request_authorization_finish (authorizer, async_result, &error) == FALSE) {
Packit 4b6dd7
 *			/* Notify the user of all errors except cancellation errors */
Packit 4b6dd7
 *			if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
Packit 4b6dd7
 *				g_error ("Authorization failed: %s", error->message);
Packit 4b6dd7
 *			}
Packit 4b6dd7
 *
Packit 4b6dd7
 *			g_error_free (error);
Packit 4b6dd7
 *			return;
Packit 4b6dd7
 *		}
Packit 4b6dd7
 *
Packit 4b6dd7
 *		/* (The client is now authenticated and authorized against the service.
Packit 4b6dd7
 *		 * It can now proceed to execute queries on the service object which require the user to be authenticated.) */
Packit 4b6dd7
 *	}
Packit 4b6dd7
 *
Packit 4b6dd7
 *	g_object_unref (service);
Packit 4b6dd7
 *	g_object_unref (authorizer);
Packit 4b6dd7
 *	</programlisting>
Packit 4b6dd7
 * </example>
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
Packit 4b6dd7
#include <config.h>
Packit 4b6dd7
#include <string.h>
Packit 4b6dd7
#include <oauth.h>
Packit 4b6dd7
#include <glib.h>
Packit 4b6dd7
#include <glib/gi18n-lib.h>
Packit 4b6dd7
Packit 4b6dd7
#include "gdata-oauth1-authorizer.h"
Packit 4b6dd7
#include "gdata-private.h"
Packit 4b6dd7
Packit 4b6dd7
#define HMAC_SHA1_LEN 20 /* bytes, raw */
Packit 4b6dd7
Packit 4b6dd7
static void authorizer_init (GDataAuthorizerInterface *iface);
Packit 4b6dd7
static void dispose (GObject *object);
Packit 4b6dd7
static void finalize (GObject *object);
Packit 4b6dd7
static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
Packit 4b6dd7
static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
Packit 4b6dd7
Packit 4b6dd7
static void process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMessage *message);
Packit 4b6dd7
static gboolean is_authorized_for_domain (GDataAuthorizer *self, GDataAuthorizationDomain *domain);
Packit 4b6dd7
Packit 4b6dd7
static void sign_message (GDataOAuth1Authorizer *self, SoupMessage *message, const gchar *token, const gchar *token_secret, GHashTable *parameters);
Packit 4b6dd7
Packit 4b6dd7
static void notify_proxy_uri_cb (GObject *object, GParamSpec *pspec, GDataOAuth1Authorizer *self);
Packit 4b6dd7
static void notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *self);
Packit 4b6dd7
Packit 4b6dd7
static SoupURI *_get_proxy_uri (GDataOAuth1Authorizer *self);
Packit 4b6dd7
static void _set_proxy_uri (GDataOAuth1Authorizer *self, SoupURI *proxy_uri);
Packit 4b6dd7
Packit 4b6dd7
struct _GDataOAuth1AuthorizerPrivate {
Packit 4b6dd7
	SoupSession *session;
Packit 4b6dd7
	SoupURI *proxy_uri; /* cached version only set if gdata_oauth1_authorizer_get_proxy_uri() is called */
Packit 4b6dd7
	GProxyResolver *proxy_resolver;
Packit 4b6dd7
Packit 4b6dd7
	gchar *application_name;
Packit 4b6dd7
	gchar *locale;
Packit 4b6dd7
Packit 4b6dd7
	GMutex mutex; /* mutex for token, token_secret and authorization_domains */
Packit 4b6dd7
Packit 4b6dd7
	/* Note: This is the access token, not the request token returned by gdata_oauth1_authorizer_request_authentication_uri().
Packit 4b6dd7
	 * It's NULL iff the authorizer isn't authenticated. token_secret must be NULL iff token is NULL. */
Packit 4b6dd7
	gchar *token;
Packit 4b6dd7
	GDataSecureString token_secret; /* must be allocated by _gdata_service_secure_strdup() */
Packit 4b6dd7
Packit 4b6dd7
	/* Mapping from GDataAuthorizationDomain to itself; a set of domains for which ->access_token is valid. */
Packit 4b6dd7
	GHashTable *authorization_domains;
Packit 4b6dd7
};
Packit 4b6dd7
Packit 4b6dd7
enum {
Packit 4b6dd7
	PROP_APPLICATION_NAME = 1,
Packit 4b6dd7
	PROP_LOCALE,
Packit 4b6dd7
	PROP_PROXY_URI,
Packit 4b6dd7
	PROP_TIMEOUT,
Packit 4b6dd7
	PROP_PROXY_RESOLVER,
Packit 4b6dd7
};
Packit 4b6dd7
Packit 4b6dd7
G_DEFINE_TYPE_WITH_CODE (GDataOAuth1Authorizer, gdata_oauth1_authorizer, G_TYPE_OBJECT,
Packit 4b6dd7
                         G_IMPLEMENT_INTERFACE (GDATA_TYPE_AUTHORIZER, authorizer_init))
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_oauth1_authorizer_class_init (GDataOAuth1AuthorizerClass *klass)
Packit 4b6dd7
{
Packit 4b6dd7
	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit 4b6dd7
Packit 4b6dd7
	g_type_class_add_private (klass, sizeof (GDataOAuth1AuthorizerPrivate));
Packit 4b6dd7
Packit 4b6dd7
	gobject_class->get_property = get_property;
Packit 4b6dd7
	gobject_class->set_property = set_property;
Packit 4b6dd7
	gobject_class->dispose = dispose;
Packit 4b6dd7
	gobject_class->finalize = finalize;
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataOAuth1Authorizer:application-name:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The human-readable, translated application name for the client, to be presented to the user on the authentication page at the URI
Packit 4b6dd7
	 * returned by gdata_oauth1_authorizer_request_authentication_uri().
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * If %NULL is provided in the constructor to #GDataOAuth1Authorizer, the value returned by g_get_application_name() will be used as a
Packit 4b6dd7
	 * fallback. Note that this may also be %NULL: in this case, the authentication page will use the application name “anonymous”.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.9.0
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_APPLICATION_NAME,
Packit 4b6dd7
	                                 g_param_spec_string ("application-name",
Packit 4b6dd7
	                                                      "Application name", "The human-readable, translated application name for the client.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataOAuth1Authorizer:locale:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The locale to use for network requests, in Unix locale format. (e.g. "en_GB", "cs", "de_DE".) Use %NULL for the default "C" locale
Packit 4b6dd7
	 * (typically "en_US").
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * This locale will be used by the server-side software to localise the authentication and authorization pages at the URI returned by
Packit 4b6dd7
	 * gdata_oauth1_authorizer_request_authentication_uri().
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The server-side behaviour is undefined if it doesn't support a given locale.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.9.0
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_LOCALE,
Packit 4b6dd7
	                                 g_param_spec_string ("locale",
Packit 4b6dd7
	                                                      "Locale", "The locale to use for network requests, in Unix locale format.",
Packit 4b6dd7
	                                                      NULL,
Packit 4b6dd7
	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataOAuth1Authorizer:proxy-uri:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The proxy URI used internally for all network requests.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.9.0
Packit 4b6dd7
	 * Deprecated: 0.15.0: Use #GDataClientLoginAuthorizer:proxy-resolver instead, which gives more flexibility over the proxy used.
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_PROXY_URI,
Packit 4b6dd7
	                                 g_param_spec_boxed ("proxy-uri",
Packit 4b6dd7
	                                                     "Proxy URI", "The proxy URI used internally for all network requests.",
Packit 4b6dd7
	                                                     SOUP_TYPE_URI,
Packit 4b6dd7
	                                                     G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataOAuth1Authorizer:timeout:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * A timeout, in seconds, for network operations. If the timeout is exceeded, the operation will be cancelled and
Packit 4b6dd7
	 * %GDATA_SERVICE_ERROR_NETWORK_ERROR will be returned.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * If the timeout is 0, operations will never time out.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.9.0
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_TIMEOUT,
Packit 4b6dd7
	                                 g_param_spec_uint ("timeout",
Packit 4b6dd7
	                                                    "Timeout", "A timeout, in seconds, for network operations.",
Packit 4b6dd7
	                                                    0, G_MAXUINT, 0,
Packit 4b6dd7
	                                                    G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
Packit 4b6dd7
	/**
Packit 4b6dd7
	 * GDataOAuth1Authorizer:proxy-resolver:
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * The #GProxyResolver used to determine a proxy URI.  Setting this will clear the #GDataOAuth1Authorizer:proxy-uri property.
Packit 4b6dd7
	 *
Packit 4b6dd7
	 * Since: 0.15.0
Packit 4b6dd7
	 */
Packit 4b6dd7
	g_object_class_install_property (gobject_class, PROP_PROXY_RESOLVER,
Packit 4b6dd7
	                                 g_param_spec_object ("proxy-resolver",
Packit 4b6dd7
	                                                      "Proxy Resolver", "A GProxyResolver used to determine a proxy URI.",
Packit 4b6dd7
	                                                      G_TYPE_PROXY_RESOLVER,
Packit 4b6dd7
	                                                      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
authorizer_init (GDataAuthorizerInterface *iface)
Packit 4b6dd7
{
Packit 4b6dd7
	iface->process_request = process_request;
Packit 4b6dd7
	iface->is_authorized_for_domain = is_authorized_for_domain;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
gdata_oauth1_authorizer_init (GDataOAuth1Authorizer *self)
Packit 4b6dd7
{
Packit 4b6dd7
	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_OAUTH1_AUTHORIZER, GDataOAuth1AuthorizerPrivate);
Packit 4b6dd7
Packit 4b6dd7
	/* Set up the authorizer's mutex */
Packit 4b6dd7
	g_mutex_init (&(self->priv->mutex));
Packit 4b6dd7
	self->priv->authorization_domains = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
Packit 4b6dd7
Packit 4b6dd7
	/* Set up the session */
Packit 4b6dd7
	self->priv->session = _gdata_service_build_session ();
Packit 4b6dd7
Packit 4b6dd7
	/* Proxy the SoupSession's proxy-uri and timeout properties */
Packit 4b6dd7
	g_signal_connect (self->priv->session, "notify::proxy-uri", (GCallback) notify_proxy_uri_cb, self);
Packit 4b6dd7
	g_signal_connect (self->priv->session, "notify::timeout", (GCallback) notify_timeout_cb, self);
Packit 4b6dd7
Packit 4b6dd7
	/* Keep our GProxyResolver synchronized with SoupSession's. */
Packit 4b6dd7
	g_object_bind_property (self->priv->session, "proxy-resolver", self, "proxy-resolver", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
dispose (GObject *object)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (object)->priv;
Packit 4b6dd7
Packit 4b6dd7
	if (priv->session != NULL)
Packit 4b6dd7
		g_object_unref (priv->session);
Packit 4b6dd7
	priv->session = NULL;
Packit 4b6dd7
Packit 4b6dd7
	g_clear_object (&priv->proxy_resolver);
Packit 4b6dd7
Packit 4b6dd7
	/* Chain up to the parent class */
Packit 4b6dd7
	G_OBJECT_CLASS (gdata_oauth1_authorizer_parent_class)->dispose (object);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
finalize (GObject *object)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (object)->priv;
Packit 4b6dd7
Packit 4b6dd7
	g_free (priv->application_name);
Packit 4b6dd7
	g_free (priv->locale);
Packit 4b6dd7
Packit 4b6dd7
	g_hash_table_destroy (priv->authorization_domains);
Packit 4b6dd7
	g_mutex_clear (&(priv->mutex));
Packit 4b6dd7
Packit 4b6dd7
	if (priv->proxy_uri != NULL) {
Packit 4b6dd7
		soup_uri_free (priv->proxy_uri);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_free (priv->token);
Packit 4b6dd7
	_gdata_service_secure_strfree (priv->token_secret);
Packit 4b6dd7
Packit 4b6dd7
	/* Chain up to the parent class */
Packit 4b6dd7
	G_OBJECT_CLASS (gdata_oauth1_authorizer_parent_class)->finalize (object);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (object)->priv;
Packit 4b6dd7
Packit 4b6dd7
	switch (property_id) {
Packit 4b6dd7
		case PROP_APPLICATION_NAME:
Packit 4b6dd7
			g_value_set_string (value, priv->application_name);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_LOCALE:
Packit 4b6dd7
			g_value_set_string (value, priv->locale);
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_PROXY_URI:
Packit 4b6dd7
			g_value_set_boxed (value, _get_proxy_uri (GDATA_OAUTH1_AUTHORIZER (object)));
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_TIMEOUT:
Packit 4b6dd7
			g_value_set_uint (value, gdata_oauth1_authorizer_get_timeout (GDATA_OAUTH1_AUTHORIZER (object)));
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_PROXY_RESOLVER:
Packit 4b6dd7
			g_value_set_object (value, gdata_oauth1_authorizer_get_proxy_resolver (GDATA_OAUTH1_AUTHORIZER (object)));
Packit 4b6dd7
			break;
Packit 4b6dd7
		default:
Packit 4b6dd7
			/* We don't have any other property... */
Packit 4b6dd7
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
Packit 4b6dd7
			break;
Packit 4b6dd7
	}
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (object)->priv;
Packit 4b6dd7
Packit 4b6dd7
	switch (property_id) {
Packit 4b6dd7
		/* Construct only */
Packit 4b6dd7
		case PROP_APPLICATION_NAME:
Packit 4b6dd7
			priv->application_name = g_value_dup_string (value);
Packit 4b6dd7
Packit 4b6dd7
			/* Default to the value of g_get_application_name() */
Packit 4b6dd7
			if (priv->application_name == NULL || *(priv->application_name) == '\0') {
Packit 4b6dd7
				g_free (priv->application_name);
Packit 4b6dd7
				priv->application_name = g_strdup (g_get_application_name ());
Packit 4b6dd7
			}
Packit 4b6dd7
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_LOCALE:
Packit 4b6dd7
			gdata_oauth1_authorizer_set_locale (GDATA_OAUTH1_AUTHORIZER (object), g_value_get_string (value));
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_PROXY_URI:
Packit 4b6dd7
			_set_proxy_uri (GDATA_OAUTH1_AUTHORIZER (object), g_value_get_boxed (value));
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_TIMEOUT:
Packit 4b6dd7
			gdata_oauth1_authorizer_set_timeout (GDATA_OAUTH1_AUTHORIZER (object), g_value_get_uint (value));
Packit 4b6dd7
			break;
Packit 4b6dd7
		case PROP_PROXY_RESOLVER:
Packit 4b6dd7
			gdata_oauth1_authorizer_set_proxy_resolver (GDATA_OAUTH1_AUTHORIZER (object), g_value_get_object (value));
Packit 4b6dd7
			break;
Packit 4b6dd7
		default:
Packit 4b6dd7
			/* We don't have any other property... */
Packit 4b6dd7
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
Packit 4b6dd7
			break;
Packit 4b6dd7
	}
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMessage *message)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (self)->priv;
Packit 4b6dd7
Packit 4b6dd7
	/* Set the authorisation header */
Packit 4b6dd7
	g_mutex_lock (&(priv->mutex));
Packit 4b6dd7
Packit 4b6dd7
	/* Sanity check */
Packit 4b6dd7
	g_assert ((priv->token == NULL) == (priv->token_secret == NULL));
Packit 4b6dd7
Packit 4b6dd7
	if (priv->token != NULL && g_hash_table_lookup (priv->authorization_domains, domain) != NULL) {
Packit 4b6dd7
		sign_message (GDATA_OAUTH1_AUTHORIZER (self), message, priv->token, priv->token_secret, NULL);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_mutex_unlock (&(priv->mutex));
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static gboolean
Packit 4b6dd7
is_authorized_for_domain (GDataAuthorizer *self, GDataAuthorizationDomain *domain)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1AuthorizerPrivate *priv = GDATA_OAUTH1_AUTHORIZER (self)->priv;
Packit 4b6dd7
	gpointer result;
Packit 4b6dd7
	const gchar *token;
Packit 4b6dd7
Packit 4b6dd7
	g_mutex_lock (&(priv->mutex));
Packit 4b6dd7
	token = priv->token;
Packit 4b6dd7
	result = g_hash_table_lookup (priv->authorization_domains, domain);
Packit 4b6dd7
	g_mutex_unlock (&(priv->mutex));
Packit 4b6dd7
Packit 4b6dd7
	/* Sanity check */
Packit 4b6dd7
	g_assert (result == NULL || result == domain);
Packit 4b6dd7
Packit 4b6dd7
	return (token != NULL && result != NULL) ? TRUE : FALSE;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/* Sign the message and add the Authorization header to it containing the signature.
Packit 4b6dd7
 * NOTE: This must not lock priv->mutex, as it's called from within a critical section in process_request() and priv->mutex isn't recursive. */
Packit 4b6dd7
static void
Packit 4b6dd7
sign_message (GDataOAuth1Authorizer *self, SoupMessage *message, const gchar *token, const gchar *token_secret, GHashTable *parameters)
Packit 4b6dd7
{
Packit 4b6dd7
	GHashTableIter iter;
Packit 4b6dd7
	const gchar *key, *value, *consumer_key, *consumer_secret, *signature_method;
Packit 4b6dd7
	gsize params_length = 0;
Packit 4b6dd7
	GList *sorted_params = NULL, *i;
Packit 4b6dd7
	GString *query_string, *signature_base_string, *secret_string, *authorization_header;
Packit 4b6dd7
	SoupURI *normalised_uri;
Packit 4b6dd7
	gchar *uri, *signature, *timestamp;
Packit 4b6dd7
	char *nonce;
Packit 4b6dd7
	gboolean is_first = TRUE;
Packit 4b6dd7
	GTimeVal time_val;
Packit 4b6dd7
	guchar signature_buf[HMAC_SHA1_LEN];
Packit 4b6dd7
	gsize signature_buf_len;
Packit 4b6dd7
	GHmac *signature_hmac;
Packit 4b6dd7
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
Packit 4b6dd7
	g_return_if_fail (SOUP_IS_MESSAGE (message));
Packit 4b6dd7
	g_return_if_fail (token == NULL || *token != '\0');
Packit 4b6dd7
	g_return_if_fail (token_secret == NULL || *token_secret != '\0');
Packit 4b6dd7
	g_return_if_fail ((token == NULL) == (token_secret == NULL));
Packit 4b6dd7
Packit 4b6dd7
	/* Build and return a HMAC-SHA1 signature for the given SoupMessage. We always use HMAC-SHA1, since installed applications have to be
Packit 4b6dd7
	 * unregistered (see: http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth).
Packit 4b6dd7
	 * Reference: http://tools.ietf.org/html/rfc5849#section-3.4 */
Packit 4b6dd7
	signature_method = "HMAC-SHA1";
Packit 4b6dd7
Packit 4b6dd7
	/* As described here, we use an anonymous consumer key and secret, since we're designed for installed applications:
Packit 4b6dd7
	 * http://code.google.com/apis/accounts/docs/OAuth_ref.html#SigningOAuth */
Packit 4b6dd7
	consumer_key = "anonymous";
Packit 4b6dd7
	consumer_secret = "anonymous";
Packit 4b6dd7
Packit 4b6dd7
	/* Add various standard parameters to the list (note: this modifies the hash table belonging to the caller) */
Packit 4b6dd7
	nonce = oauth_gen_nonce ();
Packit 4b6dd7
	g_get_current_time (&time_val);
Packit 4b6dd7
	timestamp = g_strdup_printf ("%li", time_val.tv_sec);
Packit 4b6dd7
Packit 4b6dd7
	if (parameters == NULL) {
Packit 4b6dd7
		parameters = g_hash_table_new (g_str_hash, g_str_equal);
Packit 4b6dd7
	} else {
Packit 4b6dd7
		g_hash_table_ref (parameters);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "oauth_signature_method", (gpointer) signature_method);
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "oauth_consumer_key", (gpointer) consumer_key);
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "oauth_nonce", nonce);
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "oauth_timestamp", timestamp);
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "oauth_version", (gpointer) "1.0");
Packit 4b6dd7
Packit 4b6dd7
	/* Only add the token if it's been provided */
Packit 4b6dd7
	if (token != NULL) {
Packit 4b6dd7
		g_hash_table_insert (parameters, (gpointer) "oauth_token", (gpointer) token);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	/* Sort the parameters and build a query string, as defined here: http://tools.ietf.org/html/rfc5849#section-3.4.1.3 */
Packit 4b6dd7
	g_hash_table_iter_init (&iter, parameters);
Packit 4b6dd7
Packit 4b6dd7
	while (g_hash_table_iter_next (&iter, (gpointer*) &key, (gpointer*) &value) == TRUE) {
Packit 4b6dd7
		GString *pair = g_string_new (NULL);
Packit 4b6dd7
Packit 4b6dd7
		g_string_append_uri_escaped (pair, key, NULL, FALSE);
Packit 4b6dd7
		g_string_append_c (pair, '=');
Packit 4b6dd7
		g_string_append_uri_escaped (pair, value, NULL, FALSE);
Packit 4b6dd7
Packit 4b6dd7
		/* Append the pair to the list for sorting, and keep track of the total length of the strings in the list so far */
Packit 4b6dd7
		params_length += pair->len + 1 /* sep */;
Packit 4b6dd7
		sorted_params = g_list_prepend (sorted_params, g_string_free (pair, FALSE));
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_hash_table_unref (parameters);
Packit 4b6dd7
Packit 4b6dd7
	sorted_params = g_list_sort (sorted_params, (GCompareFunc) g_strcmp0);
Packit 4b6dd7
Packit 4b6dd7
	/* Concatenate the parameters to give the query string */
Packit 4b6dd7
	query_string = g_string_sized_new (params_length);
Packit 4b6dd7
Packit 4b6dd7
	for (i = sorted_params; i != NULL; i = i->next) {
Packit 4b6dd7
		if (is_first == FALSE) {
Packit 4b6dd7
			g_string_append_c (query_string, '&';;
Packit 4b6dd7
		}
Packit 4b6dd7
Packit 4b6dd7
		g_string_append (query_string, i->data);
Packit 4b6dd7
Packit 4b6dd7
		g_free (i->data);
Packit 4b6dd7
		is_first = FALSE;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_list_free (sorted_params);
Packit 4b6dd7
Packit 4b6dd7
	/* Normalise the URI as described here: http://tools.ietf.org/html/rfc5849#section-3.4.1.2 */
Packit 4b6dd7
	normalised_uri = soup_uri_copy (soup_message_get_uri (message));
Packit 4b6dd7
	soup_uri_set_query (normalised_uri, NULL);
Packit 4b6dd7
	soup_uri_set_fragment (normalised_uri, NULL);
Packit 4b6dd7
Packit 4b6dd7
	/* Append it to the signature base string */
Packit 4b6dd7
	uri = soup_uri_to_string (normalised_uri, FALSE);
Packit 4b6dd7
Packit 4b6dd7
	/* Start building the signature base string as described here: http://tools.ietf.org/html/rfc5849#section-3.4.1.1 */
Packit 4b6dd7
	signature_base_string = g_string_sized_new (4 /* method */ + 1 /* sep */ + strlen (uri) + 1 /* sep */ + params_length /* query string */);
Packit 4b6dd7
	g_string_append_uri_escaped (signature_base_string, message->method, NULL, FALSE);
Packit 4b6dd7
	g_string_append_c (signature_base_string, '&';;
Packit 4b6dd7
	g_string_append_uri_escaped (signature_base_string, uri, NULL, FALSE);
Packit 4b6dd7
	g_string_append_c (signature_base_string, '&';;
Packit 4b6dd7
	g_string_append_uri_escaped (signature_base_string, query_string->str, NULL, FALSE);
Packit 4b6dd7
Packit 4b6dd7
	g_free (uri);
Packit 4b6dd7
	soup_uri_free (normalised_uri);
Packit 4b6dd7
	g_string_free (query_string, TRUE);
Packit 4b6dd7
Packit 4b6dd7
	/* Build the secret key to use in the HMAC */
Packit 4b6dd7
	secret_string = g_string_new (NULL);
Packit 4b6dd7
	g_string_append_uri_escaped (secret_string, consumer_secret, NULL, FALSE);
Packit 4b6dd7
	g_string_append_c (secret_string, '&';;
Packit 4b6dd7
Packit 4b6dd7
	/* Only add token_secret if it was provided */
Packit 4b6dd7
	if (token_secret != NULL) {
Packit 4b6dd7
		g_string_append_uri_escaped (secret_string, token_secret, NULL, FALSE);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	/* Create the signature as described here: http://tools.ietf.org/html/rfc5849#section-3.4.2 */
Packit 4b6dd7
	signature_hmac = g_hmac_new (G_CHECKSUM_SHA1, (const guchar*) secret_string->str, secret_string->len);
Packit 4b6dd7
	g_hmac_update (signature_hmac, (const guchar*) signature_base_string->str, signature_base_string->len);
Packit 4b6dd7
Packit 4b6dd7
	signature_buf_len = G_N_ELEMENTS (signature_buf);
Packit 4b6dd7
	g_hmac_get_digest (signature_hmac, signature_buf, &signature_buf_len);
Packit 4b6dd7
Packit 4b6dd7
	g_hmac_unref (signature_hmac);
Packit 4b6dd7
Packit 4b6dd7
	signature = g_base64_encode (signature_buf, signature_buf_len);
Packit 4b6dd7
Packit 4b6dd7
	/*g_debug ("Signing message using Signature Base String: “%s” and key “%s” using method “%s” to give signature: “%s”.",
Packit 4b6dd7
	         signature_base_string->str, secret_string->str, signature_method, signature);*/
Packit 4b6dd7
Packit 4b6dd7
	/* Zero out the secret_string before freeing it, to reduce the chance of secrets hitting disk. */
Packit 4b6dd7
	memset (secret_string->str, 0, secret_string->allocated_len);
Packit 4b6dd7
Packit 4b6dd7
	g_string_free (secret_string, TRUE);
Packit 4b6dd7
	g_string_free (signature_base_string, TRUE);
Packit 4b6dd7
Packit 4b6dd7
	/* Build the Authorization header and append it to the message */
Packit 4b6dd7
	authorization_header = g_string_new ("OAuth oauth_consumer_key=\"");
Packit 4b6dd7
	g_string_append_uri_escaped (authorization_header, consumer_key, NULL, FALSE);
Packit 4b6dd7
Packit 4b6dd7
	/* Only add the token if it's been provided */
Packit 4b6dd7
	if (token != NULL) {
Packit 4b6dd7
		g_string_append (authorization_header, "\",oauth_token=\"");
Packit 4b6dd7
		g_string_append_uri_escaped (authorization_header, token, NULL, FALSE);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_string_append (authorization_header, "\",oauth_signature_method=\"");
Packit 4b6dd7
	g_string_append_uri_escaped (authorization_header, signature_method, NULL, FALSE);
Packit 4b6dd7
	g_string_append (authorization_header, "\",oauth_signature=\"");
Packit 4b6dd7
	g_string_append_uri_escaped (authorization_header, signature, NULL, FALSE);
Packit 4b6dd7
	g_string_append (authorization_header, "\",oauth_timestamp=\"");
Packit 4b6dd7
	g_string_append_uri_escaped (authorization_header, timestamp, NULL, FALSE);
Packit 4b6dd7
	g_string_append (authorization_header, "\",oauth_nonce=\"");
Packit 4b6dd7
	g_string_append_uri_escaped (authorization_header, nonce, NULL, FALSE);
Packit 4b6dd7
	g_string_append (authorization_header, "\",oauth_version=\"1.0\"");
Packit 4b6dd7
Packit 4b6dd7
	soup_message_headers_replace (message->request_headers, "Authorization", authorization_header->str);
Packit 4b6dd7
Packit 4b6dd7
	g_string_free (authorization_header, TRUE);
Packit 4b6dd7
	free (signature);
Packit 4b6dd7
	g_free (timestamp);
Packit 4b6dd7
	free (nonce);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_new:
Packit 4b6dd7
 * @application_name: (allow-none): a human-readable, translated application name to use on authentication pages, or %NULL
Packit 4b6dd7
 * @service_type: the #GType of a #GDataService subclass which the #GDataOAuth1Authorizer will be used with
Packit 4b6dd7
 *
Packit 4b6dd7
 * Creates a new #GDataOAuth1Authorizer.
Packit 4b6dd7
 *
Packit 4b6dd7
 * The #GDataAuthorizationDomains for the given @service_type (i.e. as returned by gdata_service_get_authorization_domains()) are the ones the
Packit 4b6dd7
 * user will be requested to authorize access to on the page at the URI returned by gdata_oauth1_authorizer_request_authentication_uri().
Packit 4b6dd7
 *
Packit 4b6dd7
 * The given @application_name will set the value of #GDataOAuth1Authorizer:application-name and will be displayed to the user on authentication pages
Packit 4b6dd7
 * returned by Google. If %NULL is provided, the value of g_get_application_name() will be used as a fallback.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer full): a new #GDataOAuth1Authorizer; unref with g_object_unref()
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
GDataOAuth1Authorizer *
Packit 4b6dd7
gdata_oauth1_authorizer_new (const gchar *application_name, GType service_type)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (g_type_is_a (service_type, GDATA_TYPE_SERVICE), NULL);
Packit 4b6dd7
Packit 4b6dd7
	return gdata_oauth1_authorizer_new_for_authorization_domains (application_name, gdata_service_get_authorization_domains (service_type));
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_new_for_authorization_domains:
Packit 4b6dd7
 * @application_name: (allow-none): a human-readable, translated application name to use on authentication pages, or %NULL
Packit 4b6dd7
 * @authorization_domains: (element-type GDataAuthorizationDomain) (transfer none): a non-empty list of #GDataAuthorizationDomains to be
Packit 4b6dd7
 * authorized against by the #GDataOAuth1Authorizer
Packit 4b6dd7
 *
Packit 4b6dd7
 * Creates a new #GDataOAuth1Authorizer. This function is intended to be used only when the default authorization domain list for a single
Packit 4b6dd7
 * #GDataService, as used by gdata_oauth1_authorizer_new(), isn't suitable. For example, this could be because the #GDataOAuth1Authorizer will be used
Packit 4b6dd7
 * with multiple #GDataService subclasses, or because the client requires a specific set of authorization domains.
Packit 4b6dd7
 *
Packit 4b6dd7
 * The specified #GDataAuthorizationDomains are the ones the user will be requested to authorize access to on the page at the URI returned by
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authentication_uri().
Packit 4b6dd7
 *
Packit 4b6dd7
 * The given @application_name will set the value of #GDataOAuth1Authorizer:application-name and will be displayed to the user on authentication pages
Packit 4b6dd7
 * returned by Google. If %NULL is provided, the value of g_get_application_name() will be used as a fallback.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer full): a new #GDataOAuth1Authorizer; unref with g_object_unref()
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
GDataOAuth1Authorizer *
Packit 4b6dd7
gdata_oauth1_authorizer_new_for_authorization_domains (const gchar *application_name, GList *authorization_domains)
Packit 4b6dd7
{
Packit 4b6dd7
	GList *i;
Packit 4b6dd7
	GDataOAuth1Authorizer *authorizer;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (authorization_domains != NULL, NULL);
Packit 4b6dd7
Packit 4b6dd7
	authorizer = GDATA_OAUTH1_AUTHORIZER (g_object_new (GDATA_TYPE_OAUTH1_AUTHORIZER,
Packit 4b6dd7
	                                                    "application-name", application_name,
Packit 4b6dd7
	                                                    NULL));
Packit 4b6dd7
Packit 4b6dd7
	/* Register all the domains with the authorizer */
Packit 4b6dd7
	for (i = authorization_domains; i != NULL; i = i->next) {
Packit 4b6dd7
		g_return_val_if_fail (GDATA_IS_AUTHORIZATION_DOMAIN (i->data), NULL);
Packit 4b6dd7
Packit 4b6dd7
		/* We don't have to lock the authoriser's mutex here as no other code has seen the authoriser yet */
Packit 4b6dd7
		g_hash_table_insert (authorizer->priv->authorization_domains, g_object_ref (GDATA_AUTHORIZATION_DOMAIN (i->data)), i->data);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	return authorizer;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authentication_uri:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @token: (out callee-allocates): return location for the temporary credentials token returned by the authentication service; free with g_free()
Packit 4b6dd7
 * @token_secret: (out callee-allocates): return location for the temporary credentials token secret returned by the authentication service; free with
Packit 4b6dd7
 * g_free()
Packit 4b6dd7
 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
Packit 4b6dd7
 * @error: a #GError, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Requests a fresh unauthenticated token from the Google accounts service and builds and returns the URI of an authentication page for that token.
Packit 4b6dd7
 * This should then be presented to the user (e.g. in an embedded or stand alone web browser). The authentication page will ask the user to log in
Packit 4b6dd7
 * using their Google account, then ask them to grant access to the #GDataAuthorizationDomains passed to the constructor of the
Packit 4b6dd7
 * #GDataOAuth1Authorizer. If the user grants access, they will be given a verifier, which can then be passed to
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization() (along with the @token and @token_secret values returned by this method) to authorize the token.
Packit 4b6dd7
 *
Packit 4b6dd7
 * This method can fail if the server returns an error, but this is unlikely. If it does happen, a %GDATA_SERVICE_ERROR_PROTOCOL_ERROR will be
Packit 4b6dd7
 * raised, @token and @token_secret will be set to %NULL and %NULL will be returned.
Packit 4b6dd7
 *
Packit 4b6dd7
 * This method implements <ulink type="http" url="http://tools.ietf.org/html/rfc5849#section-2.1">Section 2.1</ulink> and
Packit 4b6dd7
 * <ulink type="http" url="http://tools.ietf.org/html/rfc5849#section-2.2">Section 2.2</ulink> of the
Packit 4b6dd7
 * <ulink type="http" url="http://tools.ietf.org/html/rfc5849">OAuth 1.0 protocol</ulink>.
Packit 4b6dd7
 *
Packit 4b6dd7
 * When freeing @token_secret, it's advisable to set it to all zeros first, to reduce the chance of the sensitive token being recoverable from the
Packit 4b6dd7
 * free memory pool and (accidentally) leaked by a different part of the process. This can be achieved with the following code:
Packit 4b6dd7
 * |[
Packit 4b6dd7
 *	if (token_secret != NULL) {
Packit 4b6dd7
 *		memset (token_secret, 0, strlen (token_secret));
Packit 4b6dd7
 *		g_free (token_secret);
Packit 4b6dd7
 *	}
Packit 4b6dd7
 * ]|
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer full): the URI of an authentication page for the user to use; free with g_free()
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
gchar *
Packit 4b6dd7
gdata_oauth1_authorizer_request_authentication_uri (GDataOAuth1Authorizer *self, gchar **token, gchar **token_secret,
Packit 4b6dd7
                                                    GCancellable *cancellable, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1AuthorizerPrivate *priv;
Packit 4b6dd7
	SoupMessage *message;
Packit 4b6dd7
	guint status;
Packit 4b6dd7
	gchar *request_body;
Packit 4b6dd7
	GString *scope_string, *authentication_uri;
Packit 4b6dd7
	GHashTable *parameters;
Packit 4b6dd7
	GHashTableIter iter;
Packit 4b6dd7
	gboolean is_first = TRUE;
Packit 4b6dd7
	GDataAuthorizationDomain *domain;
Packit 4b6dd7
	GHashTable *response_details;
Packit 4b6dd7
	const gchar *callback_uri, *_token, *_token_secret, *callback_confirmed;
Packit 4b6dd7
	SoupURI *_uri;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
Packit 4b6dd7
	g_return_val_if_fail (token != NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (token_secret != NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
Packit 4b6dd7
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit 4b6dd7
Packit 4b6dd7
	priv = self->priv;
Packit 4b6dd7
Packit 4b6dd7
	/* This implements OAuthGetRequestToken and returns the URI for OAuthAuthorizeToken, which the client must then use themselves (e.g. in an
Packit 4b6dd7
	 * embedded web browser) to authorise the temporary credentials token. They then pass the request token and verification code they get back
Packit 4b6dd7
	 * from that to gdata_oauth1_authorizer_request_authorization(). */
Packit 4b6dd7
Packit 4b6dd7
	/* We default to out-of-band callbacks */
Packit 4b6dd7
	callback_uri = "oob";
Packit 4b6dd7
Packit 4b6dd7
	/* Set the output parameters to NULL in case of failure */
Packit 4b6dd7
	*token = NULL;
Packit 4b6dd7
	*token_secret = NULL;
Packit 4b6dd7
Packit 4b6dd7
	/* Build up the space-separated list of scopes we're requesting authorisation for */
Packit 4b6dd7
	g_mutex_lock (&(priv->mutex));
Packit 4b6dd7
Packit 4b6dd7
	scope_string = g_string_new (NULL);
Packit 4b6dd7
	g_hash_table_iter_init (&iter, priv->authorization_domains);
Packit 4b6dd7
Packit 4b6dd7
	while (g_hash_table_iter_next (&iter, (gpointer*) &domain, NULL) == TRUE) {
Packit 4b6dd7
		if (is_first == FALSE) {
Packit 4b6dd7
			/* Delimiter */
Packit 4b6dd7
			g_string_append_c (scope_string, ' ');
Packit 4b6dd7
		}
Packit 4b6dd7
Packit 4b6dd7
		g_string_append (scope_string, gdata_authorization_domain_get_scope (domain));
Packit 4b6dd7
Packit 4b6dd7
		is_first = FALSE;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_mutex_unlock (&(priv->mutex));
Packit 4b6dd7
Packit 4b6dd7
	/* Build the request body and the set of parameters to be signed */
Packit 4b6dd7
	parameters = g_hash_table_new (g_str_hash, g_str_equal);
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "scope", scope_string->str);
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "xoauth_displayname", priv->application_name);
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "oauth_callback", (gpointer) callback_uri);
Packit 4b6dd7
	request_body = soup_form_encode_hash (parameters);
Packit 4b6dd7
Packit 4b6dd7
	/* Build the message */
Packit 4b6dd7
	_uri = soup_uri_new ("https://www.google.com/accounts/OAuthGetRequestToken");
Packit 4b6dd7
	soup_uri_set_port (_uri, _gdata_service_get_https_port ());
Packit 4b6dd7
	message = soup_message_new_from_uri (SOUP_METHOD_POST, _uri);
Packit 4b6dd7
	soup_uri_free (_uri);
Packit 4b6dd7
Packit 4b6dd7
	soup_message_set_request (message, "application/x-www-form-urlencoded", SOUP_MEMORY_TAKE, request_body, strlen (request_body));
Packit 4b6dd7
Packit 4b6dd7
	sign_message (self, message, NULL, NULL, parameters);
Packit 4b6dd7
Packit 4b6dd7
	g_hash_table_destroy (parameters);
Packit 4b6dd7
	g_string_free (scope_string, TRUE);
Packit 4b6dd7
Packit 4b6dd7
	/* Send the message */
Packit 4b6dd7
	_gdata_service_actually_send_message (priv->session, message, cancellable, error);
Packit 4b6dd7
	status = message->status_code;
Packit 4b6dd7
Packit 4b6dd7
	if (status == SOUP_STATUS_CANCELLED) {
Packit 4b6dd7
		/* Cancelled (the error has already been set) */
Packit 4b6dd7
		g_object_unref (message);
Packit 4b6dd7
		return NULL;
Packit 4b6dd7
	} else if (status != SOUP_STATUS_OK) {
Packit 4b6dd7
		/* Server returned an error. Not much we can do, since the error codes aren't documented and it shouldn't normally ever happen
Packit 4b6dd7
		 * anyway. */
Packit 4b6dd7
		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
Packit 4b6dd7
		                     _("The server rejected the temporary credentials request."));
Packit 4b6dd7
		g_object_unref (message);
Packit 4b6dd7
Packit 4b6dd7
		return NULL;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_assert (message->response_body->data != NULL);
Packit 4b6dd7
Packit 4b6dd7
	/* Parse the response. We expect something like:
Packit 4b6dd7
	 *   oauth_token=ab3cd9j4ks73hf7g&oauth_token_secret=ZXhhbXBsZS5jb20&oauth_callback_confirmed=true
Packit 4b6dd7
	 * See: http://code.google.com/apis/accounts/docs/OAuth_ref.html#RequestToken and
Packit 4b6dd7
	 * http://tools.ietf.org/html/rfc5849#section-2.1 for details. */
Packit 4b6dd7
	response_details = soup_form_decode (message->response_body->data);
Packit 4b6dd7
Packit 4b6dd7
	g_object_unref (message);
Packit 4b6dd7
Packit 4b6dd7
	_token = g_hash_table_lookup (response_details, "oauth_token");
Packit 4b6dd7
	_token_secret = g_hash_table_lookup (response_details, "oauth_token_secret");
Packit 4b6dd7
	callback_confirmed = g_hash_table_lookup (response_details, "oauth_callback_confirmed");
Packit 4b6dd7
Packit 4b6dd7
	/* Validate the returned values */
Packit 4b6dd7
	if (_token == NULL || _token_secret == NULL || callback_confirmed == NULL ||
Packit 4b6dd7
	    *_token == '\0' || *_token_secret == '\0' ||
Packit 4b6dd7
	    strcmp (callback_confirmed, "true") != 0) {
Packit 4b6dd7
		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
Packit 4b6dd7
		                     _("The server returned a malformed response."));
Packit 4b6dd7
		g_hash_table_destroy (response_details);
Packit 4b6dd7
Packit 4b6dd7
		return NULL;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	/* Build the authentication URI which the user will then open in a web browser and use to authenticate and authorise our application.
Packit 4b6dd7
	 * We expect to build something like this:
Packit 4b6dd7
	 *   https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=ab3cd9j4ks73hf7g&hd=mycollege.edu&hl=en&btmpl=mobile
Packit 4b6dd7
	 * See: http://code.google.com/apis/accounts/docs/OAuth_ref.html#GetAuth for more details. */
Packit 4b6dd7
	authentication_uri = g_string_new ("https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token=");
Packit 4b6dd7
	g_string_append_uri_escaped (authentication_uri, g_hash_table_lookup (response_details, "oauth_token"), NULL, TRUE);
Packit 4b6dd7
Packit 4b6dd7
	if (priv->locale != NULL) {
Packit 4b6dd7
		g_string_append (authentication_uri, "&hl=");
Packit 4b6dd7
		g_string_append_uri_escaped (authentication_uri, priv->locale, NULL, TRUE);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	/* Return the token and token secret */
Packit 4b6dd7
	*token = g_strdup (_token);
Packit 4b6dd7
	*token_secret = g_strdup (_token_secret); /* NOTE: Ideally this would be allocated in non-pageable memory, but changing that would break API */
Packit 4b6dd7
Packit 4b6dd7
	g_hash_table_destroy (response_details);
Packit 4b6dd7
Packit 4b6dd7
	return g_string_free (authentication_uri, FALSE);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
typedef struct {
Packit 4b6dd7
	/* All return values */
Packit 4b6dd7
	gchar *token;
Packit 4b6dd7
	gchar *token_secret; /* NOTE: Ideally this would be allocated in non-pageable memory, but changing that would break API */
Packit 4b6dd7
	gchar *authentication_uri;
Packit 4b6dd7
} RequestAuthenticationUriAsyncData;
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
request_authentication_uri_async_data_free (RequestAuthenticationUriAsyncData *data)
Packit 4b6dd7
{
Packit 4b6dd7
	g_free (data->token);
Packit 4b6dd7
	g_free (data->token_secret);
Packit 4b6dd7
	g_free (data->authentication_uri);
Packit 4b6dd7
Packit 4b6dd7
	g_slice_free (RequestAuthenticationUriAsyncData, data);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
G_DEFINE_AUTOPTR_CLEANUP_FUNC (RequestAuthenticationUriAsyncData, request_authentication_uri_async_data_free)
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
request_authentication_uri_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1Authorizer *authorizer = GDATA_OAUTH1_AUTHORIZER (source_object);
Packit 4b6dd7
	g_autoptr(RequestAuthenticationUriAsyncData) data = NULL;
Packit 4b6dd7
	g_autoptr(GError) error = NULL;
Packit 4b6dd7
Packit 4b6dd7
	data = g_slice_new0 (RequestAuthenticationUriAsyncData);
Packit 4b6dd7
	data->authentication_uri = gdata_oauth1_authorizer_request_authentication_uri (authorizer, &(data->token), &(data->token_secret),
Packit 4b6dd7
	                                                                               cancellable, &error);
Packit 4b6dd7
Packit 4b6dd7
	if (error != NULL)
Packit 4b6dd7
		g_task_return_error (task, g_steal_pointer (&error));
Packit 4b6dd7
	else
Packit 4b6dd7
		g_task_return_pointer (task, g_steal_pointer (&data), (GDestroyNotify) request_authentication_uri_async_data_free);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authentication_uri_async:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
Packit 4b6dd7
 * @callback: a #GAsyncReadyCallback to call when building the URI is finished
Packit 4b6dd7
 * @user_data: (closure): data to pass to the @callback function
Packit 4b6dd7
 *
Packit 4b6dd7
 * Requests a fresh unauthenticated token from the Google accounts service and builds and returns the URI of an authentication page for that token.
Packit 4b6dd7
 * @self is reffed when this method is called, so can safely be unreffed after this method returns.
Packit 4b6dd7
 *
Packit 4b6dd7
 * For more details, see gdata_oauth1_authorizer_request_authentication_uri(), which is the synchronous version of this method.
Packit 4b6dd7
 *
Packit 4b6dd7
 * When the operation is finished, @callback will be called. You can then call gdata_oauth1_authorizer_request_authentication_uri_finish() to get the
Packit 4b6dd7
 * results of the operation.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
void
Packit 4b6dd7
gdata_oauth1_authorizer_request_authentication_uri_async (GDataOAuth1Authorizer *self, GCancellable *cancellable,
Packit 4b6dd7
                                                          GAsyncReadyCallback callback, gpointer user_data)
Packit 4b6dd7
{
Packit 4b6dd7
	g_autoptr(GTask) task = NULL;
Packit 4b6dd7
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
Packit 4b6dd7
	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
Packit 4b6dd7
	g_return_if_fail (callback != NULL);
Packit 4b6dd7
Packit 4b6dd7
	task = g_task_new (self, cancellable, callback, user_data);
Packit 4b6dd7
	g_task_set_source_tag (task, gdata_oauth1_authorizer_request_authentication_uri_async);
Packit 4b6dd7
	g_task_run_in_thread (task, request_authentication_uri_thread);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authentication_uri_finish:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @async_result: a #GAsyncResult
Packit 4b6dd7
 * @token: (out callee-allocates): return location for the temporary credentials token returned by the authentication service; free with g_free()
Packit 4b6dd7
 * @token_secret: (out callee-allocates): return location for the temporary credentials token secret returned by the authentication service; free with
Packit 4b6dd7
 * g_free()
Packit 4b6dd7
 * @error: a #GError, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Finishes an asynchronous authentication URI building operation started with gdata_oauth1_authorizer_request_authentication_uri_async().
Packit 4b6dd7
 *
Packit 4b6dd7
 * This method can fail if the server has returned an error, but this is unlikely. If it does happen, a %GDATA_SERVICE_ERROR_PROTOCOL_ERROR will be
Packit 4b6dd7
 * raised, @token and @token_secret will be set to %NULL and %NULL will be returned.
Packit 4b6dd7
 *
Packit 4b6dd7
 * When freeing @token_secret, it's advisable to set it to all zeros first, to reduce the chance of the sensitive token being recoverable from the
Packit 4b6dd7
 * free memory pool and (accidentally) leaked by a different part of the process. This can be achieved with the following code:
Packit 4b6dd7
 * |[
Packit 4b6dd7
 *	if (token_secret != NULL) {
Packit 4b6dd7
 *		memset (token_secret, 0, strlen (token_secret));
Packit 4b6dd7
 *		g_free (token_secret);
Packit 4b6dd7
 *	}
Packit 4b6dd7
 * ]|
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer full): the URI of an authentication page for the user to use; free with g_free()
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
gchar *
Packit 4b6dd7
gdata_oauth1_authorizer_request_authentication_uri_finish (GDataOAuth1Authorizer *self, GAsyncResult *async_result, gchar **token,
Packit 4b6dd7
                                                           gchar **token_secret, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	g_autoptr(RequestAuthenticationUriAsyncData) data = NULL;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
Packit 4b6dd7
	g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), NULL);
Packit 4b6dd7
	g_return_val_if_fail (token != NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (token_secret != NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit 4b6dd7
	g_return_val_if_fail (g_task_is_valid (async_result, self), NULL);
Packit 4b6dd7
	g_return_val_if_fail (g_async_result_is_tagged (async_result, gdata_oauth1_authorizer_request_authentication_uri_async), NULL);
Packit 4b6dd7
Packit 4b6dd7
	data = g_task_propagate_pointer (G_TASK (async_result), error);
Packit 4b6dd7
Packit 4b6dd7
	if (data == NULL) {
Packit 4b6dd7
		/* Return the error and set all of the output parameters to NULL */
Packit 4b6dd7
		*token = NULL;
Packit 4b6dd7
		*token_secret = NULL;
Packit 4b6dd7
Packit 4b6dd7
		return NULL;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	/* Success! Transfer the output to the appropriate parameters and nullify it so it doesn't get freed when the async result gets finalised */
Packit 4b6dd7
	*token = g_steal_pointer (&data->token);
Packit 4b6dd7
	*token_secret = g_steal_pointer (&data->token_secret);
Packit 4b6dd7
Packit 4b6dd7
	return g_steal_pointer (&data->authentication_uri);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @token: the request token returned by gdata_oauth1_authorizer_request_authentication_uri()
Packit 4b6dd7
 * @token_secret: the request token secret returned by gdata_oauth1_authorizer_request_authentication_uri()
Packit 4b6dd7
 * @verifier: the verifier entered by the user from the authentication page
Packit 4b6dd7
 * @cancellable: (allow-none): optional #GCancellable object, or %NULL
Packit 4b6dd7
 * @error: a #GError, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Requests authorization of the given request @token from the Google accounts service using the given @verifier as entered by the user from the
Packit 4b6dd7
 * authentication page at the URI returned by gdata_oauth1_authorizer_request_authentication_uri(). @token and @token_secret must be the same values
Packit 4b6dd7
 * as were returned by gdata_oauth1_authorizer_request_authentication_uri() if it was successful.
Packit 4b6dd7
 *
Packit 4b6dd7
 * If the verifier is valid (i.e. the user granted access to the application and the Google accounts service has no reason to distrust the client),
Packit 4b6dd7
 * %TRUE will be returned and any operations performed from that point onwards on #GDataServices using this #GDataAuthorizer will be
Packit 4b6dd7
 * authorized.
Packit 4b6dd7
 *
Packit 4b6dd7
 * If the user denies access to the application or the Google accounts service distrusts it, a bogus verifier could be returned. In this case, %FALSE
Packit 4b6dd7
 * will be returned and a %GDATA_SERVICE_ERROR_FORBIDDEN error will be raised.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Note that if the user denies access to the application, it may be the case that they have no verifier to enter. In this case, the client can simply
Packit 4b6dd7
 * not call this method. The #GDataOAuth1Authorizer stores no state for authentication operations which have succeeded in calling
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authentication_uri() but not yet successfully called gdata_oauth1_authorizer_request_authorization().
Packit 4b6dd7
 *
Packit 4b6dd7
 * This method implements <ulink type="http" url="http://tools.ietf.org/html/rfc5849#section-2.3">Section 2.3</ulink> of the
Packit 4b6dd7
 * <ulink type="http" url="http://tools.ietf.org/html/rfc5849">OAuth 1.0 protocol</ulink>.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: %TRUE if authorization was successful, %FALSE otherwise
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
gboolean
Packit 4b6dd7
gdata_oauth1_authorizer_request_authorization (GDataOAuth1Authorizer *self, const gchar *token, const gchar *token_secret, const gchar *verifier,
Packit 4b6dd7
                                               GCancellable *cancellable, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1AuthorizerPrivate *priv;
Packit 4b6dd7
	SoupMessage *message;
Packit 4b6dd7
	guint status;
Packit 4b6dd7
	gchar *request_body;
Packit 4b6dd7
	GHashTable *parameters;
Packit 4b6dd7
	GHashTable *response_details;
Packit 4b6dd7
	const gchar *_token, *_token_secret;
Packit 4b6dd7
	SoupURI *_uri;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), FALSE);
Packit 4b6dd7
	g_return_val_if_fail (token != NULL && *token != '\0', FALSE);
Packit 4b6dd7
	g_return_val_if_fail (token_secret != NULL && *token_secret != '\0', FALSE);
Packit 4b6dd7
	g_return_val_if_fail (verifier != NULL && *verifier != '\0', FALSE);
Packit 4b6dd7
	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
Packit 4b6dd7
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit 4b6dd7
Packit 4b6dd7
	/* This implements OAuthGetAccessToken using the request token returned by OAuthGetRequestToken and the verification code returned by
Packit 4b6dd7
	 * OAuthAuthorizeToken. See:
Packit 4b6dd7
	 *  • http://code.google.com/apis/accounts/docs/OAuth_ref.html#AccessToken
Packit 4b6dd7
	 *  • http://tools.ietf.org/html/rfc5849#section-2.3
Packit 4b6dd7
	 */
Packit 4b6dd7
Packit 4b6dd7
	priv = self->priv;
Packit 4b6dd7
Packit 4b6dd7
	/* Build the request body and the set of parameters to be signed */
Packit 4b6dd7
	parameters = g_hash_table_new (g_str_hash, g_str_equal);
Packit 4b6dd7
	g_hash_table_insert (parameters, (gpointer) "oauth_verifier", (gpointer) verifier);
Packit 4b6dd7
	request_body = soup_form_encode_hash (parameters);
Packit 4b6dd7
Packit 4b6dd7
	/* Build the message */
Packit 4b6dd7
	_uri = soup_uri_new ("https://www.google.com/accounts/OAuthGetAccessToken");
Packit 4b6dd7
	soup_uri_set_port (_uri, _gdata_service_get_https_port ());
Packit 4b6dd7
	message = soup_message_new_from_uri (SOUP_METHOD_POST, _uri);
Packit 4b6dd7
	soup_uri_free (_uri);
Packit 4b6dd7
	soup_message_set_request (message, "application/x-www-form-urlencoded", SOUP_MEMORY_TAKE, request_body, strlen (request_body));
Packit 4b6dd7
Packit 4b6dd7
	sign_message (self, message, token, token_secret, parameters);
Packit 4b6dd7
Packit 4b6dd7
	g_hash_table_destroy (parameters);
Packit 4b6dd7
Packit 4b6dd7
	/* Send the message */
Packit 4b6dd7
	_gdata_service_actually_send_message (priv->session, message, cancellable, error);
Packit 4b6dd7
	status = message->status_code;
Packit 4b6dd7
Packit 4b6dd7
	if (status == SOUP_STATUS_CANCELLED) {
Packit 4b6dd7
		/* Cancelled (the error has already been set) */
Packit 4b6dd7
		g_object_unref (message);
Packit 4b6dd7
		return FALSE;
Packit 4b6dd7
	} else if (status != SOUP_STATUS_OK) {
Packit 4b6dd7
		/* Server returned an error. This either means that there was a server error or, more likely, the server doesn't trust the client
Packit 4b6dd7
		 * or the user denied authorization to the token on the authorization web page. */
Packit 4b6dd7
		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_FORBIDDEN, _("Access was denied by the user or server."));
Packit 4b6dd7
		g_object_unref (message);
Packit 4b6dd7
Packit 4b6dd7
		return FALSE;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_assert (message->response_body->data != NULL);
Packit 4b6dd7
Packit 4b6dd7
	/* Parse the response. We expect something like:
Packit 4b6dd7
	 *   oauth_token=ab3cd9j4ks73hf7g&oauth_token_secret=ZXhhbXBsZS5jb20&oauth_callback_confirmed=true
Packit 4b6dd7
	 * See: http://code.google.com/apis/accounts/docs/OAuth_ref.html#AccessToken and
Packit 4b6dd7
	 * http://tools.ietf.org/html/rfc5849#section-2.3 for details. */
Packit 4b6dd7
	response_details = soup_form_decode (message->response_body->data);
Packit 4b6dd7
Packit 4b6dd7
	/* Zero out the response body to lower the chance of it (with all the auth. tokens it contains) hitting disk or getting leaked in
Packit 4b6dd7
	 * free memory. */
Packit 4b6dd7
	memset ((void*) message->response_body->data, 0, message->response_body->length);
Packit 4b6dd7
Packit 4b6dd7
	g_object_unref (message);
Packit 4b6dd7
Packit 4b6dd7
	_token = g_hash_table_lookup (response_details, "oauth_token");
Packit 4b6dd7
	_token_secret = g_hash_table_lookup (response_details, "oauth_token_secret");
Packit 4b6dd7
Packit 4b6dd7
	/* Validate the returned values */
Packit 4b6dd7
	if (_token == NULL || _token_secret == NULL ||
Packit 4b6dd7
	    *_token == '\0' || *_token_secret == '\0') {
Packit 4b6dd7
		g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR, _("The server returned a malformed response."));
Packit 4b6dd7
		g_hash_table_destroy (response_details);
Packit 4b6dd7
Packit 4b6dd7
		return FALSE;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	/* Store the token and token secret in the authoriser */
Packit 4b6dd7
	g_mutex_lock (&(priv->mutex));
Packit 4b6dd7
Packit 4b6dd7
	g_free (priv->token);
Packit 4b6dd7
	priv->token = g_strdup (_token);
Packit 4b6dd7
Packit 4b6dd7
	_gdata_service_secure_strfree (priv->token_secret);
Packit 4b6dd7
	priv->token_secret = _gdata_service_secure_strdup (_token_secret);
Packit 4b6dd7
Packit 4b6dd7
	g_mutex_unlock (&(priv->mutex));
Packit 4b6dd7
Packit 4b6dd7
	/* Zero out the secret token before freeing the hash table, to reduce the chance of it hitting disk later. */
Packit 4b6dd7
	memset ((void*) _token_secret, 0, strlen (_token_secret));
Packit 4b6dd7
Packit 4b6dd7
	g_hash_table_destroy (response_details);
Packit 4b6dd7
Packit 4b6dd7
	return TRUE;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
typedef struct {
Packit 4b6dd7
	/* Input */
Packit 4b6dd7
	gchar *token;
Packit 4b6dd7
	GDataSecureString token_secret; /* must be allocated by _gdata_service_secure_strdup() */
Packit 4b6dd7
	gchar *verifier;
Packit 4b6dd7
} RequestAuthorizationAsyncData;
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
request_authorization_async_data_free (RequestAuthorizationAsyncData *data)
Packit 4b6dd7
{
Packit 4b6dd7
	g_free (data->token);
Packit 4b6dd7
	_gdata_service_secure_strfree (data->token_secret);
Packit 4b6dd7
	g_free (data->verifier);
Packit 4b6dd7
Packit 4b6dd7
	g_slice_free (RequestAuthorizationAsyncData, data);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
request_authorization_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
Packit 4b6dd7
{
Packit 4b6dd7
	GDataOAuth1Authorizer *authorizer = GDATA_OAUTH1_AUTHORIZER (source_object);
Packit 4b6dd7
	RequestAuthorizationAsyncData *data = task_data;
Packit 4b6dd7
	g_autoptr(GError) error = NULL;
Packit 4b6dd7
Packit 4b6dd7
	if (!gdata_oauth1_authorizer_request_authorization (authorizer, data->token, data->token_secret, data->verifier, cancellable, &error))
Packit 4b6dd7
		g_task_return_error (task, g_steal_pointer (&error));
Packit 4b6dd7
	else
Packit 4b6dd7
		g_task_return_boolean (task, TRUE);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization_async:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @token: the request token returned by gdata_oauth1_authorizer_request_authentication_uri()
Packit 4b6dd7
 * @token_secret: the request token secret returned by gdata_oauth1_authorizer_request_authentication_uri()
Packit 4b6dd7
 * @verifier: the verifier entered by the user from the authentication page
Packit 4b6dd7
 * @cancellable: (allow-none): an optional #GCancellable, or %NULL
Packit 4b6dd7
 * @callback: a #GAsyncReadyCallback to call when authorization is finished
Packit 4b6dd7
 * @user_data: (closure): data to pass to the @callback function
Packit 4b6dd7
 *
Packit 4b6dd7
 * Requests authorization of the given request @token from the Google accounts service using the given @verifier as entered by the user.
Packit 4b6dd7
 * @self, @token, @token_secret and @verifier are reffed/copied when this method is called, so can safely be freed after this method returns.
Packit 4b6dd7
 *
Packit 4b6dd7
 * For more details, see gdata_oauth1_authorizer_request_authorization(), which is the synchronous version of this method.
Packit 4b6dd7
 *
Packit 4b6dd7
 * When the operation is finished, @callback will be called. You can then call gdata_oauth1_authorizer_request_authorization_finish() to get the
Packit 4b6dd7
 * results of the operation.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
void
Packit 4b6dd7
gdata_oauth1_authorizer_request_authorization_async (GDataOAuth1Authorizer *self, const gchar *token, const gchar *token_secret,
Packit 4b6dd7
                                                     const gchar *verifier,
Packit 4b6dd7
                                                     GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
Packit 4b6dd7
{
Packit 4b6dd7
	g_autoptr(GTask) task = NULL;
Packit 4b6dd7
	RequestAuthorizationAsyncData *data;
Packit 4b6dd7
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
Packit 4b6dd7
	g_return_if_fail (token != NULL && *token != '\0');
Packit 4b6dd7
	g_return_if_fail (token_secret != NULL && *token_secret != '\0');
Packit 4b6dd7
	g_return_if_fail (verifier != NULL && *verifier != '\0');
Packit 4b6dd7
	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
Packit 4b6dd7
Packit 4b6dd7
	data = g_slice_new (RequestAuthorizationAsyncData);
Packit 4b6dd7
	data->token = g_strdup (token);
Packit 4b6dd7
	data->token_secret = _gdata_service_secure_strdup (token_secret);
Packit 4b6dd7
	data->verifier = g_strdup (verifier);
Packit 4b6dd7
Packit 4b6dd7
	task = g_task_new (self, cancellable, callback, user_data);
Packit 4b6dd7
	g_task_set_source_tag (task, gdata_oauth1_authorizer_request_authorization_async);
Packit 4b6dd7
	g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) request_authorization_async_data_free);
Packit 4b6dd7
	g_task_run_in_thread (task, request_authorization_thread);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authorization_finish:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @async_result: a #GAsyncResult
Packit 4b6dd7
 * @error: a #GError, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Finishes an asynchronous authorization operation started with gdata_oauth1_authorizer_request_authorization_async().
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: %TRUE if authorization was successful, %FALSE otherwise
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
gboolean
Packit 4b6dd7
gdata_oauth1_authorizer_request_authorization_finish (GDataOAuth1Authorizer *self, GAsyncResult *async_result, GError **error)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), FALSE);
Packit 4b6dd7
	g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), FALSE);
Packit 4b6dd7
	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
Packit 4b6dd7
	g_return_val_if_fail (g_task_is_valid (async_result, self), FALSE);
Packit 4b6dd7
	g_return_val_if_fail (g_async_result_is_tagged (async_result, gdata_oauth1_authorizer_request_authorization_async), FALSE);
Packit 4b6dd7
Packit 4b6dd7
	return g_task_propagate_boolean (G_TASK (async_result), error);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_get_application_name:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the application name being used on the authentication page at the URI returned by gdata_oauth1_authorizer_request_authentication_uri();
Packit 4b6dd7
 * i.e. the value of #GDataOAuth1Authorizer:application-name.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (allow-none): the application name, or %NULL if one isn't set
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_oauth1_authorizer_get_application_name (GDataOAuth1Authorizer *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
Packit 4b6dd7
	return self->priv->application_name;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_get_locale:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 *
Packit 4b6dd7
 * Returns the locale currently being used for network requests, or %NULL if the locale is the default.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (allow-none): the current locale
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
const gchar *
Packit 4b6dd7
gdata_oauth1_authorizer_get_locale (GDataOAuth1Authorizer *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
Packit 4b6dd7
	return self->priv->locale;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_set_locale:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @locale: (allow-none): the new locale in Unix locale format, or %NULL for the default locale
Packit 4b6dd7
 *
Packit 4b6dd7
 * Set the locale used for network requests to @locale, given in standard Unix locale format. See #GDataOAuth1Authorizer:locale for more details.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Note that while it's possible to change the locale after sending network requests (i.e. calling
Packit 4b6dd7
 * gdata_oauth1_authorizer_request_authentication_uri() for the first time), it is unsupported, as the server-side software may behave unexpectedly.
Packit 4b6dd7
 * The only supported use of this method is after creation of the authorizer, but before any network requests are made.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
void
Packit 4b6dd7
gdata_oauth1_authorizer_set_locale (GDataOAuth1Authorizer *self, const gchar *locale)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
Packit 4b6dd7
Packit 4b6dd7
	if (g_strcmp0 (locale, self->priv->locale) == 0) {
Packit 4b6dd7
		/* Already has this value */
Packit 4b6dd7
		return;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_free (self->priv->locale);
Packit 4b6dd7
	self->priv->locale = g_strdup (locale);
Packit 4b6dd7
	g_object_notify (G_OBJECT (self), "locale");
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
notify_proxy_uri_cb (GObject *gobject, GParamSpec *pspec, GDataOAuth1Authorizer *self)
Packit 4b6dd7
{
Packit 4b6dd7
	/* Flush our cached version */
Packit 4b6dd7
	if (self->priv->proxy_uri != NULL) {
Packit 4b6dd7
		soup_uri_free (self->priv->proxy_uri);
Packit 4b6dd7
		self->priv->proxy_uri = NULL;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_object_notify (G_OBJECT (self), "proxy-uri");
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/* Static function which isn't deprecated so we can continue using it internally. */
Packit 4b6dd7
static SoupURI *
Packit 4b6dd7
_get_proxy_uri (GDataOAuth1Authorizer *self)
Packit 4b6dd7
{
Packit 4b6dd7
	SoupURI *proxy_uri;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
Packit 4b6dd7
Packit 4b6dd7
	/* If we have a cached version, return that */
Packit 4b6dd7
	if (self->priv->proxy_uri != NULL) {
Packit 4b6dd7
		return self->priv->proxy_uri;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_object_get (self->priv->session, SOUP_SESSION_PROXY_URI, &proxy_uri, NULL);
Packit 4b6dd7
Packit 4b6dd7
	/* Update the cache; it takes ownership of the URI */
Packit 4b6dd7
	self->priv->proxy_uri = proxy_uri;
Packit 4b6dd7
Packit 4b6dd7
	return proxy_uri;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_get_proxy_uri:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 *
Packit 4b6dd7
 * Gets the proxy URI on the #GDataOAuth1Authorizer's #SoupSession.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer full) (allow-none): the proxy URI, or %NULL; free with soup_uri_free()
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 * Deprecated: 0.15.0: Use gdata_oauth1_authorizer_get_proxy_resolver() instead, which gives more flexibility over the proxy used.
Packit 4b6dd7
 */
Packit 4b6dd7
SoupURI *
Packit 4b6dd7
gdata_oauth1_authorizer_get_proxy_uri (GDataOAuth1Authorizer *self)
Packit 4b6dd7
{
Packit 4b6dd7
	return _get_proxy_uri (self);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/* Static function which isn't deprecated so we can continue using it internally. */
Packit 4b6dd7
static void
Packit 4b6dd7
_set_proxy_uri (GDataOAuth1Authorizer *self, SoupURI *proxy_uri)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
Packit 4b6dd7
Packit 4b6dd7
	g_object_set (self->priv->session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
Packit 4b6dd7
Packit 4b6dd7
	/* Notification is handled in notify_proxy_uri_cb() which is called as a result of setting the property on the session */
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_set_proxy_uri:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @proxy_uri: (allow-none): the proxy URI, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Sets the proxy URI on the #SoupSession used internally by the #GDataOAuth1Authorizer. This forces all requests through the given proxy.
Packit 4b6dd7
 *
Packit 4b6dd7
 * If @proxy_uri is %NULL, no proxy will be used.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 * Deprecated: 0.15.0: Use gdata_oauth1_authorizer_set_proxy_resolver() instead, which gives more flexibility over the proxy used.
Packit 4b6dd7
 */
Packit 4b6dd7
void
Packit 4b6dd7
gdata_oauth1_authorizer_set_proxy_uri (GDataOAuth1Authorizer *self, SoupURI *proxy_uri)
Packit 4b6dd7
{
Packit 4b6dd7
	_set_proxy_uri (self, proxy_uri);
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_get_proxy_resolver:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 *
Packit 4b6dd7
 * Gets the #GProxyResolver on the #GDataOAuth1Authorizer's #SoupSession.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: (transfer none) (allow-none): a #GProxyResolver, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.15.0
Packit 4b6dd7
 */
Packit 4b6dd7
GProxyResolver *
Packit 4b6dd7
gdata_oauth1_authorizer_get_proxy_resolver (GDataOAuth1Authorizer *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), NULL);
Packit 4b6dd7
Packit 4b6dd7
	return self->priv->proxy_resolver;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_set_proxy_resolver:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @proxy_resolver: (allow-none): a #GProxyResolver, or %NULL
Packit 4b6dd7
 *
Packit 4b6dd7
 * Sets the #GProxyResolver on the #SoupSession used internally by the given #GDataOAuth1Authorizer.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Setting this will clear the #GDataOAuth1Authorizer:proxy-uri property.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.15.0
Packit 4b6dd7
 */
Packit 4b6dd7
void
Packit 4b6dd7
gdata_oauth1_authorizer_set_proxy_resolver (GDataOAuth1Authorizer *self, GProxyResolver *proxy_resolver)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
Packit 4b6dd7
	g_return_if_fail (proxy_resolver == NULL || G_IS_PROXY_RESOLVER (proxy_resolver));
Packit 4b6dd7
Packit 4b6dd7
	if (proxy_resolver != NULL) {
Packit 4b6dd7
		g_object_ref (proxy_resolver);
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_clear_object (&self->priv->proxy_resolver);
Packit 4b6dd7
	self->priv->proxy_resolver = proxy_resolver;
Packit 4b6dd7
Packit 4b6dd7
	g_object_notify (G_OBJECT (self), "proxy-resolver");
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
static void
Packit 4b6dd7
notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *self)
Packit 4b6dd7
{
Packit 4b6dd7
	g_object_notify (self, "timeout");
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_get_timeout:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 *
Packit 4b6dd7
 * Gets the #GDataOAuth1Authorizer:timeout property; the network timeout, in seconds.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Return value: the timeout, or 0
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
guint
Packit 4b6dd7
gdata_oauth1_authorizer_get_timeout (GDataOAuth1Authorizer *self)
Packit 4b6dd7
{
Packit 4b6dd7
	guint timeout;
Packit 4b6dd7
Packit 4b6dd7
	g_return_val_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self), 0);
Packit 4b6dd7
Packit 4b6dd7
	g_object_get (self->priv->session, SOUP_SESSION_TIMEOUT, &timeout, NULL);
Packit 4b6dd7
Packit 4b6dd7
	return timeout;
Packit 4b6dd7
}
Packit 4b6dd7
Packit 4b6dd7
/**
Packit 4b6dd7
 * gdata_oauth1_authorizer_set_timeout:
Packit 4b6dd7
 * @self: a #GDataOAuth1Authorizer
Packit 4b6dd7
 * @timeout: the timeout, or 0
Packit 4b6dd7
 *
Packit 4b6dd7
 * Sets the #GDataOAuth1Authorizer:timeout property; the network timeout, in seconds.
Packit 4b6dd7
 *
Packit 4b6dd7
 * If @timeout is 0, network operations will never time out.
Packit 4b6dd7
 *
Packit 4b6dd7
 * Since: 0.9.0
Packit 4b6dd7
 */
Packit 4b6dd7
void
Packit 4b6dd7
gdata_oauth1_authorizer_set_timeout (GDataOAuth1Authorizer *self, guint timeout)
Packit 4b6dd7
{
Packit 4b6dd7
	g_return_if_fail (GDATA_IS_OAUTH1_AUTHORIZER (self));
Packit 4b6dd7
Packit 4b6dd7
	if (gdata_oauth1_authorizer_get_timeout (self) == timeout) {
Packit 4b6dd7
		/* Already has this value */
Packit 4b6dd7
		return;
Packit 4b6dd7
	}
Packit 4b6dd7
Packit 4b6dd7
	g_object_set (self->priv->session, SOUP_SESSION_TIMEOUT, timeout, NULL);
Packit 4b6dd7
Packit 4b6dd7
	/* Notification is handled in notify_timeout_cb() which is called as a result of setting the property on the session */
Packit 4b6dd7
}