pidgin: e6eebfe6: ft: Add infrastructure to allow a prpl t...

darkrain42 at pidgin.im darkrain42 at pidgin.im
Wed Aug 12 00:37:18 EDT 2009


-----------------------------------------------------------------
Revision: e6eebfe6a1965a7729803ad45b5d9bf3f4ea4330
Ancestor: 9953e3b86db32def937899bca8dc07d159f11eae
Author: darkrain42 at pidgin.im
Date: 2009-08-12T04:31:17
Branch: im.pidgin.pidgin
URL: http://d.pidgin.im/viewmtn/revision/info/e6eebfe6a1965a7729803ad45b5d9bf3f4ea4330

Modified files:
        ChangeLog.API libpurple/ft.c libpurple/ft.h

ChangeLog: 

ft: Add infrastructure to allow a prpl to moderate when to send packets.

The file transfer subsystem should now allow a prpl to serialize packets
(the way XMPP IBB does, where we wait for an ACK before sending the next
packet.) I think this will also be usable for msn and any other prpls
that currently try to open the local file manually.

-------------- next part --------------
============================================================
--- ChangeLog.API	078354f9aa830779e94166079a89db9e537815dc
+++ ChangeLog.API	cf717ca4347c54f8e7960a8b203dc13e09373db3
@@ -68,6 +68,7 @@ version 2.6.0 (??/??/2009):
 		* purple_strequal
 		* purple_utf8_strip_unprintables
 		* purple_util_fetch_url_request_len_with_account
+		* purple_xfer_prpl_ready
 		* purple_xfer_ui_ready
 		* xmlnode_from_file
 		* xmlnode_get_parent
============================================================
--- libpurple/ft.c	48a79ff9dc60eff2e893ab7c1a21d0999afa5369
+++ libpurple/ft.c	3f729c170caca25e0b9284b474742fe30bf5c35b
@@ -40,8 +40,35 @@ static GList *xfers;
 static PurpleXferUiOps *xfer_ui_ops = NULL;
 static GList *xfers;
 
+/*
+ * A hack to store more data since we can't extend the size of PurpleXfer
+ * easily.
+ */
+static GHashTable *xfers_data = NULL;
+
+typedef struct _PurpleXferPrivData {
+	/*
+	 * Used to moderate the file transfer when either the read/write ui_ops are
+	 * set or fd is not set. In those cases, the UI/prpl call the respective
+	 * function, which is somewhat akin to a fd watch being triggered.
+	 */
+	enum {
+		PURPLE_XFER_READY_NONE = 0x0,
+		PURPLE_XFER_READY_UI   = 0x1,
+		PURPLE_XFER_READY_PRPL = 0x2,
+	} ready;
+} PurpleXferPrivData;
+
 static int purple_xfer_choose_file(PurpleXfer *xfer);
 
