2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2021-2023 the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "claws-features.h"
29 #include <glib/gi18n.h>
44 #include "common/passcrypt.h"
45 #include "prefs_common.h"
47 #define GNUTLS_PRIORITY "NORMAL:!VERS-SSL3.0:!VERS-TLS1.0:!VERS-TLS1.1"
48 //Yahoo requires token requests to send POST header Authorization: Basic
49 //where the password is Base64 encoding of client_id:client_secret
51 static gchar
*OAUTH2info
[4][17]={
52 {"accounts.google.com",
55 "http://127.0.0.1:8888",
60 "https://mail.google.com",
69 {"login.microsoftonline.com",
72 "http://127.0.0.1:8888",
73 "/common/oauth2/v2.0/authorize",
74 "/common/oauth2/v2.0/token",
75 "/common/oauth2/v2.0/token",
77 "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send",
83 "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send",
86 {"login.microsoftonline.com",
89 "http://127.0.0.1:8888",
90 "/common/oauth2/v2.0/authorize",
91 "/common/oauth2/v2.0/token",
92 "/common/oauth2/v2.0/token",
94 "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send",
100 "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send",
103 {"api.login.yahoo.com",
107 "/oauth2/request_auth",
112 "authorization_code",
122 static gchar
*OAUTH2CodeMarker
[5][2] = {
126 {"code=","&session_state="},
127 {"yahoo_begin_mark","yahoo_end_mark"} /* Not used since token avalable to user to copy in browser window */
130 static gint
oauth2_post_request (gchar
*buf
, gchar
*host
, gchar
*resource
, gchar
*header
, gchar
*body
);
131 static gint
oauth2_filter_refresh (gchar
*json
, gchar
*refresh_token
);
132 static gint
oauth2_filter_access (gchar
*json
, gchar
*access_token
, gint
*expiry
);
133 static gint
oauth2_contact_server (SockInfo
*sock
, gchar
*request
, gchar
*response
);
136 static gint
oauth2_post_request (gchar
*buf
, gchar
*host
, gchar
*resource
, gchar
*header
, gchar
*body
)
142 return snprintf(buf
, OAUTH2BUFSIZE
, "POST %s HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: text/html,application/json\r\nContent-Length: %i\r\nHost: %s\r\nConnection: close\r\nUser-Agent: ClawsMail\r\n%s\r\n\r\n%s", resource
, len
, host
, header
, body
);
144 return snprintf(buf
, OAUTH2BUFSIZE
, "POST %s HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept: text/html,application/json\r\nContent-Length: %i\r\nHost: %s\r\nConnection: close\r\nUser-Agent: ClawsMail\r\n\r\n%s", resource
, len
, host
, body
);
147 static gint
oauth2_filter_access (gchar
*json
, gchar
*access_token
, gint
*expiry
)
149 GMatchInfo
*matchInfo
;
152 regex
= g_regex_new ("\"access_token\": ?\"(.*?)\",?", G_REGEX_RAW
, 0, NULL
);
153 g_regex_match (regex
, json
, 0, &matchInfo
);
154 if (g_match_info_matches (matchInfo
))
155 g_stpcpy (access_token
,g_match_info_fetch (matchInfo
, 1));
157 g_match_info_free (matchInfo
);
161 g_match_info_free (matchInfo
);
163 regex
= g_regex_new ("\"expires_in\": ?([0-9]*),?", G_REGEX_RAW
, 0, NULL
);
164 g_regex_match (regex
, json
, 0, &matchInfo
);
165 if (g_match_info_matches (matchInfo
)){
166 // Reduce available token life to avoid attempting connections with (near) expired tokens
167 *expiry
= (g_get_real_time () / G_USEC_PER_SEC
) + atoi(g_match_info_fetch (matchInfo
, 1)) - 120;
169 g_match_info_free (matchInfo
);
173 g_match_info_free (matchInfo
);
178 static gint
oauth2_filter_refresh (gchar
*json
, gchar
*refresh_token
)
180 GMatchInfo
*matchInfo
;
183 regex
= g_regex_new ("\"refresh_token\": ?\"(.*?)\",?", G_REGEX_RAW
, 0, NULL
);
184 g_regex_match (regex
, json
, 0, &matchInfo
);
185 if (g_match_info_matches (matchInfo
))
186 g_stpcpy (refresh_token
,g_match_info_fetch (matchInfo
, 1));
188 g_match_info_free (matchInfo
);
192 g_match_info_free (matchInfo
);
197 static gchar
* oauth2_get_token_from_response(Oauth2Service provider
, const gchar
* response
) {
200 debug_print("Auth response: %s\n", response
);
201 if (provider
== OAUTH2AUTH_YAHOO
) {
202 /* Providers which display auth token in browser for users to copy */
203 token
= g_strdup(response
);
205 gchar
* start
= g_strstr_len(response
, strlen(response
), OAUTH2CodeMarker
[provider
][0]);
208 start
+= strlen(OAUTH2CodeMarker
[provider
][0]);
209 gchar
* stop
= g_strstr_len(response
, strlen(response
), OAUTH2CodeMarker
[provider
][1]);
212 token
= g_strndup(start
, stop
- start
);
218 int oauth2_obtain_tokens (Oauth2Service provider
, OAUTH2Data
*OAUTH2Data
, const gchar
*authcode
)
225 gchar
*tmp_hd
, *tmp_hd_encoded
;
227 gchar
*refresh_token
;
232 gchar
*client_secret
;
237 i
= (int)provider
- 1;
238 if (i
< 0 || i
> (OAUTH2AUTH_LAST
-1))
241 token
= oauth2_get_token_from_response(provider
, authcode
);
242 debug_print("Auth token: %s\n", token
);
244 log_message(LOG_PROTOCOL
, _("OAuth2 missing authorization code\n"));
247 debug_print("Connect: %s:443\n", OAUTH2info
[i
][OA2_BASE_URL
]);
248 sock
= sock_connect(OAUTH2info
[i
][OA2_BASE_URL
], 443);
250 log_message(LOG_PROTOCOL
, _("OAuth2 connection error\n"));
254 sock
->ssl_cert_auto_accept
= TRUE
;
255 sock
->use_tls_sni
= TRUE
;
256 sock_set_nonblocking_mode(sock
, FALSE
);
257 gint timeout_secs
= prefs_common_get_prefs()->io_timeout_secs
;
258 debug_print("Socket timeout: %i sec(s)\n", timeout_secs
);
259 sock_set_io_timeout(timeout_secs
);
260 sock
->gnutls_priority
= GNUTLS_PRIORITY
;
261 if (ssl_init_socket(sock
) == FALSE
) {
262 log_message(LOG_PROTOCOL
, _("OAuth2 TLS connection error\n"));
267 refresh_token
= g_malloc(OAUTH2BUFSIZE
+1);
268 access_token
= g_malloc(OAUTH2BUFSIZE
+1);
269 request
= g_malloc(OAUTH2BUFSIZE
+1);
270 response
= g_malloc0(OAUTH2BUFSIZE
+1);
272 if(OAUTH2Data
->custom_client_id
)
273 client_id
= g_strdup(OAUTH2Data
->custom_client_id
);
275 client_id
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_ID
]);
277 body
= g_strconcat ("client_id=", client_id
, "&code=", token
, NULL
);
278 debug_print("Body: %s\n", body
);
281 if(OAUTH2info
[i
][OA2_CLIENT_SECRET
][0]){
282 //Only allow custom client secret if the service provider would usually expect a client secret
283 if(OAUTH2Data
->custom_client_secret
)
284 client_secret
= g_strdup(OAUTH2Data
->custom_client_secret
);
286 client_secret
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_SECRET
]);
287 uri
= g_uri_escape_string (client_secret
, NULL
, FALSE
);
288 tmp
= g_strconcat (body
, "&client_secret=", uri
, NULL
);
293 client_secret
= g_strconcat ("", NULL
);
296 if(OAUTH2info
[i
][OA2_REDIRECT_URI
][0]) {
297 tmp
= g_strconcat(body
, "&redirect_uri=", OAUTH2info
[i
][OA2_REDIRECT_URI
], NULL
);
301 if(OAUTH2info
[i
][OA2_GRANT_TYPE_ACCESS
][0]) {
302 tmp
= g_strconcat(body
, "&grant_type=", OAUTH2info
[i
][OA2_GRANT_TYPE_ACCESS
], NULL
);
306 if(OAUTH2info
[i
][OA2_TENANT
][0]) {
307 tmp
= g_strconcat(body
, "&tenant=", OAUTH2info
[i
][OA2_TENANT
], NULL
);
311 if(OAUTH2info
[i
][OA2_SCOPE_FOR_ACCESS
][0]) {
312 tmp
= g_strconcat(body
, "&scope=", OAUTH2info
[i
][OA2_SCOPE_FOR_ACCESS
], NULL
);
316 if(OAUTH2info
[i
][OA2_STATE
][0]) {
317 tmp
= g_strconcat(body
, "&state=", OAUTH2info
[i
][OA2_STATE
], NULL
);
322 if(OAUTH2info
[i
][OA2_HEADER_AUTH_BASIC
][0]){
323 tmp_hd
= g_strconcat(client_id
, ":", client_secret
, NULL
);
324 tmp_hd_encoded
= g_base64_encode (tmp_hd
, strlen(tmp_hd
));
325 header
= g_strconcat ("Authorization: Basic ", tmp_hd_encoded
, NULL
);
326 g_free(tmp_hd_encoded
);
329 header
= g_strconcat ("", NULL
);
332 debug_print("Complete body: %s\n", body
);
333 oauth2_post_request (request
, OAUTH2info
[i
][OA2_BASE_URL
], OAUTH2info
[i
][OA2_ACCESS_RESOURCE
], header
, body
);
334 ret
= oauth2_contact_server (sock
, request
, response
);
336 if(oauth2_filter_access (response
, access_token
, &expiry
) == 0){
337 OAUTH2Data
->access_token
= g_strdup(access_token
);
338 OAUTH2Data
->expiry
= expiry
;
339 OAUTH2Data
->expiry_str
= g_strdup_printf ("%i", expiry
);
341 log_message(LOG_PROTOCOL
, _("OAuth2 access token obtained\n"));
343 log_message(LOG_PROTOCOL
, _("OAuth2 access token not obtained\n"));
344 debug_print("OAuth2 - request: %s\n Response: %s", request
, response
);
348 if(oauth2_filter_refresh (response
, refresh_token
) == 0){
349 OAUTH2Data
->refresh_token
= g_strdup(refresh_token
);
350 log_message(LOG_PROTOCOL
, _("OAuth2 refresh token obtained\n"));
352 log_message(LOG_PROTOCOL
, _("OAuth2 refresh token not obtained\n"));
355 sock_close(sock
, TRUE
);
361 g_free(client_secret
);
362 g_free(access_token
);
363 g_free(refresh_token
);
368 gint
oauth2_use_refresh_token (Oauth2Service provider
, OAUTH2Data
*OAUTH2Data
)
376 gchar
*tmp_hd
, *tmp_hd_encoded
;
378 gchar
*refresh_token
;
383 gchar
*client_secret
;
387 i
= (int)provider
- 1;
388 if (i
< 0 || i
> (OAUTH2AUTH_LAST
-1))
391 sock
= sock_connect(OAUTH2info
[i
][OA2_BASE_URL
], 443);
393 log_message(LOG_PROTOCOL
, _("OAuth2 connection error\n"));
396 sock
->ssl_cert_auto_accept
= TRUE
;
397 sock
->use_tls_sni
= TRUE
;
398 sock_set_nonblocking_mode(sock
, FALSE
);
399 gint timeout_secs
= prefs_common_get_prefs()->io_timeout_secs
;
400 debug_print("Socket timeout: %i sec(s)\n", timeout_secs
);
401 sock_set_io_timeout(timeout_secs
);
402 sock
->gnutls_priority
= GNUTLS_PRIORITY
;
403 if (ssl_init_socket(sock
) == FALSE
) {
404 log_message(LOG_PROTOCOL
, _("OAuth2 TLS connection error\n"));
408 access_token
= g_malloc(OAUTH2BUFSIZE
+1);
409 refresh_token
= g_malloc(OAUTH2BUFSIZE
+1);
410 request
= g_malloc(OAUTH2BUFSIZE
+1);
411 response
= g_malloc(OAUTH2BUFSIZE
+1);
413 if(OAUTH2Data
->custom_client_id
)
414 client_id
= g_strdup(OAUTH2Data
->custom_client_id
);
416 client_id
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_ID
]);
418 uri
= g_uri_escape_string (client_id
, NULL
, FALSE
);
419 body
= g_strconcat ("client_id=", uri
, "&refresh_token=", OAUTH2Data
->refresh_token
, NULL
);
422 if(OAUTH2info
[i
][OA2_CLIENT_SECRET
][0]){
423 //Only allow custom client secret if the service provider would usually expect a client secret
424 if(OAUTH2Data
->custom_client_secret
)
425 client_secret
= g_strdup(OAUTH2Data
->custom_client_secret
);
427 client_secret
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_SECRET
]);
428 uri
= g_uri_escape_string (client_secret
, NULL
, FALSE
);
429 tmp
= g_strconcat (body
, "&client_secret=", uri
, NULL
);
434 client_secret
= g_strconcat ("", NULL
);
437 if(OAUTH2info
[i
][OA2_GRANT_TYPE_REFRESH
][0]) {
438 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_GRANT_TYPE_REFRESH
], NULL
, FALSE
);
439 tmp
= g_strconcat (body
, "&grant_type=", uri
, NULL
);
444 if(OAUTH2info
[i
][OA2_SCOPE_FOR_ACCESS
][0]) {
445 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_SCOPE_FOR_ACCESS
], NULL
, FALSE
);
446 tmp
= g_strconcat (body
, "&scope=", uri
, NULL
);
451 if(OAUTH2info
[i
][OA2_STATE
][0]) {
452 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_STATE
], NULL
, FALSE
);
453 tmp
= g_strconcat (body
, "&state=", uri
, NULL
);
459 if(OAUTH2info
[i
][OA2_HEADER_AUTH_BASIC
][0]){
460 tmp_hd
= g_strconcat(client_id
, ":", client_secret
, NULL
);
461 tmp_hd_encoded
= g_base64_encode (tmp_hd
, strlen(tmp_hd
));
462 header
= g_strconcat ("Authorization: Basic ", tmp_hd_encoded
, NULL
);
463 g_free(tmp_hd_encoded
);
466 header
= g_strconcat ("", NULL
);
469 oauth2_post_request (request
, OAUTH2info
[i
][OA2_BASE_URL
], OAUTH2info
[i
][OA2_REFRESH_RESOURCE
], header
, body
);
470 ret
= oauth2_contact_server (sock
, request
, response
);
472 if(oauth2_filter_access (response
, access_token
, &expiry
) == 0){
473 OAUTH2Data
->access_token
= g_strdup(access_token
);
474 OAUTH2Data
->expiry
= expiry
;
475 OAUTH2Data
->expiry_str
= g_strdup_printf ("%i", expiry
);
477 log_message(LOG_PROTOCOL
, _("OAuth2 access token obtained\n"));
479 log_message(LOG_PROTOCOL
, _("OAuth2 access token not obtained\n"));
480 debug_print("OAuth2 - request: %s\n Response: %s", request
, response
);
484 if (oauth2_filter_refresh (response
, refresh_token
) == 0) {
485 OAUTH2Data
->refresh_token
= g_strdup(refresh_token
);
486 log_message(LOG_PROTOCOL
, _("OAuth2 replacement refresh token provided\n"));
488 log_message(LOG_PROTOCOL
, _("OAuth2 replacement refresh token not provided\n"));
490 debug_print("OAuth2 - access token: %s\n", access_token
);
491 debug_print("OAuth2 - access token expiry: %i\n", expiry
);
493 sock_close(sock
, TRUE
);
499 g_free(client_secret
);
500 g_free(access_token
);
501 g_free(refresh_token
);
506 static gint
oauth2_contact_server (SockInfo
*sock
, gchar
*request
, gchar
*response
)
511 gint toread
= OAUTH2BUFSIZE
;
512 time_t startplus
= time(NULL
);
514 len
= strlen(request
);
516 gint timeout_secs
= prefs_common_get_prefs()->io_timeout_secs
;
517 startplus
+= timeout_secs
;
519 if (sock_write (sock
, request
, len
+1) < 0) {
520 log_message(LOG_PROTOCOL
, _("OAuth2 socket write error\n"));
524 token
= g_strconcat ("", NULL
);
527 ret
= sock_read (sock
, response
, OAUTH2BUFSIZE
);
528 if (ret
< 0 && errno
== EAGAIN
)
536 tmp
= g_strconcat(token
, response
, NULL
);
539 } while ((toread
> 0) && (time(NULL
) < startplus
));
541 if(time(NULL
) >= startplus
)
542 log_message(LOG_PROTOCOL
, _("OAuth2 socket timeout error\n"));
549 gint
oauth2_authorisation_url (Oauth2Service provider
, gchar
**url
, const gchar
*custom_client_id
)
552 gchar
*client_id
= NULL
;
556 i
= (int)provider
- 1;
557 if (i
< 0 || i
> (OAUTH2AUTH_LAST
-1))
560 if(!custom_client_id
)
561 client_id
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_ID
]);
563 uri
= g_uri_escape_string (custom_client_id
? custom_client_id
: client_id
, NULL
, FALSE
);
564 *url
= g_strconcat ("https://", OAUTH2info
[i
][OA2_BASE_URL
],OAUTH2info
[i
][OA2_AUTH_RESOURCE
], "?client_id=",
570 if(OAUTH2info
[i
][OA2_REDIRECT_URI
][0]) {
571 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_REDIRECT_URI
], NULL
, FALSE
);
572 tmp
= g_strconcat (*url
, "&redirect_uri=", uri
, NULL
);
578 if(OAUTH2info
[i
][OA2_RESPONSE_TYPE
][0]) {
579 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_RESPONSE_TYPE
], NULL
, FALSE
);
580 tmp
= g_strconcat (*url
, "&response_type=", uri
, NULL
);
585 if(OAUTH2info
[i
][OA2_SCOPE_FOR_AUTH
][0]) {
586 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_SCOPE_FOR_AUTH
], NULL
, FALSE
);
587 tmp
= g_strconcat (*url
, "&scope=", uri
, NULL
);
592 if(OAUTH2info
[i
][OA2_TENANT
][0]) {
593 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_TENANT
], NULL
, FALSE
);
594 tmp
= g_strconcat (*url
, "&tenant=", uri
, NULL
);
599 if(OAUTH2info
[i
][OA2_RESPONSE_MODE
][0]) {
600 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_RESPONSE_MODE
], NULL
, FALSE
);
601 tmp
= g_strconcat (*url
, "&response_mode=", uri
, NULL
);
606 if(OAUTH2info
[i
][OA2_STATE
][0]) {
607 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_STATE
], NULL
, FALSE
);
608 tmp
= g_strconcat (*url
, "&state=", uri
, NULL
);
617 gint
oauth2_check_passwds (PrefsAccount
*ac_prefs
)
619 gchar
*uid
= g_strdup_printf("%d", ac_prefs
->account_id
);
621 OAUTH2Data
*OAUTH2Data
= g_malloc(sizeof(* OAUTH2Data
));
625 oauth2_init (OAUTH2Data
);
627 OAUTH2Data
->custom_client_id
= ac_prefs
->oauth2_client_id
;
628 OAUTH2Data
->custom_client_secret
= ac_prefs
->oauth2_client_secret
;
630 if (passwd_store_has_password(PWS_ACCOUNT
, uid
, PWS_ACCOUNT_OAUTH2_EXPIRY
)) {
631 acc
= passwd_store_get_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_EXPIRY
);
634 if (expiry
> (g_get_real_time () / G_USEC_PER_SEC
)) {
636 log_message(LOG_PROTOCOL
, _("OAuth2 access token still fresh\n"));
642 if (passwd_store_has_password(PWS_ACCOUNT
, uid
, PWS_ACCOUNT_OAUTH2_REFRESH
)) {
643 log_message(LOG_PROTOCOL
, _("OAuth2 obtaining access token using refresh token\n"));
644 OAUTH2Data
->refresh_token
= passwd_store_get_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_REFRESH
);
645 ret
= oauth2_use_refresh_token (ac_prefs
->oauth2_provider
, OAUTH2Data
);
646 } else if (passwd_store_has_password(PWS_ACCOUNT
, uid
, PWS_ACCOUNT_OAUTH2_AUTH
)) {
647 log_message(LOG_PROTOCOL
, _("OAuth2 trying for fresh access token with authorization code\n"));
648 acc
= passwd_store_get_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_AUTH
);
649 ret
= oauth2_obtain_tokens (ac_prefs
->oauth2_provider
, OAUTH2Data
, acc
);
655 log_message(LOG_PROTOCOL
, _("OAuth2 access token not obtained\n"));
657 if (ac_prefs
->imap_auth_type
== IMAP_AUTH_OAUTH2
||
658 (ac_prefs
->use_pop_auth
&& ac_prefs
->pop_auth_type
== POPAUTH_OAUTH2
))
659 passwd_store_set_account(ac_prefs
->account_id
, PWS_ACCOUNT_RECV
, OAUTH2Data
->access_token
, FALSE
);
660 if (ac_prefs
->use_smtp_auth
&& ac_prefs
->smtp_auth_type
== SMTPAUTH_OAUTH2
)
661 passwd_store_set_account(ac_prefs
->account_id
, PWS_ACCOUNT_SEND
, OAUTH2Data
->access_token
, FALSE
);
662 passwd_store_set_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_EXPIRY
, OAUTH2Data
->expiry_str
, FALSE
);
663 //Some providers issue replacement refresh tokens with each access token. Re-store whether replaced or not.
664 passwd_store_set_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_REFRESH
, OAUTH2Data
->refresh_token
, FALSE
);
665 log_message(LOG_PROTOCOL
, _("OAuth2 access and refresh token updated\n"));
674 /* returns allocated string which must be freed */
675 guchar
* oauth2_decode(const gchar
*in
)
680 tmp
= g_base64_decode(in
, &len
);
681 passcrypt_decrypt(tmp
, len
);
686 void oauth2_encode(const gchar
*in
)
688 guchar
*tmp
= g_strdup(in
);
689 guchar
*tmp2
= g_strdup(in
);
691 gsize len
= strlen(in
);
693 passcrypt_encrypt(tmp
, len
);
694 result
= g_base64_encode(tmp
, len
);
695 tmp2
= oauth2_decode(result
);
697 log_message(LOG_PROTOCOL
, _("OAuth2 original: %s\n"), in
);
698 log_message(LOG_PROTOCOL
, _("OAuth2 encoded: %s\n"), result
);
699 log_message(LOG_PROTOCOL
, _("OAuth2 decoded: %s\n\n"), tmp2
);
706 gint
oauth2_init (OAUTH2Data
*OAUTH2Data
)
708 OAUTH2Data
->refresh_token
= NULL
;
709 OAUTH2Data
->access_token
= NULL
;
710 OAUTH2Data
->expiry_str
= NULL
;
711 OAUTH2Data
->expiry
= 0;
712 OAUTH2Data
->custom_client_id
= NULL
;
713 OAUTH2Data
->custom_client_secret
= NULL
;
718 #endif /* USE_GNUTLS */