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 }