# HG changeset patch
# Node ID 5d0a7806024b
# Parent  1f52237ebd7a
diff --git a/ChangeLog.API b/ChangeLog.API
--- a/ChangeLog.API
+++ b/ChangeLog.API
@@ -205,26 +205,11 @@
 		* Signal registration now uses GTypes instead of PurpleValues.  See
 		  SIGNAL-HOWTO for more information.
 		* purple_whiteboard_create renamed to purple_whiteboard_new
-		* purple_xfer_get_bytes_remaining now returns a goffset
-		* purple_xfer_get_bytes_sent now returns a goffset
-		* purple_xfer_get_size now returns a goffset
-		* purple_xfer_is_canceled renamed to purple_xfer_is_cancelled
-		* PurpleXfer is now a GObject. Please see the documentation for details.
-		* purple_xfer_get_type renamed to purple_xfer_get_xfer_type
-		* PurpleXferStatusType renamed to PurpleXferStatus
-		* PURPLE_XFER_* prefix of PurpleXferType enums changed to
-		  PURPLE_XFER_TYPE_*
-		* purple_xfer_set_bytes_sent now takes a goffset as the bytes_sent
-		  parameter
-		* purple_xfer_set_size now takes a goffset as the size parameter
 		* PurpleCertificateVerificationStatus enumeration is now merged with
 		  internal flags, thus removing PURPLE_CERTIFICATE_INVALID and
 		  replacing it with more precise errors.
 		* PurpleConnectionUiOps.report_disconnect now passes a
 		  PurpleConnectionError as the second parameter
-		* PurpleXfer.bytes_remaining is now a goffset
-		* PurpleXfer.bytes_sent is now a goffset
-		* PurpleXfer.size is now a goffset
 		* PurpleCertificateScheme.get_times now uses gint64 instead of
 		  time_t to represent times
 		* purple_certificate_get_times now uses gint64 instead of
@@ -829,20 +814,55 @@
 		* PurpleValue, use GValue instead.
 		* purple_whiteboard_get_ui_data and purple_whiteboard_set_ui_data, use
 		  g_object_set_data instead.
-		* PurpleXferUiOps.add_thumbnail. Use PurpleXfer::add-thumbnail
-		  instead.
-		* PurpleXferUiOps.add_xfer. Use notify::visible on #PurpleXfer
-		  objects instead.
-		* PurpleXferUiOps.cancel_local and
-		  PurpleXferUiOps.cancel_remote. Use notify::status on
-		  #PurpleXfer objects instead.
-		* PurpleXferUiOps.data_not_sent. Use PurpleXfer::data-not-sent
-		  instead.
-		* PurpleXferUiOps.destroy
-		* PurpleXferUiOps.ui_read. Use PurpleXfer::read-local instead.
-		* PurpleXferUiOps.ui_write. Use PurpleXfer::write-local instead.
-		* PurpleXferUiOps.update_progress. Use notify::progress on
-		  #PurpleXfer objects instead.
+		* PurpleXfer
+		* PurpleXferUiOps
+		* purple_xfer_cancel_local
+		* purple_xfer_cancel_remote
+		* purple_xfer_conversation_write
+		* purple_xfer_end
+		* purple_xfer_error
+		* purple_xfer_get_account
+		* purple_xfer_get_bytes_remaining
+		* purple_xfer_get_bytes_sent
+		* purple_xfer_get_end_time
+		* purple_xfer_get_filename
+		* purple_xfer_get_local_filename
+		* purple_xfer_get_local_port
+		* purple_xfer_get_progress
+		* purple_xfer_get_remote_ip
+		* purple_xfer_get_remote_port
+		* purple_xfer_get_remote_user
+		* purple_xfer_get_size
+		* purple_xfer_get_start_time
+		* purple_xfer_get_status
+		* purple_xfer_get_thumbnail
+		* purple_xfer_get_thumbnail_mimetype
+		* purple_xfer_get_ui_ops
+		* purple_xfer_is_completed
+		* purple_xfer_new
+		* purple_xfer_prepare_thumbnail
+		* purple_xfer_read
+		* purple_xfer_read_file
+		* purple_xfer_request
+		* purple_xfer_request_accepted
+		* purple_xfer_request_denied
+		* purple_xfer_set_bytes_sent
+		* purple_xfer_set_completed
+		* purple_xfer_set_filename
+		* purple_xfer_set_local_filename
+		* purple_xfer_set_message
+		* purple_xfer_set_size
+		* purple_xfer_set_thumbnail
+		* purple_xfer_start
+		* purple_xfer_ui_ready
+		* purple_xfer_write
+		* purple_xfer_write_file
+		* purple_xfers_get_all
+		* purple_xfers_get_handle
+		* purple_xfers_get_ui_ops
+		* purple_xfers_init
+		* purple_xfers_set_ui_ops
+		* purple_xfers_uninit
 		* quitting signal
 		* serv_got_attention
 		* serv_send_attention
diff --git a/doc/reference/libpurple/libpurple.toml.in b/doc/reference/libpurple/libpurple.toml.in
--- a/doc/reference/libpurple/libpurple.toml.in
+++ b/doc/reference/libpurple/libpurple.toml.in
@@ -48,7 +48,6 @@
 	"signals_core.md",
 	"signals_jabber.md",
 	"signals_savedstatus.md",
-	"signals_xfer.md",
 	"tut_c_plugins.md",
 ]
 content_images = [
diff --git a/doc/reference/libpurple/meson.build b/doc/reference/libpurple/meson.build
--- a/doc/reference/libpurple/meson.build
+++ b/doc/reference/libpurple/meson.build
@@ -10,7 +10,6 @@
 	'signals_core.md',
 	'signals_jabber.md',
 	'signals_savedstatus.md',
-	'signals_xfer.md',
 	'tut_c_plugins.md',
 ]
 
diff --git a/doc/reference/libpurple/signals_xfer.md b/doc/reference/libpurple/signals_xfer.md
deleted file mode 100644
--- a/doc/reference/libpurple/signals_xfer.md
+++ /dev/null
@@ -1,26 +0,0 @@
-Title: File Transfer Signals
-Slug: file-transfer-signals
-
-## File Transfer Signals
-
-### Signal List
-
-* [file-recv-request](#file-recv-request)
-
-### Signal Detail
-
-#### file-recv-request
-
-```c
-void user_function(PurpleXfer *xfer, gpointer data);
-```
-
-Emitted before the user is prompted for an incoming file-transfer. Plugins can intercept the signal to auto-accept/auto-reject the requests. To auto-accept the file transfer, use purple_xfer_request_accepted(). To auto-reject, set the status of the xfer to PURPLE_XFER_STATUS_CANCEL_LOCAL.
-
-**Parameters:**
-
-**xfer**
-: The file transfer.
-
-**data**
-: User data.
diff --git a/libpurple/core.c b/libpurple/core.c
--- a/libpurple/core.c
+++ b/libpurple/core.c
@@ -31,7 +31,6 @@
 #include "conversations.h"
 #include "core.h"
 #include "debug.h"
-#include "xfer.h"
 #include "idle.h"
 #include "image-store.h"
 #include "network.h"
@@ -181,7 +180,6 @@
 
 	purple_network_init();
 	purple_proxy_init();
-	purple_xfers_init();
 	purple_idle_init();
 	purple_idle_manager_startup();
 
@@ -253,7 +251,6 @@
 	purple_savedstatuses_uninit();
 	purple_statuses_uninit();
 	purple_accounts_uninit();
-	purple_xfers_uninit();
 	purple_proxy_uninit();
 	_purple_image_store_uninit();
 	purple_network_uninit();
diff --git a/libpurple/meson.build b/libpurple/meson.build
--- a/libpurple/meson.build
+++ b/libpurple/meson.build
@@ -124,7 +124,6 @@
 	'signals.c',
 	'status.c',
 	'util.c',
-	'xfer.c',
 	'xmlnode.c'
 ]
 
@@ -241,7 +240,6 @@
 	'signals.h',
 	'status.h',
 	'util.h',
-	'xfer.h',
 	'xmlnode.h',
 ]
 
@@ -330,7 +328,6 @@
 	'purpletyping.h',
 	'roomlist.h',
 	'status.h',
-	'xfer.h',
 	'xmlnode.h'
 ]
 
diff --git a/libpurple/plugins/autoaccept/meson.build b/libpurple/plugins/autoaccept/meson.build
--- a/libpurple/plugins/autoaccept/meson.build
+++ b/libpurple/plugins/autoaccept/meson.build
@@ -3,7 +3,9 @@
     gnu_symbol_visibility : 'hidden',
     dependencies : [libpurple_dep, glib],
     name_prefix : '',
