| 1 /* |
|
| 2 * @file yahoo_filexfer.c Yahoo Filetransfer |
|
| 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 #include "prpl.h" |
|
| 24 #include "internal.h" |
|
| 25 #include "util.h" |
|
| 26 #include "debug.h" |
|
| 27 #include "notify.h" |
|
| 28 #include "proxy.h" |
|
| 29 #include "ft.h" |
|
| 30 #include "yahoo.h" |
|
| 31 #include "yahoo_packet.h" |
|
| 32 #include "yahoo_filexfer.h" |
|
| 33 #include "yahoo_doodle.h" |
|
| 34 |
|
| 35 struct yahoo_xfer_data { |
|
| 36 gchar *host; |
|
| 37 gchar *path; |
|
| 38 int port; |
|
| 39 GaimConnection *gc; |
|
| 40 long expires; |
|
| 41 gboolean started; |
|
| 42 gchar *txbuf; |
|
| 43 gsize txbuflen; |
|
| 44 gsize txbuf_written; |
|
| 45 guint tx_handler; |
|
| 46 gchar *rxqueue; |
|
| 47 guint rxlen; |
|
| 48 }; |
|
| 49 |
|
| 50 static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd) |
|
| 51 { |
|
| 52 g_free(xd->host); |
|
| 53 g_free(xd->path); |
|
| 54 g_free(xd->txbuf); |
|
| 55 if (xd->tx_handler) |
|
| 56 gaim_input_remove(xd->tx_handler); |
|
| 57 g_free(xd); |
|
| 58 } |
|
| 59 |
|
| 60 static void yahoo_receivefile_send_cb(gpointer data, gint source, GaimInputCondition condition) |
|
| 61 { |
|
| 62 GaimXfer *xfer; |
|
| 63 struct yahoo_xfer_data *xd; |
|
| 64 int remaining, written; |
|
| 65 |
|
| 66 xfer = data; |
|
| 67 xd = xfer->data; |
|
| 68 |
|
| 69 remaining = xd->txbuflen - xd->txbuf_written; |
|
| 70 written = write(xfer->fd, xd->txbuf + xd->txbuf_written, remaining); |
|
| 71 |
|
| 72 if (written < 0 && errno == EAGAIN) |
|
| 73 written = 0; |
|
| 74 else if (written <= 0) { |
|
| 75 gaim_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno); |
|
| 76 gaim_xfer_cancel_remote(xfer); |
|
| 77 return; |
|
| 78 } |
|
| 79 |
|
| 80 if (written < remaining) { |
|
| 81 xd->txbuf_written += written; |
|
| 82 return; |
|
| 83 } |
|
| 84 |
|
| 85 gaim_input_remove(xd->tx_handler); |
|
| 86 xd->tx_handler = 0; |
|
| 87 g_free(xd->txbuf); |
|
| 88 xd->txbuf = NULL; |
|
| 89 xd->txbuflen = 0; |
|
| 90 |
|
| 91 gaim_xfer_start(xfer, source, NULL, 0); |
|
| 92 |
|
| 93 } |
|
| 94 |
|
| 95 static void yahoo_receivefile_connected(gpointer data, gint source, const gchar *error_message) |
|
| 96 { |
|
| 97 GaimXfer *xfer; |
|
| 98 struct yahoo_xfer_data *xd; |
|
| 99 |
|
| 100 gaim_debug(GAIM_DEBUG_INFO, "yahoo", |
|
| 101 "AAA - in yahoo_receivefile_connected\n"); |
|
| 102 if (!(xfer = data)) |
|
| 103 return; |
|
| 104 if (!(xd = xfer->data)) |
|
| 105 return; |
|
| 106 if ((source < 0) || (xd->path == NULL) || (xd->host == NULL)) { |
|
| 107 gaim_xfer_error(GAIM_XFER_RECEIVE, gaim_xfer_get_account(xfer), |
|
| 108 xfer->who, _("Unable to connect.")); |
|
| 109 gaim_xfer_cancel_remote(xfer); |
|
| 110 return; |
|
| 111 } |
|
| 112 |
|
| 113 xfer->fd = source; |
|
| 114 |
|
| 115 /* The first time we get here, assemble the tx buffer */ |
|
| 116 if (xd->txbuflen == 0) { |
|
| 117 xd->txbuf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", |
|
| 118 xd->path, xd->host); |
|
| 119 xd->txbuflen = strlen(xd->txbuf); |
|
| 120 xd->txbuf_written = 0; |
|
| 121 } |
|
| 122 |
|
| 123 if (!xd->tx_handler) |
|
| 124 { |
|
| 125 xd->tx_handler = gaim_input_add(source, GAIM_INPUT_WRITE, |
|
| 126 yahoo_receivefile_send_cb, xfer); |
|
| 127 yahoo_receivefile_send_cb(xfer, source, GAIM_INPUT_WRITE); |
|
| 128 } |
|
| 129 } |
|
| 130 |
|
| 131 static void yahoo_sendfile_send_cb(gpointer data, gint source, GaimInputCondition condition) |
|
| 132 { |
|
| 133 GaimXfer *xfer; |
|
| 134 struct yahoo_xfer_data *xd; |
|
| 135 int written, remaining; |
|
| 136 |
|
| 137 xfer = data; |
|
| 138 xd = xfer->data; |
|
| 139 |
|
| 140 remaining = xd->txbuflen - xd->txbuf_written; |
|
| 141 written = write(xfer->fd, xd->txbuf + xd->txbuf_written, remaining); |
|
| 142 |
|
| 143 if (written < 0 && errno == EAGAIN) |
|
| 144 written = 0; |
|
| 145 else if (written <= 0) { |
|
| 146 gaim_debug_error("yahoo", "Unable to write in order to start ft errno = %d\n", errno); |
|
| 147 gaim_xfer_cancel_remote(xfer); |
|
| 148 return; |
|
| 149 } |
|
| 150 |
|
| 151 if (written < remaining) { |
|
| 152 xd->txbuf_written += written; |
|
| 153 return; |
|
| 154 } |
|
| 155 |
|
| 156 gaim_input_remove(xd->tx_handler); |
|
| 157 xd->tx_handler = 0; |
|
| 158 g_free(xd->txbuf); |
|
| 159 xd->txbuf = NULL; |
|
| 160 xd->txbuflen = 0; |
|
| 161 |
|
| 162 gaim_xfer_start(xfer, source, NULL, 0); |
|
| 163 } |
|
| 164 |
|
| 165 static void yahoo_sendfile_connected(gpointer data, gint source, const gchar *error_message) |
|
| 166 { |
|
| 167 GaimXfer *xfer; |
|
| 168 struct yahoo_xfer_data *xd; |
|
| 169 struct yahoo_packet *pkt; |
|
| 170 gchar *size, *filename, *encoded_filename, *header; |
|
| 171 guchar *pkt_buf; |
|
| 172 const char *host; |
|
| 173 int port; |
|
| 174 size_t content_length, header_len, pkt_buf_len; |
|
| 175 GaimConnection *gc; |
|
| 176 GaimAccount *account; |
|
| 177 struct yahoo_data *yd; |
|
| 178 |
|
| 179 gaim_debug(GAIM_DEBUG_INFO, "yahoo", |
|
| 180 "AAA - in yahoo_sendfile_connected\n"); |
|
| 181 if (!(xfer = data)) |
|
| 182 return; |
|
| 183 if (!(xd = xfer->data)) |
|
| 184 return; |
|
| 185 |
|
| 186 if (source < 0) { |
|
| 187 gaim_xfer_error(GAIM_XFER_RECEIVE, gaim_xfer_get_account(xfer), |
|
| 188 xfer->who, _("Unable to connect.")); |
|
| 189 gaim_xfer_cancel_remote(xfer); |
|
| 190 return; |
|
| 191 } |
|
| 192 |
|
| 193 xfer->fd = source; |
|
| 194 |
|
| 195 /* Assemble the tx buffer */ |
|
| 196 gc = xd->gc; |
|
| 197 account = gaim_connection_get_account(gc); |
|
| 198 yd = gc->proto_data; |
|
| 199 |
|
| 200 pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, |
|
| 201 YAHOO_STATUS_AVAILABLE, yd->session_id); |
|
| 202 |
|
| 203 size = g_strdup_printf("%" G_GSIZE_FORMAT, gaim_xfer_get_size(xfer)); |
|
| 204 filename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); |
|
| 205 encoded_filename = yahoo_string_encode(gc, filename, NULL); |
|
| 206 |
|
| 207 yahoo_packet_hash(pkt, "sssss", 0, gaim_connection_get_display_name(gc), |
|
| 208 5, xfer->who, 14, "", 27, encoded_filename, 28, size); |
|
| 209 g_free(size); |
|
| 210 g_free(encoded_filename); |
|
| 211 g_free(filename); |
|
| 212 |
|
| 213 content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); |
|
| 214 |
|
| 215 pkt_buf_len = yahoo_packet_build(pkt, 8, FALSE, &pkt_buf); |
|
| 216 yahoo_packet_free(pkt); |
|
| 217 |
|
| 218 host = gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST); |
|
| 219 port = gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT); |
|
| 220 header = g_strdup_printf( |
|
| 221 "POST http://%s:%d/notifyft HTTP/1.0\r\n" |
|
| 222 "Content-length: %" G_GSIZE_FORMAT "\r\n" |
|
| 223 "Host: %s:%d\r\n" |
|
| 224 "Cookie: Y=%s; T=%s\r\n" |
|
| 225 "\r\n", |
|
| 226 host, port, content_length + 4 + gaim_xfer_get_size(xfer), |
|
| 227 host, port, yd->cookie_y, yd->cookie_t); |
|
| 228 |
|
| 229 header_len = strlen(header); |
|
| 230 |
|
| 231 xd->txbuflen = header_len + pkt_buf_len + 4; |
|
| 232 xd->txbuf = g_malloc(xd->txbuflen); |
|
| 233 |
|
| 234 memcpy(xd->txbuf, header, header_len); |
|
| 235 g_free(header); |
|
| 236 memcpy(xd->txbuf + header_len, pkt_buf, pkt_buf_len); |
|
| 237 g_free(pkt_buf); |
|
| 238 memcpy(xd->txbuf + header_len + pkt_buf_len, "29\xc0\x80", 4); |
|
| 239 |
|
| 240 xd->txbuf_written = 0; |
|
| 241 |
|
| 242 if (xd->tx_handler == 0) |
|
| 243 { |
|
| 244 xd->tx_handler = gaim_input_add(source, GAIM_INPUT_WRITE, |
|
| 245 yahoo_sendfile_send_cb, xfer); |
|
| 246 yahoo_sendfile_send_cb(xfer, source, GAIM_INPUT_WRITE); |
|
| 247 } |
|
| 248 } |
|
| 249 |
|
| 250 static void yahoo_xfer_init(GaimXfer *xfer) |
|
| 251 { |
|
| 252 struct yahoo_xfer_data *xfer_data; |
|
| 253 GaimConnection *gc; |
|
| 254 GaimAccount *account; |
|
| 255 struct yahoo_data *yd; |
|
| 256 |
|
| 257 xfer_data = xfer->data; |
|
| 258 gc = xfer_data->gc; |
|
| 259 yd = gc->proto_data; |
|
| 260 account = gaim_connection_get_account(gc); |
|
| 261 |
|
| 262 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { |
|
| 263 if (yd->jp) { |
|
| 264 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xferjp_host", YAHOOJP_XFER_HOST), |
|
| 265 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), |
|
| 266 yahoo_sendfile_connected, xfer) == NULL) |
|
| 267 { |
|
| 268 gaim_notify_error(gc, NULL, _("File Transfer Failed"), |
|
| 269 _("Unable to establish file descriptor.")); |
|
| 270 gaim_xfer_cancel_remote(xfer); |
|
| 271 } |
|
| 272 } else { |
|
| 273 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), |
|
| 274 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), |
|
| 275 yahoo_sendfile_connected, xfer) == NULL) |
|
| 276 { |
|
| 277 gaim_notify_error(gc, NULL, _("File Transfer Failed"), |
|
| 278 _("Unable to establish file descriptor.")); |
|
| 279 gaim_xfer_cancel_remote(xfer); |
|
| 280 } |
|
| 281 } |
|
| 282 } else { |
|
| 283 /* TODO: Using xfer->fd like this is probably a bad thing... */ |
|
| 284 if (gaim_proxy_connect(account, xfer_data->host, xfer_data->port, |
|
| 285 yahoo_receivefile_connected, xfer) == NULL) |
|
| 286 xfer->fd = -1; |
|
| 287 else |
|
| 288 xfer->fd = 0; |
|
| 289 if (xfer->fd == -1) { |
|
| 290 gaim_notify_error(gc, NULL, _("File Transfer Failed"), |
|
| 291 _("Unable to establish file descriptor.")); |
|
| 292 gaim_xfer_cancel_remote(xfer); |
|
| 293 } |
|
| 294 } |
|
| 295 } |
|
| 296 |
|
| 297 static void yahoo_xfer_start(GaimXfer *xfer) |
|
| 298 { |
|
| 299 /* We don't need to do anything here, do we? */ |
|
| 300 } |
|
| 301 |
|
| 302 static void yahoo_xfer_end(GaimXfer *xfer) |
|
| 303 { |
|
| 304 struct yahoo_xfer_data *xfer_data; |
|
| 305 |
|
| 306 xfer_data = xfer->data; |
|
| 307 |
|
| 308 if (xfer_data) |
|
| 309 yahoo_xfer_data_free(xfer_data); |
|
| 310 xfer->data = NULL; |
|
| 311 |
|
| 312 } |
|
| 313 |
|
| 314 static guint calculate_length(const gchar *l, size_t len) |
|
| 315 { |
|
| 316 int i; |
|
| 317 |
|
| 318 for (i = 0; i < len; i++) { |
|
| 319 if (!g_ascii_isdigit(l[i])) |
|
| 320 continue; |
|
| 321 return strtol(l + i, NULL, 10); |
|
| 322 } |
|
| 323 return 0; |
|
| 324 } |
|
| 325 |
|
| 326 static gssize yahoo_xfer_read(guchar **buffer, GaimXfer *xfer) |
|
| 327 { |
|
| 328 gchar buf[4096]; |
|
| 329 gssize len; |
|
| 330 gchar *start = NULL; |
|
| 331 gchar *length; |
|
| 332 gchar *end; |
|
| 333 int filelen; |
|
| 334 struct yahoo_xfer_data *xd = xfer->data; |
|
| 335 |
|
| 336 if (gaim_xfer_get_type(xfer) != GAIM_XFER_RECEIVE) { |
|
| 337 return 0; |
|
| 338 } |
|
| 339 |
|
| 340 len = read(xfer->fd, buf, sizeof(buf)); |
|
| 341 |
|
| 342 if (len <= 0) { |
|
| 343 if ((gaim_xfer_get_size(xfer) > 0) && |
|
| 344 (gaim_xfer_get_bytes_sent(xfer) >= gaim_xfer_get_size(xfer))) { |
|
| 345 gaim_xfer_set_completed(xfer, TRUE); |
|
| 346 return 0; |
|
| 347 } else |
|
| 348 return -1; |
|
| 349 } |
|
| 350 |
|
| 351 if (!xd->started) { |
|
| 352 xd->rxqueue = g_realloc(xd->rxqueue, len + xd->rxlen); |
|
| 353 memcpy(xd->rxqueue + xd->rxlen, buf, len); |
|
| 354 xd->rxlen += len; |
|
| 355 |
|
| 356 length = g_strstr_len(xd->rxqueue, len, "Content-length:"); |
|
| 357 /* some proxies re-write this header, changing the capitalization :( |
|
| 358 * technically that's allowed since headers are case-insensitive |
|
| 359 * [RFC 2616, section 4.2] */ |
|
| 360 if (length == NULL) |
|
| 361 length = g_strstr_len(xd->rxqueue, len, "Content-Length:"); |
|
| 362 if (length) { |
|
| 363 end = g_strstr_len(length, length - xd->rxqueue, "\r\n"); |
|
| 364 if (!end) |
|
| 365 return 0; |
|
| 366 if ((filelen = calculate_length(length, len - (length - xd->rxqueue)))) |
|
| 367 gaim_xfer_set_size(xfer, filelen); |
|
| 368 } |
|
| 369 start = g_strstr_len(xd->rxqueue, len, "\r\n\r\n"); |
|
| 370 if (start) |
|
| 371 start += 4; |
|
| 372 if (!start || start > (xd->rxqueue + len)) |
|
| 373 return 0; |
|
| 374 xd->started = TRUE; |
|
| 375 |
|
| 376 len -= (start - xd->rxqueue); |
|
| 377 |
|
| 378 *buffer = g_malloc(len); |
|
| 379 memcpy(*buffer, start, len); |
|
| 380 g_free(xd->rxqueue); |
|
| 381 xd->rxqueue = NULL; |
|
| 382 xd->rxlen = 0; |
|
| 383 } else { |
|
| 384 *buffer = g_malloc(len); |
|
| 385 memcpy(*buffer, buf, len); |
|
| 386 } |
|
| 387 |
|
| 388 return len; |
|
| 389 } |
|
| 390 |
|
| 391 static gssize yahoo_xfer_write(const guchar *buffer, size_t size, GaimXfer *xfer) |
|
| 392 { |
|
| 393 gssize len; |
|
| 394 struct yahoo_xfer_data *xd = xfer->data; |
|
| 395 |
|
| 396 if (!xd) |
|
| 397 return -1; |
|
| 398 |
|
| 399 if (gaim_xfer_get_type(xfer) != GAIM_XFER_SEND) { |
|
| 400 return -1; |
|
| 401 } |
|
| 402 |
|
| 403 len = write(xfer->fd, buffer, size); |
|
| 404 |
|
| 405 if (len == -1) { |
|
| 406 if (gaim_xfer_get_bytes_sent(xfer) >= gaim_xfer_get_size(xfer)) |
|
| 407 gaim_xfer_set_completed(xfer, TRUE); |
|
| 408 if ((errno != EAGAIN) && (errno != EINTR)) |
|
| 409 return -1; |
|
| 410 return 0; |
|
| 411 } |
|
| 412 |
|
| 413 if ((gaim_xfer_get_bytes_sent(xfer) + len) >= gaim_xfer_get_size(xfer)) |
|
| 414 gaim_xfer_set_completed(xfer, TRUE); |
|
| 415 |
|
| 416 return len; |
|
| 417 } |
|
| 418 |
|
| 419 static void yahoo_xfer_cancel_send(GaimXfer *xfer) |
|
| 420 { |
|
| 421 struct yahoo_xfer_data *xfer_data; |
|
| 422 |
|
| 423 xfer_data = xfer->data; |
|
| 424 |
|
| 425 if (xfer_data) |
|
| 426 yahoo_xfer_data_free(xfer_data); |
|
| 427 xfer->data = NULL; |
|
| 428 } |
|
| 429 |
|
| 430 static void yahoo_xfer_cancel_recv(GaimXfer *xfer) |
|
| 431 { |
|
| 432 struct yahoo_xfer_data *xfer_data; |
|
| 433 |
|
| 434 xfer_data = xfer->data; |
|
| 435 |
|
| 436 if (xfer_data) |
|
| 437 yahoo_xfer_data_free(xfer_data); |
|
| 438 xfer->data = NULL; |
|
| 439 } |
|
| 440 |
|
| 441 void yahoo_process_p2pfilexfer(GaimConnection *gc, struct yahoo_packet *pkt) |
|
| 442 { |
|
| 443 GSList *l = pkt->hash; |
|
| 444 |
|
| 445 char *me = NULL; |
|
| 446 char *from = NULL; |
|
| 447 char *service = NULL; |
|
| 448 char *message = NULL; |
|
| 449 char *command = NULL; |
|
| 450 char *imv = NULL; |
|
| 451 char *unknown = NULL; |
|
| 452 |
|
| 453 /* Get all the necessary values from this new packet */ |
|
| 454 while(l != NULL) |
|
| 455 { |
|
| 456 struct yahoo_pair *pair = l->data; |
|
| 457 |
|
| 458 if(pair->key == 5) /* Get who the packet is for */ |
|
| 459 me = pair->value; |
|
| 460 |
|
| 461 if(pair->key == 4) /* Get who the packet is from */ |
|
| 462 from = pair->value; |
|
| 463 |
|
| 464 if(pair->key == 49) /* Get the type of service */ |
|
| 465 service = pair->value; |
|
| 466 |
|
| 467 if(pair->key == 14) /* Get the 'message' of the packet */ |
|
| 468 message = pair->value; |
|
| 469 |
|
| 470 if(pair->key == 13) /* Get the command associated with this packet */ |
|
| 471 command = pair->value; |
|
| 472 |
|
| 473 if(pair->key == 63) /* IMVironment name and version */ |
|
| 474 imv = pair->value; |
|
| 475 |
|
| 476 if(pair->key == 64) /* Not sure, but it does vary with initialization of Doodle */ |
|
| 477 unknown = pair->value; /* So, I'll keep it (for a little while atleast) */ |
|
| 478 |
|
| 479 l = l->next; |
|
| 480 } |
|
| 481 |
|
| 482 /* If this packet is an IMVIRONMENT, handle it accordingly */ |
|
| 483 if(service != NULL && imv != NULL && !strcmp(service, "IMVIRONMENT")) |
|
| 484 { |
|
| 485 /* Check for a Doodle packet and handle it accordingly */ |
|
| 486 if(!strcmp(imv, "doodle;11")) |
|
| 487 yahoo_doodle_process(gc, me, from, command, message); |
|
| 488 |
|
| 489 /* If an IMVIRONMENT packet comes without a specific imviroment name */ |
|
| 490 if(!strcmp(imv, ";0")) |
|
| 491 { |
|
| 492 /* It is unfortunately time to close all IMVironments with the remote client */ |
|
| 493 yahoo_doodle_command_got_shutdown(gc, from); |
|
| 494 } |
|
| 495 } |
|
| 496 } |
|
| 497 |
|
| 498 void yahoo_process_filetransfer(GaimConnection *gc, struct yahoo_packet *pkt) |
|
| 499 { |
|
| 500 char *from = NULL; |
|
| 501 char *to = NULL; |
|
| 502 char *msg = NULL; |
|
| 503 char *url = NULL; |
|
| 504 char *imv = NULL; |
|
| 505 long expires = 0; |
|
| 506 GaimXfer *xfer; |
|
| 507 struct yahoo_data *yd; |
|
| 508 struct yahoo_xfer_data *xfer_data; |
|
| 509 char *service = NULL; |
|
| 510 char *filename = NULL; |
|
| 511 unsigned long filesize = 0L; |
|
| 512 GSList *l; |
|
| 513 |
|
| 514 yd = gc->proto_data; |
|
| 515 |
|
| 516 for (l = pkt->hash; l; l = l->next) { |
|
| 517 struct yahoo_pair *pair = l->data; |
|
| 518 |
|
| 519 if (pair->key == 4) |
|
| 520 from = pair->value; |
|
| 521 if (pair->key == 5) |
|
| 522 to = pair->value; |
|
| 523 if (pair->key == 14) |
|
| 524 msg = pair->value; |
|
| 525 if (pair->key == 20) |
|
| 526 url = pair->value; |
|
| 527 if (pair->key == 38) |
|
| 528 expires = strtol(pair->value, NULL, 10); |
|
| 529 if (pair->key == 27) |
|
| 530 filename = pair->value; |
|
| 531 if (pair->key == 28) |
|
| 532 filesize = atol(pair->value); |
|
| 533 if (pair->key == 49) |
|
| 534 service = pair->value; |
|
| 535 if (pair->key == 63) |
|
| 536 imv = pair->value; |
|
| 537 } |
|
| 538 |
|
| 539 /* |
|
| 540 * The remote user has changed their IMVironment. We |
|
| 541 * record it for later use. |
|
| 542 */ |
|
| 543 if (from && imv && service && (strcmp("IMVIRONMENT", service) == 0)) { |
|
| 544 g_hash_table_replace(yd->imvironments, g_strdup(from), g_strdup(imv)); |
|
| 545 return; |
|
| 546 } |
|
| 547 |
|
| 548 if (pkt->service == YAHOO_SERVICE_P2PFILEXFER) { |
|
| 549 if (service && (strcmp("FILEXFER", service) != 0)) { |
|
| 550 gaim_debug_misc("yahoo", "unhandled service 0x%02x\n", pkt->service); |
|
| 551 return; |
|
| 552 } |
|
| 553 } |
|
| 554 |
|
| 555 if (msg) { |
|
| 556 char *tmp; |
|
| 557 tmp = strchr(msg, '\006'); |
|
| 558 if (tmp) |
|
| 559 *tmp = '\0'; |
|
| 560 } |
|
| 561 |
|
| 562 if (!url || !from) |
|
| 563 return; |
|
| 564 |
|
| 565 /* Setup the Yahoo-specific file transfer data */ |
|
| 566 xfer_data = g_new0(struct yahoo_xfer_data, 1); |
|
| 567 xfer_data->gc = gc; |
|
| 568 if (!gaim_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL)) { |
|
| 569 g_free(xfer_data); |
|
| 570 return; |
|
| 571 } |
|
| 572 |
|
| 573 gaim_debug_misc("yahoo_filexfer", "Host is %s, port is %d, path is %s, and the full url was %s.\n", |
|
| 574 xfer_data->host, xfer_data->port, xfer_data->path, url); |
|
| 575 |
|
| 576 /* Build the file transfer handle. */ |
|
| 577 xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, from); |
|
| 578 xfer->data = xfer_data; |
|
| 579 |
|
| 580 /* Set the info about the incoming file. */ |
|
| 581 if (filename) { |
|
| 582 char *utf8_filename = yahoo_string_decode(gc, filename, TRUE); |
|
| 583 gaim_xfer_set_filename(xfer, utf8_filename); |
|
| 584 g_free(utf8_filename); |
|
| 585 } else { |
|
| 586 gchar *start, *end; |
|
| 587 start = g_strrstr(xfer_data->path, "/"); |
|
| 588 if (start) |
|
| 589 start++; |
|
| 590 end = g_strrstr(xfer_data->path, "?"); |
|
| 591 if (start && *start && end) { |
|
| 592 char *utf8_filename; |
|
| 593 filename = g_strndup(start, end - start); |
|
| 594 utf8_filename = yahoo_string_decode(gc, filename, TRUE); |
|
| 595 g_free(filename); |
|
| 596 gaim_xfer_set_filename(xfer, utf8_filename); |
|
| 597 g_free(utf8_filename); |
|
| 598 filename = NULL; |
|
| 599 } |
|
| 600 } |
|
| 601 |
|
| 602 gaim_xfer_set_size(xfer, filesize); |
|
| 603 |
|
| 604 /* Setup our I/O op functions */ |
|
| 605 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); |
|
| 606 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); |
|
| 607 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); |
|
| 608 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); |
|
| 609 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); |
|
| 610 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); |
|
| 611 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); |
|
| 612 |
|
| 613 /* Now perform the request */ |
|
| 614 gaim_xfer_request(xfer); |
|
| 615 } |
|
| 616 |
|
| 617 GaimXfer *yahoo_new_xfer(GaimConnection *gc, const char *who) |
|
| 618 { |
|
| 619 GaimXfer *xfer; |
|
| 620 struct yahoo_xfer_data *xfer_data; |
|
| 621 |
|
| 622 g_return_val_if_fail(who != NULL, NULL); |
|
| 623 |
|
| 624 xfer_data = g_new0(struct yahoo_xfer_data, 1); |
|
| 625 xfer_data->gc = gc; |
|
| 626 |
|
| 627 /* Build the file transfer handle. */ |
|
| 628 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); |
|
| 629 xfer->data = xfer_data; |
|
| 630 |
|
| 631 /* Setup our I/O op functions */ |
|
| 632 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); |
|
| 633 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); |
|
| 634 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); |
|
| 635 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); |
|
| 636 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); |
|
| 637 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); |
|
| 638 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); |
|
| 639 |
|
| 640 return xfer; |
|
| 641 } |
|
| 642 |
|
| 643 void yahoo_send_file(GaimConnection *gc, const char *who, const char *file) |
|
| 644 { |
|
| 645 GaimXfer *xfer = yahoo_new_xfer(gc, who); |
|
| 646 |
|
| 647 g_return_if_fail(xfer != NULL); |
|
| 648 |
|
| 649 /* Now perform the request */ |
|
| 650 if (file) |
|
| 651 gaim_xfer_request_accepted(xfer, file); |
|
| 652 else |
|
| 653 gaim_xfer_request(xfer); |
|
| 654 } |
|