Mon, 10 Apr 2006 03:37:37 +0000
[gaim-migrate @ 15994]
Disconnect the account with a decent error message when there are
problems with an oscar FLAP connection. This needed to be added
after I removed it when rewriting things for non-blocking I/O.
| 13593 | 1 | /* |
| 2 | * Gaim's oscar protocol plugin | |
| 3 | * This file is the legal property of its developers. | |
| 4 | * Please see the AUTHORS file distributed alongside this file. | |
| 5 | * | |
| 6 | * This library is free software; you can redistribute it and/or | |
| 7 | * modify it under the terms of the GNU Lesser General Public | |
| 8 | * License as published by the Free Software Foundation; either | |
| 9 | * version 2 of the License, or (at your option) any later version. | |
| 10 | * | |
| 11 | * This library is distributed in the hope that it will be useful, | |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | * Lesser General Public License for more details. | |
| 15 | * | |
| 16 | * You should have received a copy of the GNU Lesser General Public | |
| 17 | * License along with this library; if not, write to the Free Software | |
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | */ | |
| 20 | ||
| 21 | /* | |
| 22 | * I feel like this is a good place to explain OFT, so I'm going to | |
| 23 | * do just that. Each OFT packet has a header type. I guess this | |
| 24 | * is pretty similar to the subtype of a SNAC packet. The type | |
| 25 | * basically tells the other client the meaning of the OFT packet. | |
| 26 | * There are two distinct types of file transfer, which I usually | |
| 27 | * call "sendfile" and "getfile." Sendfile is when you send a file | |
| 28 | * to another AIM user. Getfile is when you share a group of files, | |
| 29 | * and other users request that you send them the files. | |
| 30 | * | |
| 31 | * A typical sendfile file transfer goes like this: | |
| 32 | * 1) Sender sends a channel 2 ICBM telling the other user that | |
| 33 | * we want to send them a file. At the same time, we open a | |
| 34 | * listener socket (this should be done before sending the | |
| 35 | * ICBM) on some port, and wait for them to connect to us. | |
| 36 | * The ICBM we sent should contain our IP address and the port | |
| 37 | * number that we're listening on. | |
| 38 | * 2) The receiver connects to the sender on the given IP address | |
| 39 | * and port. After the connection is established, the receiver | |
| 40 | * sends an ICBM signifying that we are ready and waiting. | |
| 41 | * 3) The sender sends an OFT PROMPT message over the OFT | |
| 42 | * connection. | |
| 43 | * 4) The receiver of the file sends back an exact copy of this | |
| 44 | * OFT packet, except the cookie is filled in with the cookie | |
| 45 | * from the ICBM. I think this might be an attempt to verify | |
| 46 | * that the user that is connected is actually the guy that | |
| 47 | * we sent the ICBM to. Oh, I've been calling this the ACK. | |
| 48 | * 5) The sender starts sending raw data across the connection | |
| 49 | * until the entire file has been sent. | |
| 50 | * 6) The receiver knows the file is finished because the sender | |
| 51 | * sent the file size in an earlier OFT packet. So then the | |
| 52 | * receiver sends the DONE thingy (after filling in the | |
| 53 | * "received" checksum and size) and closes the connection. | |
| 54 | */ | |
| 55 | ||
| 56 | #include "oscar.h" | |
| 57 | #include "peer.h" | |
| 58 | ||
| 59 | /** | |
| 60 | * Calculate oft checksum of buffer | |
| 61 | * | |
| 62 | * Prevcheck should be 0xFFFF0000 when starting a checksum of a file. The | |
| 63 | * checksum is kind of a rolling checksum thing, so each time you get bytes | |
| 64 | * of a file you just call this puppy and it updates the checksum. You can | |
| 65 | * calculate the checksum of an entire file by calling this in a while or a | |
| 66 | * for loop, or something. | |
| 67 | * | |
| 68 | * Thanks to Graham Booker for providing this improved checksum routine, | |
| 69 | * which is simpler and should be more accurate than Josh Myer's original | |
| 70 | * code. -- wtm | |
| 71 | * | |
| 72 | * This algorithm works every time I have tried it. The other fails | |
| 73 | * sometimes. So, AOL who thought this up? It has got to be the weirdest | |
| 74 | * checksum I have ever seen. | |
| 75 | * | |
| 76 | * @param buffer Buffer of data to checksum. Man I'd like to buff her... | |
| 77 | * @param bufsize Size of buffer. | |
| 78 | * @param prevchecksum Previous checksum. | |
| 79 | */ | |
| 80 | static guint32 | |
| 81 | peer_oft_checksum_chunk(const guint8 *buffer, int bufferlen, guint32 prevchecksum) | |
| 82 | { | |
| 83 | guint32 checksum, oldchecksum; | |
| 84 | int i; | |
| 85 | unsigned short val; | |
| 86 | ||
| 87 | checksum = (prevchecksum >> 16) & 0xffff; | |
| 88 | for (i = 0; i < bufferlen; i++) | |
| 89 | { | |
| 90 | oldchecksum = checksum; | |
| 91 | if (i & 1) | |
| 92 | val = buffer[i]; | |
| 93 | else | |
| 94 | val = buffer[i] << 8; | |
| 95 | checksum -= val; | |
| 96 | /* | |
| 97 | * The following appears to be necessary.... It happens | |
| 98 | * every once in a while and the checksum doesn't fail. | |
| 99 | */ | |
| 100 | if (checksum > oldchecksum) | |
| 101 | checksum--; | |
| 102 | } | |
| 103 | checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); | |
| 104 | checksum = ((checksum & 0x0000ffff) + (checksum >> 16)); | |
| 105 | return checksum << 16; | |
| 106 | } | |
| 107 | ||
| 108 | static guint32 | |
| 109 | peer_oft_checksum_file(char *filename) | |
| 110 | { | |
| 111 | FILE *fd; | |
| 112 | guint32 checksum = 0xffff0000; | |
| 113 | ||
| 114 | if ((fd = fopen(filename, "rb"))) | |
| 115 | { | |
| 116 | int bytes; | |
| 117 | guint8 buffer[1024]; | |
| 118 | ||
| 119 | while ((bytes = fread(buffer, 1, 1024, fd)) != 0) | |
| 120 | checksum = peer_oft_checksum_chunk(buffer, bytes, checksum); | |
| 121 | fclose(fd); | |
| 122 | } | |
| 123 | ||
| 124 | return checksum; | |
| 125 | } | |
| 126 | ||
| 127 | /** | |
| 128 | * Free any OFT related data. | |
| 129 | */ | |
| 130 | void | |
| 131 | peer_oft_close(PeerConnection *conn) | |
| 132 | { | |
| 133 | /* | |
| 134 | * If canceled by local user, and we're receiving a file, and | |
| 135 | * we're not connected/ready then send an ICBM cancel message. | |
| 136 | */ | |
| 137 | if ((gaim_xfer_get_status(conn->xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) && | |
| 138 | !conn->ready) | |
| 139 | { | |
| 140 | aim_im_sendch2_cancel(conn); | |
| 141 | } | |
| 142 | ||
| 143 | if (conn->sending_data_timer != 0) | |
| 144 | { | |
| 145 | gaim_timeout_remove(conn->sending_data_timer); | |
| 146 | conn->sending_data_timer = 0; | |
| 147 | } | |
| 148 | } | |
| 149 | ||
| 150 | /** | |
| 151 | * Write the given OftFrame to a ByteStream and send it out | |
| 152 | * on the established PeerConnection. | |
| 153 | */ | |
| 154 | static void | |
| 155 | peer_oft_send(PeerConnection *conn, OftFrame *frame) | |
| 156 | { | |
| 157 | size_t length; | |
| 158 | ByteStream bs; | |
| 159 | ||
| 160 | length = 192 + MAX(64, frame->name_length + 1); | |
| 161 | byte_stream_init(&bs, malloc(length), length); | |
| 162 | byte_stream_putraw(&bs, conn->magic, 4); | |
| 163 | byte_stream_put16(&bs, length); | |
| 164 | byte_stream_put16(&bs, frame->type); | |
| 165 | byte_stream_putraw(&bs, frame->cookie, 8); | |
| 166 | byte_stream_put16(&bs, frame->encrypt); | |
| 167 | byte_stream_put16(&bs, frame->compress); | |
| 168 | byte_stream_put16(&bs, frame->totfiles); | |
| 169 | byte_stream_put16(&bs, frame->filesleft); | |
| 170 | byte_stream_put16(&bs, frame->totparts); | |
| 171 | byte_stream_put16(&bs, frame->partsleft); | |
| 172 | byte_stream_put32(&bs, frame->totsize); | |
| 173 | byte_stream_put32(&bs, frame->size); | |
| 174 | byte_stream_put32(&bs, frame->modtime); | |
| 175 | byte_stream_put32(&bs, frame->checksum); | |
| 176 | byte_stream_put32(&bs, frame->rfrcsum); | |
| 177 | byte_stream_put32(&bs, frame->rfsize); | |
| 178 | byte_stream_put32(&bs, frame->cretime); | |
| 179 | byte_stream_put32(&bs, frame->rfcsum); | |
| 180 | byte_stream_put32(&bs, frame->nrecvd); | |
| 181 | byte_stream_put32(&bs, frame->recvcsum); | |
| 182 | byte_stream_putraw(&bs, frame->idstring, 32); | |
| 183 | byte_stream_put8(&bs, frame->flags); | |
| 184 | byte_stream_put8(&bs, frame->lnameoffset); | |
| 185 | byte_stream_put8(&bs, frame->lsizeoffset); | |
| 186 | byte_stream_putraw(&bs, frame->dummy, 69); | |
| 187 | byte_stream_putraw(&bs, frame->macfileinfo, 16); | |
| 188 | byte_stream_put16(&bs, frame->nencode); | |
| 189 | byte_stream_put16(&bs, frame->nlanguage); | |
| 190 | /* | |
| 191 | * The name can be more than 64 characters, but if it is less than | |
| 192 | * 64 characters it is padded with NULLs. | |
| 193 | */ | |
| 194 | byte_stream_putraw(&bs, frame->name, MAX(64, frame->name_length + 1)); | |
| 195 | ||
| 196 | peer_connection_send(conn, &bs); | |
| 197 | ||
| 198 | free(bs.data); | |
| 199 | } | |
| 200 | ||
| 201 | void | |
| 202 | peer_oft_send_prompt(PeerConnection *conn) | |
| 203 | { | |
| 204 | conn->xferdata.type = PEER_TYPE_PROMPT; | |
| 205 | peer_oft_send(conn, &conn->xferdata); | |
| 206 | } | |
| 207 | ||
| 208 | static void | |
| 209 | peer_oft_send_ack(PeerConnection *conn) | |
| 210 | { | |
| 211 | conn->xferdata.type = PEER_TYPE_ACK; | |
| 212 | ||
| 213 | /* Fill in the cookie */ | |
| 214 | memcpy(conn->xferdata.cookie, conn->cookie, 8); | |
| 215 | ||
| 216 | peer_oft_send(conn, &conn->xferdata); | |
| 217 | } | |
| 218 | ||
| 219 | static void | |
| 220 | peer_oft_send_done(PeerConnection *conn) | |
| 221 | { | |
| 222 | conn->xferdata.type = PEER_TYPE_DONE; | |
| 223 | conn->xferdata.filesleft = 0; | |
| 224 | conn->xferdata.partsleft = 0; | |
| 225 | conn->xferdata.nrecvd = gaim_xfer_get_bytes_sent(conn->xfer); | |
| 226 | peer_oft_send(conn, &conn->xferdata); | |
| 227 | } | |
| 228 | ||
| 229 | /** | |
| 230 | * This function exists so that we don't remove the outgoing | |
| 231 | * data watcher while we're still sending data. In most cases | |
| 232 | * any data we're sending will be instantly wisked away to a TCP | |
| 233 | * buffer maintained by our operating system... but we want to | |
| 234 | * make sure the core doesn't start sending file data while | |
| 235 | * we're still sending OFT frame data. That would be bad. | |
| 236 | */ | |
| 237 | static gboolean | |
| 238 | start_transfer_when_done_sending_data(gpointer data) | |
| 239 | { | |
| 240 | PeerConnection *conn; | |
| 241 | ||
| 242 | conn = data; | |
| 243 | ||
| 244 | if (gaim_circ_buffer_get_max_read(conn->buffer_outgoing) == 0) | |
| 245 | { | |
| 246 | conn->sending_data_timer = 0; | |
| 247 | conn->xfer->fd = conn->fd; | |
| 248 | conn->fd = -1; | |
| 249 | gaim_xfer_start(conn->xfer, conn->xfer->fd, NULL, 0); | |
| 250 | return FALSE; | |
| 251 | } | |
| 252 | ||
| 253 | return TRUE; | |
| 254 | } | |
| 255 | ||
| 256 | /** | |
| 257 | * This function is similar to the above function, except instead | |
| 258 | * of starting the xfer it will destroy the connection. This is | |
| 259 | * used when you want to send one final message across the peer | |
| 260 | * connection, and then close everything. | |
| 261 | */ | |
| 262 | static gboolean | |
| 263 | destroy_connection_when_done_sending_data(gpointer data) | |
| 264 | { | |
| 265 | PeerConnection *conn; | |
| 266 | ||
| 267 | conn = data; | |
| 268 | ||
| 269 | if (gaim_circ_buffer_get_max_read(conn->buffer_outgoing) == 0) | |
| 270 | { | |
| 271 | conn->sending_data_timer = 0; | |
| 272 | peer_connection_destroy(conn, conn->disconnect_reason); | |
| 273 | return FALSE; | |
| 274 | } | |
| 275 | ||
| 276 | return TRUE; | |
| 277 | } | |
| 278 | ||
| 279 | /* | |
| 280 | * This is called when a buddy sends us some file info. This happens when they | |
| 281 | * are sending a file to you, and you have just established a connection to them. | |
| 282 | * You should send them the exact same info except use the real cookie. We also | |
| 283 | * get like totally ready to like, receive the file, kay? | |
| 284 | */ | |
| 285 | static void | |
| 286 | peer_oft_recv_frame_prompt(PeerConnection *conn, OftFrame *frame) | |
| 287 | { | |
| 288 | /* Record the file information and send an ack */ | |
| 289 | memcpy(&conn->xferdata, frame, sizeof(OftFrame)); | |
| 290 | peer_oft_send_ack(conn); | |
| 291 | ||
| 292 | /* Remove our watchers and use the file transfer watchers in the core */ | |
| 293 | gaim_input_remove(conn->watcher_incoming); | |
| 294 | conn->watcher_incoming = 0; | |
| 295 | conn->sending_data_timer = gaim_timeout_add(100, | |
| 296 | start_transfer_when_done_sending_data, conn); | |
| 297 | } | |
| 298 | ||
| 299 | /** | |
| 300 | * We are sending a file to someone else. They have just acknowledged our | |
| 301 | * prompt, so we want to start sending data like there's no tomorrow. | |
| 302 | */ | |
| 303 | static void | |
| 304 | peer_oft_recv_frame_ack(PeerConnection *conn, OftFrame *frame) | |
| 305 | { | |
| 306 | if (memcmp(conn->cookie, frame->cookie, 8)) | |
| 307 | { | |
| 308 | gaim_debug_info("oscar", "Received an incorrect cookie. " | |
| 309 | "Closing connection.\n"); | |
|
13609
a6fbfad454b6
[gaim-migrate @ 15994]
Mark Doliner <markdoliner@pidgin.im>
parents:
13608
diff
changeset
|
310 | peer_connection_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA); |
| 13593 | 311 | return; |
| 312 | } | |
| 313 | ||
| 314 | /* Remove our watchers and use the file transfer watchers in the core */ | |
| 315 | gaim_input_remove(conn->watcher_incoming); | |
| 316 | conn->watcher_incoming = 0; | |
| 317 | conn->sending_data_timer = gaim_timeout_add(100, | |
| 318 | start_transfer_when_done_sending_data, conn); | |
| 319 | } | |
| 320 | ||
| 321 | /* | |
| 322 | * We just sent a file to someone. They said they got it and everything, | |
| 323 | * so we can close our direct connection and what not. | |
| 324 | */ | |
| 325 | static void | |
| 326 | peer_oft_recv_frame_done(PeerConnection *conn, OftFrame *frame) | |
| 327 | { | |
| 328 | if (frame->nrecvd == frame->size) | |
| 329 | gaim_xfer_set_completed(conn->xfer, TRUE); | |
| 330 | ||
| 331 | gaim_input_remove(conn->watcher_incoming); | |
| 332 | conn->watcher_incoming = 0; | |
| 333 | conn->xfer->fd = conn->fd; | |
| 334 | conn->fd = -1; | |
| 335 | gaim_xfer_end(conn->xfer); | |
| 336 | } | |
| 337 | ||
| 338 | /** | |
| 339 | * Handle an incoming OftFrame. If there is a payload associated | |
| 340 | * with this frame, then we remove the old watcher and add the | |
| 341 | * OFT watcher to read in the payload. | |
| 342 | */ | |
| 343 | void | |
| 344 | peer_oft_recv_frame(PeerConnection *conn, ByteStream *bs) | |
| 345 | { | |
| 346 | OftFrame frame; | |
| 347 | ||
| 348 | frame.type = byte_stream_get16(bs); | |
| 349 | byte_stream_getrawbuf(bs, frame.cookie, 8); | |
| 350 | frame.encrypt = byte_stream_get16(bs); | |
| 351 | frame.compress = byte_stream_get16(bs); | |
| 352 | frame.totfiles = byte_stream_get16(bs); | |
| 353 | frame.filesleft = byte_stream_get16(bs); | |
| 354 | frame.totparts = byte_stream_get16(bs); | |
| 355 | frame.partsleft = byte_stream_get16(bs); | |
| 356 | frame.totsize = byte_stream_get32(bs); | |
| 357 | frame.size = byte_stream_get32(bs); | |
| 358 | frame.modtime = byte_stream_get32(bs); | |
| 359 | frame.checksum = byte_stream_get32(bs); | |
| 360 | frame.rfrcsum = byte_stream_get32(bs); | |
| 361 | frame.rfsize = byte_stream_get32(bs); | |
| 362 | frame.cretime = byte_stream_get32(bs); | |
| 363 | frame.rfcsum = byte_stream_get32(bs); | |
| 364 | frame.nrecvd = byte_stream_get32(bs); | |
| 365 | frame.recvcsum = byte_stream_get32(bs); | |
| 366 | byte_stream_getrawbuf(bs, frame.idstring, 32); | |
| 367 | frame.flags = byte_stream_get8(bs); | |
| 368 | frame.lnameoffset = byte_stream_get8(bs); | |
| 369 | frame.lsizeoffset = byte_stream_get8(bs); | |
| 370 | byte_stream_getrawbuf(bs, frame.dummy, 69); | |
| 371 | byte_stream_getrawbuf(bs, frame.macfileinfo, 16); | |
| 372 | frame.nencode = byte_stream_get16(bs); | |
| 373 | frame.nlanguage = byte_stream_get16(bs); | |
| 374 | frame.name_length = bs->len - 186; | |
| 375 | frame.name = byte_stream_getraw(bs, frame.name_length); | |
| 376 | ||
| 377 | gaim_debug_info("oscar", "Incoming OFT frame from %s with " | |
| 378 | "type=0x%04x\n", conn->sn, frame.type); | |
| 379 | ||
| 380 | /* TODOFT: peer_oft_dirconvert_fromstupid(frame->name); */ | |
| 381 | ||
| 382 | if (frame.type == PEER_TYPE_PROMPT) | |
| 383 | peer_oft_recv_frame_prompt(conn, &frame); | |
| 384 | else if (frame.type == PEER_TYPE_ACK) | |
| 385 | peer_oft_recv_frame_ack(conn, &frame); | |
| 386 | else if (frame.type == PEER_TYPE_DONE) | |
| 387 | peer_oft_recv_frame_done(conn, &frame); | |
| 388 | ||
| 389 | free(frame.name); | |
| 390 | } | |
| 391 | ||
| 392 | /*******************************************************************/ | |
| 393 | /* Begin GaimXfer callbacks for use when receiving a file */ | |
| 394 | /*******************************************************************/ | |
| 395 | ||
| 396 | void | |
| 397 | peer_oft_recvcb_init(GaimXfer *xfer) | |
| 398 | { | |
| 399 | PeerConnection *conn; | |
| 400 | ||
| 401 | conn = xfer->data; | |
| 402 | conn->flags |= PEER_CONNECTION_FLAG_APPROVED; | |
| 403 | peer_connection_trynext(conn); | |
| 404 | } | |
| 405 | ||
| 406 | void | |
| 407 | peer_oft_recvcb_end(GaimXfer *xfer) | |
| 408 | { | |
| 409 | PeerConnection *conn; | |
| 410 | ||
| 411 | conn = xfer->data; | |
| 412 | ||
| 413 | /* Tell the other person that we've received everything */ | |
| 414 | conn->fd = conn->xfer->fd; | |
| 415 | conn->xfer->fd = -1; | |
| 416 | peer_oft_send_done(conn); | |
| 417 | ||
|
13609
a6fbfad454b6
[gaim-migrate @ 15994]
Mark Doliner <markdoliner@pidgin.im>
parents:
13608
diff
changeset
|
418 | conn->disconnect_reason = OSCAR_DISCONNECT_DONE; |
| 13593 | 419 | conn->sending_data_timer = gaim_timeout_add(100, |
| 420 | destroy_connection_when_done_sending_data, conn); | |
| 421 | } | |
| 422 | ||
| 423 | void | |
| 424 | peer_oft_recvcb_ack_recv(GaimXfer *xfer, const guchar *buffer, size_t size) | |
| 425 | { | |
| 426 | PeerConnection *conn; | |
| 427 | ||
| 428 | /* Update our rolling checksum. Like Walmart, yo. */ | |
| 429 | conn = xfer->data; | |
| 430 | conn->xferdata.recvcsum = peer_oft_checksum_chunk(buffer, | |
| 431 | size, conn->xferdata.recvcsum); | |
| 432 | } | |
| 433 | ||
| 434 | /*******************************************************************/ | |
| 435 | /* End GaimXfer callbacks for use when receiving a file */ | |
| 436 | /*******************************************************************/ | |
| 437 | ||
| 438 | /*******************************************************************/ | |
| 439 | /* Begin GaimXfer callbacks for use when sending a file */ | |
| 440 | /*******************************************************************/ | |
| 441 | ||
| 442 | void | |
| 443 | peer_oft_sendcb_init(GaimXfer *xfer) | |
| 444 | { | |
| 445 | PeerConnection *conn; | |
| 446 | ||
| 447 | conn = xfer->data; | |
| 448 | conn->flags |= PEER_CONNECTION_FLAG_APPROVED; | |
| 449 | ||
| 450 | /* Keep track of file transfer info */ | |
| 451 | conn->xferdata.totfiles = 1; | |
| 452 | conn->xferdata.filesleft = 1; | |
| 453 | conn->xferdata.totparts = 1; | |
| 454 | conn->xferdata.partsleft = 1; | |
| 455 | conn->xferdata.totsize = gaim_xfer_get_size(xfer); | |
| 456 | conn->xferdata.size = gaim_xfer_get_size(xfer); | |
| 457 | conn->xferdata.checksum = 0xffff0000; | |
| 458 | conn->xferdata.rfrcsum = 0xffff0000; | |
| 459 | conn->xferdata.rfcsum = 0xffff0000; | |
| 460 | conn->xferdata.recvcsum = 0xffff0000; | |
| 461 | strncpy((gchar *)conn->xferdata.idstring, "OFT_Windows ICBMFT V1.1 32", 31); | |
| 462 | conn->xferdata.modtime = 0; | |
| 463 | conn->xferdata.cretime = 0; | |
| 464 | xfer->filename = g_path_get_basename(xfer->local_filename); | |
| 465 | conn->xferdata.name = (guchar *)g_strdup(xfer->filename); | |
| 466 | conn->xferdata.name_length = strlen(xfer->filename); | |
| 467 | ||
| 468 | /* Calculating the checksum can take a very long time for large files */ | |
| 469 | gaim_debug_info("oscar","calculating file checksum\n"); | |
| 470 | conn->xferdata.checksum = peer_oft_checksum_file(xfer->local_filename); | |
| 471 | gaim_debug_info("oscar","checksum calculated\n"); | |
| 472 | ||
| 473 | /* Start the connection process */ | |
| 474 | peer_connection_trynext(conn); | |
| 475 | } | |
| 476 | ||
| 477 | /* | |
| 478 | * AIM file transfers aren't really meant to be thought | |
| 479 | * of as a transferring just a single file. The rendezvous | |
| 480 | * establishes a connection between two computers, and then | |
| 481 | * those computers can use the same connection for transferring | |
| 482 | * multiple files. So we don't want the Gaim core up and closing | |
| 483 | * the socket all willy-nilly. We want to do that in the oscar | |
| 484 | * prpl, whenever one side or the other says they're finished | |
| 485 | * using the connection. There might be a better way to intercept | |
| 486 | * the socket from the core... | |
| 487 | */ | |
| 488 | void | |
| 489 | peer_oft_sendcb_ack(GaimXfer *xfer, const guchar *buffer, size_t size) | |
| 490 | { | |
| 491 | PeerConnection *conn; | |
| 492 | ||
| 493 | conn = xfer->data; | |
| 494 | ||
| 495 | /* | |
| 496 | * If we're done sending, intercept the socket from the core ft code | |
| 497 | * and wait for the other guy to send the "done" OFT packet. | |
| 498 | */ | |
| 499 | if (gaim_xfer_get_bytes_remaining(xfer) <= 0) | |
| 500 | { | |
| 501 | gaim_input_remove(xfer->watcher); | |
| 502 | conn->fd = xfer->fd; | |
| 503 | xfer->fd = -1; | |
| 504 | conn->watcher_incoming = gaim_input_add(conn->fd, | |
| 505 | GAIM_INPUT_READ, peer_connection_recv_cb, conn); | |
| 506 | } | |
| 507 | } | |
| 508 | ||
| 509 | /*******************************************************************/ | |
| 510 | /* End GaimXfer callbacks for use when sending a file */ | |
| 511 | /*******************************************************************/ | |
| 512 | ||
| 513 | /*******************************************************************/ | |
| 514 | /* Begin GaimXfer callbacks for use when sending and receiving */ | |
| 515 | /*******************************************************************/ | |
| 516 | ||
| 517 | void | |
| 518 | peer_oft_cb_generic_cancel(GaimXfer *xfer) | |
| 519 | { | |
| 520 | PeerConnection *conn; | |
| 521 | ||
| 522 | conn = xfer->data; | |
| 523 | ||
| 524 | if (conn == NULL) | |
| 525 | return; | |
| 526 | ||
|
13609
a6fbfad454b6
[gaim-migrate @ 15994]
Mark Doliner <markdoliner@pidgin.im>
parents:
13608
diff
changeset
|
527 | peer_connection_destroy(conn, OSCAR_DISCONNECT_LOCAL_CLOSED); |
| 13593 | 528 | } |
| 529 | ||
| 530 | /*******************************************************************/ | |
| 531 | /* End GaimXfer callbacks for use when sending and receiving */ | |
| 532 | /*******************************************************************/ | |
| 533 | ||
| 534 | #if 0 | |
| 535 | /* | |
| 536 | * This little area in oscar.c is the nexus of file transfer code, | |
| 537 | * so I wrote a little explanation of what happens. I am such a | |
| 538 | * ninja. | |
| 539 | * | |
| 540 | * The series of events for a file send is: | |
| 541 | * -Create xfer and call gaim_xfer_request (this happens in oscar_ask_sendfile) | |
| 542 | * -User chooses a file and oscar_xfer_init is called. It establishes a | |
| 543 | * listening socket, then asks the remote user to connect to us (and | |
| 544 | * gives them the file name, port, IP, etc.) | |
| 545 | * -They connect to us and we send them an PEER_TYPE_PROMPT (this happens | |
| 546 | * in peer_oft_recv_frame_established) | |
| 547 | * -They send us an PEER_TYPE_ACK and then we start sending data | |
| 548 | * -When we finish, they send us an PEER_TYPE_DONE and they close the | |
| 549 | * connection. | |
| 550 | * -We get drunk because file transfer kicks ass. | |
| 551 | * | |
| 552 | * The series of events for a file receive is: | |
| 553 | * -Create xfer and call gaim_xfer request (this happens in incomingim_chan2) | |
| 554 | * -Gaim user selects file to name and location to save file to and | |
| 555 | * oscar_xfer_init is called | |
| 556 | * -It connects to the remote user using the IP they gave us earlier | |
| 557 | * -After connecting, they send us an PEER_TYPE_PROMPT. In reply, we send | |
| 558 | * them an PEER_TYPE_ACK. | |
| 559 | * -They begin to send us lots of raw data. | |
| 560 | * -When they finish sending data we send an PEER_TYPE_DONE and then close | |
| 561 | * the connection. | |
| 562 | * | |
| 563 | * Update August 2005: | |
| 564 | * The series of events for transfers has been seriously complicated by the addition | |
| 565 | * of transfer redirects and proxied connections. I could throw a whole lot of words | |
| 566 | * at trying to explain things here, but it probably wouldn't do much good. To get | |
| 567 | * a better idea of what happens, take a look at the diagrams and documentation | |
| 568 | * from my Summer of Code project. -- Jonathan Clark | |
| 569 | */ | |
| 570 | ||
| 571 | /** | |
| 572 | * Convert the directory separator from / (0x2f) to ^A (0x01) | |
| 573 | * | |
| 574 | * @param name The filename to convert. | |
| 575 | */ | |
| 576 | static void | |
| 577 | peer_oft_dirconvert_tostupid(char *name) | |
| 578 | { | |
| 579 | while (name[0]) { | |
| 580 | if (name[0] == 0x01) | |
| 581 | name[0] = G_DIR_SEPARATOR; | |
| 582 | name++; | |
| 583 | } | |
| 584 | } | |
| 585 | ||
| 586 | /** | |
| 587 | * Convert the directory separator from ^A (0x01) to / (0x2f) | |
| 588 | * | |
| 589 | * @param name The filename to convert. | |
| 590 | */ | |
| 591 | static void | |
| 592 | peer_oft_dirconvert_fromstupid(char *name) | |
| 593 | { | |
| 594 | while (name[0]) { | |
| 595 | if (name[0] == G_DIR_SEPARATOR) | |
| 596 | name[0] = 0x01; | |
| 597 | name++; | |
| 598 | } | |
| 599 | } | |
| 600 | #endif |