-    install : true, install_dir : PURPLE_PLUGINDIR)
+    install : true,
+    install_dir : PURPLE_PLUGINDIR,
+    build_by_default : false)
 
 settings_schemas = [
   'im.pidgin.Purple.plugin.AutoAccept.gschema.xml',
diff --git a/libpurple/server.c b/libpurple/server.c
--- a/libpurple/server.c
+++ b/libpurple/server.c
@@ -41,7 +41,6 @@
 #include "server.h"
 #include "status.h"
 #include "util.h"
-#include "xfer.h"
 
 unsigned int
 purple_serv_send_typing(PurpleConnection *gc, const char *name, PurpleIMTypingState state)
diff --git a/libpurple/xfer.h b/libpurple/xfer.h
deleted file mode 100644
--- a/libpurple/xfer.h
+++ /dev/null
@@ -1,985 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#endif
-
-#ifndef PURPLE_XFER_H
-#define PURPLE_XFER_H
-
-#define PURPLE_TYPE_XFER_UI_OPS      (purple_xfer_ui_ops_get_type())
-
-/**************************************************************************/
-/* Data Structures                                                        */
-/**************************************************************************/
-typedef struct _PurpleXferUiOps PurpleXferUiOps;
-
-#include <glib.h>
-#include <stdio.h>
-
-#include "connection.h"
-#include "purpleaccount.h"
-#include "purpleprotocol.h"
-#include "purpleversion.h"
-
-/**
- * PurpleXferType:
- * @PURPLE_XFER_TYPE_UNKNOWN: Unknown file transfer type.
- * @PURPLE_XFER_TYPE_SEND:    File sending.
- * @PURPLE_XFER_TYPE_RECEIVE: File receiving.
- *
- * Types of file transfers.
- *
- * Since: 2.0
- */
-typedef enum
-{
-	PURPLE_XFER_TYPE_UNKNOWN = 0,
-	PURPLE_XFER_TYPE_SEND,
-	PURPLE_XFER_TYPE_RECEIVE
-} PurpleXferType;
-
-/**
- * PurpleXferStatus:
- * @PURPLE_XFER_STATUS_UNKNOWN:       Unknown, the xfer may be null.
- * @PURPLE_XFER_STATUS_NOT_STARTED:   It hasn't started yet.
- * @PURPLE_XFER_STATUS_ACCEPTED:      Receive accepted, but destination file
- *                                    not selected yet.
- * @PURPLE_XFER_STATUS_STARTED:       purple_xfer_start has been called.
- * @PURPLE_XFER_STATUS_DONE:          The xfer completed successfully.
- * @PURPLE_XFER_STATUS_CANCEL_LOCAL:  The xfer was cancelled by us.
- * @PURPLE_XFER_STATUS_CANCEL_REMOTE: The xfer was cancelled by the other end,
- *                                    or we couldn't connect.
- *
- * The different states of the xfer.
- *
- * Since: 2.0
- */
-typedef enum
-{
-	PURPLE_XFER_STATUS_UNKNOWN = 0,
-	PURPLE_XFER_STATUS_NOT_STARTED,
-	PURPLE_XFER_STATUS_ACCEPTED,
-	PURPLE_XFER_STATUS_STARTED,
-	PURPLE_XFER_STATUS_DONE,
-	PURPLE_XFER_STATUS_CANCEL_LOCAL,
-	PURPLE_XFER_STATUS_CANCEL_REMOTE
-} PurpleXferStatus;
-
-G_BEGIN_DECLS
-
-#define PURPLE_TYPE_XFER             (purple_xfer_get_type())
-
-/**
- * PurpleXfer:
- *
- * A representation of a file transfer.
- *
- * Since: 2.0
- */
-
-PURPLE_AVAILABLE_IN_ALL
-G_DECLARE_DERIVABLE_TYPE(PurpleXfer, purple_xfer, PURPLE, XFER, GObject)
-
-/**
- * PurpleXferUiOps:
- * @new_xfer: UI op that's called after a new transfer is created.
- *
- * File transfer UI operations.
- *
- * Any UI representing a file transfer must assign a filled-out
- * PurpleXferUiOps structure to the purple_xfer.
- *
- * Since: 2.0
- */
-struct _PurpleXferUiOps
-{
-	void (*new_xfer)(PurpleXfer *xfer);
-};
-
-/**
- * PurpleXferClass:
- * @init: Called when the file transfer is accepted by the user.  Must call
- *   purple_xfer_start() and must be implemented.
- * @request_denied: Called when the file transfer is denied by the other side.
- * @start: Called to start the file transfer.
- * @end: Called when the file transfer should end.
- * @cancel_send: Handler for cancelling a sending file transfer.
- * @cancel_recv: Handler for cancelling a receiving file transfer.
- * @read: Called when reading data from the file transfer.
- * @write: Called when writing data to the file transfer.
- * @ack: Called when a file transfer is acknowledged.
- * @open_local: The vfunc for PurpleXfer::open-local. Since: 3.0
- * @query_local: The vfunc for PurpleXfer::query-local. Since: 3.0
- * @read_local: The vfunc for PurpleXfer::read-local. Since: 3.0
- * @write_local: The vfunc for PurpleXfer::write-local. Since: 3.0
- * @data_not_sent: The vfunc for PurpleXfer::data-not-sent. Since: 3.0
- *
- * Base class for all #PurpleXfer's
- *
- * Since: 3.0
- */
-struct _PurpleXferClass
-{
-	GObjectClass parent_class;
-
-	void (*init)(PurpleXfer *xfer);
-	void (*request_denied)(PurpleXfer *xfer);
-	void (*start)(PurpleXfer *xfer);
-	void (*end)(PurpleXfer *xfer);
-	void (*cancel_send)(PurpleXfer *xfer);
-	void (*cancel_recv)(PurpleXfer *xfer);
-	gssize (*read)(PurpleXfer *xfer, guchar **buffer, gsize size);
-	gssize (*write)(PurpleXfer *xfer, const guchar *buffer, gsize size);
-	void (*ack)(PurpleXfer *xfer, const guchar *buffer, gsize size);
-
-	gboolean (*open_local)(PurpleXfer *xfer);
-	gboolean (*query_local)(PurpleXfer *xfer, const gchar *filename);
-	gssize (*read_local)(PurpleXfer *xfer, guchar *buffer, gssize size);
-	gssize (*write_local)(PurpleXfer *xfer, const guchar *buffer, gssize size);
-	gboolean (*data_not_sent)(PurpleXfer *xfer, const guchar *buffer,
-	                          gsize size);
-
-	/*< private >*/
-	gpointer reserved[4];
-};
-
-/**************************************************************************/
-/* File Transfer API                                                      */
-/**************************************************************************/
-
-/**
- * purple_xfer_new:
- * @account: The account sending or receiving the file.
- * @type:    The type of file transfer.
- * @who:     The name of the remote user.
- *
- * Creates a new file transfer handle.
- * This is called by protocols.
- *
- * Returns: A file transfer handle.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleXfer *purple_xfer_new(PurpleAccount *account, PurpleXferType type, const char *who);
-
-/**
- * purple_xfer_request:
- * @xfer: The file transfer to request confirmation on.
- *
- * Requests confirmation for a file transfer from the user. If receiving
- * a file which is known at this point, this requests user to accept and
- * save the file. If the filename is unknown (not set) this only requests user
- * to accept the file transfer. In this case protocol must call this function
- * again once the filename is available.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_request(PurpleXfer *xfer);
-
-/**
- * purple_xfer_request_accepted:
- * @xfer:     The file transfer.
- * @filename: The filename.
- *
- * Called if the user accepts the file transfer request.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_request_accepted(PurpleXfer *xfer, const gchar *filename);
-
-/**
- * purple_xfer_request_denied:
- * @xfer: The file transfer.
- *
- * Called if the user rejects the file transfer request.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_request_denied(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_fd:
- * @xfer: The file transfer.
- *
- * Returns the socket file descriptor.
- *
- * Returns: The socket file descriptor.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-int purple_xfer_get_fd(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_watcher:
- * @xfer: The file transfer.
- *
- * Returns the Watcher for the transfer.
- *
- * Returns: The watcher.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-int purple_xfer_get_watcher(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_xfer_type:
- * @xfer: The file transfer.
- *
- * Returns the type of file transfer.
- *
- * Returns: The type of the file transfer.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-PurpleXferType purple_xfer_get_xfer_type(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_account:
- * @xfer: The file transfer.
- *
- * Returns the account the file transfer is using.
- *
- * Returns: (transfer none): The account.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleAccount *purple_xfer_get_account(PurpleXfer *xfer);
-
-/**
- * purple_xfer_set_remote_user:
- * @xfer: The file transfer.
- * @who:  The name of the remote user.
- *
- * Sets the name of the remote user.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_xfer_set_remote_user(PurpleXfer *xfer, const char *who);
-
-/**
- * purple_xfer_get_remote_user:
- * @xfer: The file transfer.
- *
- * Returns the name of the remote user.
- *
- * Returns: The name of the remote user.
- *
- * Since: 2.1
- */
-PURPLE_AVAILABLE_IN_2_1
-const char *purple_xfer_get_remote_user(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_status:
- * @xfer: The file transfer.
- *
- * Returns the status of the xfer.
- *
- * Returns: The status.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleXferStatus purple_xfer_get_status(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_visible:
- * @xfer: The file transfer.
- *
- * Returns whether the UI should show the file transfer in its listing.
- *
- * Note, this is just a hint for UIs and has no effect internally.
- *
- * Returns: The visibility.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_xfer_get_visible(PurpleXfer *xfer);
-
-/**
- * purple_xfer_is_cancelled:
- * @xfer: The file transfer.
- *
- * Returns true if the file transfer was cancelled.
- *
- * Returns: Whether or not the transfer was cancelled.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-gboolean purple_xfer_is_cancelled(PurpleXfer *xfer);
-
-/**
- * purple_xfer_is_completed:
- * @xfer: The file transfer.
- *
- * Returns the completed state for a file transfer.
- *
- * Returns: The completed state.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-gboolean purple_xfer_is_completed(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_filename:
- * @xfer: The file transfer.
- *
- * Returns the name of the file being sent or received.
- *
- * Returns: The filename.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_xfer_get_filename(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_local_filename:
- * @xfer: The file transfer.
- *
- * Returns the file's destination filename,
- *
- * Returns: The destination filename.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_xfer_get_local_filename(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_bytes_sent:
- * @xfer: The file transfer.
- *
- * Returns the number of bytes sent (or received) so far.
- *
- * Returns: The number of bytes sent.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-goffset purple_xfer_get_bytes_sent(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_bytes_remaining:
- * @xfer: The file transfer.
- *
- * Returns the number of bytes remaining to send or receive.
- *
- * Returns: The number of bytes remaining.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-goffset purple_xfer_get_bytes_remaining(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_size:
- * @xfer: The file transfer.
- *
- * Returns the size of the file being sent or received.
- *
- * Returns: The total size of the file.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-goffset purple_xfer_get_size(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_progress:
- * @xfer: The file transfer.
- *
- * Returns the current percentage of progress of the transfer.
- *
- * This is a number between 0 (0%) and 1 (100%).
- *
- * Returns: The percentage complete.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-double purple_xfer_get_progress(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_local_port:
- * @xfer: The file transfer.
- *
- * Returns the local port number in the file transfer.
- *
- * Returns: The port number on this end.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-guint16 purple_xfer_get_local_port(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_remote_ip:
- * @xfer: The file transfer.
- *
- * Returns the remote IP address in the file transfer.
- *
- * Returns: The IP address on the other end.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-const char *purple_xfer_get_remote_ip(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_remote_port:
- * @xfer: The file transfer.
- *
- * Returns the remote port number in the file transfer.
- *
- * Returns: The port number on the other end.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-guint16 purple_xfer_get_remote_port(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_start_time:
- * @xfer:  The file transfer.
- *
- * Returns the time the transfer of a file started.
- *
- * Returns: The monotonic time when the transfer started.
- *
- * Since: 2.4
- */
-PURPLE_AVAILABLE_IN_2_4
-gint64 purple_xfer_get_start_time(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_end_time:
- * @xfer:  The file transfer.
- *
- * Returns the time the transfer of a file ended.
- *
- * Returns: The monotonic time when the transfer ended.
- *
- * Since: 2.4
- */
-PURPLE_AVAILABLE_IN_2_4
-gint64 purple_xfer_get_end_time(PurpleXfer *xfer);
-
-/**
- * purple_xfer_set_fd:
- * @xfer:      The file transfer.
- * @fd:        The file descriptor.
- *
- * Sets the socket file descriptor.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_xfer_set_fd(PurpleXfer *xfer, int fd);
-
-/**
- * purple_xfer_set_watcher:
- * @xfer:      The file transfer.
- * @watcher:   The watcher.
- *
- * Sets the watcher for the file transfer.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_xfer_set_watcher(PurpleXfer *xfer, int watcher);
-
-/**
- * purple_xfer_set_completed:
- * @xfer:      The file transfer.
- * @completed: The completed state.
- *
- * Sets the completed state for the file transfer.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_set_completed(PurpleXfer *xfer, gboolean completed);
-
-/**
- * purple_xfer_set_status:
- * @xfer:      The file transfer.
- * @status:    The current status.
- *
- * Sets the current status for the file transfer.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_xfer_set_status(PurpleXfer *xfer, PurpleXferStatus status);
-
-/**
- * purple_xfer_set_visible:
- * @xfer: The file transfer.
- * @visible: The visibility.
- *
- * Sets whether the UI should show the file transfer in its listing.
- *
- * Note, this is just a hint for UIs and has no effect internally.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_xfer_set_visible(PurpleXfer *xfer, gboolean visible);
-
-/**
- * purple_xfer_set_message:
- * @xfer:     The file transfer.
- * @message: The message.
- *
- * Sets the message for the file transfer.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_set_message(PurpleXfer *xfer, const char *message);
-
-/**
- * purple_xfer_get_message:
- * @xfer:     The file transfer.
- *
- * Returns the message for the file transfer.
- *
- * Returns: The message.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-const char *purple_xfer_get_message(PurpleXfer *xfer);
-
-/**
- * purple_xfer_set_filename:
- * @xfer:     The file transfer.
- * @filename: The filename.
- *
- * Sets the filename for the file transfer.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_set_filename(PurpleXfer *xfer, const char *filename);
-
-/**
- * purple_xfer_set_local_filename:
- * @xfer:     The file transfer.
- * @filename: The filename
- *
- * Sets the local filename for the file transfer.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_set_local_filename(PurpleXfer *xfer, const char *filename);
-
-/**
- * purple_xfer_set_size:
- * @xfer: The file transfer.
- * @size: The size of the file.
- *
- * Sets the size of the file in a file transfer.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_set_size(PurpleXfer *xfer, goffset size);
-
-/**
- * purple_xfer_set_local_port:
- * @xfer:          The file transfer.
- * @local_port:    The local port.
- *
- * Sets the local port of the file transfer.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_xfer_set_local_port(PurpleXfer *xfer, guint16 local_port);
-
-/**
- * purple_xfer_set_bytes_sent:
- * @xfer:       The file transfer.
- * @bytes_sent: The new current position in the file.  If we're
- *                   sending a file then this is the next byte that we
- *                   will send.  If we're receiving a file, this is the
- *                   next byte that we expect to receive.
- *
- * 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.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_set_bytes_sent(PurpleXfer *xfer, goffset bytes_sent);
-
-/**
- * purple_xfer_get_ui_ops:
- * @xfer: The file transfer.
- *
- * Returns the UI operations structure for a file transfer.
- *
- * Returns: The UI operations structure.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleXferUiOps *purple_xfer_get_ui_ops(PurpleXfer *xfer);
-
-/**
- * purple_xfer_read:
- * @xfer:   The file transfer.
- * @buffer: The buffer that will be created to contain the data.
- *
- * Reads in data from a file transfer stream.
- *
- * Returns: The number of bytes read, or -1.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-gssize purple_xfer_read(PurpleXfer *xfer, guchar **buffer);
-
-/**
- * purple_xfer_write:
- * @xfer:   The file transfer.
- * @buffer: The buffer to read the data from.
- * @size:   The number of bytes to write.
- *
- * Writes data to a file transfer stream.
- *
- * Returns: The number of bytes written, or -1.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-gssize purple_xfer_write(PurpleXfer *xfer, const guchar *buffer, gsize size);
-
-/**
- * purple_xfer_write_file:
- * @xfer:   The file transfer.
- * @buffer: The buffer to read the data from.
- * @size:   The number of bytes to write.
- *
- * Writes chunk of received file.
- *
- * Returns: TRUE on success, FALSE otherwise.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gboolean purple_xfer_write_file(PurpleXfer *xfer, const guchar *buffer, gsize size);
-
-/**
- * purple_xfer_read_file:
- * @xfer:   The file transfer.
- * @buffer: The buffer to write the data to.
- * @size:   The size of buffer.
- *
- * Writes chunk of file being sent.
- *
- * Returns: Number of bytes written (0 means, the device is busy), or -1 on
- *         failure.
- *
- * Since: 2.11
- */
-PURPLE_AVAILABLE_IN_2_11
-gssize purple_xfer_read_file(PurpleXfer *xfer, guchar *buffer, gsize size);
-
-/**
- * purple_xfer_start:
- * @xfer: The file transfer.
- * @fd:   The file descriptor for the socket.
- * @ip:   The IP address to connect to.
- * @port: The port to connect to.
- *
- * Starts a file transfer.
- *
- * Either @fd must be specified <emphasis>or</emphasis> @ip and @port on a
- * file receive transfer. On send, @fd must be specified, and
- * @ip and @port are ignored.
- *
- * Passing @fd as '-1' is a special-case and indicates to the
- * protocol to facilitate the file transfer itself.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip, guint16 port);
-
-/**
- * purple_xfer_end:
- * @xfer: The file transfer.
- *
- * Ends a file transfer.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_end(PurpleXfer *xfer);
-
-/**
- * purple_xfer_cancel_local:
- * @xfer: The file transfer.
- *
- * Cancels a file transfer on the local end.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_cancel_local(PurpleXfer *xfer);
-
-/**
- * purple_xfer_cancel_remote:
- * @xfer: The file transfer.
- *
- * Cancels a file transfer from the remote end.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_cancel_remote(PurpleXfer *xfer);
-
-/**
- * purple_xfer_error:
- * @type:    The type of file transfer.
- * @account: The account sending or receiving the file.
- * @who:     The user on the other end of the transfer.
- * @msg:     The message to display.
- *
- * Displays a file transfer-related error message.
- *
- * This is a wrapper around purple_notify_error(), which automatically
- * specifies a title ("File transfer to <literal>user</literal> failed" or
- * "File Transfer from <literal>user</literal> failed").
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_error(PurpleXferType type, PurpleAccount *account, const char *who, const char *msg);
-
-/**
- * purple_xfer_conversation_write:
- * @xfer: The file transfer to which this message relates.
- * @message: The message to display.
- * @is_error: Is this an error message?.
- *
- * Displays a file transfer-related message in the conversation window.
- *
- * This is a wrapper around purple_conversation_write_system_message.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfer_conversation_write(PurpleXfer *xfer, const gchar *message, gboolean is_error);
-
-/**
- * purple_xfer_ui_ready:
- * @xfer: The file transfer which is ready.
- *
- * Allows the UI to signal it's ready to send/receive data (depending on
- * the direction of the file transfer. Used when the UI is providing
- * read/write/data_not_sent UI ops.
- *
- * Since: 2.6
- */
-PURPLE_AVAILABLE_IN_2_6
-void purple_xfer_ui_ready(PurpleXfer *xfer);
-
-/**
- * purple_xfer_protocol_ready:
- * @xfer: The file transfer which is ready.
- *
- * Allows the protocol to signal it's ready to send/receive data (depending on
- * the direction of the file transfer. Used when the protocol provides read/write
- * ops and cannot/does not provide a raw fd to the core.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-void purple_xfer_protocol_ready(PurpleXfer *xfer);
-
-/**
- * purple_xfer_get_thumbnail:
- * @xfer: The file transfer to get the thumbnail for
- * @len:  If not %NULL, the length of the thumbnail data returned
- *             will be set in the location pointed to by this.
- *
- * Gets the thumbnail data for a transfer
- *
- * Returns: The thumbnail data, or NULL if there is no thumbnail
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-gconstpointer purple_xfer_get_thumbnail(PurpleXfer *xfer, gsize *len);
-
-/**
- * purple_xfer_get_thumbnail_mimetype:
- * @xfer: The file transfer to get the mimetype for
- *
- * Gets the mimetype of the thumbnail preview for a transfer
- *
- * Returns: The mimetype of the thumbnail, or %NULL if not thumbnail is set
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-const gchar *purple_xfer_get_thumbnail_mimetype(PurpleXfer *xfer);
-
-
-/**
- * purple_xfer_set_thumbnail:
- * @xfer: The file transfer to set the data for
- * @thumbnail: A pointer to the thumbnail data, this will be copied
- * @size: The size in bytes of the passed in thumbnail data
- * @mimetype: The mimetype of the generated thumbnail
- *
- * Sets the thumbnail data for a transfer
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-void purple_xfer_set_thumbnail(PurpleXfer *xfer, gconstpointer thumbnail,
-	gsize size, const gchar *mimetype);
-
-/**
- * purple_xfer_prepare_thumbnail:
- * @xfer: The file transfer to create a thumbnail for
- * @formats: A comma-separated list of mimetypes for image formats
- *	 	  the protocols can use for thumbnails.
- *
- * Prepare a thumbnail for a transfer (if the UI supports it)
- * will be no-op in case the UI doesn't implement thumbnail creation
- *
- * Since: 2.7
- */
-PURPLE_AVAILABLE_IN_2_7
-void purple_xfer_prepare_thumbnail(PurpleXfer *xfer, const gchar *formats);
-
-/**************************************************************************/
-/* File Transfer Subsystem API                                            */
-/**************************************************************************/
-
-/**
- * purple_xfer_ui_ops_get_type:
- *
- * The standard _get_type function for #GType's.
- *
- * Returns: The #GType for the #PurpleXferUiOps boxed structure.
- *
- * Since: 3.0
- */
-PURPLE_AVAILABLE_IN_3_0
-GType purple_xfer_ui_ops_get_type(void);
-
-/**
- * purple_xfers_get_all:
- *
- * Returns all xfers
- *
- * Returns: (element-type Purple.Xfer) (transfer none): all current xfers
- *          with refs
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-GList *purple_xfers_get_all(void);
-
-/**
- * purple_xfers_get_handle:
- *
- * Returns the handle to the file transfer subsystem.
- *
- * Returns: The handle.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void *purple_xfers_get_handle(void);
-
-/**
- * purple_xfers_init:
- *
- * Initializes the file transfer subsystem.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfers_init(void);
-
-/**
- * purple_xfers_uninit:
- *
- * Uninitializes the file transfer subsystem.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfers_uninit(void);
-
-/**
- * purple_xfers_set_ui_ops:
- * @ops: The UI operations structure.
- *
- * Sets the UI operations structure to be used in all purple file transfers.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-void purple_xfers_set_ui_ops(PurpleXferUiOps *ops);
-
-/**
- * purple_xfers_get_ui_ops:
- *
- * Returns the UI operations structure to be used in all purple file transfers.
- *
- * Returns: The UI operations structure.
- *
- * Since: 2.0
- */
-PURPLE_AVAILABLE_IN_ALL
-PurpleXferUiOps *purple_xfers_get_ui_ops(void);
-
-G_END_DECLS
-
-#endif /* PURPLE_XFER_H */
diff --git a/libpurple/xfer.c b/libpurple/xfer.c
deleted file mode 100644
--- a/libpurple/xfer.c
+++ /dev/null
@@ -1,2608 +0,0 @@
-/*
- * Purple - Internet Messaging Library
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- *
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This library is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include <glib/gi18n-lib.h>
-
-#include "glibcompat.h" /* for purple_g_stat on win32 */
-
-#include <glib/gstdio.h>
-
-#include "debug.h"
-#include "eventloop.h"
-#include "glibcompat.h"
-#include "image-store.h"
-#include "network.h"
-#include "notify.h"
-#include "prefs.h"
-#include "proxy.h"
-#include "purpleconversationmanager.h"
-#include "purpleenums.h"
-#include "purplegio.h"
-#include "request.h"
-#include "server.h"
-#include "util.h"
-#include "xfer.h"
-
-#ifdef _WIN32
-# include "win32/libc_interface.h"
-#endif
-
-#define FT_INITIAL_BUFFER_SIZE 4096
-#define FT_MAX_BUFFER_SIZE     65535
-
-typedef struct _PurpleXferPrivate  PurpleXferPrivate;
-
-static PurpleXferUiOps *xfer_ui_ops = NULL;
-static GList *xfers;
-
-/* Private data for a file transfer */
-struct _PurpleXferPrivate {
-	PurpleXferType type;         /* The type of transfer.               */
-
-	PurpleAccount *account;      /* The account.                        */
-
-	char *who;                   /* The person on the other end of the
-	                                transfer.                           */
-
-	char *message;               /* A message sent with the request     */
-	char *filename;              /* The name sent over the network.     */
-	char *local_filename;        /* The name on the local hard drive.   */
-	goffset size;                /* The size of the file.               */
-
-	FILE *dest_fp;               /* The destination file pointer.       */
-
-	char *remote_ip;             /* The remote IP address.              */
-	guint16 local_port;          /* The local port.                     */
-	guint16 remote_port;         /* The remote port.                    */
-
-	GSocketConnection *conn;     /* The socket connection.              */
-	int fd;                      /* The socket file descriptor.         */
-	int watcher;                 /* Watcher.                            */
-
-	goffset bytes_sent;          /* The number of bytes sent.           */
-	gint64 start_time;           /* When the transfer of data began.    */
-	gint64 end_time;             /* When the transfer of data ended.    */
-
-	size_t current_buffer_size;  /* This gradually increases for fast
-	                                 network connections.               */
-
-	PurpleXferStatus status;     /* File Transfer's status.             */
-
-	gboolean visible;            /* Hint the UI that the transfer should
-	                                be visible or not. */
-	PurpleXferUiOps *ui_ops;     /* UI-specific operations.             */
-
-	/*
-	 * 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/protocol 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_PROTOCOL = 0x2,
-	} ready;
-
-	/* TODO: Should really use a PurpleCircBuffer for this. */
-	GByteArray *buffer;
-
-	gpointer thumbnail_data;     /* thumbnail image */
-	gsize thumbnail_size;
-	gchar *thumbnail_mimetype;
-};
-
-/* GObject property enums */
-enum
-{
-	PROP_0,
-	PROP_TYPE,
-	PROP_ACCOUNT,
-	PROP_REMOTE_USER,
-	PROP_MESSAGE,
-	PROP_FILENAME,
-	PROP_LOCAL_FILENAME,
-	PROP_FILE_SIZE,
-	PROP_REMOTE_IP,
-	PROP_LOCAL_PORT,
-	PROP_REMOTE_PORT,
-	PROP_FD,
-	PROP_WATCHER,
-	PROP_BYTES_SENT,
-	PROP_START_TIME,
-	PROP_END_TIME,
-	PROP_STATUS,
-	PROP_PROGRESS,
-	PROP_VISIBLE,
-	N_PROPERTIES,
-};
-
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-
-/* GObject signal enums */
-enum
-{
-	SIG_OPEN_LOCAL,
-	SIG_QUERY_LOCAL,
-	SIG_READ_LOCAL,
-	SIG_WRITE_LOCAL,
-	SIG_DATA_NOT_SENT,
-	SIG_ADD_THUMBNAIL,
-	N_SIGNALS,
-};
-static guint signals[N_SIGNALS] = {0, };
-
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleXfer, purple_xfer, G_TYPE_OBJECT);
-
-static void purple_xfer_choose_file(PurpleXfer *xfer);
-
-static const gchar *
-purple_xfer_status_type_to_string(PurpleXferStatus type)
-{
-	static const struct {
-		PurpleXferStatus type;
-		const char *name;
-	} type_names[] = {
-		{ PURPLE_XFER_STATUS_UNKNOWN, "unknown" },
-		{ PURPLE_XFER_STATUS_NOT_STARTED, "not started" },
-		{ PURPLE_XFER_STATUS_ACCEPTED, "accepted" },
-		{ PURPLE_XFER_STATUS_STARTED, "started" },
-		{ PURPLE_XFER_STATUS_DONE, "done" },
-		{ PURPLE_XFER_STATUS_CANCEL_LOCAL, "cancelled locally" },
-		{ PURPLE_XFER_STATUS_CANCEL_REMOTE, "cancelled remotely" }
-	};
-	gsize i;
-
-	for (i = 0; i < G_N_ELEMENTS(type_names); ++i)
-		if (type_names[i].type == type)
-			return type_names[i].name;
-
-	return "invalid state";
-}
-
-void
-purple_xfer_set_status(PurpleXfer *xfer, PurpleXferStatus status)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	if (purple_debug_is_verbose())
-		purple_debug_info("xfer", "Changing status of xfer %p from %s to %s\n",
-				xfer, purple_xfer_status_type_to_string(priv->status),
-				purple_xfer_status_type_to_string(status));
-
-	if (priv->status == status)
-		return;
-
-	priv->status = status;
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_STATUS]);
-}
-
-void
-purple_xfer_set_visible(PurpleXfer *xfer, gboolean visible)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-	priv->visible = visible;
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_VISIBLE]);
-}
-
-static void
-purple_xfer_conversation_write_internal(PurpleXfer *xfer,
-	const char *message, gboolean is_error, gboolean print_thumbnail)
-{
-	PurpleConversation *im = NULL;
-	PurpleConversationManager *manager = NULL;
-	PurpleMessageFlags flags = PURPLE_MESSAGE_SYSTEM;
-	char *escaped;
-	gconstpointer thumbnail_data;
-	gsize size;
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	thumbnail_data = purple_xfer_get_thumbnail(xfer, &size);
-
-	manager = purple_conversation_manager_get_default();
-	im = purple_conversation_manager_find_im(manager,
-	                                         purple_xfer_get_account(xfer),
-	                                         priv->who);
-	if(PURPLE_IS_IM_CONVERSATION(im)) {
-		return;
-	}
-
-	escaped = g_markup_escape_text(message, -1);
-
-	if (is_error)
-		flags |= PURPLE_MESSAGE_ERROR;
-
-	if (print_thumbnail && thumbnail_data) {
-		gchar *message_with_img;
-		PurpleImage *img;
-		guint id;
-
-		img = purple_image_new_from_data(thumbnail_data, size);
-		id = purple_image_store_add(img);
-		g_object_unref(img);
-
-		message_with_img = g_strdup_printf("<img src=\""
-			PURPLE_IMAGE_STORE_PROTOCOL "%u\"> %s", id, escaped);
-		purple_conversation_write_system_message(
-			im, message_with_img, flags);
-		g_free(message_with_img);
-	} else {
-		purple_conversation_write_system_message(
-			im, escaped, flags);
-	}
-	g_free(escaped);
-}
-
-void
-purple_xfer_conversation_write(PurpleXfer *xfer, const gchar *message,
-	gboolean is_error)
-{
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-	g_return_if_fail(message != NULL);
-
-	purple_xfer_conversation_write_internal(xfer, message, is_error, FALSE);
-}
-
-/* maybe this one should be exported publicly? */
-static void
-purple_xfer_conversation_write_with_thumbnail(PurpleXfer *xfer,
-	const gchar *message)
-{
-	purple_xfer_conversation_write_internal(xfer, message, FALSE, TRUE);
-}
-
-
-static void purple_xfer_show_file_error(PurpleXfer *xfer, const char *filename)
-{
-	int err = errno;
-	gchar *msg = NULL, *utf8;
-	PurpleXferType xfer_type = purple_xfer_get_xfer_type(xfer);
-	PurpleAccount *account = purple_xfer_get_account(xfer);
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
-	switch(xfer_type) {
-		case PURPLE_XFER_TYPE_SEND:
-			msg = g_strdup_printf(_("Error reading %s: \n%s.\n"),
-								  utf8, g_strerror(err));
-			break;
-		case PURPLE_XFER_TYPE_RECEIVE:
-			msg = g_strdup_printf(_("Error writing %s: \n%s.\n"),
-								  utf8, g_strerror(err));
-			break;
-		default:
-			msg = g_strdup_printf(_("Error accessing %s: \n%s.\n"),
-								  utf8, g_strerror(err));
-			break;
-	}
-	g_free(utf8);
-
-	purple_xfer_conversation_write(xfer, msg, TRUE);
-	purple_xfer_error(xfer_type, account, priv->who, msg);
-	g_free(msg);
-}
-
-static void
-purple_xfer_choose_file_ok_cb(void *user_data, const char *filename)
-{
-	PurpleXfer *xfer;
-	PurpleXferType type;
-	GStatBuf st;
-	gchar *dir;
-
-	xfer = (PurpleXfer *)user_data;
-	type = purple_xfer_get_xfer_type(xfer);
-
-	if (g_stat(filename, &st) != 0) {
-		/* File not found. */
-		if (type == PURPLE_XFER_TYPE_RECEIVE) {
-#ifndef _WIN32
-			int mode = W_OK;
-#else
-			int mode = F_OK;
-#endif
-			dir = g_path_get_dirname(filename);
-
-			if (g_access(dir, mode) == 0) {
-				purple_xfer_request_accepted(xfer, filename);
-			} else {
-				g_object_ref(xfer);
-				purple_notify_message(
-					NULL, PURPLE_NOTIFY_MSG_ERROR, NULL,
-					_("Directory is not writable."), NULL,
-					purple_request_cpar_from_account(
-						purple_xfer_get_account(xfer)),
-					(PurpleNotifyCloseCallback)purple_xfer_choose_file, xfer);
-			}
-
-			g_free(dir);
-		}
-		else {
-			purple_xfer_show_file_error(xfer, filename);
-			purple_xfer_cancel_local(xfer);
-		}
-	}
-	else if ((type == PURPLE_XFER_TYPE_SEND) && (st.st_size == 0)) {
-
-		purple_notify_error(NULL, NULL,
-			_("Cannot send a file of 0 bytes."), NULL,
-			purple_request_cpar_from_account(
-				purple_xfer_get_account(xfer)));
-
-		purple_xfer_cancel_local(xfer);
-	}
-	else if ((type == PURPLE_XFER_TYPE_SEND) && S_ISDIR(st.st_mode)) {
-		/*
-		 * XXX - Sending a directory should be valid for some protocols.
-		 */
-		purple_notify_error(NULL, NULL, _("Cannot send a directory."),
-			NULL, purple_request_cpar_from_account(
-				purple_xfer_get_account(xfer)));
-
-		purple_xfer_cancel_local(xfer);
-	}
-	else if ((type == PURPLE_XFER_TYPE_RECEIVE) && S_ISDIR(st.st_mode)) {
-		char *msg, *utf8;
-		utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
-		msg = g_strdup_printf(
-					_("%s is not a regular file. Cowardly refusing to overwrite it.\n"), utf8);
-		g_free(utf8);
-		purple_notify_error(NULL, NULL, msg, NULL,
-			purple_request_cpar_from_account(
-				purple_xfer_get_account(xfer)));
-		g_free(msg);
-		purple_xfer_request_denied(xfer);
-	}
-	else if (type == PURPLE_XFER_TYPE_SEND) {
-#ifndef _WIN32
-		int mode = R_OK;
-#else
-		int mode = F_OK;
-#endif
-
-		if (g_access(filename, mode) == 0) {
-			purple_xfer_request_accepted(xfer, filename);
-		} else {
-			g_object_ref(xfer);
-			purple_notify_message(
-				NULL, PURPLE_NOTIFY_MSG_ERROR, NULL,
-				_("File is not readable."), NULL,
-				purple_request_cpar_from_account(
-					purple_xfer_get_account(xfer)),
-				(PurpleNotifyCloseCallback)purple_xfer_choose_file, xfer);
-		}
-	}
-	else {
-		purple_xfer_request_accepted(xfer, filename);
-	}
-
-	g_object_unref(xfer);
-}
-
-static void
-purple_xfer_choose_file_cancel_cb(void *user_data,
-                                  G_GNUC_UNUSED const char *filename)
-{
-	PurpleXfer *xfer = (PurpleXfer *)user_data;
-
-	purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
-	if (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_SEND)
-		purple_xfer_cancel_local(xfer);
-	else
-		purple_xfer_request_denied(xfer);
-	g_object_unref(xfer);
-}
-
-static void
-purple_xfer_choose_file(PurpleXfer *xfer)
-{
-	purple_request_file(xfer, NULL, purple_xfer_get_filename(xfer),
-		(purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE),
-		G_CALLBACK(purple_xfer_choose_file_ok_cb),
-		G_CALLBACK(purple_xfer_choose_file_cancel_cb),
-		purple_request_cpar_from_account(purple_xfer_get_account(xfer)),
-		xfer);
-}
-
-static int
-cancel_recv_cb(PurpleXfer *xfer)
-{
-	purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
-	purple_xfer_request_denied(xfer);
-	g_object_unref(xfer);
-
-	return 0;
-}
-
-static void
-purple_xfer_ask_recv(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-	char *buf, *size_buf;
-	goffset size;
-	gconstpointer thumb;
-	gsize thumb_size;
-
-	/* If we have already accepted the request, ask the destination file
-	   name directly */
-	if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_ACCEPTED) {
-		PurpleRequestCommonParameters *cpar;
-		PurpleBuddy *buddy = purple_blist_find_buddy(priv->account, priv->who);
-
-		if (purple_xfer_get_filename(xfer) != NULL)
-		{
-			size = purple_xfer_get_size(xfer);
-			size_buf = g_format_size_full(size, G_FORMAT_SIZE_LONG_FORMAT);
-			buf = g_strdup_printf(_("%s wants to send you %s (%s)"),
-						  buddy ? purple_buddy_get_alias(buddy) : priv->who,
-						  purple_xfer_get_filename(xfer), size_buf);
-			g_free(size_buf);
-		}
-		else
-		{
-			buf = g_strdup_printf(_("%s wants to send you a file"),
-						buddy ? purple_buddy_get_alias(buddy) : priv->who);
-		}
-
-		if (priv->message != NULL)
-			purple_serv_got_im(purple_account_get_connection(priv->account),
-								 priv->who, priv->message, 0, time(NULL));
-
-		cpar = purple_request_cpar_from_account(priv->account);
-		if ((thumb = purple_xfer_get_thumbnail(xfer, &thumb_size))) {
-			purple_request_cpar_set_custom_icon(cpar, thumb,
-				thumb_size);
-		}
-
-		purple_request_accept_cancel(xfer, NULL, buf, NULL,
-			PURPLE_DEFAULT_ACTION_NONE, cpar, xfer,
-			G_CALLBACK(purple_xfer_choose_file),
-			G_CALLBACK(cancel_recv_cb));
-
-		g_free(buf);
-	} else
-		purple_xfer_choose_file(xfer);
-}
-
-static int
-ask_accept_ok(PurpleXfer *xfer)
-{
-	purple_xfer_request_accepted(xfer, NULL);
-
-	return 0;
-}
-
-static int
-ask_accept_cancel(PurpleXfer *xfer)
-{
-	purple_xfer_request_denied(xfer);
-	g_object_unref(xfer);
-
-	return 0;
-}
-
-static void
-purple_xfer_ask_accept(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-	char *buf, *buf2 = NULL;
-	PurpleBuddy *buddy = purple_blist_find_buddy(priv->account, priv->who);
-
-	buf = g_strdup_printf(_("Accept file transfer request from %s?"),
-				  buddy ? purple_buddy_get_alias(buddy) : priv->who);
-	if (purple_xfer_get_remote_ip(xfer) &&
-		purple_xfer_get_remote_port(xfer))
-		buf2 = g_strdup_printf(_("A file is available for download from:\n"
-					 "Remote host: %s\nRemote port: %d"),
-					   purple_xfer_get_remote_ip(xfer),
-					   purple_xfer_get_remote_port(xfer));
-	purple_request_accept_cancel(xfer, NULL, buf, buf2,
-		PURPLE_DEFAULT_ACTION_NONE,
-		purple_request_cpar_from_account(priv->account), xfer,
-		G_CALLBACK(ask_accept_ok), G_CALLBACK(ask_accept_cancel));
-	g_free(buf);
-	g_free(buf2);
-}
-
-void
-purple_xfer_request(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	/* this is unref'd in the finishers, like cancel and stop */
-	g_object_ref(xfer);
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	if (priv->type == PURPLE_XFER_TYPE_RECEIVE)
-	{
-		purple_signal_emit(purple_xfers_get_handle(), "file-recv-request", xfer);
-		if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL)
-		{
-			/* The file-transfer was cancelled by a plugin */
-			purple_xfer_cancel_local(xfer);
-		}
-		else if (priv->filename || priv->status == PURPLE_XFER_STATUS_ACCEPTED)
-		{
-			gchar* message = NULL;
-			PurpleBuddy *buddy = purple_blist_find_buddy(priv->account, priv->who);
-
-			message = g_strdup_printf(_("%s is offering to send file %s"),
-				buddy ? purple_buddy_get_alias(buddy) : priv->who, purple_xfer_get_filename(xfer));
-			purple_xfer_conversation_write_with_thumbnail(xfer, message);
-			g_free(message);
-
-			/* Ask for a filename to save to if it's not already given by a plugin */
-			if (priv->local_filename == NULL)
-				purple_xfer_ask_recv(xfer);
-		}
-		else
-		{
-			purple_xfer_ask_accept(xfer);
-		}
-	}
-	else
-	{
-		purple_xfer_choose_file(xfer);
-	}
-}
-
-static gboolean
-do_query_local(PurpleXfer *xfer, const gchar *filename)
-{
-	GStatBuf st;
-
-	if (g_stat(filename, &st) == -1) {
-		purple_xfer_show_file_error(xfer, filename);
-		return FALSE;
-	}
-
-	purple_xfer_set_size(xfer, st.st_size);
-	return TRUE;
-}
-
-void
-purple_xfer_request_accepted(PurpleXfer *xfer, const gchar *filename)
-{
-	PurpleXferClass *klass = NULL;
-	PurpleXferPrivate *priv = NULL;
-	gchar *msg, *utf8, *base;
-	PurpleBuddy *buddy;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	klass = PURPLE_XFER_GET_CLASS(xfer);
-	priv = purple_xfer_get_instance_private(xfer);
-
-	purple_debug_misc("xfer", "request accepted for %p\n", xfer);
-
-	if(filename == NULL) {
-		if(priv->type == PURPLE_XFER_TYPE_RECEIVE) {
-			purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_ACCEPTED);
-			klass->init(xfer);
-		} else {
-			purple_debug_warning(
-				"xfer",
-				"can not set file transfer without a file name"
-			);
-		}
-
-		return;
-	}
-
-	buddy = purple_blist_find_buddy(priv->account, priv->who);
-
-	if (priv->type == PURPLE_XFER_TYPE_SEND) {
-		/* Sending a file */
-		/* Check the filename. */
-		gboolean query_status;
-
-#ifdef _WIN32
-		if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\"))
-#else
-		if (g_strrstr(filename, "../"))
-#endif
-		{
-			utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
-
-			msg = g_strdup_printf(_("%s is not a valid filename.\n"), utf8);
-			purple_xfer_error(priv->type, priv->account, priv->who, msg);
-			g_free(utf8);
-			g_free(msg);
-
-			g_object_unref(xfer);
-			return;
-		}
-
-		g_signal_emit(xfer, signals[SIG_QUERY_LOCAL], 0, filename,
-		              &query_status);
-		if (!query_status) {
-			g_object_unref(xfer);
-			return;
-		}
-		purple_xfer_set_local_filename(xfer, filename);
-
-		base = g_path_get_basename(filename);
-		utf8 = g_filename_to_utf8(base, -1, NULL, NULL, NULL);
-		g_free(base);
-		purple_xfer_set_filename(xfer, utf8);
-
-		msg = g_strdup_printf(_("Offering to send %s to %s"),
-				utf8, buddy ? purple_buddy_get_alias(buddy) : priv->who);
-		g_free(utf8);
-		purple_xfer_conversation_write(xfer, msg, FALSE);
-		g_free(msg);
-	}
-	else {
-		/* Receiving a file */
-		purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_ACCEPTED);
-		purple_xfer_set_local_filename(xfer, filename);
-
-		msg = g_strdup_printf(_("Starting transfer of %s from %s"),
-				priv->filename, buddy ? purple_buddy_get_alias(buddy) : priv->who);
-		purple_xfer_conversation_write(xfer, msg, FALSE);
-		g_free(msg);
-	}
-
-	purple_xfer_set_visible(xfer, TRUE);
-
-	klass->init(xfer);
-}
-
-void
-purple_xfer_request_denied(PurpleXfer *xfer)
-{
-	PurpleXferClass *klass = NULL;
-
-	g_return_if_fail(PURPLE_XFER(xfer));
-
-	klass = PURPLE_XFER_GET_CLASS(xfer);
-
-	purple_debug_misc("xfer", "xfer %p denied\n", xfer);
-
-	if(klass && klass->request_denied) {
-		klass->request_denied(xfer);
-	}
-
-	g_object_unref(xfer);
-}
-
-int purple_xfer_get_fd(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->fd;
-}
-
-int purple_xfer_get_watcher(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->watcher;
-}
-
-PurpleXferType
-purple_xfer_get_xfer_type(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), PURPLE_XFER_TYPE_UNKNOWN);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->type;
-}
-
-PurpleAccount *
-purple_xfer_get_account(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->account;
-}
-
-void
-purple_xfer_set_remote_user(PurpleXfer *xfer, const char *who)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-	g_free(priv->who);
-	priv->who = g_strdup(who);
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_REMOTE_USER]);
-}
-
-const char *
-purple_xfer_get_remote_user(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->who;
-}
-
-PurpleXferStatus
-purple_xfer_get_status(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), PURPLE_XFER_STATUS_UNKNOWN);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->status;
-}
-
-gboolean
-purple_xfer_get_visible(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), FALSE);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->visible;
-}
-
-gboolean
-purple_xfer_is_cancelled(PurpleXfer *xfer)
-{
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), TRUE);
-
-	if ((purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) ||
-	    (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_REMOTE))
-		return TRUE;
-	else
-		return FALSE;
-}
-
-gboolean
-purple_xfer_is_completed(PurpleXfer *xfer)
-{
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), TRUE);
-
-	return (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_DONE);
-}
-
-const char *
-purple_xfer_get_filename(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->filename;
-}
-
-const char *
-purple_xfer_get_local_filename(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->local_filename;
-}
-
-goffset
-purple_xfer_get_bytes_sent(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->bytes_sent;
-}
-
-goffset
-purple_xfer_get_bytes_remaining(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->size - priv->bytes_sent;
-}
-
-goffset
-purple_xfer_get_size(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->size;
-}
-
-double
-purple_xfer_get_progress(PurpleXfer *xfer)
-{
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0.0);
-
-	if (purple_xfer_get_size(xfer) == 0)
-		return 0.0;
-
-	return ((double)purple_xfer_get_bytes_sent(xfer) /
-			(double)purple_xfer_get_size(xfer));
-}
-
-guint16
-purple_xfer_get_local_port(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), -1);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->local_port;
-}
-
-const char *
-purple_xfer_get_remote_ip(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->remote_ip;
-}
-
-guint16
-purple_xfer_get_remote_port(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), -1);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->remote_port;
-}
-
-gint64
-purple_xfer_get_start_time(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->start_time;
-}
-
-gint64
-purple_xfer_get_end_time(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->end_time;
-}
-
-void purple_xfer_set_fd(PurpleXfer *xfer, int fd)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-	priv->fd = fd;
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_FD]);
-}
-
-void purple_xfer_set_watcher(PurpleXfer *xfer, int watcher)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-	priv->watcher = watcher;
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_WATCHER]);
-}
-
-void
-purple_xfer_set_completed(PurpleXfer *xfer, gboolean completed)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	if (completed == TRUE) {
-		char *msg = NULL;
-		PurpleConversation *im;
-		PurpleConversationManager *manager;
-
-		purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_DONE);
-
-		if(purple_xfer_get_filename(xfer) != NULL) {
-			char *filename = g_markup_escape_text(purple_xfer_get_filename(xfer), -1);
-			if (purple_xfer_get_local_filename(xfer)
-			 && purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_RECEIVE)
-			{
-				char *local = g_markup_escape_text(purple_xfer_get_local_filename(xfer), -1);
-				msg = g_strdup_printf(_("Transfer of file <A HREF=\"file://%s\">%s</A> complete"),
-				                      local, filename);
-				g_free(local);
-			}
-			else
-				msg = g_strdup_printf(_("Transfer of file %s complete"),
-				                      filename);
-			g_free(filename);
-		} else {
-			msg = g_strdup(_("File transfer complete"));
-		}
-
-		manager = purple_conversation_manager_get_default();
-		im = purple_conversation_manager_find_im(manager, priv->account,
-		                                         priv->who);
-		if(PURPLE_IS_IM_CONVERSATION(im)) {
-			purple_conversation_write_system_message(im, msg, 0);
-		}
-		g_free(msg);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_PROGRESS]);
-}
-
-void
-purple_xfer_set_message(PurpleXfer *xfer, const char *message)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	if (message != priv->message) {
-		g_free(priv->message);
-		priv->message = g_strdup(message);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_MESSAGE]);
-}
-
-const char *
-purple_xfer_get_message(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->message;
-}
-
-void
-purple_xfer_set_filename(PurpleXfer *xfer, const char *filename)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	if (filename != priv->filename) {
-		g_free(priv->filename);
-		priv->filename = g_strdup(filename);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_FILENAME]);
-}
-
-void
-purple_xfer_set_local_filename(PurpleXfer *xfer, const char *filename)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	if (filename != priv->local_filename) {
-		g_free(priv->local_filename);
-		priv->local_filename = g_strdup(filename);
-	}
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_LOCAL_FILENAME]);
-}
-
-void
-purple_xfer_set_size(PurpleXfer *xfer, goffset size)
-{
-	PurpleXferPrivate *priv = NULL;
-	GObject *obj;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-	priv->size = size;
-
-	obj = G_OBJECT(xfer);
-	g_object_freeze_notify(obj);
-	g_object_notify_by_pspec(obj, properties[PROP_FILE_SIZE]);
-	g_object_notify_by_pspec(obj, properties[PROP_PROGRESS]);
-	g_object_thaw_notify(obj);
-}
-
-void
-purple_xfer_set_local_port(PurpleXfer *xfer, guint16 local_port)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-	priv->local_port = local_port;
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_LOCAL_PORT]);
-}
-
-void
-purple_xfer_set_bytes_sent(PurpleXfer *xfer, goffset bytes_sent)
-{
-	PurpleXferPrivate *priv = NULL;
-	GObject *obj;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-	priv->bytes_sent = bytes_sent;
-
-	obj = G_OBJECT(xfer);
-	g_object_freeze_notify(obj);
-	g_object_notify_by_pspec(obj, properties[PROP_BYTES_SENT]);
-	g_object_notify_by_pspec(obj, properties[PROP_PROGRESS]);
-	g_object_thaw_notify(obj);
-}
-
-PurpleXferUiOps *
-purple_xfer_get_ui_ops(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-	return priv->ui_ops;
-}
-
-static void
-purple_xfer_increase_buffer_size(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	priv->current_buffer_size = MIN(priv->current_buffer_size * 1.5,
-			FT_MAX_BUFFER_SIZE);
-}
-
-static gssize
-do_read(PurpleXfer *xfer, guchar **buffer, gsize size)
-{
-	PurpleXferPrivate *priv = NULL;
-	gssize r;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-	g_return_val_if_fail(buffer != NULL, 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	*buffer = g_malloc0(size);
-
-	r = read(priv->fd, *buffer, size);
-	if (r < 0 && errno == EAGAIN) {
-		r = 0;
-	} else if (r < 0) {
-		r = -1;
-	} else if (r == 0) {
-		r = -1;
-	}
-
-	return r;
-}
-
-gssize
-purple_xfer_read(PurpleXfer *xfer, guchar **buffer)
-{
-	PurpleXferPrivate *priv = NULL;
-	PurpleXferClass *klass = NULL;
-	gsize s;
-	gssize r;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-	g_return_val_if_fail(buffer != NULL, 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	if (purple_xfer_get_size(xfer) == 0) {
-		s = priv->current_buffer_size;
-	} else {
-		s = MIN(
-			(gssize)purple_xfer_get_bytes_remaining(xfer),
-			(gssize)priv->current_buffer_size
-		);
-	}
-
-	klass = PURPLE_XFER_GET_CLASS(xfer);
-	if(klass && klass->read) {
-		r = klass->read(xfer, buffer, s);
-	} else {
-		r = do_read(xfer, buffer, s);
-	}
-
-	if (r >= 0 && (gsize)r == priv->current_buffer_size) {
-		/*
-		 * We managed to read the entire buffer.  This means our
-		 * network is fast and our buffer is too small, so make it
-		 * bigger.
-		 */
-		purple_xfer_increase_buffer_size(xfer);
-	}
-
-	return r;
-}
-
-static gssize
-do_write(PurpleXfer *xfer, const guchar *buffer, gsize size)
-{
-	PurpleXferPrivate *priv = NULL;
-	gssize r;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-	g_return_val_if_fail(buffer != NULL, 0);
-	g_return_val_if_fail(size != 0, 0);
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	r = write(priv->fd, buffer, size);
-	if (r < 0 && errno == EAGAIN)
-		r = 0;
-
-	return r;
-}
-
-gssize
-purple_xfer_write(PurpleXfer *xfer, const guchar *buffer, gsize size)
-{
-	PurpleXferClass *klass = NULL;
-	gssize s;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-
-	s = MIN(
-		(gssize)purple_xfer_get_bytes_remaining(xfer),
-		(gssize)size
-	);
-
-	klass = PURPLE_XFER_GET_CLASS(xfer);
-	if(klass && klass->write) {
-		return klass->write(xfer, buffer, s);
-	}
-
-	return do_write(xfer, buffer, s);
-}
-
-static gssize
-do_write_local(PurpleXfer *xfer, const guchar *buffer, gssize size)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	if (priv->dest_fp == NULL) {
-		purple_debug_error("xfer", "File is not opened for writing");
-		return -1;
-	}
-
-	return fwrite(buffer, 1, size, priv->dest_fp);
-}
-
-gboolean
-purple_xfer_write_file(PurpleXfer *xfer, const guchar *buffer, gsize size)
-{
-	PurpleXferPrivate *priv = NULL;
-	gsize wc;
-	goffset remaining;
-	gboolean fs_known;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), FALSE);
-	g_return_val_if_fail(buffer != NULL, FALSE);
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	fs_known = (priv->size > 0);
-
-	remaining = purple_xfer_get_bytes_remaining(xfer);
-	if (fs_known && (goffset)size > remaining) {
-		purple_debug_warning("xfer",
-			"Got too much data (truncating at %" G_GOFFSET_FORMAT
-			").\n", purple_xfer_get_size(xfer));
-		size = remaining;
-	}
-
-	g_signal_emit(xfer, signals[SIG_WRITE_LOCAL], 0, buffer, size, &wc);
-
-	if (wc != size) {
-		purple_debug_error("xfer",
-			"Unable to write whole buffer.\n");
-		purple_xfer_cancel_local(xfer);
-		return FALSE;
-	}
-
-	purple_xfer_set_bytes_sent(
-		xfer,
-		purple_xfer_get_bytes_sent(xfer) + size
-	);
-
-	return TRUE;
-}
-
-static gssize
-do_read_local(PurpleXfer *xfer, guchar *buffer, gssize size)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-	gssize got_len;
-
-	if (priv->dest_fp == NULL) {
-		purple_debug_error("xfer", "File is not opened for reading");
-		return -1;
-	}
-
-	got_len = fread(buffer, 1, size, priv->dest_fp);
-	if ((got_len < 0 || got_len != size) && ferror(priv->dest_fp)) {
-		purple_debug_error("xfer", "Unable to read file.");
-		return -1;
-	}
-
-	return got_len;
-}
-
-gssize
-purple_xfer_read_file(PurpleXfer *xfer, guchar *buffer, gsize size)
-{
-	gssize got_len;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
-	g_return_val_if_fail(buffer != NULL, 0);
-
-	g_signal_emit(xfer, signals[SIG_READ_LOCAL], 0, buffer, size, &got_len);
-	if (got_len < 0 || (gsize)got_len > size) {
-		purple_debug_error("xfer", "Unable to read file.");
-		purple_xfer_cancel_local(xfer);
-		return -1;
-	}
-
-	if (got_len > 0) {
-		purple_xfer_set_bytes_sent(xfer,
-			purple_xfer_get_bytes_sent(xfer) + got_len);
-	}
-
-	return got_len;
-}
-
-static gboolean
-do_data_not_sent(PurpleXfer *xfer, const guchar *buffer, gsize size)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	if (priv->buffer == NULL) {
-		priv->buffer = g_byte_array_sized_new(FT_INITIAL_BUFFER_SIZE);
-		g_byte_array_append(priv->buffer, buffer, size);
-	}
-
-	return TRUE;
-}
-
-static void
-do_transfer(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-	guchar *buffer = NULL;
-	gssize r = 0;
-
-	if (priv->type == PURPLE_XFER_TYPE_RECEIVE) {
-		r = purple_xfer_read(xfer, &buffer);
-		if (r > 0) {
-			if (!purple_xfer_write_file(xfer, buffer, r)) {
-				g_free(buffer);
-				return;
-			}
-
-		} else if(r < 0) {
-			purple_xfer_cancel_remote(xfer);
-			g_free(buffer);
-			return;
-		}
-	} else if (priv->type == PURPLE_XFER_TYPE_SEND) {
-		gssize result = 0;
-		gsize s = MIN(
-			(gsize)purple_xfer_get_bytes_remaining(xfer),
-			(gsize)priv->current_buffer_size
-		);
-		gboolean read_more = TRUE;
-		gboolean existing_buffer = FALSE;
-
-		/* this is so the protocol can keep the connection open
-		   if it needs to for some odd reason. */
-		if (s == 0) {
-			if (priv->watcher) {
-				g_source_remove(priv->watcher);
-				purple_xfer_set_watcher(xfer, 0);
-			}
-			return;
-		}
-
-		if (priv->buffer) {
-			existing_buffer = TRUE;
-			if (priv->buffer->len < s) {
-				s -= priv->buffer->len;
-				read_more = TRUE;
-			} else {
-				read_more = FALSE;
-			}
-		}
-
-		if (read_more) {
-			buffer = g_new(guchar, s);
-			result = purple_xfer_read_file(xfer, buffer, s);
-			if (result == 0) {
-				/*
-				 * The UI claimed it was ready, but didn't have any data for
-				 * us...  It will call purple_xfer_ui_ready when ready, which
-				 * sets back up this watcher.
-				 */
-				if (priv->watcher != 0) {
-					g_source_remove(priv->watcher);
-					purple_xfer_set_watcher(xfer, 0);
-				}
-
-				/* Need to indicate the protocol is still ready... */
-				priv->ready |= PURPLE_XFER_READY_PROTOCOL;
-
-				g_free(buffer);
-				g_return_if_reached();
-			}
-			if (result < 0) {
-				g_free(buffer);
-				return;
-			}
-		}
-
-		if (priv->buffer) {
-			g_byte_array_append(priv->buffer, buffer, result);
-			g_free(buffer);
-			buffer = priv->buffer->data;
-			result = priv->buffer->len;
-		}
-
-		r = do_write(xfer, buffer, result);
-
-		if (r == -1) {
-			purple_debug_error("xfer", "do_write failed! %s\n", g_strerror(errno));
-			purple_xfer_cancel_remote(xfer);
-			if (!priv->buffer)
-				/* We don't free buffer if priv->buffer is set, because in
-				   that case buffer doesn't belong to us. */
-				g_free(buffer);
-			return;
-		} else if (r == result) {
-			/*
-			 * We managed to write the entire buffer.  This means our
-			 * network is fast and our buffer is too small, so make it
-			 * bigger.
-			 */
-			purple_xfer_increase_buffer_size(xfer);
-		} else {
-			gboolean handler_result = FALSE;
-			g_signal_emit(xfer, signals[SIG_DATA_NOT_SENT], 0, buffer + r,
-			              result - r, &handler_result);
-			if (!handler_result) {
-				purple_xfer_cancel_local(xfer);
-			}
-		}
-
-		if (existing_buffer && priv->buffer) {
-			/*
-			 * Remove what we wrote
-			 * If we wrote the whole buffer the byte array will be empty
-			 * Otherwise we'll keep what wasn't sent for next time.
-			 */
-			buffer = NULL;
-			g_byte_array_remove_range(priv->buffer, 0, r);
-		}
-	}
-
-	if (r > 0) {
-		PurpleXferClass *klass = PURPLE_XFER_GET_CLASS(xfer);
-
-		if (klass && klass->ack)
-			klass->ack(xfer, buffer, r);
-	}
-
-	g_free(buffer);
-
-	if (purple_xfer_get_bytes_sent(xfer) >= purple_xfer_get_size(xfer) &&
-			!purple_xfer_is_completed(xfer)) {
-		purple_xfer_set_completed(xfer, TRUE);
-	}
-
-	/* TODO: Check if above is the only place xfers are marked completed.
-	 *       If so, merge these conditions.
-	 */
-	if (purple_xfer_is_completed(xfer)) {
-		purple_xfer_end(xfer);
-	}
-}
-
-static void
-transfer_cb(gpointer data, G_GNUC_UNUSED gint source,
-            G_GNUC_UNUSED PurpleInputCondition condition)
-{
-	PurpleXfer *xfer = data;
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	if (priv->dest_fp == NULL) {
-		/* The UI is moderating its side manually */
-		if (0 == (priv->ready & PURPLE_XFER_READY_UI)) {
-			priv->ready |= PURPLE_XFER_READY_PROTOCOL;
-
-			g_source_remove(priv->watcher);
-			purple_xfer_set_watcher(xfer, 0);
-
-			purple_debug_misc("xfer", "Protocol is ready on ft %p, waiting for UI\n", xfer);
-			return;
-		}
-
-		priv->ready = PURPLE_XFER_READY_NONE;
-	}
-
-	do_transfer(xfer);
-}
-
-static gboolean
-do_open_local(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	priv->dest_fp =
-	        g_fopen(purple_xfer_get_local_filename(xfer),
-	                priv->type == PURPLE_XFER_TYPE_RECEIVE ? "wb" : "rb");
-
-	if (priv->dest_fp == NULL) {
-		purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
-		return FALSE;
-	}
-
-	if (fseek(priv->dest_fp, priv->bytes_sent, SEEK_SET) != 0) {
-		purple_debug_error("xfer", "couldn't seek");
-		purple_xfer_show_file_error(xfer, purple_xfer_get_local_filename(xfer));
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-static void
-begin_transfer(PurpleXfer *xfer, PurpleInputCondition cond)
-{
-	PurpleXferClass *klass = PURPLE_XFER_GET_CLASS(xfer);
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-	gboolean open_status = FALSE;
-
-	if (priv->start_time != 0) {
-		purple_debug_error("xfer", "Transfer is being started multiple times\n");
-		g_return_if_reached();
-	}
-
-	g_signal_emit(xfer, signals[SIG_OPEN_LOCAL], 0, &open_status);
-	if (!open_status) {
-		purple_xfer_cancel_local(xfer);
-	}
-
-	if (priv->fd != -1) {
-		purple_xfer_set_watcher(
-			xfer,
-			purple_input_add(priv->fd, cond, transfer_cb, xfer)
-		);
-	}
-
-	priv->start_time = g_get_monotonic_time();
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_START_TIME]);
-
-	if (klass && klass->start) {
-		klass->start(xfer);
-	}
-}
-
-static void
-connect_cb(GObject *source, GAsyncResult *result, gpointer user_data)
-{
-	PurpleXfer *xfer = PURPLE_XFER(user_data);
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-	GSocket *socket;
-	GError *error = NULL;
-
-	priv->conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
-	                                                    result, &error);
-	if (priv->conn == NULL) {
-		purple_debug_error("xfer", "Unable to connect to destination host: %s",
-		                   error ? error->message : "unknown error");
-		purple_xfer_cancel_local(xfer);
-		g_clear_error(&error);
-		return;
-	}
-
-	socket = g_socket_connection_get_socket(priv->conn);
-	purple_xfer_set_fd(xfer, g_socket_get_fd(socket));
-	begin_transfer(xfer, PURPLE_INPUT_READ);
-}
-
-void
-purple_xfer_ui_ready(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-	PurpleInputCondition cond = 0;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	priv->ready |= PURPLE_XFER_READY_UI;
-
-	if (0 == (priv->ready & PURPLE_XFER_READY_PROTOCOL)) {
-		purple_debug_misc("xfer", "UI is ready on ft %p, waiting for protocol\n", xfer);
-		return;
-	}
-
-	purple_debug_misc("xfer", "UI (and protocol) ready on ft %p, so proceeding\n", xfer);
-
-	if (priv->type == PURPLE_XFER_TYPE_SEND) {
-		cond = PURPLE_INPUT_WRITE;
-	} else if (priv->type == PURPLE_XFER_TYPE_RECEIVE) {
-		cond = PURPLE_INPUT_READ;
-	}
-
-	if (priv->watcher == 0 && priv->fd != -1) {
-		purple_xfer_set_watcher(
-			xfer,
-			purple_input_add(priv->fd, cond, transfer_cb, xfer)
-		);
-	}
-
-	priv->ready = PURPLE_XFER_READY_NONE;
-
-	do_transfer(xfer);
-}
-
-void
-purple_xfer_protocol_ready(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	priv->ready |= PURPLE_XFER_READY_PROTOCOL;
-
-	/* I don't think fwrite/fread are ever *not* ready */
-	if (priv->dest_fp == NULL && 0 == (priv->ready & PURPLE_XFER_READY_UI)) {
-		purple_debug_misc("xfer", "Protocol is ready on ft %p, waiting for UI\n", xfer);
-		return;
-	}
-
-	purple_debug_misc("xfer", "Protocol (and UI) ready on ft %p, so proceeding\n", xfer);
-
-	priv->ready = PURPLE_XFER_READY_NONE;
-
-	do_transfer(xfer);
-}
-
-void
-purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip, guint16 port)
-{
-	PurpleXferPrivate *priv = NULL;
-	PurpleInputCondition cond;
-	GObject *obj;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_STARTED);
-
-	if (priv->type == PURPLE_XFER_TYPE_RECEIVE) {
-		cond = PURPLE_INPUT_READ;
-
-		if (ip != NULL) {
-			GSocketClient *client;
-			GError *error = NULL;
-
-			priv->remote_ip   = g_strdup(ip);
-			priv->remote_port = port;
-
-			obj = G_OBJECT(xfer);
-			g_object_freeze_notify(obj);
-			g_object_notify_by_pspec(obj, properties[PROP_REMOTE_IP]);
-			g_object_notify_by_pspec(obj, properties[PROP_REMOTE_PORT]);
-			g_object_thaw_notify(obj);
-
-			client = purple_gio_socket_client_new(priv->account, &error);
-			if (client == NULL) {
-				/* Assume it's a proxy error */
-				purple_notify_error(
-				        NULL, NULL, _("Invalid proxy settings"), error->message,
-				        purple_request_cpar_from_account(priv->account));
-				g_clear_error(&error);
-				return;
-			}
-
-			purple_debug_info("xfer", "Attempting connection to %s:%u\n", ip,
-			                  port);
-
-			g_socket_client_connect_to_host_async(client, ip, port, NULL,
-			                                      connect_cb, xfer);
-			g_object_unref(client);
-
-			return;
-		} else {
-			purple_xfer_set_fd(xfer, fd);
-		}
-	} else {
-		cond = PURPLE_INPUT_WRITE;
-
-		purple_xfer_set_fd(xfer, fd);
-	}
-
-	begin_transfer(xfer, cond);
-}
-
-void
-purple_xfer_end(PurpleXfer *xfer)
-{
-	PurpleXferClass *klass = NULL;
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	klass = PURPLE_XFER_GET_CLASS(xfer);
-	priv = purple_xfer_get_instance_private(xfer);
-
-	/* See if we are actually trying to cancel this. */
-	if (!purple_xfer_is_completed(xfer)) {
-		purple_xfer_cancel_local(xfer);
-		return;
-	}
-
-	priv->end_time = g_get_monotonic_time();
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_END_TIME]);
-
-	if (klass && klass->end != NULL) {
-		klass->end(xfer);
-	}
-
-	if (priv->watcher != 0) {
-		g_source_remove(priv->watcher);
-		purple_xfer_set_watcher(xfer, 0);
-	}
-
-	if (priv->fd != -1) {
-		if (close(priv->fd)) {
-			purple_debug_error("xfer", "closing file descr in purple_xfer_end() failed: %s",
-					g_strerror(errno));
-		}
-	}
-
-	if (priv->dest_fp != NULL) {
-		if (fclose(priv->dest_fp)) {
-			purple_debug_error("xfer", "closing dest file in purple_xfer_end() failed: %s",
-					g_strerror(errno));
-		}
-		priv->dest_fp = NULL;
-	}
-
-	g_object_unref(xfer);
-}
-
-void
-purple_xfer_cancel_local(PurpleXfer *xfer)
-{
-	PurpleXferClass *klass = NULL;
-	PurpleXferPrivate *priv = NULL;
-	char *msg = NULL;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	klass = PURPLE_XFER_GET_CLASS(xfer);
-	priv = purple_xfer_get_instance_private(xfer);
-
-	/* TODO: We definitely want to close any open request dialogs associated
-	   with this transfer.  However, in some cases the request dialog might
-	   own a reference on the xfer.  This happens at least with the "%s wants
-	   to send you %s" dialog from purple_xfer_ask_recv().  In these cases
-	   the ref count will not be decremented when the request dialog is
-	   closed, so the ref count will never reach 0 and the xfer will never
-	   be freed.  This is a memleak and should be fixed.  It's not clear what
-	   the correct fix is.  Probably requests should have a destroy function
-	   that is called when the request is destroyed.  But also, ref counting
-	   xfer objects makes this code REALLY complicated.  An alternate fix is
-	   to not ref count and instead just make sure the object still exists
-	   when we try to use it. */
-	purple_request_close_with_handle(xfer);
-
-	purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
-	priv->end_time = g_get_monotonic_time();
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_END_TIME]);
-
-	if (purple_xfer_get_filename(xfer) != NULL)
-	{
-		msg = g_strdup_printf(_("You cancelled the transfer of %s"),
-							  purple_xfer_get_filename(xfer));
-	}
-	else
-	{
-		msg = g_strdup(_("File transfer cancelled"));
-	}
-	purple_xfer_conversation_write(xfer, msg, FALSE);
-	g_free(msg);
-
-	if (priv->type == PURPLE_XFER_TYPE_SEND)
-	{
-		if (klass && klass->cancel_send) {
-			klass->cancel_send(xfer);
-		}
-	} else {
-		if (klass && klass->cancel_recv) {
-			klass->cancel_recv(xfer);
-		}
-	}
-
-	if (priv->watcher != 0) {
-		g_source_remove(priv->watcher);
-		purple_xfer_set_watcher(xfer, 0);
-	}
-
-	if (priv->fd != -1) {
-		close(priv->fd);
-	}
-
-	if (priv->dest_fp != NULL) {
-		fclose(priv->dest_fp);
-		priv->dest_fp = NULL;
-	}
-
-	g_object_unref(xfer);
-}
-
-void
-purple_xfer_cancel_remote(PurpleXfer *xfer)
-{
-	PurpleXferClass *klass = NULL;
-	PurpleXferPrivate *priv = NULL;
-	gchar *msg;
-	PurpleAccount *account;
-	PurpleBuddy *buddy;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	klass = PURPLE_XFER_GET_CLASS(xfer);
-	priv = purple_xfer_get_instance_private(xfer);
-
-	purple_request_close_with_handle(xfer);
-	purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_REMOTE);
-	priv->end_time = g_get_monotonic_time();
-
-	g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_END_TIME]);
-
-	account = purple_xfer_get_account(xfer);
-	buddy = purple_blist_find_buddy(account, priv->who);
-
-	if (purple_xfer_get_filename(xfer) != NULL)
-	{
-		msg = g_strdup_printf(_("%s cancelled the transfer of %s"),
-				buddy ? purple_buddy_get_alias(buddy) : priv->who, purple_xfer_get_filename(xfer));
-	}
-	else
-	{
-		msg = g_strdup_printf(_("%s cancelled the file transfer"),
-				buddy ? purple_buddy_get_alias(buddy) : priv->who);
-	}
-	purple_xfer_conversation_write(xfer, msg, TRUE);
-	purple_xfer_error(purple_xfer_get_xfer_type(xfer), account, priv->who, msg);
-	g_free(msg);
-
-	if (priv->type == PURPLE_XFER_TYPE_SEND) {
-		if (klass && klass->cancel_send) {
-			klass->cancel_send(xfer);
-		}
-	} else if(priv->type == PURPLE_XFER_TYPE_RECEIVE) {
-		if (klass && klass->cancel_recv) {
-			klass->cancel_recv(xfer);
-		}
-	}
-
-	if (priv->watcher != 0) {
-		g_source_remove(priv->watcher);
-		purple_xfer_set_watcher(xfer, 0);
-	}
-
-	if (priv->fd != -1)
-		close(priv->fd);
-
-	if (priv->dest_fp != NULL) {
-		fclose(priv->dest_fp);
-		priv->dest_fp = NULL;
-	}
-
-	g_object_unref(xfer);
-}
-
-void
-purple_xfer_error(PurpleXferType type, PurpleAccount *account, const gchar *who, const gchar *msg)
-{
-	gchar *title = NULL;
-
-	g_return_if_fail(msg  != NULL);
-
-	if (account) {
-		PurpleBuddy *buddy;
-		buddy = purple_blist_find_buddy(account, who);
-		if (buddy)
-			who = purple_buddy_get_alias(buddy);
-	}
-
-	if (type == PURPLE_XFER_TYPE_SEND) {
-		title = g_strdup_printf(_("File transfer to %s failed."), who);
-	} else if (type == PURPLE_XFER_TYPE_RECEIVE) {
-		title = g_strdup_printf(_("File transfer from %s failed."), who);
-	}
-
-	purple_notify_error(NULL, NULL, title, msg,
-		purple_request_cpar_from_account(account));
-
-	g_free(title);
-}
-
-gconstpointer
-purple_xfer_get_thumbnail(PurpleXfer *xfer, gsize *len)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	if (len) {
-		*len = priv->thumbnail_size;
-	}
-
-	return priv->thumbnail_data;
-}
-
-const gchar *
-purple_xfer_get_thumbnail_mimetype(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = NULL;
-
-	g_return_val_if_fail(PURPLE_IS_XFER(xfer), NULL);
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	return priv->thumbnail_mimetype;
-}
-
-void
-purple_xfer_set_thumbnail(PurpleXfer *xfer, gconstpointer thumbnail,
-	gsize size, const gchar *mimetype)
-{
-	PurpleXferPrivate *priv = NULL;
-	gpointer old_thumbnail_data;
-	gchar *old_mimetype;
-
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	priv = purple_xfer_get_instance_private(xfer);
-
-	/* Hold onto these in case they are equal to passed-in pointers */
-	old_thumbnail_data = priv->thumbnail_data;
-	old_mimetype = priv->thumbnail_mimetype;
-
-	if (thumbnail && size > 0) {
-		priv->thumbnail_data = g_memdup2(thumbnail, size);
-		priv->thumbnail_size = size;
-		priv->thumbnail_mimetype = g_strdup(mimetype);
-	} else {
-		priv->thumbnail_data = NULL;
-		priv->thumbnail_size = 0;
-		priv->thumbnail_mimetype = NULL;
-	}
-
-	/* Now it's safe to free the pointers */
-	g_free(old_thumbnail_data);
-	g_free(old_mimetype);
-}
-
-void
-purple_xfer_prepare_thumbnail(PurpleXfer *xfer, const gchar *formats)
-{
-	g_return_if_fail(PURPLE_IS_XFER(xfer));
-
-	g_signal_emit(xfer, signals[SIG_ADD_THUMBNAIL], 0, formats, NULL);
-}
-
-/**************************************************************************
- * GObject code
- **************************************************************************/
-static void
-purple_xfer_set_property(GObject *obj, guint param_id, const GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleXfer *xfer = PURPLE_XFER(obj);
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	switch (param_id) {
-		case PROP_TYPE:
-			priv->type = g_value_get_enum(value);
-			break;
-		case PROP_ACCOUNT:
-			priv->account = g_value_get_object(value);
-			break;
-		case PROP_REMOTE_USER:
-			purple_xfer_set_remote_user(xfer, g_value_get_string(value));
-			break;
-		case PROP_MESSAGE:
-			purple_xfer_set_message(xfer, g_value_get_string(value));
-			break;
-		case PROP_FILENAME:
-			purple_xfer_set_filename(xfer, g_value_get_string(value));
-			break;
-		case PROP_LOCAL_FILENAME:
-			purple_xfer_set_local_filename(xfer, g_value_get_string(value));
-			break;
-		case PROP_FILE_SIZE:
-			purple_xfer_set_size(xfer, g_value_get_int64(value));
-			break;
-		case PROP_LOCAL_PORT:
-			purple_xfer_set_local_port(xfer, g_value_get_int(value));
-			break;
-		case PROP_FD:
-			purple_xfer_set_fd(xfer, g_value_get_int(value));
-			break;
-		case PROP_WATCHER:
-			purple_xfer_set_watcher(xfer, g_value_get_int(value));
-			break;
-		case PROP_BYTES_SENT:
-			purple_xfer_set_bytes_sent(xfer, g_value_get_int64(value));
-			break;
-		case PROP_STATUS:
-			purple_xfer_set_status(xfer, g_value_get_enum(value));
-			break;
-		case PROP_VISIBLE:
-			purple_xfer_set_visible(xfer, g_value_get_boolean(value));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_xfer_get_property(GObject *obj, guint param_id, GValue *value,
-		GParamSpec *pspec)
-{
-	PurpleXfer *xfer = PURPLE_XFER(obj);
-
-	switch (param_id) {
-		case PROP_TYPE:
-			g_value_set_enum(value, purple_xfer_get_xfer_type(xfer));
-			break;
-		case PROP_ACCOUNT:
-			g_value_set_object(value, purple_xfer_get_account(xfer));
-			break;
-		case PROP_REMOTE_USER:
-			g_value_set_string(value, purple_xfer_get_remote_user(xfer));
-			break;
-		case PROP_MESSAGE:
-			g_value_set_string(value, purple_xfer_get_message(xfer));
-			break;
-		case PROP_FILENAME:
-			g_value_set_string(value, purple_xfer_get_filename(xfer));
-			break;
-		case PROP_LOCAL_FILENAME:
-			g_value_set_string(value, purple_xfer_get_local_filename(xfer));
-			break;
-		case PROP_FILE_SIZE:
-			g_value_set_int64(value, purple_xfer_get_size(xfer));
-			break;
-		case PROP_REMOTE_IP:
-			g_value_set_string(value, purple_xfer_get_remote_ip(xfer));
-			break;
-		case PROP_LOCAL_PORT:
-			g_value_set_int(value, purple_xfer_get_local_port(xfer));
-			break;
-		case PROP_REMOTE_PORT:
-			g_value_set_int(value, purple_xfer_get_remote_port(xfer));
-			break;
-		case PROP_FD:
-			g_value_set_int(value, purple_xfer_get_fd(xfer));
-			break;
-		case PROP_WATCHER:
-			g_value_set_int(value, purple_xfer_get_watcher(xfer));
-			break;
-		case PROP_BYTES_SENT:
-			g_value_set_int64(value, purple_xfer_get_bytes_sent(xfer));
-			break;
-		case PROP_START_TIME:
-			g_value_set_int64(value, purple_xfer_get_start_time(xfer));
-			break;
-		case PROP_END_TIME:
-			g_value_set_int64(value, purple_xfer_get_end_time(xfer));
-			break;
-		case PROP_STATUS:
-			g_value_set_enum(value, purple_xfer_get_status(xfer));
-			break;
-		case PROP_PROGRESS:
-			g_value_set_double(value, purple_xfer_get_progress(xfer));
-			break;
-		case PROP_VISIBLE:
-			g_value_set_boolean(value, purple_xfer_get_visible(xfer));
-			break;
-		default:
-			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-			break;
-	}
-}
-
-static void
-purple_xfer_init(PurpleXfer *xfer)
-{
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	priv->ui_ops = purple_xfers_get_ui_ops();
-	priv->current_buffer_size = FT_INITIAL_BUFFER_SIZE;
-	priv->fd = -1;
-	priv->ready = PURPLE_XFER_READY_NONE;
-}
-
-static void
-purple_xfer_constructed(GObject *object)
-{
-	PurpleXfer *xfer = PURPLE_XFER(object);
-	PurpleXferUiOps *ui_ops;
-
-	G_OBJECT_CLASS(purple_xfer_parent_class)->constructed(object);
-
-	ui_ops = purple_xfers_get_ui_ops();
-
-	if (ui_ops != NULL && ui_ops->new_xfer != NULL) {
-		ui_ops->new_xfer(xfer);
-	}
-
-	xfers = g_list_prepend(xfers, xfer);
-}
-
-static void
-purple_xfer_finalize(GObject *object)
-{
-	PurpleXfer *xfer = PURPLE_XFER(object);
-	PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
-
-	/* Close the file browser, if it's open */
-	purple_request_close_with_handle(xfer);
-
-	if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_STARTED) {
-		purple_xfer_cancel_local(xfer);
-	}
-
-	xfers = g_list_remove(xfers, xfer);
-
-	g_free(priv->who);
-	g_free(priv->filename);
-	g_free(priv->remote_ip);
-	g_free(priv->local_filename);
-	g_clear_object(&priv->conn);
-
-	if (priv->buffer) {
-		g_byte_array_free(priv->buffer, TRUE);
-	}
-
-	g_free(priv->thumbnail_data);
-	g_free(priv->thumbnail_mimetype);
-
-	G_OBJECT_CLASS(purple_xfer_parent_class)->finalize(object);
-}
-
-/* Class initializer function */
-static void
-purple_xfer_class_init(PurpleXferClass *klass)
-{
-	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
-
-	obj_class->finalize = purple_xfer_finalize;
-	obj_class->constructed = purple_xfer_constructed;
-	obj_class->get_property = purple_xfer_get_property;
-	obj_class->set_property = purple_xfer_set_property;
-
-	klass->write = do_write;
-	klass->read = do_read;
-
-	klass->open_local = do_open_local;
-	klass->query_local = do_query_local;
-	klass->read_local = do_read_local;
-	klass->write_local = do_write_local;
-	klass->data_not_sent = do_data_not_sent;
-
-	/**
-	 * PurpleXfer:type:
-	 *
-	 * The type of the transfer.
-	 */
-	properties[PROP_TYPE] = g_param_spec_enum("type", "Transfer type",
-				"The type of file transfer.", PURPLE_TYPE_XFER_TYPE,
-				PURPLE_XFER_TYPE_UNKNOWN,
-				G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-				G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:account:
-	 *
-	 * The account that this transfer is for.
-	 */
-	properties[PROP_ACCOUNT] = g_param_spec_object("account", "Account",
-				"The account sending or receiving the file.",
-				PURPLE_TYPE_ACCOUNT,
-				G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
-				G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:remote-user:
-	 *
-	 * The user on the other side of this transfer.
-	 */
-	properties[PROP_REMOTE_USER] = g_param_spec_string("remote-user",
-				"Remote user",
-				"The name of the remote user.", NULL,
-				G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:message:
-	 *
-	 * A message that was sent with the transfer.
-	 */
-	properties[PROP_MESSAGE] = g_param_spec_string("message", "Message",
-				"The message for the file transfer.", NULL,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:filename:
-	 *
-	 * The name of the file being transferred.
-	 */
-	properties[PROP_FILENAME] = g_param_spec_string("filename", "Filename",
-				"The filename for the file transfer.", NULL,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:local-filename:
-	 *
-	 * The local filename for this transfer.
-	 */
-	properties[PROP_LOCAL_FILENAME] = g_param_spec_string("local-filename",
-				"Local filename",
-				"The local filename for the file transfer.", NULL,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:file-size:
-	 *
-	 * The size of the file in bytes.
-	 */
-	properties[PROP_FILE_SIZE] = g_param_spec_int64("file-size", "File size",
-				"Size of the file in a file transfer.",
-				G_MININT64, G_MAXINT64, 0,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:remote-ip:
-	 *
-	 * The IP address of the remote user.
-	 */
-	properties[PROP_REMOTE_IP] = g_param_spec_string("remote-ip", "Remote IP",
-				"The remote IP address in the file transfer.", NULL,
-				G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:local-port:
-	 *
-	 * The port number on the local side.
-	 */
-	properties[PROP_LOCAL_PORT] = g_param_spec_int("local-port", "Local port",
-				"The local port number in the file transfer.",
-				G_MININT, G_MAXINT, 0,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:remote-port:
-	 *
-	 * The port number on the remote side.
-	 */
-	properties[PROP_REMOTE_PORT] = g_param_spec_int("remote-port",
-				"Remote port",
-				"The remote port number in the file transfer.",
-				G_MININT, G_MAXINT, 0,
-				G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:fd:
-	 *
-	 * The socket file descriptor for the transfer.
-	 */
-	properties[PROP_FD] = g_param_spec_int("fd", "Socket FD",
-				"The socket file descriptor.",
-				G_MININT, G_MAXINT, 0,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:watcher:
-	 *
-	 * The input watcher for this transfer.
-	 */
-	properties[PROP_WATCHER] = g_param_spec_int("watcher", "Watcher",
-				"The watcher for the file transfer.",
-				G_MININT, G_MAXINT, 0,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:bytes-sent:
-	 *
-	 * The number of bytes that have been sent.
-	 */
-	properties[PROP_BYTES_SENT] = g_param_spec_int64("bytes-sent", "Bytes sent",
-				"The number of bytes sent (or received) so far.",
-				G_MININT64, G_MAXINT64, 0,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:start-time:
-	 *
-	 * The time when the transfer started.
-	 */
-	properties[PROP_START_TIME] = g_param_spec_int64(
-	        "start-time", "Start time",
-	        "The monotonic time the transfer of a file started.",
-	        G_MININT64, G_MAXINT64, 0,
-	        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:end-time:
-	 *
-	 * The time when the transfer ended.
-	 */
-	properties[PROP_END_TIME] = g_param_spec_int64(
-	        "end-time", "End time",
-	        "The monotonic time the transfer of a file ended.", G_MININT64,
-	        G_MAXINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:status:
-	 *
-	 * The status of the transfer.
-	 */
-	properties[PROP_STATUS] = g_param_spec_enum("status", "Status",
-				"The current status for the file transfer.",
-				PURPLE_TYPE_XFER_STATUS, PURPLE_XFER_STATUS_UNKNOWN,
-				G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:progress:
-	 *
-	 * The current progress of the transfer.
-	 */
-	properties[PROP_PROGRESS] = g_param_spec_double(
-	        "progress", "Progress",
-	        "The current progress of the file transfer.", -1.0, 1.0, -1.0,
-	        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
-
-	/**
-	 * PurpleXfer:visible:
-	 *
-	 * Whether or not user interfaces should display the transfer.
-	 */
-	properties[PROP_VISIBLE] = g_param_spec_boolean(
-	        "visible", "Visible",
-	        "Hint for UIs whether this transfer should be visible.", FALSE,
-	        G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
-	g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
-
-	/* Signals */
-
-	/**
-	 * PurpleXfer::open-local:
-	 * @xfer: The file transfer.
-	 *
-	 * Open a file locally for a file transfer.
-	 *
-	 * The default class handler will open a file using standard library
-	 * functions. If you connect to this signal, you should connect to
-	 * [signal@PurpleXfer::query-local], [signal@PurpleXfer::read-local],
-	 * [signal@PurpleXfer::write-local] and [signal@PurpleXfer::data-not-sent]
-	 * as well.
-	 *
-	 * Returns: %TRUE if the file was opened successfully, or %FALSE otherwise,
-	 *          and the transfer should be cancelled (libpurple will cancel).
-	 *
-	 * Since: 3.0
-	 */
-	signals[SIG_OPEN_LOCAL] = g_signal_new(
-	        "open-local", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
-	        G_STRUCT_OFFSET(PurpleXferClass, open_local),
-	        g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_BOOLEAN, 0);
-
-	/**
-	 * PurpleXfer::query-local:
-	 * @xfer: The file transfer.
-	 * @filename: The filename of the transfer.
-	 *
-	 * Query a file's properties locally.
-	 *
-	 * The default class handler will query a file using standard library
-	 * functions, and set the transfer's size. If you connect to this signal,
-	 * you should try to do the same, but it is not necessarily an error if you
-	 * cannot. If you connect to this signal, you must connect to
-	 * [signal@PurpleXfer::open-local], [signal@PurpleXfer::read-local],
-	 * [signal@PurpleXfer::write-local] and [signal@PurpleXfer::data-not-sent]
-	 * as well.
-	 *
-	 * Returns: %TRUE if the properties were queried successfully, or %FALSE
-	 *          otherwise, and the transfer should be cancelled (libpurple will
-	 *          cancel).
-	 *
-	 * Since: 3.0
-	 */
-	signals[SIG_QUERY_LOCAL] = g_signal_new(
-	        "query-local", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
-	        G_STRUCT_OFFSET(PurpleXferClass, query_local),
-	        g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_BOOLEAN, 1,
-	        G_TYPE_STRING);
-
-	/**
-	 * PurpleXfer::read-local:
-	 * @xfer: The file transfer.
-	 * @buffer: (out): A pointer to a buffer to fill.
-	 * @size: The maximum amount of data to put in the buffer.
-	 *
-	 * Read data locally to send to the protocol for a file transfer.
-	 *
-	 * The default class handler will read from a file using standard library
-	 * functions. If you connect to this signal, you must connect to
-	 * [signal@PurpleXfer::open-local], [signal@PurpleXfer::query-local],
-	 * [signal@PurpleXfer::write-local] and [signal@PurpleXfer::data-not-sent]
-	 * as well.
-	 *
-	 * Returns: The amount of data in the buffer, 0 if nothing is available,
-	 *          and a negative value if an error occurred and the transfer
-	 *          should be cancelled (libpurple will cancel).
-	 *
-	 * Since: 3.0
-	 */
-	signals[SIG_READ_LOCAL] = g_signal_new(
-	        "read-local", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
-	        G_STRUCT_OFFSET(PurpleXferClass, read_local),
-	        g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_LONG, 2,
-	        G_TYPE_POINTER, G_TYPE_LONG);
-
-	/**
-	 * PurpleXfer::write-local:
-	 * @xfer: The file transfer.
-	 * @buffer: The buffer to write.
-	 * @size: The size of the buffer.
-	 *
-	 * Write data received from the protocol locally. The signal handler must
-	 * deal with the entire buffer and return size, or it is treated as an
-	 * error.
-	 *
-	 * The default class handler will write to a file using standard library
-	 * functions. If you connect to this signal, you must connect to
-	 * [signal@PurpleXfer::open-local], [signal@PurpleXfer::query-local],
-	 * [signal@PurpleXfer::read-local] and [signal@PurpleXfer::data-not-sent]
-	 * as well.
-	 *
-	 * Returns: @size if the write was successful, or a value between 0 and
-	 *          @size on error.
-	 *
-	 * Since: 3.0
-	 */
-	signals[SIG_WRITE_LOCAL] = g_signal_new(
-	        "write-local", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
-	        G_STRUCT_OFFSET(PurpleXferClass, write_local),
-	        g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_LONG, 2,
-	        G_TYPE_POINTER, G_TYPE_LONG);
-
-	/**
-	 * PurpleXfer::data-not-sent:
-	 * @xfer: The file transfer.
-	 * @buffer: A pointer to the beginning of the unwritten data.
-	 * @size: The amount of unwritten data.
-	 *
-	 * Notify the UI that not all the data read in was written. The UI should
-	 * re-enqueue this data and return it the next time read is called.
-	 *
-	 * If you connect to this signal, you must connect to
-	 * [signal@PurpleXfer::open-local], [signal@PurpleXfer::query-local],
-	 * [signal@PurpleXfer::read-local] and [signal@PurpleXfer::write-local] as
-	 * well.
-	 *
-	 * Returns: %TRUE if the data was re-enqueued successfully, or %FALSE
-	 *          otherwise, and the transfer should be cancelled (libpurple
-	 *          will cancel).
-	 *
-	 * Since: 3.0
-	 */
-	signals[SIG_DATA_NOT_SENT] = g_signal_new(
-	        "data-not-sent", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
-	        G_STRUCT_OFFSET(PurpleXferClass, data_not_sent),
-	        g_signal_accumulator_first_wins, NULL, NULL, G_TYPE_BOOLEAN, 2,
-	        G_TYPE_POINTER, G_TYPE_ULONG);
-
-	/**
-	 * PurpleXfer::add-thumbnail:
-	 * @xfer: The file transfer.
-	 * @formats: A comma-separated string of allowed image formats.
-	 *
-	 * Request that a thumbnail be added to a file transfer.
-	 *
-	 * Since: 3.0
-	 */
-	signals[SIG_ADD_THUMBNAIL] = g_signal_new(
-	        "add-thumbnail", G_TYPE_FROM_CLASS(klass), G_SIGNAL_ACTION, 0, NULL,
-	        NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING);
-}
-
-PurpleXfer *
-purple_xfer_new(PurpleAccount *account, PurpleXferType type, const char *who)
-{
-	PurpleXfer *xfer;
-
-	g_return_val_if_fail(type != PURPLE_XFER_TYPE_UNKNOWN, NULL);
-	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
-	g_return_val_if_fail(who != NULL, NULL);
-
-	xfer = g_object_new(PURPLE_TYPE_XFER,
-		"account",     account,
-		"type",        type,
-		"remote-user", who,
-		NULL
-	);
-
-	return xfer;
-}
-
-/**************************************************************************
- * File Transfer Subsystem API
- **************************************************************************/
-GList *
-purple_xfers_get_all(void)
-{
-	return xfers;
-}
-
-void *
-purple_xfers_get_handle(void) {
-	static int handle = 0;
-
-	return &handle;
-}
-
-void
-purple_xfers_init(void) {
-	void *handle = purple_xfers_get_handle();
-
-	/* register signals */
-	purple_signal_register(handle, "file-recv-request",
-	                     purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-	                     PURPLE_TYPE_XFER);
-}
-
-void
-purple_xfers_uninit(void)
-{
-	void *handle = purple_xfers_get_handle();
-
-	purple_signals_disconnect_by_handle(handle);
-	purple_signals_unregister_by_instance(handle);
-}
-
-void
-purple_xfers_set_ui_ops(PurpleXferUiOps *ops) {
-	xfer_ui_ops = ops;
-}
-
-PurpleXferUiOps *
-purple_xfers_get_ui_ops(void) {
-	return xfer_ui_ops;
-}
-
-/**************************************************************************
- * GBoxed code
- **************************************************************************/
-static PurpleXferUiOps *
-purple_xfer_ui_ops_copy(PurpleXferUiOps *ops)
-{
-	PurpleXferUiOps *ops_new;
-
-	g_return_val_if_fail(ops != NULL, NULL);
-
-	ops_new = g_new(PurpleXferUiOps, 1);
-	*ops_new = *ops;
-
-	return ops_new;
-}
-
-GType
-purple_xfer_ui_ops_get_type(void)
-{
-	static GType type = 0;
-
-	if (type == 0) {
-		type = g_boxed_type_register_static("PurpleXferUiOps",
-				(GBoxedCopyFunc)purple_xfer_ui_ops_copy,
-				(GBoxedFreeFunc)g_free);
-	}
-
-	return type;
-}
diff --git a/po/POTFILES.in b/po/POTFILES.in
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -206,7 +206,6 @@
 pidgin/resources/Protocols/detailed-view.ui
 pidgin/resources/Roomlist/roomlist.ui
 pidgin/resources/Whiteboard/whiteboard.ui
-pidgin/resources/Xfer/xfer.ui
 pidgin/resources/gtk/menus.ui
 pidgin/resources/account-row.ui
 pidgin/resources/contactlist.ui
