1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2018 Red Hat, Inc. (www.redhat.com)
5 * This library is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 * SECTION: e-oauth2-service
20 * @include: libedataserver/libedataserver.h
21 * @short_description: An interface for an OAuth2 service
23 * An interface for an OAuth2 service. Any descendant might be defined
24 * as an extension of #EOAuth2Services and it should add itself into it
25 * with e_oauth2_services_add(). To make it easier, an #EOAuth2ServiceBase
26 * is provided for convenience.
29 #include "evolution-data-server-config.h"
32 #include <glib/gi18n-lib.h>
35 #include <json-glib/json-glib.h>
38 #include "e-secret-store.h"
39 #include "e-soup-ssl-trust.h"
40 #include "e-source-authentication.h"
41 #include "e-source-goa.h"
42 #include "e-source-uoa.h"
44 #include "e-oauth2-service.h"
46 G_DEFINE_INTERFACE (EOAuth2Service
, e_oauth2_service
, G_TYPE_OBJECT
)
49 eos_default_can_process (EOAuth2Service
*service
,
54 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
56 if (e_source_has_extension (source
, E_SOURCE_EXTENSION_GOA
) ||
57 e_source_has_extension (source
, E_SOURCE_EXTENSION_UOA
)) {
61 if (e_source_has_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
)) {
62 ESourceAuthentication
*auth_extension
;
65 auth_extension
= e_source_get_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
);
66 method
= e_source_authentication_dup_method (auth_extension
);
68 if (g_strcmp0 (method
, e_oauth2_service_get_name (service
)) == 0) {
80 eos_default_guess_can_process (EOAuth2Service
*service
,
81 const gchar
*protocol
,
82 const gchar
*hostname
)
87 gint ii
, name_len
, hostname_len
;
90 if (!hostname
|| !*hostname
)
93 name
= e_oauth2_service_get_name (service
);
94 g_return_val_if_fail (name
!= NULL
, FALSE
);
95 name_len
= strlen (name
);
96 hostname_len
= strlen (hostname
);
98 settings
= g_settings_new ("org.gnome.evolution-data-server");
99 values
= g_settings_get_strv (settings
, "oauth2-services-hint");
100 g_object_unref (settings
);
102 for (ii
= 0; !can
&& values
&& values
[ii
]; ii
++) {
103 const gchar
*line
= values
[ii
];
106 if (!g_str_has_prefix (line
, name
) ||
107 (line
[name_len
] != ':' && line
[name_len
] != '-'))
110 if (line
[name_len
] == '-') {
111 len
= protocol
? strlen (protocol
) : -1;
113 if (len
<= 0 || g_ascii_strncasecmp (line
+ name_len
+ 1, protocol
, len
) != 0 ||
114 line
[name_len
+ len
+ 1] != ':')
117 line
+= name_len
+ len
+ 2;
118 } else { /* line[name_len] == ':' */
119 line
+= name_len
+ 1;
122 while (line
&& *line
) {
123 if (g_ascii_strncasecmp (line
, hostname
, hostname_len
) == 0 &&
124 (line
[hostname_len
] == ',' || line
[hostname_len
] == '\0')) {
129 line
= strchr (line
, ',');
141 eos_default_get_flags (EOAuth2Service
*service
)
143 return E_OAUTH2_SERVICE_FLAG_NONE
;
147 eos_default_get_redirect_uri (EOAuth2Service
*service
,
150 return "urn:ietf:wg:oauth:2.0:oob";
154 eos_default_prepare_authentication_uri_query (EOAuth2Service
*service
,
156 GHashTable
*uri_query
)
158 e_oauth2_service_util_set_to_form (uri_query
, "response_type", "code");
159 e_oauth2_service_util_set_to_form (uri_query
, "client_id", e_oauth2_service_get_client_id (service
, source
));
160 e_oauth2_service_util_set_to_form (uri_query
, "redirect_uri", e_oauth2_service_get_redirect_uri (service
, source
));
162 if (e_source_has_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
)) {
163 ESourceAuthentication
*auth_extension
;
166 auth_extension
= e_source_get_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
);
167 user
= e_source_authentication_dup_user (auth_extension
);
170 e_oauth2_service_util_take_to_form (uri_query
, "login_hint", user
);
176 static EOAuth2ServiceNavigationPolicy
177 eos_default_get_authentication_policy (EOAuth2Service
*service
,
181 return E_OAUTH2_SERVICE_NAVIGATION_POLICY_ALLOW
;
185 eos_default_prepare_get_token_form (EOAuth2Service
*service
,
187 const gchar
*authorization_code
,
190 e_oauth2_service_util_set_to_form (form
, "code", authorization_code
);
191 e_oauth2_service_util_set_to_form (form
, "client_id", e_oauth2_service_get_client_id (service
, source
));
192 e_oauth2_service_util_set_to_form (form
, "client_secret", e_oauth2_service_get_client_secret (service
, source
));
193 e_oauth2_service_util_set_to_form (form
, "redirect_uri", e_oauth2_service_get_redirect_uri (service
, source
));
194 e_oauth2_service_util_set_to_form (form
, "grant_type", "authorization_code");
198 eos_default_prepare_get_token_message (EOAuth2Service
*service
,
200 SoupMessage
*message
)
205 eos_default_prepare_refresh_token_form (EOAuth2Service
*service
,
207 const gchar
*refresh_token
,
210 e_oauth2_service_util_set_to_form (form
, "refresh_token", refresh_token
);
211 e_oauth2_service_util_set_to_form (form
, "client_id", e_oauth2_service_get_client_id (service
, source
));
212 e_oauth2_service_util_set_to_form (form
, "client_secret", e_oauth2_service_get_client_secret (service
, source
));
213 e_oauth2_service_util_set_to_form (form
, "grant_type", "refresh_token");
217 eos_default_prepare_refresh_token_message (EOAuth2Service
*service
,
219 SoupMessage
*message
)
224 e_oauth2_service_default_init (EOAuth2ServiceInterface
*iface
)
226 iface
->can_process
= eos_default_can_process
;
227 iface
->guess_can_process
= eos_default_guess_can_process
;
228 iface
->get_flags
= eos_default_get_flags
;
229 iface
->get_redirect_uri
= eos_default_get_redirect_uri
;
230 iface
->prepare_authentication_uri_query
= eos_default_prepare_authentication_uri_query
;
231 iface
->get_authentication_policy
= eos_default_get_authentication_policy
;
232 iface
->prepare_get_token_form
= eos_default_prepare_get_token_form
;
233 iface
->prepare_get_token_message
= eos_default_prepare_get_token_message
;
234 iface
->prepare_refresh_token_form
= eos_default_prepare_refresh_token_form
;
235 iface
->prepare_refresh_token_message
= eos_default_prepare_refresh_token_message
;
239 * e_oauth2_service_can_process:
240 * @service: an #EOAuth2Service
241 * @source: an #ESource
243 * Checks whether the @service can be used with the given @source.
245 * The default implementation checks whether the @source has an #ESourceAuthentication
246 * extension and when its method matches e_oauth2_service_get_name(), then it automatically
247 * returns %TRUE. Contrary, when the @source contains GNOME Online Accounts or Ubuntu
248 * Online Accounts extension, then it returns %FALSE.
250 * The default implementation is tried always as the first and when it fails, then
251 * the descendant's implementation is called.
253 * Returns: Whether the @service can be used for the given @source
258 e_oauth2_service_can_process (EOAuth2Service
*service
,
261 EOAuth2ServiceInterface
*iface
;
263 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
264 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
266 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
267 g_return_val_if_fail (iface
!= NULL
, FALSE
);
268 g_return_val_if_fail (iface
->can_process
!= NULL
, FALSE
);
270 if (eos_default_can_process (service
, source
))
273 return iface
->can_process
!= eos_default_can_process
&&
274 iface
->can_process (service
, source
);
278 * e_oauth2_service_guess_can_process:
279 * @service: an #EOAuth2Service
280 * @protocol: (nullable): a protocol to search the service for, like "imap", or %NULL
281 * @hostname: (nullable): a host name to search the service for, like "server.example.com", or %NULL
283 * Checks whether the @service can be used with the given @protocol and/or @hostname.
284 * Any of @protocol and @hostname can be %NULL, but not both. It's up to each implementer
285 * to decide, which of the arguments are important and whether all or only any of them
288 * The function is meant to check whether the @service can be offered
289 * for example when configuring a new account. The real usage is
290 * determined by e_oauth2_service_can_process().
292 * The default implementation consults org.gnome.evolution-data-server.oauth2-services-hint
293 * GSettings key against given hostname. See its description for more information.
295 * The default implementation is tried always as the first and when it fails, then
296 * the descendant's implementation is called.
298 * Returns: Whether the @service can be used for the given arguments
303 e_oauth2_service_guess_can_process (EOAuth2Service
*service
,
304 const gchar
*protocol
,
305 const gchar
*hostname
)
307 EOAuth2ServiceInterface
*iface
;
309 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
310 g_return_val_if_fail (protocol
|| hostname
, FALSE
);
312 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
313 g_return_val_if_fail (iface
!= NULL
, FALSE
);
314 g_return_val_if_fail (iface
->guess_can_process
!= NULL
, FALSE
);
316 if (eos_default_guess_can_process (service
, protocol
, hostname
))
319 return iface
->guess_can_process
!= eos_default_guess_can_process
&&
320 iface
->guess_can_process (service
, protocol
, hostname
);
324 * e_oauth2_service_get_flags:
325 * @service: an #EOAuth2Service
327 * Returns: bit-or of #EOAuth2ServiceFlags for the @service. The default
328 * implementation returns %E_OAUTH2_SERVICE_FLAG_NONE.
333 e_oauth2_service_get_flags (EOAuth2Service
*service
)
335 EOAuth2ServiceInterface
*iface
;
337 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), E_OAUTH2_SERVICE_FLAG_NONE
);
339 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
340 g_return_val_if_fail (iface
!= NULL
, E_OAUTH2_SERVICE_FLAG_NONE
);
341 g_return_val_if_fail (iface
->get_flags
!= NULL
, E_OAUTH2_SERVICE_FLAG_NONE
);
343 return iface
->get_flags (service
);
347 * e_oauth2_service_get_name:
348 * @service: an #EOAuth2Service
350 * Returns a unique name of the service. It can be named for example
351 * by the server or the company from which it receives the OAuth2
352 * token and where it refreshes it, like "Company" for login.company.com.
354 * Returns: the name of the @service
359 e_oauth2_service_get_name (EOAuth2Service
*service
)
361 EOAuth2ServiceInterface
*iface
;
363 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), NULL
);
365 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
366 g_return_val_if_fail (iface
!= NULL
, NULL
);
367 g_return_val_if_fail (iface
->get_name
!= NULL
, NULL
);
369 return iface
->get_name (service
);
373 * e_oauth2_service_get_display_name:
374 * @service: an #EOAuth2Service
376 * Returns a human readable name of the service. This is similar to
377 * e_oauth2_service_get_name(), except this string should be localized,
378 * because it will be used in user-visible strings.
380 * Returns: the display name of the @service
385 e_oauth2_service_get_display_name (EOAuth2Service
*service
)
387 EOAuth2ServiceInterface
*iface
;
389 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), NULL
);
391 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
392 g_return_val_if_fail (iface
!= NULL
, NULL
);
393 g_return_val_if_fail (iface
->get_display_name
!= NULL
, NULL
);
395 return iface
->get_display_name (service
);
399 * e_oauth2_service_get_client_id:
400 * @service: an #EOAuth2Service
401 * @source: an associated #ESource
403 * Returns: application client ID, as provided by the server
408 e_oauth2_service_get_client_id (EOAuth2Service
*service
,
411 EOAuth2ServiceInterface
*iface
;
413 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), NULL
);
414 g_return_val_if_fail (E_IS_SOURCE (source
), NULL
);
416 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
417 g_return_val_if_fail (iface
!= NULL
, NULL
);
418 g_return_val_if_fail (iface
->get_client_id
!= NULL
, NULL
);
420 return iface
->get_client_id (service
, source
);
424 * e_oauth2_service_get_client_secret:
425 * @service: an #EOAuth2Service
426 * @source: an associated #ESource
428 * Returns: (nullable): application client secret, as provided by the server, or %NULL
433 e_oauth2_service_get_client_secret (EOAuth2Service
*service
,
436 EOAuth2ServiceInterface
*iface
;
438 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), NULL
);
439 g_return_val_if_fail (E_IS_SOURCE (source
), NULL
);
441 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
442 g_return_val_if_fail (iface
!= NULL
, NULL
);
443 g_return_val_if_fail (iface
->get_client_secret
!= NULL
, NULL
);
445 return iface
->get_client_secret (service
, source
);
449 * e_oauth2_service_get_authentication_uri:
450 * @service: an #EOAuth2Service
451 * @source: an associated #ESource
453 * Returns: an authentication URI, to be used to obtain
454 * the authentication code
459 e_oauth2_service_get_authentication_uri (EOAuth2Service
*service
,
462 EOAuth2ServiceInterface
*iface
;
464 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), NULL
);
465 g_return_val_if_fail (E_IS_SOURCE (source
), NULL
);
467 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
468 g_return_val_if_fail (iface
!= NULL
, NULL
);
469 g_return_val_if_fail (iface
->get_authentication_uri
!= NULL
, NULL
);
471 return iface
->get_authentication_uri (service
, source
);
475 * e_oauth2_service_get_refresh_uri:
476 * @service: an #EOAuth2Service
477 * @source: an associated #ESource
479 * Returns: a URI to be used to refresh the authentication token
484 e_oauth2_service_get_refresh_uri (EOAuth2Service
*service
,
487 EOAuth2ServiceInterface
*iface
;
489 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), NULL
);
490 g_return_val_if_fail (E_IS_SOURCE (source
), NULL
);
492 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
493 g_return_val_if_fail (iface
!= NULL
, NULL
);
494 g_return_val_if_fail (iface
->get_refresh_uri
!= NULL
, NULL
);
496 return iface
->get_refresh_uri (service
, source
);
500 * e_oauth2_service_get_redirect_uri:
501 * @service: an #EOAuth2Service
502 * @source: an associated #ESource
504 * Returns a value for the "redirect_uri" keys in the authenticate and get_token
505 * operations. The default implementation returns "urn:ietf:wg:oauth:2.0:oob".
507 * Returns: (nullable): The redirect_uri to use, or %NULL for none
512 e_oauth2_service_get_redirect_uri (EOAuth2Service
*service
,
515 EOAuth2ServiceInterface
*iface
;
517 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), NULL
);
518 g_return_val_if_fail (E_IS_SOURCE (source
), NULL
);
520 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
521 g_return_val_if_fail (iface
!= NULL
, NULL
);
522 g_return_val_if_fail (iface
->get_redirect_uri
!= NULL
, NULL
);
524 return iface
->get_redirect_uri (service
, source
);
528 * e_oauth2_service_prepare_authentication_uri_query:
529 * @service: an #EOAuth2Service
530 * @source: an associated #ESource
531 * @uri_query: (element-type utf8 utf8): query for the URI to use
533 * The @service can change what arguments are passed in the authentication URI
534 * in this method. The default implementation sets some values too, namely
535 * "response_type", "client_id", "redirect_uri" and "login_hint", if available
536 * in the @source. These parameters are always provided, even when the interface
537 * implementer overrides this method.
539 * The @uri_query hash table expects both key and value to be newly allocated
540 * strings, which will be freed together with the hash table or when the key
546 e_oauth2_service_prepare_authentication_uri_query (EOAuth2Service
*service
,
548 GHashTable
*uri_query
)
550 EOAuth2ServiceInterface
*iface
;
552 g_return_if_fail (E_IS_OAUTH2_SERVICE (service
));
553 g_return_if_fail (E_IS_SOURCE (source
));
554 g_return_if_fail (uri_query
!= NULL
);
556 eos_default_prepare_authentication_uri_query (service
, source
, uri_query
);
558 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
559 g_return_if_fail (iface
!= NULL
);
560 g_return_if_fail (iface
->prepare_authentication_uri_query
!= NULL
);
562 if (iface
->prepare_authentication_uri_query
!= eos_default_prepare_authentication_uri_query
)
563 iface
->prepare_authentication_uri_query (service
, source
, uri_query
);
567 * e_oauth2_service_get_authentication_policy:
568 * @service: an #EOAuth2Service
569 * @source: an associated #ESource
570 * @uri: a URI of the navigation resource
572 * Used to decide what to do when the server redirects to the next page.
573 * The default implementation always returns %E_OAUTH2_SERVICE_NAVIGATION_POLICY_ALLOW.
575 * This method is called before e_oauth2_service_extract_authorization_code() and
576 * can be used to block certain resources or to abort the authentication when
577 * the server redirects to an unexpected page (like when user denies authorization
580 * Returns: one of #EOAuth2ServiceNavigationPolicy
584 EOAuth2ServiceNavigationPolicy
585 e_oauth2_service_get_authentication_policy (EOAuth2Service
*service
,
589 EOAuth2ServiceInterface
*iface
;
591 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), E_OAUTH2_SERVICE_NAVIGATION_POLICY_ABORT
);
592 g_return_val_if_fail (E_IS_SOURCE (source
), E_OAUTH2_SERVICE_NAVIGATION_POLICY_ABORT
);
593 g_return_val_if_fail (uri
!= NULL
, E_OAUTH2_SERVICE_NAVIGATION_POLICY_ABORT
);
595 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
596 g_return_val_if_fail (iface
!= NULL
, E_OAUTH2_SERVICE_NAVIGATION_POLICY_ABORT
);
597 g_return_val_if_fail (iface
->get_authentication_policy
!= NULL
, E_OAUTH2_SERVICE_NAVIGATION_POLICY_ABORT
);
599 return iface
->get_authentication_policy (service
, source
, uri
);
603 * e_oauth2_service_extract_authorization_code:
604 * @service: an #EOAuth2Service
605 * @source: an associated #ESource
606 * @page_title: a web page title
607 * @page_uri: a web page URI
608 * @page_content: (nullable): a web page content
609 * @out_authorization_code: (out) (transfer full): the extracted authorization code
611 * Tries to extract an authorization code from a web page provided by the server.
612 * The function can be called multiple times, whenever the page load is finished.
614 * There can happen three states: 1) either the @service cannot determine
615 * the authentication code from the page information, then the %FALSE is
616 * returned and the @out_authorization_code is left untouched; or 2) the server
617 * reported a failure, in which case the function returns %TRUE and lefts
618 * the @out_authorization_code untouched; or 3) the @service could extract
619 * the authentication code from the given arguments, then the function
620 * returns %TRUE and sets the received authorization code to @out_authorization_code.
622 * The @page_content is %NULL, unless flags returned by e_oauth2_service_get_flags()
623 * contain also %E_OAUTH2_SERVICE_FLAG_EXTRACT_REQUIRES_PAGE_CONTENT.
625 * This method is always called after e_oauth2_service_get_authentication_policy().
627 * Returns: whether could recognized successful or failed server response.
628 * The @out_authorization_code is populated on success too.
633 e_oauth2_service_extract_authorization_code (EOAuth2Service
*service
,
635 const gchar
*page_title
,
636 const gchar
*page_uri
,
637 const gchar
*page_content
,
638 gchar
**out_authorization_code
)
640 EOAuth2ServiceInterface
*iface
;
642 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
643 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
645 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
646 g_return_val_if_fail (iface
!= NULL
, FALSE
);
647 g_return_val_if_fail (iface
->extract_authorization_code
!= NULL
, FALSE
);
649 return iface
->extract_authorization_code (service
, source
, page_title
, page_uri
, page_content
, out_authorization_code
);
653 * e_oauth2_service_prepare_get_token_form:
654 * @service: an #EOAuth2Service
655 * @source: an associated #ESource
656 * @authorization_code: authorization code, as returned from e_oauth2_service_extract_authorization_code()
657 * @form: (element-type utf8 utf8): form parameters to be used in the POST request
659 * Sets additional form parameters to be used in the POST request when requesting
660 * access token after successfully obtained authorization code.
661 * The default implementation sets some values too, namely
662 * "code", "client_id", "client_secret", "redirect_uri" and "grant_type".
663 * These parameters are always provided, even when the interface implementer overrides this method.
665 * The @form hash table expects both key and value to be newly allocated
666 * strings, which will be freed together with the hash table or when the key
672 e_oauth2_service_prepare_get_token_form (EOAuth2Service
*service
,
674 const gchar
*authorization_code
,
677 EOAuth2ServiceInterface
*iface
;
679 g_return_if_fail (E_IS_OAUTH2_SERVICE (service
));
680 g_return_if_fail (E_IS_SOURCE (source
));
681 g_return_if_fail (authorization_code
!= NULL
);
682 g_return_if_fail (form
!= NULL
);
684 eos_default_prepare_get_token_form (service
, source
, authorization_code
, form
);
686 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
687 g_return_if_fail (iface
!= NULL
);
688 g_return_if_fail (iface
->prepare_get_token_form
!= NULL
);
690 if (iface
->prepare_get_token_form
!= eos_default_prepare_get_token_form
)
691 iface
->prepare_get_token_form (service
, source
, authorization_code
, form
);
695 * e_oauth2_service_prepare_get_token_message:
696 * @service: an #EOAuth2Service
697 * @source: an associated #ESource
698 * @message: a #SoupMessage
700 * The @service can change the @message before it's sent to
701 * the e_oauth2_service_get_authentication_uri(), with POST data
702 * being provided by e_oauth2_service_prepare_get_token_form().
703 * The default implementation does nothing with the @message.
708 e_oauth2_service_prepare_get_token_message (EOAuth2Service
*service
,
710 SoupMessage
*message
)
712 EOAuth2ServiceInterface
*iface
;
714 g_return_if_fail (E_IS_OAUTH2_SERVICE (service
));
715 g_return_if_fail (E_IS_SOURCE (source
));
716 g_return_if_fail (SOUP_IS_MESSAGE (message
));
718 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
719 g_return_if_fail (iface
!= NULL
);
720 g_return_if_fail (iface
->prepare_get_token_message
!= NULL
);
722 iface
->prepare_get_token_message (service
, source
, message
);
726 * e_oauth2_service_prepare_refresh_token_form:
727 * @service: an #EOAuth2Service
728 * @source: an associated #ESource
729 * @refresh_token: a refresh token to be used
730 * @form: (element-type utf8 utf8): form parameters to be used in the POST request
732 * Sets additional form parameters to be used in the POST request when requesting
733 * to refresh an access token.
734 * The default implementation sets some values too, namely
735 * "refresh_token", "client_id", "client_secret" and "grant_type".
736 * These parameters are always provided, even when the interface implementer overrides this method.
738 * The @form hash table expects both key and value to be newly allocated
739 * strings, which will be freed together with the hash table or when the key
745 e_oauth2_service_prepare_refresh_token_form (EOAuth2Service
*service
,
747 const gchar
*refresh_token
,
750 EOAuth2ServiceInterface
*iface
;
752 g_return_if_fail (E_IS_OAUTH2_SERVICE (service
));
753 g_return_if_fail (E_IS_SOURCE (source
));
754 g_return_if_fail (refresh_token
!= NULL
);
755 g_return_if_fail (form
!= NULL
);
757 eos_default_prepare_refresh_token_form (service
, source
, refresh_token
, form
);
759 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
760 g_return_if_fail (iface
!= NULL
);
761 g_return_if_fail (iface
->prepare_refresh_token_form
!= NULL
);
763 if (iface
->prepare_refresh_token_form
!= eos_default_prepare_refresh_token_form
)
764 iface
->prepare_refresh_token_form (service
, source
, refresh_token
, form
);
768 * e_oauth2_service_prepare_refresh_token_message:
769 * @service: an #EOAuth2Service
770 * @source: an associated #ESource
771 * @message: a #SoupMessage
773 * The @service can change the @message before it's sent to
774 * the e_oauth2_service_get_refresh_uri(), with POST data
775 * being provided by e_oauth2_service_prepare_refresh_token_form().
776 * The default implementation does nothing with the @message.
781 e_oauth2_service_prepare_refresh_token_message (EOAuth2Service
*service
,
783 SoupMessage
*message
)
785 EOAuth2ServiceInterface
*iface
;
787 g_return_if_fail (E_IS_OAUTH2_SERVICE (service
));
788 g_return_if_fail (E_IS_SOURCE (source
));
789 g_return_if_fail (SOUP_IS_MESSAGE (message
));
791 iface
= E_OAUTH2_SERVICE_GET_INTERFACE (service
);
792 g_return_if_fail (iface
!= NULL
);
793 g_return_if_fail (iface
->prepare_refresh_token_message
!= NULL
);
795 iface
->prepare_refresh_token_message (service
, source
, message
);
799 eos_create_soup_session (EOAuth2ServiceRefSourceFunc ref_source
,
800 gpointer ref_source_user_data
,
803 static gint oauth2_debug
= -1;
804 ESourceAuthentication
*auth_extension
;
805 ESource
*proxy_source
= NULL
;
806 SoupSession
*session
;
809 if (oauth2_debug
== -1)
810 oauth2_debug
= g_strcmp0 (g_getenv ("OAUTH2_DEBUG"), "1") == 0 ? 1 : 0;
812 session
= soup_session_new ();
815 SOUP_SESSION_TIMEOUT
, 90,
816 SOUP_SESSION_SSL_STRICT
, TRUE
,
817 SOUP_SESSION_SSL_USE_SYSTEM_CA_FILE
, TRUE
,
818 SOUP_SESSION_ACCEPT_LANGUAGE_AUTO
, TRUE
,
824 logger
= soup_logger_new (SOUP_LOGGER_LOG_BODY
, -1);
825 soup_session_add_feature (session
, SOUP_SESSION_FEATURE (logger
));
826 g_object_unref (logger
);
829 if (!e_source_has_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
))
832 auth_extension
= e_source_get_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
);
833 uid
= e_source_authentication_dup_proxy_uid (auth_extension
);
835 proxy_source
= ref_source (ref_source_user_data
, uid
);
841 GProxyResolver
*proxy_resolver
;
843 proxy_resolver
= G_PROXY_RESOLVER (proxy_source
);
844 if (g_proxy_resolver_is_supported (proxy_resolver
))
845 g_object_set (session
, SOUP_SESSION_PROXY_RESOLVER
, proxy_resolver
, NULL
);
847 g_object_unref (proxy_source
);
854 eos_create_soup_message (ESource
*source
,
856 GHashTable
*post_form
)
858 SoupMessage
*message
;
861 g_return_val_if_fail (E_IS_SOURCE (source
), NULL
);
862 g_return_val_if_fail (uri
!= NULL
, NULL
);
863 g_return_val_if_fail (post_form
!= NULL
, NULL
);
865 message
= soup_message_new (SOUP_METHOD_POST
, uri
);
866 g_return_val_if_fail (message
!= NULL
, NULL
);
868 post_data
= soup_form_encode_hash (post_form
);
870 g_warn_if_fail (post_data
!= NULL
);
871 g_object_unref (message
);
876 soup_message_set_request (message
, "application/x-www-form-urlencoded",
877 SOUP_MEMORY_TAKE
, post_data
, strlen (post_data
));
879 e_soup_ssl_trust_connect (message
, source
);
881 soup_message_headers_append (message
->request_headers
, "Connection", "close");
887 eos_abort_session_cb (GCancellable
*cancellable
,
888 SoupSession
*session
)
890 soup_session_abort (session
);
894 eos_send_message (SoupSession
*session
,
895 SoupMessage
*message
,
896 gchar
**out_response_body
,
897 GCancellable
*cancellable
,
900 guint status_code
= SOUP_STATUS_CANCELLED
;
901 gboolean success
= FALSE
;
903 g_return_val_if_fail (SOUP_IS_SESSION (session
), FALSE
);
904 g_return_val_if_fail (SOUP_IS_MESSAGE (message
), FALSE
);
905 g_return_val_if_fail (out_response_body
!= NULL
, FALSE
);
907 if (!g_cancellable_set_error_if_cancelled (cancellable
, error
)) {
908 gulong cancel_handler_id
= 0;
911 cancel_handler_id
= g_cancellable_connect (cancellable
, G_CALLBACK (eos_abort_session_cb
), session
, NULL
);
913 status_code
= soup_session_send_message (session
, message
);
915 if (cancel_handler_id
)
916 g_cancellable_disconnect (cancellable
, cancel_handler_id
);
919 if (SOUP_STATUS_IS_SUCCESSFUL (status_code
)) {
920 if (message
->response_body
) {
921 *out_response_body
= g_strndup (message
->response_body
->data
, message
->response_body
->length
);
924 status_code
= SOUP_STATUS_MALFORMED
;
926 } else if (status_code
!= SOUP_STATUS_CANCELLED
) {
929 error_msg
= g_string_new (message
->reason_phrase
);
930 if (message
->response_body
&& message
->response_body
->length
) {
931 g_string_append (error_msg
, " (");
932 g_string_append_len (error_msg
, message
->response_body
->data
, message
->response_body
->length
);
933 g_string_append (error_msg
, ")");
936 g_set_error_literal (error
, SOUP_HTTP_ERROR
, message
->status_code
, error_msg
->str
);
938 g_string_free (error_msg
, TRUE
);
945 eos_generate_secret_uid (EOAuth2Service
*service
,
949 ESourceAuthentication
*authentication_extension
;
952 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
953 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
958 if (!e_source_has_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
))
961 authentication_extension
= e_source_get_extension (source
, E_SOURCE_EXTENSION_AUTHENTICATION
);
962 user
= e_source_authentication_dup_user (authentication_extension
);
963 if (!user
|| !*user
) {
969 *out_uid
= g_strdup_printf ("OAuth2::%s[%s]", e_oauth2_service_get_name (service
), user
);
977 eos_encode_to_secret (gchar
**out_secret
,
978 const gchar
*key1_name
,
980 ...) G_GNUC_NULL_TERMINATED
;
983 eos_encode_to_secret (gchar
**out_secret
,
984 const gchar
*key1_name
,
989 JsonBuilder
*builder
;
991 const gchar
*key
, *value
;
994 g_return_val_if_fail (out_secret
!= NULL
, FALSE
);
995 g_return_val_if_fail (key1_name
!= NULL
, FALSE
);
996 g_return_val_if_fail (value1
!= NULL
, FALSE
);
1000 builder
= json_builder_new ();
1002 va_start (va
, value1
);
1006 json_builder_begin_object (builder
);
1008 while (key
&& value
) {
1009 json_builder_set_member_name (builder
, key
);
1010 json_builder_add_string_value (builder
, value
);
1012 key
= va_arg (va
, const gchar
*);
1016 value
= va_arg (va
, const gchar
*);
1017 g_warn_if_fail (value
!= NULL
);
1022 json_builder_end_object (builder
);
1023 node
= json_builder_get_root (builder
);
1025 g_object_unref (builder
);
1028 JsonGenerator
*generator
;
1030 generator
= json_generator_new ();
1031 json_generator_set_root (generator
, node
);
1033 *out_secret
= json_generator_to_data (generator
, NULL
);
1035 g_object_unref (generator
);
1036 json_node_free (node
);
1039 return *out_secret
!= NULL
;
1046 eos_decode_from_secret (const gchar
*secret
,
1047 const gchar
*key1_name
,
1049 ...) G_GNUC_NULL_TERMINATED
;
1052 eos_decode_from_secret (const gchar
*secret
,
1053 const gchar
*key1_name
,
1057 #ifdef ENABLE_OAUTH2
1063 GError
*error
= NULL
;
1065 g_return_val_if_fail (key1_name
!= NULL
, FALSE
);
1066 g_return_val_if_fail (out_value1
!= NULL
, FALSE
);
1068 if (!secret
|| !*secret
)
1071 parser
= json_parser_new ();
1072 if (!json_parser_load_from_data (parser
, secret
, -1, &error
)) {
1073 g_object_unref (parser
);
1075 g_debug ("%s: Failed to parse secret '%s': %s", G_STRFUNC
, secret
, error
? error
->message
: "Unknown error");
1076 g_clear_error (&error
);
1081 reader
= json_reader_new (json_parser_get_root (parser
));
1083 out_value
= out_value1
;
1085 va_start (va
, out_value1
);
1087 while (key
&& out_value
) {
1090 if (json_reader_read_member (reader
, key
)) {
1091 *out_value
= g_strdup (json_reader_get_string_value (reader
));
1093 const GError
*reader_error
= json_reader_get_error (reader
);
1095 if (g_error_matches (reader_error
, JSON_READER_ERROR
, JSON_READER_ERROR_INVALID_TYPE
)) {
1098 json_reader_end_member (reader
);
1100 iv64
= json_reader_get_int_value (reader
);
1102 if (!json_reader_get_error (reader
))
1103 *out_value
= g_strdup_printf ("%" G_GINT64_FORMAT
, iv64
);
1107 if (*out_value
&& !**out_value
) {
1108 g_free (*out_value
);
1113 json_reader_end_member (reader
);
1115 key
= va_arg (va
, const gchar
*);
1119 out_value
= va_arg (va
, gchar
**);
1120 g_warn_if_fail (out_value
!= NULL
);
1123 g_object_unref (reader
);
1124 g_object_unref (parser
);
1134 eos_store_token_sync (EOAuth2Service
*service
,
1136 const gchar
*refresh_token
,
1137 const gchar
*access_token
,
1138 const gchar
*expires_in
,
1139 GCancellable
*cancellable
,
1142 gint64 expires_after_tm
;
1143 gchar
*expires_after
, *secret
= NULL
, *uid
= NULL
;
1144 gboolean success
= FALSE
;
1146 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
1148 if (!refresh_token
|| !access_token
|| !expires_in
)
1151 if (g_cancellable_set_error_if_cancelled (cancellable
, error
))
1154 expires_after_tm
= g_get_real_time () / G_USEC_PER_SEC
;
1155 expires_after_tm
+= g_ascii_strtoll (expires_in
, NULL
, 10);
1156 expires_after
= g_strdup_printf ("%" G_GINT64_FORMAT
, expires_after_tm
);
1158 if (eos_encode_to_secret (&secret
,
1159 E_OAUTH2_SECRET_REFRESH_TOKEN
, refresh_token
,
1160 E_OAUTH2_SECRET_ACCESS_TOKEN
, access_token
,
1161 E_OAUTH2_SECRET_EXPIRES_AFTER
, expires_after
, NULL
) &&
1162 eos_generate_secret_uid (service
, source
, &uid
)) {
1165 label
= g_strdup_printf ("Evolution Data Source - %s", strstr (uid
, "::") + 2);
1167 success
= e_secret_store_store_sync (uid
, secret
, label
, TRUE
, cancellable
, error
);
1174 g_free (expires_after
);
1179 /* Can return success when the access token is already expired and refresh token is available */
1181 eos_lookup_token_sync (EOAuth2Service
*service
,
1183 gchar
**out_refresh_token
,
1184 gchar
**out_access_token
,
1185 gint
*out_expires_in
,
1186 GCancellable
*cancellable
,
1189 gchar
*secret
= NULL
, *uid
= NULL
, *expires_after
= NULL
;
1190 gboolean success
= FALSE
;
1192 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
1193 g_return_val_if_fail (out_refresh_token
!= NULL
, FALSE
);
1194 g_return_val_if_fail (out_access_token
!= NULL
, FALSE
);
1195 g_return_val_if_fail (out_expires_in
!= NULL
, FALSE
);
1197 *out_refresh_token
= NULL
;
1198 *out_access_token
= NULL
;
1199 *out_expires_in
= -1;
1201 if (g_cancellable_set_error_if_cancelled (cancellable
, error
))
1204 if (!eos_generate_secret_uid (service
, source
, &uid
)) {
1205 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
1206 /* Translators: The first %s is a display name of the source, the second is its UID and
1207 the third is the name of the OAuth service. */
1208 _("Source ā%sā (%s) is not valid for ā%sā OAuth2 service"),
1209 e_source_get_display_name (source
),
1210 e_source_get_uid (source
),
1211 e_oauth2_service_get_name (service
));
1215 if (!e_secret_store_lookup_sync (uid
, &secret
, cancellable
, error
)) {
1223 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_NOT_FOUND
, _("OAuth2 secret not found"));
1227 success
= eos_decode_from_secret (secret
,
1228 E_OAUTH2_SECRET_REFRESH_TOKEN
, out_refresh_token
,
1229 E_OAUTH2_SECRET_ACCESS_TOKEN
, out_access_token
,
1230 E_OAUTH2_SECRET_EXPIRES_AFTER
, &expires_after
,
1233 if (success
&& expires_after
) {
1234 gint64 num_expires_after
, num_now
;
1236 num_expires_after
= g_ascii_strtoll (expires_after
, NULL
, 10);
1237 num_now
= g_get_real_time () / G_USEC_PER_SEC
;
1239 if (num_now
< num_expires_after
)
1240 *out_expires_in
= num_expires_after
- num_now
- 1;
1243 e_util_safe_free_string (secret
);
1244 g_free (expires_after
);
1246 return success
&& *out_refresh_token
!= NULL
;
1250 * e_oauth2_service_receive_and_store_token_sync:
1251 * @service: an #EOAuth2Service
1252 * @source: an #ESource
1253 * @authorization_code: authorization code provided by the server
1254 * @ref_source: (scope call): an #EOAuth2ServiceRefSourceFunc function to obtain an #ESource
1255 * @ref_source_user_data user data for @ref_source
1256 * @cancellable: optional #GCancellable object, or %NULL
1257 * @error: return location for a #GError, or %NULL
1259 * Queries @service at e_oauth2_service_get_refresh_uri() with a request to obtain
1260 * a new access token, associated with the given @authorization_code and stores
1261 * it into the secret store on success.
1263 * Returns: whether succeeded
1268 e_oauth2_service_receive_and_store_token_sync (EOAuth2Service
*service
,
1270 const gchar
*authorization_code
,
1271 EOAuth2ServiceRefSourceFunc ref_source
,
1272 gpointer ref_source_user_data
,
1273 GCancellable
*cancellable
,
1276 SoupSession
*session
;
1277 SoupMessage
*message
;
1278 GHashTable
*post_form
;
1279 gchar
*response_json
= NULL
;
1282 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
1283 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
1284 g_return_val_if_fail (authorization_code
!= NULL
, FALSE
);
1285 g_return_val_if_fail (ref_source
!= NULL
, FALSE
);
1287 session
= eos_create_soup_session (ref_source
, ref_source_user_data
, source
);
1291 post_form
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_free
);
1293 e_oauth2_service_prepare_get_token_form (service
, source
, authorization_code
, post_form
);
1295 message
= eos_create_soup_message (source
, e_oauth2_service_get_refresh_uri (service
, source
), post_form
);
1297 g_hash_table_destroy (post_form
);
1300 g_object_unref (session
);
1304 e_oauth2_service_prepare_get_token_message (service
, source
, message
);
1306 success
= eos_send_message (session
, message
, &response_json
, cancellable
, error
);
1308 gchar
*access_token
= NULL
, *refresh_token
= NULL
, *expires_in
= NULL
, *token_type
= NULL
;
1310 if (eos_decode_from_secret (response_json
,
1311 "access_token", &access_token
,
1312 "refresh_token", &refresh_token
,
1313 "expires_in", &expires_in
,
1314 "token_type", &token_type
,
1315 NULL
) && access_token
&& refresh_token
&& expires_in
&& token_type
) {
1317 g_warn_if_fail (g_ascii_strcasecmp (token_type
, "Bearer") == 0);
1319 success
= eos_store_token_sync (service
, source
,
1320 refresh_token
, access_token
, expires_in
, cancellable
, error
);
1325 e_util_safe_free_string (access_token
);
1326 e_util_safe_free_string (refresh_token
);
1327 g_free (expires_in
);
1328 g_free (token_type
);
1331 g_object_unref (message
);
1332 g_object_unref (session
);
1333 e_util_safe_free_string (response_json
);
1339 * e_oauth2_service_refresh_and_store_token_sync:
1340 * @service: an #EOAuth2Service
1341 * @source: an #ESource
1342 * @refresh_token: refresh token as provided by the server
1343 * @ref_source: (scope call): an #EOAuth2ServiceRefSourceFunc function to obtain an #ESource
1344 * @ref_source_user_data: user data for @ref_source
1345 * @cancellable: optional #GCancellable object, or %NULL
1346 * @error: return location for a #GError, or %NULL
1348 * Queries @service at e_oauth2_service_get_refresh_uri() with a request to refresh
1349 * existing access token with provided @refresh_token and stores it into the secret
1352 * Returns: whether succeeded
1357 e_oauth2_service_refresh_and_store_token_sync (EOAuth2Service
*service
,
1359 const gchar
*refresh_token
,
1360 EOAuth2ServiceRefSourceFunc ref_source
,
1361 gpointer ref_source_user_data
,
1362 GCancellable
*cancellable
,
1365 SoupSession
*session
;
1366 SoupMessage
*message
;
1367 GHashTable
*post_form
;
1368 gchar
*response_json
= NULL
;
1370 GError
*local_error
= NULL
;
1372 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
1373 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
1374 g_return_val_if_fail (refresh_token
!= NULL
, FALSE
);
1375 g_return_val_if_fail (ref_source
!= NULL
, FALSE
);
1377 session
= eos_create_soup_session (ref_source
, ref_source_user_data
, source
);
1381 post_form
= g_hash_table_new_full (g_str_hash
, g_str_equal
, g_free
, g_free
);
1383 e_oauth2_service_prepare_refresh_token_form (service
, source
, refresh_token
, post_form
);
1385 message
= eos_create_soup_message (source
, e_oauth2_service_get_refresh_uri (service
, source
), post_form
);
1387 g_hash_table_destroy (post_form
);
1390 g_object_unref (session
);
1394 e_oauth2_service_prepare_refresh_token_message (service
, source
, message
);
1396 success
= eos_send_message (session
, message
, &response_json
, cancellable
, &local_error
);
1398 gchar
*access_token
= NULL
, *expires_in
= NULL
, *new_refresh_token
= NULL
;
1400 if (eos_decode_from_secret (response_json
,
1401 "access_token", &access_token
,
1402 "expires_in", &expires_in
,
1403 "refresh_token", &new_refresh_token
,
1404 NULL
) && access_token
&& expires_in
) {
1405 success
= eos_store_token_sync (service
, source
,
1406 (new_refresh_token
&& *new_refresh_token
) ? new_refresh_token
: refresh_token
,
1407 access_token
, expires_in
, cancellable
, error
);
1411 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
, _("Received incorrect response from server ā%sā."),
1412 e_oauth2_service_get_refresh_uri (service
, source
));
1415 e_util_safe_free_string (access_token
);
1416 g_free (new_refresh_token
);
1417 g_free (expires_in
);
1418 } else if (g_error_matches (local_error
, SOUP_HTTP_ERROR
, SOUP_STATUS_BAD_REQUEST
)) {
1419 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_CONNECTION_REFUSED
,
1420 _("Failed to refresh access token. Sign to the server again, please."));
1421 g_clear_error (&local_error
);
1425 g_propagate_error (error
, local_error
);
1427 g_object_unref (message
);
1428 g_object_unref (session
);
1429 e_util_safe_free_string (response_json
);
1435 * e_oauth2_service_delete_token_sync:
1436 * @service: an #EOAuth2Service
1437 * @source: an #ESource
1438 * @cancellable: optional #GCancellable object, or %NULL
1439 * @error: return location for a #GError, or %NULL
1441 * Deletes token information for the @service and @source from the secret store.
1443 * Returns: whether succeeded
1448 e_oauth2_service_delete_token_sync (EOAuth2Service
*service
,
1450 GCancellable
*cancellable
,
1456 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
1457 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
1459 if (!eos_generate_secret_uid (service
, source
, &uid
)) {
1460 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
,
1461 /* Translators: The first %s is a display name of the source, the second is its UID. */
1462 _("Source ā%sā (%s) is not a valid OAuth2 source"),
1463 e_source_get_display_name (source
),
1464 e_source_get_uid (source
));
1468 success
= e_secret_store_delete_sync (uid
, cancellable
, error
);
1476 * e_oauth2_service_get_access_token_sync:
1477 * @service: an #EOAuth2Service
1478 * @source: an #ESource
1479 * @ref_source: (scope call): an #EOAuth2ServiceRefSourceFunc function to obtain an #ESource
1480 * @ref_source_user_data: user data for @ref_source
1481 * @out_access_token: (out) (transfer full): return location for the access token
1482 * @out_expires_in: (out): how many seconds the access token expires in
1483 * @cancellable: optional #GCancellable object, or %NULL
1484 * @error: return location for a #GError, or %NULL
1486 * Reads access token information from the secret store for the @source and
1487 * in case it's expired it refreshes the token, if possible.
1489 * Free the returned @out_access_token with g_free(), when no longer needed.
1491 * Returns: %TRUE, when the returned access token has been set and it's not expired,
1497 e_oauth2_service_get_access_token_sync (EOAuth2Service
*service
,
1499 EOAuth2ServiceRefSourceFunc ref_source
,
1500 gpointer ref_source_user_data
,
1501 gchar
**out_access_token
,
1502 gint
*out_expires_in
,
1503 GCancellable
*cancellable
,
1506 gchar
*refresh_token
= NULL
;
1507 gboolean success
= TRUE
;
1509 g_return_val_if_fail (E_IS_OAUTH2_SERVICE (service
), FALSE
);
1510 g_return_val_if_fail (E_IS_SOURCE (source
), FALSE
);
1511 g_return_val_if_fail (ref_source
!= NULL
, FALSE
);
1512 g_return_val_if_fail (out_access_token
!= NULL
, FALSE
);
1513 g_return_val_if_fail (out_expires_in
!= NULL
, FALSE
);
1515 if (!eos_lookup_token_sync (service
, source
, &refresh_token
, out_access_token
, out_expires_in
, cancellable
, error
))
1518 if (*out_expires_in
<= 0 && refresh_token
) {
1519 success
= e_oauth2_service_refresh_and_store_token_sync (service
, source
, refresh_token
,
1520 ref_source
, ref_source_user_data
, cancellable
, error
);
1522 g_clear_pointer (&refresh_token
, e_util_safe_free_string
);
1524 success
= success
&& eos_lookup_token_sync (service
, source
, &refresh_token
, out_access_token
, out_expires_in
, cancellable
, error
);
1527 e_util_safe_free_string (refresh_token
);
1529 if (success
&& *out_expires_in
<= 0) {
1530 e_util_safe_free_string (*out_access_token
);
1531 *out_access_token
= NULL
;
1534 g_set_error_literal (error
, G_IO_ERROR
, G_IO_ERROR_CONNECTION_REFUSED
,
1535 _("The access token is expired and it failed to refresh it. Sign to the server again, please."));
1542 * e_oauth2_service_util_set_to_form:
1543 * @form: a #GHashTable
1544 * @name: a property name
1545 * @value: (nullable): a property value
1547 * Sets @value for @name to @form. The @form should be
1548 * the one used in e_oauth2_service_prepare_authentication_uri_query(),
1549 * e_oauth2_service_prepare_get_token_form() or
1550 * e_oauth2_service_prepare_refresh_token_form().
1552 * If the @value is %NULL, then the property named @name is removed
1553 * from the @form instead.
1558 e_oauth2_service_util_set_to_form (GHashTable
*form
,
1562 g_return_if_fail (form
!= NULL
);
1563 g_return_if_fail (name
!= NULL
);
1566 g_hash_table_insert (form
, g_strdup (name
), g_strdup (value
));
1568 g_hash_table_remove (form
, name
);
1572 * e_oauth2_service_util_take_to_form:
1573 * @form: a #GHashTable
1574 * @name: a property name
1575 * @value: (transfer full) (nullable): a property value
1577 * Takes ownership of @value and sets it for @name to @form. The @value
1578 * will be freed with g_free(), when no longer needed. The @form should be
1579 * the one used in e_oauth2_service_prepare_authentication_uri_query(),
1580 * e_oauth2_service_prepare_get_token_form() or
1581 * e_oauth2_service_prepare_refresh_token_form().
1583 * If the @value is %NULL, then the property named @name is removed
1584 * from the @form instead.
1589 e_oauth2_service_util_take_to_form (GHashTable
*form
,
1593 g_return_if_fail (form
!= NULL
);
1594 g_return_if_fail (name
!= NULL
);
1597 g_hash_table_insert (form
, g_strdup (name
), value
);
1599 g_hash_table_remove (form
, name
);