Mercurial > pidgin
annotate src/protocols/yahoo/yahoo_filexfer.c @ 8231:f50c059b6384
[gaim-migrate @ 8954]
This is Tim Ringenbach's patch to move some IP-related functions into the
new gaim_network namespace, improve the local IP checking functionality by
opening a socket, change some prefs, and add the ability to modify these
prefs in the UI. Some ft.c bugs were fixed, and OSCAR, Jabber and Yahoo
were updated to reflect the changes. The DCC SEND portion of this patch was
not committed, as per his request (unless I misunderstood? :)
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Thu, 12 Feb 2004 00:36:55 +0000 |
parents | fa6395637e2c |
children | ab35a0bec13a |
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) { | |
198 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
199 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
200 yahoo_sendfile_connected, xfer) == -1) | |
201 { | |
202 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
7827 | 203 _("Unable to establish file descriptor.")); |
7651 | 204 gaim_xfer_cancel_remote(xfer); |
205 } | |
206 } else { | |
207 xfer->fd = gaim_proxy_connect(account, xfer_data->host, xfer_data->port, | |
208 yahoo_receivefile_connected, xfer); | |
209 if (xfer->fd == -1) { | |
210 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
211 _("Unable to establish file descriptor.")); | |
212 gaim_xfer_cancel_remote(xfer); | |
213 } | |
214 } | |
215 } | |
216 | |
217 static void yahoo_xfer_start(GaimXfer *xfer) | |
218 { | |
219 /* We don't need to do anything here, do we? */ | |
220 } | |
221 | |
222 static void yahoo_xfer_end(GaimXfer *xfer) | |
223 { | |
224 GaimAccount *account; | |
225 struct yahoo_xfer_data *xfer_data; | |
226 | |
227 account = gaim_xfer_get_account(xfer); | |
228 xfer_data = xfer->data; | |
229 | |
230 | |
231 if (xfer_data) | |
232 yahoo_xfer_data_free(xfer_data); | |
233 xfer->data = NULL; | |
234 | |
235 } | |
236 | |
237 guint calculate_length(const gchar *l, size_t len) | |
238 { | |
239 int i; | |
240 | |
241 for (i = 0; i < len; i++) { | |
242 if (!g_ascii_isdigit(l[i])) | |
243 continue; | |
244 return strtol(l + i, NULL, 10); | |
245 } | |
246 return 0; | |
247 } | |
248 | |
249 | |
8231
f50c059b6384
[gaim-migrate @ 8954]
Christian Hammond <chipx86@chipx86.com>
parents:
8046
diff
changeset
|
250 ssize_t yahoo_xfer_read(char **buffer, GaimXfer *xfer) |
7651 | 251 { |
7710 | 252 gchar buf[4096]; |
7682 | 253 ssize_t len; |
7651 | 254 gchar *start = NULL; |
255 gchar *length; | |
256 gchar *end; | |
7710 | 257 int filelen; |
7651 | 258 struct yahoo_xfer_data *xd = xfer->data; |
259 | |
260 if (gaim_xfer_get_type(xfer) != GAIM_XFER_RECEIVE) { | |
261 return 0; | |
262 } | |
263 | |
264 len = read(xfer->fd, buf, sizeof(buf)); | |
265 | |
7682 | 266 if (len <= 0) { |
7710 | 267 if ((gaim_xfer_get_size(xfer) > 0) && |
268 (gaim_xfer_get_bytes_sent(xfer) >= gaim_xfer_get_size(xfer))) | |
7682 | 269 gaim_xfer_set_completed(xfer, TRUE); |
7651 | 270 else |
271 gaim_xfer_cancel_remote(xfer); | |
272 return 0; | |
273 } | |
274 | |
275 | |
276 if (!xd->started) { | |
277 xd->rxqueue = g_realloc(xd->rxqueue, len + xd->rxlen); | |
278 memcpy(xd->rxqueue + xd->rxlen, buf, len); | |
279 xd->rxlen += len; | |
280 | |
281 length = g_strstr_len(xd->rxqueue, len, "Content-length:"); | |
282 if (length) { | |
283 end = g_strstr_len(length, length - xd->rxqueue, "\r\n"); | |
284 if (!end) | |
285 return 0; | |
7710 | 286 if ((filelen = calculate_length(length, len - (length - xd->rxqueue)))) |
287 gaim_xfer_set_size(xfer, filelen); | |
7651 | 288 } |
289 start = g_strstr_len(xd->rxqueue, len, "\r\n\r\n"); | |
290 if (start) | |
291 start += 4; | |
292 if (!start || start > (xd->rxqueue + len)) | |
293 return 0; | |
294 xd->started = TRUE; | |
295 | |
296 len -= (start - xd->rxqueue); | |
297 | |
298 *buffer = g_malloc(len); | |
299 memcpy(*buffer, start, len); | |
300 g_free(xd->rxqueue); | |
301 xd->rxqueue = NULL; | |
302 xd->rxlen = 0; | |
303 } else { | |
304 *buffer = g_malloc(len); | |
305 memcpy(*buffer, buf, len); | |
306 } | |
307 | |
308 return len; | |
309 } | |
310 | |
8231
f50c059b6384
[gaim-migrate @ 8954]
Christian Hammond <chipx86@chipx86.com>
parents:
8046
diff
changeset
|
311 ssize_t yahoo_xfer_write(const char *buffer, size_t size, GaimXfer *xfer) |
7651 | 312 { |
7710 | 313 ssize_t len; |
7651 | 314 struct yahoo_xfer_data *xd = xfer->data; |
315 | |
316 if (!xd) | |
317 return 0; | |
318 | |
319 if (gaim_xfer_get_type(xfer) != GAIM_XFER_SEND) { | |
320 return 0; | |
321 } | |
322 | |
323 len = write(xfer->fd, buffer, size); | |
324 | |
7710 | 325 if (len == -1) { |
326 if (gaim_xfer_get_bytes_sent(xfer) >= gaim_xfer_get_size(xfer)) | |
327 gaim_xfer_set_completed(xfer, TRUE); | |
328 if ((errno != EAGAIN) && (errno != EINTR)) | |
329 gaim_xfer_cancel_remote(xfer); | |
330 return 0; | |
331 } | |
332 | |
333 if ((gaim_xfer_get_bytes_sent(xfer) + len) >= gaim_xfer_get_size(xfer)) | |
7651 | 334 gaim_xfer_set_completed(xfer, TRUE); |
335 | |
336 return len; | |
337 } | |
338 | |
339 static void yahoo_xfer_cancel_send(GaimXfer *xfer) | |
340 { | |
341 GaimAccount *account; | |
342 struct yahoo_xfer_data *xfer_data; | |
343 | |
344 xfer_data = xfer->data; | |
345 account = gaim_xfer_get_account(xfer); | |
346 | |
347 if (xfer_data) | |
348 yahoo_xfer_data_free(xfer_data); | |
349 xfer->data = NULL; | |
350 } | |
351 | |
352 static void yahoo_xfer_cancel_recv(GaimXfer *xfer) | |
353 { | |
354 GaimAccount *account; | |
355 struct yahoo_xfer_data *xfer_data; | |
356 | |
357 account = gaim_xfer_get_account(xfer); | |
358 xfer_data = xfer->data; | |
359 | |
360 if (xfer_data) | |
361 yahoo_xfer_data_free(xfer_data); | |
362 xfer->data = NULL; | |
363 } | |
364 | |
365 void yahoo_process_filetransfer(GaimConnection *gc, struct yahoo_packet *pkt) | |
366 { | |
367 char *from = NULL; | |
368 char *to = NULL; | |
369 char *msg = NULL; | |
370 char *url = NULL; | |
371 long expires = 0; | |
372 GaimXfer *xfer; | |
373 struct yahoo_xfer_data *xfer_data; | |
374 | |
375 char *service = NULL; | |
376 | |
377 char *filename = NULL; | |
378 unsigned long filesize = 0L; | |
379 | |
380 GSList *l; | |
381 | |
382 for (l = pkt->hash; l; l = l->next) { | |
383 struct yahoo_pair *pair = l->data; | |
384 | |
385 if (pair->key == 4) | |
386 from = pair->value; | |
387 if (pair->key == 5) | |
388 to = pair->value; | |
389 if (pair->key == 14) | |
390 msg = pair->value; | |
391 if (pair->key == 20) | |
392 url = pair->value; | |
393 if (pair->key == 38) | |
394 expires = strtol(pair->value, NULL, 10); | |
395 | |
396 if (pair->key == 27) | |
397 filename = pair->value; | |
398 if (pair->key == 28) | |
399 filesize = atol(pair->value); | |
400 | |
401 if (pair->key == 49) | |
402 service = pair->value; | |
403 } | |
404 | |
405 if (pkt->service == YAHOO_SERVICE_P2PFILEXFER) { | |
406 if (strcmp("FILEXFER", service) != 0) { | |
407 gaim_debug_misc("yahoo", "unhandled service 0x%02x", pkt->service); | |
408 return; | |
409 } | |
410 } | |
411 | |
412 if (msg) { | |
413 char *tmp; | |
414 tmp = strchr(msg, '\006'); | |
415 if (tmp) | |
416 *tmp = '\0'; | |
417 } | |
418 | |
419 if (!url || !from) | |
420 return; | |
421 | |
422 | |
423 /* Setup the Yahoo-specific file transfer data */ | |
424 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
425 xfer_data->gc = gc; | |
426 if (!gaim_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path))) { | |
427 g_free(xfer_data); | |
428 return; | |
429 } | |
430 | |
431 gaim_debug_misc("yahoo_filexfer", "Host is %s, port is %d, path is %s, and the full url was %s.\n", | |
432 xfer_data->host, xfer_data->port, xfer_data->path, url); | |
433 | |
434 /* Build the file transfer handle. */ | |
435 xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, from); | |
436 xfer->data = xfer_data; | |
437 | |
438 /* Set the info about the incoming file. */ | |
439 if (filename) | |
440 gaim_xfer_set_filename(xfer, filename); | |
441 else { | |
442 gchar *start, *end; | |
443 start = g_strrstr(xfer_data->path, "/"); | |
444 if (start) | |
445 start++; | |
446 end = g_strrstr(xfer_data->path, "?"); | |
447 if (start && *start && end) { | |
448 filename = g_strndup(start, end - start); | |
449 gaim_xfer_set_filename(xfer, filename); | |
450 g_free(filename); | |
451 filename = NULL; | |
452 } | |
453 } | |
454 | |
455 gaim_xfer_set_size(xfer, filesize); | |
456 | |
457 /* Setup our I/O op functions */ | |
458 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
459 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
460 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
461 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
462 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
463 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
464 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
465 | |
466 /* Now perform the request */ | |
467 gaim_xfer_request(xfer); | |
468 } | |
469 | |
470 void yahoo_ask_send_file(GaimConnection *gc, const char *who) | |
471 { | |
472 GaimXfer *xfer; | |
473 struct yahoo_xfer_data *xfer_data; | |
474 | |
475 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
476 xfer_data->gc = gc; | |
477 | |
478 | |
479 /* Build the file transfer handle. */ | |
480 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); | |
481 xfer->data = xfer_data; | |
482 | |
483 /* Setup our I/O op functions */ | |
484 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
485 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
486 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
487 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
488 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
489 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
490 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
491 | |
492 /* Now perform the request */ | |
493 gaim_xfer_request(xfer); | |
494 } | |
495 | |
496 void yahoo_send_file(GaimConnection *gc, const char *who, const char *file) | |
497 { | |
498 GaimXfer *xfer; | |
499 struct yahoo_xfer_data *xfer_data; | |
500 | |
501 if (!who || !file) | |
502 return; | |
503 | |
504 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
505 xfer_data->gc = gc; | |
506 | |
507 | |
508 /* Build the file transfer handle. */ | |
509 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); | |
510 xfer->data = xfer_data; | |
511 | |
512 /* Setup our I/O op functions */ | |
513 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
514 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
515 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
516 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
517 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
518 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
519 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
520 | |
521 /* Now perform the request */ | |
7805 | 522 gaim_xfer_request_accepted(xfer, file); |
7651 | 523 } |