aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libempathy/empathy-ft-handler.c267
1 files changed, 120 insertions, 147 deletions
diff --git a/libempathy/empathy-ft-handler.c b/libempathy/empathy-ft-handler.c
index c1365fb86..00bcf3087 100644
--- a/libempathy/empathy-ft-handler.c
+++ b/libempathy/empathy-ft-handler.c
@@ -27,6 +27,7 @@
#include <telepathy-glib/util.h>
#include "empathy-ft-handler.h"
+#include "empathy-contact-factory.h"
#include "empathy-dispatcher.h"
#include "empathy-marshal.h"
#include "empathy-utils.h"
@@ -58,20 +59,14 @@ enum {
};
typedef struct {
- EmpathyFTHandler *handler;
- GFile *gfile;
- GHashTable *request;
- goffset total_size;
-} RequestData;
-
-typedef struct {
- RequestData *req_data;
GInputStream *stream;
gboolean done_reading;
GError *error;
guchar *buffer;
GChecksum *checksum;
gssize total_read;
+ guint64 total_bytes;
+ EmpathyFTHandler *handler;
} HashingData;
typedef struct {
@@ -83,17 +78,21 @@ typedef struct {
/* private data */
typedef struct {
gboolean dispose_run;
- EmpathyContact *contact;
GFile *gfile;
EmpathyTpFile *tpfile;
GCancellable *cancellable;
+ /* request for the new transfer */
+ GHashTable *request;
+
/* transfer properties */
+ EmpathyContact *contact;
gchar *content_type;
gchar *filename;
gchar *description;
guint64 total_bytes;
guint64 transferred_bytes;
+ guint64 mtime;
gchar *content_hash;
EmpFileHashType content_hash_type;
} EmpathyFTHandlerPriv;
@@ -310,40 +309,13 @@ hash_data_free (HashingData *data)
g_error_free (data->error);
data->error = NULL;
}
-
- g_slice_free (HashingData, data);
-}
-
-static void
-request_data_free (RequestData *data)
-{
- if (data->gfile != NULL)
- {
- g_object_unref (data->gfile);
- data->gfile = NULL;
- }
-
- if (data->request != NULL)
+ if (data->handler != NULL)
{
- g_hash_table_unref (data->request);
- data->request = NULL;
+ g_object_unref (data->handler);
+ data->handler = NULL;
}
- g_slice_free (RequestData, data);
-}
-
-static RequestData *
-request_data_new (EmpathyFTHandler *handler, GFile *gfile)
-{
- RequestData *ret;
-
- ret = g_slice_new0 (RequestData);
- ret->request = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
- (GDestroyNotify) tp_g_value_slice_free);
- ret->handler = g_object_ref (handler);
- ret->gfile = g_object_ref (gfile);
-
- return ret;
+ g_slice_free (HashingData, data);
}
static void
@@ -351,41 +323,38 @@ ft_handler_create_channel_cb (EmpathyDispatchOperation *operation,
const GError *error,
gpointer user_data)
{
- RequestData *req_data = user_data;
+ EmpathyFTHandler *handler = user_data;
GError *myerr = NULL;
- EmpathyFTHandlerPriv *priv = GET_PRIV (req_data->handler);
+ EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
DEBUG ("FT: dispatcher create channel CB");
if (error != NULL)
{
/* TODO: error handling */
- goto out;
+ return;
}
priv->tpfile = g_object_ref
(empathy_dispatch_operation_get_channel_wrapper (operation));
- empathy_tp_file_offer (priv->tpfile, req_data->gfile, &myerr);
+ empathy_tp_file_offer (priv->tpfile, priv->gfile, &myerr);
empathy_dispatch_operation_claim (operation);
-
-out:
- request_data_free (req_data);
}
static void
-ft_handler_push_to_dispatcher (RequestData *req_data)
+ft_handler_push_to_dispatcher (EmpathyFTHandler *handler)
{
EmpathyDispatcher *dispatcher;
McAccount *account;
- EmpathyFTHandlerPriv *priv = GET_PRIV (req_data->handler);
+ EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
DEBUG ("FT: pushing request to the dispatcher");
dispatcher = empathy_dispatcher_dup_singleton ();
account = empathy_contact_get_account (priv->contact);
- empathy_dispatcher_create_channel (dispatcher, account, req_data->request,
- ft_handler_create_channel_cb, req_data);
+ empathy_dispatcher_create_channel (dispatcher, account, priv->request,
+ ft_handler_create_channel_cb, handler);
g_object_unref (dispatcher);
}
@@ -415,25 +384,17 @@ ft_handler_check_if_allowed (EmpathyFTHandler *handler)
}
static void
-ft_handler_populate_outgoing_request (RequestData *req_data,
- GFileInfo *file_info)
+ft_handler_populate_outgoing_request (EmpathyFTHandler *handler)
{
guint contact_handle;
- const char *content_type;
- const char *display_name;
- goffset size;
- GTimeVal mtime;
+ GHashTable *request;
GValue *value;
- GHashTable *request = req_data->request;
- EmpathyFTHandlerPriv *priv = GET_PRIV (req_data->handler);
+ EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
- /* gather all the information */
- contact_handle = empathy_contact_get_handle (priv->contact);
+ request = priv->request = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify) tp_g_value_slice_free);
- content_type = g_file_info_get_content_type (file_info);
- display_name = g_file_info_get_display_name (file_info);
- size = g_file_info_get_size (file_info);
- g_file_info_get_modification_time (file_info, &mtime);
+ contact_handle = empathy_contact_get_handle (priv->contact);
/* org.freedesktop.Telepathy.Channel.ChannelType */
value = tp_g_value_slice_new (G_TYPE_STRING);
@@ -452,25 +413,25 @@ ft_handler_populate_outgoing_request (RequestData *req_data,
/* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentType */
value = tp_g_value_slice_new (G_TYPE_STRING);
- g_value_set_string (value, content_type);
+ g_value_set_string (value, priv->content_type);
g_hash_table_insert (request,
EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentType", value);
/* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Filename */
value = tp_g_value_slice_new (G_TYPE_STRING);
- g_value_set_string (value, display_name);
+ g_value_set_string (value, priv->filename);
g_hash_table_insert (request,
EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Filename", value);
/* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Size */
value = tp_g_value_slice_new (G_TYPE_UINT64);
- g_value_set_uint64 (value, (guint64) size);
+ g_value_set_uint64 (value, (guint64) priv->total_bytes);
g_hash_table_insert (request,
EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Size", value);
/* org.freedesktop.Telepathy.Channel.Type.FileTransfer.Date */
value = tp_g_value_slice_new (G_TYPE_UINT64);
- g_value_set_uint64 (value, (guint64) mtime.tv_sec);
+ g_value_set_uint64 (value, (guint64) priv->mtime);
g_hash_table_insert (request,
EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".Date", value);
}
@@ -481,13 +442,15 @@ hash_job_async_close_stream_cb (GObject *source,
gpointer user_data)
{
HashingData *hash_data = user_data;
- RequestData *req_data = hash_data->req_data;
+ EmpathyFTHandler *handler = hash_data->handler;
+ EmpathyFTHandlerPriv *priv;
GError *error = NULL;
GValue *value;
- GHashTable *request;
DEBUG ("FT: closing stream after hashing.");
+ priv = GET_PRIV (handler);
+
/* if we're here we for sure have done reading, check if we stopped due
* to an error.
*/
@@ -514,14 +477,13 @@ hash_job_async_close_stream_cb (GObject *source,
}
/* set the checksum in the request */
- request = req_data->request;
DEBUG ("FT: got file hash %s", g_checksum_get_string (hash_data->checksum));
/* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentHash */
value = tp_g_value_slice_new (G_TYPE_STRING);
g_value_set_string (value, g_checksum_get_string (hash_data->checksum));
- g_hash_table_insert (request,
+ g_hash_table_insert (priv->request,
EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHash", value);
cleanup:
@@ -529,14 +491,15 @@ cleanup:
if (error != NULL)
{
- g_signal_emit (req_data->handler, signals[TRANSFER_ERROR], 0, error);
+ g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
g_clear_error (&error);
- request_data_free (req_data);
}
else
{
+ g_signal_emit (handler, signals[HASHING_DONE], 0);
+
/* the request is complete now, push it to the dispatcher */
- ft_handler_push_to_dispatcher (req_data);
+ ft_handler_push_to_dispatcher (handler);
}
}
@@ -546,7 +509,6 @@ hash_job_async_read_cb (GObject *source,
gpointer user_data)
{
HashingData *hash_data = user_data;
- RequestData *req_data = hash_data->req_data;
gssize bytes_read;
GError *error = NULL;
@@ -571,8 +533,8 @@ hash_job_async_read_cb (GObject *source,
else
{
g_checksum_update (hash_data->checksum, hash_data->buffer, bytes_read);
- g_signal_emit (req_data->handler, signals[HASHING_PROGRESS], 0,
- (guint64) hash_data->total_read, (guint64) req_data->total_size);
+ g_signal_emit (hash_data->handler, signals[HASHING_PROGRESS], 0,
+ (guint64) hash_data->total_read, (guint64) hash_data->total_bytes);
}
out:
@@ -586,9 +548,8 @@ static void
schedule_hash_chunk (HashingData *hash_data)
{
EmpathyFTHandlerPriv *priv;
- RequestData *req_data = hash_data->req_data;
- priv = GET_PRIV (req_data->handler);
+ priv = GET_PRIV (hash_data->handler);
if (hash_data->done_reading)
{
@@ -614,18 +575,16 @@ ft_handler_read_async_cb (GObject *source,
GFileInputStream *stream;
GError *error = NULL;
HashingData *hash_data;
- GHashTable *request;
GValue *value;
- RequestData *req_data = user_data;
+ EmpathyFTHandler *handler = user_data;
+ EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
DEBUG ("FT: GFile read async CB.");
- stream = g_file_read_finish (req_data->gfile, res, &error);
+ stream = g_file_read_finish (priv->gfile, res, &error);
if (error != NULL)
{
- g_signal_emit (req_data->handler, signals[TRANSFER_ERROR], 0, error);
-
- request_data_free (req_data);
+ g_signal_emit (handler, signals[TRANSFER_ERROR], 0, error);
g_clear_error (&error);
return;
@@ -634,21 +593,20 @@ ft_handler_read_async_cb (GObject *source,
hash_data = g_slice_new0 (HashingData);
hash_data->stream = G_INPUT_STREAM (stream);
hash_data->done_reading = FALSE;
- hash_data->req_data = req_data;
+ hash_data->total_bytes = priv->total_bytes;
+ hash_data->handler = g_object_ref (handler);
/* FIXME: should look at the CM capabilities before setting the
* checksum type?
*/
hash_data->checksum = g_checksum_new (G_CHECKSUM_MD5);
- request = req_data->request;
-
/* org.freedesktop.Telepathy.Channel.Type.FileTransfer.ContentHashType */
value = tp_g_value_slice_new (G_TYPE_UINT);
g_value_set_uint (value, EMP_FILE_HASH_TYPE_MD5);
- g_hash_table_insert (request,
+ g_hash_table_insert (priv->request,
EMP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHashType", value);
- g_signal_emit (req_data->handler, signals[HASHING_STARTED], 0);
+ g_signal_emit (handler, signals[HASHING_STARTED], 0);
schedule_hash_chunk (hash_data);
}
@@ -659,36 +617,36 @@ ft_handler_complete_request (EmpathyFTHandler *handler)
EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
GError *myerr = NULL;
- g_cancellable_set_error_if_cancelled (priv->cancellable, &myerr);
-
- if (myerr == NULL)
- {
- if (error != NULL)
- {
- myerr = g_error_copy (error);
- }
- else
- {
- /* check if FT is allowed before firing up the I/O machinery */
- if (!ft_handler_check_if_allowed (req_data->handler))
- {
- g_set_error_literal (&myerr, EMPATHY_FT_ERROR_QUARK,
- EMPATHY_FT_ERROR_NOT_SUPPORTED,
- _("File transfer not supported by remote contact"));
- }
- }
- }
-
- if (myerr != NULL)
+ /* check if FT is allowed before firing up the I/O machinery */
+ if (!ft_handler_check_if_allowed (handler))
{
- g_signal_emit (req_data->handler, signals[TRANSFER_ERROR], 0, myerr);
+ g_set_error_literal (&myerr, EMPATHY_FT_ERROR_QUARK,
+ EMPATHY_FT_ERROR_NOT_SUPPORTED,
+ _("File transfer not supported by remote contact"));
- request_data_free (req_data);
+ g_signal_emit (handler, signals[TRANSFER_ERROR], 0, myerr);
g_clear_error (&myerr);
return;
}
+ /* populate the request table with all the known properties */
+ ft_handler_populate_outgoing_request (handler);
+
+ /* now start hashing the file */
+ g_file_read_async (priv->gfile, G_PRIORITY_DEFAULT,
+ priv->cancellable, ft_handler_read_async_cb, handler);
+}
+
+static void
+callbacks_data_free (gpointer user_data)
+{
+ CallbacksData *data = user_data;
+
+ if (data->handler)
+ g_object_unref (data->handler);
+
+ g_slice_free (CallbacksData, data);
}
static void
@@ -698,26 +656,39 @@ ft_handler_gfile_ready_cb (GObject *source,
{
GFileInfo *info;
GError *error = NULL;
- EmpathyFTHandlerPriv *priv = GET_PRIV (req_data->handler);
+ GTimeVal mtime;
+ EmpathyFTHandlerPriv *priv = GET_PRIV (cb_data->handler);
DEBUG ("FT: got GFileInfo.");
- info = g_file_query_info_finish (req_data->gfile, res, &error);
+ info = g_file_query_info_finish (priv->gfile, res, &error);
+
if (error != NULL)
- {
- /* TODO: error handling */
- g_clear_error (&error);
+ goto out;
- return;
- }
+ priv->content_type = g_strdup (g_file_info_get_content_type (info));
+ priv->filename = g_strdup (g_file_info_get_display_name (info));
+ priv->total_bytes = g_file_info_get_size (info);
+ g_file_info_get_modification_time (info, &mtime);
+ priv->mtime = mtime.tv_sec;
+ priv->transferred_bytes = 0;
+ priv->description = NULL;
- ft_handler_populate_outgoing_request (req_data, info);
+ g_object_unref (info);
- req_data->total_size = g_file_info_get_size (info);
+out:
+ if (error == NULL)
+ {
+ cb_data->callback (cb_data->handler, NULL, cb_data->user_data);
+ }
+ else
+ {
+ cb_data->callback (NULL, error, cb_data->user_data);
+ g_error_free (error);
+ g_object_unref (cb_data->handler);
+ }
- /* now start hashing the file */
- g_file_read_async (req_data->gfile, G_PRIORITY_DEFAULT,
- priv->cancellable, ft_handler_read_async_cb, req_data);
+ callbacks_data_free (cb_data);
}
static void
@@ -746,16 +717,6 @@ ft_handler_contact_ready_cb (EmpathyContact *contact,
}
static void
-callbacks_data_free (gpointer user_data)
-{
- CallbacksData *data = user_data;
-
- g_object_unref (data->handler);
-
- g_slice_free (CallbacksData, data);
-}
-
-static void
channel_get_all_properties_cb (TpProxy *proxy,
GHashTable *properties,
const GError *error,
@@ -765,10 +726,14 @@ channel_get_all_properties_cb (TpProxy *proxy,
CallbacksData *cb_data = user_data;
EmpathyFTHandler *handler = EMPATHY_FT_HANDLER (weak_object);
EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
+ EmpathyContactFactory *c_factory;
+ guint c_handle;
+ McAccount *account;
if (error != NULL)
{
- cb_data->callback (handler, error, cb_data->user_data);
+ cb_data->callback (NULL, error, cb_data->user_data);
+ g_object_unref (handler);
return;
}
@@ -795,6 +760,15 @@ channel_get_all_properties_cb (TpProxy *proxy,
g_hash_table_destroy (properties);
+ c_factory = empathy_contact_factory_dup_singleton ();
+ account = empathy_channel_get_account (TP_CHANNEL (proxy));
+ c_handle = tp_channel_get_handle (TP_CHANNEL (proxy), NULL);
+ priv->contact = empathy_contact_factory_get_from_handle
+ (c_factory, account,c_handle);
+
+ g_object_unref (c_factory);
+ g_object_unref (account);
+
cb_data->callback (handler, NULL, cb_data->user_data);
}
@@ -808,13 +782,16 @@ empathy_ft_handler_new_outgoing (EmpathyContact *contact,
{
EmpathyFTHandler *handler;
CallbacksData *data;
+ EmpathyFTHandlerPriv *priv;
- g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
- g_return_val_if_fail (G_IS_FILE (source), NULL);
+ g_return_if_fail (EMPATHY_IS_CONTACT (contact));
+ g_return_if_fail (G_IS_FILE (source));
handler = g_object_new (EMPATHY_TYPE_FT_HANDLER,
"contact", contact, "gfile", source, NULL);
+ priv = GET_PRIV (handler);
+
data = g_slice_new0 (CallbacksData);
data->callback = callback;
data->user_data = user_data;
@@ -835,8 +812,8 @@ empathy_ft_handler_new_incoming (EmpathyTpFile *tp_file,
TpChannel *channel;
CallbacksData *data;
- g_return_val_if_fail (EMPATHY_IS_TP_FILE (tp_file), NULL);
- g_return_val_if_fail (G_IS_FILE (destination), NULL);
+ g_return_if_fail (EMPATHY_IS_TP_FILE (tp_file));
+ g_return_if_fail (G_IS_FILE (destination));
handler = g_object_new (EMPATHY_TYPE_FT_HANDLER,
"tp-file", tp_file, "gfile", destination, NULL);
@@ -857,7 +834,6 @@ void
empathy_ft_handler_start_transfer (EmpathyFTHandler *handler,
GCancellable *cancellable)
{
- RequestData *data;
EmpathyFTHandlerPriv *priv;
GError *error = NULL;
@@ -868,10 +844,7 @@ empathy_ft_handler_start_transfer (EmpathyFTHandler *handler,
if (priv->tpfile == NULL)
{
- data = request_data_new (handler, priv->gfile);
- empathy_contact_call_when_ready (priv->contact,
- EMPATHY_CONTACT_READY_HANDLE,
- ft_handler_contact_ready_cb, data, NULL, G_OBJECT (handler));
+ ft_handler_complete_request (handler);
}
else
{