# HG changeset patch # User Mark Doliner # Date 1070859487 0 # Node ID 5f0bb52c06092cdf472a39621a6480f485cadb72 # Parent 622c9149609cf9f20d44882e17ef03bc216b9259 [gaim-migrate @ 8452] File transfer changes from marv. This fixes various ft related bugs, including: * Sometimes clicking cancel on a send would crash. * We seemed to leak the GaimXfer most of the time. * Choosing to not overwrite the file would cancel the receive altogether. This should fix all these issues. It would be nice if someone (SimGuy?) could test this for me, especially on windows, to make sure i didn't break anything. Jabber ft is untested, althoughi didn't make any changes in the jabber source. So, it should still work, i just can't comfirm it. Yahoo and OSCAR do still work. Amoung other things, this patch impliments some reference counting on the GaimXfer, so the ui can keep it around a while if it wants, without leaking it because we're afraid to destroy it. committer: Tailor Script diff -r 622c9149609c -r 5f0bb52c0609 src/ft.c --- a/src/ft.c Mon Dec 08 03:51:33 2003 +0000 +++ b/src/ft.c Mon Dec 08 04:58:07 2003 +0000 @@ -40,6 +40,7 @@ xfer = g_new0(GaimXfer, 1); + xfer->ref = 1; xfer->type = type; xfer->account = account; xfer->who = g_strdup(who); @@ -55,14 +56,14 @@ return xfer; } -void +static void gaim_xfer_destroy(GaimXfer *xfer) { GaimXferUiOps *ui_ops; g_return_if_fail(xfer != NULL); - if (!xfer->completed) + if (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_STARTED) gaim_xfer_cancel_local(xfer); ui_ops = gaim_xfer_get_ui_ops(xfer); @@ -83,6 +84,25 @@ } void +gaim_xfer_ref(GaimXfer *xfer) +{ + g_return_if_fail(xfer != NULL); + + xfer->ref++; +} + +void +gaim_xfer_unref(GaimXfer *xfer) +{ + g_return_if_fail(xfer != NULL); + + xfer->ref--; + + if (xfer->ref == 0) + gaim_xfer_destroy(xfer); +} + +void gaim_xfer_request(GaimXfer *xfer) { GaimXferUiOps *ui_ops; @@ -99,15 +119,11 @@ } void -gaim_xfer_request_accepted(GaimXfer *xfer, char *filename) +gaim_xfer_request_accepted(GaimXfer *xfer, const char *filename) { GaimXferType type; if (xfer == NULL || filename == NULL) { - - if (filename != NULL) - g_free(filename); - return; } @@ -126,8 +142,7 @@ gaim_xfer_error(type, xfer->who, msg); g_free(msg); - g_free(filename); - + gaim_xfer_unref(xfer); return; } @@ -139,8 +154,7 @@ gaim_xfer_error(type, xfer->who, msg); g_free(msg); - g_free(filename); - + gaim_xfer_unref(xfer); return; } @@ -153,7 +167,6 @@ gaim_xfer_set_local_filename(xfer, filename); } - g_free(filename); xfer->ops.init(xfer); } @@ -163,9 +176,10 @@ { g_return_if_fail(xfer != NULL); - gaim_xfer_destroy(xfer); + if (xfer->ops.request_denied != NULL) + xfer->ops.request_denied(xfer); - /* TODO */ + gaim_xfer_unref(xfer); } GaimXferType @@ -184,12 +198,24 @@ return xfer->account; } -GaimXferCancelType +GaimXferStatusType +gaim_xfer_get_status(const GaimXfer *xfer) +{ + g_return_val_if_fail(xfer != NULL, GAIM_XFER_STATUS_UNKNOWN); + + return xfer->status; +} + +gboolean gaim_xfer_is_canceled(const GaimXfer *xfer) { g_return_val_if_fail(xfer != NULL, TRUE); - return xfer->canceled; + if ((gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) || + (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_REMOTE)) + return TRUE; + else + return FALSE; } gboolean @@ -197,7 +223,7 @@ { g_return_val_if_fail(xfer != NULL, TRUE); - return xfer->completed; + return (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_DONE); } const char * @@ -285,11 +311,11 @@ } static void -gaim_xfer_set_canceled(GaimXfer *xfer, GaimXferCancelType canceled) +gaim_xfer_set_status(GaimXfer *xfer, GaimXferStatusType status) { g_return_if_fail(xfer != NULL); - xfer->canceled = canceled; + xfer->status = status; } void @@ -299,7 +325,8 @@ g_return_if_fail(xfer != NULL); - xfer->completed = completed; + if (completed == TRUE) + gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_DONE); ui_ops = gaim_xfer_get_ui_ops(xfer); @@ -357,6 +384,12 @@ xfer->ops.init = fnc; } +void gaim_xfer_set_request_denied_fnc(GaimXfer *xfer, void (*fnc)(GaimXfer *)) +{ + g_return_if_fail(xfer != NULL); + + xfer->ops.request_denied = fnc; +} void gaim_xfer_set_read_fnc(GaimXfer *xfer, size_t (*fnc)(char **, GaimXfer *)) @@ -565,6 +598,8 @@ 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) { cond = GAIM_INPUT_READ; @@ -597,7 +632,7 @@ g_return_if_fail(xfer != NULL); /* See if we are actually trying to cancel this. */ - if (!xfer->completed) { + if (gaim_xfer_get_status(xfer) != GAIM_XFER_STATUS_DONE) { gaim_xfer_cancel_local(xfer); return; } @@ -617,6 +652,8 @@ fclose(xfer->dest_fp); xfer->dest_fp = NULL; } + + gaim_xfer_unref(xfer); } void @@ -626,7 +663,7 @@ g_return_if_fail(xfer != NULL); - gaim_xfer_set_canceled(xfer, GAIM_XFER_CANCEL_LOCAL); + gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_LOCAL); if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { @@ -658,6 +695,8 @@ ui_ops->cancel_local(xfer); xfer->bytes_remaining = 0; + + gaim_xfer_unref(xfer); } void @@ -667,7 +706,7 @@ g_return_if_fail(xfer != NULL); - gaim_xfer_set_canceled(xfer, GAIM_XFER_CANCEL_REMOTE); + gaim_xfer_set_status(xfer, GAIM_XFER_STATUS_CANCEL_REMOTE); if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND) { @@ -699,6 +738,8 @@ ui_ops->cancel_remote(xfer); xfer->bytes_remaining = 0; + + gaim_xfer_unref(xfer); } void diff -r 622c9149609c -r 5f0bb52c0609 src/ft.h --- a/src/ft.h Mon Dec 08 03:51:33 2003 +0000 +++ b/src/ft.h Mon Dec 08 04:58:07 2003 +0000 @@ -41,12 +41,18 @@ } GaimXferType; +/** + * The different states of the xfer. + */ typedef enum { - GAIM_XFER_CANCEL_NOT = 0, - GAIM_XFER_CANCEL_LOCAL, - GAIM_XFER_CANCEL_REMOTE -} GaimXferCancelType; + GAIM_XFER_STATUS_UNKNOWN = 0, /**< Unknown, the xfer may be null. */ + GAIM_XFER_STATUS_NOT_STARTED, /**< It hasn't started yet. */ + GAIM_XFER_STATUS_STARTED, /**< gaim_xfer_start has been called. */ + GAIM_XFER_STATUS_DONE, /**< The xfer completed successfully. */ + GAIM_XFER_STATUS_CANCEL_LOCAL, /**< The xfer was canceled by us. */ + GAIM_XFER_STATUS_CANCEL_REMOTE /**< The xfer was canceled by the other end, or we couldn't connect. */ +} GaimXferStatusType; /** * File transfer UI operations. @@ -72,6 +78,7 @@ */ struct _GaimXfer { + guint ref; /**in_list = TRUE; gaim_gtkxfer_dialog_show(dialog); @@ -823,12 +833,12 @@ if (data == NULL) return; - gtk_list_store_remove(GTK_LIST_STORE(dialog->model), &data->iter); + if (!data->in_list) + return; - g_free(data->name); - g_free(data); + data->in_list = FALSE; - xfer->ui_data = NULL; + gtk_list_store_remove(GTK_LIST_STORE(dialog->model), &data->iter); dialog->num_transfers--; @@ -836,6 +846,8 @@ gaim_gtkxfer_dialog_hide(dialog); else ensure_row_selected(dialog); + + gaim_xfer_unref(xfer); } void @@ -846,7 +858,6 @@ GdkPixbuf *pixbuf; gchar *status; - g_return_if_fail(dialog != NULL); g_return_if_fail(xfer != NULL); @@ -856,19 +867,8 @@ return; - if ((gaim_xfer_is_canceled(xfer) == GAIM_XFER_CANCEL_LOCAL) && (dialog->auto_clear)) { - gtk_list_store_remove(GTK_LIST_STORE(dialog->model), &data->iter); - - g_free(data->name); - g_free(data); - - xfer->ui_data = NULL; - - dialog->num_transfers--; - - if (dialog->num_transfers == 0 && !dialog->keep_open) - gaim_gtkxfer_dialog_hide(dialog); - + if ((gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) && (dialog->auto_clear)) { + gaim_gtkxfer_dialog_remove_xfer(dialog, xfer); return; } @@ -878,7 +878,7 @@ GAIM_STOCK_FILE_CANCELED, GTK_ICON_SIZE_MENU, NULL); - if (gaim_xfer_is_canceled(xfer) == GAIM_XFER_CANCEL_LOCAL) + if (gaim_xfer_get_status(xfer) == GAIM_XFER_STATUS_CANCEL_LOCAL) status = _("Canceled"); else status = _("Failed"); @@ -907,6 +907,9 @@ if ((data = GAIM_GTKXFER(xfer)) == NULL) return; + if (data->in_list == FALSE) + return; + size_str = gaim_str_size_to_units(gaim_xfer_get_size(xfer)); remaining_str = gaim_str_size_to_units(gaim_xfer_get_bytes_remaining(xfer)); @@ -958,13 +961,26 @@ static void gaim_gtkxfer_destroy(GaimXfer *xfer) { - gaim_gtkxfer_dialog_remove_xfer(xfer_dialog, xfer); + GaimGtkXferUiData *data; + + data = GAIM_GTKXFER(xfer); + if (data) { + if (data->name) + g_free(data->name); + g_free(data); + xfer->ui_data = NULL; + } } static gboolean choose_file_close_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) { - gaim_xfer_request_denied((GaimXfer *)user_data); + GaimXfer *xfer = (GaimXfer *)user_data; + GaimGtkXferUiData *data; + + data = GAIM_GTKXFER(xfer); + data->filesel = NULL; + gaim_xfer_request_denied(xfer); return FALSE; } @@ -976,11 +992,9 @@ GaimGtkXferUiData *data; data = GAIM_GTKXFER(xfer); - - gaim_xfer_request_denied(xfer); - gtk_widget_destroy(data->filesel); data->filesel = NULL; + gaim_xfer_request_denied(xfer); } static int @@ -992,10 +1006,7 @@ gaim_xfer_request_accepted(xfer, data->name); - /* - * No, we don't want to free data->name. gaim_xfer_request_accepted - * will deal with it. - */ + g_free(data->name); data->name = NULL; return 0; @@ -1011,7 +1022,7 @@ g_free(data->name); data->name = NULL; - gaim_xfer_request_denied(xfer); + choose_file(xfer); return 0; } @@ -1068,7 +1079,7 @@ G_CALLBACK(dont_overwrite_cb)); } else { - gaim_xfer_request_accepted(xfer, g_strdup(name)); + gaim_xfer_request_accepted(xfer, name); } } @@ -1174,25 +1185,20 @@ gaim_gtkxfer_update_progress(GaimXfer *xfer, double percent) { gaim_gtkxfer_dialog_update_xfer(xfer_dialog, xfer); - - /* See if it's removed. */ - /* XXX - This caused some bad stuff, and I don't see a point to it */ -#if 0 - if (xfer->ui_data == NULL) - gaim_xfer_destroy(xfer); -#endif } static void gaim_gtkxfer_cancel_local(GaimXfer *xfer) { - gaim_gtkxfer_dialog_cancel_xfer(xfer_dialog, xfer); + if (xfer_dialog) + gaim_gtkxfer_dialog_cancel_xfer(xfer_dialog, xfer); } static void gaim_gtkxfer_cancel_remote(GaimXfer *xfer) { - gaim_gtkxfer_dialog_cancel_xfer(xfer_dialog, xfer); + if (xfer_dialog) + gaim_gtkxfer_dialog_cancel_xfer(xfer_dialog, xfer); } static GaimXferUiOps ops = diff -r 622c9149609c -r 5f0bb52c0609 src/protocols/oscar/oscar.c --- a/src/protocols/oscar/oscar.c Mon Dec 08 03:51:33 2003 +0000 +++ b/src/protocols/oscar/oscar.c Mon Dec 08 04:58:07 2003 +0000 @@ -717,7 +717,7 @@ while (od->file_transfers) { GaimXfer *xfer; xfer = (GaimXfer *)od->file_transfers->data; - gaim_xfer_destroy(xfer); + gaim_xfer_cancel_local(xfer); } while (od->requesticon) { char *sn = od->requesticon->data; diff -r 622c9149609c -r 5f0bb52c0609 src/protocols/yahoo/yahoo_filexfer.c --- a/src/protocols/yahoo/yahoo_filexfer.c Mon Dec 08 03:51:33 2003 +0000 +++ b/src/protocols/yahoo/yahoo_filexfer.c Mon Dec 08 04:58:07 2003 +0000 @@ -68,7 +68,7 @@ return; if (source < 0) { gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to connect.")); - gaim_xfer_end(xfer); + gaim_xfer_cancel_remote(xfer); return; } @@ -122,6 +122,7 @@ GaimConnection *gc; GaimAccount *account; struct yahoo_data *yd; + char *filename; gaim_debug(GAIM_DEBUG_INFO, "yahoo", "AAA - in yahoo_sendfile_connected\n"); @@ -138,7 +139,7 @@ if (source < 0) { gaim_xfer_error(GAIM_XFER_RECEIVE, xfer->who, _("Unable to connect.")); - gaim_xfer_end(xfer); + gaim_xfer_cancel_remote(xfer); return; } @@ -153,7 +154,8 @@ yahoo_packet_hash(pkt, 0, gaim_connection_get_display_name(gc)); yahoo_packet_hash(pkt, 5, xfer->who); yahoo_packet_hash(pkt, 14, ""); - yahoo_packet_hash(pkt, 27, gaim_xfer_get_local_filename(xfer)); + filename = g_path_get_basename(gaim_xfer_get_local_filename(xfer)); + yahoo_packet_hash(pkt, 27, filename); yahoo_packet_hash(pkt, 28, size); content_length = YAHOO_PACKET_HDRLEN + yahoo_packet_length(pkt); @@ -179,6 +181,7 @@ g_free(size); g_free(post); g_free(buf); + g_free(filename); } static void yahoo_xfer_init(GaimXfer *xfer) @@ -517,5 +520,5 @@ gaim_xfer_set_write_fnc(xfer, yahoo_xfer_write); /* Now perform the request */ - gaim_xfer_request_accepted(xfer, g_strdup(file)); + gaim_xfer_request_accepted(xfer, file); }