aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libempathy/empathy-ft-handler.c113
-rw-r--r--libempathy/empathy-utils.h1
2 files changed, 103 insertions, 11 deletions
diff --git a/libempathy/empathy-ft-handler.c b/libempathy/empathy-ft-handler.c
index f2fafd73b..a41909570 100644
--- a/libempathy/empathy-ft-handler.c
+++ b/libempathy/empathy-ft-handler.c
@@ -61,7 +61,6 @@ enum {
typedef struct {
GInputStream *stream;
- gboolean done_reading;
GError *error;
guchar *buffer;
GChecksum *checksum;
@@ -110,6 +109,9 @@ typedef struct {
static guint signals[LAST_SIGNAL] = { 0 };
+static gboolean do_hash_job_incoming (GIOSchedulerJob *job,
+ GCancellable *cancellable, gpointer user_data);
+
/* GObject implementations */
static void
do_get_property (GObject *object,
@@ -360,6 +362,51 @@ hash_data_free (HashingData *data)
g_slice_free (HashingData, data);
}
+static GChecksumType
+tp_file_hash_to_g_checksum (TpFileHashType type)
+{
+ GChecksumType retval;
+
+ switch (type)
+ {
+ case TP_FILE_HASH_TYPE_MD5:
+ retval = G_CHECKSUM_MD5;
+ break;
+ case TP_FILE_HASH_TYPE_SHA1:
+ retval = G_CHECKSUM_SHA1;
+ break;
+ case TP_FILE_HASH_TYPE_SHA256:
+ retval = G_CHECKSUM_SHA256;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return retval;
+}
+
+static void
+check_hash_incoming (EmpathyFTHandler *handler)
+{
+ HashingData *hash_data;
+ EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
+
+ if (priv->content_hash != NULL)
+ {
+ hash_data = g_slice_new0 (HashingData);
+ hash_data->total_bytes = priv->total_bytes;
+ hash_data->handler = g_object_ref (handler);
+ hash_data->checksum = g_checksum_new
+ (tp_file_hash_to_g_checksum (priv->content_hash_type));
+
+ g_signal_emit (handler, signals[HASHING_STARTED], 0);
+
+ g_io_scheduler_push_job (do_hash_job_incoming, hash_data, NULL,
+ G_PRIORITY_DEFAULT, priv->cancellable);
+ }
+}
+
static void
emit_error_signal (EmpathyFTHandler *handler,
const GError *error)
@@ -392,6 +439,11 @@ ft_transfer_operation_callback (EmpathyTpFile *tp_file,
g_signal_emit (handler, signals[TRANSFER_DONE], 0, tp_file);
empathy_tp_file_close (tp_file);
+
+ if (empathy_ft_handler_is_incoming (handler) && priv->use_hash)
+ {
+ check_hash_incoming (handler);
+ }
}
}
@@ -600,15 +652,29 @@ hash_job_done (gpointer user_data)
goto cleanup;
}
- /* set the checksum in the request */
-
DEBUG ("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 (priv->request,
- TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHash", value);
+ if (empathy_ft_handler_is_incoming (handler))
+ {
+ if (g_strcmp0 (g_checksum_get_string (hash_data->checksum),
+ priv->content_hash))
+ {
+ hash_data->error = g_error_new_literal (EMPATHY_FT_ERROR_QUARK,
+ EMPATHY_FT_ERROR_HASH_MISMATCH,
+ _("The hash of the received file and the sent one do not match"));
+ goto cleanup;
+ }
+ }
+ else
+ {
+ /* set the checksum in the request...
+ * 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 (priv->request,
+ TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER ".ContentHash", value);
+ }
cleanup:
@@ -620,8 +686,9 @@ cleanup:
{
g_signal_emit (handler, signals[HASHING_DONE], 0);
- /* the request is complete now, push it to the dispatcher */
- ft_handler_push_to_dispatcher (handler);
+ if (!empathy_ft_handler_is_incoming (handler))
+ /* the request is complete now, push it to the dispatcher */
+ ft_handler_push_to_dispatcher (handler);
}
hash_data_free (hash_data);
@@ -690,6 +757,31 @@ out:
return FALSE;
}
+static gboolean
+do_hash_job_incoming (GIOSchedulerJob *job,
+ GCancellable *cancellable,
+ gpointer user_data)
+{
+ HashingData *hash_data = user_data;
+ EmpathyFTHandler *handler = hash_data->handler;
+ EmpathyFTHandlerPriv *priv = GET_PRIV (handler);
+ GError *error = NULL;
+
+ /* need to get the stream first */
+ hash_data->stream =
+ G_INPUT_STREAM (g_file_read (priv->gfile, cancellable, &error));
+
+ if (error)
+ {
+ hash_data->error = error;
+ g_io_scheduler_job_send_to_mainloop_async (job, hash_job_done,
+ hash_data, NULL);
+ return FALSE;
+ }
+
+ return do_hash_job (job, cancellable, user_data);
+}
+
static void
ft_handler_read_async_cb (GObject *source,
GAsyncResult *res,
@@ -715,7 +807,6 @@ 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->total_bytes = priv->total_bytes;
hash_data->handler = g_object_ref (handler);
/* FIXME: should look at the CM capabilities before setting the
diff --git a/libempathy/empathy-utils.h b/libempathy/empathy-utils.h
index 681705d59..fc3df4bf9 100644
--- a/libempathy/empathy-utils.h
+++ b/libempathy/empathy-utils.h
@@ -46,6 +46,7 @@ G_BEGIN_DECLS
typedef enum {
EMPATHY_FT_ERROR_FAILED,
+ EMPATHY_FT_ERROR_HASH_MISMATCH,
EMPATHY_FT_ERROR_TP_ERROR,
EMPATHY_FT_ERROR_SOCKET,
EMPATHY_FT_ERROR_NOT_SUPPORTED