Mercurial > pidgin
annotate src/protocols/yahoo/yahoo_filexfer.c @ 9306:04a3e9e869ee
[gaim-migrate @ 10114]
Ok, this is yahoo buddy icon uploading support.
It's still not quite right, but it mostly works.
We don't send out updates yet so changing it or unsetting it may not work.
But setting it initally, or changing it and relogging will probably work.
I never did figure out what hash function yahoo is using, so I just used
g_string_hash. It probably won't matter.
I hope to finish this up before release. But people probably won't notice
the bugs too much anyway. It shouldn't crash or anything, people just might
not always see your newest icon right away.
Have fun kids.
For the record, Simguy tells me Yahoo likes 96x96 PNGs.
committer: Tailor Script <tailor@pidgin.im>
author | Tim Ringenbach <marv@pidgin.im> |
---|---|
date | Fri, 18 Jun 2004 07:28:25 +0000 |
parents | 9171e528d7e5 |
children | d27156c9c876 |
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 void yahoo_sendfile_connected(gpointer data, gint source, GaimInputCondition condition) | |
84 { | |
85 GaimXfer *xfer; | |
86 struct yahoo_xfer_data *xd; | |
87 struct yahoo_packet *pkt; | |
88 gchar *size, *post, *buf; | |
89 int content_length; | |
90 GaimConnection *gc; | |
91 GaimAccount *account; | |
92 struct yahoo_data *yd; | |
7805 | 93 char *filename; |
7651 | 94 |
95 gaim_debug(GAIM_DEBUG_INFO, "yahoo", | |
96 "AAA - in yahoo_sendfile_connected\n"); | |
97 if (!(xfer = data)) | |
98 return; | |
99 if (!(xd = xfer->data)) | |
100 return; | |
101 | |
102 gc = xd->gc; | |
103 account = gaim_connection_get_account(gc); | |
104 yd = gc->proto_data; | |
105 | |
106 | |
107 | |
108 if (source < 0) { | |
109 gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to connect.")); | |
7805 | 110 gaim_xfer_cancel_remote(xfer); |
7651 | 111 return; |
112 } | |
113 | |
114 xfer->fd = source; | |
115 gaim_xfer_start(xfer, source, NULL, 0); | |
116 | |
117 | |
118 pkt = yahoo_packet_new(YAHOO_SERVICE_FILETRANSFER, YAHOO_STATUS_AVAILABLE, yd->session_id); | |
119 | |
120 size = g_strdup_printf("%d", gaim_xfer_get_size(xfer)); | |
121 | |
122 yahoo_packet_hash(pkt, 0, gaim_connection_get_display_name(gc)); | |
123 yahoo_packet_hash(pkt, 5, xfer->who); | |
124 yahoo_packet_hash(pkt, 14, ""); | |
7805 | 125 filename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); |
126 yahoo_packet_hash(pkt, 27, filename); | |
7651 | 127 yahoo_packet_hash(pkt, 28, size); |
128 | |
129 content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); | |
130 | |
131 buf = g_strdup_printf("Y=%s; T=%s", yd->cookie_y, yd->cookie_t); | |
132 | |
133 post = g_strdup_printf("POST /notifyft HTTP/1.0\r\n" | |
134 "Content-length: %d\r\n" | |
135 "Host: %s:%d\r\n" | |
136 "Cookie: %s\r\n" | |
137 "\r\n", | |
138 content_length + 4 + gaim_xfer_get_size(xfer), | |
139 gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
140 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
141 buf); | |
142 write(xfer->fd, post, strlen(post)); | |
143 | |
144 yahoo_send_packet_special(xfer->fd, pkt, 8); | |
145 yahoo_packet_free(pkt); | |
146 | |
147 write(xfer->fd, "29\xc0\x80", 4); | |
148 | |
149 g_free(size); | |
150 g_free(post); | |
151 g_free(buf); | |
7805 | 152 g_free(filename); |
7651 | 153 } |
154 | |
155 static void yahoo_xfer_init(GaimXfer *xfer) | |
156 { | |
157 struct yahoo_xfer_data *xfer_data; | |
158 GaimConnection *gc; | |
159 GaimAccount *account; | |
7827 | 160 struct yahoo_data *yd; |
7651 | 161 |
162 xfer_data = xfer->data; | |
163 gc = xfer_data->gc; | |
7827 | 164 yd = gc->proto_data; |
7651 | 165 account = gaim_connection_get_account(gc); |
166 | |
167 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { | |
8282 | 168 if (gaim_xfer_get_size(xfer) >= 1048577) { |
7651 | 169 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), |
8282 | 170 _("Gaim cannot send files over Yahoo! that are bigger than " |
171 "One Megabyte (1,048,576 bytes).")); | |
172 gaim_xfer_cancel_local(xfer); | |
173 } else { | |
9164 | 174 if (yd->jp) { |
175 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xferjp_host", YAHOOJP_XFER_HOST), | |
176 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
177 yahoo_sendfile_connected, xfer) == -1) | |
178 { | |
179 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
180 _("Unable to establish file descriptor.")); | |
181 gaim_xfer_cancel_remote(xfer); | |
182 } | |
183 } else { | |
184 if (gaim_proxy_connect(account, gaim_account_get_string(account, "xfer_host", YAHOO_XFER_HOST), | |
185 gaim_account_get_int(account, "xfer_port", YAHOO_XFER_PORT), | |
186 yahoo_sendfile_connected, xfer) == -1) | |
187 { | |
188 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
189 _("Unable to establish file descriptor.")); | |
190 gaim_xfer_cancel_remote(xfer); | |
191 } | |
8282 | 192 } |
7651 | 193 } |
194 } else { | |
195 xfer->fd = gaim_proxy_connect(account, xfer_data->host, xfer_data->port, | |
196 yahoo_receivefile_connected, xfer); | |
197 if (xfer->fd == -1) { | |
198 gaim_notify_error(gc, NULL, _("File Transfer Aborted"), | |
199 _("Unable to establish file descriptor.")); | |
200 gaim_xfer_cancel_remote(xfer); | |
201 } | |
202 } | |
203 } | |
204 | |
205 static void yahoo_xfer_start(GaimXfer *xfer) | |
206 { | |
207 /* We don't need to do anything here, do we? */ | |
208 } | |
209 | |
210 static void yahoo_xfer_end(GaimXfer *xfer) | |
211 { | |
212 GaimAccount *account; | |
213 struct yahoo_xfer_data *xfer_data; | |
214 | |
215 account = gaim_xfer_get_account(xfer); | |
216 xfer_data = xfer->data; | |
217 | |
218 | |
219 if (xfer_data) | |
220 yahoo_xfer_data_free(xfer_data); | |
221 xfer->data = NULL; | |
222 | |
223 } | |
224 | |
225 guint calculate_length(const gchar *l, size_t len) | |
226 { | |
227 int i; | |
228 | |
229 for (i = 0; i < len; i++) { | |
230 if (!g_ascii_isdigit(l[i])) | |
231 continue; | |
232 return strtol(l + i, NULL, 10); | |
233 } | |
234 return 0; | |
235 } | |
236 | |
237 | |
8231
f50c059b6384
[gaim-migrate @ 8954]
Christian Hammond <chipx86@chipx86.com>
parents:
8046
diff
changeset
|
238 ssize_t yahoo_xfer_read(char **buffer, GaimXfer *xfer) |
7651 | 239 { |
7710 | 240 gchar buf[4096]; |
7682 | 241 ssize_t len; |
7651 | 242 gchar *start = NULL; |
243 gchar *length; | |
244 gchar *end; | |
7710 | 245 int filelen; |
7651 | 246 struct yahoo_xfer_data *xd = xfer->data; |
247 | |
248 if (gaim_xfer_get_type(xfer) != GAIM_XFER_RECEIVE) { | |
249 return 0; | |
250 } | |
251 | |
252 len = read(xfer->fd, buf, sizeof(buf)); | |
253 | |
7682 | 254 if (len <= 0) { |
7710 | 255 if ((gaim_xfer_get_size(xfer) > 0) && |
256 (gaim_xfer_get_bytes_sent(xfer) >= gaim_xfer_get_size(xfer))) | |
7682 | 257 gaim_xfer_set_completed(xfer, TRUE); |
7651 | 258 else |
259 gaim_xfer_cancel_remote(xfer); | |
260 return 0; | |
261 } | |
262 | |
263 | |
264 if (!xd->started) { | |
265 xd->rxqueue = g_realloc(xd->rxqueue, len + xd->rxlen); | |
266 memcpy(xd->rxqueue + xd->rxlen, buf, len); | |
267 xd->rxlen += len; | |
268 | |
269 length = g_strstr_len(xd->rxqueue, len, "Content-length:"); | |
270 if (length) { | |
271 end = g_strstr_len(length, length - xd->rxqueue, "\r\n"); | |
272 if (!end) | |
273 return 0; | |
7710 | 274 if ((filelen = calculate_length(length, len - (length - xd->rxqueue)))) |
275 gaim_xfer_set_size(xfer, filelen); | |
7651 | 276 } |
277 start = g_strstr_len(xd->rxqueue, len, "\r\n\r\n"); | |
278 if (start) | |
279 start += 4; | |
280 if (!start || start > (xd->rxqueue + len)) | |
281 return 0; | |
282 xd->started = TRUE; | |
283 | |
284 len -= (start - xd->rxqueue); | |
285 | |
286 *buffer = g_malloc(len); | |
287 memcpy(*buffer, start, len); | |
288 g_free(xd->rxqueue); | |
289 xd->rxqueue = NULL; | |
290 xd->rxlen = 0; | |
291 } else { | |
292 *buffer = g_malloc(len); | |
293 memcpy(*buffer, buf, len); | |
294 } | |
295 | |
296 return len; | |
297 } | |
298 | |
8231
f50c059b6384
[gaim-migrate @ 8954]
Christian Hammond <chipx86@chipx86.com>
parents:
8046
diff
changeset
|
299 ssize_t yahoo_xfer_write(const char *buffer, size_t size, GaimXfer *xfer) |
7651 | 300 { |
7710 | 301 ssize_t len; |
7651 | 302 struct yahoo_xfer_data *xd = xfer->data; |
303 | |
304 if (!xd) | |
305 return 0; | |
306 | |
307 if (gaim_xfer_get_type(xfer) != GAIM_XFER_SEND) { | |
308 return 0; | |
309 } | |
310 | |
311 len = write(xfer->fd, buffer, size); | |
312 | |
7710 | 313 if (len == -1) { |
314 if (gaim_xfer_get_bytes_sent(xfer) >= gaim_xfer_get_size(xfer)) | |
315 gaim_xfer_set_completed(xfer, TRUE); | |
316 if ((errno != EAGAIN) && (errno != EINTR)) | |
317 gaim_xfer_cancel_remote(xfer); | |
318 return 0; | |
319 } | |
320 | |
321 if ((gaim_xfer_get_bytes_sent(xfer) + len) >= gaim_xfer_get_size(xfer)) | |
7651 | 322 gaim_xfer_set_completed(xfer, TRUE); |
323 | |
324 return len; | |
325 } | |
326 | |
327 static void yahoo_xfer_cancel_send(GaimXfer *xfer) | |
328 { | |
329 GaimAccount *account; | |
330 struct yahoo_xfer_data *xfer_data; | |
331 | |
332 xfer_data = xfer->data; | |
333 account = gaim_xfer_get_account(xfer); | |
334 | |
335 if (xfer_data) | |
336 yahoo_xfer_data_free(xfer_data); | |
337 xfer->data = NULL; | |
338 } | |
339 | |
340 static void yahoo_xfer_cancel_recv(GaimXfer *xfer) | |
341 { | |
342 GaimAccount *account; | |
343 struct yahoo_xfer_data *xfer_data; | |
344 | |
345 account = gaim_xfer_get_account(xfer); | |
346 xfer_data = xfer->data; | |
347 | |
348 if (xfer_data) | |
349 yahoo_xfer_data_free(xfer_data); | |
350 xfer->data = NULL; | |
351 } | |
352 | |
353 void yahoo_process_filetransfer(GaimConnection *gc, struct yahoo_packet *pkt) | |
354 { | |
355 char *from = NULL; | |
356 char *to = NULL; | |
357 char *msg = NULL; | |
358 char *url = NULL; | |
359 long expires = 0; | |
360 GaimXfer *xfer; | |
361 struct yahoo_xfer_data *xfer_data; | |
362 | |
363 char *service = NULL; | |
364 | |
365 char *filename = NULL; | |
366 unsigned long filesize = 0L; | |
367 | |
368 GSList *l; | |
369 | |
370 for (l = pkt->hash; l; l = l->next) { | |
371 struct yahoo_pair *pair = l->data; | |
372 | |
373 if (pair->key == 4) | |
374 from = pair->value; | |
375 if (pair->key == 5) | |
376 to = pair->value; | |
377 if (pair->key == 14) | |
378 msg = pair->value; | |
379 if (pair->key == 20) | |
380 url = pair->value; | |
381 if (pair->key == 38) | |
382 expires = strtol(pair->value, NULL, 10); | |
383 | |
384 if (pair->key == 27) | |
385 filename = pair->value; | |
386 if (pair->key == 28) | |
387 filesize = atol(pair->value); | |
388 | |
389 if (pair->key == 49) | |
390 service = pair->value; | |
391 } | |
392 | |
393 if (pkt->service == YAHOO_SERVICE_P2PFILEXFER) { | |
394 if (strcmp("FILEXFER", service) != 0) { | |
395 gaim_debug_misc("yahoo", "unhandled service 0x%02x", pkt->service); | |
396 return; | |
397 } | |
398 } | |
399 | |
400 if (msg) { | |
401 char *tmp; | |
402 tmp = strchr(msg, '\006'); | |
403 if (tmp) | |
404 *tmp = '\0'; | |
405 } | |
406 | |
407 if (!url || !from) | |
408 return; | |
409 | |
410 | |
411 /* Setup the Yahoo-specific file transfer data */ | |
412 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
413 xfer_data->gc = gc; | |
9227
9171e528d7e5
[gaim-migrate @ 10023]
Christian Hammond <chipx86@chipx86.com>
parents:
9164
diff
changeset
|
414 if (!gaim_url_parse(url, &(xfer_data->host), &(xfer_data->port), &(xfer_data->path), NULL, NULL)) { |
7651 | 415 g_free(xfer_data); |
416 return; | |
417 } | |
418 | |
419 gaim_debug_misc("yahoo_filexfer", "Host is %s, port is %d, path is %s, and the full url was %s.\n", | |
420 xfer_data->host, xfer_data->port, xfer_data->path, url); | |
421 | |
422 /* Build the file transfer handle. */ | |
423 xfer = gaim_xfer_new(gc->account, GAIM_XFER_RECEIVE, from); | |
424 xfer->data = xfer_data; | |
425 | |
426 /* Set the info about the incoming file. */ | |
427 if (filename) | |
428 gaim_xfer_set_filename(xfer, filename); | |
429 else { | |
430 gchar *start, *end; | |
431 start = g_strrstr(xfer_data->path, "/"); | |
432 if (start) | |
433 start++; | |
434 end = g_strrstr(xfer_data->path, "?"); | |
435 if (start && *start && end) { | |
436 filename = g_strndup(start, end - start); | |
437 gaim_xfer_set_filename(xfer, filename); | |
438 g_free(filename); | |
439 filename = NULL; | |
440 } | |
441 } | |
442 | |
443 gaim_xfer_set_size(xfer, filesize); | |
444 | |
445 /* Setup our I/O op functions */ | |
446 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
447 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
448 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
449 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
450 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
451 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
452 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
453 | |
454 /* Now perform the request */ | |
455 gaim_xfer_request(xfer); | |
456 } | |
457 | |
458 void yahoo_ask_send_file(GaimConnection *gc, const char *who) | |
459 { | |
460 GaimXfer *xfer; | |
461 struct yahoo_xfer_data *xfer_data; | |
462 | |
463 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
464 xfer_data->gc = gc; | |
465 | |
466 | |
467 /* Build the file transfer handle. */ | |
468 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); | |
469 xfer->data = xfer_data; | |
470 | |
471 /* Setup our I/O op functions */ | |
472 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
473 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
474 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
475 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
476 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
477 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
478 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
479 | |
480 /* Now perform the request */ | |
481 gaim_xfer_request(xfer); | |
482 } | |
483 | |
484 void yahoo_send_file(GaimConnection *gc, const char *who, const char *file) | |
485 { | |
486 GaimXfer *xfer; | |
487 struct yahoo_xfer_data *xfer_data; | |
488 | |
489 if (!who || !file) | |
490 return; | |
491 | |
492 xfer_data = g_new0(struct yahoo_xfer_data, 1); | |
493 xfer_data->gc = gc; | |
494 | |
495 | |
496 /* Build the file transfer handle. */ | |
497 xfer = gaim_xfer_new(gc->account, GAIM_XFER_SEND, who); | |
498 xfer->data = xfer_data; | |
499 | |
500 /* Setup our I/O op functions */ | |
501 gaim_xfer_set_init_fnc(xfer, yahoo_xfer_init); | |
502 gaim_xfer_set_start_fnc(xfer, yahoo_xfer_start); | |
503 gaim_xfer_set_end_fnc(xfer, yahoo_xfer_end); | |
504 gaim_xfer_set_cancel_send_fnc(xfer, yahoo_xfer_cancel_send); | |
505 gaim_xfer_set_cancel_recv_fnc(xfer, yahoo_xfer_cancel_recv); | |
506 gaim_xfer_set_read_fnc(xfer, yahoo_xfer_read); | |
507 gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); | |
508 | |
509 /* Now perform the request */ | |
7805 | 510 gaim_xfer_request_accepted(xfer, file); |
7651 | 511 } |