* Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * Rewritten from scratch during Google Summer of Code 2012 * by Tomek Wasilczyk (http://www.wasilczyk.pl). * Previously implemented by: * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001); * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005; * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011). * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA #include "oauth/oauth-purple.h" #define GGP_AVATAR_USERAGENT "GG Client build 11.0.0.7562" #define GGP_AVATAR_SIZE_MAX 1048576 /* Buddy avatars updating */ } ggp_avatar_buddy_update_req; #define GGP_AVATAR_BUDDY_URL "http://avatars.gg.pl/%u/s,big" struct _ggp_avatar_session_data { #define GGP_AVATAR_RESPONSE_MAX 10240 /******************************************************************************* ******************************************************************************/ static inline ggp_avatar_session_data * ggp_avatar_get_avdata(PurpleConnection *gc) GGPInfo *accdata = purple_connection_get_protocol_data(gc); return accdata->avatar_data; void ggp_avatar_setup(PurpleConnection *gc) GGPInfo *info = purple_connection_get_protocol_data(gc); info->avatar_data = g_new0(ggp_avatar_session_data, 1); void ggp_avatar_cleanup(PurpleConnection *gc) GGPInfo *info = purple_connection_get_protocol_data(gc); g_free(info->avatar_data); /******************************************************************************* * Buddy avatars updating. ******************************************************************************/ void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin) if (purple_debug_is_verbose()) { purple_debug_misc("gg", "ggp_avatar_buddy_remove(%p, %u)\n", gc, uin); purple_buddy_icons_set_for_user(purple_connection_get_account(gc), ggp_uin_to_str(uin), NULL, 0, NULL); ggp_avatar_buddy_update_received(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg, gpointer _pending_update) ggp_avatar_buddy_update_req *pending_update = _pending_update; PurpleConnection *gc = pending_update->gc; PURPLE_ASSERT_CONNECTION_IS_VALID(gc); if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) { "ggp_avatar_buddy_update_received: bad response " "while getting avatar for %u: %s", pending_update->uin, msg->reason_phrase); account = purple_connection_get_account(gc); buddy = purple_blist_find_buddy(account, ggp_uin_to_str(pending_update->uin)); "gg", "ggp_avatar_buddy_update_received: buddy %u disappeared", g_snprintf(timestamp_str, sizeof(timestamp_str), "%lu", pending_update->timestamp); got_data = msg->response_body->data; got_len = msg->response_body->length; purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy), g_memdup(got_data, got_len), got_len, "ggp_avatar_buddy_update_received: got avatar for buddy " pending_update->uin, pending_update->timestamp); ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp) GGPInfo *info = purple_connection_get_protocol_data(gc); ggp_avatar_buddy_update_req *pending_update; PurpleAccount *account = purple_connection_get_account(gc); const char *old_timestamp_str; if (purple_debug_is_verbose()) { purple_debug_misc("gg", "ggp_avatar_buddy_update(%p, %u, %lu)", gc, uin, buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin)); if (ggp_str_to_uin(purple_account_get_username(account)) == uin) { "ggp_avatar_buddy_update(%p): own avatar update requested, " "but we don't have ourselves on buddy list", purple_debug_warning("gg", "ggp_avatar_buddy_update(%p): %u update " "requested, but he's not on buddy list", old_timestamp_str = purple_buddy_icons_get_checksum_for_user(buddy); old_timestamp = old_timestamp_str ? g_ascii_strtoull( old_timestamp_str, NULL, 10) : 0; if (old_timestamp == timestamp) { if (purple_debug_is_verbose()) { "ggp_avatar_buddy_update(%p): %u have up to date " if (old_timestamp > timestamp) { purple_debug_warning("gg", "ggp_avatar_buddy_update(%p): saved timestamp for " "%u is newer than received (%lu > %lu)", gc, uin, old_timestamp, timestamp); "ggp_avatar_buddy_update(%p): updating %u with ts=%lu...", pending_update = g_new(ggp_avatar_buddy_update_req, 1); pending_update->uin = uin; pending_update->timestamp = timestamp; url = g_strdup_printf(GGP_AVATAR_BUDDY_URL, pending_update->uin); req = soup_message_new("GET", url); soup_message_headers_replace(req->request_headers, "User-Agent", // purple_http_request_set_max_len(req, GGP_AVATAR_SIZE_MAX); soup_session_queue_message( info->http, req, ggp_avatar_buddy_update_received, pending_update); /******************************************************************************* ******************************************************************************/ * TODO: use new, GG11 method, when IMToken will be provided by libgadu. * POST https://avatars.mpa.gg.pl/avatars/user,<uin>/0 * Authorization: IMToken 0123456789abcdef0123456789abcdef01234567 ggp_avatar_own_sent(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg, PurpleConnection *gc = user_data; PURPLE_ASSERT_CONNECTION_IS_VALID(gc); if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) { purple_debug_error("gg", "ggp_avatar_own_sent: avatar not sent. %s\n", purple_debug_info("gg", "ggp_avatar_own_sent: %s\n", msg->response_body->data); ggp_avatar_own_got_token(PurpleConnection *gc, const gchar *token, GGPInfo *info = purple_connection_get_protocol_data(gc); ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc); gchar *img_data, *uin_str; PurpleAccount *account = purple_connection_get_account(gc); uin_t uin = ggp_str_to_uin(purple_account_get_username(account)); if (img != avdata->own_img) { purple_debug_warning("gg", "ggp_avatar_own_got_token: " "avatar was changed in meantime\n"); img_data = g_base64_encode(purple_image_get_data(img), purple_image_get_data_size(img)); uin_str = g_strdup_printf("%d", uin); purple_debug_misc("gg", "ggp_avatar_own_got_token: " "uploading new avatar...\n"); req = soup_form_request_new("POST", "http://avatars.nowe.gg/upload", "uin", uin_str, "photo", img_data, NULL); // purple_http_request_set_max_len(req, GGP_AVATAR_RESPONSE_MAX); soup_message_headers_replace(req->request_headers, "Authorization", token); soup_message_headers_replace(req->request_headers, "From", soup_session_queue_message(info->http, req, ggp_avatar_own_sent, gc); ggp_avatar_own_set(PurpleConnection *gc, PurpleImage *img) ggp_avatar_session_data *avdata; PURPLE_ASSERT_CONNECTION_IS_VALID(gc); purple_debug_info("gg", "ggp_avatar_own_set(%p, %p)", gc, img); avdata = ggp_avatar_get_avdata(gc); purple_debug_warning("gg", "ggp_avatar_own_set: avatar removing is " "probably not possible within old protocol"); ggp_oauth_request(gc, ggp_avatar_own_got_token, img, NULL, NULL);