Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno Coudoin <bcoudoin@src.gnome.org>2009-02-05 00:25:57 (GMT)
committer Bruno Coudoin <bruno.coudoin@free.fr>2009-06-20 22:18:43 (GMT)
commit26bbbc542bcfd43f6a753dfea6fbdd2a6c49b6ab (patch)
treeb64faa223b8036aa788b004ff7608a29228890ed
parent1633c0f7d7fabe97e39eeb3baed7eb0c1c21f5b9 (diff)
Miguel DE IZARRA added support for online wordlist.
This save custom data in user_dir and make a content.txt (a md5sum like file) listing custom files. Simply put this files in a web server to diffuse in classroom. GCompris clients are launch with --server and --cache-dir On start, client download content.txt from server. And when a client need a file: - first he search in server list (from content.txt) - if found, he check md5 of file in cache_dir - if md5 isn't ok, file is download in cache_dir file in cache_dir is used - if not found, search in package_dir (like now) svn path=/trunk/; revision=3720
-rw-r--r--ChangeLog51
-rw-r--r--configure.in15
-rw-r--r--src/advanced_colors-activity/advanced_colors.c2
-rw-r--r--src/babymatch-activity/shapegame.c2
-rw-r--r--src/gcompris/board_config_wordlist.c28
-rw-r--r--src/gcompris/dialog.c3
-rw-r--r--src/gcompris/gameutil.c35
-rw-r--r--src/gcompris/gameutil.h1
-rw-r--r--src/gcompris/gc_net.c378
-rw-r--r--src/gcompris/gc_net.h12
-rw-r--r--src/gcompris/gcompris.c8
-rw-r--r--src/gcompris/images_selector.c68
-rw-r--r--src/gcompris/properties.h1
-rw-r--r--src/gcompris/skin.c2
-rw-r--r--src/gcompris/wordlist.c2
-rw-r--r--src/imageid-activity/imageid.c2
-rw-r--r--src/missing_letter-activity/missingletter.c2
-rw-r--r--src/wordprocessor-activity/wordprocessor.c2
18 files changed, 576 insertions, 38 deletions
diff --git a/ChangeLog b/ChangeLog
index 4831c65..3b491c5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,54 @@
-2009-01-31 Bruno coudoin <bruno.coudoin@free.fr>
+2009-06-20 Bruno coudoin <bruno.coudoin@free.fr>
+
+ From trunk.
+ Miguel DE IZARRA added support for online wordlist.
+ This save custom data in user_dir and make a content.txt (a md5sum
+ like file) listing custom files. Simply put this files in a web server
+ to diffuse in classroom.
+
+ GCompris clients are launch with --server and --cache-dir
+ On start, client download content.txt from server.
+
+ And when a client need a file:
+ - first he search in server list (from content.txt)
+ - if found, he check md5 of file in cache_dir
+ - if md5 isn't ok, file is download in cache_dir
+ file in cache_dir is used
+ - if not found, search in package_dir (like now)
+
+ * configure.in:
+ * src/boards/advanced_colors.c: (read_xml_file):
+ * src/boards/imageid.c: (read_xml_file):
+ * src/boards/missingletter.c: (read_xml_file):
+ * src/boards/python/admin/board_list.py:
+ * src/boards/read_colors.c: (read_xml_file):
+ * src/boards/shapegame.c: (read_xml_file):
+ * src/boards/superbrain.c: (mark_pieces):
+ * src/boards/wordprocessor.c: (load_buffer):
+ * src/gcompris/Makefile.am:
+ * src/gcompris/board_config_wordlist.c: (_return_clicked),
+ (gc_board_config_wordlist):
+ * src/gcompris/cache.c:
+ * src/gcompris/config.c: (set_locale_flag):
+ * src/gcompris/dialog.c:
+ * src/gcompris/gameutil.c: (gc_pixmap_load),
+ (gc_file_find_absolute), (gc_file_find_absolute_writeable):
+ * src/gcompris/gameutil.h:
+ * src/gcompris/gc_core.h:
+ * src/gcompris/gc_net.c: (load_md5file), (gc_net_init),
+ (gc_net_destroy), (gc_net_get_url_from_file), (gc_cache_init),
+ (gc_cache_get_relative), (gc_cache_add), (gc_cache_remove),
+ (_table_foreach), (gc_cache_save), (gc_cache_destroy):
+ * src/gcompris/gc_net.h:
+ * src/gcompris/gcompris.c: (setup_window), (cleanup), (main):
+ * src/gcompris/images_selector.c: (gc_selector_images_start),
+ (read_xml_file):
+ * src/gcompris/skin.c: (skin_xml_load):
+ * src/gcompris/wordlist.c: (gc_wordlist_save):
+2009-06-20 Bruno coudoin <bruno.coudoin@free.fr>
+
+ From trunk
Vitali Perchonok is com gmail from vitali.pe
Fixed crash bug when changing level while dragging an item (2 click drag mode)
diff --git a/configure.in b/configure.in
index 247c8d9..d64f83b 100644
--- a/configure.in
+++ b/configure.in
@@ -366,6 +366,20 @@ if test x$TETEX = xno; then
fi
+dnl GNET support
+AC_MSG_CHECKING([wether we build with GNET (if not, networking will be disabled)])
+AC_ARG_ENABLE(gnet,
+ AC_HELP_STRING(
+ [--disable-gnet],
+ [Turn on gnet (will let GCompris fetch content from a web server)]),
+ with_gnet="$enableval", with_gnet="no")
+AC_MSG_RESULT($with_gnet)
+
+if test x$with_gnet = xyes; then
+ PKG_CHECK_MODULES(GNET, gnet-2.0,, AC_MSG_ERROR([*** GNET not found!]))
+ AC_DEFINE([USE_GNET], 1,[Networking is enabled])
+fi
+
dnl SQLITE support
AC_MSG_CHECKING([wether we build with SQLITE (if not profile will be disabled)])
AC_ARG_ENABLE(sqlite,
@@ -830,6 +844,7 @@ echo "Python plugin = $build_python_plugin"
echo "SQLITE database (--enable-sqlite) = $with_sqlite (profiles depend on this)"
echo "DBUS Support (OLPC XO Sugar) = $with_dbus"
+echo "GNET Networking (--enable-gnet) = $with_gnet (networking depends on this)"
echo "BINRELOC (--enable-binreloc) = $br_cv_binreloc"
echo "NSBundle (--enable-nsbundle) = $nsbundle"
diff --git a/src/advanced_colors-activity/advanced_colors.c b/src/advanced_colors-activity/advanced_colors.c
index f03b37f..97f4448 100644
--- a/src/advanced_colors-activity/advanced_colors.c
+++ b/src/advanced_colors-activity/advanced_colors.c
@@ -520,7 +520,7 @@ static gboolean read_xml_file(char *fname)
g_return_val_if_fail(fname!=NULL,FALSE);
/* parse the new file and put the result into newdoc */
- doc = gc_net_load_xml(fname);
+ doc = xmlParseFile(fname);
/* in case something went wrong */
if(!doc)
diff --git a/src/babymatch-activity/shapegame.c b/src/babymatch-activity/shapegame.c
index bc7a4e7..5d60953 100644
--- a/src/babymatch-activity/shapegame.c
+++ b/src/babymatch-activity/shapegame.c
@@ -1720,7 +1720,7 @@ read_xml_file(char *fname)
g_return_val_if_fail(fname!=NULL,FALSE);
/* parse the new file and put the result into newdoc */
- doc = gc_net_load_xml(fname);
+ doc = xmlParseFile(fname);
/* in case something went wrong */
if(!doc)
return FALSE;
diff --git a/src/gcompris/board_config_wordlist.c b/src/gcompris/board_config_wordlist.c
index c0dd7c1..b0609ba 100644
--- a/src/gcompris/board_config_wordlist.c
+++ b/src/gcompris/board_config_wordlist.c
@@ -118,6 +118,22 @@ static void _textview_changed(GtkWidget *w, gpointer data)
gtk_widget_set_sensitive(GTK_WIDGET(u->button), TRUE);
}
+static void _return_clicked(GtkWidget *w, gpointer data)
+{
+ int level;
+ user_param_type_wordlist *u = (user_param_type_wordlist*)data;
+ gchar *filename;
+
+ filename = gc_file_find_absolute_writeable(u->wordlist->filename);
+ gc_cache_remove(filename);
+ g_free(filename);
+
+ level = gtk_combo_box_get_active(u->combo_level)+1;
+ _combo_lang_changed(u->combo_lang, u);
+ gtk_combo_box_set_active(u->combo_level, level-1);
+ _combo_level_changed(u->combo_level, u);
+}
+
static void _button_clicked(GtkWidget *w, gpointer data)
{
user_param_type_wordlist *u = (user_param_type_wordlist*)data;
@@ -223,10 +239,18 @@ GtkWidget *gc_board_config_wordlist(GcomprisBoardConf *config, const gchar *file
gtk_container_add (GTK_CONTAINER(scroll), textview);
/* valid button */
+ hbox = gtk_hbox_new(FALSE, 8);
+ gtk_widget_show(hbox);
+ gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 8);
+
+ GtkWidget * b_default = gtk_button_new_with_label(_("Return to default"));
+ gtk_widget_show(b_default);
+ gtk_box_pack_start(GTK_BOX(hbox), b_default, FALSE, FALSE, 8);
+
button = gtk_button_new_from_stock(GTK_STOCK_APPLY);
gtk_widget_show(button);
gtk_widget_set_sensitive(button, FALSE);
- gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 8);
+ gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 8);
/* user_data */
user_data = g_malloc0(sizeof(user_param_type_wordlist));
@@ -246,6 +270,8 @@ GtkWidget *gc_board_config_wordlist(GcomprisBoardConf *config, const gchar *file
G_CALLBACK(_textview_changed), (gpointer)user_data);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(_button_clicked), (gpointer)user_data);
+ g_signal_connect(G_OBJECT(b_default), "clicked",
+ G_CALLBACK(_return_clicked), (gpointer)user_data);
_combo_lang_changed(GTK_COMBO_BOX(combo_lang), user_data);
diff --git a/src/gcompris/dialog.c b/src/gcompris/dialog.c
index db85b38..2a059e9 100644
--- a/src/gcompris/dialog.c
+++ b/src/gcompris/dialog.c
@@ -27,9 +27,6 @@ static gboolean item_event_ok (GooCanvasItem *item,
GdkEventButton *event,
DialogBoxCallBack dbcb);
-typedef void (*sighandler_t)(int);
-
-
/*
* Close the dialog box if it was open. It not, do nothing.
*/
diff --git a/src/gcompris/gameutil.c b/src/gcompris/gameutil.c
index bd155bd..465ce04 100644
--- a/src/gcompris/gameutil.c
+++ b/src/gcompris/gameutil.c
@@ -87,7 +87,7 @@ GdkPixbuf *gc_pixmap_load_or_null(const gchar *format, ...)
filename = gc_file_find_absolute(pixmapfile);
if(filename)
- pixmap = gc_net_load_pixmap(filename);
+ pixmap = gdk_pixbuf_new_from_file(filename,NULL);
g_free(pixmapfile);
g_free(filename);
@@ -582,6 +582,9 @@ gc_file_find_absolute(const gchar *format, ...)
* Search it on the file system
*/
+ if(properties->server)
+ dir_to_search[i++] = "";
+ dir_to_search[i++] = properties->user_dir;
dir_to_search[i++] = properties->package_data_dir;
dir_to_search[i++] = properties->package_skin_dir;
dir_to_search[i++] = NULL;
@@ -624,6 +627,7 @@ gc_file_find_absolute(const gchar *format, ...)
g_free(filename2);
goto FOUND;
}
+ g_free(absolute_filename);
g_free(filename2);
@@ -653,6 +657,35 @@ gc_file_find_absolute(const gchar *format, ...)
return abs_name;
}
+gchar*
+gc_file_find_absolute_writeable(const gchar *format, ...)
+{
+ gchar *filename, *absolute_filename, *dirname;
+ GcomprisProperties *prop;
+ va_list args;
+
+ va_start (args, format);
+ filename = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ prop = gc_prop_get();
+ absolute_filename = g_build_filename(prop->user_dir, filename,NULL);
+ g_free(filename);
+ dirname = g_path_get_dirname(absolute_filename);
+ if(!g_file_test(dirname, G_FILE_TEST_IS_DIR))
+ {
+ if(g_mkdir_with_parents(dirname, 0755))
+ {
+ g_free(absolute_filename);
+ absolute_filename=NULL;
+ }
+ }
+ g_free(dirname);
+ if(absolute_filename)
+ gc_cache_add(absolute_filename);
+ return absolute_filename;
+}
+
/** Create a directory if needed.
*
* \param rootdir: the directory to create
diff --git a/src/gcompris/gameutil.h b/src/gcompris/gameutil.h
index ff9a640..d062c22 100644
--- a/src/gcompris/gameutil.h
+++ b/src/gcompris/gameutil.h
@@ -85,6 +85,7 @@ void gc_item_rotate_relative_with_center(GooCanvasItem *item, double angle, in
/* find the complete filename looking for the file everywhere (printf formatting supported) */
gchar *gc_file_find_absolute(const gchar *filename, ...);
+gchar *gc_file_find_absolute_writeable(const gchar *filename, ...);
int gc_util_create_rootdir (gchar *rootdir);
void gc_activity_intro_play (GcomprisBoard *gcomprisBoard);
diff --git a/src/gcompris/gc_net.c b/src/gcompris/gc_net.c
index 630a905..ecc7b73 100644
--- a/src/gcompris/gc_net.c
+++ b/src/gcompris/gc_net.c
@@ -1,4 +1,4 @@
-/* gcompris - gc_net.c
+/* gcompris - gameutil_net.c
*
* Copyright (C) 2006 Bruno Coudoin
*
@@ -19,39 +19,373 @@
#include "gc_net.h"
#include "gc_core.h"
#include <string.h>
+#ifdef USE_GNET
+#include <gnet.h>
+#endif
+#include <glib/gstdio.h>
-static gboolean
-path_represents_svg_image (const char *path)
+/* FIXME: Should not be needed, a bug in gnet header ? */
+gboolean gnet_http_get (const gchar *url,
+ gchar **buffer,
+ gsize *length,
+ guint *response);
+
+#ifdef USE_GNET
+static GHashTable *server_content = NULL;
+static GHashTable *cache_content=NULL;
+#define SUPPORT_OR_RETURN(rv) {if(!gc_prop_get()->server) return rv;}
+#else
+#define SUPPORT_OR_RETURN(rv) { return rv; }
+#endif
+
+#ifdef USE_GNET
+static void load_md5file(GHashTable *ht, gchar *content)
{
- /* Synchronous mime sniffing is a really bad idea here
- * since it's only useful for people adding custom icons,
- * and if they're doing that, they can behave themselves
- * and use a .svg extension.
- */
- return path != NULL && (strstr (path, ".svg") != NULL || strstr (path, ".svgz") != NULL);
+ gchar **lines, **keyval;
+ int i;
+
+ lines = g_strsplit(content, "\n", 0);
+ if(lines && lines[0])
+ {
+ for(i=0; lines[i]; i++)
+ {
+ keyval = g_strsplit(lines[i], " ", 2);
+ if(keyval && keyval[0])
+ {
+ g_hash_table_insert(ht, g_strdup(keyval[1]), g_strdup(keyval[0]));
+ }
+ g_strfreev(keyval);
+ }
+ }
+ g_strfreev(lines);
}
+#endif
-/** Load a pixmap localy
+/** Init the network library, must be called once before using it
*
- * \param pixmapfile : a full path to the file to load as an image
- * \return a GdkPixbuf or NULL
*/
-GdkPixbuf *gc_net_load_pixmap(const char *file)
+void gc_net_init()
{
- if (path_represents_svg_image (file))
- return(rsvg_pixbuf_from_file (file, NULL));
+ SUPPORT_OR_RETURN();
+
+#ifdef USE_GNET
+ GcomprisProperties *properties = gc_prop_get();
+ gchar *url;
+ gchar *buf = NULL;
+ gsize buflen;
+ guint response;
+
+ gnet_init();
+
+ /*
+ * Get the content.txt file at the root of the http server and store it in a glist
+ * we then now exactly which files we have there
+ * warning, do not use gc_net_get_url_from_file() since we are in fact buildind the list of file
+ * for it.
+ */
+ url = g_strdup_printf("%s/%s", properties->server, "/content.txt");
+
+ if(gnet_http_get(url, &buf, &buflen, &response) && response == 200)
+ {
+ server_content = g_hash_table_new(g_str_hash, g_str_equal);
+ load_md5file(server_content, buf);
+ }
else
- return(gdk_pixbuf_new_from_file (file, NULL));
+ {
+ /* We did not get the content list, disable network now */
+ g_free(properties->server);
+ properties->server = NULL;
+ g_warning("Failed to initialize networked GCompris because '%s' is not found", url);
+ }
+
+ g_free(buf);
+ g_free(url);
+#endif
+}
+
+void gc_net_destroy(void)
+{
+ SUPPORT_OR_RETURN();
+
+#ifdef USE_GNET
+ if(server_content)
+ g_hash_table_destroy(server_content);
+ server_content = NULL;
+#endif
}
-/** Load an xml file from the network
+/** return an absolute URL if the given file is part of the file available on our server
*
- * \param xmlfile : a full URL to the xml file to load as an xmlDocPtr
- * in case a local file is given, it will be loaded.
- * \return a xmlDocPtr or NULL
+ * \param file: the file to check
+ * \return: a newly allocated URL or NULL
*/
-xmlDocPtr gc_net_load_xml(const char *url)
+gchar *
+gc_net_get_url_from_file(const gchar *format, ...)
+{
+ SUPPORT_OR_RETURN(NULL);
+
+#ifdef USE_GNET
+ GcomprisProperties *properties = gc_prop_get();
+ gchar *file, *cache=NULL, *value;
+ va_list args;
+ gboolean cache_ok=FALSE;
+
+ va_start (args, format);
+ file = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ g_warning("gc_net_get_url_from_file '%s'", file);
+
+ value = g_hash_table_lookup(server_content, (gpointer) file);
+ if(value)
+ {
+ cache = g_strconcat(properties->cache_dir, "/", file, NULL);
+ if(g_file_test(cache, G_FILE_TEST_IS_REGULAR))
+ {
+ gchar * content;
+ gsize length;
+ GMD5 *md5cache, *md5serv;
+
+ /* calc md5 of cache file */
+ g_file_get_contents(cache, &content, &length, NULL);
+ md5cache = gnet_md5_new(content, length);
+ g_free(content);
+
+ md5serv = gnet_md5_new_string(value);
+
+ cache_ok = gnet_md5_equal(md5serv, md5cache);
+
+ gnet_md5_delete(md5serv);
+ gnet_md5_delete(md5cache);
+ }
+ if(cache_ok==0)
+ {
+ gchar *url;
+ gchar *buf = NULL;
+ gsize buflen;
+ guint response;
+
+ url = g_strconcat(properties->server, "/", file, NULL);
+ if(gnet_http_get(url, &buf, &buflen, &response) && response == 200)
+ {
+ gchar *dirname;
+
+ dirname = g_path_get_dirname(cache);
+ g_mkdir_with_parents(dirname, 0755);
+ g_free(dirname);
+ g_file_set_contents(cache, buf, buflen, NULL);
+ g_free(buf);
+ }
+ else
+ { /* file is in content.txt but not in server */
+ g_free(cache);
+ cache = NULL;
+ }
+ }
+ }
+ g_free(file);
+
+ return cache;
+#endif
+ }
+
+#if 0
+/** return a glist with the content of the files in the given directory
+ *
+ * \param dir: the directory to scan
+ * \param ext: optional extention filter. e.g. ".xml" to get only *.xml files.
+ *
+ * \return: a new allocated glist that points to internal elements. Do not free the list
+ * data itself.
+ */
+GSList *gc_net_dir_read_name(const gchar* dir, const gchar *ext)
+{
+ SUPPORT_OR_RETURN(NULL);
+
+#ifdef USE_GNET
+ GSList *filelist = NULL;
+ GSList *i = NULL;
+
+ g_return_val_if_fail(dir!=NULL, NULL);
+
+ for (i = server_content_list; i != NULL; i = g_slist_next (i))
+ {
+ if(strncmp(dir, (gchar *)i->data, strlen(dir)) == 0)
+ if(ext == NULL ||
+ g_str_has_suffix ((gchar *)i->data, ext))
+ filelist = g_slist_prepend(filelist, i->data);
+ }
+
+ return(filelist);
+#endif
+ }
+#endif
+
+
+#define CONTENT_FILENAME "content.txt"
+
+void gc_cache_init(void)
+{
+#ifdef USE_GNET
+ gchar *filename;
+ gchar *buf;
+ gsize buflen;
+
+ cache_content = g_hash_table_new(g_str_hash, g_str_equal);
+ filename = gc_file_find_absolute_writeable(CONTENT_FILENAME);
+
+ if(g_file_get_contents(filename, &buf, &buflen,NULL))
+ {
+ load_md5file(cache_content, buf);
+ g_free(buf);
+ }
+ g_free(filename);
+#endif
+}
+
+#ifdef USE_GNET
+static gchar *gc_cache_get_relative(gchar *filename)
+{
+ gchar *filename_content, *dirname;
+
+ filename_content = gc_file_find_absolute_writeable(CONTENT_FILENAME);
+ dirname = g_path_get_dirname(filename_content);
+ if(g_str_has_prefix(filename, dirname))
+ filename = filename + strlen(dirname) + 1;
+ g_free(filename_content);
+ g_free(dirname);
+ return filename;
+}
+#endif
+
+void gc_cache_add(gchar *filename)
+{
+#ifdef USE_GNET
+ if(cache_content==NULL)
+ return;
+ if(g_str_has_suffix(filename, CONTENT_FILENAME))
+ return;
+
+ filename = gc_cache_get_relative(filename);
+ g_hash_table_insert(cache_content, g_strdup(filename), g_strdup("0"));
+#endif
+}
+
+gchar* gc_cache_import_pixmap(gchar *filename, gchar *boarddir, gint width, gint height)
+{
+#ifdef USE_GNET
+ GdkPixbuf *pixmap;
+ gchar *basename, *file, *ext, *name, *abs;
+
+ if(!g_path_is_absolute(filename))
+ return g_strdup(filename);
+ basename = g_path_get_basename(filename);
+ name = g_build_filename(boarddir, basename,NULL);
+ abs = gc_file_find_absolute(name);
+ if(abs && strcmp(abs,filename)==0)
+ {
+ g_free(basename);
+ g_free(abs);
+ return name;
+ }
+ pixmap = gdk_pixbuf_new_from_file_at_size(filename, width, height,NULL);
+ if(!pixmap)
+ {
+ g_free(abs);
+ g_free(basename);
+ g_free(name);
+ return NULL;
+ }
+
+ file = gc_file_find_absolute_writeable(name);
+ ext = strchr(basename, '.')+1;
+ if(strcmp(ext, "jpg")==0)
+ ext ="jpeg";
+
+ gdk_pixbuf_save(pixmap, file, ext, NULL,NULL);
+
+ g_free(abs);
+ g_free(basename);
+ g_free(file);
+ return name;
+#else
+ return NULL;
+#endif
+}
+
+void gc_cache_remove(gchar *filename)
+{
+#ifdef USE_GNET
+ g_remove(filename);
+ filename = gc_cache_get_relative(filename);
+ g_hash_table_remove(cache_content, filename);
+#endif
+}
+
+struct _table_data
+ {
+ FILE *pf;
+ gchar *path;
+ };
+
+#ifdef USE_GNET
+static void _table_foreach(gpointer key, gpointer value, gpointer user_data)
+{
+ struct _table_data *data = (struct _table_data*)user_data;
+ gchar * content, *filename;
+ gsize length;
+ GMD5 *md5;
+
+ if(strcmp(value, "0")==0)
+ {
+ filename = g_build_filename(data->path, (gchar*)key, NULL);
+ if(g_file_get_contents(filename, &content, &length, NULL))
+ {
+ md5 = gnet_md5_new(content, length);
+ value = gnet_md5_get_string(md5);
+ gnet_md5_delete(md5);
+ g_free(content);
+ }
+ g_free(filename);
+ }
+ if(strcmp(value, "0"))
+ {
+ fprintf(data->pf, "%s %s\n", (gchar*)value, (gchar*)key);
+ }
+}
+#endif
+
+void gc_cache_save(void)
+{
+#ifdef USE_GNET
+ struct _table_data data;
+ FILE *pf;
+ gchar *filename;
+
+ filename = gc_file_find_absolute_writeable(CONTENT_FILENAME);
+ pf = fopen(filename, "w");
+ if(!pf)
+ {
+ g_warning("Couldn't save %s\n", filename);
+ return;
+ }
+
+ data.pf = pf;
+ data.path = g_path_get_dirname(filename);
+ g_hash_table_foreach(cache_content, _table_foreach, &data);
+
+ g_free(filename);
+ g_free(data.path);
+ fclose(pf);
+#endif
+}
+
+void gc_cache_destroy(void)
{
- return(xmlParseFile(url));
+#ifdef USE_GNET
+ gc_cache_save();
+ g_hash_table_destroy(cache_content);
+ cache_content = NULL;
+#endif
}
diff --git a/src/gcompris/gc_net.h b/src/gcompris/gc_net.h
index 598b6d8..c377748 100644
--- a/src/gcompris/gc_net.h
+++ b/src/gcompris/gc_net.h
@@ -31,7 +31,15 @@
#include "gcompris.h"
-GdkPixbuf *gc_net_load_pixmap(const char *url);
-xmlDocPtr gc_net_load_xml(const char *url);
+void gc_net_init();
+gchar *gc_net_get_url_from_file(const gchar *format, ...);
+GSList *gc_net_dir_read_name(const gchar* dir, const gchar *ext);
+void gc_net_destroy();
+
+void gc_cache_init(void);
+void gc_cache_add(gchar *filename);
+void gc_cache_remove(gchar *filename);
+void gc_cache_save(void);
+void gc_cache_destroy(void);
#endif
diff --git a/src/gcompris/gcompris.c b/src/gcompris/gcompris.c
index 72ede83..efbe124 100644
--- a/src/gcompris/gcompris.c
+++ b/src/gcompris/gcompris.c
@@ -730,7 +730,7 @@ static void setup_window ()
NULL);
if(iconfile)
{
- icon_pixbuf = gc_pixmap_load(iconfile);
+ icon_pixbuf = gdk_pixbuf_new_from_file(iconfile, NULL);
g_free(iconfile);
if (icon_pixbuf)
@@ -1060,6 +1060,8 @@ static void cleanup()
gc_db_exit();
gc_fullscreen_set(FALSE);
gc_menu_destroy();
+ gc_net_destroy();
+ gc_cache_destroy();
gc_prop_destroy(gc_prop_get());
}
@@ -1718,6 +1720,10 @@ main (int argc, char *argv[])
single_instance_check();
+ /* networking init */
+ gc_net_init();
+ gc_cache_init();
+
gc_skin_load(properties->skin);
if(properties->music || properties->fx)
diff --git a/src/gcompris/images_selector.c b/src/gcompris/images_selector.c
index 4926bc3..7516b53 100644
--- a/src/gcompris/images_selector.c
+++ b/src/gcompris/images_selector.c
@@ -41,6 +41,7 @@ static gint item_event_imageset_selector(GooCanvasItem *item,
gpointer data);
static void item_event_scroll(GtkAdjustment *adj,
GooCanvas *canvas);
+static gboolean read_xml_file(gchar *fname);
static gboolean read_dataset_directory(gchar *dataset_dir);
static void display_image(gchar *imagename, GooCanvasItem *rootitem);
static void free_stuff (GSList *data);
@@ -262,6 +263,34 @@ gc_selector_images_start (GcomprisBoard *gcomprisBoard, gchar *dataset,
read_dataset_directory(dataseturl);
}
+ else if(dataseturl)
+ {
+ /* Read the given data set file, local or net */
+ read_xml_file(dataseturl);
+ }
+ else
+ {
+ /* Network code for dataset directory */
+ GSList *filelist = NULL;
+ GSList *i = NULL;
+
+ g_free(dataseturl);
+ dataseturl = g_strconcat("boards/", dataset, NULL);
+ /* TODO */
+ filelist = NULL; //gc_net_dir_read_name(dataseturl, ".xml");
+
+ for (i = filelist; i != NULL; i = g_slist_next (i))
+ {
+ gchar *url = gc_file_find_absolute(i->data,
+ NULL);
+ g_warning("processing dataset=%s\n", (char *)i->data);
+ read_xml_file(url);
+ g_free(url);
+ }
+
+ g_slist_free(filelist);
+
+ }
g_free(dataseturl);
/*
@@ -721,6 +750,45 @@ parse_doc(xmlDocPtr doc) {
}
+/* read an xml file into our memory structures and update our view,
+ * dump any old data we have in memory if we can load a new set
+ *
+ * \param fname is an absolute file name
+ *
+ */
+static gboolean
+read_xml_file(gchar *fname)
+{
+ /* pointer to the new doc */
+ xmlDocPtr doc;
+
+ g_return_val_if_fail(fname!=NULL, FALSE);
+
+ doc = xmlParseFile(fname);
+
+ /* in case something went wrong */
+ if(!doc)
+ return FALSE;
+
+ if(/* if there is no root element */
+ !doc->children ||
+ /* if it doesn't have a name */
+ !doc->children->name ||
+ /* if it isn't the good node */
+ g_strcasecmp((gchar *)doc->children->name, "ImageSetRoot")!=0) {
+ xmlFreeDoc(doc);
+ return FALSE;
+ }
+
+ /* parse our document and replace old data */
+ parse_doc(doc);
+
+ xmlFreeDoc(doc);
+
+ return TRUE;
+}
+
+
/** read an xml file into our memory structures and update our view,
* dump any old data we have in memory if we can load a new set
*
diff --git a/src/gcompris/properties.h b/src/gcompris/properties.h
index 46c723b..1eb995c 100644
--- a/src/gcompris/properties.h
+++ b/src/gcompris/properties.h
@@ -63,6 +63,7 @@ typedef struct {
GtkIMContext *context;
gchar *default_context;
gint experimental;
+ gchar *server;
gint drag_mode;
} GcomprisProperties;
diff --git a/src/gcompris/skin.c b/src/gcompris/skin.c
index ba4154d..276e724 100644
--- a/src/gcompris/skin.c
+++ b/src/gcompris/skin.c
@@ -308,7 +308,7 @@ skin_xml_load (gchar* skin)
return;
}
- xmldoc = gc_net_load_xml(xmlfilename);
+ xmldoc = xmlParseFile(xmlfilename);
g_free(xmlfilename);
if(!xmldoc)
diff --git a/src/gcompris/wordlist.c b/src/gcompris/wordlist.c
index b8410c3..8c56080 100644
--- a/src/gcompris/wordlist.c
+++ b/src/gcompris/wordlist.c
@@ -384,7 +384,7 @@ void gc_wordlist_save(GcomprisWordlist *wordlist)
}
}
- filename = gc_file_find_absolute(wordlist->filename);
+ filename = gc_file_find_absolute_writeable(wordlist->filename);
if(filename)
{
if(xmlSaveFormatFileEnc(filename, doc, NULL, 1)<0)
diff --git a/src/imageid-activity/imageid.c b/src/imageid-activity/imageid.c
index 978a646..7f13402 100644
--- a/src/imageid-activity/imageid.c
+++ b/src/imageid-activity/imageid.c
@@ -590,7 +590,7 @@ read_xml_file(char *fname)
g_return_val_if_fail(fname!=NULL, FALSE);
/* parse the new file and put the result into newdoc */
- doc = gc_net_load_xml(fname);
+ doc = xmlParseFile(fname);
/* in case something went wrong */
if(!doc)
diff --git a/src/missing_letter-activity/missingletter.c b/src/missing_letter-activity/missingletter.c
index 1b14640..80a3f79 100644
--- a/src/missing_letter-activity/missingletter.c
+++ b/src/missing_letter-activity/missingletter.c
@@ -639,7 +639,7 @@ read_xml_file(char *fname)
g_return_val_if_fail(fname!=NULL,FALSE);
/* parse the new file and put the result into newdoc */
- doc = gc_net_load_xml(fname);
+ doc = xmlParseFile(fname);
/* in case something went wrong */
if(!doc)
diff --git a/src/wordprocessor-activity/wordprocessor.c b/src/wordprocessor-activity/wordprocessor.c
index 2f8dbae..172e858 100644
--- a/src/wordprocessor-activity/wordprocessor.c
+++ b/src/wordprocessor-activity/wordprocessor.c
@@ -1012,7 +1012,7 @@ load_buffer(gchar *file, gchar *file_type)
GtkTextIter iter_start, iter_end;
/* parse the new file and put the result into newdoc */
- doc = gc_net_load_xml(file);
+ doc = xmlParseFile(file);
/* in case something went wrong */
if(!doc)