Mercurial > pidgin
comparison src/protocols/yahoo/yahoo_filexfer.c @ 7651:580bd39219a2
[gaim-migrate @ 8295]
Tim Ringenbach (marv_sf) " Because Sean asked nicely." implemented yahoo
file transfer for the masses. of this second version of the patch, he adds:
"Here's a new diff, that adds a right click send file menu
like oscar, and should still compile without those new
callbacks that got reverted."
i'm using (and perhaps abusing) the permission to commit yahoo patches from
him that i obtained in previous releases :-)
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Sat, 29 Nov 2003 03:30:01 +0000 |
parents | |
children | d9caaddaa56d |
comparison
equal
deleted
inserted
replaced
7650:6db061321ec4 | 7651:580bd39219a2 |
---|---|
1 /* | |
2 * @file yahoo_filexfer.c Yahoo Filetransfer | |
3 * | |
4 * | |
5 * Copyright (C) 2003 Timothy T Ringenbach <omarvo@hotmail.com> | |
6 * Some code borrowed from MSN and copyright (C) 2003 Christian Hammond <chipx86@gnupdate.org> | |
7 * Some code copyright (C) 2002, Philip S Tellis <philip . tellis AT gmx . net> | |
8 * | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 */ | |
24 | |
25 #include "prpl.h" | |
26 #include "internal.h" | |
27 #include "util.h" | |
28 #include "debug.h" | |
29 #include "notify.h" | |
30 #include "proxy.h" | |
31 #include "ft.h" | |
32 #include "yahoo.h" | |
33 #include "yahoo_filexfer.h" | |
34 | |
35 | |
36 | |
37 struct yahoo_xfer_data { | |
38 gchar *host; | |
39 gchar *path; | |
40 int port; | |
41 GaimConnection *gc; | |
42 long expires; | |
43 gboolean started; | |
44 guint length; | |
45 gchar *rxqueue; | |
46 guint rxlen; | |
47 guint bytes_in; | |
48 }; | |
49 | |
50 static void yahoo_xfer_data_free(struct yahoo_xfer_data *xd) | |
51 { | |
52 if (xd->host) | |
53 g_free(xd->host); | |
54 if (xd->path) | |
55 g_free(xd->path); | |
56 g_free(xd); | |
57 } | |
58 | |
59 static void yahoo_receivefile_connected(gpointer data, gint source, GaimInputCondition condition) | |
60 { | |
61 GaimXfer *xfer; | |
62 struct yahoo_xfer_data *xd; | |
63 gchar *buf; | |
64 | |
65 gaim_debug(GAIM_DEBUG_INFO, "yahoo", | |
66 "AAA - in yahoo_receivefile_connected\n"); | |
67 if (!(xfer = data)) | |
68 return; | |
69 if (!(xd = xfer->data)) | |
70 return; | |
71 if (source < 0) { | |
72 gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to connect.")); | |
73 gaim_xfer_end(xfer); | |
74 return; | |
75 } | |
76 | |
77 xfer->fd = source; | |
78 gaim_xfer_start(xfer, source, NULL, 0); | |
79 | |
80 buf = g_strdup_printf("GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n", xd->path, xd->host); | |
81 write(xfer->fd, buf, strlen(buf)); | |
82 g_free(buf); | |
83 | |
84 return; | |
85 } | |
86 | |
87 static int yahoo_send_packet_special(int fd, struct yahoo_packet *pkt, int pad) | |
88 { | |
89 int pktlen = yahoo_packet_length(pkt); | |
90 int len = YAHOO_PACKET_HDRLEN + pktlen; | |
91 int ret; | |
92 | |
93 guchar *data; | |
94 int pos = 0; | |
95 | |
96 if (fd < 0) | |
97 return -1; | |
98 | |
99 data = g_malloc0(len + 1); | |
100 | |
101 memcpy(data + pos, "YMSG", 4); pos += 4; | |
102 pos += yahoo_put16(data + pos, YAHOO_PROTO_VER); | |
103 pos += yahoo_put16(data + pos, 0x0000); | |
104 pos += yahoo_put16(data + pos, pktlen + pad); | |
105 pos += yahoo_put16(data + pos, pkt->service); | |
106 pos += yahoo_put32(data + pos, pkt->status); | |
107 pos += yahoo_put32(data + pos, pkt->id); | |
108 | |
109 yahoo_packet_write(pkt, data + pos); | |
110 | |
111 ret = write(fd, data, len); | |
112 g_free(data); | |
113 | |
114 return ret; | |
115 } | |
116 | |
117 static void yahoo_sendfile_connected(gpointer data, gint source, GaimInputCondition condition) | |
118 { | |
119 GaimXfer *xfer; | |
120 struct yahoo_xfer_data *xd; | |
121 struct yahoo_packet *pkt; | |
122 gchar *size, *post, *buf; | |
123 int content_length; | |
124 GaimConnection *gc; | |
125 GaimAccount *account; | |
126 struct yahoo_data *yd; | |
127 | |
128 gaim_debug(GAIM_DEBUG_INFO, "yahoo", | |
129 "AAA - in yahoo_sendfile_connected\n"); | |
130 if (!(xfer = data)) | |
131 return; | |
132 if (!(xd = xfer->data)) | |
133 return; | |
134 | |
135 gc = xd->gc; | |
136 account = gaim_connection_get_account(gc); | |
137 yd = gc->proto_data; | |
138 | |
139 | |
140 | |
141 if (source < 0) { | |
142 gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to connect.")); | |
143 gaim_xfer_end(xfer); | |
144 return; | |
145 } | |
146 | |
147 xfer->fd = source; | |
148 gaim_xfer_start(xfer, source, NULL, 0); | |
149 | |
150 | |
151 pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id); | |
152 | |
153 size = g_strdup_printf("%d", gaim_xfer_get_size(xfer)); | |
154 | |
155 yahoo_packet_hash(pkt, 0, gaim_connection_get_display_name(gc)); | |
156 yahoo_packet_hash(pkt, 5, xfer->who); | |
157 yahoo_packet_hash(pkt, 14, ""); | |
158 yahoo_packet_hash(pkt, 27, gaim_xfer_get_local_filename(xfer)); | |
159 yahoo_packet_hash(pkt, 28, size); | |
160 | |
161 content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); | |
162 | |
163 buf = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t); | |
164 | |
165 post = g_strdup_printf("POST /notifyft HTTP/1.0\r\n" | |
166 "Content-length: %d\r\n" | |
167 "Host: %s:%d\r\n" | |
168 "Cookie: %s\r\n" | |
169 "\r\n", | |
170 content_length + 4 + gaim_xfer_get_size(xfer), | |
171 gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
172 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
173 buf); | |
174 write(xfer->fd, post, strlen(post)); | |
175 | |
176 yahoo_send_packet_special(xfer->fd, pkt, 8); | |
177 yahoo_packet_free(pkt); | |
178 | |
179 write(xfer->fd, "29\xc0\x80", 4); | |
180 | |
181 g_free(size); | |
182 g_free(post); | |
183 g_free(buf); | |
184 } | |
185 | |
186 static void yahoo_xfer_init(GaimXfer *xfer) | |
187 { | |
188 struct yahoo_xfer_data *xfer_data; | |
189 GaimConnection *gc; | |
190 GaimAccount *account; | |
191 | |
192 xfer_data = xfer->data; | |
193 gc = xfer_data->gc; | |
194 account = gaim_connection_get_account(gc); | |
195 | |
196 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { | |
197 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
198 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
199 yahoo_sendfile_connected, xfer) == -1) | |
200 { | |
201 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
202 _("Unable to establish file descriptor.")); | |
203 gaim_xfer_cancel_remote(xfer); | |
204 } | |
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 | |
250 size_t yahoo_xfer_read(char **buffer, GaimXfer *xfer) | |
251 { | |
252 gchar buf[1024]; | |
253 size_t len; | |
254 gchar *start = NULL; | |
255 gchar *length; | |
256 gchar *end; | |
257 struct yahoo_xfer_data *xd = xfer->data; | |
258 | |
259 if (gaim_xfer_get_type(xfer) != GAIM_XFER_RECEIVE) { | |
260 return 0; | |
261 } | |
262 | |
263 len = read(xfer->fd, buf, sizeof(buf)); | |
264 | |
265 if (len == 0) { | |
266 if (xd->length && (xd->length == xd->bytes_in)) | |
267 gaim_xfer_end(xfer); | |
268 else | |
269 gaim_xfer_cancel_remote(xfer); | |
270 return 0; | |
271 } | |
272 | |
273 | |
274 if (!xd->started) { | |
275 xd->rxqueue = g_realloc(xd->rxqueue, len + xd->rxlen); | |
276 memcpy(xd->rxqueue + xd->rxlen, buf, len); | |
277 xd->rxlen += len; | |
278 | |
279 length = g_strstr_len(xd->rxqueue, len, "Content-length:"); | |
280 if (length) { | |
281 end = g_strstr_len(length, length - xd->rxqueue, "\r\n"); | |
282 if (!end) | |
283 return 0; | |
284 if ((xd->length = calculate_length(length, len - (length - xd->rxqueue)))) | |
285 gaim_xfer_set_size(xfer, xd->length); | |
286 } | |
287 start = g_strstr_len(xd->rxqueue, len, "\r\n\r\n"); | |
288 if (start) | |
289 start += 4; | |
290 if (!start || start > (xd->rxqueue + len)) | |
291 return 0; | |
292 xd->started = TRUE; | |
293 | |
294 len -= (start - xd->rxqueue); | |
295 | |
296 *buffer = g_malloc(len); | |
297 memcpy(*buffer, start, len); | |
298 g_free(xd->rxqueue); | |
299 xd->rxqueue = NULL; | |
300 xd->rxlen = 0; | |
301 } else { | |
302 *buffer = g_malloc(len); | |
303 memcpy(*buffer, buf, len); | |
304 } | |
305 | |
306 xd->bytes_in += len; | |
307 return len; | |
308 } | |
309 | |
310 size_t yahoo_xfer_write(const char *buffer, size_t size, GaimXfer *xfer) | |
311 { | |
312 size_t len; | |
313 struct yahoo_xfer_data *xd = xfer->data; | |
314 | |
315 if (!xd) | |
316 return 0; | |
317 | |
318 if (gaim_xfer_get_type(xfer) != GAIM_XFER_SEND) { | |
319 return 0; | |
320 } | |
321 | |
322 len = write(xfer->fd, buffer, size); | |
323 | |
324 xd->bytes_in += len; | |
325 if (xd->bytes_in >= gaim_xfer_get_size(xfer)) | |
326 gaim_xfer_set_completed(xfer, TRUE); | |
327 | |
328 return len; | |
329 | |
330 } | |
331 | |
332 static void yahoo_xfer_cancel_send(GaimXfer *xfer) | |
333 { | |
334 GaimAccount *account; | |
335 struct yahoo_xfer_data *xfer_data; | |
336 | |
337 xfer_data = xfer->data; | |
338 account = gaim_xfer_get_account(xfer); | |
339 | |
340 if (xfer_data) | |
341 yahoo_xfer_data_free(xfer_data); | |
342 xfer->data = NULL; | |
343 } | |
344 | |
345 static void yahoo_xfer_cancel_recv(GaimXfer *xfer) | |
346 { | |
347 GaimAccount *account; | |
348 struct yahoo_xfer_data *xfer_data; | |
349 | |
350 account = gaim_xfer_get_account(xfer); | |
351 xfer_data = xfer->data; | |
352 | |
353 if (xfer_data) | |
354 yahoo_xfer_data_free(xfer_data); | |
355 xfer->data = NULL; | |
356 } | |
357 | |
358 void yahoo_process_filetransfer(GaimConnection *gc, struct yahoo_packet *pkt) | |
359 { | |
360 char *from = NULL; | |
361 char *to = NULL; | |
362 char *msg = NULL; | |
363 char *url = NULL; | |
364 long expires = 0; | |
365 GaimXfer *xfer; | |
366 struct yahoo_xfer_data *xfer_data; | |
367 | |
368 char *service = NULL; | |
369 | |
370 char *filename = NULL; | |
371 unsigned long filesize = 0L; | |
372 | |
373 GSList *l; | |
374 | |
375 for (l = pkt->hash; l; l = l->next) { | |
376 struct yahoo_pair *pair = l->data; | |
377 | |
378 if (pair->key == 4) | |
379 from = pair->value; | |
380 if (pair->key == 5) | |
381 to = pair->value; | |
382 if (pair->key == 14) | |
383 msg = pair->value; | |
384 if (pair->key == 20) | |
385 url = pair->value; | |
386 if (pair->key == 38) | |
387 expires = strtol(pair->value, NULL, 10); | |
388 | |
389 if (pair->key == 27) | |
390 filename = pair->value; | |
391 if (pair->key == 28) | |
392 filesize = atol(pair->value); | |
393 | |
394 if (pair->key == 49) | |
395 service = pair->value; | |
396 } | |
397 | |
398 if (pkt->service == YAHOO_SERVICE_P2PFILEXFER) { | |
399 if (strcmp("FILEXFER", service) != 0) { | |
400 gaim_debug_misc("yahoo", "unhandled service 0x%02x", pkt->service); | |
401 return; | |
402 } | |
403 } | |
404 | |
405 if (msg) { | |
406 char *tmp; | |
407 tmp = strchr(msg, '\006'); | |
408 if (tmp) | |
409 *tmp = '\0'; | |
410 } | |
411 | |
412 if (!url || !from) | |
413 return; | |
414 | |
415 | |
416 /* Setup the Yahoo-specific file transfer data */ | |
417 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
418 xfer_data->gc = gc; | |
419 if (!gaim_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path))) { | |
420 g_free(xfer_data); | |
421 return; | |
422 } | |
423 | |
424 gaim_debug_misc("yahoo_filexfer", "Host is %s, port is %d, path is %s, and the full url was %s.\n", | |
425 xfer_data->host, xfer_data->port, xfer_data->path, url); | |
426 | |
427 /* Build the file transfer handle. */ | |
428 xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, from); | |
429 xfer->data = xfer_data; | |
430 | |
431 /* Set the info about the incoming file. */ | |
432 if (filename) | |
433 gaim_xfer_set_filename(xfer, filename); | |
434 else { | |
435 gchar *start, *end; | |
436 start = g_strrstr(xfer_data->path, "/"); | |
437 if (start) | |
438 start++; | |
439 end = g_strrstr(xfer_data->path, "?"); | |
440 if (start && *start && end) { | |
441 filename = g_strndup(start, end - start); | |
442 gaim_xfer_set_filename(xfer, filename); | |
443 g_free(filename); | |
444 filename = NULL; | |
445 } | |
446 } | |
447 | |
448 gaim_xfer_set_size(xfer, filesize); | |
449 | |
450 /* Setup our I/O op functions */ | |
451 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
452 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
453 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
454 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
455 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
456 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
457 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
458 | |
459 /* Now perform the request */ | |
460 gaim_xfer_request(xfer); | |
461 } | |
462 | |
463 void yahoo_ask_send_file(GaimConnection *gc, const char *who) | |
464 { | |
465 GaimXfer *xfer; | |
466 struct yahoo_xfer_data *xfer_data; | |
467 | |
468 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
469 xfer_data->gc = gc; | |
470 | |
471 | |
472 /* Build the file transfer handle. */ | |
473 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); | |
474 xfer->data = xfer_data; | |
475 | |
476 /* Setup our I/O op functions */ | |
477 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
478 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
479 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
480 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
481 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
482 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
483 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
484 | |
485 /* Now perform the request */ | |
486 gaim_xfer_request(xfer); | |
487 } | |
488 | |
489 void yahoo_send_file(GaimConnection *gc, const char *who, const char *file) | |
490 { | |
491 GaimXfer *xfer; | |
492 struct yahoo_xfer_data *xfer_data; | |
493 | |
494 if (!who || !file) | |
495 return; | |
496 | |
497 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
498 xfer_data->gc = gc; | |
499 | |
500 | |
501 /* Build the file transfer handle. */ | |
502 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); | |
503 xfer->data = xfer_data; | |
504 | |
505 /* Setup our I/O op functions */ | |
506 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
507 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
508 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
509 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
510 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
511 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
512 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
513 | |
514 /* Now perform the request */ | |
515 gaim_xfer_request_accepted(xfer, g_strdup(file)); | |
516 } |