diff options
Diffstat (limited to 'protocols/purple/ft.c')
-rw-r--r-- | protocols/purple/ft.c | 79 |
1 files changed, 68 insertions, 11 deletions
diff --git a/protocols/purple/ft.c b/protocols/purple/ft.c index 320fc887..81fee8d0 100644 --- a/protocols/purple/ft.c +++ b/protocols/purple/ft.c @@ -41,6 +41,7 @@ struct prpl_xfer_data { int fd; char *fn, *handle; gboolean ui_wants_data; + int timeout; }; static file_transfer_t *next_ft; @@ -63,13 +64,47 @@ static void prpl_xfer_canceled(struct file_transfer *ft, char *reason) { struct prpl_xfer_data *px = ft->data; - purple_xfer_request_denied(px->xfer); + if (px->xfer) { + if (!purple_xfer_is_completed(px->xfer) && !purple_xfer_is_canceled(px->xfer)) { + purple_xfer_cancel_local(px->xfer); + } + px->xfer->ui_data = NULL; + purple_xfer_unref(px->xfer); + px->xfer = NULL; + } +} + +static void prpl_xfer_free(struct file_transfer *ft) +{ + struct prpl_xfer_data *px = ft->data; + struct purple_data *pd = px->ic->proto_data; + + pd->filetransfers = g_slist_remove(pd->filetransfers, px); + + if (px->xfer) { + px->xfer->ui_data = NULL; + purple_xfer_unref(px->xfer); + } + + if (px->timeout) { + b_event_remove(px->timeout); + } + + g_free(px->fn); + g_free(px->handle); + if (px->fd >= 0) { + close(px->fd); + } + g_free(px); } static void prplcb_xfer_new(PurpleXfer *xfer) { + purple_xfer_ref(xfer); + if (purple_xfer_get_type(xfer) == PURPLE_XFER_RECEIVE) { struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); + struct purple_data *pd; xfer->ui_data = px; px->xfer = xfer; @@ -77,6 +112,9 @@ static void prplcb_xfer_new(PurpleXfer *xfer) px->fd = -1; px->ic = purple_ic_by_pa(xfer->account); + pd = px->ic->proto_data; + pd->filetransfers = g_slist_prepend(pd->filetransfers, px); + purple_xfer_set_local_filename(xfer, px->fn); /* Sadly the xfer struct is still empty ATM so come back after @@ -111,6 +149,7 @@ static gboolean prplcb_xfer_new_send_cb(gpointer data, gint fd, b_input_conditio px->ft->accept = prpl_xfer_accept; px->ft->canceled = prpl_xfer_canceled; + px->ft->free = prpl_xfer_free; px->ft->write_request = prpl_xfer_write_request; return FALSE; @@ -163,17 +202,13 @@ static gboolean prpl_xfer_write_request(struct file_transfer *ft) } -/* Generic (IM<>UI): */ static void prplcb_xfer_destroy(PurpleXfer *xfer) { struct prpl_xfer_data *px = xfer->ui_data; - g_free(px->fn); - g_free(px->handle); - if (px->fd >= 0) { - close(px->fd); + if (px) { + px->xfer = NULL; } - g_free(px); } static void prplcb_xfer_progress(PurpleXfer *xfer, double percent) @@ -223,9 +258,9 @@ static void prplcb_xfer_cancel_remote(PurpleXfer *xfer) { struct prpl_xfer_data *px = xfer->ui_data; - if (px->ft) { + if (px && px->ft) { imcb_file_canceled(px->ic, px->ft, "Canceled by remote end"); - } else { + } else if (px) { /* px->ft == NULL for sends, because of the two stages. :-/ */ imcb_error(px->ic, "File transfer cancelled by remote end"); } @@ -239,10 +274,12 @@ static gboolean purple_transfer_request_cb(gpointer data, gint fd, b_input_condi void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char *handle) { struct prpl_xfer_data *px = g_new0(struct prpl_xfer_data, 1); + struct purple_data *pd; char *dir, *basename; ft->data = px; px->ft = ft; + px->ft->free = prpl_xfer_free; dir = g_strdup("/tmp/bitlbee-purple-ft.XXXXXX"); if (!mkdtemp(dir)) { @@ -271,10 +308,13 @@ void purple_transfer_request(struct im_connection *ic, file_transfer_t *ft, char px->ic = ic; px->handle = g_strdup(handle); + pd = px->ic->proto_data; + pd->filetransfers = g_slist_prepend(pd->filetransfers, px); + imcb_log(ic, "Due to libpurple limitations, the file has to be cached locally before proceeding with the actual file transfer. Please wait..."); - b_timeout_add(0, purple_transfer_request_cb, ft); + px->timeout = b_timeout_add(0, purple_transfer_request_cb, ft); } static void purple_transfer_forward(struct file_transfer *ft) @@ -294,6 +334,8 @@ static gboolean purple_transfer_request_cb(gpointer data, gint fd, b_input_condi file_transfer_t *ft = data; struct prpl_xfer_data *px = ft->data; + px->timeout = 0; + if (ft->write == NULL) { ft->write = prpl_xfer_write; imcb_file_recv_start(px->ic, ft); @@ -321,12 +363,27 @@ static gboolean prpl_xfer_write(struct file_transfer *ft, char *buffer, unsigned imcb_file_finished(px->ic, ft); px->ft = NULL; } else { - b_timeout_add(0, purple_transfer_request_cb, ft); + px->timeout = b_timeout_add(0, purple_transfer_request_cb, ft); } return TRUE; } +void purple_transfer_cancel_all(struct im_connection *ic) +{ + struct purple_data *pd = ic->proto_data; + + while (pd->filetransfers) { + struct prpl_xfer_data *px = pd->filetransfers->data; + + if (px->ft) { + imcb_file_canceled(ic, px->ft, "Logging out"); + } + + pd->filetransfers = g_slist_remove(pd->filetransfers, px); + } +} + PurpleXferUiOps bee_xfer_uiops = |