Mercurial > pidgin.yaz
annotate src/protocols/yahoo/yahoo_filexfer.c @ 9164:76125b842b23
[gaim-migrate @ 9949]
This is proper yahoo japan support. Technically it worked before, but
you had to know the yahoo japan server, and typing in nonascii didn't work.
The account options are kind of ugly. Eventually Chip is going to replace
the check box with something more like a dropdown thingy, that automaticly
hides the settings that aren't used (Pager Host vs. Japan Pager Host, etc)
But it's not too bad now. And I think I orignally wrote this patch for
0.64 or something, so I got tired of waiting.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Wed, 02 Jun 2004 03:02:50 +0000 |
parents | ab35a0bec13a |
children | 9171e528d7e5 |
rev | line source |
---|---|
7651 | 1 /* |
2 * @file yahoo_filexfer.c Yahoo Filetransfer | |
3 * | |
8046 | 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. | |
7651 | 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_filexfer.h" | |
32 | |
33 | |
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 *rxqueue; | |
43 guint rxlen; | |
44 }; | |
45 | |
46 static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd) | |
47 { | |
48 if (xd->host) | |
49 g_free(xd->host); | |
50 if (xd->path) | |
51 g_free(xd->path); | |
52 g_free(xd); | |
53 } | |
54 | |
55 static void yahoo_receivefile_connected(gpointer data, gint source, GaimInputCondition condition) | |
56 { | |
57 GaimXfer *xfer; | |
58 struct yahoo_xfer_data *xd; | |
59 gchar *buf; | |
60 | |
61 gaim_debug(GAIM_DEBUG_INFO, "yahoo", | |
62 "AAA - in yahoo_receivefile_connected\n"); | |
63 if (!(xfer = data)) | |
64 return; | |
65 if (!(xd = xfer->data)) | |
66 return; | |
67 if (source < 0) { | |
68 gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to connect.")); | |
7805 | 69 gaim_xfer_cancel_remote(xfer); |
7651 | 70 return; |
71 } | |
72 | |
73 xfer->fd = source; | |
74 gaim_xfer_start(xfer, source, NULL, 0); | |
75 | |
76 buf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", xd->path, xd->host); | |
77 write(xfer->fd, buf, strlen(buf)); | |
78 g_free(buf); | |
79 | |
80 return; | |
81 } | |
82 | |
83 static int yahoo_send_packet_special(int fd, struct yahoo_packet *pkt, int pad) | |
84 { | |
85 int pktlen = yahoo_packet_length(pkt); | |
86 int len = YAHOO_PACKET_HDRLEN + pktlen; | |
87 int ret; | |
88 | |
89 guchar *data; | |
90 int pos = 0; | |
91 | |
92 if (fd < 0) | |
93 return -1; | |
94 | |
95 data = g_malloc0(len + 1); | |
96 | |
97 memcpy(data + pos, "YMSG", 4); pos += 4; | |
98 pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); | |
99 pos += yahoo_put16(data + pos, 0x0000); | |
100 pos += yahoo_put16(data + pos, pktlen + pad); | |
101 pos += yahoo_put16(data + pos, pkt->service); | |
102 pos += yahoo_put32(data + pos, pkt->status); | |
103 pos += yahoo_put32(data + pos, pkt->id); | |
104 | |
105 yahoo_packet_write(pkt, data + pos); | |
106 | |
107 ret = write(fd, data, len); | |
108 g_free(data); | |
109 | |
110 return ret; | |
111 } | |
112 | |
113 static void yahoo_sendfile_connected(gpointer data, gint source, GaimInputCondition condition) | |
114 { | |
115 GaimXfer *xfer; | |
116 struct yahoo_xfer_data *xd; | |
117 struct yahoo_packet *pkt; | |
118 gchar *size, *post, *buf; | |
119 int content_length; | |
120 GaimConnection *gc; | |
121 GaimAccount *account; | |
122 struct yahoo_data *yd; | |
7805 | 123 char *filename; |
7651 | 124 |
125 gaim_debug(GAIM_DEBUG_INFO, "yahoo", | |
126 "AAA - in yahoo_sendfile_connected\n"); | |
127 if (!(xfer = data)) | |
128 return; | |
129 if (!(xd = xfer->data)) | |
130 return; | |
131 | |
132 gc = xd->gc; | |
133 account = gaim_connection_get_account(gc); | |
134 yd = gc->proto_data; | |
135 | |
136 | |
137 | |
138 if (source < 0) { | |
139 gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to connect.")); | |
7805 | 140 gaim_xfer_cancel_remote(xfer); |
7651 | 141 return; |
142 } | |
143 | |
144 xfer->fd = source; | |
145 gaim_xfer_start(xfer, source, NULL, 0); | |
146 | |
147 | |
148 pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id); | |
149 | |
150 size = g_strdup_printf("%d", gaim_xfer_get_size(xfer)); | |
151 | |
152 yahoo_packet_hash(pkt, 0, gaim_connection_get_display_name(gc)); | |
153 yahoo_packet_hash(pkt, 5, xfer->who); | |
154 yahoo_packet_hash(pkt, 14, ""); | |
7805 | 155 filename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); |
156 yahoo_packet_hash(pkt, 27, filename); | |
7651 | 157 yahoo_packet_hash(pkt, 28, size); |
158 | |
159 content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); | |
160 | |
161 buf = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t); | |
162 | |
163 post = g_strdup_printf("POST /notifyft HTTP/1.0\r\n" | |
164 "Content-length: %d\r\n" | |
165 "Host: %s:%d\r\n" | |
166 "Cookie: %s\r\n" | |
167 "\r\n", | |
168 content_length + 4 + gaim_xfer_get_size(xfer), | |
169 gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
170 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
171 buf); | |
172 write(xfer->fd, post, strlen(post)); | |
173 | |
174 yahoo_send_packet_special(xfer->fd, pkt, 8); | |
175 yahoo_packet_free(pkt); | |
176 | |
177 write(xfer->fd, "29\xc0\x80", 4); | |
178 | |
179 g_free(size); | |
180 g_free(post); | |
181 g_free(buf); | |
7805 | 182 g_free(filename); |
7651 | 183 } |
184 | |
185 static void yahoo_xfer_init(GaimXfer *xfer) | |
186 { | |
187 struct yahoo_xfer_data *xfer_data; | |
188 GaimConnection *gc; | |
189 GaimAccount *account; | |
7827 | 190 struct yahoo_data *yd; |
7651 | 191 |
192 xfer_data = xfer->data; | |
193 gc = xfer_data->gc; | |
7827 | 194 yd = gc->proto_data; |
7651 | 195 account = gaim_connection_get_account(gc); |
196 | |
197 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { | |
8282 | 198 if (gaim_xfer_get_size(xfer) >= 1048577) { |
7651 | 199 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), |
8282 | 200 _("Gaim cannot send files over Yahoo! that are bigger than " |
201 "One Megabyte (1,048,576 bytes).")); | |
202 gaim_xfer_cancel_local(xfer); | |
203 } else { | |
9164 | 204 if (yd->jp) { |
205 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xferjp_host", YAHOOJP_XFER_HOST), | |
206 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
207 yahoo_sendfile_connected, xfer) == -1) | |
208 { | |
209 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
210 _("Unable to establish file descriptor.")); | |
211 gaim_xfer_cancel_remote(xfer); | |
212 } | |
213 } else { | |
214 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
215 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
216 yahoo_sendfile_connected, xfer) == -1) | |
217 { | |
218 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
219 _("Unable to establish file descriptor.")); | |
220 gaim_xfer_cancel_remote(xfer); | |
221 } | |
8282 | 222 } |
7651 | 223 } |
224 } else { | |
225 xfer->fd = gaim_proxy_connect(account, xfer_data->host, xfer_data->port, | |
226 yahoo_receivefile_connected, xfer); | |
227 if (xfer->fd == -1) { | |
228 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
229 _("Unable to establish file descriptor.")); | |
230 gaim_xfer_cancel_remote(xfer); | |
231 } | |
232 } | |
233 } | |
234 | |
235 static void yahoo_xfer_start(GaimXfer *xfer) | |
236 { | |
237 /* We don't need to do anything here, do we? */ | |
238 } | |
239 | |
240 static void yahoo_xfer_end(GaimXfer *xfer) | |
241 { | |
242 GaimAccount *account; | |
243 struct yahoo_xfer_data *xfer_data; | |
244 | |
245 account = gaim_xfer_get_account(xfer); | |
246 xfer_data = xfer->data; | |
247 | |
248 | |
249 if (xfer_data) | |
250 yahoo_xfer_data_free(xfer_data); | |
251 xfer->data = NULL; | |
252 | |
253 } | |
254 | |
255 guint calculate_length(const gchar *l, size_t len) | |
256 { | |
257 int i; | |
258 | |
259 for (i = 0; i < len; i++) { | |
260 if (!g_ascii_isdigit(l[i])) | |
261 continue; | |
262 return strtol(l + i, NULL, 10); | |
263 } | |
264 return 0; | |
265 } | |
266 | |
267 | |
8231
f50c059b6384
[gaim-migrate @ 8954]
Christian Hammond <chipx86@chipx86.com>
parents:
8046
diff
changeset
|
268 ssize_t yahoo_xfer_read(char **buffer, GaimXfer *xfer) |
7651 | 269 { |
7710 | 270 gchar buf[4096]; |
7682 | 271 ssize_t len; |
7651 | 272 gchar *start = NULL; |
273 gchar *length; | |
274 gchar *end; | |
7710 | 275 int filelen; |
7651 | 276 struct yahoo_xfer_data *xd = xfer->data; |
277 | |
278 if (gaim_xfer_get_type(xfer) != GAIM_XFER_RECEIVE) { | |
279 return 0; | |
280 } | |
281 | |
282 len = read(xfer->fd, buf, sizeof(buf)); | |
283 | |
7682 | 284 if (len <= 0) { |
7710 | 285 if ((gaim_xfer_get_size(xfer) > 0) && |
286 (gaim_xfer_get_bytes_sent(xfer) >= gaim_xfer_get_size(xfer))) | |
7682 | 287 gaim_xfer_set_completed(xfer, TRUE); |
7651 | 288 else |
289 gaim_xfer_cancel_remote(xfer); | |
290 return 0; | |
291 } | |
292 | |
293 | |
294 if (!xd->started) { | |
295 xd->rxqueue = g_realloc(xd->rxqueue, len + xd->rxlen); | |
296 memcpy(xd->rxqueue + xd->rxlen, buf, len); | |
297 xd->rxlen += len; | |
298 | |
299 length = g_strstr_len(xd->rxqueue, len, "Content-length:"); | |
300 if (length) { | |
301 end = g_strstr_len(length, length - xd->rxqueue, "\r\n"); | |
302 if (!end) | |
303 return 0; | |
7710 | 304 if ((filelen = calculate_length(length, len - (length - xd->rxqueue)))) |
305 gaim_xfer_set_size(xfer, filelen); | |
7651 | 306 } |
307 start = g_strstr_len(xd->rxqueue, len, "\r\n\r\n"); | |
308 if (start) | |
309 start += 4; | |
310 if (!start || start > (xd->rxqueue + len)) | |
311 return 0; | |
312 xd->started = TRUE; | |
313 | |
314 len -= (start - xd->rxqueue); | |
315 | |
316 *buffer = g_malloc(len); | |
317 memcpy(*buffer, start, len); | |
318 g_free(xd->rxqueue); | |
319 xd->rxqueue = NULL; | |
320 xd->rxlen = 0; | |
321 } else { | |
322 *buffer = g_malloc(len); | |
323 memcpy(*buffer, buf, len); | |
324 } | |
325 | |
326 return len; | |
327 } | |
328 | |
8231
f50c059b6384
[gaim-migrate @ 8954]
Christian Hammond <chipx86@chipx86.com>
parents:
8046
diff
changeset
|
329 ssize_t yahoo_xfer_write(const char *buffer, size_t size, GaimXfer *xfer) |
7651 | 330 { |
7710 | 331 ssize_t len; |
7651 | 332 struct yahoo_xfer_data *xd = xfer->data; |
333 | |
334 if (!xd) | |
335 return 0; | |
336 | |
337 if (gaim_xfer_get_type(xfer) != GAIM_XFER_SEND) { | |
338 return 0; | |
339 } | |
340 | |
341 len = write(xfer->fd, buffer, size); | |
342 | |
7710 | 343 if (len == -1) { |
344 if (gaim_xfer_get_bytes_sent(xfer) >= gaim_xfer_get_size(xfer)) | |
345 gaim_xfer_set_completed(xfer, TRUE); | |
346 if ((errno != EAGAIN) && (errno != EINTR)) | |
347 gaim_xfer_cancel_remote(xfer); | |
348 return 0; | |
349 } | |
350 | |
351 if ((gaim_xfer_get_bytes_sent(xfer) + len) >= gaim_xfer_get_size(xfer)) | |
7651 | 352 gaim_xfer_set_completed(xfer, TRUE); |
353 | |
354 return len; | |
355 } | |
356 | |
357 static void yahoo_xfer_cancel_send(GaimXfer *xfer) | |
358 { | |
359 GaimAccount *account; | |
360 struct yahoo_xfer_data *xfer_data; | |
361 | |
362 xfer_data = xfer->data; | |
363 account = gaim_xfer_get_account(xfer); | |
364 | |
365 if (xfer_data) | |
366 yahoo_xfer_data_free(xfer_data); | |
367 xfer->data = NULL; | |
368 } | |
369 | |
370 static void yahoo_xfer_cancel_recv(GaimXfer *xfer) | |
371 { | |
372 GaimAccount *account; | |
373 struct yahoo_xfer_data *xfer_data; | |
374 | |
375 account = gaim_xfer_get_account(xfer); | |
376 xfer_data = xfer->data; | |
377 | |
378 if (xfer_data) | |
379 yahoo_xfer_data_free(xfer_data); | |
380 xfer->data = NULL; | |
381 } | |
382 | |
383 void yahoo_process_filetransfer(GaimConnection *gc, struct yahoo_packet *pkt) | |
384 { | |
385 char *from = NULL; | |
386 char *to = NULL; | |
387 char *msg = NULL; | |
388 char *url = NULL; | |
389 long expires = 0; | |
390 GaimXfer *xfer; | |
391 struct yahoo_xfer_data *xfer_data; | |
392 | |
393 char *service = NULL; | |
394 | |
395 char *filename = NULL; | |
396 unsigned long filesize = 0L; | |
397 | |
398 GSList *l; | |
399 | |
400 for (l = pkt->hash; l; l = l->next) { | |
401 struct yahoo_pair *pair = l->data; | |
402 | |
403 if (pair->key == 4) | |
404 from = pair->value; | |
405 if (pair->key == 5) | |
406 to = pair->value; | |
407 if (pair->key == 14) | |
408 msg = pair->value; | |
409 if (pair->key == 20) | |
410 url = pair->value; | |
411 if (pair->key == 38) | |
412 expires = strtol(pair->value, NULL, 10); | |
413 | |
414 if (pair->key == 27) | |
415 filename = pair->value; | |
416 if (pair->key == 28) | |
417 filesize = atol(pair->value); | |
418 | |
419 if (pair->key == 49) | |
420 service = pair->value; | |
421 } | |
422 | |
423 if (pkt->service == YAHOO_SERVICE_P2PFILEXFER) { | |
424 if (strcmp("FILEXFER", service) != 0) { | |
425 gaim_debug_misc("yahoo", "unhandled service 0x%02x", pkt->service); | |
426 return; | |
427 } | |
428 } | |
429 | |
430 if (msg) { | |
431 char *tmp; | |
432 tmp = strchr(msg, '\006'); | |
433 if (tmp) | |
434 *tmp = '\0'; | |
435 } | |
436 | |
437 if (!url || !from) | |
438 return; | |
439 | |
440 | |
441 /* Setup the Yahoo-specific file transfer data */ | |
442 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
443 xfer_data->gc = gc; | |
444 if (!gaim_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path))) { | |
445 g_free(xfer_data); | |
446 return; | |
447 } | |
448 | |
449 gaim_debug_misc("yahoo_filexfer", "Host is %s, port is %d, path is %s, and the full url was %s.\n", | |
450 xfer_data->host, xfer_data->port, xfer_data->path, url); | |
451 | |
452 /* Build the file transfer handle. */ | |
453 xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, from); | |
454 xfer->data = xfer_data; | |
455 | |
456 /* Set the info about the incoming file. */ | |
457 if (filename) | |
458 gaim_xfer_set_filename(xfer, filename); | |
459 else { | |
460 gchar *start, *end; | |
461 start = g_strrstr(xfer_data->path, "/"); | |
462 if (start) | |
463 start++; | |
464 end = g_strrstr(xfer_data->path, "?"); | |
465 if (start && *start && end) { | |
466 filename = g_strndup(start, end - start); | |
467 gaim_xfer_set_filename(xfer, filename); | |
468 g_free(filename); | |
469 filename = NULL; | |
470 } | |
471 } | |
472 | |
473 gaim_xfer_set_size(xfer, filesize); | |
474 | |
475 /* Setup our I/O op functions */ | |
476 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
477 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
478 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
479 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
480 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
481 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
482 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
483 | |
484 /* Now perform the request */ | |
485 gaim_xfer_request(xfer); | |
486 } | |
487 | |
488 void yahoo_ask_send_file(GaimConnection *gc, const char *who) | |
489 { | |
490 GaimXfer *xfer; | |
491 struct yahoo_xfer_data *xfer_data; | |
492 | |
493 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
494 xfer_data->gc = gc; | |
495 | |
496 | |
497 /* Build the file transfer handle. */ | |
498 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); | |
499 xfer->data = xfer_data; | |
500 | |
501 /* Setup our I/O op functions */ | |
502 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
503 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
504 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
505 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
506 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
507 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
508 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
509 | |
510 /* Now perform the request */ | |
511 gaim_xfer_request(xfer); | |
512 } | |
513 | |
514 void yahoo_send_file(GaimConnection *gc, const char *who, const char *file) | |
515 { | |
516 GaimXfer *xfer; | |
517 struct yahoo_xfer_data *xfer_data; | |
518 | |
519 if (!who || !file) | |
520 return; | |
521 | |
522 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
523 xfer_data->gc = gc; | |
524 | |
525 | |
526 /* Build the file transfer handle. */ | |
527 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); | |
528 xfer->data = xfer_data; | |
529 | |
530 /* Setup our I/O op functions */ | |
531 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
532 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
533 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
534 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
535 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
536 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
537 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
538 | |
539 /* Now perform the request */ | |
7805 | 540 gaim_xfer_request_accepted(xfer, file); |
7651 | 541 } |