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 d8e3260..716a753 100644 (file)
@@ -1114,7 +1114,7 @@ AC_CHECK_LIB([archive], [archive_read_new],
                       )
 
 dnl libgdata *******************************************************************
                       )
 
 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)
 
 AC_SUBST(GDATA_CFLAGS)
 AC_SUBST(GDATA_LIBS)
 
index b8175e6..00289d3 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;
 
 {
   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))
   {
     /* 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();
 }
 
   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)
 {
 /* 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()
 {
 
 static void query()
 {
-  gchar *auth_uri;
-  gchar *auth_code;
-
   if(cm_gdata_contacts_query_running)
   {
     debug_print("GData plugin: Network query already in progress");
   if(cm_gdata_contacts_query_running)
   {
     debug_print("GData plugin: Network query already in progress");
@@ -475,6 +524,8 @@ static void query()
 
   if(!authorizer)
   {
 
   if(!authorizer)
   {
+    GError *error = NULL;
+
     gchar *c1 = decode(GDATA_C1);
     gchar *c2 = decode(GDATA_C2);
     gchar *c3 = decode(GDATA_C3);
     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)))
   {
 
   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
     {
     }
     else
     {
-      log_warning(LOG_PROTOCOL, _("GData plugin: No authorization code received, authorization request cancelled\n"));
+      cm_gdata_interactive_auth();
     }
     }
-
-    g_free(auth_uri);
   }
   else
   {
   }
   else
   {
@@ -579,6 +620,9 @@ void cm_gdata_contacts_done(void)
 
   if(authorizer)
   {
 
   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;
   }
     g_object_unref(G_OBJECT(authorizer));
     authorizer = NULL;
   }
index 683706b..1e06143 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},
 
     { "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 }
 };
 
     {NULL, NULL, NULL, P_OTHER, NULL, NULL, NULL }
 };
 
index 533bf00..adb7676 100644 (file)
@@ -25,6 +25,7 @@ typedef struct {
   char *password;
   int max_num_results;
   int max_cache_age;
   char *password;
   int max_num_results;
   int max_cache_age;
+  char *oauth2_refresh_token;
 } CmGDataPrefs;
 
 extern CmGDataPrefs cm_gdata_config;
 } CmGDataPrefs;
 
 extern CmGDataPrefs cm_gdata_config;
index c3c6248..40bdcca 100644 (file)
@@ -41,6 +41,7 @@
                <dependencies>
                        <dep package="glib"/>
                        <dep package="liboauth"/>
                <dependencies>
                        <dep package="glib"/>
                        <dep package="liboauth"/>
+                       <dep package="m4-common"/>
                </dependencies>
        </autotools>
 
                </dependencies>
        </autotools>
 
                        md5sum="973ded7a1af348c5bfe4e3b6b7e47bd3"
                        size="459597"/>
        </tarball>
                        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"
 
        <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 d271004..751d07b 100644 (file)
@@ -26,7 +26,7 @@ prefix = '/opt/claws-mail'
 
 # module-specific autofoo args
 #module_autogenargs['claws-mail'] = " ".join([autogenargs, "--disable-manual"])
 
 # 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
 
 # path for building (if None, build in-tree)
 #buildroot = None