eion/purple-hangouts
Merge
draft
2019-05-24, Eion Robb
* Hangouts Plugin for libpurple/Pidgin * Copyright (c) 2015-2016 Eion Robb, Mike Ruprecht * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. #include "hangouts_auth.h" #include "hangouts_json.h" #include "hangouts_connection.h" #include "hangouts_conversation.h" static gpointer bitlbee_module; static bitlbee_im_connection *(*bitlbee_purple_ic_by_pa)(PurpleAccount *); static int (*bitlbee_set_setstr)(gpointer *, const char *, const char *); static gboolean bitlbee_password_funcs_loaded = FALSE; # define dlopen(filename, flag) GetModuleHandleA(filename) # define dlsym(handle, symbol) GetProcAddress(handle, symbol) # define dlclose(handle) FreeLibrary(handle) static gchar *last_dlopen_error = NULL; # define dlerror() (g_free(last_dlopen_error),last_dlopen_error=g_win32_error_message(GetLastError())) # define RTLD_LAZY 0x0001 save_bitlbee_password(PurpleAccount *account, const gchar *password) bitlbee_im_connection *imconn; gboolean result = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_accounts_get_handle(), "bitlbee-set-account-password", account, password)); if (bitlbee_password_funcs_loaded == FALSE) { bitlbee_module = dlopen(NULL, RTLD_LAZY); if (bitlbee_module == NULL) { purple_debug_error("hangouts", "Couldn't acquire address of bitlbee handle: %s\n", dlerror()); g_return_if_fail(bitlbee_module); bitlbee_purple_ic_by_pa = (gpointer) dlsym(bitlbee_module, "purple_ic_by_pa"); bitlbee_set_setstr = (gpointer) dlsym(bitlbee_module, "set_setstr"); bitlbee_password_funcs_loaded = TRUE; imconn = bitlbee_purple_ic_by_pa(account); bitlbee_set_setstr(&acc->set, "password", password ? password : ""); hangouts_save_refresh_token_password(PurpleAccount *account, const gchar *password) purple_account_set_password(account, password, NULL, NULL); if (g_strcmp0(purple_core_get_ui(), "BitlBee") == 0) { save_bitlbee_password(account, password); hangouts_oauth_refresh_token_cb(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data) HangoutsAccount *ha = user_data; const gchar *raw_response; raw_response = purple_http_response_get_data(response, &response_len); obj = json_decode_object(raw_response, response_len); if (purple_http_response_is_successful(response) && obj) ha->access_token = g_strdup(json_object_get_string_member(obj, "access_token")); hangouts_auth_get_session_cookies(ha); if (json_object_has_member(obj, "error")) { if (g_strcmp0(json_object_get_string_member(obj, "error"), "invalid_grant") == 0) { hangouts_save_refresh_token_password(ha->account, NULL); purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, json_object_get_string_member(obj, "error_description")); purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, json_object_get_string_member(obj, "error_description")); purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, hangouts_oauth_refresh_token(HangoutsAccount *ha) PurpleHttpRequest *request; postdata = g_string_new(NULL); g_string_append_printf(postdata, "client_id=%s&", purple_url_encode(GOOGLE_CLIENT_ID)); g_string_append_printf(postdata, "client_secret=%s&", purple_url_encode(GOOGLE_CLIENT_SECRET)); g_string_append_printf(postdata, "refresh_token=%s&", purple_url_encode(ha->refresh_token)); g_string_append(postdata, "grant_type=refresh_token&"); request = purple_http_request_new(HANGOUTS_API_OAUTH2_TOKEN_URL); purple_http_request_set_cookie_jar(request, ha->cookie_jar); purple_http_request_set_method(request, "POST"); purple_http_request_header_set(request, "Content-Type", "application/x-www-form-urlencoded"); purple_http_request_set_contents(request, postdata->str, postdata->len); purple_http_request(pc, request, hangouts_oauth_refresh_token_cb, ha); purple_http_request_unref(request); purple_debug_info("hangouts", "Postdata: %s\n", postdata->str); g_string_free(postdata, TRUE); hangouts_oauth_with_code_cb(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data) HangoutsAccount *ha = user_data; const gchar *raw_response; PurpleAccount *account = ha->account; raw_response = purple_http_response_get_data(response, &response_len); obj = json_decode_object(raw_response, response_len); if (purple_http_response_is_successful(response) && obj) ha->access_token = g_strdup(json_object_get_string_member(obj, "access_token")); ha->refresh_token = g_strdup(json_object_get_string_member(obj, "refresh_token")); purple_account_set_remember_password(account, TRUE); hangouts_save_refresh_token_password(account, ha->refresh_token); hangouts_auth_get_session_cookies(ha); if (json_object_has_member(obj, "error")) { if (g_strcmp0(json_object_get_string_member(obj, "error"), "invalid_grant") == 0) { hangouts_save_refresh_token_password(ha->account, NULL); purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, json_object_get_string_member(obj, "error_description")); purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, json_object_get_string_member(obj, "error_description")); purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, hangouts_oauth_with_code(HangoutsAccount *ha, const gchar *auth_code) PurpleHttpRequest *request; postdata = g_string_new(NULL); g_string_append_printf(postdata, "client_id=%s&", purple_url_encode(GOOGLE_CLIENT_ID)); g_string_append_printf(postdata, "client_secret=%s&", purple_url_encode(GOOGLE_CLIENT_SECRET)); g_string_append_printf(postdata, "code=%s&", purple_url_encode(auth_code)); g_string_append_printf(postdata, "redirect_uri=%s&", purple_url_encode(HANGOUTS_API_OAUTH2_REDIRECT_URI)); g_string_append(postdata, "grant_type=authorization_code&"); request = purple_http_request_new(HANGOUTS_API_OAUTH2_TOKEN_URL); purple_http_request_set_cookie_jar(request, ha->cookie_jar); purple_http_request_set_method(request, "POST"); purple_http_request_header_set(request, "Content-Type", "application/x-www-form-urlencoded"); purple_http_request_set_contents(request, postdata->str, postdata->len); purple_http_request(pc, request, hangouts_oauth_with_code_cb, ha); purple_http_request_unref(request); g_string_free(postdata, TRUE); /*****************************************************************************/ hangouts_auth_get_session_cookies_got_cb(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data) HangoutsAccount *ha = user_data; guint64 last_event_timestamp; gchar *sapisid_cookie = purple_http_cookie_jar_get(ha->cookie_jar, "SAPISID"); if (sapisid_cookie == NULL) { purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, _("SAPISID Cookie not received")); //Restore the last_event_timestamp before it gets overridden by new events last_event_timestamp = purple_account_get_int(ha->account, "last_event_timestamp_high", 0); if (last_event_timestamp != 0) { last_event_timestamp = (last_event_timestamp << 32) | ((guint64) purple_account_get_int(ha->account, "last_event_timestamp_low", 0) & 0xFFFFFFFF); ha->last_event_timestamp = last_event_timestamp; hangouts_fetch_channel_sid(ha); purple_connection_set_state(ha->pc, PURPLE_CONNECTION_CONNECTED); //TODO trigger event instead hangouts_get_self_info(ha); hangouts_get_conversation_list(ha); ha->poll_buddy_status_timeout = g_timeout_add_seconds(120, hangouts_poll_buddy_status, ha); hangouts_auth_get_session_cookies_uberauth_cb(PurpleHttpConnection *http_conn, PurpleHttpResponse *response, gpointer user_data) HangoutsAccount *ha = user_data; PurpleHttpRequest *request; uberauth = purple_http_response_get_data(response, NULL); if (purple_http_response_get_error(response) != NULL) { purple_connection_error(ha->pc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, purple_debug_misc("hangouts-prpl", "uberauth: %s", uberauth); request = purple_http_request_new(NULL); purple_http_request_set_url_printf(request, "https://accounts.google.com/MergeSession" "?service=mail&continue=http://www.google.com&uberauth=%s", purple_url_encode(uberauth)); purple_http_request_set_cookie_jar(request, ha->cookie_jar); purple_http_request_header_set_printf(request, "Authorization", "Bearer %s", ha->access_token); purple_http_request_set_max_redirects(request, 0); purple_http_request(ha->pc, request, hangouts_auth_get_session_cookies_got_cb, ha); purple_http_request_unref(request); hangouts_auth_get_session_cookies(HangoutsAccount *ha) PurpleHttpRequest *request; request = purple_http_request_new("https://accounts.google.com/accounts/OAuthLogin" "?source=pidgin&issueuberauth=1"); purple_http_request_set_cookie_jar(request, ha->cookie_jar); purple_http_request_header_set_printf(request, "Authorization", "Bearer %s", ha->access_token); purple_http_request(ha->pc, request, hangouts_auth_get_session_cookies_uberauth_cb, ha); purple_http_request_unref(request);