libpurple/protocols/gg/avatar.c

branch
soc.2012.gg
changeset 33313
5a0c6582d5b1
child 33328
c71e5e8976ba
equal deleted inserted replaced
33312:7dd184afae2c 33313:5a0c6582d5b1
1 #include "avatar.h"
2
3 #include <debug.h>
4
5 #include "gg.h"
6 #include "utils.h"
7
8 // Common
9
10 static inline ggp_avatar_session_data *
11 ggp_avatar_get_avdata(PurpleConnection *gc);
12
13 static gboolean ggp_avatar_timer_cb(gpointer _gc);
14
15 #define GGP_AVATAR_USERAGENT "GG Client build 11.0.0.7562"
16 #define GGP_AVATAR_SIZE_MAX 1048576
17
18 // Buddy avatars updating
19
20 typedef struct
21 {
22 uin_t uin;
23 time_t timestamp;
24
25 PurpleConnection *gc;
26 PurpleUtilFetchUrlData *request;
27 } ggp_avatar_buddy_update_req;
28
29 static gboolean ggp_avatar_buddy_update_next(PurpleConnection *gc);
30 static void ggp_avatar_buddy_update_received(PurpleUtilFetchUrlData *url_data,
31 gpointer _pending_update, const gchar *url_text, gsize len,
32 const gchar *error_message);
33
34 #define GGP_AVATAR_BUDDY_URL "http://avatars.gg.pl/%u/s,big"
35
36 /*******************************************************************************
37 * Common.
38 ******************************************************************************/
39
40 void ggp_avatar_setup(PurpleConnection *gc)
41 {
42 ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
43
44 avdata->pending_updates = NULL;
45 avdata->current_update = NULL;
46
47 avdata->timer = purple_timeout_add_seconds(1, ggp_avatar_timer_cb, gc);
48 }
49
50 void ggp_avatar_cleanup(PurpleConnection *gc)
51 {
52 ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
53
54 purple_timeout_remove(avdata->timer);
55
56 if (avdata->current_update != NULL)
57 {
58 ggp_avatar_buddy_update_req *current_update =
59 avdata->current_update;
60
61 purple_util_fetch_url_cancel(current_update->request);
62 g_free(current_update);
63 }
64 avdata->current_update = NULL;
65
66 g_list_free_full(avdata->pending_updates, &g_free);
67 avdata->pending_updates = NULL;
68 }
69
70 static inline ggp_avatar_session_data *
71 ggp_avatar_get_avdata(PurpleConnection *gc)
72 {
73 GGPInfo *accdata = purple_connection_get_protocol_data(gc);
74 return &accdata->avatar_data;
75 }
76
77 static gboolean ggp_avatar_timer_cb(gpointer _gc)
78 {
79 PurpleConnection *gc = _gc;
80 ggp_avatar_session_data *avdata;
81
82 g_return_val_if_fail(PURPLE_CONNECTION_IS_VALID(gc), FALSE);
83
84 avdata = ggp_avatar_get_avdata(gc);
85 if (avdata->current_update != NULL)
86 {
87 //TODO: verbose mode
88 //purple_debug_misc("gg", "ggp_avatar_timer_cb(%p): there is "
89 // "already an update running\n", gc);
90 return TRUE;
91 }
92
93 while (!ggp_avatar_buddy_update_next(gc));
94
95 return TRUE;
96 }
97
98 /*******************************************************************************
99 * Buddy avatars updating.
100 ******************************************************************************/
101
102 void ggp_avatar_buddy_update(PurpleConnection *gc, uin_t uin, time_t timestamp)
103 {
104 ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
105 ggp_avatar_buddy_update_req *pending_update =
106 g_new(ggp_avatar_buddy_update_req, 1);
107
108 purple_debug_misc("gg", "ggp_avatar_buddy_update(%p, %u, %lu)\n", gc,
109 uin, timestamp);
110
111 pending_update->uin = uin;
112 pending_update->timestamp = timestamp;
113
114 avdata->pending_updates = g_list_append(avdata->pending_updates,
115 pending_update);
116 }
117
118 void ggp_avatar_buddy_remove(PurpleConnection *gc, uin_t uin)
119 {
120 //TODO: verbose mode
121 //purple_debug_misc("gg", "ggp_avatar_buddy_remove(%p, %u) - "
122 // "probably not necessary, thus not implemented\n", gc, uin);
123 }
124
125 /* return TRUE if avatar update was performed or there is no new requests,
126 FALSE if we can request another one immediately */
127 static gboolean ggp_avatar_buddy_update_next(PurpleConnection *gc)
128 {
129 ggp_avatar_session_data *avdata = ggp_avatar_get_avdata(gc);
130 GList *pending_update_it;
131 ggp_avatar_buddy_update_req *pending_update;
132 PurpleBuddy *buddy;
133 PurpleAccount *account = purple_connection_get_account(gc);
134 time_t old_timestamp;
135 const char *old_timestamp_str;
136 gchar *avatar_url;
137
138 pending_update_it = g_list_first(avdata->pending_updates);
139 if (pending_update_it == NULL)
140 return TRUE;
141
142 pending_update = pending_update_it->data;
143 avdata->pending_updates = g_list_remove(avdata->pending_updates,
144 pending_update);
145 buddy = purple_find_buddy(account, ggp_uin_to_str(pending_update->uin));
146
147 if (!buddy)
148 {
149 if (ggp_str_to_uin(purple_account_get_username(account)) ==
150 pending_update->uin)
151 {
152 purple_debug_misc("gg",
153 "ggp_avatar_buddy_update_next(%p): own "
154 "avatar update requested, but we don't have "
155 "ourselves on buddy list\n", gc);
156 }
157 else
158 {
159 purple_debug_warning("gg",
160 "ggp_avatar_buddy_update_next(%p): "
161 "%u update requested, but he's not on buddy "
162 "list\n", gc, pending_update->uin);
163 }
164 return FALSE;
165 }
166
167 old_timestamp_str = purple_buddy_icons_get_checksum_for_user(buddy);
168 old_timestamp = old_timestamp_str ? g_ascii_strtoull(
169 old_timestamp_str, NULL, 10) : 0;
170 if (old_timestamp == pending_update->timestamp)
171 {
172 purple_debug_misc("gg",
173 "ggp_avatar_buddy_update_next(%p): "
174 "%u have up to date avatar with ts=%lu\n", gc,
175 pending_update->uin, pending_update->timestamp);
176 return FALSE;
177 }
178 if (old_timestamp > pending_update->timestamp)
179 {
180 purple_debug_warning("gg",
181 "ggp_avatar_buddy_update_next(%p): "
182 "saved timestamp for %u is newer than received "
183 "(%lu > %lu)\n", gc, pending_update->uin, old_timestamp,
184 pending_update->timestamp);
185 }
186
187 purple_debug_info("gg",
188 "ggp_avatar_buddy_update_next(%p): "
189 "updating %u with ts=%lu...\n", gc, pending_update->uin,
190 pending_update->timestamp);
191
192 pending_update->gc = gc;
193 avdata->current_update = pending_update;
194 avatar_url = g_strdup_printf(GGP_AVATAR_BUDDY_URL, pending_update->uin);
195 pending_update->request = purple_util_fetch_url_request(account,
196 avatar_url, FALSE, GGP_AVATAR_USERAGENT, TRUE, NULL, FALSE,
197 GGP_AVATAR_SIZE_MAX, ggp_avatar_buddy_update_received,
198 pending_update);
199 g_free(avatar_url);
200
201 return TRUE;
202 }
203
204 static void ggp_avatar_buddy_update_received(PurpleUtilFetchUrlData *url_data,
205 gpointer _pending_update, const gchar *url_text, gsize len,
206 const gchar *error_message)
207 {
208 ggp_avatar_buddy_update_req *pending_update = _pending_update;
209 PurpleBuddy *buddy;
210 PurpleAccount *account;
211 PurpleConnection *gc = pending_update->gc;
212 ggp_avatar_session_data *avdata;
213 gchar timestamp_str[20];
214
215 if (!PURPLE_CONNECTION_IS_VALID(gc))
216 {
217 g_free(pending_update);
218 return;
219 }
220
221 avdata = ggp_avatar_get_avdata(gc);
222 g_assert(pending_update == avdata->current_update);
223 avdata->current_update = NULL;
224
225 if (len == 0)
226 {
227 purple_debug_error("gg", "ggp_avatar_buddy_update_received: bad"
228 " response while getting avatar for %u: %s\n",
229 pending_update->uin, error_message);
230 g_free(pending_update);
231 return;
232 }
233
234 account = purple_connection_get_account(gc);
235 buddy = purple_find_buddy(account, ggp_uin_to_str(pending_update->uin));
236
237 if (!buddy)
238 {
239 purple_debug_warning("gg", "ggp_avatar_buddy_update_received: "
240 "buddy %u disappeared\n", pending_update->uin);
241 g_free(pending_update);
242 return;
243 }
244
245 g_snprintf(timestamp_str, sizeof(timestamp_str), "%lu",
246 pending_update->timestamp);
247 purple_buddy_icons_set_for_user(account, purple_buddy_get_name(buddy),
248 g_memdup(url_text, len), len, timestamp_str);
249
250 purple_debug_info("gg", "ggp_avatar_buddy_update_received: "
251 "got avatar for buddy %u [ts=%lu]\n", pending_update->uin,
252 pending_update->timestamp);
253 g_free(pending_update);
254 }

mercurial