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 }