changeset 15261:5176a9f30ba3

[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 <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Sat, 23 Dec 2006 19:32:10 +0000
parents c7acd154bcb3
children b5dff06f9c84
files ChangeLog ChangeLog.API libgaim/ft.c libgaim/ft.h libgaim/protocols/oscar/oft.c libgaim/protocols/oscar/peer.c libgaim/protocols/oscar/peer.h
diffstat 7 files changed, 110 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- 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)
--- 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.
--- 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) {
--- 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.
--- 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);
 }
--- 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);
--- 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" */