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 */
25 #include <glib/gi18n.h>
26 #include <telepathy-glib/util.h>
28 #include "empathy-ft-handler.h"
29 #include "empathy-contact-factory.h"
30 #include "empathy-dispatcher.h"
31 #include "empathy-marshal.h"
32 #include "empathy-utils.h"
34 #define DEBUG_FLAG EMPATHY_DEBUG_FT
35 #include "empathy-debug.h"
37 G_DEFINE_TYPE (EmpathyFTHandler, empathy_ft_handler, G_TYPE_OBJECT)
39 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyFTHandler)
41 #define BUFFER_SIZE 4096
62 gboolean done_reading;
68 EmpathyFTHandler *handler;
72 EmpathyFTHandlerReadyCallback callback;
74 EmpathyFTHandler *handler;
81 EmpathyTpFile *tpfile;
82 GCancellable *cancellable;
84 /* request for the new transfer */
87 /* transfer properties */
88 EmpathyContact *contact;
93 guint64 transferred_bytes;
96 TpFileHashType content_hash_type;
97 TpFileTransferState current_state;
99 gboolean is_completed;
100 gboolean is_cancelled;
101 } EmpathyFTHandlerPriv;
103 static guint signals[LAST_SIGNAL] = { 0 };
106 static void schedule_hash_chunk (HashingData *hash_data);
108 /* GObject implementations */
110 do_get_property (GObject *object,
115 EmpathyFTHandlerPriv *priv = GET_PRIV (object);
120 g_value_set_object (value, priv->contact);
123 g_value_set_object (value, priv->gfile);
126 g_value_set_object (value, priv->tpfile);
129 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
134 do_set_property (GObject *object,
139 EmpathyFTHandlerPriv *priv = GET_PRIV (object);
144 priv->contact = g_value_dup_object (value);
147 priv->gfile = g_value_dup_object (value);
150 priv->tpfile = g_value_dup_object (value);
153 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
158 do_dispose (GObject *object)
160 EmpathyFTHandlerPriv *priv = GET_PRIV (object);
162 if (priv->dispose_run)
165 priv->dispose_run = TRUE;
168 g_object_unref (priv->contact);
169 priv->contact = NULL;
173 g_object_unref (priv->gfile);
178 empathy_tp_file_close (priv->tpfile);
179 g_object_unref (priv->tpfile);
183 if (priv->cancellable) {
184 g_object_unref (priv->cancellable);
185 priv->cancellable = NULL;
188 G_OBJECT_CLASS (empathy_ft_handler_parent_class)->dispose (object);
192 do_finalize (GObject *object)
194 EmpathyFTHandlerPriv *priv = GET_PRIV (object);
196 g_free (priv->content_type);
197 priv->content_type = NULL;
199 g_free (priv->filename);
200 priv->filename = NULL;
202 g_free (priv->description);
203 priv->description = NULL;
205 g_free (priv->content_hash);
206 priv->content_hash = NULL;
208 if (priv->request != NULL)
210 g_hash_table_destroy (priv->request);
211 priv->request = NULL;
214 G_OBJECT_CLASS (empathy_ft_handler_parent_class)->finalize (object);
218 empathy_ft_handler_class_init (EmpathyFTHandlerClass *klass)
220 GObjectClass *object_class = G_OBJECT_CLASS (klass);
221 GParamSpec *param_spec;
223 g_type_class_add_private (klass, sizeof (EmpathyFTHandlerPriv));
225 object_class->get_property = do_get_property;
226 object_class->set_property = do_set_property;
227 object_class->dispose = do_dispose;
228 object_class->finalize = do_finalize;
231 param_spec = g_param_spec_object ("contact",
232 "contact", "The remote contact",
233 EMPATHY_TYPE_CONTACT,
234 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
235 g_object_class_install_property (object_class, PROP_CONTACT, param_spec);
237 param_spec = g_param_spec_object ("gfile",
238 "gfile", "The GFile we're handling",
240 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
241 g_object_class_install_property (object_class, PROP_G_FILE, param_spec);
243 param_spec = g_param_spec_object ("tp-file",
244 "tp-file", "The file's channel wrapper",
245 EMPATHY_TYPE_TP_FILE,
246 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
247 g_object_class_install_property (object_class, PROP_TP_FILE, param_spec);
250 signals[TRANSFER_STARTED] =
251 g_signal_new ("transfer-started", G_TYPE_FROM_CLASS (klass),
252 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
253 g_cclosure_marshal_VOID__OBJECT,
255 1, EMPATHY_TYPE_TP_FILE);
257 signals[TRANSFER_DONE] =
258 g_signal_new ("transfer-done", G_TYPE_FROM_CLASS (klass),
259 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
260 g_cclosure_marshal_VOID__OBJECT,
262 1, EMPATHY_TYPE_TP_FILE);
264 signals[TRANSFER_ERROR] =
265 g_signal_new ("transfer-error", G_TYPE_FROM_CLASS (klass),
266 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
267 g_cclosure_marshal_VOID__POINTER,
271 signals[TRANSFER_PROGRESS] =
272 g_signal_new ("transfer-progress", G_TYPE_FROM_CLASS (klass),
273 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
274 _empathy_marshal_VOID__UINT64_UINT64,
276 2, G_TYPE_UINT64, G_TYPE_UINT64);
278 signals[HASHING_STARTED] =
279 g_signal_new ("hashing-started", G_TYPE_FROM_CLASS (klass),
280 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
281 g_cclosure_marshal_VOID__VOID,
284 signals[HASHING_PROGRESS] =
285 g_signal_new ("hashing-progress", G_TYPE_FROM_CLASS (klass),
286 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
287 _empathy_marshal_VOID__UINT64_UINT64,
289 2, G_TYPE_UINT64, G_TYPE_UINT64);
291 signals[HASHING_DONE] =
292 g_signal_new ("hashing-done", G_TYPE_FROM_CLASS (klass),
293 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
294 g_cclosure_marshal_VOID__VOID,
299 empathy_ft_handler_init (EmpathyFTHandler *self)
301 EmpathyFTHandlerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
302 EMPATHY_TYPE_FT_HANDLER, EmpathyFTHandlerPriv);
307 /* private functions */
310 hash_data_free (HashingData *data)
312 if (data->buffer != NULL)
314 g_free (data->buffer);
318 if (data->stream != NULL)
320 g_object_unref (data->stream);
324 if (data->checksum != NULL)
326 g_checksum_free (data->checksum);
327 data->checksum = NULL;
330 if (data->error != NULL)
332 g_error_free (data->error);
335 if (data->handler != NULL)
337 g_object_unref (data->handler);
338 data->handler = NULL;
341 g_slice_free (HashingData, data);
345 ft_transfer_operation_callback (EmpathyTpFile *tp_file,
349 EmpathyFTHandler *handler = user_data;
350 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
352 DEBUG ("Transfer operation callback, error %p", error);
356 priv->is_cancelled = TRUE;
357 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
361 priv->is_completed = TRUE;
362 g_signal_emit (handler, signals[TRANSFER_DONE], 0, tp_file);
367 ft_transfer_progress_callback (EmpathyTpFile *tp_file,
368 guint64 transferred_bytes,
371 EmpathyFTHandler *handler = user_data;
372 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
374 if (priv->transferred_bytes != transferred_bytes)
376 priv->transferred_bytes = transferred_bytes;
377 g_signal_emit (handler, signals[TRANSFER_PROGRESS], 0,
378 transferred_bytes, priv->total_bytes);
383 ft_handler_create_channel_cb (EmpathyDispatchOperation *operation,
387 EmpathyFTHandler *handler = user_data;
388 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
389 GError *my_error = NULL;
391 DEBUG ("Dispatcher create channel CB");
395 priv->is_cancelled = TRUE;
396 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
400 g_cancellable_set_error_if_cancelled (priv->cancellable, &my_error);
402 if (my_error != NULL)
404 priv->is_cancelled = TRUE;
405 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, my_error);
406 g_clear_error (&my_error);
411 priv->tpfile = g_object_ref
412 (empathy_dispatch_operation_get_channel_wrapper (operation));
414 g_signal_emit (handler, signals[TRANSFER_STARTED], 0, priv->tpfile);
416 empathy_tp_file_offer (priv->tpfile, priv->gfile, priv->cancellable,
417 ft_transfer_progress_callback, handler,
418 ft_transfer_operation_callback, handler);
420 empathy_dispatch_operation_claim (operation);
424 ft_handler_push_to_dispatcher (EmpathyFTHandler *handler)
426 EmpathyDispatcher *dispatcher;
428 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
430 DEBUG ("Pushing request to the dispatcher");
432 dispatcher = empathy_dispatcher_dup_singleton ();
433 account = empathy_contact_get_account (priv->contact);
435 empathy_dispatcher_create_channel (dispatcher, account, priv->request,
436 ft_handler_create_channel_cb, handler);
438 g_object_unref (dispatcher);
442 ft_handler_check_if_allowed (EmpathyFTHandler *handler)
444 EmpathyDispatcher *dispatcher;
445 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
450 dispatcher = empathy_dispatcher_dup_singleton ();
451 account = empathy_contact_get_account (priv->contact);
453 allowed = empathy_dispatcher_find_channel_class (dispatcher, account,
454 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER, TP_HANDLE_TYPE_CONTACT);
456 if (!tp_strv_contains ((const gchar * const *) allowed,
457 TP_IFACE_CHANNEL ".TargetHandle"))
460 g_object_unref (dispatcher);
466 ft_handler_populate_outgoing_request (EmpathyFTHandler *handler)
468 guint contact_handle;
471 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
473 request = priv->request = g_hash_table_new_full (g_str_hash, g_str_equal,
474 NULL, (GDestroyNotify) tp_g_value_slice_free);
476 contact_handle = empathy_contact_get_handle (priv->contact);
478 /* org.freedesktop.Telepathy.Channel.ChannelType */
479 value = tp_g_value_slice_new (G_TYPE_STRING);
480 g_value_set_string (value, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER);
481 g_hash_table_insert (request, TP_IFACE_CHANNEL ".ChannelType", value);
483 /* org.freedesktop.Telepathy.Channel.TargetHandleType */
484 value = tp_g_value_slice_new (G_TYPE_UINT);
485 g_value_set_uint (value, TP_HANDLE_TYPE_CONTACT);
486 g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandleType", value);
488 /* org.freedesktop.Telepathy.Channel.TargetHandle */
489 value = tp_g_value_slice_new (G_TYPE_UINT);
490 g_value_set_uint (value, contact_handle);
491 g_hash_table_insert (request, TP_IFACE_CHANNEL ".TargetHandle", value);
493 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentType */
494 value = tp_g_value_slice_new (G_TYPE_STRING);
495 g_value_set_string (value, priv->content_type);
496 g_hash_table_insert (request,
497 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentType", value);
499 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Filename */
500 value = tp_g_value_slice_new (G_TYPE_STRING);
501 g_value_set_string (value, priv->filename);
502 g_hash_table_insert (request,
503 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Filename", value);
505 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Size */
506 value = tp_g_value_slice_new (G_TYPE_UINT64);
507 g_value_set_uint64 (value, (guint64) priv->total_bytes);
508 g_hash_table_insert (request,
509 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Size", value);
511 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Date */
512 value = tp_g_value_slice_new (G_TYPE_UINT64);
513 g_value_set_uint64 (value, (guint64) priv->mtime);
514 g_hash_table_insert (request,
515 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Date", value);
519 hash_job_async_close_stream_cb (GObject *source,
523 HashingData *hash_data = user_data;
524 EmpathyFTHandler *handler = hash_data->handler;
525 EmpathyFTHandlerPriv *priv;
526 GError *error = NULL;
529 DEBUG ("Closing stream after hashing.");
531 priv = GET_PRIV (handler);
533 /* if we're here we for sure have done reading, check if we stopped due
536 g_input_stream_close_finish (hash_data->stream, res, &error);
539 if (hash_data->error != NULL)
541 /* if we already stopped due to an error, probably we're completely
542 * hosed for some reason. just return the first read error
545 g_clear_error (&error);
546 error = hash_data->error;
552 if (hash_data->error != NULL)
554 error = hash_data->error;
558 /* set the checksum in the request */
560 DEBUG ("Got file hash %s", g_checksum_get_string (hash_data->checksum));
562 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentHash */
563 value = tp_g_value_slice_new (G_TYPE_STRING);
564 g_value_set_string (value, g_checksum_get_string (hash_data->checksum));
565 g_hash_table_insert (priv->request,
566 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHash", value);
569 hash_data_free (hash_data);
573 priv->is_cancelled = TRUE;
574 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
575 g_clear_error (&error);
579 g_signal_emit (handler, signals[HASHING_DONE], 0);
581 /* the request is complete now, push it to the dispatcher */
582 ft_handler_push_to_dispatcher (handler);
587 hash_job_async_read_cb (GObject *source,
591 HashingData *hash_data = user_data;
593 GError *error = NULL;
595 DEBUG ("Reading a chunk for hashing.");
597 bytes_read = g_input_stream_read_finish (hash_data->stream, res, &error);
600 hash_data->error = error;
601 hash_data->done_reading = TRUE;
605 hash_data->total_read += bytes_read;
607 /* we now have the chunk */
610 hash_data->done_reading = TRUE;
615 g_checksum_update (hash_data->checksum, hash_data->buffer, bytes_read);
616 g_signal_emit (hash_data->handler, signals[HASHING_PROGRESS], 0,
617 (guint64) hash_data->total_read, (guint64) hash_data->total_bytes);
621 g_free (hash_data->buffer);
622 hash_data->buffer = NULL;
624 schedule_hash_chunk (hash_data);
628 schedule_hash_chunk (HashingData *hash_data)
630 EmpathyFTHandlerPriv *priv;
632 priv = GET_PRIV (hash_data->handler);
634 if (hash_data->done_reading)
636 g_input_stream_close_async (hash_data->stream, G_PRIORITY_DEFAULT,
637 priv->cancellable, hash_job_async_close_stream_cb, hash_data);
641 if (hash_data->buffer == NULL)
642 hash_data->buffer = g_malloc0 (BUFFER_SIZE);
644 g_input_stream_read_async (hash_data->stream, hash_data->buffer,
645 BUFFER_SIZE, G_PRIORITY_DEFAULT, priv->cancellable,
646 hash_job_async_read_cb, hash_data);
651 ft_handler_read_async_cb (GObject *source,
655 GFileInputStream *stream;
656 GError *error = NULL;
657 HashingData *hash_data;
659 EmpathyFTHandler *handler = user_data;
660 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
662 DEBUG ("GFile read async CB.");
664 stream = g_file_read_finish (priv->gfile, res, &error);
667 priv->is_cancelled = TRUE;
668 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
669 g_clear_error (&error);
674 hash_data = g_slice_new0 (HashingData);
675 hash_data->stream = G_INPUT_STREAM (stream);
676 hash_data->done_reading = FALSE;
677 hash_data->total_bytes = priv->total_bytes;
678 hash_data->handler = g_object_ref (handler);
679 /* FIXME: should look at the CM capabilities before setting the
682 hash_data->checksum = g_checksum_new (G_CHECKSUM_MD5);
684 /* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentHashType */
685 value = tp_g_value_slice_new (G_TYPE_UINT);
686 g_value_set_uint (value, TP_FILE_HASH_TYPE_MD5);
687 g_hash_table_insert (priv->request,
688 TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHashType", value);
690 g_signal_emit (handler, signals[HASHING_STARTED], 0);
692 schedule_hash_chunk (hash_data);
696 ft_handler_complete_request (EmpathyFTHandler *handler)
698 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
699 GError *myerr = NULL;
701 /* check if FT is allowed before firing up the I/O machinery */
702 if (!ft_handler_check_if_allowed (handler))
704 g_set_error_literal (&myerr, EMPATHY_FT_ERROR_QUARK,
705 EMPATHY_FT_ERROR_NOT_SUPPORTED,
706 _("File transfer not supported by remote contact"));
708 priv->is_cancelled = TRUE;
709 g_signal_emit (handler, signals[TRANSFER_ERROR], 0, myerr);
710 g_clear_error (&myerr);
715 /* populate the request table with all the known properties */
716 ft_handler_populate_outgoing_request (handler);
718 /* now start hashing the file */
719 g_file_read_async (priv->gfile, G_PRIORITY_DEFAULT,
720 priv->cancellable, ft_handler_read_async_cb, handler);
724 callbacks_data_free (gpointer user_data)
726 CallbacksData *data = user_data;
729 g_object_unref (data->handler);
731 g_slice_free (CallbacksData, data);
735 ft_handler_gfile_ready_cb (GObject *source,
737 CallbacksData *cb_data)
740 GError *error = NULL;
742 EmpathyFTHandlerPriv *priv = GET_PRIV (cb_data->handler);
744 DEBUG ("Got GFileInfo.");
746 info = g_file_query_info_finish (priv->gfile, res, &error);
751 priv->content_type = g_strdup (g_file_info_get_content_type (info));
752 priv->filename = g_strdup (g_file_info_get_display_name (info));
753 priv->total_bytes = g_file_info_get_size (info);
754 g_file_info_get_modification_time (info, &mtime);
755 priv->mtime = mtime.tv_sec;
756 priv->transferred_bytes = 0;
757 priv->description = NULL;
759 g_object_unref (info);
764 cb_data->callback (cb_data->handler, NULL, cb_data->user_data);
768 cb_data->callback (NULL, error, cb_data->user_data);
769 g_error_free (error);
770 g_object_unref (cb_data->handler);
773 callbacks_data_free (cb_data);
777 ft_handler_contact_ready_cb (EmpathyContact *contact,
780 GObject *weak_object)
782 CallbacksData *cb_data = user_data;
783 EmpathyFTHandlerPriv *priv = GET_PRIV (weak_object);
785 g_assert (priv->contact != NULL);
786 g_assert (priv->gfile != NULL);
788 DEBUG ("Contact is ready.");
790 /* start collecting info about the file */
791 g_file_query_info_async (priv->gfile,
792 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
793 G_FILE_ATTRIBUTE_STANDARD_SIZE ","
794 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
795 G_FILE_ATTRIBUTE_TIME_MODIFIED,
796 G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT,
797 NULL, (GAsyncReadyCallback) ft_handler_gfile_ready_cb,
802 channel_get_all_properties_cb (TpProxy *proxy,
803 GHashTable *properties,
806 GObject *weak_object)
808 CallbacksData *cb_data = user_data;
809 EmpathyFTHandler *handler = EMPATHY_FT_HANDLER (weak_object);
810 EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
811 EmpathyContactFactory *c_factory;
817 cb_data->callback (NULL, (GError *) error, cb_data->user_data);
818 g_object_unref (handler);
822 priv->total_bytes = g_value_get_uint64 (
823 g_hash_table_lookup (properties, "Size"));
825 priv->transferred_bytes = g_value_get_uint64 (
826 g_hash_table_lookup (properties, "TransferredBytes"));
828 priv->filename = g_value_dup_string (
829 g_hash_table_lookup (properties, "Filename"));
831 priv->content_hash = g_value_dup_string (
832 g_hash_table_lookup (properties, "ContentHash"));
834 priv->content_hash_type = g_value_get_uint (
835 g_hash_table_lookup (properties, "ContentHashType"));
837 priv->content_type = g_value_dup_string (
838 g_hash_table_lookup (properties, "ContentType"));
840 priv->description = g_value_dup_string (
841 g_hash_table_lookup (properties, "Description"));
843 g_hash_table_destroy (properties);
845 c_factory = empathy_contact_factory_dup_singleton ();
846 account = empathy_channel_get_account (TP_CHANNEL (proxy));
847 c_handle = tp_channel_get_handle (TP_CHANNEL (proxy), NULL);
848 priv->contact = empathy_contact_factory_get_from_handle
849 (c_factory, account, c_handle);
851 g_object_unref (c_factory);
852 g_object_unref (account);
854 cb_data->callback (handler, NULL, cb_data->user_data);
860 empathy_ft_handler_new_outgoing (EmpathyContact *contact,
862 EmpathyFTHandlerReadyCallback callback,
865 EmpathyFTHandler *handler;
867 EmpathyFTHandlerPriv *priv;
869 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
870 g_return_if_fail (G_IS_FILE (source));
872 handler = g_object_new (EMPATHY_TYPE_FT_HANDLER,
873 "contact", contact, "gfile", source, NULL);
875 priv = GET_PRIV (handler);
877 data = g_slice_new0 (CallbacksData);
878 data->callback = callback;
879 data->user_data = user_data;
880 data->handler = g_object_ref (handler);
882 empathy_contact_call_when_ready (priv->contact,
883 EMPATHY_CONTACT_READY_HANDLE,
884 ft_handler_contact_ready_cb, data, NULL, G_OBJECT (handler));
888 empathy_ft_handler_new_incoming (EmpathyTpFile *tp_file,
889 EmpathyFTHandlerReadyCallback callback,
892 EmpathyFTHandler *handler;
896 g_return_if_fail (EMPATHY_IS_TP_FILE (tp_file));
898 handler = g_object_new (EMPATHY_TYPE_FT_HANDLER,
899 "tp-file", tp_file, NULL);
901 g_object_get (tp_file, "channel", &channel, NULL);
903 data = g_slice_new0 (CallbacksData);
904 data->callback = callback;
905 data->user_data = user_data;
906 data->handler = g_object_ref (handler);
908 tp_cli_dbus_properties_call_get_all (channel,
909 -1, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER,
910 channel_get_all_properties_cb, data, callbacks_data_free, G_OBJECT (handler));
914 empathy_ft_handler_start_transfer (EmpathyFTHandler *handler)
916 EmpathyFTHandlerPriv *priv;
918 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
920 priv = GET_PRIV (handler);
921 priv->cancellable = g_cancellable_new ();
923 if (priv->tpfile == NULL)
925 ft_handler_complete_request (handler);
929 /* emit the start signal now, so that we can catch errors in the
932 g_signal_emit (handler, signals[TRANSFER_STARTED], 0, priv->tpfile);
934 /* TODO: add support for resume. */
935 empathy_tp_file_accept (priv->tpfile, 0, priv->gfile, priv->cancellable,
936 ft_transfer_progress_callback, handler,
937 ft_transfer_operation_callback, handler);
942 empathy_ft_handler_cancel_transfer (EmpathyFTHandler *handler)
944 EmpathyFTHandlerPriv *priv;
946 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
948 priv = GET_PRIV (handler);
950 g_return_if_fail (priv->tpfile != NULL);
952 empathy_tp_file_cancel (priv->tpfile);
956 empathy_ft_handler_incoming_set_destination (EmpathyFTHandler *handler,
959 g_return_if_fail (EMPATHY_IS_FT_HANDLER (handler));
960 g_return_if_fail (G_IS_FILE (destination));
962 g_object_set (handler, "gfile", destination, NULL);
966 empathy_ft_handler_get_filename (EmpathyFTHandler *handler)
968 EmpathyFTHandlerPriv *priv;
970 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL);
972 priv = GET_PRIV (handler);
974 return priv->filename;
978 empathy_ft_handler_get_content_type (EmpathyFTHandler *handler)
980 EmpathyFTHandlerPriv *priv;
982 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL);
984 priv = GET_PRIV (handler);
986 return priv->content_type;
990 empathy_ft_handler_get_contact (EmpathyFTHandler *handler)
992 EmpathyFTHandlerPriv *priv;
994 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL);
996 priv = GET_PRIV (handler);
998 return priv->contact;
1002 empathy_ft_handler_get_gfile (EmpathyFTHandler *handler)
1004 EmpathyFTHandlerPriv *priv;
1006 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), NULL);
1008 priv = GET_PRIV (handler);
1014 empathy_ft_handler_get_state (EmpathyFTHandler *handler,
1015 char **state_string)
1017 EmpathyFTHandlerPriv *priv;
1019 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), -1);
1021 priv = GET_PRIV (handler);
1023 return priv->current_state;
1027 empathy_ft_handler_is_incoming (EmpathyFTHandler *handler)
1029 EmpathyFTHandlerPriv *priv;
1031 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), FALSE);
1033 priv = GET_PRIV (handler);
1035 if (priv->tpfile == NULL)
1038 return empathy_tp_file_is_incoming (priv->tpfile);
1042 empathy_ft_handler_get_transferred_bytes (EmpathyFTHandler *handler)
1044 EmpathyFTHandlerPriv *priv;
1046 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), 0);
1048 priv = GET_PRIV (handler);
1050 return priv->transferred_bytes;
1054 empathy_ft_handler_get_total_bytes (EmpathyFTHandler *handler)
1056 EmpathyFTHandlerPriv *priv;
1058 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), 0);
1060 priv = GET_PRIV (handler);
1062 return priv->total_bytes;
1066 empathy_ft_handler_is_completed (EmpathyFTHandler *handler)
1068 EmpathyFTHandlerPriv *priv;
1070 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), FALSE);
1072 priv = GET_PRIV (handler);
1074 return priv->is_completed;
1078 empathy_ft_handler_is_cancelled (EmpathyFTHandler *handler)
1080 EmpathyFTHandlerPriv *priv;
1082 g_return_val_if_fail (EMPATHY_IS_FT_HANDLER (handler), FALSE);
1084 priv = GET_PRIV (handler);
1086 return priv->is_cancelled;