2 * empathy-ft-handler.c - Source for EmpathyFTHandler
3 * Copyright (C) 2009 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
22 /* empathy-ft-handler.c */
24 #include <extensions/extensions.h>
26 #include <glib/gi18n.h>
27 #include <telepathy-glib/util.h>
29 #include "empathy-ft-handler.h"
30 #include "empathy-contact-factory.h"
31 #include "empathy-dispatcher.h"
32 #include "empathy-marshal.h"
33 #include "empathy-utils.h"
35 #define DEBUG_FLAG EMPATHY_DEBUG_FT
36 #include "empathy-debug.h"
38 G_DEFINE_TYPE (EmpathyFTHandler, empathy_ft_handler, G_TYPE_OBJECT)
40 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTHandler)
42 #define BUFFER_SIZE 4096
63 gboolean done_reading;
69 EmpathyFTHandler *handler;
73 EmpathyFTHandlerReadyCallback callback;
75 EmpathyFTHandler *handler;
82 EmpathyTpFile *tpfile;
83 GCancellable *cancellable;
85 /* request for the new transfer */
88 /* transfer properties */
89 EmpathyContact *contact;
94 guint64 transferred_bytes;
97 EmpFileHashType content_hash_type;
98 EmpathyFTHandlerState current_state;
99 } EmpathyFTHandlerPriv;
101 static guint signals[LAST_SIGNAL] = { 0 };
104 static void schedule_hash_chunk (HashingData *hash_data);
106 /* GObject implementations */
108 do_get_property (GObject *object,
113 EmpathyFTHandlerPriv *priv = GET_PRIV (object);
118 g_value_set_object (value, priv->contact);
121 g_value_set_object (value, priv->gfile);
124 g_value_set_object (value, priv->tpfile);
127 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
132 do_set_property (GObject *object,
137 EmpathyFTHandlerPriv *priv = GET_PRIV (object);
142 priv->contact = g_value_dup_object (value);
145 priv->gfile = g_value_dup_object (value);
148 priv->tpfile = g_value_dup_object (value);
151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
156 do_dispose (GObject *object)
158 EmpathyFTHandlerPriv *priv = GET_PRIV (object);
160 if (priv->dispose_run)
163 priv->dispose_run = TRUE;
166 g_object_unref (priv->contact);
167 priv->contact = NULL;
171 g_object_unref (priv->gfile);
176 empathy_tp_file_close (priv->tpfile);
177 g_object_unref (priv->tpfile);
181 if (priv->cancellable) {
182 g_object_unref (priv->cancellable);
183 priv->cancellable = NULL;
186 G_OBJECT_CLASS (empathy_ft_handler_parent_class)->dispose (object);
190 do_finalize (GObject *object)
192 EmpathyFTHandlerPriv *priv = GET_PRIV (object);
194 g_free (priv->content_type);
195 priv->content_type = NULL;
197 g_free (priv->filename);
198 priv->filename = NULL;
200 g_free (priv->description);
201 priv->description = NULL;
203 g_free (priv->content_hash);
204 priv->content_hash = NULL;
206 if (priv->request != NULL)
208 g_hash_table_destroy (priv->request);
209 priv->request = NULL;
212 G_OBJECT_CLASS (empathy_ft_handler_parent_class)->finalize (object);
216 empathy_ft_handler_class_init (EmpathyFTHandlerClass *klass)
218 GObjectClass *object_class = G_OBJECT_CLASS (klass);
219 GParamSpec *param_spec;
221 g_type_class_add_private (klass, sizeof (EmpathyFTHandlerPriv));
223 object_class->get_property = do_get_property;
224 object_class->set_property = do_set_property;
225 object_class->dispose = do_dispose;
226 object_class->finalize = do_finalize;
229 param_spec = g_param_spec_object ("contact",
230 "contact", "The remote contact",
231 EMPATHY_TYPE_CONTACT,
232 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
233 g_object_class_install_property (object_class, PROP_CONTACT, param_spec);
235 param_spec = g_param_spec_object ("gfile",
236 "gfile", "The GFile we're handling",
238 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
239 g_object_class_install_property (object_class, PROP_G_FILE, param_spec);
241 param_spec = g_param_spec_object ("tp-file",
242 "tp-file", "The file's channel wrapper",
243 EMPATHY_TYPE_TP_FILE,
244 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
245 g_object_class_install_property (object_class, PROP_TP_FILE, param_spec);
248 signals[TRANSFER_STARTED] =
249 g_signal_new ("transfer-started", G_TYPE_FROM_CLASS (klass),
250 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
251 g_cclosure_marshal_VOID__OBJECT,
253 1, EMPATHY_TYPE_TP_FILE);
255 signals[TRANSFER_DONE] =
256 g_signal_new ("transfer-done", G_TYPE_FROM_CLASS (klass),
257 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
258 g_cclosure_marshal_VOID__OBJECT,
260 1, EMPATHY_TYPE_TP_FILE);
262 signals[TRANSFER_ERROR] =
263 g_signal_new ("transfer-error", G_TYPE_FROM_CLASS (klass),
264 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
265 g_cclosure_marshal_VOID__POINTER,
269 signals[TRANSFER_PROGRESS] =
270 g_signal_new ("transfer-progress", G_TYPE_FROM_CLASS (klass),
271 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
272 _empathy_marshal_VOID__UINT64_UINT64,
274 2, G_TYPE_UINT64, G_TYPE_UINT64);
276 signals[HASHING_STARTED] =
277 g_signal_new ("hashing-started", G_TYPE_FROM_CLASS (klass),
278 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
279 g_cclosure_marshal_VOID__VOID,
282 signals[HASHING_PROGRESS] =
283 g_signal_new ("hashing-progress", G_TYPE_FROM_CLASS (klass),
284 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
285 _empathy_marshal_VOID__UINT64_UINT64,
287 2, G_TYPE_UINT64, G_TYPE_UINT64);
289 signals[HASHING_DONE] =
290 g_signal_new ("hashing-done", G_TYPE_FROM_CLASS (klass),
291 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
292 g_cclosure_marshal_VOID__VOID,
297 empathy_ft_handler_init (EmpathyFTHandler *self)
299 EmpathyFTHandlerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
300 EMPATHY_TYPE_FT_HANDLER, EmpathyFTHandlerPriv);
305 /* private functions */
308 hash_data_free (HashingData *data)
310 if (data->buffer != NULL)
312 g_free (data->buffer);
316 if (data->stream != NULL)
318 g_object_unref (data->stream);
322 if (data->checksum != NULL)
324 g_checksum_free (data->checksum);
325 data->checksum = NULL;
328 if (data->error != NULL)
330 g_error_free (data->error);
333 if (data->handler != NULL)
335 g_object_unref (data->handler);
336 data->handler = NULL;
339 g_slice_free (HashingData, data);
343 ft_transfer_operation_callback (EmpathyTpFile *tp_file,
347 EmpathyFTHandler *handler = user_data;
350 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
352 g_signal_emit (handler, signals[TRANSFER_DONE], 0);
356 ft_transfer_progress_callback (EmpathyTpFile *tp_file,
357 guint64 transferred_bytes,
360 EmpathyFTHandler *handler = user_data;
361 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
363 if (priv->transferred_bytes != transferred_bytes)
365 priv->transferred_bytes = transferred_bytes;
366 g_signal_emit (handler, signals[TRANSFER_PROGRESS], 0,
367 transferred_bytes, priv->total_bytes);
372 ft_handler_create_channel_cb (EmpathyDispatchOperation *operation,
376 EmpathyFTHandler *handler = user_data;
377 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
378 GError *my_error = NULL;
380 DEBUG ("FT: dispatcher create channel CB");
384 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
388 g_cancellable_set_error_if_cancelled (priv->cancellable, &my_error);
390 if (my_error != NULL)
392 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, my_error);
393 g_clear_error (&my_error);
397 priv->tpfile = g_object_ref
398 (empathy_dispatch_operation_get_channel_wrapper (operation));
399 empathy_tp_file_offer (priv->tpfile, priv->gfile, priv->cancellable,
400 ft_transfer_progress_callback, handler,
401 ft_transfer_operation_callback, handler);
403 empathy_dispatch_operation_claim (operation);
407 ft_handler_push_to_dispatcher (EmpathyFTHandler *handler)
409 EmpathyDispatcher *dispatcher;
411 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
413 DEBUG ("FT: pushing request to the dispatcher");
415 dispatcher = empathy_dispatcher_dup_singleton ();
416 account = empathy_contact_get_account (priv->contact);
418 empathy_dispatcher_create_channel (dispatcher, account, priv->request,
419 ft_handler_create_channel_cb, handler);
421 g_object_unref (dispatcher);
425 ft_handler_check_if_allowed (EmpathyFTHandler *handler)
427 EmpathyDispatcher *dispatcher;
428 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
433 dispatcher = empathy_dispatcher_dup_singleton ();
434 account = empathy_contact_get_account (priv->contact);
436 allowed = empathy_dispatcher_find_channel_class (dispatcher, account,
437 EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT);
439 if (!tp_strv_contains ((const gchar * const *) allowed,
440 TP_IFACE_CHANNEL ".TargetHandle"))
443 g_object_unref (dispatcher);
449 ft_handler_populate_outgoing_request (EmpathyFTHandler *handler)
451 guint contact_handle;
454 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
456 request = priv->request = g_hash_table_new_full (g_str_hash, g_str_equal,
457 NULL, (GDestroyNotify) tp_g_value_slice_free);
459 contact_handle = empathy_contact_get_handle (priv->contact);
461 /* org.freedesktop.Telepathy.Channel.ChannelType */
462 value = tp_g_value_slice_new (G_TYPE_STRING);
463 g_value_set_string (value, EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER);
464 g_hash_table_insert (request, TP_IFACE_CHANNEL ".ChannelType", value);
466 /* org.freedesktop.Telepathy.Channel.TargetHandleType */
467 value = tp_g_value_slice_new (G_TYPE_UINT);
468 g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
469 g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandleType", value);
471 /* org.freedesktop.Telepathy.Channel.TargetHandle */
472 value = tp_g_value_slice_new (G_TYPE_UINT);
473 g_value_set_uint (value, contact_handle);
474 g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value);
476 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentType */
477 value = tp_g_value_slice_new (G_TYPE_STRING);
478 g_value_set_string (value, priv->content_type);
479 g_hash_table_insert (request,
480 EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentType", value);
482 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Filename */
483 value = tp_g_value_slice_new (G_TYPE_STRING);
484 g_value_set_string (value, priv->filename);
485 g_hash_table_insert (request,
486 EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Filename", value);
488 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Size */
489 value = tp_g_value_slice_new (G_TYPE_UINT64);
490 g_value_set_uint64 (value, (guint64) priv->total_bytes);
491 g_hash_table_insert (request,
492 EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Size", value);
494 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Date */
495 value = tp_g_value_slice_new (G_TYPE_UINT64);
496 g_value_set_uint64 (value, (guint64) priv->mtime);
497 g_hash_table_insert (request,
498 EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Date", value);
502 hash_job_async_close_stream_cb (GObject *source,
506 HashingData *hash_data = user_data;
507 EmpathyFTHandler *handler = hash_data->handler;
508 EmpathyFTHandlerPriv *priv;
509 GError *error = NULL;
512 DEBUG ("FT: closing stream after hashing.");
514 priv = GET_PRIV (handler);
516 /* if we're here we for sure have done reading, check if we stopped due
519 g_input_stream_close_finish (hash_data->stream, res, &error);
522 if (hash_data->error != NULL)
524 /* if we already stopped due to an error, probably we're completely
525 * hosed for some reason. just return the first read error
528 g_clear_error (&error);
529 error = hash_data->error;
535 if (hash_data->error != NULL)
537 error = hash_data->error;
541 /* set the checksum in the request */
543 DEBUG ("FT: got file hash %s", g_checksum_get_string (hash_data->checksum));
545 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentHash */
546 value = tp_g_value_slice_new (G_TYPE_STRING);
547 g_value_set_string (value, g_checksum_get_string (hash_data->checksum));
548 g_hash_table_insert (priv->request,
549 EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHash", value);
552 hash_data_free (hash_data);
556 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
557 g_clear_error (&error);
561 g_signal_emit (handler, signals[HASHING_DONE], 0);
563 /* the request is complete now, push it to the dispatcher */
564 ft_handler_push_to_dispatcher (handler);
569 hash_job_async_read_cb (GObject *source,
573 HashingData *hash_data = user_data;
575 GError *error = NULL;
577 DEBUG ("FT: reading a chunk for hashing.");
579 bytes_read = g_input_stream_read_finish (hash_data->stream, res, &error);
582 hash_data->error = error;
583 hash_data->done_reading = TRUE;
587 hash_data->total_read += bytes_read;
589 /* we now have the chunk */
592 hash_data->done_reading = TRUE;
597 g_checksum_update (hash_data->checksum, hash_data->buffer, bytes_read);
598 g_signal_emit (hash_data->handler, signals[HASHING_PROGRESS], 0,
599 (guint64) hash_data->total_read, (guint64) hash_data->total_bytes);
603 g_free (hash_data->buffer);
604 hash_data->buffer = NULL;
606 schedule_hash_chunk (hash_data);
610 schedule_hash_chunk (HashingData *hash_data)
612 EmpathyFTHandlerPriv *priv;
614 priv = GET_PRIV (hash_data->handler);
616 if (hash_data->done_reading)
618 g_input_stream_close_async (hash_data->stream, G_PRIORITY_DEFAULT,
619 priv->cancellable, hash_job_async_close_stream_cb, hash_data);
623 if (hash_data->buffer == NULL)
624 hash_data->buffer = g_malloc0 (BUFFER_SIZE);
626 g_input_stream_read_async (hash_data->stream, hash_data->buffer,
627 BUFFER_SIZE, G_PRIORITY_DEFAULT, priv->cancellable,
628 hash_job_async_read_cb, hash_data);
633 ft_handler_read_async_cb (GObject *source,
637 GFileInputStream *stream;
638 GError *error = NULL;
639 HashingData *hash_data;
641 EmpathyFTHandler *handler = user_data;
642 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
644 DEBUG ("FT: GFile read async CB.");
646 stream = g_file_read_finish (priv->gfile, res, &error);
649 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
650 g_clear_error (&error);
655 hash_data = g_slice_new0 (HashingData);
656 hash_data->stream = G_INPUT_STREAM (stream);
657 hash_data->done_reading = FALSE;
658 hash_data->total_bytes = priv->total_bytes;
659 hash_data->handler = g_object_ref (handler);
660 /* FIXME: should look at the CM capabilities before setting the
663 hash_data->checksum = g_checksum_new (G_CHECKSUM_MD5);
665 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentHashType */
666 value = tp_g_value_slice_new (G_TYPE_UINT);
667 g_value_set_uint (value, EMP_FILE_HASH_TYPE_MD5);
668 g_hash_table_insert (priv->request,
669 EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHashType", value);
671 g_signal_emit (handler, signals[HASHING_STARTED], 0);
673 schedule_hash_chunk (hash_data);
677 ft_handler_complete_request (EmpathyFTHandler *handler)
679 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
680 GError *myerr = NULL;
682 /* check if FT is allowed before firing up the I/O machinery */
683 if (!ft_handler_check_if_allowed (handler))
685 g_set_error_literal (&myerr, EMPATHY_FT_ERROR_QUARK,
686 EMPATHY_FT_ERROR_NOT_SUPPORTED,
687 _("File transfer not supported by remote contact"));
689 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, myerr);
690 g_clear_error (&myerr);
695 /* populate the request table with all the known properties */
696 ft_handler_populate_outgoing_request (handler);
698 /* now start hashing the file */
699 g_file_read_async (priv->gfile, G_PRIORITY_DEFAULT,
700 priv->cancellable, ft_handler_read_async_cb, handler);
704 callbacks_data_free (gpointer user_data)
706 CallbacksData *data = user_data;
709 g_object_unref (data->handler);
711 g_slice_free (CallbacksData, data);
715 ft_handler_gfile_ready_cb (GObject *source,
717 CallbacksData *cb_data)
720 GError *error = NULL;
722 EmpathyFTHandlerPriv *priv = GET_PRIV (cb_data->handler);
724 DEBUG ("FT: got GFileInfo.");
726 info = g_file_query_info_finish (priv->gfile, res, &error);
731 priv->content_type = g_strdup (g_file_info_get_content_type (info));
732 priv->filename = g_strdup (g_file_info_get_display_name (info));
733 priv->total_bytes = g_file_info_get_size (info);
734 g_file_info_get_modification_time (info, &mtime);
735 priv->mtime = mtime.tv_sec;
736 priv->transferred_bytes = 0;
737 priv->description = NULL;
739 g_object_unref (info);
744 cb_data->callback (cb_data->handler, NULL, cb_data->user_data);
748 cb_data->callback (NULL, error, cb_data->user_data);
749 g_error_free (error);
750 g_object_unref (cb_data->handler);
753 callbacks_data_free (cb_data);
757 ft_handler_contact_ready_cb (EmpathyContact *contact,
760 GObject *weak_object)
762 CallbacksData *cb_data = user_data;
763 EmpathyFTHandlerPriv *priv = GET_PRIV (weak_object);
765 g_assert (priv->contact != NULL);
766 g_assert (priv->gfile != NULL);
768 DEBUG ("FT: contact is ready.");
770 /* start collecting info about the file */
771 g_file_query_info_async (priv->gfile,
772 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
773 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
774 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
775 G_FILE_ATTRIBUTE_TIME_MODIFIED,
776 G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
777 NULL, (GAsyncReadyCallback) ft_handler_gfile_ready_cb,
782 channel_get_all_properties_cb (TpProxy *proxy,
783 GHashTable *properties,
786 GObject *weak_object)
788 CallbacksData *cb_data = user_data;
789 EmpathyFTHandler *handler = EMPATHY_FT_HANDLER (weak_object);
790 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
791 EmpathyContactFactory *c_factory;
797 cb_data->callback (NULL, (GError *) error, cb_data->user_data);
798 g_object_unref (handler);
802 priv->total_bytes = g_value_get_uint64 (
803 g_hash_table_lookup (properties, "Size"));
805 priv->transferred_bytes = g_value_get_uint64 (
806 g_hash_table_lookup (properties, "TransferredBytes"));
808 priv->filename = g_value_dup_string (
809 g_hash_table_lookup (properties, "Filename"));
811 priv->content_hash = g_value_dup_string (
812 g_hash_table_lookup (properties, "ContentHash"));
814 priv->content_hash_type = g_value_get_uint (
815 g_hash_table_lookup (properties, "ContentHashType"));
817 priv->content_type = g_value_dup_string (
818 g_hash_table_lookup (properties, "ContentType"));
820 priv->description = g_value_dup_string (
821 g_hash_table_lookup (properties, "Description"));
823 g_hash_table_destroy (properties);
825 c_factory = empathy_contact_factory_dup_singleton ();
826 account = empathy_channel_get_account (TP_CHANNEL (proxy));
827 c_handle = tp_channel_get_handle (TP_CHANNEL (proxy), NULL);
828 priv->contact = empathy_contact_factory_get_from_handle
829 (c_factory, account, c_handle);
831 g_object_unref (c_factory);
832 g_object_unref (account);
834 cb_data->callback (handler, NULL, cb_data->user_data);
840 empathy_ft_handler_new_outgoing (EmpathyContact *contact,
842 EmpathyFTHandlerReadyCallback callback,
845 EmpathyFTHandler *handler;
847 EmpathyFTHandlerPriv *priv;
849 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
850 g_return_if_fail (G_IS_FILE (source));
852 handler = g_object_new (EMPATHY_TYPE_FT_HANDLER,
853 "contact", contact, "gfile", source, NULL);
855 priv = GET_PRIV (handler);
857 data = g_slice_new0 (CallbacksData);
858 data->callback = callback;
859 data->user_data = user_data;
860 data->handler = g_object_ref (handler);
862 empathy_contact_call_when_ready (priv->contact,
863 EMPATHY_CONTACT_READY_HANDLE,
864 ft_handler_contact_ready_cb, data, NULL, G_OBJECT (handler));
868 empathy_ft_handler_new_incoming (EmpathyTpFile *tp_file,
869 EmpathyFTHandlerReadyCallback callback,
872 EmpathyFTHandler *handler;
876 g_return_if_fail (EMPATHY_IS_TP_FILE (tp_file));
878 handler = g_object_new (EMPATHY_TYPE_FT_HANDLER,
879 "tp-file", tp_file, NULL);
881 g_object_get (tp_file, "channel", &channel, NULL);
883 data = g_slice_new0 (CallbacksData);
884 data->callback = callback;
885 data->user_data = user_data;
886 data->handler = g_object_ref (handler);
888 tp_cli_dbus_properties_call_get_all (channel,
889 -1, EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER,
890 channel_get_all_properties_cb, data, callbacks_data_free, G_OBJECT (handler));
894 empathy_ft_handler_start_transfer (EmpathyFTHandler *handler,
895 GCancellable *cancellable)
897 EmpathyFTHandlerPriv *priv;
899 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
901 priv = GET_PRIV (handler);
902 priv->cancellable = g_object_ref (cancellable);
904 if (priv->tpfile == NULL)
906 ft_handler_complete_request (handler);
910 /* emit the start signal now, so that we can catch errors in the
913 g_signal_emit (handler, signals[TRANSFER_STARTED], 0, priv->tpfile);
915 /* TODO: add support for resume. */
916 empathy_tp_file_accept (priv->tpfile, 0, priv->gfile, priv->cancellable,
917 ft_transfer_progress_callback, handler,
918 ft_transfer_operation_callback, handler);
923 empathy_ft_handler_incoming_set_destination (EmpathyFTHandler *handler,
926 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
927 g_return_if_fail (G_IS_FILE (destination));
929 g_object_set (handler, "gfile", destination, NULL);
933 empathy_ft_handler_get_filename (EmpathyFTHandler *handler)
935 EmpathyFTHandlerPriv *priv;
937 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL);
939 priv = GET_PRIV (handler);
941 return priv->filename;
945 empathy_ft_handler_get_content_type (EmpathyFTHandler *handler)
947 EmpathyFTHandlerPriv *priv;
949 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL);
951 priv = GET_PRIV (handler);
953 return priv->content_type;
957 empathy_ft_handler_get_contact (EmpathyFTHandler *handler)
959 EmpathyFTHandlerPriv *priv;
961 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL);
963 priv = GET_PRIV (handler);
965 return priv->contact;
969 empathy_ft_handler_get_gfile (EmpathyFTHandler *handler)
971 EmpathyFTHandlerPriv *priv;
973 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL);
975 priv = GET_PRIV (handler);
981 EmpathyFTHandlerState
982 empathy_ft_handler_get_state (EmpathyFTHandler *handler)
984 EmpathyFTHandlerPriv *priv;
986 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), -1);
988 priv = GET_PRIV (handler);
990 return priv->current_state;
994 empathy_ft_handler_is_incoming (EmpathyFTHandler *handler)
996 EmpathyFTHandlerPriv *priv;
998 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), FALSE);
1000 priv = GET_PRIV (handler);
1002 if (priv->tpfile == NULL)
1005 return empathy_tp_file_is_incoming (priv->tpfile);