# HG changeset patch # User Mark Doliner # Date 1166902330 0 # Node ID 5176a9f30ba3c4e3265b93116a3780c6f2466448 # Parent c7acd154bcb38fc2cdd950e3980a4653aa4463f4 [gaim-migrate @ 18050] AIM/ICQ file transfer pausing an resuming. This should work, but could use a little more testing. It's a patch from Graham Booker with modifcations by me. Blame me if I broke file transfer for anything. committer: Tailor Script diff -r c7acd154bcb3 -r 5176a9f30ba3 ChangeLog --- a/ChangeLog Sat Dec 23 05:42:41 2006 +0000 +++ b/ChangeLog Sat Dec 23 19:32:10 2006 +0000 @@ -145,8 +145,10 @@ AIM/ICQ Features: * ICQ file transfer support with newer ICQ clients (Jonathan Clark, Google Summer of Code) - * Many overall improvements to OSCAR file transfers (Jonathan Clark, - Google Summer of Code) + * Many overall improvements to AIM and ICQ file transfers (Jonathan + Clark, Google Summer of Code) + * Support for pausing and resuming AIM and ICQ file transfers + (Graham Booker) * Ability to set ICQ "require authorization" and "web aware" setting (Ettore Simone) * ICQ encoding fix for offline buddies (Ilya Konstantinov) diff -r c7acd154bcb3 -r 5176a9f30ba3 ChangeLog.API --- a/ChangeLog.API Sat Dec 23 05:42:41 2006 +0000 +++ b/ChangeLog.API Sat Dec 23 19:32:10 2006 +0000 @@ -353,6 +353,8 @@ * gaim_gtk_roomlist_dialog_show_with_account * gaim_gtk_tree_view_search_equal_func to be used with gtk_tree_view_set_search_equal_func + * gaim_xfer_set_bytes_sent(). Sets the offset in the file to + read from or write to. Signals - Changed: (See the Doxygen docs for details on all signals.) * Signal propagation now stops after a handler returns a non-NULL value. diff -r c7acd154bcb3 -r 5176a9f30ba3 libgaim/ft.c --- a/libgaim/ft.c Sat Dec 23 05:42:41 2006 +0000 +++ b/libgaim/ft.c Sat Dec 23 19:32:10 2006 +0000 @@ -698,10 +698,17 @@ { g_return_if_fail(xfer != NULL); - if (xfer->size == 0) - xfer->bytes_remaining = size - xfer->bytes_sent; + xfer->size = size; + xfer->bytes_remaining = xfer->size - gaim_xfer_get_bytes_sent(xfer); +} - xfer->size = size; +void +gaim_xfer_set_bytes_sent(GaimXfer *xfer, size_t bytes_sent) +{ + g_return_if_fail(xfer != NULL); + + xfer->bytes_sent = bytes_sent; + xfer->bytes_remaining = gaim_xfer_get_size(xfer) - bytes_sent; } GaimXferUiOps * @@ -948,6 +955,8 @@ return; } + fseek(xfer->dest_fp, xfer->bytes_sent, SEEK_SET); + xfer->watcher = gaim_input_add(xfer->fd, cond, transfer_cb, xfer); xfer->start_time = time(NULL); @@ -978,9 +987,6 @@ type = gaim_xfer_get_type(xfer); - xfer->bytes_remaining = gaim_xfer_get_size(xfer); - xfer->bytes_sent = 0; - gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_STARTED); if (type == GAIM_XFER_RECEIVE) { diff -r c7acd154bcb3 -r 5176a9f30ba3 libgaim/ft.h --- a/libgaim/ft.h Sat Dec 23 05:42:41 2006 +0000 +++ b/libgaim/ft.h Sat Dec 23 19:32:10 2006 +0000 @@ -376,6 +376,21 @@ void gaim_xfer_set_size(GaimXfer *xfer, size_t size); /** + * Sets the current working position in the active file transfer. This + * can be used to jump backward in the file if the protocol detects + * that some bit of data needs to be resent or has been sent twice. + * + * It's used for pausing and resuming an oscar file transfer. + * + * @param xfer The file transfer. + * @param bytes_sent The new current position in the file. If we're + * sending a file then this is the byte that we will + * send. If we're receiving a file, this is the + * next byte that we expect to receive. + */ +void gaim_xfer_set_bytes_sent(GaimXfer *xfer, size_t bytes_sent); + +/** * Returns the UI operations structure for a file transfer. * * @param xfer The file transfer. diff -r c7acd154bcb3 -r 5176a9f30ba3 libgaim/protocols/oscar/oft.c --- a/libgaim/protocols/oscar/oft.c Sat Dec 23 05:42:41 2006 +0000 +++ b/libgaim/protocols/oscar/oft.c Sat Dec 23 19:32:10 2006 +0000 @@ -116,16 +116,26 @@ if ((fd = fopen(filename, "rb"))) { int bytes; - guint8 buffer[1024]; + guint8 *buffer = g_malloc(65536); - while ((bytes = fread(buffer, 1, 1024, fd)) != 0) + while ((bytes = fread(buffer, 1, 65536, fd)) != 0) checksum = peer_oft_checksum_chunk(buffer, bytes, checksum); + g_free(buffer); fclose(fd); } return checksum; } +static void +peer_oft_copy_xfer_data(PeerConnection *conn, OftFrame *frame) +{ + g_free(conn->xferdata.name); + + memcpy(&(conn->xferdata), frame, sizeof(OftFrame)); + conn->xferdata.name = g_memdup(frame->name, frame->name_length); +} + /** * Free any OFT related data. */ @@ -219,6 +229,17 @@ } static void +peer_oft_send_resume_accept(PeerConnection *conn) +{ + conn->xferdata.type = PEER_TYPE_RESUMEACCEPT; + + /* Fill in the cookie */ + memcpy(conn->xferdata.cookie, conn->cookie, 8); + + peer_oft_send(conn, &conn->xferdata); +} + +static void peer_oft_send_done(PeerConnection *conn) { conn->xferdata.type = PEER_TYPE_DONE; @@ -288,7 +309,7 @@ peer_oft_recv_frame_prompt(PeerConnection *conn, OftFrame *frame) { /* Record the file information and send an ack */ - memcpy(&conn->xferdata, frame, sizeof(OftFrame)); + peer_oft_copy_xfer_data(conn, frame); peer_oft_send_ack(conn); /* Remove our watchers and use the file transfer watchers in the core */ @@ -305,7 +326,7 @@ static void peer_oft_recv_frame_ack(PeerConnection *conn, OftFrame *frame) { - if (memcmp(conn->cookie, frame->cookie, 8)) + if (memcmp(conn->cookie, frame->cookie, 8) != 0) { gaim_debug_info("oscar", "Received an incorrect cookie. " "Closing connection.\n"); @@ -320,6 +341,36 @@ start_transfer_when_done_sending_data, conn); } +/** + * We are sending a file to someone else. They have just acknowledged our + * prompt and are asking to resume, so we accept their resume and await + * a resume ack. + */ +static void +peer_oft_recv_frame_resume(PeerConnection *conn, OftFrame *frame) +{ + if (memcmp(conn->cookie, frame->cookie, 8) != 0) + { + gaim_debug_info("oscar", "Received an incorrect cookie. " + "Closing connection.\n"); + peer_connection_destroy(conn, OSCAR_DISCONNECT_INVALID_DATA, NULL); + return; + } + + /* + * TODO: Check the checksums here. If they don't match then don't + * copy the data like below. + */ + + /* Copy resume data into internal structure */ + conn->xferdata.recvcsum = frame->recvcsum; + conn->xferdata.rfrcsum = frame->rfrcsum; + conn->xferdata.nrecvd = frame->nrecvd; + + gaim_xfer_set_bytes_sent(conn->xfer, frame->nrecvd); + peer_oft_send_resume_accept(conn); +} + /* * We just sent a file to someone. They said they got it and everything, * so we can close our direct connection and what not. @@ -378,12 +429,24 @@ /* TODOFT: peer_oft_dirconvert_fromstupid(frame->name); */ - if (frame.type == PEER_TYPE_PROMPT) - peer_oft_recv_frame_prompt(conn, &frame); - else if (frame.type == PEER_TYPE_ACK) - peer_oft_recv_frame_ack(conn, &frame); - else if (frame.type == PEER_TYPE_DONE) - peer_oft_recv_frame_done(conn, &frame); + switch(frame.type) + { + case PEER_TYPE_PROMPT: + peer_oft_recv_frame_prompt(conn, &frame); + break; + case PEER_TYPE_ACK: + case PEER_TYPE_RESUMEACK: + peer_oft_recv_frame_ack(conn, &frame); + break; + case PEER_TYPE_RESUME: + peer_oft_recv_frame_resume(conn, &frame); + break; + case PEER_TYPE_DONE: + peer_oft_recv_frame_done(conn, &frame); + break; + default: + break; + } free(frame.name); } diff -r c7acd154bcb3 -r 5176a9f30ba3 libgaim/protocols/oscar/peer.c --- a/libgaim/protocols/oscar/peer.c Sat Dec 23 05:42:41 2006 +0000 +++ b/libgaim/protocols/oscar/peer.c Sat Dec 23 19:32:10 2006 +0000 @@ -230,6 +230,7 @@ g_free(conn->proxyip); g_free(conn->clientip); g_free(conn->verifiedip); + g_free(conn->xferdata.name); gaim_circ_buffer_destroy(conn->buffer_outgoing); conn->od->peer_connections = g_slist_remove(conn->od->peer_connections, conn); diff -r c7acd154bcb3 -r 5176a9f30ba3 libgaim/protocols/oscar/peer.h --- a/libgaim/protocols/oscar/peer.h Sat Dec 23 05:42:41 2006 +0000 +++ b/libgaim/protocols/oscar/peer.h Sat Dec 23 19:32:10 2006 +0000 @@ -42,11 +42,11 @@ #define PEER_CONNECTION_FLAG_IS_INCOMING 0x0020 #define PEER_TYPE_PROMPT 0x0101 /* "I am going to send you this file, is that ok?" */ -#define PEER_TYPE_RESUMESOMETHING 0x0106 /* I really don't know */ +#define PEER_TYPE_RESUMEACCEPT 0x0106 /* We are accepting the resume */ #define PEER_TYPE_ACK 0x0202 /* "Yes, it is ok for you to send me that file" */ #define PEER_TYPE_DONE 0x0204 /* "I received that file with no problems, thanks a bunch" */ -#define PEER_TYPE_RESUME 0x0205 /* Resume transferring, sent by whoever paused? */ -#define PEER_TYPE_RESUMEACK 0x0207 /* Not really sure */ +#define PEER_TYPE_RESUME 0x0205 /* Resume transferring, sent by whoever receives */ +#define PEER_TYPE_RESUMEACK 0x0207 /* Our resume accept was ACKed */ #define PEER_TYPE_GETFILE_REQUESTLISTING 0x1108 /* "I have a listing.txt file, do you want it?" */ #define PEER_TYPE_GETFILE_RECEIVELISTING 0x1209 /* "Yes, please send me your listing.txt file" */