+static void
+purple_xfer_priv_data_destroy(gpointer data)
+{
+	PurpleXferPrivData *priv = data;
+
+	g_free(priv);
+}
+
 GList *
 purple_xfers_get_all()
 {
@@ -53,6 +80,7 @@ purple_xfer_new(PurpleAccount *account, 
 {
 	PurpleXfer *xfer;
 	PurpleXferUiOps *ui_ops;
+	PurpleXferPrivData *priv;
 
 	g_return_val_if_fail(type    != PURPLE_XFER_UNKNOWN, NULL);
 	g_return_val_if_fail(account != NULL,              NULL);
@@ -70,6 +98,11 @@ purple_xfer_new(PurpleAccount *account, 
 	xfer->current_buffer_size = FT_INITIAL_BUFFER_SIZE;
 	xfer->fd = -1;
 
+	priv = g_new0(PurpleXferPrivData, 1);
+	priv->ready = PURPLE_XFER_READY_NONE;
+
+	g_hash_table_insert(xfers_data, xfer, priv);
+
 	ui_ops = purple_xfer_get_ui_ops(xfer);
 
 	if (ui_ops != NULL && ui_ops->new_xfer != NULL)
@@ -102,9 +135,11 @@ purple_xfer_destroy(PurpleXfer *xfer)
 	g_free(xfer->remote_ip);
 	g_free(xfer->local_filename);
 
+	g_hash_table_remove(xfers_data, xfer);
+
 	PURPLE_DBUS_UNREGISTER_POINTER(xfer);
+	xfers = g_list_remove(xfers, xfer);
 	g_free(xfer);
-	xfers = g_list_remove(xfers, xfer);
 }
 
 void
@@ -946,16 +981,15 @@ static void
 }
 
 static void
-transfer_cb(gpointer data, gint source, PurpleInputCondition condition)
+do_transfer(PurpleXfer *xfer)
 {
 	PurpleXferUiOps *ui_ops;
-	PurpleXfer *xfer = (PurpleXfer *)data;
 	guchar *buffer = NULL;
 	gssize r = 0;
 
 	ui_ops = purple_xfer_get_ui_ops(xfer);
-	
-	if (condition & PURPLE_INPUT_READ) {
+
+	if (xfer->type == PURPLE_XFER_RECEIVE) {
 		r = purple_xfer_read(xfer, &buffer);
 		if (r > 0) {
 			size_t wc;
@@ -975,7 +1009,7 @@ transfer_cb(gpointer data, gint source, 
 			g_free(buffer);
 			return;
 		}
-	} else if (condition & PURPLE_INPUT_WRITE) {
+	} else if (xfer->type == PURPLE_XFER_SEND) {
 		size_t result;
 		size_t s = MIN(purple_xfer_get_bytes_remaining(xfer), xfer->current_buffer_size);
 
@@ -1067,6 +1101,26 @@ static void
 }
 
 static void
+transfer_cb(gpointer data, gint source, PurpleInputCondition condition)
+{
+	PurpleXfer *xfer = data;
+
+	if (xfer->dest_fp == NULL) {
+		/* The UI is moderating its side manually */
+		PurpleXferPrivData *priv = g_hash_table_lookup(xfers_data, xfer);
+		if (0 == (priv->ready & PURPLE_XFER_READY_UI)) {
+			priv->ready |= PURPLE_XFER_READY_PRPL;
+
+			purple_input_remove(xfer->watcher);
+			xfer->watcher = 0;
+			return;
+		}
+	}
+
+	do_transfer(xfer);
+}
+
+static void
 begin_transfer(PurpleXfer *xfer, PurpleInputCondition cond)
 {
 	PurpleXferType type = purple_xfer_get_type(xfer);
@@ -1114,9 +1168,16 @@ purple_xfer_ui_ready(PurpleXfer *xfer)
 {
 	PurpleInputCondition cond;
 	PurpleXferType type;
+	PurpleXferPrivData *priv;
 
 	g_return_if_fail(xfer != NULL);
 
+	priv = g_hash_table_lookup(xfers_data, xfer);
+	priv->ready |= PURPLE_XFER_READY_UI;
+
+	if (0 == (priv->ready & PURPLE_XFER_READY_PRPL))
+		return;
+
 	type = purple_xfer_get_type(xfer);
 	if (type == PURPLE_XFER_SEND)
 		cond = PURPLE_INPUT_WRITE;
@@ -1126,10 +1187,31 @@ purple_xfer_ui_ready(PurpleXfer *xfer)
 	if (xfer->watcher == 0 && xfer->fd != -1)
 		xfer->watcher = purple_input_add(xfer->fd, cond, transfer_cb, xfer);
 
-	transfer_cb(xfer, 0, cond);
+	priv->ready = PURPLE_XFER_READY_NONE;
+
+	do_transfer(xfer);
 }
 
 void
+purple_xfer_prpl_ready(PurpleXfer *xfer)
+{
+	PurpleXferPrivData *priv;
+
+	g_return_if_fail(xfer != NULL);
+
+	priv = g_hash_table_lookup(xfers_data, xfer);
+	priv->ready |= PURPLE_XFER_READY_PRPL;
+
+	/* I don't think fwrite/fread are ever *not* ready */
+	if (xfer->dest_fp == NULL && 0 == (priv->ready & PURPLE_XFER_READY_UI))
+		return;
+
+	priv->ready = PURPLE_XFER_READY_NONE;
+
+	do_transfer(xfer);
+}
+
+void
 purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip,
 				unsigned int port)
 {
@@ -1394,6 +1476,9 @@ purple_xfers_init(void) {
 purple_xfers_init(void) {
 	void *handle = purple_xfers_get_handle();
 
+	xfers_data = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+	                                   NULL, purple_xfer_priv_data_destroy);
+
 	/* register signals */
 	purple_signal_register(handle, "file-recv-accept",
 	                     purple_marshal_VOID__POINTER, NULL, 1,
@@ -1440,6 +1525,9 @@ purple_xfers_uninit(void)
 
 	purple_signals_disconnect_by_handle(handle);
 	purple_signals_unregister_by_instance(handle);
+
+	g_hash_table_destroy(xfers_data);
+	xfers_data = NULL;
 }
 
 void
============================================================
--- libpurple/ft.h	6324b78c116985dc27147503d6d733e8423c53de
+++ libpurple/ft.h	8d4d3387e1bbbcde694d536ff749cf155fb94c64
@@ -664,14 +664,26 @@ void purple_xfer_conversation_write(Purp
 
 /**
  * Allows the UI to signal it's ready to send/receive data (depending on
- * the direction of the file transfer.
+ * the direction of the file transfer. Used when the UI is providing
+ * read/write/data_not_sent UI ops.
  *
- * @param xfer The file transfer for which data is ready.
+ * @param xfer The file transfer which is ready.
  *
  * @since 2.6.0
  */
 void purple_xfer_ui_ready(PurpleXfer *xfer);
 
+/**
+ * Allows the prpl to signal it's readh to send/receive data (depending on
+ * the direction of the file transfer. Used when the prpl provides read/write
+ * ops and cannot/does not provide a raw fd to the core.
+ *
+ * @param xfer The file transfer which is ready.
+ *
+ * @since 2.6.0
+ */
+void purple_xfer_prpl_ready(PurpleXfer *xfer);
+
 /*@}*/
 
 /**************************************************************************/


More information about the Commits mailing list