GData plugin: Support cold-start
authorHolger Berndt <hb@claws-mail.org>
Sun, 14 Jun 2015 19:45:16 +0000 (21:45 +0200)
committerHolger Berndt <hb@claws-mail.org>
Wed, 17 Jun 2015 22:33:48 +0000 (00:33 +0200)
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

configure.ac
src/plugins/gdata/cm_gdata_contacts.c
src/plugins/gdata/cm_gdata_prefs.c
src/plugins/gdata/cm_gdata_prefs.h
tools/jhbuild/claws-mail.modules
tools/jhbuild/sample.jhbuildrc-claws-mail

index d8e326014ff03fba205b63d7499cd5c8a1419407..716a75308ddef86e4d26480444dc7bf9903b2e5a 100644 (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)
 
index b8175e6cf7ff8323b25f8eae2a75ade85bccf1fb..00289d31e1a1fd3a1a9c17e10029fc195cdd1304 100644 (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;
   }
index 683706bfe499d9a03be812be71425f8ea86e8e7d..1e0614357665083029493ce9b55a97e7242ef133 100644 (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 }
 };
 
index 533bf00e25bbfec3014c56ad590bc698172c868d..adb767617bc4430fa4f2eb8b0e5571cbac29e8c4 100644 (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;
index c3c624819bbd8a840a51234206259bab1f00d568..40bdcca854b8fb5ea4c24574f431da3b6c9c411a 100644 (file)
@@ -41,6 +41,7 @@
                <dependencies>
                        <dep package="glib"/>
                        <dep package="liboauth"/>
+                       <dep package="m4-common"/>
                </dependencies>
        </autotools>
 
                        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"
index d271004afb3a1de50bca9e58d0c57adfca75a363..751d07b3b005b8503465d70d64e177dcffd85d9a 100644 (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