summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <philip@tecnocode.co.uk>2021-06-17 14:22:45 +0000
committerPhilip Withnall <philip@tecnocode.co.uk>2021-06-17 14:22:45 +0000
commite3e0714ca1fc67e4bcb7b04b57ec5cb6fa207bf7 (patch)
treec1795a81968671425ef771e9a712f548f48df7ca
parent4d4e1e45e86c16e0edb2b8d18d93fe5e55f32751 (diff)
parent8eecbd9012986dce266eacdb9d280d9df1933147 (diff)
downloadlibgdata-e3e0714ca1fc67e4bcb7b04b57ec5cb6fa207bf7.tar.gz
Merge branch 'drop-deprecated-apis' into 'master'
core: Drop ClientLogin authorizer See merge request GNOME/libgdata!40
-rw-r--r--demos/scrapbook/scrapbook.c102
-rw-r--r--demos/scrapbook/scrapbook.h11
-rw-r--r--docs/reference/gdata-docs.xml1
-rw-r--r--docs/reference/gdata-sections.txt.in34
-rw-r--r--gdata/gdata-authorizer.c4
-rw-r--r--gdata/gdata-client-login-authorizer.c1343
-rw-r--r--gdata/gdata-client-login-authorizer.h141
-rw-r--r--gdata/gdata-core.symbols17
-rw-r--r--gdata/gdata-goa-authorizer.c2
-rw-r--r--gdata/gdata-service.c1
-rw-r--r--gdata/gdata.h1
-rw-r--r--gdata/meson.build2
-rw-r--r--gdata/services/picasaweb/gdata-picasaweb-service.c7
-rw-r--r--gdata/symbol.map17
-rw-r--r--po/POTFILES.in1
15 files changed, 62 insertions, 1622 deletions
diff --git a/demos/scrapbook/scrapbook.c b/demos/scrapbook/scrapbook.c
index d909ab05..9e330cb8 100644
--- a/demos/scrapbook/scrapbook.c
+++ b/demos/scrapbook/scrapbook.c
@@ -425,26 +425,62 @@ start_new_youtube_search (GtkWidget *widget, ScrapData *first) /* *first is a po
/* everything else is implemented somewhere else */
}
-
-static void
-properties_set (GtkWidget *widget, ScrapProps *self)
+static GDataAuthorizer *
+create_authorizer (GError **error)
{
- GDataClientLoginAuthorizer *authorizer;
+ GDataOAuth2Authorizer *authorizer = NULL; /* owned */
GList *domains = NULL; /* list of GDataAuthorizationDomains */
- GError *error = NULL;
-
- /* Get the username and password to use */
- self->main_data->username = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->username_entry)));
- self->main_data->password = g_strdup (gtk_entry_get_text (GTK_ENTRY (self->password_entry)));
+ gchar *uri = NULL;
+ gchar code[100];
+ GError *child_error = NULL;
/* Domains we need to be authorised for */
domains = g_list_prepend (domains, gdata_youtube_service_get_primary_authorization_domain ());
domains = g_list_prepend (domains, gdata_picasaweb_service_get_primary_authorization_domain ());
- /* Authenticate */
- authorizer = gdata_client_login_authorizer_new_for_authorization_domains (CLIENT_ID, domains);
+ /* Go through the interactive OAuth dance. */
+ authorizer = gdata_oauth2_authorizer_new_for_authorization_domains (CLIENT_ID, CLIENT_SECRET,
+ REDIRECT_URI,
+ domains);
+
+ /* Get an authentication URI */
+ uri = gdata_oauth2_authorizer_build_authentication_uri (authorizer,
+ NULL, FALSE);
+
+ /* Wait for the user to retrieve and enter the verifier. */
+ g_print ("Please navigate to the following URI and grant access:\n"
+ " %s\n", uri);
+ g_print ("Enter verifier (EOF to abort): ");
+
+ g_free (uri);
+
+ if (scanf ("%100s", code) != 1) {
+ /* User chose to abort. */
+ g_print ("\n");
+ g_clear_object (&authorizer);
+ return NULL;
+ }
+
+ /* Authorise the token. */
+ gdata_oauth2_authorizer_request_authorization (authorizer, code, NULL,
+ &child_error);
+
+ if (child_error != NULL) {
+ g_propagate_error (error, child_error);
+ g_clear_object (&authorizer);
+ return NULL;
+ }
+
+ return GDATA_AUTHORIZER (authorizer);
+}
+
+static void
+properties_set (GtkWidget *widget, ScrapProps *self)
+{
+ GDataAuthorizer *authorizer;
+ GError *error = NULL;
- gdata_client_login_authorizer_authenticate (authorizer, self->main_data->username, self->main_data->password, NULL, &error);
+ authorizer = create_authorizer (&error);
if (error != NULL) { /* we show this to the user in case they mistyped their password */
GtkWidget *label;
@@ -458,8 +494,8 @@ properties_set (GtkWidget *widget, ScrapProps *self)
g_error_free (error);
}
- gdata_service_set_authorizer (GDATA_SERVICE (self->main_data->youtube_service), GDATA_AUTHORIZER (authorizer));
- gdata_service_set_authorizer (GDATA_SERVICE (self->main_data->picasaweb_service), GDATA_AUTHORIZER (authorizer));
+ gdata_service_set_authorizer (GDATA_SERVICE (self->main_data->youtube_service), authorizer);
+ gdata_service_set_authorizer (GDATA_SERVICE (self->main_data->picasaweb_service), authorizer);
gtk_widget_destroy (self->window);
g_object_unref (authorizer);
@@ -469,7 +505,7 @@ static void
properties_show (GtkWidget *widget, ScrapData *first)
{
ScrapProps *self;
- GtkWidget *label, *button, *box2;
+ GtkWidget *button;
self = g_slice_new (struct _ScrapProps);
self->main_data = first;
@@ -479,42 +515,6 @@ properties_show (GtkWidget *widget, ScrapData *first)
self->box1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
- /* Username/Password labels box */
- box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
-
- label = gtk_label_new ("Username");
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (box2), label, TRUE, TRUE, 0);
-
- label = gtk_label_new ("Password");
- gtk_widget_show (label);
- gtk_box_pack_start (GTK_BOX (box2), label, TRUE, TRUE, 0);
-
- gtk_widget_show (box2);
- gtk_box_pack_start (GTK_BOX (self->box1), box2, FALSE, FALSE, 0);
-
- /* Username/Password entries box */
- box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
- self->username_entry = gtk_entry_new ();
-
- if (self->main_data->username != NULL)
- gtk_entry_set_text (GTK_ENTRY(self->username_entry), self->main_data->username);
-
- gtk_widget_show (self->username_entry);
- gtk_box_pack_start (GTK_BOX (box2), self->username_entry, TRUE, TRUE, 0);
-
- self->password_entry = gtk_entry_new ();
- gtk_entry_set_visibility (GTK_ENTRY (self->password_entry), FALSE);
-
- if (self->main_data->password != NULL)
- gtk_entry_set_text (GTK_ENTRY(self->password_entry), self->main_data->password);
-
- gtk_widget_show (self->password_entry);
- gtk_box_pack_start (GTK_BOX (box2), self->password_entry, TRUE, TRUE, 0);
-
- gtk_box_pack_start (GTK_BOX (self->box1), box2, FALSE, FALSE, 0);
- gtk_widget_show (box2);
-
/* OK button */
button = gtk_button_new_with_label ("_OK");
g_signal_connect (button, "clicked", (GCallback) properties_set, self);
diff --git a/demos/scrapbook/scrapbook.h b/demos/scrapbook/scrapbook.h
index 802e7369..032cb770 100644
--- a/demos/scrapbook/scrapbook.h
+++ b/demos/scrapbook/scrapbook.h
@@ -23,8 +23,12 @@
#include <gdata/gdata.h>
#include <glib.h>
#include <glib-object.h>
-#define DEVELOPER_KEY "AI39si5MkSF-0bzTmP5WETk1D-Z7inHaQJzX13PeG_5Uzeu8mz3vo40cFoqnxjejB-UqzYFrqzOSlsqJvHuPNEGqdycqnPo30A"
-#define CLIENT_ID "ytapi-GNOME-libgdata-444fubtt-0"
+
+#define DEVELOPER_KEY "AI39si7Me3Q7zYs6hmkFvpRBD2nrkVjYYsUO5lh_3HdOkGRc9g6Z4nzxZatk_aAo2EsA21k7vrda0OO6oFg2rnhMedZXPyXoEw"
+#define CLIENT_ID "352818697630-nqu2cmt5quqd6lr17ouoqmb684u84l1f.apps.googleusercontent.com"
+#define CLIENT_SECRET "-fA4pHQJxR3zJ-FyAMPQsikg"
+#define REDIRECT_URI "urn:ietf:wg:oauth:2.0:oob"
+
#define THUMBNAIL_WIDTH 180
#define MAX_RESULTS 10
@@ -73,8 +77,6 @@ typedef struct _ScrapData {
ScrapPicSearch *pic_search;
ScrapPUpload *p_upload;
gint max_rows;
- gchar *username;
- gchar *password;
GtkListStore *lStore;
GDataYouTubeService *youtube_service;
@@ -131,7 +133,6 @@ struct _ScrapPSearch { /* for finding albums */
typedef struct _ScrapProps {
GtkWidget *window;
GtkWidget *box1;
- GtkWidget *username_entry, *password_entry;
ScrapData *main_data;
} ScrapProps;
diff --git a/docs/reference/gdata-docs.xml b/docs/reference/gdata-docs.xml
index 09764c8d..c3f6ee36 100644
--- a/docs/reference/gdata-docs.xml
+++ b/docs/reference/gdata-docs.xml
@@ -54,7 +54,6 @@
<title>Authentication/Authorization API</title>
<xi:include href="xml/gdata-authorizer.xml"/>
<xi:include href="xml/gdata-authorization-domain.xml"/>
- <xi:include href="xml/gdata-client-login-authorizer.xml"/>
<xi:include href="xml/gdata-goa-authorizer.xml"><xi:fallback /></xi:include>
<xi:include href="xml/gdata-oauth2-authorizer.xml"/>
</chapter>
diff --git a/docs/reference/gdata-sections.txt.in b/docs/reference/gdata-sections.txt.in
index 4a5dc697..ed8b9eae 100644
--- a/docs/reference/gdata-sections.txt.in
+++ b/docs/reference/gdata-sections.txt.in
@@ -2088,40 +2088,6 @@ GDATA_IS_AUTHORIZATION_DOMAIN_CLASS
GDataAuthorizationDomainPrivate
</SECTION>
-<SECTION>
-<FILE>gdata-client-login-authorizer</FILE>
-<TITLE>GDataClientLoginAuthorizer</TITLE>
-GDataClientLoginAuthorizer
-GDataClientLoginAuthorizerClass
-GDataClientLoginAuthorizerError
-gdata_client_login_authorizer_new
-gdata_client_login_authorizer_new_for_authorization_domains
-gdata_client_login_authorizer_authenticate
-gdata_client_login_authorizer_authenticate_async
-gdata_client_login_authorizer_authenticate_finish
-gdata_client_login_authorizer_get_client_id
-gdata_client_login_authorizer_get_username
-gdata_client_login_authorizer_get_password
-gdata_client_login_authorizer_get_proxy_uri
-gdata_client_login_authorizer_set_proxy_uri
-gdata_client_login_authorizer_get_proxy_resolver
-gdata_client_login_authorizer_set_proxy_resolver
-gdata_client_login_authorizer_get_timeout
-gdata_client_login_authorizer_set_timeout
-<SUBSECTION Standard>
-GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER
-GDATA_CLIENT_LOGIN_AUTHORIZER
-GDATA_CLIENT_LOGIN_AUTHORIZER_CLASS
-GDATA_IS_CLIENT_LOGIN_AUTHORIZER
-GDATA_IS_CLIENT_LOGIN_AUTHORIZER_CLASS
-GDATA_CLIENT_LOGIN_AUTHORIZER_GET_CLASS
-gdata_client_login_authorizer_get_type
-GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR
-gdata_client_login_authorizer_error_quark
-<SUBSECTION Private>
-GDataClientLoginAuthorizerPrivate
-</SECTION>
-
@COMMENT@<SECTION>
@COMMENT@<FILE>gdata-goa-authorizer</FILE>
@COMMENT@<TITLE>GDataGoaAuthorizer</TITLE>
diff --git a/gdata/gdata-authorizer.c b/gdata/gdata-authorizer.c
index fbfff764..b51c8950 100644
--- a/gdata/gdata-authorizer.c
+++ b/gdata/gdata-authorizer.c
@@ -24,7 +24,7 @@
* @include: gdata/gdata-authorizer.h
*
* The #GDataAuthorizer interface provides a uniform way to implement authentication and authorization processes for use by #GDataServices.
- * Client code will construct a new #GDataAuthorizer instance of their choosing, such as #GDataClientLoginAuthorizer or #GDataOAuth2Authorizer, for
+ * Client code will construct a new #GDataAuthorizer instance of their choosing, such as #GDataOAuth2Authorizer, for
* the #GDataServices which will be used by the client, then authenticates and authorizes with the #GDataAuthorizer instead of the
* #GDataService. The #GDataService then uses the #GDataAuthorizer to authorize individual network requests using whatever authorization token was
* returned to the #GDataAuthorizer by the Google Accounts service.
@@ -38,8 +38,6 @@
* #GDataAuthorizer implementations are provided for some of the standard authorization processes supported by Google for installed applications, as
* listed in their <ulink type="http" url="http://code.google.com/apis/accounts/docs/GettingStarted.html">online documentation</ulink>:
* <itemizedlist>
- * <listitem>#GDataClientLoginAuthorizer for
- * <ulink type="http" url="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html">ClientLogin</ulink> (deprecated)</listitem>
* <listitem>#GDataOAuth2Authorizer for
* <ulink type="http" url="https://developers.google.com/accounts/docs/OAuth2InstalledApp">OAuth 2.0</ulink> (preferred)</listitem>
* </itemizedlist>
diff --git a/gdata/gdata-client-login-authorizer.c b/gdata/gdata-client-login-authorizer.c
deleted file mode 100644
index 295f5106..00000000
--- a/gdata/gdata-client-login-authorizer.c
+++ /dev/null
@@ -1,1343 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/*
- * GData Client
- * Copyright (C) Philip Withnall 2011 <philip@tecnocode.co.uk>
- *
- * GData Client is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * GData Client 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * SECTION:gdata-client-login-authorizer
- * @short_description: GData ClientLogin authorization interface
- * @stability: Stable
- * @include: gdata/gdata-client-login-authorizer.h
- *
- * #GDataClientLoginAuthorizer provides an implementation of the #GDataAuthorizer interface for authentication and authorization using the deprecated
- * <ulink type="http" url="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html">ClientLogin</ulink> process.
- *
- * As noted, the ClientLogin process is being deprecated in favour of OAuth 2.0. This API is not (yet) deprecated, however. One of the main reasons
- * for ClientLogin being deprecated is that it cannot support two-factor authentication as now available to Google Accounts. Any account which has
- * two-factor authentication enabled has to use a service-specific one-time password instead if a client is authenticating with
- * #GDataClientLoginAuthorizer. More documentation about this is
- * <ulink type="http" url="http://www.google.com/support/accounts/bin/static.py?page=guide.cs&guide=1056283&topic=1056286">available online</ulink>.
- * Note that newer services cannot be authenticated against using ClientLogin,
- * and a #GDataOAuth2Authorizer must be used instead.
- *
- * The ClientLogin process is a simple one whereby the user's Google Account username and password are sent over an HTTPS connection to the Google
- * Account servers (when gdata_client_login_authorizer_authenticate() is called), which return an authorization token. This token is then attached to
- * all future requests to the online service. A slight complication is that the Google Accounts service may return a CAPTCHA challenge instead of
- * immediately returning an authorization token. In this case, the #GDataClientLoginAuthorizer::captcha-challenge signal will be emitted, and the
- * user's response to the CAPTCHA should be returned by the handler.
- *
- * ClientLogin does not natively support authorization against multiple authorization domains concurrently with a single authorization token, so it
- * has to be simulated by maintaining multiple authorization tokens if multiple authorization domains are used. This means that proportionally more
- * network requests are made when gdata_client_login_authorizer_authenticate() is called, which will be proportionally slower. Handling of the
- * multiple authorization tokens is otherwise transparent to the client.
- *
- * Each authorization token is long lived, so reauthorization is rarely necessary with #GDataClientLoginAuthorizer. Consequently, refreshing
- * authorization using gdata_authorizer_refresh_authorization() is not supported by #GDataClientLoginAuthorizer, and will immediately return %FALSE
- * with no error set.
- *
- * <example>
- * <title>Authenticating Asynchronously Using ClientLogin</title>
- * <programlisting>
- * GDataSomeService *service;
- * GDataClientLoginAuthorizer *authorizer;
- *
- * /<!-- -->* Create an authorizer and authenticate and authorize the service we're using, asynchronously. *<!-- -->/
- * authorizer = gdata_client_login_authorizer_new ("companyName-applicationName-versionID", GDATA_TYPE_SOME_SERVICE);
- * gdata_client_login_authorizer_authenticate_async (authorizer, username, password, cancellable,
- * (GAsyncReadyCallback) authenticate_cb, user_data);
- *
- * /<!-- -->* Create a service object and link it with the authorizer *<!-- -->/
- * service = gdata_some_service_new (GDATA_AUTHORIZER (authorizer));
- *
- * static void
- * authenticate_cb (GDataClientLoginAuthorizer *authorizer, GAsyncResult *async_result, gpointer user_data)
- * {
- * GError *error = NULL;
- *
- * if (gdata_client_login_authorizer_authenticate_finish (authorizer, async_result, &error) == FALSE) {
- * /<!-- -->* Notify the user of all errors except cancellation errors *<!-- -->/
- * if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- * g_error ("Authentication failed: %s", error->message);
- * }
- * g_error_free (error);
- * return;
- * }
- *
- * /<!-- -->* (The client is now authenticated and authorized against the service.
- * * It can now proceed to execute queries on the service object which require the user to be authenticated.) *<!-- -->/
- * }
- *
- * g_object_unref (service);
- * g_object_unref (authorizer);
- * </programlisting>
- * </example>
- *
- * Since: 0.9.0
- */
-
-#include <config.h>
-#include <glib.h>
-#include <glib/gi18n-lib.h>
-#include <string.h>
-
-#include "gdata-service.h"
-#include "gdata-private.h"
-#include "gdata-marshal.h"
-#include "gdata-client-login-authorizer.h"
-
-/* The default e-mail domain to use for usernames */
-#define EMAIL_DOMAIN "gmail.com"
-
-GQuark
-gdata_client_login_authorizer_error_quark (void)
-{
- return g_quark_from_static_string ("gdata-client-login-authorizer-error-quark");
-}
-
-static void authorizer_init (GDataAuthorizerInterface *iface);
-static void dispose (GObject *object);
-static void finalize (GObject *object);
-static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
-static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
-
-static void process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMessage *message);
-static gboolean is_authorized_for_domain (GDataAuthorizer *self, GDataAuthorizationDomain *domain);
-
-static void notify_proxy_uri_cb (GObject *gobject, GParamSpec *pspec, GDataClientLoginAuthorizer *self);
-static void notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *self);
-
-static SoupURI *_get_proxy_uri (GDataClientLoginAuthorizer *self);
-static void _set_proxy_uri (GDataClientLoginAuthorizer *self, SoupURI *proxy_uri);
-
-struct _GDataClientLoginAuthorizerPrivate {
- SoupSession *session;
- SoupURI *proxy_uri; /* cached version only set if gdata_client_login_authorizer_get_proxy_uri() is called */
- GProxyResolver *proxy_resolver;
-
- gchar *client_id;
-
- /* Mutex for username, password and auth_tokens. It has to be recursive as the top-level authentication functions need to hold a lock on
- * auth_tokens while looping over it, but lower-level functions also need to modify auth_tokens to add the auth_tokens themselves once they're
- * returned by the online service. */
- GRecMutex mutex;
-
- gchar *username;
- GDataSecureString password; /* must be allocated by _gdata_service_secure_strdup() */
-
- /* Mapping from GDataAuthorizationDomain to string? auth_token; auth_token is NULL for domains which aren't authorised at the moment */
- GHashTable *auth_tokens;
-};
-
-enum {
- PROP_CLIENT_ID = 1,
- PROP_USERNAME,
- PROP_PASSWORD,
- PROP_PROXY_URI,
- PROP_TIMEOUT,
- PROP_PROXY_RESOLVER,
-};
-
-enum {
- SIGNAL_CAPTCHA_CHALLENGE,
- LAST_SIGNAL
-};
-
-static guint authorizer_signals[LAST_SIGNAL] = { 0, };
-
-G_DEFINE_TYPE_WITH_CODE (GDataClientLoginAuthorizer, gdata_client_login_authorizer, G_TYPE_OBJECT,
- G_ADD_PRIVATE (GDataClientLoginAuthorizer)
- G_IMPLEMENT_INTERFACE (GDATA_TYPE_AUTHORIZER, authorizer_init))
-
-static void
-gdata_client_login_authorizer_class_init (GDataClientLoginAuthorizerClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gobject_class->get_property = get_property;
- gobject_class->set_property = set_property;
- gobject_class->dispose = dispose;
- gobject_class->finalize = finalize;
-
- /**
- * GDataClientLoginAuthorizer:client-id:
- *
- * A client ID for your application (see the
- * <ulink url="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#Request" type="http">reference documentation</ulink>).
- *
- * It is recommended that the ID is of the form <literal><replaceable>company name</replaceable>-<replaceable>application name</replaceable>-
- * <replaceable>version ID</replaceable></literal>.
- *
- * Since: 0.9.0
- */
- g_object_class_install_property (gobject_class, PROP_CLIENT_ID,
- g_param_spec_string ("client-id",
- "Client ID", "A client ID for your application.",
- NULL,
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GDataClientLoginAuthorizer:username:
- *
- * The user's Google username for authentication. This will always be a full e-mail address.
- *
- * This will only be set after authentication using gdata_client_login_authorizer_authenticate() is completed successfully. It will
- * then be set to the username passed to gdata_client_login_authorizer_authenticate(), and a #GObject::notify signal will be emitted. If
- * authentication fails, it will be set to %NULL.
- *
- * Since: 0.9.0
- */
- g_object_class_install_property (gobject_class, PROP_USERNAME,
- g_param_spec_string ("username",
- "Username", "The user's Google username for authentication.",
- NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GDataClientLoginAuthorizer:password:
- *
- * The user's account password for authentication.
- *
- * This will only be set after authentication using gdata_client_login_authorizer_authenticate() is completed successfully. It will
- * then be set to the password passed to gdata_client_login_authorizer_authenticate(), and a #GObject::notify signal will be emitted. If
- * authentication fails, it will be set to %NULL.
- *
- * If libgdata is compiled with libgcr support, the password will be stored in non-pageable memory. However, if it is retrieved
- * using g_object_get() (or related functions) it will be copied to non-pageable memory and could end up being written to disk. Accessing
- * the password using gdata_client_login_authorizer_get_password() will not perform any copies, and so maintains privacy.
- *
- * Since: 0.9.0
- */
- g_object_class_install_property (gobject_class, PROP_PASSWORD,
- g_param_spec_string ("password",
- "Password", "The user's account password for authentication.",
- NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GDataClientLoginAuthorizer:proxy-uri:
- *
- * The proxy URI used internally for all network requests.
- *
- * Since: 0.9.0
- * Deprecated: 0.15.0: Use #GDataClientLoginAuthorizer:proxy-resolver instead, which gives more flexibility over the proxy used.
- */
- g_object_class_install_property (gobject_class, PROP_PROXY_URI,
- g_param_spec_boxed ("proxy-uri",
- "Proxy URI", "The proxy URI used internally for all network requests.",
- SOUP_TYPE_URI,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GDataClientLoginAuthorizer:timeout:
- *
- * A timeout, in seconds, for network operations. If the timeout is exceeded, the operation will be cancelled and
- * %GDATA_SERVICE_ERROR_NETWORK_ERROR will be returned.
- *
- * If the timeout is <code class="literal">0</code>, operations will never time out.
- *
- * Since: 0.9.0
- */
- g_object_class_install_property (gobject_class, PROP_TIMEOUT,
- g_param_spec_uint ("timeout",
- "Timeout", "A timeout, in seconds, for network operations.",
- 0, G_MAXUINT, 0,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GDataClientLoginAuthorizer:proxy-resolver:
- *
- * The #GProxyResolver used to determine a proxy URI. Setting this will clear the #GDataClientLoginAuthorizer:proxy-uri property.
- *
- * Since: 0.15.0
- */
- g_object_class_install_property (gobject_class, PROP_PROXY_RESOLVER,
- g_param_spec_object ("proxy-resolver",
- "Proxy Resolver", "A GProxyResolver used to determine a proxy URI.",
- G_TYPE_PROXY_RESOLVER,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GDataClientLoginAuthorizer::captcha-challenge:
- * @authorizer: the #GDataClientLoginAuthorizer which received the challenge
- * @uri: the URI of the CAPTCHA image to be used
- *
- * The #GDataClientLoginAuthorizer::captcha-challenge signal is emitted during the authentication process if the authorizer requires a CAPTCHA
- * to be completed. The URI of a CAPTCHA image is given, and the program should display this to the user, and return their response (the text
- * displayed in the image). There is no timeout imposed by the library for the response.
- *
- * Return value: a newly allocated string containing the text in the CAPTCHA image
- *
- * Since: 0.9.0
- */
- authorizer_signals[SIGNAL_CAPTCHA_CHALLENGE] = g_signal_new ("captcha-challenge",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0, NULL, NULL,
- gdata_marshal_STRING__OBJECT_STRING,
- G_TYPE_STRING, 1, G_TYPE_STRING);
-}
-
-static void
-authorizer_init (GDataAuthorizerInterface *iface)
-{
- iface->process_request = process_request;
- iface->is_authorized_for_domain = is_authorized_for_domain;
-}
-
-static void
-gdata_client_login_authorizer_init (GDataClientLoginAuthorizer *self)
-{
- self->priv = gdata_client_login_authorizer_get_instance_private (self);
-
- /* Set up the authentication mutex */
- g_rec_mutex_init (&(self->priv->mutex));
- self->priv->auth_tokens = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) _gdata_service_secure_strfree);
-
- /* Set up the session */
- self->priv->session = _gdata_service_build_session ();
-
- /* Proxy the SoupSession's proxy-uri and timeout properties */
- g_signal_connect (self->priv->session, "notify::proxy-uri", (GCallback) notify_proxy_uri_cb, self);
- g_signal_connect (self->priv->session, "notify::timeout", (GCallback) notify_timeout_cb, self);
-
- /* Keep our GProxyResolver synchronized with SoupSession's. */
- g_object_bind_property (self->priv->session, "proxy-resolver", self, "proxy-resolver", G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
-}
-
-static void
-dispose (GObject *object)
-{
- GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (object)->priv;
-
- if (priv->session != NULL) {
- g_object_unref (priv->session);
- }
- priv->session = NULL;
-
- g_clear_object (&priv->proxy_resolver);
-
- /* Chain up to the parent class */
- G_OBJECT_CLASS (gdata_client_login_authorizer_parent_class)->dispose (object);
-}
-
-static void
-finalize (GObject *object)
-{
- GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (object)->priv;
-
- g_free (priv->username);
- _gdata_service_secure_strfree (priv->password);
- g_free (priv->client_id);
- g_hash_table_destroy (priv->auth_tokens);
- g_rec_mutex_clear (&(priv->mutex));
-
- if (priv->proxy_uri != NULL) {
- soup_uri_free (priv->proxy_uri);
- }
-
- /* Chain up to the parent class */
- G_OBJECT_CLASS (gdata_client_login_authorizer_parent_class)->finalize (object);
-}
-
-static void
-get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
-{
- GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (object)->priv;
-
- switch (property_id) {
- case PROP_CLIENT_ID:
- g_value_set_string (value, priv->client_id);
- break;
- case PROP_USERNAME:
- g_rec_mutex_lock (&(priv->mutex));
- g_value_set_string (value, priv->username);
- g_rec_mutex_unlock (&(priv->mutex));
- break;
- case PROP_PASSWORD:
- /* NOTE: This takes a pageable copy of non-pageable memory and thus could result in the password hitting disk. */
- g_rec_mutex_lock (&(priv->mutex));
- g_value_set_string (value, priv->password);
- g_rec_mutex_unlock (&(priv->mutex));
- break;
- case PROP_PROXY_URI:
- g_value_set_boxed (value, _get_proxy_uri (GDATA_CLIENT_LOGIN_AUTHORIZER (object)));
- break;
- case PROP_TIMEOUT:
- g_value_set_uint (value, gdata_client_login_authorizer_get_timeout (GDATA_CLIENT_LOGIN_AUTHORIZER (object)));
- break;
- case PROP_PROXY_RESOLVER:
- g_value_set_object (value, gdata_client_login_authorizer_get_proxy_resolver (GDATA_CLIENT_LOGIN_AUTHORIZER (object)));
- break;
- default:
- /* We don't have any other property... */
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static void
-set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
-{
- GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (object)->priv;
-
- switch (property_id) {
- case PROP_CLIENT_ID:
- priv->client_id = g_value_dup_string (value);
- break;
- case PROP_PROXY_URI:
- _set_proxy_uri (GDATA_CLIENT_LOGIN_AUTHORIZER (object), g_value_get_boxed (value));
- break;
- case PROP_TIMEOUT:
- gdata_client_login_authorizer_set_timeout (GDATA_CLIENT_LOGIN_AUTHORIZER (object), g_value_get_uint (value));
- break;
- case PROP_PROXY_RESOLVER:
- gdata_client_login_authorizer_set_proxy_resolver (GDATA_CLIENT_LOGIN_AUTHORIZER (object), g_value_get_object (value));
- break;
- default:
- /* We don't have any other property... */
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
- break;
- }
-}
-
-static void
-process_request (GDataAuthorizer *self, GDataAuthorizationDomain *domain, SoupMessage *message)
-{
- GDataConstSecureString auth_token; /* privacy sensitive */
- GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (self)->priv;
-
- /* If the domain's NULL, return immediately */
- if (domain == NULL) {
- return;
- }
-
- /* Set the authorisation header */
- g_rec_mutex_lock (&(priv->mutex));
-
- auth_token = (GDataConstSecureString) g_hash_table_lookup (priv->auth_tokens, domain);
-
- if (auth_token != NULL) {
- /* Ensure that we're using HTTPS: if not, we shouldn't set the Authorization header or we could be revealing the auth token to
- * anyone snooping the connection, which would give them the same rights as us on the user's data. Generally a bad thing to happen. */
- if (soup_message_get_uri (message)->scheme != SOUP_URI_SCHEME_HTTPS) {
- g_warning ("Not authorizing a non-HTTPS message with the user's ClientLogin auth token as the connection isn't secure.");
- } else {
- /* Ideally, authorisation_header would be allocated in non-pageable memory. However, it's copied by
- * soup_message_headers_replace() immediately anyway, so there's not much point. However, we do ensure we zero it out before
- * freeing. */
- gchar *authorisation_header = g_strdup_printf ("GoogleLogin auth=%s", auth_token);
- soup_message_headers_replace (message->request_headers, "Authorization", authorisation_header);
- memset (authorisation_header, 0, strlen (authorisation_header));
- g_free (authorisation_header);
- }
- }
-
- g_rec_mutex_unlock (&(priv->mutex));
-}
-
-static gboolean
-is_authorized_for_domain (GDataAuthorizer *self, GDataAuthorizationDomain *domain)
-{
- GDataClientLoginAuthorizerPrivate *priv = GDATA_CLIENT_LOGIN_AUTHORIZER (self)->priv;
- gpointer result;
-
- g_rec_mutex_lock (&(priv->mutex));
- result = g_hash_table_lookup (priv->auth_tokens, domain);
- g_rec_mutex_unlock (&(priv->mutex));
-
- return (result != NULL) ? TRUE : FALSE;
-}
-
-/**
- * gdata_client_login_authorizer_new:
- * @client_id: your application's client ID
- * @service_type: the #GType of a #GDataService subclass which the #GDataClientLoginAuthorizer will be used with
- *
- * Creates a new #GDataClientLoginAuthorizer. The @client_id must be unique for your application, and as registered with Google.
- *
- * The #GDataAuthorizationDomains for the given @service_type (i.e. as returned by gdata_service_get_authorization_domains()) are the ones the
- * user will be logged in to using the provided username and password when gdata_client_login_authorizer_authenticate() is called. Note that the same
- * username and password will be used for all domains.
- *
- * Return value: (transfer full): a new #GDataClientLoginAuthorizer, or %NULL; unref with g_object_unref()
- *
- * Since: 0.9.0
- */
-GDataClientLoginAuthorizer *
-gdata_client_login_authorizer_new (const gchar *client_id, GType service_type)
-{
- g_return_val_if_fail (client_id != NULL && *client_id != '\0', NULL);
- g_return_val_if_fail (g_type_is_a (service_type, GDATA_TYPE_SERVICE), NULL);
-
- return gdata_client_login_authorizer_new_for_authorization_domains (client_id,
- gdata_service_get_authorization_domains (service_type));
-}
-
-/**
- * gdata_client_login_authorizer_new_for_authorization_domains:
- * @client_id: your application's client ID
- * @authorization_domains: (element-type GDataAuthorizationDomain) (transfer none): a non-empty list of #GDataAuthorizationDomains to be
- * authorized against by the #GDataClientLoginAuthorizer
- *
- * Creates a new #GDataClientLoginAuthorizer. The @client_id must be unique for your application, and as registered with Google. This function is
- * intended to be used only when the default authorization domain list for a single #GDataService, as used by gdata_client_login_authorizer_new(),
- * isn't suitable. For example, this could be because the #GDataClientLoginAuthorizer will be used with multiple #GDataService subclasses, or because
- * the client requires a specific set of authorization domains.
- *
- * The specified #GDataAuthorizationDomains are the ones the user will be logged in to using the provided username and password when
- * gdata_client_login_authorizer_authenticate() is called. Note that the same username and password will be used for all domains.
- *
- * Return value: (transfer full): a new #GDataClientLoginAuthorizer, or %NULL; unref with g_object_unref()
- *
- * Since: 0.9.0
- */
-GDataClientLoginAuthorizer *
-gdata_client_login_authorizer_new_for_authorization_domains (const gchar *client_id, GList *authorization_domains)
-{
- GList *i;
- GDataClientLoginAuthorizer *authorizer;
-
- g_return_val_if_fail (client_id != NULL && *client_id != '\0', NULL);
- g_return_val_if_fail (authorization_domains != NULL, NULL);
-
- authorizer = GDATA_CLIENT_LOGIN_AUTHORIZER (g_object_new (GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER,
- "client-id", client_id,
- NULL));
-
- /* Register all the domains with the authorizer */
- for (i = authorization_domains; i != NULL; i = i->next) {
- g_return_val_if_fail (GDATA_IS_AUTHORIZATION_DOMAIN (i->data), NULL);
-
- /* We don't have to lock the authoriser's mutex here as no other code has seen the authoriser yet */
- g_hash_table_insert (authorizer->priv->auth_tokens, g_object_ref (GDATA_AUTHORIZATION_DOMAIN (i->data)), NULL);
- }
-
- return authorizer;
-}
-
-/* Called in the main thread to notify of changes to the username and password properties from the authentication thread. It swallows a reference
- * the authoriser. */
-static gboolean
-notify_authentication_details_cb (GDataClientLoginAuthorizer *self)
-{
- GObject *authorizer = G_OBJECT (self);
-
- g_object_freeze_notify (authorizer);
- g_object_notify (authorizer, "username");
- g_object_notify (authorizer, "password");
- g_object_thaw_notify (authorizer);
-
- g_object_unref (self);
-
- /* Only execute once */
- return FALSE;
-}
-
-static void
-set_authentication_details (GDataClientLoginAuthorizer *self, const gchar *username, const gchar *password, GHashTable *new_auth_tokens,
- gboolean is_async)
-{
- GDataClientLoginAuthorizerPrivate *priv = self->priv;
- GHashTableIter iter;
-
- g_rec_mutex_lock (&(priv->mutex));
-
- /* Ensure the username is always a full e-mail address */
- g_free (priv->username);
- if (username != NULL && strchr (username, '@') == NULL) {
- priv->username = g_strdup_printf ("%s@" EMAIL_DOMAIN, username);
- } else {
- priv->username = g_strdup (username);
- }
-
- _gdata_service_secure_strfree (priv->password);
- priv->password = _gdata_service_secure_strdup (password);
-
- /* Transfer all successful auth. tokens to the object-wide auth. token store. */
- if (new_auth_tokens == NULL) {
- /* Reset ->auth_tokens to contain no auth. tokens, just the domains. */
- g_hash_table_iter_init (&iter, priv->auth_tokens);
-
- while (g_hash_table_iter_next (&iter, NULL, NULL) == TRUE) {
- g_hash_table_iter_replace (&iter, NULL);
- }
- } else {
- /* Replace the existing ->auth_tokens with the new one, which contains all the shiny new auth. tokens. */
- g_hash_table_ref (new_auth_tokens);
- g_hash_table_unref (priv->auth_tokens);
- priv->auth_tokens = new_auth_tokens;
- }
-
- g_rec_mutex_unlock (&(priv->mutex));
-
- /* Notify of the property changes in the main thread; i.e. if we're running an async operation, schedule the notification in an idle
- * callback; but if we're running a sync operation, emit them immediately.
- * This guarantees that:
- * • notifications will always be emitted before gdata_client_login_authorizer_authenticate() returns; and
- * • notifications will always be emitted in the main thread for calls to gdata_client_login_authorizer_authenticate_async(). */
- if (is_async == TRUE) {
- g_idle_add ((GSourceFunc) notify_authentication_details_cb, g_object_ref (self));
- } else {
- notify_authentication_details_cb (g_object_ref (self));
- }
-}
-
-static GDataSecureString
-parse_authentication_response (GDataClientLoginAuthorizer *self, GDataAuthorizationDomain *domain, guint status,
- const gchar *response_body, gint length, GError **error)
-{
- gchar *auth_start, *auth_end;
- GDataSecureString auth_token; /* NOTE: auth_token must be allocated using _gdata_service_secure_strdup() and friends */
-
- /* Parse the response */
- auth_start = strstr (response_body, "Auth=");
- if (auth_start == NULL) {
- goto protocol_error;
- }
- auth_start += strlen ("Auth=");
-
- auth_end = strstr (auth_start, "\n");
- if (auth_end == NULL) {
- goto protocol_error;
- }
-
- auth_token = _gdata_service_secure_strndup (auth_start, auth_end - auth_start);
- if (auth_token == NULL || strlen (auth_token) == 0) {
- _gdata_service_secure_strfree (auth_token);
- goto protocol_error;
- }
-
- return auth_token;
-
-protocol_error:
- g_set_error_literal (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
- _("The server returned a malformed response."));
- return NULL;
-}
-
-static void
-parse_error_response (GDataClientLoginAuthorizer *self, guint status, const gchar *reason_phrase, const gchar *response_body, gint length,
- GError **error)
-{
- /* We prefer to include the @response_body in the error message, but if it's empty, fall back to the @reason_phrase */
- if (response_body == NULL || *response_body == '\0') {
- response_body = reason_phrase;
- }
-
- /* See: http://code.google.com/apis/gdata/docs/2.0/reference.html#HTTPStatusCodes */
- switch (status) {
- case SOUP_STATUS_CANT_RESOLVE:
- case SOUP_STATUS_CANT_CONNECT:
- case SOUP_STATUS_SSL_FAILED:
- case SOUP_STATUS_IO_ERROR:
- g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_NETWORK_ERROR,
- _("Cannot connect to the service’s server."));
- return;
- case SOUP_STATUS_CANT_RESOLVE_PROXY:
- case SOUP_STATUS_CANT_CONNECT_PROXY:
- g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROXY_ERROR,
- _("Cannot connect to the proxy server."));
- return;
- case SOUP_STATUS_MALFORMED:
- case SOUP_STATUS_BAD_REQUEST: /* 400 */
- g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
- /* Translators: the parameter is an error message returned by the server. */
- _("Invalid request URI or header, or unsupported nonstandard parameter: %s"), response_body);
- return;
- case SOUP_STATUS_UNAUTHORIZED: /* 401 */
- case SOUP_STATUS_FORBIDDEN: /* 403 */
- g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_AUTHENTICATION_REQUIRED,
- /* Translators: the parameter is an error message returned by the server. */
- _("Authentication required: %s"), response_body);
- return;
- case SOUP_STATUS_NOT_FOUND: /* 404 */
- g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_NOT_FOUND,
- /* Translators: the parameter is an error message returned by the server. */
- _("The requested resource was not found: %s"), response_body);
- return;
- case SOUP_STATUS_CONFLICT: /* 409 */
- case SOUP_STATUS_PRECONDITION_FAILED: /* 412 */
- g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_CONFLICT,
- /* Translators: the parameter is an error message returned by the server. */
- _("The entry has been modified since it was downloaded: %s"), response_body);
- return;
- case SOUP_STATUS_INTERNAL_SERVER_ERROR: /* 500 */
- default:
- /* We'll fall back to a generic error, below */
- break;
- }
-
- /* If the error hasn't been handled already, throw a generic error */
- g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR,
- /* Translators: the first parameter is an HTTP status,
- * and the second is an error message returned by the server. */
- _("Error code %u when authenticating: %s"), status, response_body);
-}
-
-static GDataSecureString
-authenticate (GDataClientLoginAuthorizer *self, GDataAuthorizationDomain *domain, const gchar *username, const gchar *password,
- gchar *captcha_token, gchar *captcha_answer, GCancellable *cancellable, GError **error)
-{
- GDataClientLoginAuthorizerPrivate *priv = self->priv;
- SoupMessage *message;
- gchar *request_body;
- const gchar *service_name;
- guint status;
- GDataSecureString auth_token;
- SoupURI *_uri;
-
- /* Prepare the request.
- * NOTE: At this point, our non-pageable password is copied into a pageable HTTP request structure. We can't do much about this
- * except note that the request is transient and so the chance of it getting paged out is low (but still positive). */
- service_name = gdata_authorization_domain_get_service_name (domain);
- request_body = soup_form_encode ("accountType", "HOSTED_OR_GOOGLE",
- "Email", username,
- "Passwd", password,
- "service", service_name,
- "source", priv->client_id,
- (captcha_token == NULL) ? NULL : "logintoken", captcha_token,
- "loginanswer", captcha_answer,
- NULL);
-
- /* Free the CAPTCHA token and answer if necessary */
- g_free (captcha_token);
- g_free (captcha_answer);
-
- /* Build the message */
- _uri = soup_uri_new ("https://www.google.com/accounts/ClientLogin");
- soup_uri_set_port (_uri, _gdata_service_get_https_port ());
- message = soup_message_new_from_uri (SOUP_METHOD_POST, _uri);
- soup_uri_free (_uri);
- soup_message_set_request (message, "application/x-www-form-urlencoded", SOUP_MEMORY_TAKE, request_body, strlen (request_body));
-
- /* Send the message */
- _gdata_service_actually_send_message (priv->session, message, cancellable, error);
- status = message->status_code;
-
- if (status == SOUP_STATUS_CANCELLED) {
- /* Cancelled (the error has already been set) */
- g_object_unref (message);
- return NULL;
- } else if (status != SOUP_STATUS_OK) {
- const gchar *response_body = message->response_body->data;
- gchar *error_start, *error_end, *uri_start, *uri_end, *uri = NULL;
-
- /* Parse the error response; see: http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#Errors */
- if (response_body == NULL) {
- goto protocol_error;
- }
-
- /* Error */
- error_start = strstr (response_body, "Error=");
- if (error_start == NULL) {
- goto protocol_error;
- }
- error_start += strlen ("Error=");
-
- error_end = strstr (error_start, "\n");
- if (error_end == NULL) {
- goto protocol_error;
- }
-
- if (strncmp (error_start, "CaptchaRequired", error_end - error_start) == 0) {
- const gchar *captcha_base_uri = "http://www.google.com/accounts/";
- gchar *captcha_start, *captcha_end, *captcha_uri, *new_captcha_answer;
- guint captcha_base_uri_length;
-
- /* CAPTCHA required to log in */
- captcha_start = strstr (response_body, "CaptchaUrl=");
- if (captcha_start == NULL) {
- goto protocol_error;
- }
- captcha_start += strlen ("CaptchaUrl=");
-
- captcha_end = strstr (captcha_start, "\n");
- if (captcha_end == NULL) {
- goto protocol_error;
- }
-
- /* Do some fancy memory stuff to save ourselves another alloc */
- captcha_base_uri_length = strlen (captcha_base_uri);
- captcha_uri = g_malloc (captcha_base_uri_length + (captcha_end - captcha_start) + 1);
- memcpy (captcha_uri, captcha_base_uri, captcha_base_uri_length);
- memcpy (captcha_uri + captcha_base_uri_length, captcha_start, (captcha_end - captcha_start));
- captcha_uri[captcha_base_uri_length + (captcha_end - captcha_start)] = '\0';
-
- /* Request a CAPTCHA answer from the application */
- g_signal_emit (self, authorizer_signals[SIGNAL_CAPTCHA_CHALLENGE], 0, captcha_uri, &new_captcha_answer);
- g_free (captcha_uri);
-
- if (new_captcha_answer == NULL || *new_captcha_answer == '\0') {
- g_set_error_literal (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_CAPTCHA_REQUIRED,
- /* Translators: see http://en.wikipedia.org/wiki/CAPTCHA for information about CAPTCHAs */
- _("A CAPTCHA must be filled out to log in."));
- goto login_error;
- }
-
- /* Get the CAPTCHA token */
- captcha_start = strstr (response_body, "CaptchaToken=");
- if (captcha_start == NULL) {
- goto protocol_error;
- }
- captcha_start += strlen ("CaptchaToken=");
-
- captcha_end = strstr (captcha_start, "\n");
- if (captcha_end == NULL) {
- goto protocol_error;
- }
-
- /* Save the CAPTCHA token and answer, and attempt to log in with them */
- g_object_unref (message);
-
- return authenticate (self, domain, username, password,
- g_strndup (captcha_start, captcha_end - captcha_start), new_captcha_answer,
- cancellable, error);
- } else if (strncmp (error_start, "Unknown", error_end - error_start) == 0) {
- goto protocol_error;
- } else if (strncmp (error_start, "BadAuthentication", error_end - error_start) == 0) {
- /* Looks like Error=BadAuthentication errors don't return a URI */
- gchar *info_start, *info_end;
-
- info_start = strstr (response_body, "Info=");
- if (info_start != NULL) {
- info_start += strlen ("Info=");
- info_end = strstr (info_start, "\n");
- }
-
- /* If Info=InvalidSecondFactor, the user needs to generate an application-specific password and use that instead */
- if (info_start != NULL && info_end != NULL && strncmp (info_start, "InvalidSecondFactor", info_end - info_start) == 0) {
- g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_INVALID_SECOND_FACTOR,
- /* Translators: the parameter is a URI for further information. */
- _("This account requires an application-specific password. (%s)"),
- "http://www.google.com/support/accounts/bin/static.py?page=guide.cs&guide=1056283&topic=1056286");
- goto login_error;
- }
-
- /* Fall back to a generic "bad authentication details" message */
- g_set_error_literal (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_BAD_AUTHENTICATION,
- _("Your username or password were incorrect."));
- goto login_error;
- }
-
- /* Get the information URI */
- uri_start = strstr (response_body, "Url=");
- if (uri_start == NULL) {
- goto protocol_error;
- }
- uri_start += strlen ("Url=");
-
- uri_end = strstr (uri_start, "\n");
- if (uri_end == NULL) {
- goto protocol_error;
- }
-
- uri = g_strndup (uri_start, uri_end - uri_start);
-
- if (strncmp (error_start, "NotVerified", error_end - error_start) == 0) {
- g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_NOT_VERIFIED,
- /* Translators: the parameter is a URI for further information. */
- _("Your account’s e-mail address has not been verified. (%s)"), uri);
- goto login_error;
- } else if (strncmp (error_start, "TermsNotAgreed", error_end - error_start) == 0) {
- g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_TERMS_NOT_AGREED,
- /* Translators: the parameter is a URI for further information. */
- _("You have not agreed to the service’s terms and conditions. (%s)"), uri);
- goto login_error;
- } else if (strncmp (error_start, "AccountMigrated", error_end - error_start) == 0) {
- /* This is non-standard, and used by YouTube since it's got messed-up accounts */
- g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_MIGRATED,
- /* Translators: the parameter is a URI for further information. */
- _("This account has been migrated. Please log in online to receive your new username and password. (%s)"), uri);
- goto login_error;
- } else if (strncmp (error_start, "AccountDeleted", error_end - error_start) == 0) {
- g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DELETED,
- /* Translators: the parameter is a URI for further information. */
- _("This account has been deleted. (%s)"), uri);
- goto login_error;
- } else if (strncmp (error_start, "AccountDisabled", error_end - error_start) == 0) {
- g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DISABLED,
- /* Translators: the parameter is a URI for further information. */
- _("This account has been disabled. (%s)"), uri);
- goto login_error;
- } else if (strncmp (error_start, "ServiceDisabled", error_end - error_start) == 0) {
- g_set_error (error, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR, GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_SERVICE_DISABLED,
- /* Translators: the parameter is a URI for further information. */
- _("This account’s access to this service has been disabled. (%s)"), uri);
- goto login_error;
- } else if (strncmp (error_start, "ServiceUnavailable", error_end - error_start) == 0) {
- g_set_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_UNAVAILABLE,
- /* Translators: the parameter is a URI for further information. */
- _("This service is not available at the moment. (%s)"), uri);
- goto login_error;
- }
-
- /* Unknown error type! */
- goto protocol_error;
-
-login_error:
- g_free (uri);
- g_object_unref (message);
-
- return NULL;
- }
-
- g_assert (message->response_body->data != NULL);
-
- auth_token = parse_authentication_response (self, domain, status, message->response_body->data, message->response_body->length, error);
-
- /* Zero out the response body to lower the chance of it (with all the juicy passwords and auth. tokens it contains) hitting disk or getting
- * leaked in free memory. */
- memset ((void*) message->response_body->data, 0, message->response_body->length);
-
- g_object_unref (message);
-
- return auth_token;
-
-protocol_error:
- parse_error_response (self, status, message->reason_phrase, message->response_body->data, message->response_body->length, error);
-
- g_object_unref (message);
-
- return NULL;
-}
-
-static gboolean
-authenticate_loop (GDataClientLoginAuthorizer *authorizer, gboolean is_async, const gchar *username, const gchar *password, GCancellable *cancellable,
- GError **error)
-{
- GDataClientLoginAuthorizerPrivate *priv = authorizer->priv;
- gboolean cumulative_success = TRUE;
- GHashTable *new_auth_tokens;
- GHashTableIter iter;
- GDataAuthorizationDomain *domain;
- GDataSecureString auth_token;
-
- g_rec_mutex_lock (&(priv->mutex));
-
- /* Authenticate and authorize against each of the services registered with the authorizer */
- new_auth_tokens = g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, (GDestroyNotify) _gdata_service_secure_strfree);
- g_hash_table_iter_init (&iter, priv->auth_tokens);
-
- while (g_hash_table_iter_next (&iter, (gpointer*) &domain, NULL) == TRUE) {
- GError *authenticate_error = NULL;
-
- auth_token = authenticate (authorizer, domain, username, password, NULL, NULL, cancellable, &authenticate_error);
-
- if (auth_token == NULL && cumulative_success == TRUE) {
- /* Only propagate the first error which occurs. */
- g_propagate_error (error, authenticate_error);
- authenticate_error = NULL;
- }
-
- cumulative_success = (auth_token != NULL) && cumulative_success;
-
- /* Store the auth. token (or lack thereof if authentication failed). */
- g_hash_table_insert (new_auth_tokens, g_object_ref (domain), auth_token);
-
- g_clear_error (&authenticate_error);
- }
-
- g_rec_mutex_unlock (&(priv->mutex));
-
- /* Set or clear the authentication details and return now that we're done */
- if (cumulative_success == TRUE) {
- set_authentication_details (authorizer, username, password, new_auth_tokens, is_async);
- } else {
- set_authentication_details (authorizer, NULL, NULL, NULL, is_async);
- }
-
- g_hash_table_unref (new_auth_tokens);
-
- return cumulative_success;
-}
-
-typedef struct {
- gchar *username;
- GDataSecureString password; /* NOTE: This must be allocated in non-pageable memory using _gdata_service_secure_strdup(). */
-} AuthenticateAsyncData;
-
-static void
-authenticate_async_data_free (AuthenticateAsyncData *self)
-{
- g_free (self->username);
- _gdata_service_secure_strfree (self->password);
-
- g_slice_free (AuthenticateAsyncData, self);
-}
-
-static void
-authenticate_thread (GTask *task, gpointer source_object, gpointer task_data, GCancellable *cancellable)
-{
- GDataClientLoginAuthorizer *authorizer = GDATA_CLIENT_LOGIN_AUTHORIZER (source_object);
- g_autoptr(GError) error = NULL;
- AuthenticateAsyncData *data = task_data;
-
- if (!authenticate_loop (authorizer, TRUE, data->username, data->password, cancellable, &error))
- g_task_return_error (task, g_steal_pointer (&error));
- else
- g_task_return_boolean (task, TRUE);
-}
-
-/**
- * gdata_client_login_authorizer_authenticate_async:
- * @self: a #GDataClientLoginAuthorizer
- * @username: the user's username
- * @password: the user's password
- * @cancellable: (allow-none): optional #GCancellable object, or %NULL
- * @callback: a #GAsyncReadyCallback to call when authentication is finished
- * @user_data: (closure): data to pass to the @callback function
- *
- * Authenticates the #GDataClientLoginAuthorizer with the Google accounts service using the given @username and @password. @self, @username and
- * @password are all reffed/copied when this function is called, so can safely be freed after this function returns.
- *
- * For more details, see gdata_client_login_authorizer_authenticate(), which is the synchronous version of this function.
- *
- * When the operation is finished, @callback will be called. You can then call gdata_client_login_authorizer_authenticate_finish()
- * to get the results of the operation.
- *
- * Since: 0.9.0
- */
-void
-gdata_client_login_authorizer_authenticate_async (GDataClientLoginAuthorizer *self, const gchar *username, const gchar *password,
- GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
-{
- g_autoptr(GTask) task = NULL;
- AuthenticateAsyncData *data;
-
- g_return_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self));
- g_return_if_fail (username != NULL);
- g_return_if_fail (password != NULL);
- g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
-
- data = g_slice_new (AuthenticateAsyncData);
- data->username = g_strdup (username);
- data->password = _gdata_service_secure_strdup (password);
-
- task = g_task_new (self, cancellable, callback, user_data);
- g_task_set_source_tag (task, gdata_client_login_authorizer_authenticate_async);
- g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) authenticate_async_data_free);
- g_task_run_in_thread (task, authenticate_thread);
-}
-
-/**
- * gdata_client_login_authorizer_authenticate_finish:
- * @self: a #GDataClientLoginAuthorizer
- * @async_result: a #GAsyncResult
- * @error: a #GError, or %NULL
- *
- * Finishes an asynchronous authentication operation started with gdata_client_login_authorizer_authenticate_async().
- *
- * Return value: %TRUE if authentication was successful, %FALSE otherwise
- *
- * Since: 0.9.0
- */
-gboolean
-gdata_client_login_authorizer_authenticate_finish (GDataClientLoginAuthorizer *self, GAsyncResult *async_result, GError **error)
-{
- g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), FALSE);
- g_return_val_if_fail (G_IS_ASYNC_RESULT (async_result), FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_return_val_if_fail (g_task_is_valid (async_result, self), FALSE);
- g_return_val_if_fail (g_async_result_is_tagged (async_result, gdata_client_login_authorizer_authenticate_async), FALSE);
-
- return g_task_propagate_boolean (G_TASK (async_result), error);
-}
-
-/**
- * gdata_client_login_authorizer_authenticate:
- * @self: a #GDataClientLoginAuthorizer
- * @username: the user's username
- * @password: the user's password
- * @cancellable: (allow-none): optional #GCancellable object, or %NULL
- * @error: a #GError, or %NULL
- *
- * Authenticates the #GDataClientLoginAuthorizer with the Google Accounts service using @username and @password and authorizes it against all the
- * service types passed to gdata_client_login_authorizer_new(); i.e. logs into the service with the given user account. @username should be a full
- * e-mail address (e.g. <literal>john.smith\@gmail.com</literal>). If a full e-mail address is not given, @username will have
- * <literal>\@gmail.com</literal> appended to create an e-mail address
- *
- * If @cancellable is not %NULL, then the operation can be cancelled by triggering the @cancellable object from another thread.
- * If the operation was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
- *
- * If the operation errors or is cancelled part-way through, gdata_authorizer_is_authorized_for_domain() is guaranteed to return %FALSE
- * for all #GDataAuthorizationDomains, even if authentication has succeeded for some of them already.
- *
- * A %GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_BAD_AUTHENTICATION will be returned if authentication failed due to an incorrect username or password.
- * Other #GDataClientLoginAuthorizerError errors can be returned for other conditions.
- *
- * If the service requires a CAPTCHA to be completed, the #GDataClientLoginAuthorizer::captcha-challenge signal will be emitted.
- * The return value from a signal handler for the signal should be a newly allocated string containing the text from the image. If the text is %NULL
- * or empty, authentication will fail with a %GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_CAPTCHA_REQUIRED error. Otherwise, authentication will be
- * automatically and transparently restarted with the new CAPTCHA details.
- *
- * A %GDATA_SERVICE_ERROR_PROTOCOL_ERROR will be returned if the server's responses were invalid.
- *
- * Return value: %TRUE if authentication and authorization was successful against all the services, %FALSE otherwise
- *
- * Since: 0.9.0
- */
-gboolean
-gdata_client_login_authorizer_authenticate (GDataClientLoginAuthorizer *self, const gchar *username, const gchar *password,
- GCancellable *cancellable, GError **error)
-{
- g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), FALSE);
- g_return_val_if_fail (username != NULL, FALSE);
- g_return_val_if_fail (password != NULL, FALSE);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
- g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-
- return authenticate_loop (self, FALSE, username, password, cancellable, error);
-}
-
-static void
-notify_proxy_uri_cb (GObject *object, GParamSpec *pspec, GDataClientLoginAuthorizer *self)
-{
- /* Flush our cached version */
- if (self->priv->proxy_uri != NULL) {
- soup_uri_free (self->priv->proxy_uri);
- self->priv->proxy_uri = NULL;
- }
-
- g_object_notify (G_OBJECT (self), "proxy-uri");
-}
-
-/* Static function which isn't deprecated so we can continue using it internally. */
-static SoupURI *
-_get_proxy_uri (GDataClientLoginAuthorizer *self)
-{
- SoupURI *proxy_uri;
-
- g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
-
- /* If we have a cached version, return that */
- if (self->priv->proxy_uri != NULL) {
- return self->priv->proxy_uri;
- }
-
- g_object_get (self->priv->session, SOUP_SESSION_PROXY_URI, &proxy_uri, NULL);
-
- /* Update the cache; it takes ownership of the URI */
- self->priv->proxy_uri = proxy_uri;
-
- return proxy_uri;
-}
-
-/**
- * gdata_client_login_authorizer_get_proxy_uri:
- * @self: a #GDataClientLoginAuthorizer
- *
- * Gets the proxy URI on the #GDataClientLoginAuthorizer's #SoupSession.
- *
- * Return value: (transfer full): the proxy URI, or %NULL; free with soup_uri_free()
- *
- * Since: 0.9.0
- * Deprecated: 0.15.0: Use gdata_client_login_authorizer_get_proxy_resolver() instead, which gives more flexibility over the proxy used.
- */
-SoupURI *
-gdata_client_login_authorizer_get_proxy_uri (GDataClientLoginAuthorizer *self)
-{
- return _get_proxy_uri (self);
-}
-
-/* Static function which isn't deprecated so we can continue using it internally. */
-static void
-_set_proxy_uri (GDataClientLoginAuthorizer *self, SoupURI *proxy_uri)
-{
- g_return_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self));
-
- g_object_set (self->priv->session, SOUP_SESSION_PROXY_URI, proxy_uri, NULL);
-
- /* Notification is handled in notify_proxy_uri_cb() which is called as a result of setting the property on the session */
-}
-
-/**
- * gdata_client_login_authorizer_set_proxy_uri:
- * @self: a #GDataClientLoginAuthorizer
- * @proxy_uri: (allow-none): the proxy URI, or %NULL
- *
- * Sets the proxy URI on the #SoupSession used internally by the #GDataClientLoginAuthorizer. This forces all requests through the given proxy.
- *
- * If @proxy_uri is %NULL, no proxy will be used.
- *
- * Since: 0.9.0
- * Deprecated: 0.15.0: Use gdata_client_login_authorizer_set_proxy_resolver() instead, which gives more flexibility over the proxy used.
- */
-void
-gdata_client_login_authorizer_set_proxy_uri (GDataClientLoginAuthorizer *self, SoupURI *proxy_uri)
-{
- _set_proxy_uri (self, proxy_uri);
-}
-
-/**
- * gdata_client_login_authorizer_get_proxy_resolver:
- * @self: a #GDataClientLoginAuthorizer
- *
- * Gets the #GProxyResolver on the #GDataClientLoginAuthorizer's #SoupSession.
- *
- * Return value: (transfer none) (allow-none): a #GProxyResolver, or %NULL
- *
- * Since: 0.15.0
- */
-GProxyResolver *
-gdata_client_login_authorizer_get_proxy_resolver (GDataClientLoginAuthorizer *self)
-{
- g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
-
- return self->priv->proxy_resolver;
-}
-
-/**
- * gdata_client_login_authorizer_set_proxy_resolver:
- * @self: a #GDataClientLoginAuthorizer
- * @proxy_resolver: (allow-none): a #GProxyResolver, or %NULL
- *
- * Sets the #GProxyResolver on the #SoupSession used internally by the given #GDataClientLoginAuthorizer.
- *
- * Setting this will clear the #GDataClientLoginAuthorizer:proxy-uri property.
- *
- * Since: 0.15.0
- */
-void
-gdata_client_login_authorizer_set_proxy_resolver (GDataClientLoginAuthorizer *self, GProxyResolver *proxy_resolver)
-{
- g_return_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self));
- g_return_if_fail (proxy_resolver == NULL || G_IS_PROXY_RESOLVER (proxy_resolver));
-
- if (proxy_resolver != NULL) {
- g_object_ref (proxy_resolver);
- }
-
- g_clear_object (&self->priv->proxy_resolver);
- self->priv->proxy_resolver = proxy_resolver;
-
- g_object_notify (G_OBJECT (self), "proxy-resolver");
-}
-
-static void
-notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *self)
-{
- g_object_notify (self, "timeout");
-}
-
-/**
- * gdata_client_login_authorizer_get_timeout:
- * @self: a #GDataClientLoginAuthorizer
- *
- * Gets the #GDataClientLoginAuthorizer:timeout property; the network timeout, in seconds.
- *
- * Return value: the timeout, or <code class="literal">0</code>
- *
- * Since: 0.9.0
- */
-guint
-gdata_client_login_authorizer_get_timeout (GDataClientLoginAuthorizer *self)
-{
- guint timeout;
-
- g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), 0);
-
- g_object_get (self->priv->session, SOUP_SESSION_TIMEOUT, &timeout, NULL);
-
- return timeout;
-}
-
-/**
- * gdata_client_login_authorizer_set_timeout:
- * @self: a #GDataClientLoginAuthorizer
- * @timeout: the timeout, or <code class="literal">0</code>
- *
- * Sets the #GDataClientLoginAuthorizer:timeout property; the network timeout, in seconds.
- *
- * If @timeout is <code class="literal">0</code>, network operations will never time out.
- *
- * Since: 0.9.0
- */
-void
-gdata_client_login_authorizer_set_timeout (GDataClientLoginAuthorizer *self, guint timeout)
-{
- g_return_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self));
-
- g_object_set (self->priv->session, SOUP_SESSION_TIMEOUT, timeout, NULL);
-
- /* Notification is handled in notify_proxy_uri_cb() which is called as a result of setting the property on the session */
-}
-
-/**
- * gdata_client_login_authorizer_get_client_id:
- * @self: a #GDataClientLoginAuthorizer
- *
- * Returns the authorizer's client ID, as specified on constructing the #GDataClientLoginAuthorizer.
- *
- * Return value: the authorizer's client ID
- *
- * Since: 0.9.0
- */
-const gchar *
-gdata_client_login_authorizer_get_client_id (GDataClientLoginAuthorizer *self)
-{
- g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
-
- return self->priv->client_id;
-}
-
-/**
- * gdata_client_login_authorizer_get_username:
- * @self: a #GDataClientLoginAuthorizer
- *
- * Returns the username of the currently authenticated user, or %NULL if nobody is authenticated.
- *
- * It is not safe to call this while an authentication operation is ongoing.
- *
- * Return value: the username of the currently authenticated user, or %NULL
- *
- * Since: 0.9.0
- */
-const gchar *
-gdata_client_login_authorizer_get_username (GDataClientLoginAuthorizer *self)
-{
- g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
-
- /* There's little point protecting this with ->mutex, as the data's meaningless if accessed during an authentication operation,
- * and not being accessed concurrently otherwise. */
- return self->priv->username;
-}
-
-/**
- * gdata_client_login_authorizer_get_password:
- * @self: a #GDataClientLoginAuthorizer
- *
- * Returns the password of the currently authenticated user, or %NULL if nobody is authenticated.
- *
- * It is not safe to call this while an authentication operation is ongoing.
- *
- * If libgdata is compiled with libgcr support, the password will be stored in non-pageable memory. Since this function doesn't return
- * a copy of the password, the returned value is guaranteed to not hit disk. It's advised that any copies of the password made in client programs
- * also use non-pageable memory.
- *
- * Return value: the password of the currently authenticated user, or %NULL
- *
- * Since: 0.9.0
- */
-const gchar *
-gdata_client_login_authorizer_get_password (GDataClientLoginAuthorizer *self)
-{
- g_return_val_if_fail (GDATA_IS_CLIENT_LOGIN_AUTHORIZER (self), NULL);
-
- /* There's little point protecting this with ->mutex, as the data's meaningless if accessed during an authentication operation,
- * and not being accessed concurrently otherwise. */
- return self->priv->password;
-}
diff --git a/gdata/gdata-client-login-authorizer.h b/gdata/gdata-client-login-authorizer.h
deleted file mode 100644
index 7e13ca1c..00000000
--- a/gdata/gdata-client-login-authorizer.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/*
- * GData Client
- * Copyright (C) Philip Withnall 2011 <philip@tecnocode.co.uk>
- *
- * GData Client is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * GData Client 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef GDATA_CLIENT_LOGIN_AUTHORIZER_H
-#define GDATA_CLIENT_LOGIN_AUTHORIZER_H
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include "gdata-authorizer.h"
-
-G_BEGIN_DECLS
-
-/**
- * GDataClientLoginAuthorizerError:
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_BAD_AUTHENTICATION: The login request used a username or password that is not recognized.
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_NOT_VERIFIED: The account email address has not been verified. The user will need to access their Google
- * account directly to resolve the issue before logging in using a non-Google application.
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_TERMS_NOT_AGREED: The user has not agreed to terms. The user will need to access their Google account directly
- * to resolve the issue before logging in using a non-Google application.
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_CAPTCHA_REQUIRED: A CAPTCHA is required. (A response with this error code will also contain an image URI and a
- * CAPTCHA token.)
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DELETED: The user account has been deleted.
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DISABLED: The user account has been disabled.
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_SERVICE_DISABLED: The user's access to the specified service has been disabled. (The user account may still be
- * valid.)
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_MIGRATED: The user's account login details have been migrated to a new system. (This is used for the
- * transition from the old YouTube login details to the new ones.)
- * @GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_INVALID_SECOND_FACTOR: The user's account requires an application-specific password to be used.
- *
- * Error codes for authentication and authorization operations on #GDataClientLoginAuthorizer. See the
- * <ulink type="http" url="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#Errors">online ClientLogin documentation</ulink> for
- * more information.
- *
- * Since: 0.9.0
- */
-typedef enum {
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_BAD_AUTHENTICATION = 1,
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_NOT_VERIFIED,
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_TERMS_NOT_AGREED,
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_CAPTCHA_REQUIRED,
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DELETED,
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_DISABLED,
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_SERVICE_DISABLED,
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_ACCOUNT_MIGRATED,
- GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR_INVALID_SECOND_FACTOR
-} GDataClientLoginAuthorizerError;
-
-GQuark gdata_client_login_authorizer_error_quark (void) G_GNUC_CONST;
-
-#define GDATA_CLIENT_LOGIN_AUTHORIZER_ERROR gdata_client_login_authorizer_error_quark ()
-
-#define GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER (gdata_client_login_authorizer_get_type ())
-#define GDATA_CLIENT_LOGIN_AUTHORIZER(o) \
- (G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER, GDataClientLoginAuthorizer))
-#define GDATA_CLIENT_LOGIN_AUTHORIZER_CLASS(k) \
- (G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER, GDataClientLoginAuthorizerClass))
-#define GDATA_IS_CLIENT_LOGIN_AUTHORIZER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER))
-#define GDATA_IS_CLIENT_LOGIN_AUTHORIZER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER))
-#define GDATA_CLIENT_LOGIN_AUTHORIZER_GET_CLASS(o) \
- (G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_CLIENT_LOGIN_AUTHORIZER, GDataClientLoginAuthorizerClass))
-
-typedef struct _GDataClientLoginAuthorizerPrivate GDataClientLoginAuthorizerPrivate;
-
-/**
- * GDataClientLoginAuthorizer:
- *
- * All the fields in the #GDataClientLoginAuthorizer structure are private and should never be accessed directly.
- *
- * Since: 0.9.0
- */
-typedef struct {
- /*< private >*/
- GObject parent;
- GDataClientLoginAuthorizerPrivate *priv;
-} GDataClientLoginAuthorizer;
-
-/**
- * GDataClientLoginAuthorizerClass:
- *
- * All the fields in the #GDataClientLoginAuthorizerClass structure are private and should never be accessed directly.
- *
- * Since: 0.9.0
- */
-typedef struct {
- /*< private >*/
- GObjectClass parent;
-
- /*< private >*/
- /* Padding for future expansion */
- void (*_g_reserved0) (void);
- void (*_g_reserved1) (void);
-} GDataClientLoginAuthorizerClass;
-
-GType gdata_client_login_authorizer_get_type (void) G_GNUC_CONST;
-G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDataClientLoginAuthorizer, g_object_unref)
-
-GDataClientLoginAuthorizer *gdata_client_login_authorizer_new (const gchar *client_id, GType service_type) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-GDataClientLoginAuthorizer *gdata_client_login_authorizer_new_for_authorization_domains (const gchar *client_id, GList *authorization_domains)
- G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
-
-gboolean gdata_client_login_authorizer_authenticate (GDataClientLoginAuthorizer *self, const gchar *username, const gchar *password,
- GCancellable *cancellable, GError **error);
-void gdata_client_login_authorizer_authenticate_async (GDataClientLoginAuthorizer *self, const gchar *username, const gchar *password,
- GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
-gboolean gdata_client_login_authorizer_authenticate_finish (GDataClientLoginAuthorizer *self, GAsyncResult *async_result, GError **error);
-
-const gchar *gdata_client_login_authorizer_get_client_id (GDataClientLoginAuthorizer *self) G_GNUC_PURE;
-const gchar *gdata_client_login_authorizer_get_username (GDataClientLoginAuthorizer *self) G_GNUC_PURE;
-const gchar *gdata_client_login_authorizer_get_password (GDataClientLoginAuthorizer *self) G_GNUC_PURE;
-
-#ifndef LIBGDATA_DISABLE_DEPRECATED
-SoupURI *gdata_client_login_authorizer_get_proxy_uri (GDataClientLoginAuthorizer *self) G_GNUC_PURE G_GNUC_DEPRECATED_FOR (gdata_client_login_authorizer_get_proxy_resolver);
-void gdata_client_login_authorizer_set_proxy_uri (GDataClientLoginAuthorizer *self, SoupURI *proxy_uri) G_GNUC_DEPRECATED_FOR (gdata_client_login_authorizer_set_proxy_resolver);
-#endif /* !LIBGDATA_DISABLE_DEPRECATED */
-
-GProxyResolver *gdata_client_login_authorizer_get_proxy_resolver (GDataClientLoginAuthorizer *self) G_GNUC_PURE;
-void gdata_client_login_authorizer_set_proxy_resolver (GDataClientLoginAuthorizer *self, GProxyResolver *proxy_resolver);
-
-guint gdata_client_login_authorizer_get_timeout (GDataClientLoginAuthorizer *self) G_GNUC_PURE;
-void gdata_client_login_authorizer_set_timeout (GDataClientLoginAuthorizer *self, guint timeout);
-
-G_END_DECLS
-
-#endif /* !GDATA_CLIENT_LOGIN_AUTHORIZER_H */
diff --git a/gdata/gdata-core.symbols b/gdata/gdata-core.symbols
index db529ae2..a94d12b7 100644
--- a/gdata/gdata-core.symbols
+++ b/gdata/gdata-core.symbols
@@ -740,23 +740,6 @@ gdata_authorizer_refresh_authorization_finish
gdata_authorization_domain_get_type
gdata_authorization_domain_get_service_name
gdata_authorization_domain_get_scope
-gdata_client_login_authorizer_get_type
-gdata_client_login_authorizer_new
-gdata_client_login_authorizer_new_for_authorization_domains
-gdata_client_login_authorizer_authenticate
-gdata_client_login_authorizer_authenticate_async
-gdata_client_login_authorizer_authenticate_finish
-gdata_client_login_authorizer_get_client_id
-gdata_client_login_authorizer_get_username
-gdata_client_login_authorizer_get_password
-gdata_client_login_authorizer_get_proxy_uri
-gdata_client_login_authorizer_set_proxy_uri
-gdata_client_login_authorizer_get_proxy_resolver
-gdata_client_login_authorizer_set_proxy_resolver
-gdata_client_login_authorizer_get_timeout
-gdata_client_login_authorizer_set_timeout
-gdata_client_login_authorizer_error_quark
-gdata_client_login_authorizer_error_get_type
gdata_download_stream_get_authorization_domain
gdata_upload_stream_get_authorization_domain
gdata_batch_operation_get_authorization_domain
diff --git a/gdata/gdata-goa-authorizer.c b/gdata/gdata-goa-authorizer.c
index e71f6145..88c014e9 100644
--- a/gdata/gdata-goa-authorizer.c
+++ b/gdata/gdata-goa-authorizer.c
@@ -32,7 +32,7 @@
* <ulink type="http" url="http://code.google.com/apis/accounts/docs/OAuthForInstalledApps.html">OAuth 1.0</ulink> or
* <ulink type="http" url="https://developers.google.com/identity/protocols/OAuth2">OAuth 2.0</ulink> processes.
*
- * #GDataGoaAuthorizer natively supports authorization against multiple services (unlike #GDataClientLoginAuthorizer), depending entirely on which
+ * #GDataGoaAuthorizer natively supports authorization against multiple services, depending entirely on which
* services the user has enabled for their Google account in GOA. #GDataGoaAuthorizer cannot authenticate for more services than are enabled in GOA.
*
* <example>
diff --git a/gdata/gdata-service.c b/gdata/gdata-service.c
index 40fbaf84..8c62c367 100644
--- a/gdata/gdata-service.c
+++ b/gdata/gdata-service.c
@@ -51,7 +51,6 @@
#include "gdata-service.h"
#include "gdata-private.h"
-#include "gdata-client-login-authorizer.h"
#include "gdata-marshal.h"
#include "gdata-types.h"
diff --git a/gdata/gdata.h b/gdata/gdata.h
index 8612dc05..3c4b3eb9 100644
--- a/gdata/gdata.h
+++ b/gdata/gdata.h
@@ -37,7 +37,6 @@
#include <gdata/gdata-batch-operation.h>
#include <gdata/gdata-authorizer.h>
#include <gdata/gdata-authorization-domain.h>
-#include <gdata/gdata-client-login-authorizer.h>
#include <gdata/gdata-oauth2-authorizer.h>
#ifdef GOA_API_IS_SUBJECT_TO_CHANGE
/* You need to define GOA_API_IS_SUBJECT_TO_CHANGE in order to use the GOA authoriser. */
diff --git a/gdata/meson.build b/gdata/meson.build
index ff14f81f..728bfc1f 100644
--- a/gdata/meson.build
+++ b/gdata/meson.build
@@ -27,7 +27,6 @@ headers = files(
'gdata-authorizer.h',
'gdata-batch-operation.h',
'gdata-batchable.h',
- 'gdata-client-login-authorizer.h',
'gdata-comment.h',
'gdata-commentable.h',
'gdata-comparable.h',
@@ -51,7 +50,6 @@ sources += files(
'gdata-batch-operation.c',
'gdata-batchable.c',
'gdata-buffer.c',
- 'gdata-client-login-authorizer.c',
'gdata-comment.c',
'gdata-commentable.c',
'gdata-comparable.c',
diff --git a/gdata/services/picasaweb/gdata-picasaweb-service.c b/gdata/services/picasaweb/gdata-picasaweb-service.c
index 89dcd7ac..1a9dc8ce 100644
--- a/gdata/services/picasaweb/gdata-picasaweb-service.c
+++ b/gdata/services/picasaweb/gdata-picasaweb-service.c
@@ -33,14 +33,13 @@
* <example>
* <title>Authenticating and Creating a New Album</title>
* <programlisting>
- * GDataClientLoginAuthorizer *authorizer;
+ * GDataAuthorizer *authorizer;
* GDataPicasaWebService *service;
* GDataPicasaWebAlbum *album, *inserted_album;
*
* /<!-- -->* Create a service object and authorize against the PicasaWeb service *<!-- -->/
- * authorizer = gdata_client_login_authorizer_new ("companyName-applicationName-versionID", GDATA_TYPE_PICASAWEB_SERVICE);
- * gdata_client_login_authorizer_authenticate (authorizer, username, password, NULL, NULL);
- * service = gdata_picasaweb_service_new (GDATA_AUTHORIZER (authorizer));
+ * authorizer = create_authorizer (…, gdata_picasaweb_service_get_primary_authorization_domain ());
+ * service = gdata_picasaweb_service_new (authorizer);
*
* /<!-- -->* Create a GDataPicasaWebAlbum entry for the new album, setting some information about it *<!-- -->/
* album = gdata_picasaweb_album_new (NULL);
diff --git a/gdata/symbol.map b/gdata/symbol.map
index eec13753..750055fa 100644
--- a/gdata/symbol.map
+++ b/gdata/symbol.map
@@ -129,23 +129,6 @@ global:
gdata_category_set_label;
gdata_category_set_scheme;
gdata_category_set_term;
- gdata_client_login_authorizer_authenticate;
- gdata_client_login_authorizer_authenticate_async;
- gdata_client_login_authorizer_authenticate_finish;
- gdata_client_login_authorizer_error_get_type;
- gdata_client_login_authorizer_error_quark;
- gdata_client_login_authorizer_get_client_id;
- gdata_client_login_authorizer_get_password;
- gdata_client_login_authorizer_get_proxy_resolver;
- gdata_client_login_authorizer_get_proxy_uri;
- gdata_client_login_authorizer_get_timeout;
- gdata_client_login_authorizer_get_type;
- gdata_client_login_authorizer_get_username;
- gdata_client_login_authorizer_new;
- gdata_client_login_authorizer_new_for_authorization_domains;
- gdata_client_login_authorizer_set_proxy_resolver;
- gdata_client_login_authorizer_set_proxy_uri;
- gdata_client_login_authorizer_set_timeout;
gdata_color_from_hexadecimal;
gdata_color_get_type;
gdata_color_to_hexadecimal;
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e42183c8..014dac90 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -2,7 +2,6 @@
# Please keep this file sorted alphabetically.
gdata/gdata-access-handler.c
gdata/gdata-batch-operation.c
-gdata/gdata-client-login-authorizer.c
gdata/gdata-commentable.c
gdata/gdata-download-stream.c
gdata/gdata-entry.c