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 }