Add dummy handle functions in the FT module.
/*
* filetransfer.c
*
* Copyrigth (C) 2010 Nicolas Cornu <nicolas.cornu@ensi-bourges.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include "config.h"
#include <glib.h>
#include <string.h>
#include <mcabber/modules.h>
#include <mcabber/utils.h>
#include <mcabber/xmpp_helper.h>
#include <mcabber/settings.h>
#include <mcabber/logprint.h>
#include <jingle/jingle.h>
#include <jingle/check.h>
#include <jingle/register.h>
#include "filetransfer.h"
gconstpointer jingle_ft_check(JingleContent *cn, GError **err);
void jingle_ft_handle(gconstpointer data, LmMessageNode *node);
gboolean jingle_ft_handle_data(gconstpointer data, const gchar *data2, guint len);
static gboolean is_md5_hash(const gchar *hash);
static void jingle_ft_init(void);
static void jingle_ft_uninit(void);
const gchar *deps[] = { "jingle", NULL };
JingleAppFuncs funcs = {
jingle_ft_check,
jingle_ft_handle,
jingle_ft_handle_data
};
module_info_t info_jingle_filetransfer = {
.branch = MCABBER_BRANCH,
.api = MCABBER_API_VERSION,
.version = PROJECT_VERSION,
.description = "Jingle File Transfer (XEP-0234)\n",
.requires = deps,
.init = jingle_ft_init,
.uninit = jingle_ft_uninit,
.next = NULL,
};
gconstpointer jingle_ft_check(JingleContent *cn, GError **err)
{
JingleFT *ft = NULL;
LmMessageNode *node;
const gchar *datestr, *sizestr;
node = lm_message_node_get_child(cn->description, "offer");
if (!node) {
g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
"the offer element is missing");
return NULL;
}
node = lm_message_node_get_child(node, "file");
if (!node) {
g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
"the file element is missing");
return NULL;
}
if (g_strcmp0(lm_message_node_get_attribute(node, "xmlns"), NS_SI_FT)) {
g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_MISSING,
"the file transfer offer has an invalid/unsupported namespace");
return NULL;
}
ft = g_new0(JingleFT, 1);
datestr = lm_message_node_get_attribute(node, "date");
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);
// the size attribute is a xs:integer an therefore can be negative.
if (ft->size < 0) {
g_set_error(err, JINGLE_CHECK_ERROR, JINGLE_CHECK_ERROR_BADVALUE,
"the offered file has a negative size");
g_free(ft);
return NULL;
}
ft->name = g_path_get_basename(ft->name);
if (settings_opt_get("jingle_ft_dir") != NULL)
ft->name = g_build_filename(settings_opt_get("jingle_ft_dir"), ft->name, NULL);
else
ft->name = g_build_filename("/tmp", ft->name, NULL);
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;
}
void jingle_ft_handle(gconstpointer data, LmMessageNode *node)
{
return;
}
gboolean jingle_ft_handle_data(gconstpointer data, const gchar *data2, guint len)
{
return FALSE;
}
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 == 32)
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);
xmpp_add_feature(NS_JINGLE_APP_FT);
}
static void jingle_ft_uninit(void)
{
xmpp_del_feature(NS_JINGLE_APP_FT);
jingle_unregister_app(NS_JINGLE_APP_FT);
}