| |
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 } |