[gcompris/gcomprixogoo] Miguel DE IZARRA added support for online wordlist.



commit 26bbbc542bcfd43f6a753dfea6fbdd2a6c49b6ab
Author: Bruno Coudoin <bcoudoin src gnome org>
Date:   Thu Feb 5 00:25:57 2009 +0000

    	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

 ChangeLog                                      |   51 +++-
 configure.in                                   |   15 +
 src/advanced_colors-activity/advanced_colors.c |    2 +-
 src/babymatch-activity/shapegame.c             |    2 +-
 src/gcompris/board_config_wordlist.c           |   28 ++-
 src/gcompris/dialog.c                          |    3 -
 src/gcompris/gameutil.c                        |   35 +++-
 src/gcompris/gameutil.h                        |    1 +
 src/gcompris/gc_net.c                          |  378 ++++++++++++++++++++++--
 src/gcompris/gc_net.h                          |   12 +-
 src/gcompris/gcompris.c                        |    8 +-
 src/gcompris/images_selector.c                 |   68 +++++
 src/gcompris/properties.h                      |    1 +
 src/gcompris/skin.c                            |    2 +-
 src/gcompris/wordlist.c                        |    2 +-
 src/imageid-activity/imageid.c                 |    2 +-
 src/missing_letter-activity/missingletter.c    |    2 +-
 src/wordprocessor-activity/wordprocessor.c     |    2 +-
 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)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]