Mercurial > pidgin
changeset 27878:b7b25f580637
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.
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Wed, 12 Aug 2009 04:31:17 +0000 |
parents | e502112a03e7 |
children | b2dd32ce7353 |
files | ChangeLog.API libpurple/ft.c libpurple/ft.h |
diffstat | 3 files changed, 110 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog.API Tue Aug 11 15:57:54 2009 +0000 +++ b/ChangeLog.API Wed Aug 12 04:31:17 2009 +0000 @@ -68,6 +68,7 @@ * 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
--- a/libpurple/ft.c Tue Aug 11 15:57:54 2009 +0000 +++ b/libpurple/ft.c Wed Aug 12 04:31:17 2009 +0000 @@ -40,8 +40,35 @@ 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 @@ { 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 @@ 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 @@ 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 -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 @@ 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 +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 @@ { 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,7 +1187,28 @@ 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 @@ -1394,6 +1476,9 @@ 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_signals_disconnect_by_handle(handle); purple_signals_unregister_by_instance(handle); + + g_hash_table_destroy(xfers_data); + xfers_data = NULL; } void
--- a/libpurple/ft.h Tue Aug 11 15:57:54 2009 +0000 +++ b/libpurple/ft.h Wed Aug 12 04:31:17 2009 +0000 @@ -664,14 +664,26 @@ /** * 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); + /*@}*/ /**************************************************************************/