Remove PurpleXfer
the autoaccept plugin has been left for now, but no longer builds by default
because we haven't ported it to the new PurpleFileTransfer API yet.
Testing Done:
Hung out with the turtles.
Reviewed at https://reviews.imfreedom.org/r/3086/
--- a/ChangeLog.API Thu Apr 11 04:02:16 2024 -0500
+++ b/ChangeLog.API Thu Apr 11 20:34:07 2024 -0500
@@ -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_set_bytes_sent now takes a goffset as the bytes_sent
- * 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
- * PurpleXferUiOps.add_xfer. Use notify::visible on #PurpleXfer
- * PurpleXferUiOps.cancel_local and
- PurpleXferUiOps.cancel_remote. Use notify::status on
- #PurpleXfer objects instead.
- * PurpleXferUiOps.data_not_sent. Use PurpleXfer::data-not-sent
- * 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.
+ * purple_xfer_cancel_local + * purple_xfer_cancel_remote + * purple_xfer_conversation_write + * 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_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_prepare_thumbnail + * purple_xfer_read_file + * 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_thumbnail + * purple_xfer_write_file + * purple_xfers_get_handle + * purple_xfers_get_ui_ops + * purple_xfers_set_ui_ops --- a/doc/reference/libpurple/libpurple.toml.in Thu Apr 11 04:02:16 2024 -0500
+++ b/doc/reference/libpurple/libpurple.toml.in Thu Apr 11 20:34:07 2024 -0500
@@ -48,7 +48,6 @@
"signals_savedstatus.md",
--- a/doc/reference/libpurple/meson.build Thu Apr 11 04:02:16 2024 -0500
+++ b/doc/reference/libpurple/meson.build Thu Apr 11 20:34:07 2024 -0500
@@ -10,7 +10,6 @@
'signals_savedstatus.md',
--- a/doc/reference/libpurple/signals_xfer.md Thu Apr 11 04:02:16 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-Title: File Transfer Signals
-Slug: file-transfer-signals
-## File Transfer Signals
-* [file-recv-request](#file-recv-request)
-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.
--- a/libpurple/core.c Thu Apr 11 04:02:16 2024 -0500
+++ b/libpurple/core.c Thu Apr 11 20:34:07 2024 -0500
@@ -31,7 +31,6 @@
#include "conversations.h"
@@ -181,7 +180,6 @@
purple_idle_manager_startup();
@@ -253,7 +251,6 @@
purple_savedstatuses_uninit();
purple_statuses_uninit();
purple_accounts_uninit();
_purple_image_store_uninit();
--- a/libpurple/meson.build Thu Apr 11 04:02:16 2024 -0500
+++ b/libpurple/meson.build Thu Apr 11 20:34:07 2024 -0500
@@ -124,7 +124,6 @@
@@ -241,7 +240,6 @@
@@ -330,7 +328,6 @@
--- a/libpurple/plugins/autoaccept/meson.build Thu Apr 11 04:02:16 2024 -0500
+++ b/libpurple/plugins/autoaccept/meson.build Thu Apr 11 20:34:07 2024 -0500
@@ -3,7 +3,9 @@
gnu_symbol_visibility : 'hidden',
dependencies : [libpurple_dep, glib],
- install : true, install_dir : PURPLE_PLUGINDIR)
+ install_dir : PURPLE_PLUGINDIR, + build_by_default : false) 'im.pidgin.Purple.plugin.AutoAccept.gschema.xml',
--- a/libpurple/server.c Thu Apr 11 04:02:16 2024 -0500
+++ b/libpurple/server.c Thu Apr 11 20:34:07 2024 -0500
@@ -41,7 +41,6 @@
purple_serv_send_typing(PurpleConnection *gc, const char *name, PurpleIMTypingState state)
--- a/libpurple/xfer.c Thu Apr 11 04:02:16 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
- * 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)
- * 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
- * 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 "image-store.h"
-#include "purpleconversationmanager.h"
-#include "purpleenums.h"
-# include "win32/libc_interface.h"
-#define FT_INITIAL_BUFFER_SIZE 4096
-#define FT_MAX_BUFFER_SIZE 65535
-typedef struct _PurpleXferPrivate PurpleXferPrivate;
-static PurpleXferUiOps *xfer_ui_ops = NULL;
-/* 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
- 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
- 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.
- PURPLE_XFER_READY_NONE = 0x0,
- PURPLE_XFER_READY_UI = 0x1,
- PURPLE_XFER_READY_PROTOCOL = 0x2,
- /* TODO: Should really use a PurpleCircBuffer for this. */
- gpointer thumbnail_data; /* thumbnail image */
- gchar *thumbnail_mimetype;
-/* GObject property enums */
-static GParamSpec *properties[N_PROPERTIES] = {NULL, };
-/* GObject signal enums */
-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);
-purple_xfer_status_type_to_string(PurpleXferStatus type)
- { 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" }
- for (i = 0; i < G_N_ELEMENTS(type_names); ++i)
- if (type_names[i].type == type)
- return type_names[i].name;
- return "invalid state";
-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)
- g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_STATUS]);
-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]);
-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;
- gconstpointer thumbnail_data;
- 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),
- if(PURPLE_IS_IM_CONVERSATION(im)) {
- escaped = g_markup_escape_text(message, -1);
- flags |= PURPLE_MESSAGE_ERROR;
- if (print_thumbnail && thumbnail_data) {
- gchar *message_with_img;
- img = purple_image_new_from_data(thumbnail_data, size);
- id = purple_image_store_add(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);
- purple_conversation_write_system_message(
-purple_xfer_conversation_write(PurpleXfer *xfer, const gchar *message,
- 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? */
-purple_xfer_conversation_write_with_thumbnail(PurpleXfer *xfer,
- purple_xfer_conversation_write_internal(xfer, message, FALSE, TRUE);
-static void purple_xfer_show_file_error(PurpleXfer *xfer, const char *filename)
- 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);
- case PURPLE_XFER_TYPE_SEND:
- msg = g_strdup_printf(_("Error reading %s: \n%s.\n"),
- utf8, g_strerror(err));
- case PURPLE_XFER_TYPE_RECEIVE:
- msg = g_strdup_printf(_("Error writing %s: \n%s.\n"),
- utf8, g_strerror(err));
- msg = g_strdup_printf(_("Error accessing %s: \n%s.\n"),
- utf8, g_strerror(err));
- purple_xfer_conversation_write(xfer, msg, TRUE);
- purple_xfer_error(xfer_type, account, priv->who, msg);
-purple_xfer_choose_file_ok_cb(void *user_data, const char *filename)
- xfer = (PurpleXfer *)user_data;
- type = purple_xfer_get_xfer_type(xfer);
- if (g_stat(filename, &st) != 0) {
- if (type == PURPLE_XFER_TYPE_RECEIVE) {
- dir = g_path_get_dirname(filename);
- if (g_access(dir, mode) == 0) {
- purple_xfer_request_accepted(xfer, filename);
- 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);
- 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)) {
- utf8 = g_filename_to_utf8(filename, -1, NULL, NULL, NULL);
- _("%s is not a regular file. Cowardly refusing to overwrite it.\n"), utf8);
- purple_notify_error(NULL, NULL, msg, NULL,
- purple_request_cpar_from_account(
- purple_xfer_get_account(xfer)));
- purple_xfer_request_denied(xfer);
- else if (type == PURPLE_XFER_TYPE_SEND) {
- if (g_access(filename, mode) == 0) {
- purple_xfer_request_accepted(xfer, filename);
- 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);
- purple_xfer_request_accepted(xfer, filename);
-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);
- purple_xfer_request_denied(xfer);
-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)),
-cancel_recv_cb(PurpleXfer *xfer)
- purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
- purple_xfer_request_denied(xfer);
-purple_xfer_ask_recv(PurpleXfer *xfer)
- PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
- /* If we have already accepted the request, ask the destination file
- 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);
- 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,
- 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));
- purple_xfer_choose_file(xfer);
-ask_accept_ok(PurpleXfer *xfer)
- purple_xfer_request_accepted(xfer, NULL);
-ask_accept_cancel(PurpleXfer *xfer)
- purple_xfer_request_denied(xfer);
-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));
-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 */
- 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)
- 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);
- /* 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);
- purple_xfer_ask_accept(xfer);
- purple_xfer_choose_file(xfer);
-do_query_local(PurpleXfer *xfer, const gchar *filename)
- if (g_stat(filename, &st) == -1) {
- purple_xfer_show_file_error(xfer, filename);
- purple_xfer_set_size(xfer, st.st_size);
-purple_xfer_request_accepted(PurpleXfer *xfer, const gchar *filename)
- PurpleXferClass *klass = NULL;
- PurpleXferPrivate *priv = NULL;
- gchar *msg, *utf8, *base;
- 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(priv->type == PURPLE_XFER_TYPE_RECEIVE) {
- purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_ACCEPTED);
- "can not set file transfer without a file name"
- buddy = purple_blist_find_buddy(priv->account, priv->who);
- if (priv->type == PURPLE_XFER_TYPE_SEND) {
- /* Check the filename. */
- if (g_strrstr(filename, "../") || g_strrstr(filename, "..\\"))
- if (g_strrstr(filename, "../"))
- 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_signal_emit(xfer, signals[SIG_QUERY_LOCAL], 0, filename,
- purple_xfer_set_local_filename(xfer, filename);
- base = g_path_get_basename(filename);
- utf8 = g_filename_to_utf8(base, -1, NULL, NULL, NULL);
- 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);
- purple_xfer_conversation_write(xfer, msg, FALSE);
- 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);
- purple_xfer_set_visible(xfer, TRUE);
-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);
-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);
-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);
-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);
-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);
-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);
- priv->who = g_strdup(who);
- g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_REMOTE_USER]);
-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);
-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);
-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);
-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))
-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);
-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);
-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;
-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;
-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;
-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);
-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 ((double)purple_xfer_get_bytes_sent(xfer) /
- (double)purple_xfer_get_size(xfer));
-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;
-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;
-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;
-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;
-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);
-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);
- 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]);
-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) {
- 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"),
- msg = g_strdup_printf(_("Transfer of file %s complete"),
- msg = g_strdup(_("File transfer complete"));
- manager = purple_conversation_manager_get_default();
- im = purple_conversation_manager_find_im(manager, priv->account,
- if(PURPLE_IS_IM_CONVERSATION(im)) {
- purple_conversation_write_system_message(im, msg, 0);
- g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_PROGRESS]);
-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) {
- priv->message = g_strdup(message);
- g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_MESSAGE]);
-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);
-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]);
-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]);
-purple_xfer_set_size(PurpleXfer *xfer, goffset size)
- PurpleXferPrivate *priv = NULL;
- g_return_if_fail(PURPLE_IS_XFER(xfer));
- priv = purple_xfer_get_instance_private(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);
-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]);
-purple_xfer_set_bytes_sent(PurpleXfer *xfer, goffset bytes_sent)
- PurpleXferPrivate *priv = NULL;
- g_return_if_fail(PURPLE_IS_XFER(xfer));
- priv = purple_xfer_get_instance_private(xfer);
- priv->bytes_sent = bytes_sent;
- 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);
-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);
-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,
-do_read(PurpleXfer *xfer, guchar **buffer, gsize size)
- PurpleXferPrivate *priv = NULL;
- 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) {
-purple_xfer_read(PurpleXfer *xfer, guchar **buffer)
- PurpleXferPrivate *priv = NULL;
- PurpleXferClass *klass = NULL;
- 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;
- (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);
- 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
- purple_xfer_increase_buffer_size(xfer);
-do_write(PurpleXfer *xfer, const guchar *buffer, gsize size)
- PurpleXferPrivate *priv = NULL;
- 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)
-purple_xfer_write(PurpleXfer *xfer, const guchar *buffer, gsize size)
- PurpleXferClass *klass = NULL;
- g_return_val_if_fail(PURPLE_IS_XFER(xfer), 0);
- (gssize)purple_xfer_get_bytes_remaining(xfer),
- klass = PURPLE_XFER_GET_CLASS(xfer);
- if(klass && klass->write) {
- return klass->write(xfer, buffer, s);
- return do_write(xfer, buffer, s);
-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 fwrite(buffer, 1, size, priv->dest_fp);
-purple_xfer_write_file(PurpleXfer *xfer, const guchar *buffer, gsize size)
- PurpleXferPrivate *priv = NULL;
- 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));
- g_signal_emit(xfer, signals[SIG_WRITE_LOCAL], 0, buffer, size, &wc);
- purple_debug_error("xfer",
- "Unable to write whole buffer.\n");
- purple_xfer_cancel_local(xfer);
- purple_xfer_set_bytes_sent(
- purple_xfer_get_bytes_sent(xfer) + size
-do_read_local(PurpleXfer *xfer, 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 reading");
- 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.");
-purple_xfer_read_file(PurpleXfer *xfer, guchar *buffer, gsize size)
- 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);
- purple_xfer_set_bytes_sent(xfer,
- purple_xfer_get_bytes_sent(xfer) + got_len);
-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);
-do_transfer(PurpleXfer *xfer)
- PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
- if (priv->type == PURPLE_XFER_TYPE_RECEIVE) {
- r = purple_xfer_read(xfer, &buffer);
- if (!purple_xfer_write_file(xfer, buffer, r)) {
- purple_xfer_cancel_remote(xfer);
- } else if (priv->type == PURPLE_XFER_TYPE_SEND) {
- (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. */
- g_source_remove(priv->watcher);
- purple_xfer_set_watcher(xfer, 0);
- existing_buffer = TRUE;
- if (priv->buffer->len < s) {
- s -= priv->buffer->len;
- buffer = g_new(guchar, s);
- result = purple_xfer_read_file(xfer, buffer, s);
- * 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_byte_array_append(priv->buffer, buffer, result);
- buffer = priv->buffer->data;
- result = priv->buffer->len;
- r = do_write(xfer, buffer, result);
- purple_debug_error("xfer", "do_write failed! %s\n", g_strerror(errno));
- purple_xfer_cancel_remote(xfer);
- /* We don't free buffer if priv->buffer is set, because in
- that case buffer doesn't belong to us. */
- } 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
- purple_xfer_increase_buffer_size(xfer);
- gboolean handler_result = FALSE;
- g_signal_emit(xfer, signals[SIG_DATA_NOT_SENT], 0, buffer + r,
- result - r, &handler_result);
- purple_xfer_cancel_local(xfer);
- if (existing_buffer && priv->buffer) {
- * If we wrote the whole buffer the byte array will be empty
- * Otherwise we'll keep what wasn't sent for next time.
- g_byte_array_remove_range(priv->buffer, 0, r);
- PurpleXferClass *klass = PURPLE_XFER_GET_CLASS(xfer);
- if (klass && klass->ack)
- klass->ack(xfer, buffer, r);
- 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)) {
-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);
- priv->ready = PURPLE_XFER_READY_NONE;
-do_open_local(PurpleXfer *xfer)
- PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
- 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));
- 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));
-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_signal_emit(xfer, signals[SIG_OPEN_LOCAL], 0, &open_status);
- purple_xfer_cancel_local(xfer);
- purple_xfer_set_watcher(
- 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) {
-connect_cb(GObject *source, GAsyncResult *result, gpointer user_data)
- PurpleXfer *xfer = PURPLE_XFER(user_data);
- PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
- priv->conn = g_socket_client_connect_to_host_finish(G_SOCKET_CLIENT(source),
- 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);
- socket = g_socket_connection_get_socket(priv->conn);
- purple_xfer_set_fd(xfer, g_socket_get_fd(socket));
- begin_transfer(xfer, PURPLE_INPUT_READ);
-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);
- 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(
- purple_input_add(priv->fd, cond, transfer_cb, xfer)
- priv->ready = PURPLE_XFER_READY_NONE;
-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);
- purple_debug_misc("xfer", "Protocol (and UI) ready on ft %p, so proceeding\n", xfer);
- priv->ready = PURPLE_XFER_READY_NONE;
-purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip, guint16 port)
- PurpleXferPrivate *priv = NULL;
- PurpleInputCondition cond;
- 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;
- priv->remote_ip = g_strdup(ip);
- priv->remote_port = port;
- 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);
- /* Assume it's a proxy error */
- NULL, NULL, _("Invalid proxy settings"), error->message,
- purple_request_cpar_from_account(priv->account));
- purple_debug_info("xfer", "Attempting connection to %s:%u\n", ip,
- g_socket_client_connect_to_host_async(client, ip, port, NULL,
- g_object_unref(client);
- purple_xfer_set_fd(xfer, fd);
- cond = PURPLE_INPUT_WRITE;
- purple_xfer_set_fd(xfer, fd);
- begin_transfer(xfer, cond);
-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);
- priv->end_time = g_get_monotonic_time();
- g_object_notify_by_pspec(G_OBJECT(xfer), properties[PROP_END_TIME]);
- if (klass && klass->end != NULL) {
- if (priv->watcher != 0) {
- g_source_remove(priv->watcher);
- purple_xfer_set_watcher(xfer, 0);
- purple_debug_error("xfer", "closing file descr in purple_xfer_end() failed: %s",
- if (priv->dest_fp != NULL) {
- if (fclose(priv->dest_fp)) {
- purple_debug_error("xfer", "closing dest file in purple_xfer_end() failed: %s",
-purple_xfer_cancel_local(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);
- /* 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));
- msg = g_strdup(_("File transfer cancelled"));
- purple_xfer_conversation_write(xfer, msg, FALSE);
- if (priv->type == PURPLE_XFER_TYPE_SEND)
- if (klass && klass->cancel_send) {
- klass->cancel_send(xfer);
- 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->dest_fp != NULL) {
-purple_xfer_cancel_remote(PurpleXfer *xfer)
- PurpleXferClass *klass = NULL;
- PurpleXferPrivate *priv = NULL;
- PurpleAccount *account;
- 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));
- 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);
- 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->dest_fp != NULL) {
-purple_xfer_error(PurpleXferType type, PurpleAccount *account, const gchar *who, const gchar *msg)
- g_return_if_fail(msg != NULL);
- buddy = purple_blist_find_buddy(account, who);
- 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));
-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);
- *len = priv->thumbnail_size;
- return priv->thumbnail_data;
-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;
-purple_xfer_set_thumbnail(PurpleXfer *xfer, gconstpointer thumbnail,
- gsize size, const gchar *mimetype)
- PurpleXferPrivate *priv = NULL;
- gpointer old_thumbnail_data;
- 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);
- 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);
-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);
-/**************************************************************************
- **************************************************************************/
-purple_xfer_set_property(GObject *obj, guint param_id, const GValue *value,
- PurpleXfer *xfer = PURPLE_XFER(obj);
- PurpleXferPrivate *priv = purple_xfer_get_instance_private(xfer);
- priv->type = g_value_get_enum(value);
- priv->account = g_value_get_object(value);
- purple_xfer_set_remote_user(xfer, g_value_get_string(value));
- purple_xfer_set_message(xfer, g_value_get_string(value));
- purple_xfer_set_filename(xfer, g_value_get_string(value));
- case PROP_LOCAL_FILENAME:
- purple_xfer_set_local_filename(xfer, g_value_get_string(value));
- purple_xfer_set_size(xfer, g_value_get_int64(value));
- purple_xfer_set_local_port(xfer, g_value_get_int(value));
- purple_xfer_set_fd(xfer, g_value_get_int(value));
- purple_xfer_set_watcher(xfer, g_value_get_int(value));
- purple_xfer_set_bytes_sent(xfer, g_value_get_int64(value));
- purple_xfer_set_status(xfer, g_value_get_enum(value));
- purple_xfer_set_visible(xfer, g_value_get_boolean(value));
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-purple_xfer_get_property(GObject *obj, guint param_id, GValue *value,
- PurpleXfer *xfer = PURPLE_XFER(obj);
- g_value_set_enum(value, purple_xfer_get_xfer_type(xfer));
- g_value_set_object(value, purple_xfer_get_account(xfer));
- g_value_set_string(value, purple_xfer_get_remote_user(xfer));
- g_value_set_string(value, purple_xfer_get_message(xfer));
- g_value_set_string(value, purple_xfer_get_filename(xfer));
- case PROP_LOCAL_FILENAME:
- g_value_set_string(value, purple_xfer_get_local_filename(xfer));
- g_value_set_int64(value, purple_xfer_get_size(xfer));
- g_value_set_string(value, purple_xfer_get_remote_ip(xfer));
- g_value_set_int(value, purple_xfer_get_local_port(xfer));
- g_value_set_int(value, purple_xfer_get_remote_port(xfer));
- g_value_set_int(value, purple_xfer_get_fd(xfer));
- g_value_set_int(value, purple_xfer_get_watcher(xfer));
- g_value_set_int64(value, purple_xfer_get_bytes_sent(xfer));
- g_value_set_int64(value, purple_xfer_get_start_time(xfer));
- g_value_set_int64(value, purple_xfer_get_end_time(xfer));
- g_value_set_enum(value, purple_xfer_get_status(xfer));
- g_value_set_double(value, purple_xfer_get_progress(xfer));
- g_value_set_boolean(value, purple_xfer_get_visible(xfer));
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-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->ready = PURPLE_XFER_READY_NONE;
-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);
-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->filename);
- g_free(priv->remote_ip);
- g_free(priv->local_filename);
- g_clear_object(&priv->conn);
- 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 */
-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->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;
- * 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);
- * The account that this transfer is for.
- properties[PROP_ACCOUNT] = g_param_spec_object("account", "Account",
- "The account sending or receiving the file.",
- 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",
- "The name of the remote user.", NULL,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
- * 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);
- * 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",
- "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_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",
- "The remote port number in the file transfer.",
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- * The socket file descriptor for the transfer.
- properties[PROP_FD] = g_param_spec_int("fd", "Socket FD",
- "The socket file descriptor.",
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- * The input watcher for this transfer.
- properties[PROP_WATCHER] = g_param_spec_int("watcher", "Watcher",
- "The watcher for the file transfer.",
- 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);
- * 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);
- * 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);
- * 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);
- * Whether or not user interfaces should display the transfer.
- properties[PROP_VISIBLE] = g_param_spec_boolean(
- "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);
- * 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]
- * Returns: %TRUE if the file was opened successfully, or %FALSE otherwise,
- * and the transfer should be cancelled (libpurple will cancel).
- 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]
- * Returns: %TRUE if the properties were queried successfully, or %FALSE
- * otherwise, and the transfer should be cancelled (libpurple will
- 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,
- * 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]
- * 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).
- 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
- * 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]
- * Returns: @size if the write was successful, or a value between 0 and
- 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
- * Returns: %TRUE if the data was re-enqueued successfully, or %FALSE
- * otherwise, and the transfer should be cancelled (libpurple
- 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.
- 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);
-purple_xfer_new(PurpleAccount *account, PurpleXferType type, const char *who)
- 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,
-/**************************************************************************
- * File Transfer Subsystem API
- **************************************************************************/
-purple_xfers_get_all(void)
-purple_xfers_get_handle(void) {
-purple_xfers_init(void) {
- void *handle = purple_xfers_get_handle();
- purple_signal_register(handle, "file-recv-request",
- purple_marshal_VOID__POINTER, G_TYPE_NONE, 1,
-purple_xfers_uninit(void)
- void *handle = purple_xfers_get_handle();
- purple_signals_disconnect_by_handle(handle);
- purple_signals_unregister_by_instance(handle);
-purple_xfers_set_ui_ops(PurpleXferUiOps *ops) {
-purple_xfers_get_ui_ops(void) {
-/**************************************************************************
- **************************************************************************/
-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);
-purple_xfer_ui_ops_get_type(void)
- type = g_boxed_type_register_static("PurpleXferUiOps",
- (GBoxedCopyFunc)purple_xfer_ui_ops_copy,
- (GBoxedFreeFunc)g_free);
--- a/libpurple/xfer.h Thu Apr 11 04:02:16 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -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
- * 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)
- * 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
- * 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"
-#define PURPLE_TYPE_XFER_UI_OPS (purple_xfer_ui_ops_get_type())
-/**************************************************************************/
-/**************************************************************************/
-typedef struct _PurpleXferUiOps PurpleXferUiOps;
-#include "purpleaccount.h"
-#include "purpleprotocol.h"
-#include "purpleversion.h"
- * @PURPLE_XFER_TYPE_UNKNOWN: Unknown file transfer type.
- * @PURPLE_XFER_TYPE_SEND: File sending.
- * @PURPLE_XFER_TYPE_RECEIVE: File receiving.
- * Types of file transfers.
- PURPLE_XFER_TYPE_UNKNOWN = 0,
- PURPLE_XFER_TYPE_RECEIVE
- * @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
- * @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.
- 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
-#define PURPLE_TYPE_XFER (purple_xfer_get_type())
- * A representation of a file transfer.
-G_DECLARE_DERIVABLE_TYPE(PurpleXfer, purple_xfer, PURPLE, XFER, GObject)
- * @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.
- void (*new_xfer)(PurpleXfer *xfer);
- * @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
- 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,
-/**************************************************************************/
-/**************************************************************************/
- * @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.
-PurpleXfer *purple_xfer_new(PurpleAccount *account, PurpleXferType type, const char *who);
- * @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.
-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.
-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.
-void purple_xfer_request_denied(PurpleXfer *xfer);
- * @xfer: The file transfer.
- * Returns the socket file descriptor.
- * Returns: The socket file descriptor.
-int purple_xfer_get_fd(PurpleXfer *xfer);
- * purple_xfer_get_watcher:
- * @xfer: The file transfer.
- * Returns the Watcher for the transfer.
- * Returns: The watcher.
-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.
-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.
-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.
-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.
-const char *purple_xfer_get_remote_user(PurpleXfer *xfer);
- * purple_xfer_get_status:
- * @xfer: The file transfer.
- * Returns the status of the xfer.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-gint64 purple_xfer_get_end_time(PurpleXfer *xfer);
- * @xfer: The file transfer.
- * @fd: The file descriptor.
- * Sets the socket file descriptor.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-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.
-PurpleXferUiOps *purple_xfer_get_ui_ops(PurpleXfer *xfer);
- * @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.
-gssize purple_xfer_read(PurpleXfer *xfer, guchar **buffer);
- * @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.
-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.
-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
-PURPLE_AVAILABLE_IN_2_11
-gssize purple_xfer_read_file(PurpleXfer *xfer, guchar *buffer, gsize size);
- * @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.
-void purple_xfer_start(PurpleXfer *xfer, int fd, const char *ip, guint16 port);
- * @xfer: The file transfer.
- * Ends a file transfer.
-void purple_xfer_end(PurpleXfer *xfer);
- * purple_xfer_cancel_local:
- * @xfer: The file transfer.
- * Cancels a file transfer on the local end.
-void purple_xfer_cancel_local(PurpleXfer *xfer);
- * purple_xfer_cancel_remote:
- * @xfer: The file transfer.
- * Cancels a file transfer from the remote end.
-void purple_xfer_cancel_remote(PurpleXfer *xfer);
- * @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").
-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.
-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.
-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.
-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
-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
-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
-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
-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.
-GType purple_xfer_ui_ops_get_type(void);
- * purple_xfers_get_all:
- * Returns: (element-type Purple.Xfer) (transfer none): all current xfers
-GList *purple_xfers_get_all(void);
- * purple_xfers_get_handle:
- * Returns the handle to the file transfer subsystem.
-void *purple_xfers_get_handle(void);
- * Initializes the file transfer subsystem.
-void purple_xfers_init(void);
- * Uninitializes the file transfer subsystem.
-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.
-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.
-PurpleXferUiOps *purple_xfers_get_ui_ops(void);
-#endif /* PURPLE_XFER_H */
--- a/po/POTFILES.in Thu Apr 11 04:02:16 2024 -0500
+++ b/po/POTFILES.in Thu Apr 11 20:34:07 2024 -0500
@@ -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