Replace functions which called once with their bodies
[pidgin-git.git] / libpurple / protocols / gg / avatar.c
blobe7cd0bf7d68dc5537b80e9f80444db60b6f93905
1 /* purple
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
5 * source distribution.
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
30 #include "avatar.h"
32 #include <debug.h>
33 #include <glibcompat.h>
35 #include "gg.h"
36 #include "utils.h"
37 #include "oauth/oauth-purple.h"
39 /* Common */
41 #define GGP_AVATAR_USERAGENT "GG Client build 11.0.0.7562"
42 #define GGP_AVATAR_SIZE_MAX 1048576
44 /* Buddy avatars updating */
46 typedef struct
48 uin_t uin;
49 time_t timestamp;
50 PurpleConnection *gc;
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 {
58 PurpleImage *own_img;
61 #define GGP_AVATAR_RESPONSE_MAX 10240
63 /*******************************************************************************
64 * Common.
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);
102 static void
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;
107 PurpleBuddy *buddy;
108 PurpleAccount *account;
109 PurpleConnection *gc = pending_update->gc;
110 gchar timestamp_str[20];
111 const gchar *got_data;
112 size_t got_len;
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);
122 return;
125 account = purple_connection_get_account(gc);
126 buddy = purple_blist_find_buddy(account,
127 ggp_uin_to_str(pending_update->uin));
129 if (!buddy) {
130 purple_debug_warning(
131 "gg", "ggp_avatar_buddy_update_received: buddy %u disappeared",
132 pending_update->uin);
133 g_free(pending_update);
134 return;
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,
143 timestamp_str);
145 purple_debug_info("gg",
146 "ggp_avatar_buddy_update_received: got avatar for buddy "
147 "%u [ts=%lu]",
148 pending_update->uin, pending_update->timestamp);
149 g_free(pending_update);
152 void
153 ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp)
155 GGPInfo *info = purple_connection_get_protocol_data(gc);
156 gchar *url;
157 SoupMessage *req;
158 ggp_avatar_buddy_update_req *pending_update;
159 PurpleBuddy *buddy;
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,
166 timestamp);
169 buddy = purple_blist_find_buddy(account, ggp_uin_to_str(uin));
171 if (!buddy) {
172 if (ggp_str_to_uin(purple_account_get_username(account)) == uin) {
173 purple_debug_misc(
174 "gg",
175 "ggp_avatar_buddy_update(%p): own avatar update requested, "
176 "but we don't have ourselves on buddy list",
177 gc);
178 } else {
179 purple_debug_warning("gg",
180 "ggp_avatar_buddy_update(%p): %u update "
181 "requested, but he's not on buddy list",
182 gc, uin);
184 return;
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",
195 gc, uin, timestamp);
197 return;
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...",
208 gc, uin, timestamp);
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);
217 g_free(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>
237 static void
238 ggp_avatar_own_sent(G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
239 gpointer user_data)
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",
247 msg->reason_phrase);
248 return;
250 purple_debug_info("gg", "ggp_avatar_own_sent: %s\n",
251 msg->response_body->data);
254 static void
255 ggp_avatar_own_got_token(PurpleConnection *gc, const gchar *token,
256 gpointer _img)
258 GGPInfo *info = purple_connection_get_protocol_data(gc);
259 ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
260 SoupMessage *req;
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");
269 return;
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);
287 g_free(img_data);
288 g_free(uin_str);
291 void
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);
302 if (img == NULL) {
303 purple_debug_warning("gg", "ggp_avatar_own_set: avatar removing is "
304 "probably not possible within old protocol");
305 return;
308 avdata->own_img = img;
310 ggp_oauth_request(gc, ggp_avatar_own_got_token, img, NULL, NULL);