GData plugin: Support cold-start

Store refresh token, and try to authorize Google access with it on
startup. Interactive authorization is now only the fallback if refreshing
cannot be done or was not successful.

Fixes bug #3432 but requires yet unreleased libgdata, see
https://bugzilla.gnome.org/show_bug.cgi?id=750746
This commit is contained in:
Holger Berndt 2015-06-14 21:45:16 +02:00
parent bee73785e5
commit aadb7d5405
6 changed files with 76 additions and 23 deletions

View File

@ -1114,7 +1114,7 @@ AC_CHECK_LIB([archive], [archive_read_new],
)
dnl libgdata *******************************************************************
PKG_CHECK_MODULES(GDATA, libgdata >= 0.17.1, HAVE_GDATA=yes, HAVE_GDATA=no)
PKG_CHECK_MODULES(GDATA, libgdata >= 0.17.2, HAVE_GDATA=yes, HAVE_GDATA=no)
AC_SUBST(GDATA_CFLAGS)
AC_SUBST(GDATA_LIBS)

View File

@ -430,11 +430,11 @@ static void query_after_auth()
}
static void cm_gdata_auth_ready(GDataOAuth2Authorizer *authorizer, GAsyncResult *res, gpointer data)
static void cm_gdata_auth_ready(GDataOAuth2Authorizer *auth, GAsyncResult *res, gpointer data)
{
GError *error = NULL;
if(gdata_oauth2_authorizer_request_authorization_finish(authorizer, res, &error) == FALSE)
if(gdata_oauth2_authorizer_request_authorization_finish(auth, res, &error) == FALSE)
{
/* Notify the user of all errors except cancellation errors */
if(!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
@ -451,6 +451,58 @@ static void cm_gdata_auth_ready(GDataOAuth2Authorizer *authorizer, GAsyncResult
query_after_auth();
}
static void cm_gdata_interactive_auth()
{
gchar *auth_uri;
gchar *auth_code;
log_message(LOG_PROTOCOL, _("GData plugin: Starting interactive authorization\n"));
auth_uri = gdata_oauth2_authorizer_build_authentication_uri(authorizer, cm_gdata_config.username, FALSE);
g_return_if_fail(auth_uri);
auth_code = ask_user_for_auth_code(auth_uri);
if(auth_code)
{
cm_gdata_contacts_query_running = TRUE;
log_message(LOG_PROTOCOL, _("GData plugin: Got authorization code, requesting authorization\n"));
gdata_oauth2_authorizer_request_authorization_async(authorizer, auth_code, NULL, (GAsyncReadyCallback)cm_gdata_auth_ready, NULL);
memset(auth_code, 0, strlen(auth_code));
g_free(auth_code);
}
else
{
log_warning(LOG_PROTOCOL, _("GData plugin: No authorization code received, authorization request cancelled\n"));
}
g_free(auth_uri);
}
static void cm_gdata_refresh_ready(GDataOAuth2Authorizer *auth, GAsyncResult *res, gpointer data)
{
GError *error = NULL;
if(gdata_authorizer_refresh_authorization_finish(GDATA_AUTHORIZER(auth), res, &error) == FALSE)
{
/* Notify the user of all errors except cancellation errors */
if(!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
{
log_error(LOG_PROTOCOL, _("GData plugin: Authorization refresh error: %s\n"), error->message);
}
g_error_free(error);
cm_gdata_interactive_auth();
return;
}
log_message(LOG_PROTOCOL, _("GData plugin: Authorization refresh successful\n"));
query_after_auth();
}
/* returns allocated string which must be freed */
static guchar* decode(const gchar *in)
{
@ -464,9 +516,6 @@ static guchar* decode(const gchar *in)
static void query()
{
gchar *auth_uri;
gchar *auth_code;
if(cm_gdata_contacts_query_running)
{
debug_print("GData plugin: Network query already in progress");
@ -475,6 +524,8 @@ static void query()
if(!authorizer)
{
GError *error = NULL;
gchar *c1 = decode(GDATA_C1);
gchar *c2 = decode(GDATA_C2);
gchar *c3 = decode(GDATA_C3);
@ -495,27 +546,17 @@ static void query()
if(!gdata_service_is_authorized(GDATA_SERVICE(service)))
{
log_message(LOG_PROTOCOL, _("GData plugin: Starting async authorization\n"));
auth_uri = gdata_oauth2_authorizer_build_authentication_uri(authorizer, cm_gdata_config.username, FALSE);
g_return_if_fail(auth_uri);
auth_code = ask_user_for_auth_code(auth_uri);
if(auth_code)
/* Try to restore from saved refresh token.*/
if(cm_gdata_config.oauth2_refresh_token)
{
cm_gdata_contacts_query_running = TRUE;
log_message(LOG_PROTOCOL, _("GData plugin: Got authorization code, requesting authorization\n"));
gdata_oauth2_authorizer_request_authorization_async(authorizer, auth_code, NULL, (GAsyncReadyCallback)cm_gdata_auth_ready, NULL);
memset(auth_code, 0, strlen(auth_code));
g_free(auth_code);
log_message(LOG_PROTOCOL, _("GData plugin: Trying to refresh authorization\n"));
gdata_oauth2_authorizer_set_refresh_token(authorizer, cm_gdata_config.oauth2_refresh_token);
gdata_authorizer_refresh_authorization_async(GDATA_AUTHORIZER(authorizer), NULL, (GAsyncReadyCallback)cm_gdata_refresh_ready, NULL);
}
else
{
log_warning(LOG_PROTOCOL, _("GData plugin: No authorization code received, authorization request cancelled\n"));
cm_gdata_interactive_auth();
}
g_free(auth_uri);
}
else
{
@ -579,6 +620,9 @@ void cm_gdata_contacts_done(void)
if(authorizer)
{
/* store refresh token */
cm_gdata_config.oauth2_refresh_token = gdata_oauth2_authorizer_dup_refresh_token(authorizer);
g_object_unref(G_OBJECT(authorizer));
authorizer = NULL;
}

View File

@ -56,6 +56,9 @@ PrefParam cm_gdata_param[] =
{ "max_cache_age", "300", &cm_gdata_config.max_cache_age, P_INT,
&gdata_page.spin_max_cache_age, prefs_set_data_from_spinbtn, prefs_set_spinbtn},
{"oauth2_refresh_token", NULL, &cm_gdata_config.oauth2_refresh_token, P_PASSWORD,
NULL, NULL, NULL},
{NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL }
};

View File

@ -25,6 +25,7 @@ typedef struct {
char *password;
int max_num_results;
int max_cache_age;
char *oauth2_refresh_token;
} CmGDataPrefs;
extern CmGDataPrefs cm_gdata_config;

View File

@ -41,6 +41,7 @@
<dependencies>
<dep package="glib"/>
<dep package="liboauth"/>
<dep package="m4-common"/>
</dependencies>
</autotools>
@ -50,6 +51,10 @@
md5sum="973ded7a1af348c5bfe4e3b6b7e47bd3"
size="459597"/>
</tarball>
<autotools id="m4-common">
<branch repo="github.com" module="desrt/m4-common.git"/>
</autotools>
<tarball id="libchamplain" version="0.8.3" makeargs="LDFLAGS='-lgthread-2.0'">
<source href="ftp://ftp.gnome.org/pub/GNOME/sources/libchamplain/0.8/libchamplain-0.8.3.tar.gz"

View File

@ -26,7 +26,7 @@ prefix = '/opt/claws-mail'
# module-specific autofoo args
#module_autogenargs['claws-mail'] = " ".join([autogenargs, "--disable-manual"])
#module_autogenargs['libgdata'] = " ".join([autogenargs, "--disable-tests"])
#module_autogenargs['libgdata'] = " ".join([autogenargs, "--disable-always-build-tests"])
# path for building (if None, build in-tree)
#buildroot = None