Mercurial > pidgin.yaz
comparison src/protocols/yahoo/yahoo_picture.c @ 9306:04a3e9e869ee
[gaim-migrate @ 10114]
Ok, this is yahoo buddy icon uploading support.
It's still not quite right, but it mostly works.
We don't send out updates yet so changing it or unsetting it may not work.
But setting it initally, or changing it and relogging will probably work.
I never did figure out what hash function yahoo is using, so I just used
g_string_hash. It probably won't matter.
I hope to finish this up before release. But people probably won't notice
the bugs too much anyway. It shouldn't crash or anything, people just might
not always see your newest icon right away.
Have fun kids.
For the record, Simguy tells me Yahoo likes 96x96 PNGs.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Fri, 18 Jun 2004 07:28:25 +0000 |
parents | |
children | 085190b9dd64 |
comparison
equal
deleted
inserted
replaced
9305:0c201a2386c7 | 9306:04a3e9e869ee |
---|---|
1 /* | |
2 * gaim | |
3 * | |
4 * Gaim is the legal property of its developers, whose names are too numerous | |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
23 | |
24 #include "internal.h" | |
25 | |
26 #include "account.h" | |
27 #include "accountopt.h" | |
28 #include "blist.h" | |
29 #include "debug.h" | |
30 #include "prpl.h" | |
31 #include "proxy.h" | |
32 #include "util.h" | |
33 | |
34 #include "yahoo.h" | |
35 #include "yahoo_friend.h" | |
36 #include "yahoo_picture.h" | |
37 | |
38 | |
39 struct yahoo_fetch_picture_data { | |
40 GaimConnection *gc; | |
41 char *who; | |
42 int checksum; | |
43 }; | |
44 | |
45 void yahoo_fetch_picture_cb(void *user_data, const char *pic_data, size_t len) | |
46 { | |
47 struct yahoo_fetch_picture_data *d = user_data; | |
48 GaimBuddy *b; | |
49 | |
50 if (GAIM_CONNECTION_IS_VALID(d->gc) && len) { | |
51 gaim_buddy_icons_set_for_user(gaim_connection_get_account(d->gc), d->who, (void *)pic_data, len); | |
52 b = gaim_find_buddy(gaim_connection_get_account(d->gc), d->who); | |
53 if (b) | |
54 gaim_blist_node_set_int((GaimBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY, d->checksum); | |
55 } else { | |
56 gaim_debug_error("yahoo", "Fetching buddy icon failed.\n"); | |
57 } | |
58 | |
59 g_free(d->who); | |
60 g_free(d); | |
61 } | |
62 | |
63 void yahoo_send_picture_info(GaimConnection *gc, const char *who) | |
64 { | |
65 struct yahoo_data *yd = gc->proto_data; | |
66 struct yahoo_packet *pkt; | |
67 char *buf; | |
68 | |
69 if (!yd->picture_url) | |
70 return; | |
71 | |
72 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0); | |
73 yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc)); | |
74 yahoo_packet_hash(pkt, 4, gaim_connection_get_display_name(gc)); | |
75 yahoo_packet_hash(pkt, 5, who); | |
76 yahoo_packet_hash(pkt, 13, "2"); | |
77 yahoo_packet_hash(pkt, 20, yd->picture_url); | |
78 buf = g_strdup_printf("%d", yd->picture_checksum); | |
79 yahoo_packet_hash(pkt, 192, buf); | |
80 | |
81 yahoo_send_packet(yd, pkt); | |
82 yahoo_packet_free(pkt); | |
83 g_free(buf); | |
84 } | |
85 | |
86 void yahoo_process_picture(GaimConnection *gc, struct yahoo_packet *pkt) | |
87 { | |
88 GSList *l = pkt->hash; | |
89 char *who = NULL, *us = NULL; | |
90 gboolean got_icon_info = FALSE, send_icon_info = FALSE; | |
91 char *url = NULL; | |
92 int checksum = 0; | |
93 | |
94 while (l) { | |
95 struct yahoo_pair *pair = l->data; | |
96 | |
97 switch (pair->key) { | |
98 case 1: | |
99 case 4: | |
100 who = pair->value; | |
101 break; | |
102 case 5: | |
103 us = pair->value; | |
104 break; | |
105 case 13: { | |
106 int tmp; | |
107 tmp = strtol(pair->value, NULL, 10); | |
108 if (tmp == 1) { | |
109 send_icon_info = TRUE; | |
110 } else if (tmp == 2) { | |
111 got_icon_info = TRUE; | |
112 } | |
113 break; | |
114 } | |
115 case 20: | |
116 url = pair->value; | |
117 break; | |
118 case 192: | |
119 checksum = strtol(pair->value, NULL, 10); | |
120 break; | |
121 } | |
122 | |
123 l = l->next; | |
124 } | |
125 | |
126 if (who && got_icon_info && url) { | |
127 /* TODO: make this work p2p, try p2p before the url */ | |
128 struct yahoo_fetch_picture_data *data; | |
129 GaimBuddy *b = gaim_find_buddy(gc->account, who); | |
130 if (b && (checksum == gaim_blist_node_get_int((GaimBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY))) | |
131 return; | |
132 | |
133 data = g_new0(struct yahoo_fetch_picture_data, 1); | |
134 data->gc = gc; | |
135 data->who = g_strdup(who); | |
136 data->checksum = checksum; | |
137 gaim_url_fetch(url, FALSE, "Mozilla/4.0 (compatible; MSIE 5.0)", FALSE, | |
138 yahoo_fetch_picture_cb, data); | |
139 } else if (who && send_icon_info) { | |
140 yahoo_send_picture_info(gc, who); | |
141 } | |
142 | |
143 } | |
144 | |
145 void yahoo_process_picture_update(GaimConnection *gc, struct yahoo_packet *pkt) | |
146 { | |
147 GSList *l = pkt->hash; | |
148 char *who = NULL; | |
149 int icon = 0; | |
150 | |
151 while (l) { | |
152 struct yahoo_pair *pair = l->data; | |
153 | |
154 switch (pair->key) { | |
155 case 4: | |
156 who = pair->value; | |
157 break; | |
158 case 5: | |
159 /* us */ | |
160 break; | |
161 case 206: | |
162 icon = strtol(pair->value, NULL, 10); | |
163 break; | |
164 } | |
165 l = l->next; | |
166 } | |
167 | |
168 if (who) { | |
169 if (icon == 2) | |
170 yahoo_send_buddy_icon_request(gc, who); | |
171 else if (icon == 0) | |
172 gaim_buddy_icons_set_for_user(gc->account, who, NULL, 0); | |
173 } | |
174 } | |
175 | |
176 void yahoo_process_picture_checksum(GaimConnection *gc, struct yahoo_packet *pkt) | |
177 { | |
178 GSList *l = pkt->hash; | |
179 char *who = NULL; | |
180 int checksum = 0; | |
181 | |
182 while (l) { | |
183 struct yahoo_pair *pair = l->data; | |
184 | |
185 switch (pair->key) { | |
186 case 4: | |
187 who = pair->value; | |
188 break; | |
189 case 5: | |
190 /* us */ | |
191 break; | |
192 case 192: | |
193 checksum = strtol(pair->value, NULL, 10); | |
194 break; | |
195 } | |
196 l = l->next; | |
197 } | |
198 | |
199 if (who) { | |
200 GaimBuddy *b = gaim_find_buddy(gc->account, who); | |
201 if (b && (checksum != gaim_blist_node_get_int((GaimBlistNode*)b, YAHOO_ICON_CHECKSUM_KEY))) | |
202 yahoo_send_buddy_icon_request(gc, who); | |
203 } | |
204 } | |
205 | |
206 void yahoo_process_picture_upload(GaimConnection *gc, struct yahoo_packet *pkt) | |
207 { | |
208 GaimAccount *account = gaim_connection_get_account(gc); | |
209 struct yahoo_data *yd = gc->proto_data; | |
210 GSList *l = pkt->hash; | |
211 char *url = NULL; | |
212 | |
213 while (l) { | |
214 struct yahoo_pair *pair = l->data; | |
215 | |
216 switch (pair->key) { | |
217 case 5: | |
218 /* us */ | |
219 break; | |
220 case 27: | |
221 /* filename on our computer. */ | |
222 break; | |
223 case 20: /* url at yahoo */ | |
224 url = pair->value; | |
225 case 38: /* timestamp */ | |
226 break; | |
227 } | |
228 l = l->next; | |
229 } | |
230 | |
231 if (url) { | |
232 if (yd->picture_url) | |
233 g_free(yd->picture_url); | |
234 yd->picture_url = g_strdup(url); | |
235 gaim_account_set_string(account, YAHOO_PICURL_SETTING, url); | |
236 gaim_account_set_int(account, YAHOO_PICCKSUM_SETTING, yd->picture_checksum); | |
237 } | |
238 } | |
239 | |
240 | |
241 void yahoo_send_buddy_icon_request(GaimConnection *gc, const char *who) | |
242 { | |
243 struct yahoo_data *yd = gc->proto_data; | |
244 struct yahoo_packet *pkt; | |
245 | |
246 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, 0); | |
247 yahoo_packet_hash(pkt, 4, gaim_connection_get_display_name(gc)); /* me */ | |
248 yahoo_packet_hash(pkt, 5, who); /* the other guy */ | |
249 yahoo_packet_hash(pkt, 13, "1"); /* 1 = request, 2 = reply */ | |
250 yahoo_send_packet(yd, pkt); | |
251 yahoo_packet_free(pkt); | |
252 } | |
253 | |
254 void yahoo_buddy_icon_upload_data_free(struct yahoo_buddy_icon_upload_data *d) | |
255 { | |
256 gaim_debug_misc("yahoo", "In yahoo_buddy_icon_upload_data_free()\n"); | |
257 | |
258 if (d->str) | |
259 g_string_free(d->str, TRUE); | |
260 if (d->filename) | |
261 g_free(d->filename); | |
262 if (d->watcher) | |
263 gaim_input_remove(d->watcher); | |
264 if (d->fd != -1) | |
265 close(d->fd); | |
266 g_free(d); | |
267 } | |
268 | |
269 /* we could care less about the server's responce, but yahoo gets grumpy if we close before it sends it */ | |
270 static void yahoo_buddy_icon_upload_reading(gpointer data, gint source, GaimInputCondition condition) | |
271 { | |
272 struct yahoo_buddy_icon_upload_data *d = data; | |
273 GaimConnection *gc = d->gc; | |
274 char buf[1024]; | |
275 | |
276 if (!GAIM_CONNECTION_IS_VALID(gc)) { | |
277 yahoo_buddy_icon_upload_data_free(d); | |
278 return; | |
279 } | |
280 | |
281 if (read(d->fd, buf, sizeof(buf)) <= 0) | |
282 yahoo_buddy_icon_upload_data_free(d); | |
283 } | |
284 | |
285 static void yahoo_buddy_icon_upload_pending(gpointer data, gint source, GaimInputCondition condition) | |
286 { | |
287 struct yahoo_buddy_icon_upload_data *d = data; | |
288 GaimConnection *gc = d->gc; | |
289 ssize_t wrote; | |
290 | |
291 if (!GAIM_CONNECTION_IS_VALID(gc)) { | |
292 yahoo_buddy_icon_upload_data_free(d); | |
293 return; | |
294 } | |
295 | |
296 wrote = write(d->fd, d->str->str + d->pos, d->str->len - d->pos); | |
297 if (wrote <= 0) { | |
298 yahoo_buddy_icon_upload_data_free(d); | |
299 return; | |
300 } | |
301 d->pos += wrote; | |
302 if (d->pos >= d->str->len) { | |
303 gaim_debug_misc("yahoo", "Finished uploading buddy icon.\n"); | |
304 gaim_input_remove(d->watcher); | |
305 d->watcher = gaim_input_add(d->fd, GAIM_INPUT_READ, yahoo_buddy_icon_upload_reading, d); | |
306 } | |
307 } | |
308 | |
309 static void yahoo_buddy_icon_upload_connected(gpointer data, gint source, GaimInputCondition condition) | |
310 { | |
311 struct yahoo_buddy_icon_upload_data *d = data; | |
312 struct yahoo_packet *pkt; | |
313 gchar *size, *post, *buf; | |
314 int content_length; | |
315 GaimConnection *gc; | |
316 GaimAccount *account; | |
317 struct yahoo_data *yd; | |
318 | |
319 if (!d) | |
320 return; | |
321 | |
322 | |
323 gc = d->gc; | |
324 account = gaim_connection_get_account(gc); | |
325 yd = gc->proto_data; | |
326 | |
327 | |
328 if (source < 0) { | |
329 gaim_debug_error("yahoo", "Buddy icon upload failed, no file desc.\n"); | |
330 yahoo_buddy_icon_upload_data_free(d); | |
331 return; | |
332 } | |
333 | |
334 d->fd = source; | |
335 d->watcher = gaim_input_add(d->fd, GAIM_INPUT_WRITE, yahoo_buddy_icon_upload_pending, d); | |
336 | |
337 pkt = yahoo_packet_new(0xc2, YAHOO_STATUS_AVAILABLE, yd->session_id); | |
338 | |
339 size = g_strdup_printf("%d", d->str->len); | |
340 /* 1 = me, 38 = expire time(?), 0 = me, 28 = size, 27 = filename, 14 = NULL, 29 = data */ | |
341 yahoo_packet_hash(pkt, 1, gaim_connection_get_display_name(gc)); | |
342 yahoo_packet_hash(pkt, 38, "604800"); /* time til expire */ | |
343 gaim_account_set_int(account, YAHOO_PICEXPIRE_SETTING, time(NULL) + 604800); | |
344 yahoo_packet_hash(pkt, 0, gaim_connection_get_display_name(gc)); | |
345 yahoo_packet_hash(pkt, 28, size); | |
346 yahoo_packet_hash(pkt, 27, d->filename); | |
347 yahoo_packet_hash(pkt, 14, ""); | |
348 | |
349 content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); | |
350 | |
351 buf = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t); | |
352 | |
353 post = g_strdup_printf("POST /notifyft HTTP/1.0\r\n" | |
354 "Content-length: %d\r\n" | |
355 "Host: %s:%d\r\n" | |
356 "Cookie: %s\r\n" | |
357 "\r\n", | |
358 content_length + 4 + d->str->len, | |
359 gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
360 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
361 buf); | |
362 write(d->fd, post, strlen(post)); | |
363 | |
364 yahoo_send_packet_special(d->fd, pkt, 8); | |
365 yahoo_packet_free(pkt); | |
366 | |
367 write(d->fd, "29\xc0\x80", 4); | |
368 | |
369 g_free(size); | |
370 g_free(post); | |
371 g_free(buf); | |
372 } | |
373 | |
374 void yahoo_buddy_icon_upload(GaimConnection *gc, struct yahoo_buddy_icon_upload_data *d) | |
375 { | |
376 GaimAccount *account = gaim_connection_get_account(gc); | |
377 struct yahoo_data *yd = gc->proto_data; | |
378 | |
379 if (yd->jp) { | |
380 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xferjp_host", YAHOOJP_XFER_HOST), | |
381 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
382 yahoo_buddy_icon_upload_connected, d) == -1) | |
383 { | |
384 gaim_debug_error("yahoo", "Uploading our buddy icon failed to connect.\n"); | |
385 yahoo_buddy_icon_upload_data_free(d); | |
386 } | |
387 } else { | |
388 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
389 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
390 yahoo_buddy_icon_upload_connected, d) == -1) | |
391 { | |
392 gaim_debug_error("yahoo", "Uploading our buddy icon failed to connect.\n"); | |
393 yahoo_buddy_icon_upload_data_free(d); | |
394 } | |
395 } | |
396 } | |
397 | |
398 void yahoo_set_buddy_icon(GaimConnection *gc, const char *iconfile) | |
399 { | |
400 struct yahoo_data *yd = gc->proto_data; | |
401 GaimAccount *account = gc->account; | |
402 FILE *file; | |
403 struct stat st; | |
404 | |
405 if (iconfile == NULL) { | |
406 if (yd->picture_url) | |
407 g_free(yd->picture_url); | |
408 yd->picture_url = NULL; | |
409 | |
410 gaim_account_set_string(account, YAHOO_PICURL_SETTING, NULL); | |
411 gaim_account_set_int(account, YAHOO_PICCKSUM_SETTING, 0); | |
412 gaim_account_set_int(account, YAHOO_PICEXPIRE_SETTING, 0); | |
413 /* TODO: check if we're connected and tell everyone we ain't not one no more */ | |
414 } else if (!stat(iconfile, &st)) { | |
415 file = fopen(iconfile, "rb"); | |
416 if (file) { | |
417 GString *s = g_string_sized_new(st.st_size); | |
418 size_t len; | |
419 struct yahoo_buddy_icon_upload_data *d; | |
420 int oldcksum = gaim_account_get_int(account, YAHOO_PICCKSUM_SETTING, 0); | |
421 int expire = gaim_account_get_int(account, YAHOO_PICEXPIRE_SETTING, 0); | |
422 const char *oldurl = gaim_account_get_string(account, YAHOO_PICURL_SETTING, NULL); | |
423 | |
424 g_string_set_size(s, st.st_size); | |
425 len = fread(s->str, 1, st.st_size, file); | |
426 fclose(file); | |
427 g_string_set_size(s, len); | |
428 yd->picture_checksum = g_string_hash(s); | |
429 | |
430 if ((yd->picture_checksum == oldcksum) && (expire > (time(NULL) + 60*60*24)) && | |
431 oldcksum && expire && oldurl) { | |
432 gaim_debug_misc("yahoo", "buddy icon is up to date. Not reuploading.\n"); | |
433 g_string_free(s, TRUE); | |
434 if (yd->picture_url) | |
435 g_free(yd->picture_url); | |
436 yd->picture_url = g_strdup(oldurl); | |
437 return; | |
438 } | |
439 | |
440 d = g_new0(struct yahoo_buddy_icon_upload_data, 1); | |
441 d->gc = gc; | |
442 d->str = s; | |
443 d->fd = -1; | |
444 d->filename = g_strdup(iconfile); | |
445 | |
446 if (!yd->logged_in) { | |
447 yd->picture_upload_todo = d; | |
448 return; | |
449 } | |
450 | |
451 yahoo_buddy_icon_upload(gc, d); | |
452 } else | |
453 gaim_debug_error("yahoo", | |
454 "Can't open buddy icon file!\n"); | |
455 } else | |
456 gaim_debug_error("yahooo", | |
457 "Can't stat buddy icon file!\n"); | |
458 } |