Add a function to handle incoming data in the filetransfert module.
Also, check the filename and md5 hash in the jingle_ft_check function.
--- a/jingle-filetransfer/filetransfer.c Tue Jul 13 18:30:23 2010 +0200
+++ b/jingle-filetransfer/filetransfer.c Sun Jul 18 18:55:22 2010 +0200
@@ -22,6 +22,7 @@
#include "config.h"
#include <glib.h>
+#include <string.h>
#include <mcabber/modules.h>
#include <mcabber/utils.h>
@@ -35,6 +36,7 @@
gconstpointer jingle_ft_check(JingleContent *cn, GError **err);
+static gboolean is_md5_hash(const gchar *hash);
static void jingle_ft_init(void);
static void jingle_ft_uninit(void);
@@ -83,17 +85,17 @@
ft = g_new0(JingleFT, 1);
datestr = lm_message_node_get_attribute(node, "date");
- ft->hash = lm_message_node_get_attribute(node, "hash");
- ft->name = lm_message_node_get_attribute(node, "name");
+ ft->hash = (gchar *) lm_message_node_get_attribute(node, "hash");
+ ft->name = (gchar *) lm_message_node_get_attribute(node, "name");
sizestr = lm_message_node_get_attribute(node, "size");
-
+
if (!ft->name || !sizestr) {
g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
"an attribute of the file element is missing");
g_free(ft);
return NULL;
}
-
+
ft->date = from_iso8601(datestr, 1);
ft->size = g_ascii_strtoll(sizestr, NULL, 10);
@@ -105,9 +107,68 @@
return NULL;
}
+ ft->name = g_path_get_basename(ft->name);
+ if (!g_strcmp0(ft->name, ".")) {
+ g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_BADVALUE,
+ "the offered file has an invalid filename");
+ g_free(ft->name);
+ g_free(ft);
+ return NULL;
+ }
+
+ // check if the md5 hash is valid ([a-fA-F0-9){32})
+ if (ft->hash != NULL && (strlen(ft->hash) != 32 || !is_md5_hash(ft->hash))) {
+ g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_BADVALUE,
+ "the offered file has an invalid filename");
+ g_free(ft->name);
+ g_free(ft);
+ return NULL;
+ }
+ ft->hash = g_strndup(ft->hash, 32);
+
return (gconstpointer) ft;
}
+static gboolean is_md5_hash(const gchar *hash) {
+ int i = 0;
+ for (i = 0; i < 32 && hash[i]; i++)
+ if (!g_ascii_isxdigit(hash[i])) break;
+
+ if (i == 31)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+gboolean handle_data(gconstpointer *jingleft, const gchar *data, guint len)
+{
+ JingleFT *ft = (JingleFT *) jingleft;
+ GError *err = NULL;
+ GIOStatus status;
+ gsize bytes_written = 0;
+
+ // TODO: check if the file already exist or if it was created
+ // during the call to jingle_ft_check and handle_data
+ if (ft->outfile == NULL) {
+ ft->outfile = g_io_channel_new_file(ft->name, "w", &err);
+ if (ft->outfile == NULL || err != NULL) {
+ // propagate the GError ?
+ return FALSE;
+ }
+ }
+ status = g_io_channel_write_chars(ft->outfile, data, (gssize) len,
+ &bytes_written, &err);
+
+ if (status != G_IO_STATUS_NORMAL || err != NULL) {
+ return FALSE;
+ }
+ if (bytes_written != len) {
+ // not supposed to happen if status is normal, unless outfile is non-blocking
+ return FALSE;
+ }
+ return TRUE;
+}
+
static void jingle_ft_init(void)
{
jingle_register_app(NS_JINGLE_APP_FT, &funcs, JINGLE_TRANS_TCP);
--- a/jingle-filetransfer/filetransfer.h Tue Jul 13 18:30:23 2010 +0200
+++ b/jingle-filetransfer/filetransfer.h Sun Jul 18 18:55:22 2010 +0200
@@ -10,13 +10,16 @@
time_t date;
/* MD5 hash of the file, optional */
- const gchar *hash;
+ gchar *hash;
/* the name of the file that the sender wishes to send */
- const gchar *name;
+ gchar *name;
/* the size, in bytes, of the data to be sent */
gint64 size;
+
+ /* descriptor to the output file */
+ GIOChannel *outfile;
} JingleFT;
#endif