| 1 /* |
|
| 2 * purple |
|
| 3 * |
|
| 4 * Purple 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 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 "privacy.h" |
|
| 31 #include "prpl.h" |
|
| 32 #include "proxy.h" |
|
| 33 #include "util.h" |
|
| 34 |
|
| 35 #include "libymsg.h" |
|
| 36 #include "yahoo_packet.h" |
|
| 37 #include "yahoo_friend.h" |
|
| 38 #include "yahoo_picture.h" |
|
| 39 |
|
| 40 |
|
| 41 struct yahoo_fetch_picture_data { |
|
| 42 PurpleConnection *gc; |
|
| 43 char *who; |
|
| 44 int checksum; |
|
| 45 }; |
|
| 46 |
|
| 47 static void |
|
| 48 yahoo_fetch_picture_cb(PurpleUtilFetchUrlData *url_data, gpointer user_data, |
|
| 49 const gchar *pic_data, size_t len, const gchar *error_message) |
|
| 50 { |
|
| 51 struct yahoo_fetch_picture_data *d; |
|
| 52 YahooData *yd; |
|
| 53 |
|
| 54 d = user_data; |
|
| 55 yd = d->gc->proto_data; |
|
| 56 yd->url_datas = g_slist_remove(yd->url_datas, url_data); |
|
| 57 |
|
| 58 if (error_message != NULL) { |
|
| 59 purple_debug_error("yahoo", "Fetching buddy icon failed: %s\n", error_message); |
|
| 60 } else if (len == 0) { |
|
| 61 purple_debug_error("yahoo", "Fetched an icon with length 0. Strange.\n"); |
|
| 62 } else { |
|
| 63 char *checksum = g_strdup_printf("%i", d->checksum); |
|
| 64 purple_buddy_icons_set_for_user(purple_connection_get_account(d->gc), d->who, g_memdup(pic_data, len), len, checksum); |
|
| 65 g_free(checksum); |
|
| 66 } |
|
| 67 |
|
| 68 g_free(d->who); |
|
| 69 g_free(d); |
|
| 70 } |
|
| 71 |
|
| 72 void yahoo_process_picture(PurpleConnection *gc, struct yahoo_packet *pkt) |
|
| 73 { |
|
| 74 YahooData *yd; |
|
| 75 GSList *l = pkt->hash; |
|
| 76 char *who = NULL; |
|
| 77 gboolean got_icon_info = FALSE, send_icon_info = FALSE; |
|
| 78 char *url = NULL; |
|
| 79 int checksum = 0; |
|
| 80 |
|
| 81 while (l) { |
|
| 82 struct yahoo_pair *pair = l->data; |
|
| 83 |
|
| 84 switch (pair->key) { |
|
| 85 case 1: |
|
| 86 case 4: |
|
| 87 if (g_utf8_validate(pair->value, -1, NULL)) { |
|
| 88 who = pair->value; |
|
| 89 } else { |
|
| 90 purple_debug_warning("yahoo", "yahoo_process_picture " |
|
| 91 "got non-UTF-8 string for key %d\n", pair->key); |
|
| 92 } |
|
| 93 break; |
|
| 94 case 5: /* us */ |
|
| 95 break; |
|
| 96 case 13: { |
|
| 97 int tmp; |
|
| 98 tmp = strtol(pair->value, NULL, 10); |
|
| 99 if (tmp == 1) { |
|
| 100 send_icon_info = TRUE; |
|
| 101 } else if (tmp == 2) { |
|
| 102 got_icon_info = TRUE; |
|
| 103 } |
|
| 104 break; |
|
| 105 } |
|
| 106 case 20: |
|
| 107 if (g_utf8_validate(pair->value, -1, NULL)) { |
|
| 108 url = pair->value; |
|
| 109 } else { |
|
| 110 purple_debug_warning("yahoo", "yahoo_process_picture " |
|
| 111 "got non-UTF-8 string for key %d\n", pair->key); |
|
| 112 } |
|
| 113 break; |
|
| 114 case 192: |
|
| 115 checksum = strtol(pair->value, NULL, 10); |
|
| 116 break; |
|
| 117 } |
|
| 118 |
|
| 119 l = l->next; |
|
| 120 } |
|
| 121 |
|
| 122 if (!who) |
|
| 123 return; |
|
| 124 |
|
| 125 if (!purple_privacy_check(purple_connection_get_account(gc), who)) { |
|
| 126 purple_debug_info("yahoo", "Picture packet from %s dropped.\n", who); |
|
| 127 return; |
|
| 128 } |
|
| 129 |
|
| 130 /* Yahoo IM 6 spits out 0.png as the URL if the buddy icon is not set */ |
|
| 131 if (who && got_icon_info && url && !g_ascii_strncasecmp(url, "http://", 7)) { |
|
| 132 /* TODO: make this work p2p, try p2p before the url */ |
|
| 133 PurpleUtilFetchUrlData *url_data; |
|
| 134 struct yahoo_fetch_picture_data *data; |
|
| 135 /* use whole URL if using HTTP Proxy */ |
|
| 136 gboolean use_whole_url = yahoo_account_use_http_proxy(gc); |
|
| 137 |
|
| 138 data = g_new0(struct yahoo_fetch_picture_data, 1); |
|
| 139 data->gc = gc; |
|
| 140 data->who = g_strdup(who); |
|
| 141 data->checksum = checksum; |
|
| 142 /* TODO: Does this need to be MSIE 5.0? */ |
|
| 143 url_data = purple_util_fetch_url(url, use_whole_url, |
|
| 144 "Mozilla/4.0 (compatible; MSIE 5.5)", FALSE, |
|
| 145 yahoo_fetch_picture_cb, data); |
|
| 146 if (url_data != NULL) { |
|
| 147 yd = gc->proto_data; |
|
| 148 yd->url_datas = g_slist_prepend(yd->url_datas, url_data); |
|
| 149 } |
|
| 150 } else if (who && send_icon_info) { |
|
| 151 yahoo_send_picture_info(gc, who); |
|
| 152 } |
|
| 153 } |
|
| 154 |
|
| 155 void yahoo_process_picture_checksum(PurpleConnection *gc, struct yahoo_packet *pkt) |
|
| 156 { |
|
| 157 GSList *l = pkt->hash; |
|
| 158 char *who = NULL; |
|
| 159 int checksum = 0; |
|
| 160 |
|
| 161 while (l) { |
|
| 162 struct yahoo_pair *pair = l->data; |
|
| 163 |
|
| 164 switch (pair->key) { |
|
| 165 case 4: |
|
| 166 if (g_utf8_validate(pair->value, -1, NULL)) { |
|
| 167 who = pair->value; |
|
| 168 } else { |
|
| 169 purple_debug_warning("yahoo", "yahoo_process_picture_checksum " |
|
| 170 "got non-UTF-8 string for key %d\n", pair->key); |
|
| 171 } |
|
| 172 break; |
|
| 173 case 5: |
|
| 174 /* us */ |
|
| 175 break; |
|
| 176 case 192: |
|
| 177 checksum = strtol(pair->value, NULL, 10); |
|
| 178 break; |
|
| 179 } |
|
| 180 l = l->next; |
|
| 181 } |
|
| 182 |
|
| 183 if (who) { |
|
| 184 PurpleBuddy *b = purple_find_buddy(gc->account, who); |
|
| 185 const char *locksum = NULL; |
|
| 186 |
|
| 187 /* FIXME: Cleanup this strtol() stuff if possible. */ |
|
| 188 if (b) { |
|
| 189 locksum = purple_buddy_icons_get_checksum_for_user(b); |
|
| 190 if (!locksum || (checksum != strtol(locksum, NULL, 10))) |
|
| 191 yahoo_send_picture_request(gc, who); |
|
| 192 } |
|
| 193 } |
|
| 194 } |
|
| 195 |
|
| 196 void yahoo_process_picture_upload(PurpleConnection *gc, struct yahoo_packet *pkt) |
|
| 197 { |
|
| 198 PurpleAccount *account = purple_connection_get_account(gc); |
|
| 199 YahooData *yd = gc->proto_data; |
|
| 200 GSList *l = pkt->hash; |
|
| 201 char *url = NULL; |
|
| 202 |
|
| 203 while (l) { |
|
| 204 struct yahoo_pair *pair = l->data; |
|
| 205 |
|
| 206 switch (pair->key) { |
|
| 207 case 5: |
|
| 208 /* us */ |
|
| 209 break; |
|
| 210 case 27: |
|
| 211 /* filename on our computer. */ |
|
| 212 break; |
|
| 213 case 20: /* url at yahoo */ |
|
| 214 if (g_utf8_validate(pair->value, -1, NULL)) { |
|
| 215 url = pair->value; |
|
| 216 } else { |
|
| 217 purple_debug_warning("yahoo", "yahoo_process_picture_upload " |
|
| 218 "got non-UTF-8 string for key %d\n", pair->key); |
|
| 219 } |
|
| 220 case 38: /* timestamp */ |
|
| 221 break; |
|
| 222 } |
|
| 223 l = l->next; |
|
| 224 } |
|
| 225 |
|
| 226 if (url) { |
|
| 227 g_free(yd->picture_url); |
|
| 228 yd->picture_url = g_strdup(url); |
|
| 229 purple_account_set_string(account, YAHOO_PICURL_SETTING, url); |
|
| 230 purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, yd->picture_checksum); |
|
| 231 yahoo_send_picture_checksum(gc); |
|
| 232 yahoo_send_picture_update(gc, 2); |
|
| 233 } |
|
| 234 } |
|
| 235 |
|
| 236 void yahoo_process_avatar_update(PurpleConnection *gc, struct yahoo_packet *pkt) |
|
| 237 { |
|
| 238 GSList *l = pkt->hash; |
|
| 239 char *who = NULL; |
|
| 240 int avatar = 0; |
|
| 241 |
|
| 242 while (l) { |
|
| 243 struct yahoo_pair *pair = l->data; |
|
| 244 |
|
| 245 switch (pair->key) { |
|
| 246 case 4: |
|
| 247 if (g_utf8_validate(pair->value, -1, NULL)) { |
|
| 248 who = pair->value; |
|
| 249 } else { |
|
| 250 purple_debug_warning("yahoo", "yahoo_process_avatar_upload " |
|
| 251 "got non-UTF-8 string for key %d\n", pair->key); |
|
| 252 } |
|
| 253 break; |
|
| 254 case 5: |
|
| 255 /* us */ |
|
| 256 break; |
|
| 257 case 206: /* Older versions. Still needed? */ |
|
| 258 case 213: /* Newer versions */ |
|
| 259 /* |
|
| 260 * 0 - No icon or avatar |
|
| 261 * 1 - Using an avatar |
|
| 262 * 2 - Using an icon |
|
| 263 */ |
|
| 264 avatar = strtol(pair->value, NULL, 10); |
|
| 265 break; |
|
| 266 } |
|
| 267 l = l->next; |
|
| 268 } |
|
| 269 |
|
| 270 if (who) { |
|
| 271 if (avatar == 2) |
|
| 272 yahoo_send_picture_request(gc, who); |
|
| 273 else if ((avatar == 0) || (avatar == 1)) { |
|
| 274 YahooFriend *f; |
|
| 275 purple_buddy_icons_set_for_user(gc->account, who, NULL, 0, NULL); |
|
| 276 if ((f = yahoo_friend_find(gc, who))) |
|
| 277 yahoo_friend_set_buddy_icon_need_request(f, TRUE); |
|
| 278 purple_debug_misc("yahoo", "Setting user %s's icon to NULL.\n", who); |
|
| 279 } |
|
| 280 } |
|
| 281 } |
|
| 282 |
|
| 283 void yahoo_send_picture_info(PurpleConnection *gc, const char *who) |
|
| 284 { |
|
| 285 YahooData *yd = gc->proto_data; |
|
| 286 struct yahoo_packet *pkt; |
|
| 287 |
|
| 288 if (!yd->picture_url) { |
|
| 289 purple_debug_warning("yahoo", "Attempted to send picture info without a picture\n"); |
|
| 290 return; |
|
| 291 } |
|
| 292 |
|
| 293 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, yd->session_id); |
|
| 294 yahoo_packet_hash(pkt, "ssssi", 1, purple_connection_get_display_name(gc), |
|
| 295 5, who, |
|
| 296 13, "2", 20, yd->picture_url, 192, yd->picture_checksum); |
|
| 297 yahoo_packet_send_and_free(pkt, yd); |
|
| 298 } |
|
| 299 |
|
| 300 void yahoo_send_picture_request(PurpleConnection *gc, const char *who) |
|
| 301 { |
|
| 302 YahooData *yd = gc->proto_data; |
|
| 303 struct yahoo_packet *pkt; |
|
| 304 |
|
| 305 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE, YAHOO_STATUS_AVAILABLE, yd->session_id); |
|
| 306 yahoo_packet_hash_str(pkt, 1, purple_connection_get_display_name(gc)); /* me */ |
|
| 307 yahoo_packet_hash_str(pkt, 5, who); /* the other guy */ |
|
| 308 yahoo_packet_hash_str(pkt, 13, "1"); /* 1 = request, 2 = reply */ |
|
| 309 yahoo_packet_send_and_free(pkt, yd); |
|
| 310 } |
|
| 311 |
|
| 312 void yahoo_send_picture_checksum(PurpleConnection *gc) |
|
| 313 { |
|
| 314 YahooData *yd = gc->proto_data; |
|
| 315 struct yahoo_packet *pkt; |
|
| 316 |
|
| 317 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_CHECKSUM, YAHOO_STATUS_AVAILABLE, yd->session_id); |
|
| 318 yahoo_packet_hash(pkt, "ssi", 1, purple_connection_get_display_name(gc), |
|
| 319 212, "1", 192, yd->picture_checksum); |
|
| 320 yahoo_packet_send_and_free(pkt, yd); |
|
| 321 } |
|
| 322 |
|
| 323 void yahoo_send_picture_update_to_user(PurpleConnection *gc, const char *who, int type) |
|
| 324 { |
|
| 325 YahooData *yd = gc->proto_data; |
|
| 326 struct yahoo_packet *pkt; |
|
| 327 |
|
| 328 pkt = yahoo_packet_new(YAHOO_SERVICE_AVATAR_UPDATE, YAHOO_STATUS_AVAILABLE, yd->session_id); |
|
| 329 yahoo_packet_hash(pkt, "si", 3, who, 213, type); |
|
| 330 yahoo_packet_send_and_free(pkt, yd); |
|
| 331 } |
|
| 332 |
|
| 333 struct yspufe { |
|
| 334 PurpleConnection *gc; |
|
| 335 int type; |
|
| 336 }; |
|
| 337 |
|
| 338 static void yahoo_send_picture_update_foreach(gpointer key, gpointer value, gpointer data) |
|
| 339 { |
|
| 340 const char *who = key; |
|
| 341 YahooFriend *f = value; |
|
| 342 struct yspufe *d = data; |
|
| 343 |
|
| 344 if (f->status != YAHOO_STATUS_OFFLINE) |
|
| 345 yahoo_send_picture_update_to_user(d->gc, who, d->type); |
|
| 346 } |
|
| 347 |
|
| 348 void yahoo_send_picture_update(PurpleConnection *gc, int type) |
|
| 349 { |
|
| 350 YahooData *yd = gc->proto_data; |
|
| 351 struct yspufe data; |
|
| 352 |
|
| 353 data.gc = gc; |
|
| 354 data.type = type; |
|
| 355 |
|
| 356 g_hash_table_foreach(yd->friends, yahoo_send_picture_update_foreach, &data); |
|
| 357 } |
|
| 358 |
|
| 359 void yahoo_buddy_icon_upload_data_free(struct yahoo_buddy_icon_upload_data *d) |
|
| 360 { |
|
| 361 purple_debug_misc("yahoo", "In yahoo_buddy_icon_upload_data_free()\n"); |
|
| 362 |
|
| 363 if (d->str) |
|
| 364 g_string_free(d->str, TRUE); |
|
| 365 g_free(d->filename); |
|
| 366 if (d->watcher) |
|
| 367 purple_input_remove(d->watcher); |
|
| 368 if (d->fd != -1) |
|
| 369 close(d->fd); |
|
| 370 g_free(d); |
|
| 371 } |
|
| 372 |
|
| 373 /* we couldn't care less about the server's response, but yahoo gets grumpy if we close before it sends it */ |
|
| 374 static void yahoo_buddy_icon_upload_reading(gpointer data, gint source, PurpleInputCondition condition) |
|
| 375 { |
|
| 376 struct yahoo_buddy_icon_upload_data *d = data; |
|
| 377 PurpleConnection *gc = d->gc; |
|
| 378 char buf[1024]; |
|
| 379 int ret; |
|
| 380 |
|
| 381 if (!PURPLE_CONNECTION_IS_VALID(gc)) { |
|
| 382 yahoo_buddy_icon_upload_data_free(d); |
|
| 383 return; |
|
| 384 } |
|
| 385 |
|
| 386 ret = read(d->fd, buf, sizeof(buf)); |
|
| 387 |
|
| 388 if (ret < 0 && errno == EAGAIN) |
|
| 389 return; |
|
| 390 else if (ret <= 0) { |
|
| 391 /* There are other problems if d->str->len overflows, so shut up the |
|
| 392 * warning on 64-bit. */ |
|
| 393 purple_debug_info("yahoo", "Buddy icon upload response (%" G_GSIZE_FORMAT ") bytes (> ~400 indicates failure):\n%.*s\n", |
|
| 394 d->str->len, (guint)d->str->len, d->str->str); |
|
| 395 |
|
| 396 yahoo_buddy_icon_upload_data_free(d); |
|
| 397 return; |
|
| 398 } |
|
| 399 |
|
| 400 g_string_append_len(d->str, buf, ret); |
|
| 401 } |
|
| 402 |
|
| 403 static void yahoo_buddy_icon_upload_pending(gpointer data, gint source, PurpleInputCondition condition) |
|
| 404 { |
|
| 405 struct yahoo_buddy_icon_upload_data *d = data; |
|
| 406 PurpleConnection *gc = d->gc; |
|
| 407 gssize wrote; |
|
| 408 |
|
| 409 if (!PURPLE_CONNECTION_IS_VALID(gc)) { |
|
| 410 yahoo_buddy_icon_upload_data_free(d); |
|
| 411 return; |
|
| 412 } |
|
| 413 |
|
| 414 wrote = write(d->fd, d->str->str + d->pos, d->str->len - d->pos); |
|
| 415 if (wrote < 0 && errno == EAGAIN) |
|
| 416 return; |
|
| 417 if (wrote <= 0) { |
|
| 418 purple_debug_info("yahoo", "Error uploading buddy icon.\n"); |
|
| 419 yahoo_buddy_icon_upload_data_free(d); |
|
| 420 return; |
|
| 421 } |
|
| 422 d->pos += wrote; |
|
| 423 if ((size_t)d->pos >= d->str->len) { |
|
| 424 purple_debug_misc("yahoo", "Finished uploading buddy icon.\n"); |
|
| 425 purple_input_remove(d->watcher); |
|
| 426 /* Clean out the sent buffer and reuse it to read the result */ |
|
| 427 g_string_free(d->str, TRUE); |
|
| 428 d->str = g_string_new(""); |
|
| 429 d->watcher = purple_input_add(d->fd, PURPLE_INPUT_READ, yahoo_buddy_icon_upload_reading, d); |
|
| 430 } |
|
| 431 } |
|
| 432 |
|
| 433 static void yahoo_buddy_icon_upload_connected(gpointer data, gint source, const gchar *error_message) |
|
| 434 { |
|
| 435 struct yahoo_buddy_icon_upload_data *d = data; |
|
| 436 struct yahoo_packet *pkt; |
|
| 437 gchar *tmp, *header; |
|
| 438 guchar *pkt_buf; |
|
| 439 const char *host; |
|
| 440 int port; |
|
| 441 gsize pkt_buf_len; |
|
| 442 PurpleConnection *gc = d->gc; |
|
| 443 PurpleAccount *account; |
|
| 444 YahooData *yd; |
|
| 445 /* use whole URL if using HTTP Proxy */ |
|
| 446 gboolean use_whole_url = yahoo_account_use_http_proxy(gc); |
|
| 447 |
|
| 448 account = purple_connection_get_account(gc); |
|
| 449 yd = gc->proto_data; |
|
| 450 |
|
| 451 /* Buddy icon connect is now complete; clear the PurpleProxyConnectData */ |
|
| 452 yd->buddy_icon_connect_data = NULL; |
|
| 453 |
|
| 454 if (source < 0) { |
|
| 455 purple_debug_error("yahoo", "Buddy icon upload failed: %s\n", error_message); |
|
| 456 yahoo_buddy_icon_upload_data_free(d); |
|
| 457 return; |
|
| 458 } |
|
| 459 |
|
| 460 pkt = yahoo_packet_new(YAHOO_SERVICE_PICTURE_UPLOAD, YAHOO_STATUS_AVAILABLE, yd->session_id); |
|
| 461 |
|
| 462 tmp = g_strdup_printf("%" G_GSIZE_FORMAT, d->str->len); |
|
| 463 /* 1 = me, 38 = expire time(?), 0 = me, 28 = size, 27 = filename, 14 = NULL, 29 = data */ |
|
| 464 yahoo_packet_hash_str(pkt, 1, purple_connection_get_display_name(gc)); |
|
| 465 yahoo_packet_hash_str(pkt, 38, "604800"); /* time til expire */ |
|
| 466 purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, time(NULL) + 604800); |
|
| 467 yahoo_packet_hash_str(pkt, 0, purple_connection_get_display_name(gc)); |
|
| 468 yahoo_packet_hash_str(pkt, 28, tmp); |
|
| 469 g_free(tmp); |
|
| 470 yahoo_packet_hash_str(pkt, 27, d->filename); |
|
| 471 yahoo_packet_hash_str(pkt, 14, ""); |
|
| 472 /* 4 padding for the 29 key name */ |
|
| 473 pkt_buf_len = yahoo_packet_build(pkt, 4, FALSE, yd->jp, &pkt_buf); |
|
| 474 yahoo_packet_free(pkt); |
|
| 475 |
|
| 476 /* header + packet + "29" + 0xc0 + 0x80) + pictureblob */ |
|
| 477 |
|
| 478 host = purple_account_get_string(account, "xfer_host", yd->jp? YAHOOJP_XFER_HOST : YAHOO_XFER_HOST); |
|
| 479 port = purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT); |
|
| 480 tmp = g_strdup_printf("%s:%d", host, port); |
|
| 481 header = g_strdup_printf("POST %s%s/notifyft HTTP/1.1\r\n" |
|
| 482 "User-Agent: " YAHOO_CLIENT_USERAGENT "\r\n" |
|
| 483 "Cookie: T=%s; Y=%s\r\n" |
|
| 484 "Host: %s\r\n" |
|
| 485 "Content-Length: %" G_GSIZE_FORMAT "\r\n" |
|
| 486 "Cache-Control: no-cache\r\n\r\n", |
|
| 487 use_whole_url ? "http://" : "", use_whole_url ? tmp : "", |
|
| 488 yd->cookie_t, yd->cookie_y, |
|
| 489 tmp, |
|
| 490 pkt_buf_len + 4 + d->str->len); |
|
| 491 g_free(tmp); |
|
| 492 |
|
| 493 /* There's no magic here, we just need to prepend in reverse order */ |
|
| 494 g_string_prepend(d->str, "29\xc0\x80"); |
|
| 495 |
|
| 496 g_string_prepend_len(d->str, (char *)pkt_buf, pkt_buf_len); |
|
| 497 g_free(pkt_buf); |
|
| 498 |
|
| 499 g_string_prepend(d->str, header); |
|
| 500 g_free(header); |
|
| 501 |
|
| 502 /* There are other problems if we're uploading over 4GB of data */ |
|
| 503 purple_debug_info("yahoo", "Buddy icon upload data:\n%.*s\n", (guint)d->str->len, d->str->str); |
|
| 504 |
|
| 505 d->fd = source; |
|
| 506 d->watcher = purple_input_add(d->fd, PURPLE_INPUT_WRITE, yahoo_buddy_icon_upload_pending, d); |
|
| 507 |
|
| 508 yahoo_buddy_icon_upload_pending(d, d->fd, PURPLE_INPUT_WRITE); |
|
| 509 } |
|
| 510 |
|
| 511 void yahoo_buddy_icon_upload(PurpleConnection *gc, struct yahoo_buddy_icon_upload_data *d) |
|
| 512 { |
|
| 513 PurpleAccount *account = purple_connection_get_account(gc); |
|
| 514 YahooData *yd = gc->proto_data; |
|
| 515 |
|
| 516 if (yd->buddy_icon_connect_data != NULL) { |
|
| 517 /* Cancel any in-progress buddy icon upload */ |
|
| 518 purple_proxy_connect_cancel(yd->buddy_icon_connect_data); |
|
| 519 yd->buddy_icon_connect_data = NULL; |
|
| 520 } |
|
| 521 |
|
| 522 yd->buddy_icon_connect_data = purple_proxy_connect(NULL, account, |
|
| 523 purple_account_get_string(account, "xfer_host", |
|
| 524 yd->jp? YAHOOJP_XFER_HOST : YAHOO_XFER_HOST), |
|
| 525 purple_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), |
|
| 526 yahoo_buddy_icon_upload_connected, d); |
|
| 527 |
|
| 528 if (yd->buddy_icon_connect_data == NULL) |
|
| 529 { |
|
| 530 purple_debug_error("yahoo", "Uploading our buddy icon failed to connect.\n"); |
|
| 531 yahoo_buddy_icon_upload_data_free(d); |
|
| 532 } |
|
| 533 } |
|
| 534 |
|
| 535 static int yahoo_buddy_icon_calculate_checksum(const guchar *data, gsize len) |
|
| 536 { |
|
| 537 /* This code is borrowed from Kopete, which seems to be managing to calculate |
|
| 538 checksums in such a manner that Yahoo!'s servers are happy */ |
|
| 539 |
|
| 540 const guchar *p = data; |
|
| 541 int checksum = 0, g, i = len; |
|
| 542 |
|
| 543 while(i--) { |
|
| 544 checksum = (checksum << 4) + *p++; |
|
| 545 |
|
| 546 if((g = (checksum & 0xf0000000)) != 0) |
|
| 547 checksum ^= g >> 23; |
|
| 548 |
|
| 549 checksum &= ~g; |
|
| 550 } |
|
| 551 |
|
| 552 purple_debug_misc("yahoo", "Calculated buddy icon checksum: %d\n", checksum); |
|
| 553 |
|
| 554 return checksum; |
|
| 555 } |
|
| 556 |
|
| 557 void yahoo_set_buddy_icon(PurpleConnection *gc, PurpleStoredImage *img) |
|
| 558 { |
|
| 559 YahooData *yd = gc->proto_data; |
|
| 560 PurpleAccount *account = gc->account; |
|
| 561 |
|
| 562 if (img == NULL) { |
|
| 563 g_free(yd->picture_url); |
|
| 564 yd->picture_url = NULL; |
|
| 565 |
|
| 566 /* TODO: don't we have to clear it on the server too?! */ |
|
| 567 |
|
| 568 purple_account_set_string(account, YAHOO_PICURL_SETTING, NULL); |
|
| 569 purple_account_set_int(account, YAHOO_PICCKSUM_SETTING, 0); |
|
| 570 purple_account_set_int(account, YAHOO_PICEXPIRE_SETTING, 0); |
|
| 571 if (yd->logged_in) |
|
| 572 /* Tell everyone we ain't got one no more */ |
|
| 573 yahoo_send_picture_update(gc, 0); |
|
| 574 |
|
| 575 } else { |
|
| 576 gconstpointer data = purple_imgstore_get_data(img); |
|
| 577 size_t len = purple_imgstore_get_size(img); |
|
| 578 GString *s = g_string_new_len(data, len); |
|
| 579 struct yahoo_buddy_icon_upload_data *d; |
|
| 580 int oldcksum = purple_account_get_int(account, YAHOO_PICCKSUM_SETTING, 0); |
|
| 581 int expire = purple_account_get_int(account, YAHOO_PICEXPIRE_SETTING, 0); |
|
| 582 const char *oldurl = purple_account_get_string(account, YAHOO_PICURL_SETTING, NULL); |
|
| 583 |
|
| 584 yd->picture_checksum = yahoo_buddy_icon_calculate_checksum(data, len); |
|
| 585 |
|
| 586 if ((yd->picture_checksum == oldcksum) && |
|
| 587 (expire > (time(NULL) + 60*60*24)) && oldurl) |
|
| 588 { |
|
| 589 purple_debug_misc("yahoo", "buddy icon is up to date. Not reuploading.\n"); |
|
| 590 g_string_free(s, TRUE); |
|
| 591 g_free(yd->picture_url); |
|
| 592 yd->picture_url = g_strdup(oldurl); |
|
| 593 return; |
|
| 594 } |
|
| 595 |
|
| 596 /* We use this solely for sending a filename to the server */ |
|
| 597 d = g_new0(struct yahoo_buddy_icon_upload_data, 1); |
|
| 598 d->gc = gc; |
|
| 599 d->str = s; |
|
| 600 d->fd = -1; |
|
| 601 d->filename = g_strdup(purple_imgstore_get_filename(img)); |
|
| 602 |
|
| 603 if (!yd->logged_in) { |
|
| 604 yd->picture_upload_todo = d; |
|
| 605 return; |
|
| 606 } |
|
| 607 |
|
| 608 yahoo_buddy_icon_upload(gc, d); |
|
| 609 |
|
| 610 } |
|
| 611 } |
|