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
);
135 static gint
oauth2_post_request (gchar
*buf
, gchar
*host
, gchar
*resource
, gchar
*header
, gchar
*body
)
139 debug_print("Complete body: %s\n", 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 static gchar
*oauth2_contact_server(SockInfo
*sock
, const gchar
*request
)
220 gboolean got_some_error
, timeout
;
223 GString
*response
= g_string_sized_new(sizeof(buf
));
224 time_t end_time
= time(NULL
);
226 end_time
+= prefs_common_get_prefs()->io_timeout_secs
;
231 if (sock_write(sock
, request
, strlen(request
)) < 0) {
232 log_message(LOG_PROTOCOL
, _("OAuth2 socket write error\n"));
237 ret
= sock_read(sock
, buf
, sizeof(buf
) - 1);
238 got_some_error
= ret
< 0;
239 timeout
= time(NULL
) > end_time
;
244 if (ret
< 0 && errno
== EAGAIN
)
252 g_string_append_len(response
, buf
, ret
);
257 log_message(LOG_PROTOCOL
, _("OAuth2 socket timeout error\n"));
259 return g_string_free(response
, got_some_error
|| timeout
);
262 int oauth2_obtain_tokens (Oauth2Service provider
, OAUTH2Data
*OAUTH2Data
, const gchar
*authcode
)
269 gchar
*tmp_hd
, *tmp_hd_encoded
;
271 gchar
*refresh_token
;
276 gchar
*client_secret
;
281 i
= (int)provider
- 1;
282 if (i
< 0 || i
> (OAUTH2AUTH_LAST
-1))
285 token
= oauth2_get_token_from_response(provider
, authcode
);
286 debug_print("Auth token: %s\n", token
);
288 log_message(LOG_PROTOCOL
, _("OAuth2 missing authorization code\n"));
291 debug_print("Connect: %s:443\n", OAUTH2info
[i
][OA2_BASE_URL
]);
292 sock
= sock_connect(OAUTH2info
[i
][OA2_BASE_URL
], 443);
294 log_message(LOG_PROTOCOL
, _("OAuth2 connection error\n"));
298 sock
->ssl_cert_auto_accept
= TRUE
;
299 sock
->use_tls_sni
= TRUE
;
300 sock_set_nonblocking_mode(sock
, FALSE
);
301 gint timeout_secs
= prefs_common_get_prefs()->io_timeout_secs
;
302 debug_print("Socket timeout: %i sec(s)\n", timeout_secs
);
303 sock_set_io_timeout(timeout_secs
);
304 sock
->gnutls_priority
= GNUTLS_PRIORITY
;
305 if (ssl_init_socket(sock
) == FALSE
) {
306 log_message(LOG_PROTOCOL
, _("OAuth2 TLS connection error\n"));
311 refresh_token
= g_malloc(OAUTH2BUFSIZE
+1);
312 access_token
= g_malloc(OAUTH2BUFSIZE
+1);
313 request
= g_malloc(OAUTH2BUFSIZE
+1);
315 if(OAUTH2Data
->custom_client_id
)
316 client_id
= g_strdup(OAUTH2Data
->custom_client_id
);
318 client_id
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_ID
]);
320 body
= g_strconcat ("client_id=", client_id
, "&code=", token
, NULL
);
321 debug_print("Body: %s\n", body
);
324 if(OAUTH2info
[i
][OA2_CLIENT_SECRET
][0]){
325 //Only allow custom client secret if the service provider would usually expect a client secret
326 if(OAUTH2Data
->custom_client_secret
)
327 client_secret
= g_strdup(OAUTH2Data
->custom_client_secret
);
329 client_secret
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_SECRET
]);
330 uri
= g_uri_escape_string (client_secret
, NULL
, FALSE
);
331 tmp
= g_strconcat (body
, "&client_secret=", uri
, NULL
);
336 client_secret
= g_strconcat ("", NULL
);
339 if(OAUTH2info
[i
][OA2_REDIRECT_URI
][0]) {
340 tmp
= g_strconcat(body
, "&redirect_uri=", OAUTH2info
[i
][OA2_REDIRECT_URI
], NULL
);
344 if(OAUTH2info
[i
][OA2_GRANT_TYPE_ACCESS
][0]) {
345 tmp
= g_strconcat(body
, "&grant_type=", OAUTH2info
[i
][OA2_GRANT_TYPE_ACCESS
], NULL
);
349 if(OAUTH2info
[i
][OA2_TENANT
][0]) {
350 tmp
= g_strconcat(body
, "&tenant=", OAUTH2info
[i
][OA2_TENANT
], NULL
);
354 if(OAUTH2info
[i
][OA2_SCOPE_FOR_ACCESS
][0]) {
355 tmp
= g_strconcat(body
, "&scope=", OAUTH2info
[i
][OA2_SCOPE_FOR_ACCESS
], NULL
);
359 if(OAUTH2info
[i
][OA2_STATE
][0]) {
360 tmp
= g_strconcat(body
, "&state=", OAUTH2info
[i
][OA2_STATE
], NULL
);
365 if(OAUTH2info
[i
][OA2_HEADER_AUTH_BASIC
][0]){
366 tmp_hd
= g_strconcat(client_id
, ":", client_secret
, NULL
);
367 tmp_hd_encoded
= g_base64_encode (tmp_hd
, strlen(tmp_hd
));
368 header
= g_strconcat ("Authorization: Basic ", tmp_hd_encoded
, NULL
);
369 g_free(tmp_hd_encoded
);
372 header
= g_strconcat ("", NULL
);
375 oauth2_post_request (request
, OAUTH2info
[i
][OA2_BASE_URL
], OAUTH2info
[i
][OA2_ACCESS_RESOURCE
], header
, body
);
376 response
= oauth2_contact_server (sock
, request
);
377 debug_print("Response from server: %s\n", response
);
379 if(response
&& oauth2_filter_access (response
, access_token
, &expiry
) == 0){
380 OAUTH2Data
->access_token
= g_strdup(access_token
);
381 OAUTH2Data
->expiry
= expiry
;
382 OAUTH2Data
->expiry_str
= g_strdup_printf ("%i", expiry
);
384 log_message(LOG_PROTOCOL
, _("OAuth2 access token obtained\n"));
386 log_message(LOG_PROTOCOL
, _("OAuth2 access token not obtained\n"));
387 debug_print("OAuth2 - request: %s\n Response: %s", request
, response
);
391 if(response
&& oauth2_filter_refresh (response
, refresh_token
) == 0){
392 OAUTH2Data
->refresh_token
= g_strdup(refresh_token
);
393 log_message(LOG_PROTOCOL
, _("OAuth2 refresh token obtained\n"));
395 log_message(LOG_PROTOCOL
, _("OAuth2 refresh token not obtained\n"));
398 sock_close(sock
, TRUE
);
404 g_free(client_secret
);
405 g_free(access_token
);
406 g_free(refresh_token
);
411 gint
oauth2_use_refresh_token (Oauth2Service provider
, OAUTH2Data
*OAUTH2Data
)
419 gchar
*tmp_hd
, *tmp_hd_encoded
;
421 gchar
*refresh_token
;
426 gchar
*client_secret
;
430 i
= (int)provider
- 1;
431 if (i
< 0 || i
> (OAUTH2AUTH_LAST
-1))
434 sock
= sock_connect(OAUTH2info
[i
][OA2_BASE_URL
], 443);
436 log_message(LOG_PROTOCOL
, _("OAuth2 connection error\n"));
439 sock
->ssl_cert_auto_accept
= TRUE
;
440 sock
->use_tls_sni
= TRUE
;
441 sock_set_nonblocking_mode(sock
, FALSE
);
442 gint timeout_secs
= prefs_common_get_prefs()->io_timeout_secs
;
443 debug_print("Socket timeout: %i sec(s)\n", timeout_secs
);
444 sock_set_io_timeout(timeout_secs
);
445 sock
->gnutls_priority
= GNUTLS_PRIORITY
;
446 if (ssl_init_socket(sock
) == FALSE
) {
447 log_message(LOG_PROTOCOL
, _("OAuth2 TLS connection error\n"));
451 access_token
= g_malloc(OAUTH2BUFSIZE
+1);
452 refresh_token
= g_malloc(OAUTH2BUFSIZE
+1);
453 request
= g_malloc(OAUTH2BUFSIZE
+1);
455 if(OAUTH2Data
->custom_client_id
)
456 client_id
= g_strdup(OAUTH2Data
->custom_client_id
);
458 client_id
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_ID
]);
460 uri
= g_uri_escape_string (client_id
, NULL
, FALSE
);
461 body
= g_strconcat ("client_id=", uri
, "&refresh_token=", OAUTH2Data
->refresh_token
, NULL
);
464 if(OAUTH2info
[i
][OA2_CLIENT_SECRET
][0]){
465 //Only allow custom client secret if the service provider would usually expect a client secret
466 if(OAUTH2Data
->custom_client_secret
)
467 client_secret
= g_strdup(OAUTH2Data
->custom_client_secret
);
469 client_secret
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_SECRET
]);
470 uri
= g_uri_escape_string (client_secret
, NULL
, FALSE
);
471 tmp
= g_strconcat (body
, "&client_secret=", uri
, NULL
);
476 client_secret
= g_strconcat ("", NULL
);
479 if(OAUTH2info
[i
][OA2_GRANT_TYPE_REFRESH
][0]) {
480 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_GRANT_TYPE_REFRESH
], NULL
, FALSE
);
481 tmp
= g_strconcat (body
, "&grant_type=", uri
, NULL
);
486 if(OAUTH2info
[i
][OA2_SCOPE_FOR_ACCESS
][0]) {
487 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_SCOPE_FOR_ACCESS
], NULL
, FALSE
);
488 tmp
= g_strconcat (body
, "&scope=", uri
, NULL
);
493 if(OAUTH2info
[i
][OA2_STATE
][0]) {
494 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_STATE
], NULL
, FALSE
);
495 tmp
= g_strconcat (body
, "&state=", uri
, NULL
);
501 if(OAUTH2info
[i
][OA2_HEADER_AUTH_BASIC
][0]){
502 tmp_hd
= g_strconcat(client_id
, ":", client_secret
, NULL
);
503 tmp_hd_encoded
= g_base64_encode (tmp_hd
, strlen(tmp_hd
));
504 header
= g_strconcat ("Authorization: Basic ", tmp_hd_encoded
, NULL
);
505 g_free(tmp_hd_encoded
);
508 header
= g_strconcat ("", NULL
);
511 oauth2_post_request (request
, OAUTH2info
[i
][OA2_BASE_URL
], OAUTH2info
[i
][OA2_REFRESH_RESOURCE
], header
, body
);
512 debug_print("Request: %s\n", request
);
513 response
= oauth2_contact_server (sock
, request
);
514 debug_print("Response from server: %s\n", response
);
517 if(response
&& oauth2_filter_access (response
, access_token
, &expiry
) == 0){
518 OAUTH2Data
->access_token
= g_strdup(access_token
);
519 OAUTH2Data
->expiry
= expiry
;
520 OAUTH2Data
->expiry_str
= g_strdup_printf ("%i", expiry
);
522 log_message(LOG_PROTOCOL
, _("OAuth2 access token obtained\n"));
524 log_message(LOG_PROTOCOL
, _("OAuth2 access token not obtained\n"));
525 debug_print("OAuth2 - request: %s\n Response: %s", request
, response
);
529 if (response
&& oauth2_filter_refresh (response
, refresh_token
) == 0) {
530 OAUTH2Data
->refresh_token
= g_strdup(refresh_token
);
531 log_message(LOG_PROTOCOL
, _("OAuth2 replacement refresh token provided\n"));
533 log_message(LOG_PROTOCOL
, _("OAuth2 replacement refresh token not provided\n"));
535 debug_print("OAuth2 - access token: %s\n", access_token
);
536 debug_print("OAuth2 - access token expiry: %i\n", expiry
);
538 sock_close(sock
, TRUE
);
544 g_free(client_secret
);
545 g_free(access_token
);
546 g_free(refresh_token
);
551 gint
oauth2_authorisation_url (Oauth2Service provider
, gchar
**url
, const gchar
*custom_client_id
)
554 gchar
*client_id
= NULL
;
558 i
= (int)provider
- 1;
559 if (i
< 0 || i
> (OAUTH2AUTH_LAST
-1))
562 if(!custom_client_id
)
563 client_id
= oauth2_decode(OAUTH2info
[i
][OA2_CLIENT_ID
]);
565 uri
= g_uri_escape_string (custom_client_id
? custom_client_id
: client_id
, NULL
, FALSE
);
566 *url
= g_strconcat ("https://", OAUTH2info
[i
][OA2_BASE_URL
],OAUTH2info
[i
][OA2_AUTH_RESOURCE
], "?client_id=",
572 if(OAUTH2info
[i
][OA2_REDIRECT_URI
][0]) {
573 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_REDIRECT_URI
], NULL
, FALSE
);
574 tmp
= g_strconcat (*url
, "&redirect_uri=", uri
, NULL
);
580 if(OAUTH2info
[i
][OA2_RESPONSE_TYPE
][0]) {
581 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_RESPONSE_TYPE
], NULL
, FALSE
);
582 tmp
= g_strconcat (*url
, "&response_type=", uri
, NULL
);
587 if(OAUTH2info
[i
][OA2_SCOPE_FOR_AUTH
][0]) {
588 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_SCOPE_FOR_AUTH
], NULL
, FALSE
);
589 tmp
= g_strconcat (*url
, "&scope=", uri
, NULL
);
594 if(OAUTH2info
[i
][OA2_TENANT
][0]) {
595 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_TENANT
], NULL
, FALSE
);
596 tmp
= g_strconcat (*url
, "&tenant=", uri
, NULL
);
601 if(OAUTH2info
[i
][OA2_RESPONSE_MODE
][0]) {
602 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_RESPONSE_MODE
], NULL
, FALSE
);
603 tmp
= g_strconcat (*url
, "&response_mode=", uri
, NULL
);
608 if(OAUTH2info
[i
][OA2_STATE
][0]) {
609 uri
= g_uri_escape_string (OAUTH2info
[i
][OA2_STATE
], NULL
, FALSE
);
610 tmp
= g_strconcat (*url
, "&state=", uri
, NULL
);
619 gint
oauth2_check_passwds (PrefsAccount
*ac_prefs
)
621 gchar
*uid
= g_strdup_printf("%d", ac_prefs
->account_id
);
623 OAUTH2Data
*OAUTH2Data
= g_malloc(sizeof(* OAUTH2Data
));
627 oauth2_init (OAUTH2Data
);
629 OAUTH2Data
->custom_client_id
= ac_prefs
->oauth2_client_id
;
630 OAUTH2Data
->custom_client_secret
= ac_prefs
->oauth2_client_secret
;
632 if (passwd_store_has_password(PWS_ACCOUNT
, uid
, PWS_ACCOUNT_OAUTH2_EXPIRY
)) {
633 acc
= passwd_store_get_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_EXPIRY
);
636 if (expiry
> (g_get_real_time () / G_USEC_PER_SEC
)) {
638 log_message(LOG_PROTOCOL
, _("OAuth2 access token still fresh\n"));
644 if (passwd_store_has_password(PWS_ACCOUNT
, uid
, PWS_ACCOUNT_OAUTH2_REFRESH
)) {
645 log_message(LOG_PROTOCOL
, _("OAuth2 obtaining access token using refresh token\n"));
646 OAUTH2Data
->refresh_token
= passwd_store_get_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_REFRESH
);
647 ret
= oauth2_use_refresh_token (ac_prefs
->oauth2_provider
, OAUTH2Data
);
648 } else if (passwd_store_has_password(PWS_ACCOUNT
, uid
, PWS_ACCOUNT_OAUTH2_AUTH
)) {
649 log_message(LOG_PROTOCOL
, _("OAuth2 trying for fresh access token with authorization code\n"));
650 acc
= passwd_store_get_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_AUTH
);
651 ret
= oauth2_obtain_tokens (ac_prefs
->oauth2_provider
, OAUTH2Data
, acc
);
657 log_message(LOG_PROTOCOL
, _("OAuth2 access token not obtained\n"));
659 if (ac_prefs
->imap_auth_type
== IMAP_AUTH_OAUTH2
||
660 (ac_prefs
->use_pop_auth
&& ac_prefs
->pop_auth_type
== POPAUTH_OAUTH2
))
661 passwd_store_set_account(ac_prefs
->account_id
, PWS_ACCOUNT_RECV
, OAUTH2Data
->access_token
, FALSE
);
662 if (ac_prefs
->use_smtp_auth
&& ac_prefs
->smtp_auth_type
== SMTPAUTH_OAUTH2
)
663 passwd_store_set_account(ac_prefs
->account_id
, PWS_ACCOUNT_SEND
, OAUTH2Data
->access_token
, FALSE
);
664 passwd_store_set_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_EXPIRY
, OAUTH2Data
->expiry_str
, FALSE
);
665 //Some providers issue replacement refresh tokens with each access token. Re-store whether replaced or not.
666 if (OAUTH2Data
->refresh_token
!= NULL
)
667 passwd_store_set_account(ac_prefs
->account_id
, PWS_ACCOUNT_OAUTH2_REFRESH
, OAUTH2Data
->refresh_token
, FALSE
);
668 passwd_store_write_config();
669 log_message(LOG_PROTOCOL
, _("OAuth2 access and refresh token updated\n"));
678 /* returns allocated string which must be freed */
679 guchar
* oauth2_decode(const gchar
*in
)
684 tmp
= g_base64_decode(in
, &len
);
685 passcrypt_decrypt(tmp
, len
);
690 void oauth2_encode(const gchar
*in
)
692 guchar
*tmp
= g_strdup(in
);
693 guchar
*tmp2
= g_strdup(in
);
695 gsize len
= strlen(in
);
697 passcrypt_encrypt(tmp
, len
);
698 result
= g_base64_encode(tmp
, len
);
699 tmp2
= oauth2_decode(result
);
701 log_message(LOG_PROTOCOL
, _("OAuth2 original: %s\n"), in
);
702 log_message(LOG_PROTOCOL
, _("OAuth2 encoded: %s\n"), result
);
703 log_message(LOG_PROTOCOL
, _("OAuth2 decoded: %s\n\n"), tmp2
);
710 gint
oauth2_init (OAUTH2Data
*OAUTH2Data
)
712 OAUTH2Data
->refresh_token
= NULL
;
713 OAUTH2Data
->access_token
= NULL
;
714 OAUTH2Data
->expiry_str
= NULL
;
715 OAUTH2Data
->expiry
= 0;
716 OAUTH2Data
->custom_client_id
= NULL
;
717 OAUTH2Data
->custom_client_secret
= NULL
;
722 #endif /* USE_GNUTLS */