3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * Rewritten from scratch during Google Summer of Code 2012
8 * by Tomek Wasilczyk (http://www.wasilczyk.pl).
10 * Previously implemented by:
11 * - Arkadiusz Miskiewicz <misiek@pld.org.pl> - first implementation (2001);
12 * - Bartosz Oler <bartosz@bzimage.us> - reimplemented during GSoC 2005;
13 * - Krzysztof Klinikowski <grommasher@gmail.com> - some parts (2009-2011).
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
33 #include <glibcompat.h>
37 #include "oauth/oauth-purple.h"
41 #define GGP_AVATAR_USERAGENT "GG Client build 11.0.0.7562"
42 #define GGP_AVATAR_SIZE_MAX 1048576
44 /* Buddy avatars updating */
51 } ggp_avatar_buddy_update_req
;
53 #define GGP_AVATAR_BUDDY_URL "http://avatars.gg.pl/%u/s,big"
55 /* Own avatar setting */
57 struct _ggp_avatar_session_data
{
61 #define GGP_AVATAR_RESPONSE_MAX 10240
63 /*******************************************************************************
65 ******************************************************************************/
67 static inline ggp_avatar_session_data
*
68 ggp_avatar_get_avdata(PurpleConnection
*gc
)
70 GGPInfo
*accdata
= purple_connection_get_protocol_data(gc
);
71 return accdata
->avatar_data
;
74 void ggp_avatar_setup(PurpleConnection
*gc
)
76 GGPInfo
*info
= purple_connection_get_protocol_data(gc
);
78 info
->avatar_data
= g_new0(ggp_avatar_session_data
, 1);
81 void ggp_avatar_cleanup(PurpleConnection
*gc
)
83 GGPInfo
*info
= purple_connection_get_protocol_data(gc
);
85 g_free(info
->avatar_data
);
88 /*******************************************************************************
89 * Buddy avatars updating.
90 ******************************************************************************/
92 void ggp_avatar_buddy_remove(PurpleConnection
*gc
, uin_t uin
)
94 if (purple_debug_is_verbose()) {
95 purple_debug_misc("gg", "ggp_avatar_buddy_remove(%p, %u)\n", gc
, uin
);
98 purple_buddy_icons_set_for_user(purple_connection_get_account(gc
),
99 ggp_uin_to_str(uin
), NULL
, 0, NULL
);
103 ggp_avatar_buddy_update_received(G_GNUC_UNUSED SoupSession
*session
,
104 SoupMessage
*msg
, gpointer _pending_update
)
106 ggp_avatar_buddy_update_req
*pending_update
= _pending_update
;
108 PurpleAccount
*account
;
109 PurpleConnection
*gc
= pending_update
->gc
;
110 gchar timestamp_str
[20];
111 const gchar
*got_data
;
114 PURPLE_ASSERT_CONNECTION_IS_VALID(gc
);
116 if (!SOUP_STATUS_IS_SUCCESSFUL(msg
->status_code
)) {
117 purple_debug_error("gg",
118 "ggp_avatar_buddy_update_received: bad response "
119 "while getting avatar for %u: %s",
120 pending_update
->uin
, msg
->reason_phrase
);
121 g_free(pending_update
);
125 account
= purple_connection_get_account(gc
);
126 buddy
= purple_blist_find_buddy(account
,
127 ggp_uin_to_str(pending_update
->uin
));
130 purple_debug_warning(
131 "gg", "ggp_avatar_buddy_update_received: buddy %u disappeared",
132 pending_update
->uin
);
133 g_free(pending_update
);
137 g_snprintf(timestamp_str
, sizeof(timestamp_str
), "%lu",
138 pending_update
->timestamp
);
139 got_data
= msg
->response_body
->data
;
140 got_len
= msg
->response_body
->length
;
141 purple_buddy_icons_set_for_user(account
, purple_buddy_get_name(buddy
),
142 g_memdup(got_data
, got_len
), got_len
,
145 purple_debug_info("gg",
146 "ggp_avatar_buddy_update_received: got avatar for buddy "
148 pending_update
->uin
, pending_update
->timestamp
);
149 g_free(pending_update
);
153 ggp_avatar_buddy_update(PurpleConnection
*gc
, uin_t uin
, time_t timestamp
)
155 GGPInfo
*info
= purple_connection_get_protocol_data(gc
);
158 ggp_avatar_buddy_update_req
*pending_update
;
160 PurpleAccount
*account
= purple_connection_get_account(gc
);
161 time_t old_timestamp
;
162 const char *old_timestamp_str
;
164 if (purple_debug_is_verbose()) {
165 purple_debug_misc("gg", "ggp_avatar_buddy_update(%p, %u, %lu)", gc
, uin
,
169 buddy
= purple_blist_find_buddy(account
, ggp_uin_to_str(uin
));
172 if (ggp_str_to_uin(purple_account_get_username(account
)) == uin
) {
175 "ggp_avatar_buddy_update(%p): own avatar update requested, "
176 "but we don't have ourselves on buddy list",
179 purple_debug_warning("gg",
180 "ggp_avatar_buddy_update(%p): %u update "
181 "requested, but he's not on buddy list",
187 old_timestamp_str
= purple_buddy_icons_get_checksum_for_user(buddy
);
188 old_timestamp
= old_timestamp_str
? g_ascii_strtoull(
189 old_timestamp_str
, NULL
, 10) : 0;
190 if (old_timestamp
== timestamp
) {
191 if (purple_debug_is_verbose()) {
192 purple_debug_misc("gg",
193 "ggp_avatar_buddy_update(%p): %u have up to date "
194 "avatar with ts=%lu",
199 if (old_timestamp
> timestamp
) {
200 purple_debug_warning("gg",
201 "ggp_avatar_buddy_update(%p): saved timestamp for "
202 "%u is newer than received (%lu > %lu)",
203 gc
, uin
, old_timestamp
, timestamp
);
206 purple_debug_info("gg",
207 "ggp_avatar_buddy_update(%p): updating %u with ts=%lu...",
210 pending_update
= g_new(ggp_avatar_buddy_update_req
, 1);
211 pending_update
->uin
= uin
;
212 pending_update
->timestamp
= timestamp
;
213 pending_update
->gc
= gc
;
215 url
= g_strdup_printf(GGP_AVATAR_BUDDY_URL
, pending_update
->uin
);
216 req
= soup_message_new("GET", url
);
218 soup_message_headers_replace(req
->request_headers
, "User-Agent",
219 GGP_AVATAR_USERAGENT
);
220 // purple_http_request_set_max_len(req, GGP_AVATAR_SIZE_MAX);
221 soup_session_queue_message(
222 info
->http
, req
, ggp_avatar_buddy_update_received
, pending_update
);
225 /*******************************************************************************
226 * Own avatar setting.
227 ******************************************************************************/
230 * TODO: use new, GG11 method, when IMToken will be provided by libgadu.
232 * POST https://avatars.mpa.gg.pl/avatars/user,<uin>/0
233 * Authorization: IMToken 0123456789abcdef0123456789abcdef01234567
234 * photo=<avatar content>
238 ggp_avatar_own_sent(G_GNUC_UNUSED SoupSession
*session
, SoupMessage
*msg
,
241 PurpleConnection
*gc
= user_data
;
243 PURPLE_ASSERT_CONNECTION_IS_VALID(gc
);
245 if (!SOUP_STATUS_IS_SUCCESSFUL(msg
->status_code
)) {
246 purple_debug_error("gg", "ggp_avatar_own_sent: avatar not sent. %s\n",
250 purple_debug_info("gg", "ggp_avatar_own_sent: %s\n",
251 msg
->response_body
->data
);
255 ggp_avatar_own_got_token(PurpleConnection
*gc
, const gchar
*token
,
258 GGPInfo
*info
= purple_connection_get_protocol_data(gc
);
259 ggp_avatar_session_data
*avdata
= ggp_avatar_get_avdata(gc
);
261 PurpleImage
*img
= _img
;
262 gchar
*img_data
, *uin_str
;
263 PurpleAccount
*account
= purple_connection_get_account(gc
);
264 uin_t uin
= ggp_str_to_uin(purple_account_get_username(account
));
266 if (img
!= avdata
->own_img
) {
267 purple_debug_warning("gg", "ggp_avatar_own_got_token: "
268 "avatar was changed in meantime\n");
271 avdata
->own_img
= NULL
;
273 img_data
= g_base64_encode(purple_image_get_data(img
),
274 purple_image_get_data_size(img
));
275 uin_str
= g_strdup_printf("%d", uin
);
277 purple_debug_misc("gg", "ggp_avatar_own_got_token: "
278 "uploading new avatar...\n");
280 req
= soup_form_request_new("POST", "http://avatars.nowe.gg/upload", "uin",
281 uin_str
, "photo", img_data
, NULL
);
282 // purple_http_request_set_max_len(req, GGP_AVATAR_RESPONSE_MAX);
283 soup_message_headers_replace(req
->request_headers
, "Authorization", token
);
284 soup_message_headers_replace(req
->request_headers
, "From",
285 "avatars to avatars");
286 soup_session_queue_message(info
->http
, req
, ggp_avatar_own_sent
, gc
);
292 ggp_avatar_own_set(PurpleConnection
*gc
, PurpleImage
*img
)
294 ggp_avatar_session_data
*avdata
;
296 PURPLE_ASSERT_CONNECTION_IS_VALID(gc
);
298 purple_debug_info("gg", "ggp_avatar_own_set(%p, %p)", gc
, img
);
300 avdata
= ggp_avatar_get_avdata(gc
);
303 purple_debug_warning("gg", "ggp_avatar_own_set: avatar removing is "
304 "probably not possible within old protocol");
308 avdata
->own_img
= img
;
310 ggp_oauth_request(gc
, ggp_avatar_own_got_token
, img
, NULL
, NULL
);