diff -up evolution-data-server-3.12.11/calendar/backends/caldav/e-cal-backend-caldav.c.caldav-daily-limit-exceeded evolution-data-server-3.12.11/calendar/backends/caldav/e-cal-backend-caldav.c --- evolution-data-server-3.12.11/calendar/backends/caldav/e-cal-backend-caldav.c.caldav-daily-limit-exceeded 2016-09-06 11:43:45.023286287 +0200 +++ evolution-data-server-3.12.11/calendar/backends/caldav/e-cal-backend-caldav.c 2016-09-06 11:45:13.838282462 +0200 @@ -130,7 +130,7 @@ struct _ECalBackendCalDAVPrivate { * message than a generic 401 description. */ GError *bearer_auth_error; GMutex bearer_auth_error_lock; - gboolean using_bearer_auth; + ESoupAuthBearer *using_bearer_auth; }; /* Forward Declarations */ @@ -597,7 +597,24 @@ status_code_to_result (SoupMessage *mess break; case SOUP_STATUS_FORBIDDEN: - g_propagate_error (perror, EDC_ERROR (AuthenticationRequired)); + if (cbdav->priv->using_bearer_auth && message->response_body && + message->response_body->data && message->response_body->length) { + gchar *body = g_strndup (message->response_body->data, message->response_body->length); + + /* Do not localize this string, it is returned by the server. */ + if (body && (e_util_strstrcase (body, "Daily Limit Exceeded") || + e_util_strstrcase (body, "https://console.developers.google.com/"))) { + /* Special-case this condition and provide this error up to the UI. */ + g_propagate_error (perror, + e_data_cal_create_error_fmt (OtherError, _("Failed to login to the server: %s"), body)); + } else { + g_propagate_error (perror, EDC_ERROR (AuthenticationRequired)); + } + + g_free (body); + } else { + g_propagate_error (perror, EDC_ERROR (AuthenticationRequired)); + } break; case SOUP_STATUS_UNAUTHORIZED: @@ -1044,7 +1061,11 @@ soup_authenticate (SoupSession *session, extension_name = E_SOURCE_EXTENSION_AUTHENTICATION; auth_extension = e_source_get_extension (source, extension_name); - cbdav->priv->using_bearer_auth = E_IS_SOUP_AUTH_BEARER (auth); + if (E_IS_SOUP_AUTH_BEARER (auth)) { + g_warn_if_fail ((gpointer) cbdav->priv->using_bearer_auth == (gpointer) auth); + g_clear_object (&cbdav->priv->using_bearer_auth); + cbdav->priv->using_bearer_auth = g_object_ref (auth); + } if (retrying || cbdav->priv->force_ask_password) { cbdav->priv->force_ask_password = !cbdav->priv->using_bearer_auth; @@ -1070,6 +1091,34 @@ soup_authenticate (SoupSession *session, /* ************************************************************************* */ /* direct CalDAV server access functions */ +static gboolean +caldav_backend_setup_bearer_auth (ECalBackendCalDAV *cbdav, + ESoupAuthBearer *bearer, + GCancellable *cancellable, + GError **error) +{ + ESource *source; + gchar *access_token = NULL; + gint expires_in_seconds = -1; + gboolean success; + + g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (cbdav), FALSE); + g_return_val_if_fail (E_IS_SOUP_AUTH_BEARER (bearer), FALSE); + + source = e_backend_get_source (E_BACKEND (cbdav)); + + success = e_source_get_oauth2_access_token_sync ( + source, cancellable, &access_token, + &expires_in_seconds, error); + + if (success) + e_soup_auth_bearer_set_access_token (bearer, access_token, expires_in_seconds); + + g_free (access_token); + + return success; +} + static void redirect_handler (SoupMessage *msg, gpointer user_data) @@ -1120,6 +1169,20 @@ send_and_handle_redirection (ECalBackend if (new_location) old_uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE); + if (cbdav->priv->using_bearer_auth && e_soup_auth_bearer_is_expired (cbdav->priv->using_bearer_auth)) { + GError *local_error = NULL; + + if (!caldav_backend_setup_bearer_auth (cbdav, cbdav->priv->using_bearer_auth, cancellable, &local_error)) { + if (local_error) { + soup_message_set_status_full (msg, SOUP_STATUS_BAD_REQUEST, local_error->message); + g_propagate_error (error, local_error); + } else { + soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST); + } + return; + } + } + soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT); soup_message_add_header_handler (msg, "got_body", "Location", G_CALLBACK (redirect_handler), cbdav->priv->session); soup_message_headers_append (msg->request_headers, "Connection", "close"); @@ -5238,6 +5301,7 @@ e_cal_backend_caldav_dispose (GObject *o g_clear_object (&priv->store); g_clear_object (&priv->session); + g_clear_object (&priv->using_bearer_auth); /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (parent_class)->dispose (object); @@ -5304,8 +5368,6 @@ caldav_backend_initable_init (GInitable ESourceWebdav *extension; SoupAuth *soup_auth; SoupURI *soup_uri; - gchar *access_token = NULL; - gint expires_in_seconds = -1; extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND; extension = e_source_get_extension (source, extension_name); @@ -5315,21 +5377,17 @@ caldav_backend_initable_init (GInitable E_TYPE_SOUP_AUTH_BEARER, SOUP_AUTH_HOST, soup_uri->host, NULL); - success = e_source_get_oauth2_access_token_sync ( - source, cancellable, &access_token, - &expires_in_seconds, error); + success = caldav_backend_setup_bearer_auth (E_CAL_BACKEND_CALDAV (initable), + E_SOUP_AUTH_BEARER (soup_auth), cancellable, error); if (success) { - e_soup_auth_bearer_set_access_token ( - E_SOUP_AUTH_BEARER (soup_auth), - access_token, expires_in_seconds); + priv->using_bearer_auth = g_object_ref (soup_auth); soup_auth_manager_use_auth ( SOUP_AUTH_MANAGER (feature), soup_uri, soup_auth); } - g_free (access_token); g_object_unref (soup_auth); soup_uri_free (soup_uri); } diff -up evolution-data-server-3.12.11/libebackend/e-soup-auth-bearer.c.caldav-daily-limit-exceeded evolution-data-server-3.12.11/libebackend/e-soup-auth-bearer.c --- evolution-data-server-3.12.11/libebackend/e-soup-auth-bearer.c.caldav-daily-limit-exceeded 2016-09-06 11:44:57.973283145 +0200 +++ evolution-data-server-3.12.11/libebackend/e-soup-auth-bearer.c 2016-09-06 11:45:13.839282462 +0200 @@ -52,17 +52,6 @@ G_DEFINE_TYPE ( e_soup_auth_bearer, SOUP_TYPE_AUTH) -static gboolean -e_soup_auth_bearer_is_expired (ESoupAuthBearer *bearer) -{ - gboolean expired = FALSE; - - if (bearer->priv->expiry != EXPIRY_INVALID) - expired = (bearer->priv->expiry < time (NULL)); - - return expired; -} - static void e_soup_auth_bearer_finalize (GObject *object) { @@ -193,3 +182,15 @@ e_soup_auth_bearer_set_access_token (ESo SOUP_AUTH_IS_AUTHENTICATED); } +gboolean +e_soup_auth_bearer_is_expired (ESoupAuthBearer *bearer) +{ + gboolean expired = TRUE; + + g_return_val_if_fail (E_IS_SOUP_AUTH_BEARER (bearer), TRUE); + + if (bearer->priv->expiry != EXPIRY_INVALID) + expired = (bearer->priv->expiry < time (NULL)); + + return expired; +} diff -up evolution-data-server-3.12.11/libebackend/e-soup-auth-bearer.h.caldav-daily-limit-exceeded evolution-data-server-3.12.11/libebackend/e-soup-auth-bearer.h --- evolution-data-server-3.12.11/libebackend/e-soup-auth-bearer.h.caldav-daily-limit-exceeded 2016-09-06 11:45:05.941282802 +0200 +++ evolution-data-server-3.12.11/libebackend/e-soup-auth-bearer.h 2016-09-06 11:45:13.839282462 +0200 @@ -71,6 +71,7 @@ void e_soup_auth_bearer_set_access_toke (ESoupAuthBearer *bearer, const gchar *access_token, gint expires_in_seconds); +gboolean e_soup_auth_bearer_is_expired (ESoupAuthBearer *bearer); G_END_DECLS