Mercurial > pidgin
comparison libpurple/protocols/yahoo/yahoo_picture.c @ 23028:e56831d0329a
applied changes from c7504bbbe35f5bef52032c0cdf6bc7182128a469
through c63750bedbfe2b637719fb4225f6c40085e13be9
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Thu, 19 Jun 2008 03:12:46 +0000 |
parents | 49264628f72d |
children | 25975a6a5b63 |
comparison
equal
deleted
inserted
replaced
23027:3c33405fd630 | 23028:e56831d0329a |
---|---|
242 } | 242 } |
243 l = l->next; | 243 l = l->next; |
244 } | 244 } |
245 | 245 |
246 if (url) { | 246 if (url) { |
247 if (yd->picture_url) | 247 g_free(yd->picture_url); |
248 g_free(yd->picture_url); | |
249 yd->picture_url = g_strdup(url); | 248 yd->picture_url = g_strdup(url); |
250 purple_account_set_string(account, YAHOO_PICURL_SETTING, url); | 249 purple_account_set_string(account, YAHOO_PICURL_SETTING, url); |
251 purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, yd->picture_checksum); | 250 purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, yd->picture_checksum); |
251 yahoo_send_picture_checksum(gc); | |
252 yahoo_send_picture_update(gc, 2); | 252 yahoo_send_picture_update(gc, 2); |
253 yahoo_send_picture_checksum(gc); | |
254 } | 253 } |
255 } | 254 } |
256 | 255 |
257 void yahoo_process_avatar_update(PurpleConnection *gc, struct yahoo_packet *pkt) | 256 void yahoo_process_avatar_update(PurpleConnection *gc, struct yahoo_packet *pkt) |
258 { | 257 { |
400 | 399 |
401 ret = read(d->fd, buf, sizeof(buf)); | 400 ret = read(d->fd, buf, sizeof(buf)); |
402 | 401 |
403 if (ret < 0 && errno == EAGAIN) | 402 if (ret < 0 && errno == EAGAIN) |
404 return; | 403 return; |
405 else if (ret <= 0) | 404 else if (ret <= 0) { |
405 purple_debug_info("yahoo", "Buddy icon upload response (%d) bytes (> ~400 indicates failure):\n%.*s\n", | |
406 d->str->len, d->str->len, d->str->str); | |
407 | |
406 yahoo_buddy_icon_upload_data_free(d); | 408 yahoo_buddy_icon_upload_data_free(d); |
409 return; | |
410 } | |
411 | |
412 g_string_append_len(d->str, buf, ret); | |
407 } | 413 } |
408 | 414 |
409 static void yahoo_buddy_icon_upload_pending(gpointer data, gint source, PurpleInputCondition condition) | 415 static void yahoo_buddy_icon_upload_pending(gpointer data, gint source, PurpleInputCondition condition) |
410 { | 416 { |
411 struct yahoo_buddy_icon_upload_data *d = data; | 417 struct yahoo_buddy_icon_upload_data *d = data; |
419 | 425 |
420 wrote = write(d->fd, d->str->str + d->pos, d->str->len - d->pos); | 426 wrote = write(d->fd, d->str->str + d->pos, d->str->len - d->pos); |
421 if (wrote < 0 && errno == EAGAIN) | 427 if (wrote < 0 && errno == EAGAIN) |
422 return; | 428 return; |
423 if (wrote <= 0) { | 429 if (wrote <= 0) { |
430 purple_debug_info("yahoo", "Error uploading buddy icon.\n"); | |
424 yahoo_buddy_icon_upload_data_free(d); | 431 yahoo_buddy_icon_upload_data_free(d); |
425 return; | 432 return; |
426 } | 433 } |
427 d->pos += wrote; | 434 d->pos += wrote; |
428 if (d->pos >= d->str->len) { | 435 if (d->pos >= d->str->len) { |
429 purple_debug_misc("yahoo", "Finished uploading buddy icon.\n"); | 436 purple_debug_misc("yahoo", "Finished uploading buddy icon.\n"); |
430 purple_input_remove(d->watcher); | 437 purple_input_remove(d->watcher); |
438 /* Clean out the sent buffer and reuse it to read the result */ | |
439 g_string_free(d->str, TRUE); | |
440 d->str = g_string_new(""); | |
431 d->watcher = purple_input_add(d->fd, PURPLE_INPUT_READ, yahoo_buddy_icon_upload_reading, d); | 441 d->watcher = purple_input_add(d->fd, PURPLE_INPUT_READ, yahoo_buddy_icon_upload_reading, d); |
432 } | 442 } |
433 } | 443 } |
434 | 444 |
435 static void yahoo_buddy_icon_upload_connected(gpointer data, gint source, const gchar *error_message) | 445 static void yahoo_buddy_icon_upload_connected(gpointer data, gint source, const gchar *error_message) |
436 { | 446 { |
437 struct yahoo_buddy_icon_upload_data *d = data; | 447 struct yahoo_buddy_icon_upload_data *d = data; |
438 struct yahoo_packet *pkt; | 448 struct yahoo_packet *pkt; |
439 gchar *size, *header; | 449 gchar *tmp, *header; |
440 guchar *pkt_buf; | 450 guchar *pkt_buf; |
441 const char *host; | 451 const char *host; |
442 int port; | 452 int port; |
443 size_t content_length, pkt_buf_len; | 453 gsize pkt_buf_len; |
444 PurpleConnection *gc; | 454 PurpleConnection *gc = d->gc; |
445 PurpleAccount *account; | 455 PurpleAccount *account; |
446 struct yahoo_data *yd; | 456 struct yahoo_data *yd; |
447 | 457 gboolean use_whole_url = FALSE; |
448 gc = d->gc; | 458 |
449 account = purple_connection_get_account(gc); | 459 account = purple_connection_get_account(gc); |
450 yd = gc->proto_data; | 460 yd = gc->proto_data; |
451 | 461 |
452 /* Buddy icon connect is now complete; clear the PurpleProxyConnectData */ | 462 /* Buddy icon connect is now complete; clear the PurpleProxyConnectData */ |
453 yd->buddy_icon_connect_data = NULL; | 463 yd->buddy_icon_connect_data = NULL; |
455 if (source < 0) { | 465 if (source < 0) { |
456 purple_debug_error("yahoo", "Buddy icon upload failed: %s\n", error_message); | 466 purple_debug_error("yahoo", "Buddy icon upload failed: %s\n", error_message); |
457 yahoo_buddy_icon_upload_data_free(d); | 467 yahoo_buddy_icon_upload_data_free(d); |
458 return; | 468 return; |
459 } | 469 } |
460 | 470 /* use whole URL if using HTTP Proxy */ |
461 pkt = yahoo_packet_new(0xc2, YAHOO_STATUS_AVAILABLE, yd->session_id); | 471 if ((gc->account->proxy_info) |
462 | 472 && (gc->account->proxy_info->type == PURPLE_PROXY_HTTP)) |
463 size = g_strdup_printf("%" G_GSIZE_FORMAT, d->str->len); | 473 use_whole_url = TRUE; |
474 | |
475 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id); | |
476 | |
477 tmp = g_strdup_printf("%" G_GSIZE_FORMAT, d->str->len); | |
464 /* 1 = me, 38 = expire time(?), 0 = me, 28 = size, 27 = filename, 14 = NULL, 29 = data */ | 478 /* 1 = me, 38 = expire time(?), 0 = me, 28 = size, 27 = filename, 14 = NULL, 29 = data */ |
465 yahoo_packet_hash_str(pkt, 1, purple_connection_get_display_name(gc)); | 479 yahoo_packet_hash_str(pkt, 1, purple_connection_get_display_name(gc)); |
466 yahoo_packet_hash_str(pkt, 38, "604800"); /* time til expire */ | 480 yahoo_packet_hash_str(pkt, 38, "604800"); /* time til expire */ |
467 purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, time(NULL) + 604800); | 481 purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, time(NULL) + 604800); |
468 yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc)); | 482 yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc)); |
469 yahoo_packet_hash_str(pkt, 28, size); | 483 yahoo_packet_hash_str(pkt, 28, tmp); |
470 g_free(size); | 484 g_free(tmp); |
471 yahoo_packet_hash_str(pkt, 27, d->filename); | 485 yahoo_packet_hash_str(pkt, 27, d->filename); |
472 yahoo_packet_hash_str(pkt, 14, ""); | 486 yahoo_packet_hash_str(pkt, 14, ""); |
473 | 487 /* 4 padding for the 29 key name */ |
474 content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); | 488 pkt_buf_len = yahoo_packet_build(pkt, 4, FALSE, yd->jp, &pkt_buf); |
489 yahoo_packet_free(pkt); | |
490 | |
491 /* header + packet + "29" + 0xc0 + 0x80) + pictureblob */ | |
475 | 492 |
476 host = purple_account_get_string(account, "xfer_host", YAHOO_XFER_HOST); | 493 host = purple_account_get_string(account, "xfer_host", YAHOO_XFER_HOST); |
477 port = purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT); | 494 port = purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT); |
478 header = g_strdup_printf( | 495 tmp = g_strdup_printf("%s:%d", host, port); |
479 "POST http://%s:%d/notifyft HTTP/1.0\r\n" | 496 header = g_strdup_printf("POST %s%s/notifyft HTTP/1.1\r\n" |
480 "Content-length: %" G_GSIZE_FORMAT "\r\n" | 497 "User-Agent: Mozilla/4.0 (compatible; MSIE 5.5)\r\n" |
481 "Host: %s:%d\r\n" | 498 "Cookie: T=%s; Y=%s\r\n" |
482 "Cookie: Y=%s; T=%s\r\n" | 499 "Host: %s\r\n" |
483 "\r\n", | 500 "Content-Length: %" G_GSIZE_FORMAT "\r\n" |
484 host, port, content_length + 4 + d->str->len, | 501 "Cache-Control: no-cache\r\n\r\n", |
485 host, port, yd->cookie_y, yd->cookie_t); | 502 use_whole_url ? "http://" : "", use_whole_url ? tmp : "", |
503 yd->cookie_t, yd->cookie_y, | |
504 tmp, | |
505 pkt_buf_len + 4 + d->str->len); | |
506 g_free(tmp); | |
486 | 507 |
487 /* There's no magic here, we just need to prepend in reverse order */ | 508 /* There's no magic here, we just need to prepend in reverse order */ |
488 g_string_prepend(d->str, "29\xc0\x80"); | 509 g_string_prepend(d->str, "29\xc0\x80"); |
489 | 510 |
490 pkt_buf_len = yahoo_packet_build(pkt, 8, FALSE, yd->jp, &pkt_buf); | |
491 yahoo_packet_free(pkt); | |
492 g_string_prepend_len(d->str, (char *)pkt_buf, pkt_buf_len); | 511 g_string_prepend_len(d->str, (char *)pkt_buf, pkt_buf_len); |
493 g_free(pkt_buf); | 512 g_free(pkt_buf); |
494 | 513 |
495 g_string_prepend(d->str, header); | 514 g_string_prepend(d->str, header); |
496 g_free(header); | 515 g_free(header); |
516 | |
517 purple_debug_info("yahoo", "Buddy icon upload data:\n%.*s\n", d->str->len, d->str->str); | |
497 | 518 |
498 d->fd = source; | 519 d->fd = source; |
499 d->watcher = purple_input_add(d->fd, PURPLE_INPUT_WRITE, yahoo_buddy_icon_upload_pending, d); | 520 d->watcher = purple_input_add(d->fd, PURPLE_INPUT_WRITE, yahoo_buddy_icon_upload_pending, d); |
500 | 521 |
501 yahoo_buddy_icon_upload_pending(d, d->fd, PURPLE_INPUT_WRITE); | 522 yahoo_buddy_icon_upload_pending(d, d->fd, PURPLE_INPUT_WRITE); |
523 purple_debug_error("yahoo", "Uploading our buddy icon failed to connect.\n"); | 544 purple_debug_error("yahoo", "Uploading our buddy icon failed to connect.\n"); |
524 yahoo_buddy_icon_upload_data_free(d); | 545 yahoo_buddy_icon_upload_data_free(d); |
525 } | 546 } |
526 } | 547 } |
527 | 548 |
549 static int yahoo_buddy_icon_calculate_checksum(const guchar *data, gsize len) | |
550 { | |
551 /* This code is borrowed from Kopete, which seems to be managing to calculate | |
552 checksums in such a manner that Yahoo!'s servers are happy */ | |
553 | |
554 const guchar *p = data; | |
555 int checksum = 0, g, i = len; | |
556 | |
557 while(i--) { | |
558 checksum = (checksum << 4) + *p++; | |
559 | |
560 if((g = (checksum & 0xf0000000)) != 0) | |
561 checksum ^= g >> 23; | |
562 | |
563 checksum &= ~g; | |
564 } | |
565 | |
566 purple_debug_misc("yahoo", "Calculated buddy icon checksum: %d", checksum); | |
567 | |
568 return checksum; | |
569 } | |
570 | |
528 void yahoo_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) | 571 void yahoo_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) |
529 { | 572 { |
530 struct yahoo_data *yd = gc->proto_data; | 573 struct yahoo_data *yd = gc->proto_data; |
531 PurpleAccount *account = gc->account; | 574 PurpleAccount *account = gc->account; |
532 | 575 |
533 if (img == NULL) { | 576 if (img == NULL) { |
534 g_free(yd->picture_url); | 577 g_free(yd->picture_url); |
535 yd->picture_url = NULL; | 578 yd->picture_url = NULL; |
579 | |
580 /* TODO: don't we have to clear it on the server too?! */ | |
536 | 581 |
537 purple_account_set_string(account, YAHOO_PICURL_SETTING, NULL); | 582 purple_account_set_string(account, YAHOO_PICURL_SETTING, NULL); |
538 purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, 0); | 583 purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, 0); |
539 purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, 0); | 584 purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, 0); |
540 if (yd->logged_in) | 585 if (yd->logged_in) |
547 GString *s = g_string_new_len(data, len); | 592 GString *s = g_string_new_len(data, len); |
548 struct yahoo_buddy_icon_upload_data *d; | 593 struct yahoo_buddy_icon_upload_data *d; |
549 int oldcksum = purple_account_get_int(account, YAHOO_PICCKSUM_SETTING, 0); | 594 int oldcksum = purple_account_get_int(account, YAHOO_PICCKSUM_SETTING, 0); |
550 int expire = purple_account_get_int(account, YAHOO_PICEXPIRE_SETTING, 0); | 595 int expire = purple_account_get_int(account, YAHOO_PICEXPIRE_SETTING, 0); |
551 const char *oldurl = purple_account_get_string(account, YAHOO_PICURL_SETTING, NULL); | 596 const char *oldurl = purple_account_get_string(account, YAHOO_PICURL_SETTING, NULL); |
552 char *iconfile; | 597 |
553 | 598 yd->picture_checksum = yahoo_buddy_icon_calculate_checksum(data, len); |
554 /* TODO: At some point, it'd be nice to fix this for real, or | |
555 * TODO: at least change it to be something like: | |
556 * TODO: purple_imgstore_get_filename(img); | |
557 * TODO: But it would be great if we knew how to calculate the | |
558 * TODO: Checksum correctly. */ | |
559 yd->picture_checksum = g_string_hash(s); | |
560 | 599 |
561 if ((yd->picture_checksum == oldcksum) && | 600 if ((yd->picture_checksum == oldcksum) && |
562 (expire > (time(NULL) + 60*60*24)) && oldurl) | 601 (expire > (time(NULL) + 60*60*24)) && oldurl) |
563 { | 602 { |
564 purple_debug_misc("yahoo", "buddy icon is up to date. Not reuploading.\n"); | 603 purple_debug_misc("yahoo", "buddy icon is up to date. Not reuploading.\n"); |
567 yd->picture_url = g_strdup(oldurl); | 606 yd->picture_url = g_strdup(oldurl); |
568 return; | 607 return; |
569 } | 608 } |
570 | 609 |
571 /* We use this solely for sending a filename to the server */ | 610 /* We use this solely for sending a filename to the server */ |
572 iconfile = g_strdup(purple_imgstore_get_filename(img)); | |
573 d = g_new0(struct yahoo_buddy_icon_upload_data, 1); | 611 d = g_new0(struct yahoo_buddy_icon_upload_data, 1); |
574 d->gc = gc; | 612 d->gc = gc; |
575 d->str = s; | 613 d->str = s; |
576 d->fd = -1; | 614 d->fd = -1; |
577 d->filename = iconfile; | 615 d->filename = g_strdup(purple_imgstore_get_filename(img)); |
578 | 616 |
579 if (!yd->logged_in) { | 617 if (!yd->logged_in) { |
580 yd->picture_upload_todo = d; | 618 yd->picture_upload_todo = d; |
581 return; | 619 return; |
582 } | 620 } |