[monkey-bubble: 666/753] Bring back sane versions of these files. Will be marked as deprecated



commit 2c257a00cfab3740573fd336b83fae23d3b6e0f4
Author: George Lebl <jirka 5z com>
Date:   Sun Aug 26 07:41:14 2001 +0000

    Bring back sane versions of these files. Will be marked as deprecated
    
    Sun Aug 26 07:29:59 2001  George Lebl <jirka 5z com>
    
    	* Makefile.am, gnome-config.[ch], parse-path.cP, gnome-sound.[ch],
    	  gnome-triggersP.h, gnome-triggers.[ch], gnome-i18n.[ch],
    	  gnome-i18nP.h, libgnome.h:  Bring back sane versions of these files.
    	  Will be marked as deprecated where appropriate later after some more
    	  discussion.  In gnome-i18n, don't bring back the broken and
    	  unused crap (preffered language and get_language)
    
    	* gnome-i18nP.h, gnome-exec.c, gnome-init.c, gnome-program.c,
    	  gnome-url.c, test-libgnome.c: Make translations works once more
    
    	* gnome-util.c: paranoia fix, setuid/setgid programs can't use
    	  getenv ("SHELL") (for obvious reasons).

 libgnome/ChangeLog         |   15 +
 libgnome/Makefile.am       |   12 +-
 libgnome/gnome-config.c    | 2144 ++++++++++++++++++++++++++++++++++++++++++++
 libgnome/gnome-config.h    |  291 ++++++
 libgnome/gnome-exec.c      |    2 +
 libgnome/gnome-i18n.c      |  375 ++++++++
 libgnome/gnome-i18n.h      |   49 +-
 libgnome/gnome-i18nP.h     |   57 ++
 libgnome/gnome-init.c      |    1 +
 libgnome/gnome-program.c   |    4 +
 libgnome/gnome-sound.c     |  516 +++++++++++
 libgnome/gnome-sound.h     |   50 +
 libgnome/gnome-triggers.c  |  605 +++++++++++++
 libgnome/gnome-triggers.h  |   84 ++
 libgnome/gnome-triggersP.h |   40 +
 libgnome/gnome-url.c       |    2 +
 libgnome/gnome-util.c      |    8 +-
 libgnome/libgnome.h        |    5 +
 libgnome/test-libgnome.c   |    2 +
 19 files changed, 4253 insertions(+), 9 deletions(-)
---
diff --git a/libgnome/ChangeLog b/libgnome/ChangeLog
index e9ab741..e9d6fc0 100644
--- a/libgnome/ChangeLog
+++ b/libgnome/ChangeLog
@@ -1,3 +1,18 @@
+Sun Aug 26 07:29:59 2001  George Lebl <jirka 5z com>
+
+	* Makefile.am, gnome-config.[ch], parse-path.cP, gnome-sound.[ch],
+	  gnome-triggersP.h, gnome-triggers.[ch], gnome-i18n.[ch],
+	  gnome-i18nP.h, libgnome.h:  Bring back sane versions of these files.
+	  Will be marked as deprecated where appropriate later after some more
+	  discussion.  In gnome-i18n, don't bring back the broken and
+	  unused crap (preffered language and get_language)
+
+	* gnome-i18nP.h, gnome-exec.c, gnome-init.c, gnome-program.c, 
+	  gnome-url.c, test-libgnome.c: Make translations works once more
+
+	* gnome-util.c: paranoia fix, setuid/setgid programs can't use
+	  getenv ("SHELL") (for obvious reasons).
+
 Thu Aug 23 23:23:42 2001  George Lebl <jirka 5z com>
 
 	* gnome-exec.c: fix a 64bit issue with a format string (remember
diff --git a/libgnome/Makefile.am b/libgnome/Makefile.am
index 02add92..c82f0cc 100644
--- a/libgnome/Makefile.am
+++ b/libgnome/Makefile.am
@@ -50,8 +50,14 @@ $(CORBA_SOURCE): $(idls) $(ORBIT_IDL)
 libgnome_src = \
 	libgnometypebuiltins.h	\
 	libgnometypebuiltins.c	\
+	gnome-config.c		\
+	gnome-sound.c		\
+	gnome-triggers.c	\
+	gnome-triggersP.h	\
 	gnome-program.c		\
 	gnome-exec.c		\
+	gnome-i18n.c		\
+	gnome-i18nP.h		\
 	gnome-url.c		\
 	gnome-util.c		\
 	gnome-preferences.c	\
@@ -69,6 +75,9 @@ libinclude_HEADERS = \
 	libgnome.h
 
 libgnome_headers = \
+	gnome-config.h		\
+	gnome-sound.h		\
+	gnome-triggers.h	\
 	gnome-program.h		\
 	gnome-i18n.h		\
 	gnome-exec.h		\
@@ -151,7 +160,8 @@ $(srcdir)/gnome-marshal.c: @REBUILD@ Makefile.am gnome-marshal.list
 EXTRA_DIST = \
 	libgnome-2.0.pc.in		\
 	gnome-marshal.list		\
-	gnome-marshal.c
+	gnome-marshal.c			\
+	parse-path.cP
 
 BUILT_SOURCES = \
 	libgnometypebuiltins.h		\
diff --git a/libgnome/gnome-config.c b/libgnome/gnome-config.c
new file mode 100644
index 0000000..d701b32
--- /dev/null
+++ b/libgnome/gnome-config.c
@@ -0,0 +1,2144 @@
+/*
+ * Configuration-File Functions.
+ *
+ *  Copyright 1993, 1994, 1997 The Free Software Foundation
+ *
+ * Authors: Miguel de Icaza
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License
+   as published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+   
+   The Gnome Library 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
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+/*
+  @NOTATION@
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+/* AIX requires this to be the first thing in the file.  */
+#ifndef __GNUC__
+# if HAVE_ALLOCA_H
+#  include <alloca.h>
+# else
+#  ifdef _AIX
+ #pragma alloca
+#  else
+#   ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+#   endif
+#  endif
+# endif
+#endif
+
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>	/* unlink() */
+#include <stdlib.h>	/* atoi() */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include <ctype.h> /* tolower() */
+
+#include "gnome-i18nP.h"
+#include "gnome-util.h"
+#include "gnome-config.h"
+
+#ifdef HAVE_STRNDUP
+#include <string.h>
+#else
+/* Like strdup, but only copy N chars.  */
+extern char *strndup (const char *s, size_t n);
+#endif
+
+#if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
+# define getc_unlocked(fp) getc (fp)
+#endif
+
+#define STRSIZE 4096
+#define overflow (next == &CharBuffer [STRSIZE-1])
+
+enum {
+	FirstBrace,
+	OnSecHeader,
+	IgnoreToEOL,
+	IgnoreToEOLFirst,
+	KeyDef,
+	KeyDefOnKey,
+	KeyValue
+};
+
+typedef struct {
+	int type;
+	void *value;
+} iterator_type;
+
+typedef enum {
+	LOOKUP,
+	SET
+} access_type;
+
+typedef struct TKeys {
+	char *key_name;
+	char *value;
+	struct TKeys *link;
+} TKeys;
+
+typedef struct TSecHeader {
+	char *section_name;
+	TKeys *keys;
+	struct TSecHeader *link;
+} TSecHeader;
+
+typedef struct TProfile {
+	char *filename;
+	TSecHeader *section;
+	struct TProfile *link;
+	time_t last_checked;
+	time_t mtime;
+	gboolean written_to;
+	gboolean to_be_deleted;
+} TProfile;
+
+/*
+ * Prefix for all the configuration operations
+ * iff the path does not begin with / or with #
+ */
+
+#define prefix (prefix_list ? prefix_list->data : NULL)
+
+static GSList *prefix_list = NULL;
+
+static TProfile *Current = 0;
+
+/*
+ * This one keeps track of all of the opened files
+ */
+static TProfile *Base = 0;
+
+/* The `release_path' and `parsed_path' routines are inside the
+   following file.  It is in a separate file to allow the test-suite
+   to get at it, without needing to export special symbols.
+
+   typedef struct {
+	char *file, *section, *key, *def;
+	char *path, *opath;
+   } ParsedPath;
+
+   static void release_path (ParsedPath *p);
+   static ParsedPath *parse_path (const char *path, gboolean priv); */
+#include "parse-path.cP"
+
+static void 
+free_keys (TKeys *p)
+{
+	if (!p)
+		return;
+	free_keys (p->link);
+	g_free (p->key_name);
+	g_free (p->value);
+	g_free (p);
+}
+
+static void 
+free_sections (TSecHeader *p)
+{
+	if (!p)
+		return;
+	free_sections (p->link);
+	free_keys (p->keys);
+	g_free (p->section_name);
+	p->link = 0;
+	p->keys = 0;
+	g_free (p);
+}
+
+static void 
+free_profile (TProfile *p)
+{
+	if (!p)
+		return;
+	if(Current == p)
+		Current = NULL;
+	free_profile (p->link);
+	free_sections (p->section);
+	g_free (p->filename);
+	g_free (p);
+}
+
+static int 
+is_loaded (const char *filename, TSecHeader **section)
+{
+	TProfile *p = Base;
+	TProfile *lastp = NULL;
+	struct stat st;
+	
+	/*
+	 * if the last one we accessed was this one we don't want to
+	 * search
+	 */
+	if (Current && strcasecmp (filename, Current->filename) == 0){
+		if (Current->last_checked != time (NULL)){
+			if (stat (filename, &st) == -1)
+				st.st_mtime = 0;
+			if (Current->mtime != st.st_mtime) {
+				free_sections (Current->section);
+				Current->section = NULL;
+				Current->filename[0] = '\0';
+				Current->written_to = TRUE;
+				Current->to_be_deleted = FALSE;
+				Current = NULL;
+				return 0;
+			}
+			Current->last_checked = time (NULL);
+		}
+		*section = Current->section;
+		return 1;
+	}
+	
+	while (p){
+		/*search and destroy empty nodes*/
+		if (p->filename[0]=='\0') {
+			TProfile *next = p->link;
+			if(lastp)
+				lastp->link = next;
+			else /*the next one is the first one actually*/
+				Base = next;
+			g_free(p->filename);
+			g_free(p);
+			p = next;
+		} else if (strcasecmp (filename, p->filename) == 0){
+			if (p->last_checked != time (NULL)){
+				if (stat (filename, &st) == -1)
+					st.st_mtime = 0;
+				if (p->mtime != st.st_mtime) {
+					if(p == Current)
+						Current = NULL;
+					free_sections (p->section);
+					p->section = NULL;
+					p->filename[0] = '\0';
+					p->written_to = TRUE;
+					p->to_be_deleted = FALSE;
+					return 0;
+				}
+				p->last_checked = time (NULL);
+			}
+			Current = p;
+			*section = p->section;
+			return 1;
+		} else {
+			lastp = p;
+			p = p->link;
+		}
+	}
+	return 0;
+}
+
+static char *
+decode_string_and_dup (char *s)
+{
+	char *p = g_malloc (strlen (s) + 1);
+	char *q = p;
+
+	do {
+		if (*s == '\\'){
+			switch (*(++s)){
+			case 'n':
+				*p++ = '\n';
+				break;
+			case '\\':
+				*p++ = '\\';
+				break;
+			case 'r':
+				*p++ = '\r';
+				break;
+			default:
+				*p++ = '\\';
+				*p++ = *s;
+			}
+		} else
+			*p++ = *s;
+	} while (*s++);
+	return q;
+}
+
+static char *
+escape_string_and_dup (char *s)
+{
+	char *return_value, *p = s;
+	int len = 0;
+
+	if(!s)
+		return g_strdup("");
+	
+	while (*p){
+		len++;
+		if (*p == '\n' || *p == '\\' || *p == '\r' || *p == '\0')
+			len++;
+		p++;
+	}
+	return_value = p = (char *) g_malloc (len + 1);
+	if (!return_value)
+		return 0;
+	do {
+		switch (*s){
+		case '\n':
+			*p++ = '\\';
+			*p++ = 'n';
+			break;
+		case '\r':
+			*p++ = '\\';
+			*p++ = 'r';
+			break;
+		case '\\':
+			*p++ = '\\';
+			*p++ = '\\';
+			break;
+		default:
+			*p++ = *s;
+		}
+	} while (*s++);
+	return return_value;
+}
+
+static TSecHeader *
+load (const char *file)
+{
+	FILE *f;
+	int state;
+	TSecHeader *SecHeader = 0;
+	char CharBuffer [STRSIZE];
+	char *next = "";		/* Not needed */
+	int c;
+	
+	if ((f = fopen (file, "r"))==NULL)
+		return NULL;
+	
+	state = FirstBrace;
+	while ((c = getc_unlocked (f)) != EOF){
+		if (c == '\r')		/* Ignore Carriage Return */
+			continue;
+		
+		switch (state){
+			
+		case OnSecHeader:
+			if (c == ']' || overflow){
+				*next = '\0';
+				next = CharBuffer;
+				SecHeader->section_name = g_strdup (CharBuffer);
+				state = IgnoreToEOL;
+			} else
+				*next++ = c;
+			break;
+
+		case IgnoreToEOL:
+		case IgnoreToEOLFirst:
+			if (c == '\n'){
+				if (state == IgnoreToEOLFirst)
+					state = FirstBrace;
+				else
+					state = KeyDef;
+				next = CharBuffer;
+			}
+			break;
+
+		case FirstBrace:
+		case KeyDef:
+		case KeyDefOnKey:
+			if (c == '#') {
+				if (state == FirstBrace)
+					state = IgnoreToEOLFirst;
+				else
+					state = IgnoreToEOL;
+				break;
+			}
+
+			if (c == '[' && state != KeyDefOnKey){
+				TSecHeader *temp;
+		
+				temp = SecHeader;
+				SecHeader = (TSecHeader *) g_malloc (sizeof (TSecHeader));
+				SecHeader->link = temp;
+				SecHeader->keys = 0;
+				state = OnSecHeader;
+				next = CharBuffer;
+				break;
+			}
+			/* On first pass, don't allow dangling keys */
+			if (state == FirstBrace)
+				break;
+	    
+			if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
+				break;
+	    
+			if (c == '\n' || overflow) { /* Abort Definition */
+				next = CharBuffer;
+				state = KeyDef;
+                                break;
+                        }
+	    
+			if (c == '=' || overflow){
+				TKeys *temp;
+
+				temp = SecHeader->keys;
+				*next = '\0';
+				SecHeader->keys = (TKeys *) g_malloc (sizeof (TKeys));
+				SecHeader->keys->link = temp;
+				SecHeader->keys->key_name = g_strdup (CharBuffer);
+				state = KeyValue;
+				next = CharBuffer;
+			} else {
+				*next++ = c;
+				state = KeyDefOnKey;
+			}
+			break;
+
+		case KeyValue:
+			if (overflow || c == '\n'){
+				*next = '\0';
+				SecHeader->keys->value = decode_string_and_dup (CharBuffer);
+				state = c == '\n' ? KeyDef : IgnoreToEOL;
+				next = CharBuffer;
+#ifdef GNOME_ENABLE_DEBUG
+#endif
+			} else
+				*next++ = c;
+			break;
+	    
+		} /* switch */
+	
+	} /* while ((c = getc_unlocked (f)) != EOF) */
+	if (c == EOF && state == KeyValue){
+		*next = '\0';
+		SecHeader->keys->value = decode_string_and_dup (CharBuffer);
+	}
+	fclose (f);
+	return SecHeader;
+}
+
+static void 
+new_key (TSecHeader *section, const char *key_name, const char *value)
+{
+	TKeys *key;
+    
+	key = (TKeys *) g_malloc (sizeof (TKeys));
+	key->key_name = g_strdup (key_name);
+	key->value   = g_strdup (value);
+	key->link = section->keys;
+	section->keys = key;
+}
+
+static const char *
+access_config (access_type mode, const char *section_name,
+	       const char *key_name, const char *def, const char *filename,
+	       gboolean *def_used)
+{
+    
+	TProfile   *New;
+	TSecHeader *section;
+	TKeys      *key;
+
+	if (def_used)
+		*def_used = FALSE;
+	if (!is_loaded (filename, &section)){
+		struct stat st;
+		
+		if (stat (filename, &st) == -1)
+			st.st_mtime = 0;
+
+		New = (TProfile *) g_malloc (sizeof (TProfile));
+		New->link = Base;
+		New->filename = g_strdup (filename);
+		New->section = load (filename);
+		New->mtime = st.st_mtime;
+		New->written_to = FALSE;
+		New->to_be_deleted = FALSE;
+		New->last_checked = time (NULL);
+		Base = New;
+		section = New->section;
+		Current = New;
+	}
+    
+	/* Start search */
+	for (; section; section = section->link){
+		/*if section name empty or deleted or not the one we're
+		  looking for, then search on*/
+		if (!section->section_name ||
+		    !*section->section_name ||
+		    strcasecmp (section->section_name, section_name))
+			continue;
+		
+		for (key = section->keys; key; key = key->link){
+			if (strcasecmp (key->key_name, key_name))
+				continue;
+			if (mode == SET){
+				g_free (key->value);
+				key->value = g_strdup (def);
+				Current->written_to = TRUE;
+			}
+			return key->value;
+		}
+
+		/* No key found */
+		if (mode == SET){
+			new_key (section, key_name, def);
+			Current->written_to = TRUE;
+			return 0;
+		}
+	}
+    
+	/* Non existent section */
+	if ((mode == SET) && def){
+		section = (TSecHeader *) g_malloc (sizeof (TSecHeader));
+		section->section_name = g_strdup (section_name);
+		section->keys = 0;
+		new_key (section, key_name, def);
+		section->link = Current->section;
+		Current->section = section;
+		Current->written_to = TRUE;
+	} 
+	if (def_used)
+		*def_used = TRUE;
+	return def;
+}
+
+/* an extended version of access_config for looking up values in ~/.gnome.
+ * For writes it falls through to the standard behaviour.
+ * For lookups, it first checks for the value in
+ * $(datadir)/gnome/config-override, and if it isn't there in ~/.gnome,
+ * then checks $(datadir)/gnome/config, and as a last fallback uses def.
+ * This gives system administrators high level control over the default
+ * configuration values for GNOME
+ *
+ * Note that it doesn't really make sense to have system wide defaults for
+ * ~/.gnome_private data (IMHO), so I haven't addressed it in this
+ * interface. It probably isn't suitable for absolute config file names */
+static const char *
+access_config_extended (access_type mode, const char *section_name,
+			const char *key_name, const char *def,
+			const char *rel_file, gboolean *def_used)
+{
+	char *tmp, *filename;
+	const char *ret_val;
+	gboolean internal_def;
+
+	static time_t cache_time = 0;
+	static char *cache_filename = NULL;
+	static char *cache_overrride_filename = NULL;
+	static char *cache_global_filename = NULL;
+	gboolean cache_valid;
+	time_t now;
+
+	switch (mode) {
+	case SET:
+		/* fall through to normal behaviour */
+		filename = gnome_util_home_file (rel_file);
+		ret_val = access_config (mode, section_name, key_name, def,
+					 filename, def_used);
+		g_free(filename);
+ 		cache_time = 0;  /* Invalidate cache.  */
+		return ret_val;
+	case LOOKUP:
+ 		now = time (NULL);
+ 		cache_valid = (cache_filename &&
+ 			       strcmp (cache_filename, rel_file) == 0 &&
+ 			       now - cache_time <= 2);
+ 		if (!cache_valid) {
+ 			if (cache_filename) 
+				g_free (cache_filename);
+
+ 			cache_filename = g_strdup (rel_file);
+ 			cache_time = now;
+
+ 			if (cache_overrride_filename)
+				g_free (cache_overrride_filename);
+
+ 			tmp = g_concat_dir_and_file ("gnome/config-override",rel_file);
+ 			filename = gnome_program_locate_file
+			    (gnome_program_get (), GNOME_FILE_DOMAIN_CONFIG,
+			     tmp, TRUE, NULL);
+ 			g_free (tmp);
+ 			cache_overrride_filename = filename ? g_strdup (filename) : NULL;
+			
+ 			if (cache_global_filename)
+				g_free (cache_global_filename);
+
+			tmp = g_concat_dir_and_file ("gnome/config", rel_file);
+ 			filename = gnome_program_locate_file
+			    (gnome_program_get (), GNOME_FILE_DOMAIN_CONFIG,
+			     tmp, TRUE, NULL);
+ 			g_free (tmp);
+			cache_global_filename = filename ? g_strdup (filename) : NULL;
+ 		}
+
+		if (cache_overrride_filename) {
+			/* the required config file exists */
+			ret_val = access_config (mode, section_name, key_name,
+						 NULL,
+						 cache_overrride_filename,
+						 &internal_def);
+			if (!internal_def) {
+				if (def_used)
+					*def_used = FALSE;
+				return ret_val;
+			}
+			g_assert (ret_val == NULL);
+		}
+
+		/* fall through to the user config section */
+		filename = gnome_util_home_file (rel_file);
+		ret_val = access_config (mode, section_name, key_name, NULL,
+					 filename, &internal_def);
+		g_free (filename);
+		if (!internal_def) {
+			if (def_used) 
+				*def_used = FALSE;
+			return ret_val;
+		}
+		g_assert (ret_val == NULL);
+
+		/* fall through to the system wide config default tree */
+		if (cache_global_filename) {
+			/* the file exists */
+			ret_val = access_config (mode, section_name, key_name,
+						 def,
+						 cache_global_filename,
+						 def_used);
+			return ret_val;
+		} else {
+			/* it doesn't -- use the default value */
+			if (def_used) 
+				*def_used = TRUE;
+			return def;
+		}
+	}
+	g_assert_not_reached ();
+
+	/* keep the compiler happy */
+	if (def_used) 
+		*def_used = TRUE;
+	return def;
+}
+
+static void 
+dump_keys (FILE *profile, TKeys *p)
+{
+	if (!p)
+		return;
+	dump_keys (profile, p->link);
+	if (*p->key_name) {
+		char *t = escape_string_and_dup (p->value);
+		fprintf (profile, "%s=%s\n", p->key_name, t);
+		g_free (t);
+	}
+}
+
+static void 
+dump_sections (FILE *profile, TSecHeader *p)
+{
+	if (!p)
+		return;
+	dump_sections (profile, p->link);
+	if (p->section_name && p->section_name [0]){
+		fprintf (profile, "\n[%s]\n", p->section_name);
+		dump_keys (profile, p->keys);
+	}
+}
+
+/*check the path and if we need to create directories create them with
+  mode newmode, it needs an absolute path name or it will fail, it
+  needs to be passed the dir and the filename since it will take the
+  filename off*/
+static gint
+check_path(char *path, mode_t newmode)
+{
+	gchar *dirpath;
+	gchar *p;
+	GString *newpath;
+	struct stat s;
+	char *tokp;
+
+	g_return_val_if_fail (path != NULL, FALSE);
+
+	if(strchr(path,'/')==NULL)
+		return FALSE;
+
+	dirpath = strcpy (alloca (strlen (path) + 1), path);
+	g_return_val_if_fail (dirpath != NULL, FALSE);
+
+	if (*dirpath == '\0')
+		return FALSE;
+
+	/*not absolute, we refuse to work*/
+	if (dirpath[0] != '/')
+		return FALSE;
+
+	p = strrchr(dirpath,'/');
+		*p='\0';
+
+	/*special case if directory exists, this is probably gonna happen
+	  a lot so we don't want to go though checking it part by part*/
+	if (stat(dirpath, &s) == 0) {
+		/*check if a directory*/
+		if (!S_ISDIR(s.st_mode))
+			return FALSE;
+		else
+			return TRUE;
+	}
+
+
+	/*skip leading '/'*/
+	p = dirpath;
+	while(*p == '/')
+		p++;
+
+	p = strtok_r(p, "/", &tokp);
+	newpath = g_string_new("");
+	do {
+		newpath = g_string_append_c(newpath,'/');
+		newpath = g_string_append(newpath,p);
+		if(stat(newpath->str,&s)==0) {
+			/*check if a directory*/
+			if(!S_ISDIR(s.st_mode)) {
+				g_string_free(newpath,TRUE);
+				return FALSE;
+			}
+		} else {
+			/*we couldn't stat it .. let's try making the
+			  directory*/
+			if(mkdir(newpath->str,newmode)!=0) {
+				/*error, return false*/
+				g_string_free(newpath,TRUE);
+				return FALSE;
+			}
+		}
+
+	} while ((p = strtok_r(NULL, "/", &tokp)) != NULL);
+
+	g_string_free(newpath,TRUE);
+
+	return TRUE;
+}
+
+
+
+static gboolean 
+dump_profile (TProfile *p, gboolean one_only)
+{
+	gboolean ret = TRUE;
+	FILE *profile;
+    
+	if (!p)
+		return ret;
+	if(!one_only) {
+		if(!dump_profile (p->link, FALSE))
+			ret = FALSE;
+	}
+	
+	/*
+	 * was this profile written to?, if not it's not necessary to dump
+	 * it to disk
+	 */
+	if (!p->to_be_deleted && !p->written_to)
+		return ret;
+
+	/* .ado: p->filename can be empty, it's better to jump over */
+	if (p->filename[0] != '\0') {
+
+		/*
+		 * this file was added to after it was cleaned so it doesn't
+		 * want to be deleted
+		 */
+		if(p->to_be_deleted && p->section)
+			p->to_be_deleted = FALSE;
+		if(p->to_be_deleted) {
+			/*remove the file and remove all it's ramaints
+			  from memory*/
+			unlink(p->filename);
+			/* this already must have been true */
+			/*p->section = 0;*/
+			p->filename [0] = '\0';
+			p->written_to = TRUE;
+			p->to_be_deleted = FALSE;
+			if(p==Current)
+				Current = NULL;
+		} else if (check_path(p->filename,0755) &&
+		    (profile = fopen (p->filename, "w")) != NULL){
+			dump_sections (profile, p->section);
+			fclose (profile);
+		} else {
+			/* we failed at actually writing to the file */
+			ret = FALSE;
+		}
+	}
+	
+	/*mark this to not be dumped any more*/
+	p->written_to = FALSE;
+
+	return ret;
+}
+
+/**
+ * gnome_config_sync:
+ *
+ * Writes all of the information modified by gnome-config to the
+ * disk.
+ *
+ * Note: the gnome_config code does not write anything to the
+ * configuration files until this routine is actually invoked.
+ *
+ * Returns: %TRUE if everything went well.  %FALSE if any file
+ * could not be written to disk.
+ */
+gboolean 
+gnome_config_sync (void)
+{
+	gboolean ret;
+	ret = dump_profile (Base, FALSE);
+	gnome_config_drop_all();
+	return ret;
+}
+
+/**
+ * gnome_config_sync_file:
+ * @path: A gnome-config path
+ *
+ * Writes all of the information modified by gnome-config to the
+ * disk for the given file.
+ *
+ * Note: the gnome_config code does not write anything to the
+ * configuration files until this routine or gnome_config_sync 
+ * is actually invoked.
+ */
+/**
+ * gnome_config_private_sync_file:
+ * @path: A gnome-config path
+ *
+ * Writes all of the information modified by gnome-config to the
+ * disk for the given private file.
+ *
+ * Note: the gnome_config code does not write anything to the
+ * configuration files until this routine or gnome_config_sync 
+ * is actually invoked.
+ *
+ * Returns: %TRUE if everything went well, %FALSE if the file
+ * could not be written to for some reason.  %FALSE is only returned
+ * when a write was actually attempted and failed.
+ */
+gboolean 
+_gnome_config_sync_file (char *path, gboolean priv)
+{
+	gboolean ret = TRUE;
+	TProfile *p;
+	ParsedPath *pp;
+	char *fake_path;
+	
+	if (!path)
+		return ret;
+
+	fake_path = g_concat_dir_and_file (path, "section/key");
+	pp = parse_path (fake_path, priv);
+	g_free (fake_path);
+
+	for (p = Base; p; p = p->link){
+		if (strcmp (pp->file, p->filename) != 0)
+			continue;
+		if(!p->written_to)
+			break;
+		if(!dump_profile (p, TRUE))
+			ret = FALSE;
+		gnome_config_drop_file(path);
+		break;
+	}
+	release_path (pp);
+
+	return ret;
+}
+
+/**
+ * gnome_config_clean_file: 
+ * @path: A gnome-config path
+ *
+ * Cleans up the configuration file specified by @path from any
+ * configuration information.
+ *
+ * Changes will take place after #gnome_config_sync has been invoked.
+ */
+/**
+ * gnome_config_private_clean_file:
+ * @path: A gnome-config path
+ *
+ * Cleans up the private configuration file specified by @path from
+ * any configuration information.
+ *
+ * Changes will take place after #gnome_config_sync has been invoked.
+ */
+void 
+_gnome_config_clean_file (const char *path, gboolean priv)
+{
+	TProfile *p;
+	ParsedPath *pp;
+	char *fake_path;
+	
+	if (!path)
+		return;
+
+	fake_path = g_concat_dir_and_file (path, "section/key");
+	pp = parse_path (fake_path, priv);
+	g_free (fake_path);
+
+	Current = NULL;
+	
+	for (p = Base; p; p = p->link){
+		if (strcmp (pp->file, p->filename) != 0)
+			continue;
+		
+		free_sections (p->section);
+		p->section = NULL;
+		p->written_to = TRUE;
+		p->to_be_deleted = TRUE;
+		release_path (pp);
+		return;
+	}
+	release_path (pp);
+}
+
+/**
+ * gnome_config_drop_file: 
+ * @path: A gnome-config path
+ *
+ * Releases any memory resources that were allocated from accessing
+ * the configuration file in @path.  Changes will take place after
+ * #gnome_config_sync has been invoked
+ */
+/**
+ * gnome_config_private_drop_file:
+ * @path: A gnome-config path
+ *
+ * Releases any memory resources that were allocated from accessing the
+ * private configuration file in @path.
+ */
+void 
+_gnome_config_drop_file (const char *path, gboolean priv)
+{
+	TProfile *p;
+	TProfile *last;
+	ParsedPath *pp;
+	char *fake_path;
+	
+	if (!path)
+		return;
+
+	fake_path = g_concat_dir_and_file (path, "section/key");
+	pp = parse_path (fake_path, priv);
+	g_free (fake_path);
+
+	Current = NULL;
+	
+	for (last = NULL,p = Base; p; last = p, p = p->link){
+		if (strcmp (pp->file, p->filename) != 0)
+			continue;
+		
+		if(last)
+			last->link = p->link;
+		else
+			Base = p->link;
+		
+		free_sections (p->section);
+		g_free(p->filename);
+		g_free(p);
+		release_path (pp);
+		return;
+	}
+	release_path (pp);
+}
+
+/**
+ * gnome_config_init_iterator:
+ * @path: A gnome configuration path for a section.
+ *
+ * Creates an iterator handle that can be used to
+ * iterate over the keys in a section in a gnome configuration
+ * file.  @path must refer to a section.  The returned value
+ * can be used as an iterator for #gnome_config_iterator_next().
+ *
+ * Returns the iterator handle.
+ */
+/**
+ * gnome_config_private_init_iterator:
+ * @path: A gnome configuration path for a section.
+ *
+ * Creates an iterator handle that can be used to
+ * iterate over the keys in a section in a private gnome configuration
+ * file.  @path must refer to a section.  The returned value
+ * can be used as an iterator for #gnome_config_iterator_next().
+ *
+ * Returns the iterator handle.
+ */
+void *
+_gnome_config_init_iterator (const char *path, gboolean priv)
+{
+	TProfile   *New;
+	TSecHeader *section;
+	ParsedPath *pp;
+	char *fake_path;
+	iterator_type *iter;
+
+
+	fake_path = g_concat_dir_and_file (path, "key");
+	pp = parse_path (fake_path, priv);
+	g_free (fake_path);
+	
+	if (!is_loaded (pp->file, &section)){
+		struct stat st;
+		
+		if (stat (pp->file, &st) == -1){
+			st.st_mtime = 0;
+		}
+
+		New = (TProfile *) g_malloc (sizeof (TProfile));
+		New->link = Base;
+		New->filename = g_strdup (pp->file);
+		New->section = load (pp->file);
+		New->mtime = st.st_mtime;
+		New->last_checked = time (NULL);
+		New->written_to = FALSE;
+		New->to_be_deleted = FALSE;
+		Base = New;
+		section = New->section;
+		Current = New;
+	}
+	for (; section; section = section->link){
+		if (strcasecmp (section->section_name, pp->section))
+			continue;
+		iter = g_new (iterator_type, 1);
+		iter->type = 0;
+		iter->value = section->keys;
+		release_path (pp);
+		return iter;
+	}
+	release_path (pp);
+	return 0;
+}
+
+
+/**
+ * gnome_config_init_iterator_sections:
+ * @path: A gnome configuration path for a file.
+ *
+ * Creates an iterator handle that can be used to iterate over the
+ * sections in a gnome configuration file.  @path must refer to a
+ * gnome configuration file.  The returned value can be used as an
+ * iterator for #gnome_config_iterator_next().
+ *
+ * Returns the iterator handle.
+ */
+/**
+ * gnome_config_private_init_iterator_sections:
+ * @path: A gnome configuration path for a file
+ *
+ * Creates an iterator handle that can be used to iterate over the
+ * sections in a private gnome configuration file.  @path must refer to a
+ * gnome configuration file.  The returned value can be used as an
+ * iterator for #gnome_config_iterator_next().
+ *
+ * Returns the iterator handle.
+ */
+void *
+_gnome_config_init_iterator_sections (const char *path, gboolean priv)
+{
+	TProfile   *New;
+	TSecHeader *section;
+	ParsedPath *pp;
+	char *fake_path;
+	iterator_type *iter;
+
+
+	fake_path = g_concat_dir_and_file (path, "section/key");
+	pp = parse_path (fake_path, priv);
+	g_free (fake_path);
+	
+	if (!is_loaded (pp->file, &section)){
+		struct stat st;
+		
+		if (stat (pp->file, &st) == -1)
+			st.st_mtime = 0;
+
+		New = (TProfile *) g_malloc (sizeof (TProfile));
+		New->link = Base;
+		New->filename = g_strdup (pp->file);
+		New->section = load (pp->file);
+		New->mtime = st.st_mtime;
+		New->last_checked = time (NULL);
+		New->written_to = FALSE;
+		New->to_be_deleted = FALSE;
+		Base = New;
+		section = New->section;
+		Current = New;
+	}
+	iter = g_new (iterator_type, 1);
+	iter->type = 1;
+	iter->value = section;
+	release_path (pp);
+	return iter;
+}
+
+/**
+ * gnome_config_iterator_next:
+ * @iterator_handle: A gnome configu iterator handle, returned from any
+ *                   iteration start routine or this routine.
+ * @key:   Address where the key gets stored.
+ * @value: Address where the value gets stored.
+ *
+ *
+ * Returns a new iterator handle.
+ *
+ * If @key is non-NULL, then @key will point to a g_malloc()ed region that
+ * holds the key.
+ *
+ * If @value is non-NULL, then @value will point to a g_malloc()ed region that
+ * holds the key.
+ *
+ */
+void *
+gnome_config_iterator_next (void *iterator_handle, char **key, char **value)
+{
+	iterator_type *iter = iterator_handle;
+
+        /*
+	 * g_return_if_fail is not appropriate since this is not
+	 * really a failure, but passing in an "empty" iterator (we
+	 * return NULL at times)
+	 */
+	if(!iterator_handle)
+		return NULL; 
+
+	if (key)
+		*key = NULL;
+	if (value)
+		*value = NULL;
+	
+	if (iter->type == 0){
+		TKeys *keys;
+		keys = iter->value;
+		if (keys){
+			if (key)
+				*key   = g_strdup (keys->key_name);
+			if (value)
+				*value = g_strdup (keys->value);
+			keys   = keys->link;
+			iter->value = keys;
+			return iter;
+		} else {
+			g_free (iter);
+			return 0;
+		}
+	} else {
+		TSecHeader *section;
+		section = iter->value;
+
+		if (section){
+			if (key)
+				*key = g_strdup (section->section_name);
+			section = section->link;
+			iter->value = section;
+			return iter;
+		} else {
+			g_free (iter);
+			return 0;
+		}
+	}
+}
+
+/**
+ * gnome_config_clean_section:
+ * @path: a gnome configuration path to a section.
+ *
+ * Cleans up the section specified by @path from any
+ * configuration information.  Changes will only take place
+ * after #gnome_config_sync has been invoked.
+ */
+/**
+ * gnome_config_private_clean_section:
+ * @path: a gnome configuration path to a section.
+ *
+ * Cleans up the section specified by @path in a private file from any
+ * configuration information.  Changes will only take place after
+ * #gnome_config_sync has been invoked.
+ */
+void 
+_gnome_config_clean_section (const char *path, gboolean priv)
+{
+	TProfile   *New;
+	TSecHeader *section;
+	ParsedPath *pp;
+	char *fake_path;
+	
+	fake_path = g_concat_dir_and_file (path, "key");
+	pp = parse_path (fake_path, priv);
+	g_free (fake_path);
+	
+	if (!is_loaded (pp->file, &section)){
+		struct stat st;
+
+		if (stat (pp->file, &st) == -1)
+			st.st_mtime = 0;
+
+		New = (TProfile *) g_malloc (sizeof (TProfile));
+		New->link = Base;
+		New->filename = g_strdup (pp->file);
+		New->section = load (pp->file);
+		New->mtime = st.st_mtime;
+		New->last_checked = time (NULL);
+		New->written_to = FALSE;
+		New->to_be_deleted = FALSE;
+		Base = New;
+		section = New->section;
+		Current = New;
+	}
+	/* We only disable the section, so it will still be g_freed, but it */
+	/* won't be found by further walks of the structure */
+
+	for (; section; section = section->link){
+		if (strcasecmp (section->section_name, pp->section))
+			continue;
+		section->section_name [0] = '\0';
+		Current->written_to = TRUE;
+	}
+	release_path (pp);
+}
+
+/**
+ * gnome_config_clean_key:
+ * @path: a gnome configuration path to a key.
+ *
+ * Removes the definition for the key on a gnome configuration file.
+ *
+ * Changes will take place after #gnome_config_sync has been invoked.
+ */
+/**
+ * gnome_config_private_clean_key:
+ * @path: a gnome configuration path to a key.
+ *
+ * Removes the definition for the key on a private gnome configuration
+ * file.
+ *
+ * Changes will take place after #gnome_config_sync has been invoked.
+ */
+void 
+_gnome_config_clean_key (const char *path, gboolean priv)
+	/* *section_name, char *file */
+{
+	TProfile   *New;
+	TSecHeader *section;
+	TKeys *key;
+	ParsedPath *pp;
+	
+	pp = parse_path (path, priv);
+	
+	if (!is_loaded (pp->file, &section)){
+		struct stat st;
+		
+		if (stat (pp->file, &st) == -1)
+			st.st_mtime = 0;
+
+		New = (TProfile *) g_malloc (sizeof (TProfile));
+		New->link = Base;
+		New->filename = g_strdup (pp->file);
+		New->section = load (pp->file);
+		New->mtime = st.st_mtime;
+		New->written_to = FALSE;
+		New->last_checked = time (NULL);
+		New->to_be_deleted = FALSE;
+		Base = New;
+		section = New->section;
+		Current = New;
+	}
+	for (; section; section = section->link){
+	        if (strcasecmp (section->section_name, pp->section))
+		        continue;
+		for (key = section->keys; key; key = key->link){
+			if (strcasecmp (key->key_name, pp->key))
+				continue;
+			key->key_name [0] = 0;
+			Current->written_to = TRUE;
+		}
+	}
+	release_path (pp);
+}
+
+/**
+ * gnome_config_has_section:
+ * @path: A gnome configuration path to a section
+ *
+ * Queries the gnome configuration file for the presence
+ * of the section specified in @path.
+ *
+ * Returns TRUE if the section exists.  FALSE otherwise.
+ */
+/**
+ * gnome_config_private_has_section:
+ * @path: A gnome configuration path to a section
+ *
+ * Queries the private gnome configuration file for the presence
+ * of the section specified in @path.
+ *
+ * Returns TRUE if the section exists.  FALSE otherwise.
+ */
+gboolean 
+_gnome_config_has_section (const char *path, gboolean priv)
+	/* char *section_name, char *profile */
+{
+	TProfile   *New;
+	TSecHeader *section;
+	ParsedPath *pp;
+	char *fake_path;
+
+	fake_path = g_concat_dir_and_file (path, "key");
+	pp = parse_path (fake_path,priv);
+	g_free (fake_path);
+	
+	if (!is_loaded (pp->file, &section)){
+		struct stat st;
+		
+		if (stat (pp->file, &st) == -1)
+			st.st_mtime = 0;
+
+		New = (TProfile *) g_malloc (sizeof (TProfile));
+		New->link = Base;
+		New->filename = g_strdup (pp->file);
+		New->section = load (pp->file);
+		New->mtime = st.st_mtime;
+		New->written_to = FALSE;
+		New->last_checked = time (NULL);
+		New->to_be_deleted = FALSE;
+		Base = New;
+		section = New->section;
+		Current = New;
+	}
+	for (; section; section = section->link){
+		if (strcasecmp (section->section_name, pp->section))
+			continue;
+		release_path (pp);
+		return 1;
+	}
+	release_path (pp);
+	return 0;
+}
+
+/**
+ * gnome_config_drop_all:
+ *
+ * Drops any information cached in memory that was fetched with
+ * gnome config.  Any pending information that has not been
+ * written to disk is discarded.
+ */
+void 
+gnome_config_drop_all (void)
+{
+	free_profile (Base);
+	Base = NULL;
+	Current = NULL;
+}
+
+/**
+ * gnome_config_get_int:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as an integer.
+ */
+/**
+ * gnome_config_private_get_int:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as an integer.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+/**
+ * gnome_config_get_int_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as an integer.
+ */
+/**
+ * gnome_config_private_get_int_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as an integer.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+gint
+_gnome_config_get_int_with_default (const char *path, gboolean *def, gboolean priv)
+{
+	ParsedPath *pp;
+	const char *r;
+	int  v;
+	
+	pp = parse_path (path, priv);
+	/*is there a better way to check if an absolute path has been given?*/
+	if (!priv && pp->opath[0] != '=')
+		r = access_config_extended (LOOKUP, pp->section, pp->key,
+					    pp->def, pp->path, def);
+	else
+		r = access_config (LOOKUP, pp->section, pp->key, pp->def,
+				   pp->file, def);
+
+	/* It isn't an error if the key is not found.  */
+	if (r == NULL) {
+		release_path (pp);
+		return 0;
+	}
+
+	v = atoi (r);
+	release_path (pp);
+	return v;
+}
+
+/**
+ * gnome_config_get_float:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as a floating-point
+ * number.
+ */
+/**
+ * gnome_config_private_get_float:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as a floating-point number.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+/**
+ * gnome_config_get_float_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a floating-point number.
+ */
+/**
+ * gnome_config_private_get_float_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a floating-point number.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+gdouble
+_gnome_config_get_float_with_default (const char *path, gboolean *def, gboolean priv)
+{
+	ParsedPath *pp;
+	const char *r;
+	gdouble v;
+	
+	pp = parse_path (path, priv);
+	if (!priv && pp->opath[0] != '=')
+		r = access_config_extended (LOOKUP, pp->section, pp->key,
+					    pp->def, pp->path, def);
+	else
+		r = access_config (LOOKUP, pp->section, pp->key, pp->def,
+				   pp->file, def);
+
+	/* It isn't an error if the key is not found.  */
+	if (r == NULL) {
+		release_path (pp);
+		return 0;
+	}
+
+        /* make sure we read values in a consistent manner */
+	gnome_i18n_push_c_numeric_locale ();
+	v = strtod(r, NULL);
+	gnome_i18n_pop_c_numeric_locale ();
+
+	release_path (pp);
+	return v;
+}
+
+/*
+ * same as _gnome_config_get_string_with_default, but using (ParsedPath *)
+ */
+static char *
+get_string_with_default_from_pp (ParsedPath *pp, gboolean *def, gboolean priv)
+{
+	const char *r;
+	char *ret = NULL;
+	
+	if (!priv && pp->opath[0] != '=')
+		r = access_config_extended (LOOKUP, pp->section, pp->key,
+					    pp->def, pp->path, def);
+	else
+		r = access_config (LOOKUP, pp->section, pp->key, pp->def,
+				   pp->file, def);
+	if (r)
+		ret = g_strdup (r);
+	return ret;
+}
+
+/*
+ * like get_string_with_default_from_pp but with language
+ * This is because we must work on the parsed path to add the language
+ * thingie.
+ */
+static char *
+get_string_with_default_from_pp_with_lang (ParsedPath *pp,
+					   const char *lang,
+					   gboolean *def,
+					   gboolean priv)
+{
+	char *value;
+	char *oldkey;
+
+	/* switch the key in the key from underneath it, then
+	 * return it back */
+	oldkey = pp->key;
+	pp->key = g_strconcat (oldkey, "[", lang, "]", NULL);
+	value = get_string_with_default_from_pp (pp, def, priv);
+	g_free (pp->key);
+	pp->key = oldkey;
+
+	return value;
+}
+
+/**
+ * gnome_config_get_translated_string:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as a string
+ * appropriate for the current language. The returned value should be
+ * g_free()'d when no longer needed.
+ */
+/**
+ * gnome_config_private_get_translated_string:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as a string appropriate for the current language. The returned value should be
+ * g_free()'d when no longer needed.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+/**
+ * gnome_config_get_translated_string_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string appropriate for the current language. The returned value should be
+ * g_free()'d when no longer needed.
+ */
+/**
+ * gnome_config_private_get_translated_string_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string appropriate for the current language. The returned value should be
+ * g_free()'d when no longer needed.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+char *
+_gnome_config_get_translated_string_with_default (const char *path,
+						  gboolean *def,
+						  gboolean priv)
+{
+	ParsedPath *pp;
+	const GList *language_list;
+	gboolean local_def = FALSE;
+
+	char *value= NULL;
+
+	language_list = gnome_i18n_get_language_list ("LC_MESSAGES");
+
+	pp = parse_path (path, priv);
+
+	while (!value && language_list) {
+		const char *lang= language_list->data;
+
+		value = get_string_with_default_from_pp_with_lang
+			(pp, lang, &local_def, priv);
+
+		if (local_def || !value || *value == '\0') {
+			size_t n;
+
+			g_free (value);
+			value= NULL;
+
+			/* Sometimes the locale info looks
+			   like `pt_PT verbose'.  In this case
+			   we want to try `pt' as a backup.  */
+			n = strcspn (lang, "@_");
+			if (lang[n]) {
+				char *copy = g_strndup (lang, n);
+
+				value = get_string_with_default_from_pp_with_lang (pp, copy, &local_def, priv);
+				g_free (copy);
+				if (local_def || ! value || *value == '\0') {
+					g_free (value);
+					value = NULL;
+				}
+			}
+		}
+		language_list = language_list->next;
+	}
+
+	if (def != NULL) {
+		*def = local_def;
+	}
+
+	if (!value){
+		value = get_string_with_default_from_pp (pp, def, priv);
+
+		if (!value || *value == '\0'){
+			g_free (value);
+			value = NULL;
+		}
+	}
+
+	release_path (pp);
+
+	return value;
+}
+
+/**
+ * gnome_config_get_string:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as a string.
+ * The returned value should be
+ * g_free()'d when no longer needed.
+ */
+/**
+ * gnome_config_private_get_string:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as a
+ * string. The returned value should be g_free()'d when no longer
+ * needed.  The item is retrieved from the user's private
+ * configuration storage area.
+ */
+/**
+ * gnome_config_get_string_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string.
+ * The returned value should be g_free()'d when no longer needed.
+ *
+ */
+/**
+ * gnome_config_private_get_string_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string.
+ * The returned value should be g_free()'d when no longer needed.  The
+ * item is retrieved from the user's private configuration storage
+ * area.
+ *
+ */
+char *
+_gnome_config_get_string_with_default (const char *path, gboolean *def,
+				       gboolean priv)
+{
+	ParsedPath *pp;
+	char *ret;
+	
+	pp = parse_path (path, priv);
+	ret = get_string_with_default_from_pp (pp, def, priv);
+	release_path (pp);
+
+	return ret;
+}
+
+/**
+ * gnome_config_get_bool:
+ * @path: A gnome configuration path to an item.
+ *
+ * Retrieves & returns the value of a configuration item as a boolean.
+ */
+/**
+ * gnome_config_private_get_bool:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ *
+ * Retrieves & returns the value of a configuration item as a boolean.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+/**
+ * gnome_config_get_bool_with_default:
+ * @path: A gnome configuration path to an item.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a boolean.
+ */
+/**
+ * gnome_config_private_get_bool_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a boolean.
+ * The item is retrieved from the user's private configuration storage area.
+ */
+gboolean
+_gnome_config_get_bool_with_default (const char *path, gboolean *def,
+				     gboolean priv)
+{
+	ParsedPath *pp;
+	const char *r;
+	int  v;
+	
+	pp = parse_path (path, priv);
+	if (!priv && pp->opath[0] != '=')
+		r = access_config_extended (LOOKUP, pp->section, pp->key,
+					    pp->def, pp->path, def);
+	else
+		r = access_config (LOOKUP, pp->section, pp->key, pp->def,
+				   pp->file, def);
+
+	/* It isn't an error if the key is not found.  */
+	if (r == NULL) {
+		release_path (pp);
+		return 0;
+	}
+
+	if (tolower(*r) == 't' || tolower(*r) == 'y' || atoi(r)) {
+	  v = 1;
+	} else {
+	  /* If it's not true it has to be false :) */
+	  v = 0;
+	}
+	release_path (pp);
+	return v;
+}
+
+/**
+ * gnome_config_make_vector:
+ * @string: The stringified vector to decode into 'argcp' and 'argvp'
+ * @argcp: Returns the number of elements in 'argvp'
+ * @argvp: Returns the array of strings found in 'rr'.
+ *
+ * Creates a new vector from a string as it stored in the config file,
+ * breaks the string on spaces except if the space is escaped with a
+ * backslash.
+ *
+ */
+void
+gnome_config_make_vector (const char *string, int *argcp, char ***argvp)
+{
+	char *p;
+	int count, esc_spcs;
+	int space_seen;
+
+	/* Figure out how large to make return vector.  Start at 2
+	 * because we want to make NULL-terminated array, and because
+	 * the loop doesn't count the final element.
+	 */
+	count = 2;
+	space_seen = 0;
+	for (p = (char *) string; *p; ++p) {
+	        if (*p == '\\' && *(p+1)) {
+			++p;
+			if (space_seen){
+				count++;
+				space_seen = 0;
+			}
+		} else if (*p == ' ') {
+			space_seen = 1;
+		} else if (space_seen){
+			count++;
+			space_seen = 0;
+		}
+	}
+
+	*argcp = count - 1;
+	*argvp = (char **) g_malloc0 (count * sizeof (char *));
+
+	p = (char *) string;
+	count = 0;
+	do {
+		char *s, *tmp = p;
+
+		esc_spcs = 0;
+		while (*p && (esc_spcs ? 1 : (*p != ' '))){
+			esc_spcs = 0;
+			if (*p == '\\')
+				esc_spcs = 1;
+			p++;
+		}
+
+ 		s = (char *) g_strndup (tmp, p - tmp);
+
+		(*argvp)[count++] = tmp = s;
+
+		while (*s) {
+			if (*s == '\\') 
+				s++;				
+			if (!*s) break;
+			*tmp++ = *s++;
+		}
+		*tmp = '\0';
+
+		while (*p && *p == ' ')
+			p++;
+	} while (*p);
+}
+
+/**
+ * gnome_config_get_vector:
+ * @path: A gnome configuration path to an item.
+ * @argcp: Number of elements in the vector
+ * @argvp: Vector of strings
+ *
+ * Retrieves & returns the value of a configuration item as a string array.
+ * The returned value should be
+ * g_free()'d when no longer needed.
+ */
+/**
+ * gnome_config_private_get_vector:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @argcp: Number of elements in the vector
+ * @argvp: Vector of strings
+ *
+ * Retrieves & returns the value of a configuration item as a
+ * string. The returned value should be g_free()'d when no longer
+ * needed.  The item is retrieved from the user's private
+ * configuration storage area.
+ */
+/**
+ * gnome_config_get_vector_with_default:
+ * @path: A gnome configuration path to an item.
+ * @argcp: Number of elements in the vector
+ * @argvp: Vector of strings
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string array.
+ * The returned value should be g_free()'d when no longer needed.
+ *
+ */
+/**
+ * gnome_config_private_get_vector_with_default:
+ * @path: A gnome configuration path to an item in the user-private namespace.
+ * @argcp: Number of elements in the vector
+ * @argvp: Vector of strings
+ * @def: A pointer to a flag that will be set if the default value for the item
+ * is returned.
+ *
+ * Retrieves & returns the value of a configuration item as a string array.
+ * The returned value should be g_free()'d when no longer needed.  The
+ * item is retrieved from the user's private configuration storage
+ * area.
+ *
+ */
+void
+_gnome_config_get_vector_with_default (const char *path, int *argcp,
+				       char ***argvp, gboolean *def, gboolean priv)
+{
+	ParsedPath *pp;
+	const char *rr;
+	
+	pp = parse_path (path, priv);
+	if (!priv && pp->opath[0] != '=')
+		rr = access_config_extended (LOOKUP, pp->section, pp->key,
+					     pp->def, pp->path, def);
+	else
+		rr = access_config (LOOKUP, pp->section, pp->key, pp->def,
+				    pp->file, def);
+
+	if (rr == NULL) {
+		*argvp = NULL;
+		*argcp = 0;
+	} else
+		gnome_config_make_vector (rr, argcp, argvp);
+	release_path (pp);
+}
+
+/**
+ * gnome_config_set_translated_string:
+ * @path: a gnome configuration path to a key
+ * @value: a string value to set.
+ * 
+ * Stores the string value @new_value in the file/section/key defined
+ * by the @path on the proper section for the current language set by
+ * by the user.
+ */
+void
+_gnome_config_set_translated_string (const char *path, const char *value,
+				     gboolean priv)
+{
+	const GList *language_list;
+	const char *lang;
+	char *tkey;
+
+	language_list = gnome_i18n_get_language_list("LC_MESSAGES");
+
+	lang= language_list ? language_list->data : NULL;
+
+	if (lang && (strcmp (lang, "C") != 0)) {
+		tkey = g_strconcat (path, "[", lang, "]", NULL);
+		_gnome_config_set_string(tkey, value, priv);
+		g_free (tkey);
+	} else
+		_gnome_config_set_string (path, value, priv);
+}
+
+/**
+ * gnome_config_set_string:
+ * @path: a gnome configuration path to a key
+ * @new_value: a string value to set.
+ *
+ * Stores the string value @new_value in the file/section/key
+ * defined by the @path
+ */
+void
+_gnome_config_set_string (const char *path, const char *new_value, gboolean priv)
+{
+	ParsedPath *pp;
+	const char *r;
+	
+	pp = parse_path (path, priv);
+	r = access_config (SET, pp->section, pp->key, new_value, pp->file,
+			   NULL);
+	release_path (pp);
+}
+
+/**
+ * gnome_config_set_int:
+ * @path: a gnome configuration path to a key
+ * @new_value: a int value to set.
+ *
+ * Stores the integer value @new_value in the file/section/key
+ * defined by the @path
+ */
+void
+_gnome_config_set_int (const char *path, int new_value, gboolean priv)
+{
+	ParsedPath *pp;
+	char intbuf [40];
+	const char *r;
+	
+	pp = parse_path (path, priv);
+	g_snprintf (intbuf, sizeof(intbuf), "%d", new_value);
+	r = access_config (SET, pp->section, pp->key, intbuf, pp->file,
+			   NULL);
+	release_path (pp);
+}
+
+/**
+ * gnome_config_set_float:
+ * @path: a gnome configuration path to a key
+ * @new_value: a double value to set.
+ *
+ * Stores the double value @new_value in the file/section/key
+ * defined by the @path
+ */
+void
+_gnome_config_set_float (const char *path, gdouble new_value, gboolean priv)
+{
+	ParsedPath *pp;
+	char floatbuf [40];
+	const char *r;
+	
+	pp = parse_path (path, priv);
+
+        /* make sure we write values in a consistent manner */
+	gnome_i18n_push_c_numeric_locale ();
+	g_snprintf (floatbuf, sizeof(floatbuf), "%.17g", new_value);
+	gnome_i18n_pop_c_numeric_locale ();
+
+	r = access_config (SET, pp->section, pp->key, floatbuf, pp->file,
+			   NULL);
+	release_path (pp);
+}
+
+/**
+ * gnome_config_set_bool:
+ * @path: a gnome configuration path to a key
+ * @new_value: a boolean value to set
+ *
+ * Stores boolean value @new_value in the file/section/key defined by
+ * @path.
+ */
+void
+_gnome_config_set_bool (const char *path, gboolean new_value, gboolean priv)
+{
+	ParsedPath *pp;
+	const char *r;
+	
+	pp = parse_path (path, priv);
+	r = access_config (SET, pp->section, pp->key,
+			   new_value ? "true" : "false", pp->file, NULL);
+	release_path (pp);
+}
+
+/**
+ * gnome_config_assemble_vector:
+ * @argc: Number of elements in the @argv string array.
+ * @argv: An array of strings.
+ *
+ * This routine returns the the strings in the array contactenated by
+ * spaces.
+ *
+ * Returns: a g_malloc()ed string with the concatenation results.
+ */
+char *
+gnome_config_assemble_vector (int argc, const char *const argv [])
+{
+	char *value, *p;
+	const char *s;
+	int i;
+	size_t len;
+
+	/*
+	 * Compute length of quoted string.  We cheat and just use
+	 * twice the sum of the lengths of all the strings.  
+	 */
+	len = 1;
+	for (i = 0; i < argc; ++i)
+		len += 2 * strlen (argv [i]) + 1 + argc;
+
+	p = value = g_malloc (len);
+	for (i = 0; i < argc; ++i) {
+		for (s = argv [i]; *s; ++s) {
+			if (*s == ' ' || *s == '\\')
+				*p++ = '\\';
+			*p++ = *s;
+		}
+		*p++ = ' ';
+	}
+	*p = '\0';
+
+	return value;
+}
+
+/**
+ * gnome_config_set_vector:
+ * @path: a gnome configuration path to a key
+ * @argc: the number of elements in @argv
+ * @argv: a string array holding the data to store.
+ *
+ * Stores vector @argv in the file/section/key defined by
+ * @path.
+ */
+void
+_gnome_config_set_vector (const char *path, int argc,
+			  const char *const argv[],
+			  gboolean priv)
+{
+	ParsedPath *pp;
+	char *s;
+
+	pp = parse_path (path, priv);
+	s = gnome_config_assemble_vector (argc, argv);
+	access_config (SET, pp->section, pp->key, s, pp->file, NULL);
+	g_free (s);
+	release_path (pp);
+}
+
+/**
+ * gnome_config_push_prefix:
+ * @path: a gnome configuration path prefix
+ *
+ * @path is a prefix that will be prepended automatically to any
+ * non-absolute configuration path in gnome config.
+ *
+ * This is used to simplify application loading code.
+ *
+ * Library code will usually have to set the prefix before doing
+ * any gnome-configuration access, since the application might
+ * be using their own prefix. 
+ */
+void
+gnome_config_push_prefix (const char *path)
+{
+	prefix_list = g_slist_prepend(prefix_list, g_strdup(path));
+}
+
+/**
+ * gnome_config_pop_prefix:
+ *
+ * Call this routine to remove the current configuration prefix from the stack.
+ */
+void
+gnome_config_pop_prefix (void)
+{
+	if(prefix_list) {
+		GSList *plist = prefix_list;
+		g_free(prefix_list->data);
+		prefix_list = prefix_list->next;
+		g_slist_free_1(plist);
+	}
+}
+
+/**
+ * gnome_config_set_set_handler
+ * @func: Obsolete
+ * @data: Obsolete
+ *
+ * Internal Obsolete.
+ */
+void
+gnome_config_set_set_handler(void (*func)(void *),void *data)
+{
+	g_warning("gnome_config_set_set_handler is obscolete and has no replacement");
+}
+
+/**
+ * gnome_config_set_sync_handler
+ * @func: obsolete
+ * @data: obsolete
+ *
+ * Internal routine
+ */
+void
+gnome_config_set_sync_handler(void (*func)(void *),void *data)
+{
+	g_warning("gnome_config_set_sync_handler is obscolete and has no replacement");
+}
+
+#ifdef TEST
+
+static
+x (char *str, char *file, char *sec, char *key, char *val)
+{
+	ParsedPath *pp;
+
+	printf ("%s\n", str);
+	pp = parse_path (str, FALSE);
+	printf ("   file: %s [%s]\n", pp->file, file);
+	printf ("   sect: %s [%s]\n", pp->section, sec);
+	printf ("   key:  %s [%s]\n", pp->key, key);
+	printf ("   def:  %s [%s]\n", pp->def, val);
+}
+
+
+main ()
+{
+	gnome_user_dir = "USERDIR";
+	x ("=/tmp/file=seccion/llave=valor", "/tmp/file", "seccion", "llave", "valor");
+	x ("=/tmp/file=seccion/llave", "/tmp/file", "seccion", "llave", NULL);
+	x ("/file/seccion/llave=valor", "USERDIR/file", "seccion", "llave", "valor");
+	x ("/file/seccion/llave", "USERDIR/file", "seccion", "llave", NULL);
+	x ("/file/archivo/archivo/seccion/llave", "USERDIR/file/archivo/archivo", "seccion", "llave", NULL);
+	x ("/file/archivo/archivo/seccion/llave=valor", "USERDIR/file/archivo/archivo", "seccion", "llave", "valor");
+	
+}
+#endif
diff --git a/libgnome/gnome-config.h b/libgnome/gnome-config.h
new file mode 100644
index 0000000..443eb5d
--- /dev/null
+++ b/libgnome/gnome-config.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 1993, 1994, 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifndef GNOME_CONFIG_H
+#define GNOME_CONFIG_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* Prototypes for the profile management functions */
+
+/*
+ * DOC: gnome configuration routines.
+ *
+ * All of the routines receive a pathname, the pathname has the following
+ * form:
+ *
+ *      /filename/section/key[=default]
+ *
+ * This format reprensents: a filename relative to the Gnome config
+ * directory called filename (ie, ~/.gnome/filename), in that file there
+ * is a section called [section] and key is the left handed side of the
+ * values.
+ *
+ * If default is provided, it cane be used to return a default value
+ * if none is specified on the config file.
+ *
+ * Examples:
+ * 
+ * /gmix/Balance/Ratio=0.5
+ * /filemanager/Panel Display/html=1
+ *
+ * If the pathname starts with '=', then instead of being a ~/.gnome relative
+ * file, it is an abolute pathname, example:
+ *
+ * =/home/miguel/.mc.ini=/Left Panel/reverse=1
+ *
+ * This reprensents the config file: /home/miguel/.mc.ini, section [Left Panel],
+ * variable reverse.
+ */
+
+/* These functions look for the config option named in PATH.  If the
+   option does not exist, and a default is specified in PATH, then the
+   default will be returned.  In all cases, *DEF is set to 1 if the
+   default was return, 0 otherwise.  If DEF is NULL then it will not
+   be set.  */
+
+/*use the wrappers below*/
+char *_gnome_config_get_string_with_default    (const char *path,
+					        gboolean *def,
+						gboolean priv);
+char *_gnome_config_get_translated_string_with_default(const char *path,
+						       gboolean *def,
+						       gboolean priv);
+gint  _gnome_config_get_int_with_default       (const char *path,
+					        gboolean *def,
+						gboolean priv);
+gdouble  _gnome_config_get_float_with_default  (const char *path,
+					        gboolean *def,
+						gboolean priv);
+gboolean _gnome_config_get_bool_with_default   (const char *path,
+					        gboolean *def,
+					        gboolean priv);
+void _gnome_config_get_vector_with_default     (const char *path, gint *argcp,
+					        char ***argvp,
+					        gboolean *def,
+					        gboolean priv);
+
+/*these just call the above functions, but devide them into two groups,
+  in the future these may be different functions, so use these defines*/
+/*normal functions*/
+#define gnome_config_get_string_with_default(path,def) \
+	(_gnome_config_get_string_with_default((path),(def),FALSE))
+#define gnome_config_get_translated_string_with_default(path,def) \
+	(_gnome_config_get_translated_string_with_default((path),(def),FALSE))
+#define gnome_config_get_int_with_default(path,def) \
+	(_gnome_config_get_int_with_default((path),(def),FALSE))
+#define gnome_config_get_float_with_default(path,def) \
+	(_gnome_config_get_float_with_default((path),(def),FALSE))
+#define gnome_config_get_bool_with_default(path,def) \
+	(_gnome_config_get_bool_with_default((path),(def),FALSE))
+#define gnome_config_get_vector_with_default(path, argcp, argvp, def) \
+        (_gnome_config_get_vector_with_default ((path),(argcp),(argvp), \
+						(def),FALSE))
+
+/*private functions*/
+#define gnome_config_private_get_string_with_default(path,def) \
+	(_gnome_config_get_string_with_default((path),(def),TRUE))
+#define gnome_config_private_get_translated_string_with_default(path,def) \
+	(_gnome_config_get_translated_string_with_default((path), (def),TRUE))
+#define gnome_config_private_get_int_with_default(path,def) \
+	(_gnome_config_get_int_with_default((path),(def),TRUE))
+#define gnome_config_private_get_float_with_default(path,def) \
+	(_gnome_config_get_int_with_default((path),(def),TRUE))
+#define gnome_config_private_get_bool_with_default(path,def) \
+	(_gnome_config_get_bool_with_default((path),(def),TRUE))
+#define gnome_config_private_get_vector_with_default(path, argcp, argvp, def) \
+        (_gnome_config_get_vector_with_default ((path),(argcp), (argvp), \
+        					(def), TRUE))
+
+/* Convenience wrappers for the case when you don't care if you see
+   the default.  */
+/*normal functions*/
+#define gnome_config_get_string(path) \
+	(_gnome_config_get_string_with_default ((path), NULL, FALSE))
+#define gnome_config_get_translated_string(path) \
+	(_gnome_config_get_translated_string_with_default ((path), NULL, FALSE))
+#define gnome_config_get_int(path) \
+	(_gnome_config_get_int_with_default ((path), NULL, FALSE))
+#define gnome_config_get_float(path) \
+	(_gnome_config_get_float_with_default ((path), NULL, FALSE))
+#define gnome_config_get_bool(path) \
+	(_gnome_config_get_bool_with_default ((path), NULL, FALSE))
+#define gnome_config_get_vector(path, argcp, argvp) \
+        (_gnome_config_get_vector_with_default ((path), (argcp), (argvp), \
+        					NULL, FALSE))
+
+/*private functions*/
+#define gnome_config_private_get_string(path) \
+	(_gnome_config_get_string_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_translated_string(path) \
+	(_gnome_config_get_translated_string_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_int(path) \
+	(_gnome_config_get_int_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_float(path) \
+	(_gnome_config_get_float_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_bool(path) \
+	(_gnome_config_get_bool_with_default ((path), NULL, TRUE))
+#define gnome_config_private_get_vector(path, argcp, argvp) \
+        (_gnome_config_get_vector_with_default ((path), (argcp), (argvp), \
+        					NULL, TRUE))
+
+/* Set a config variable.  Use the warppers below*/
+void _gnome_config_set_string     (const char *path, const char *value,
+				   gboolean priv);
+void _gnome_config_set_translated_string (const char *path, const char *value,
+					  gboolean priv);
+void _gnome_config_set_int        (const char *path, int value,
+				   gboolean priv);
+void _gnome_config_set_float        (const char *path, gdouble value,
+				     gboolean priv);
+void _gnome_config_set_bool       (const char *path, gboolean value,
+				   gboolean priv);
+void _gnome_config_set_vector     (const char *path,
+				   int argc,
+				   const char * const argv[],
+				   gboolean priv);
+
+
+/* normal functions */
+#define gnome_config_set_string(path,new_value) \
+	(_gnome_config_set_string((path),(new_value),FALSE))
+#define gnome_config_set_translated_string(path,value) \
+	(_gnome_config_set_translated_string((path),(value),FALSE))
+#define gnome_config_set_int(path,new_value) \
+	(_gnome_config_set_int((path),(new_value),FALSE))
+#define gnome_config_set_float(path,new_value) \
+	(_gnome_config_set_float((path),(new_value),FALSE))
+#define gnome_config_set_bool(path,new_value) \
+	(_gnome_config_set_bool((path),(new_value),FALSE))
+#define gnome_config_set_vector(path,argc,argv) \
+	(_gnome_config_set_vector((path),(argc),(argv),FALSE))
+
+/* private functions */
+#define gnome_config_private_set_string(path,new_value) \
+	(_gnome_config_set_string((path),(new_value),TRUE))
+#define gnome_config_private_set_translated_string(path,new_value) \
+	(_gnome_config_set_translated_string((path),(new_value),TRUE))
+#define gnome_config_private_set_int(path,new_value) \
+	(_gnome_config_set_int((path),(new_value),TRUE))
+#define gnome_config_private_set_float(path,new_value) \
+	(_gnome_config_set_float((path),(new_value),TRUE))
+#define gnome_config_private_set_bool(path,new_value) \
+	(_gnome_config_set_bool((path),(new_value),TRUE))
+#define gnome_config_private_set_vector(path,argc,argv) \
+	(_gnome_config_set_vector((path),(argc),(argv),TRUE))
+
+/* Returns true if /path/section is defined */
+gboolean  _gnome_config_has_section    (const char *path, gboolean priv);
+#define gnome_config_has_section(path) \
+	(_gnome_config_has_section((path),FALSE))
+#define gnome_config_private_has_section(path) \
+	(_gnome_config_has_section((path),TRUE))
+
+/* Returns a pointer for iterating on /file/section contents */
+void *_gnome_config_init_iterator (const char *path, gboolean priv);
+#define gnome_config_init_iterator(path) \
+	(_gnome_config_init_iterator((path),FALSE))
+#define gnome_config_private_init_iterator(path) \
+	(_gnome_config_init_iterator((path),TRUE))
+
+/* Returns a pointer for iterating on /file contents */
+void *_gnome_config_init_iterator_sections (const char *path, gboolean priv);
+#define gnome_config_init_iterator_sections(path) \
+	(_gnome_config_init_iterator_sections((path),FALSE))
+#define gnome_config_private_init_iterator_sections(path) \
+	(_gnome_config_init_iterator_sections((path),TRUE))
+
+/* Get next key and value value from a section */
+void *gnome_config_iterator_next (void *iterator_handle, char **key, char **value);
+
+void gnome_config_drop_all       (void);
+
+gboolean gnome_config_sync       (void);
+
+/* sync's data for one file only */
+gboolean _gnome_config_sync_file (char *path, gboolean priv);
+#define gnome_config_sync_file(path) \
+	(_gnome_config_sync_file((path),FALSE))
+#define gnome_config_private_sync_file(path) \
+	(_gnome_config_sync_file((path),TRUE))
+
+/* This routine drops the information about /file, meaning changes
+   done to this file will be dropped, it will no delete the file */
+void _gnome_config_drop_file     (const char *path, gboolean priv);
+#define gnome_config_drop_file(path) \
+	(_gnome_config_drop_file((path),FALSE))
+#define gnome_config_private_drop_file(path) \
+	(_gnome_config_drop_file((path),TRUE))
+
+/* This routine actually removes /file on sync (not right away, you
+   can still save it by dropping it)*/
+void _gnome_config_clean_file     (const char *path, gboolean priv);
+#define gnome_config_clean_file(path) \
+	(_gnome_config_clean_file((path),FALSE))
+#define gnome_config_private_clean_file(path) \
+	(_gnome_config_clean_file((path),TRUE))
+
+/* This routine drops all of the information related to /file/section 
+   this will actually remove the section */
+void _gnome_config_clean_section  (const char *path, gboolean priv);
+#define gnome_config_clean_section(path) \
+	(_gnome_config_clean_section((path),FALSE))
+#define gnome_config_private_clean_section(path) \
+	(_gnome_config_clean_section((path),TRUE))
+
+/* Drops the information for a specific key, this will actually remove
+   the key */
+void _gnome_config_clean_key (const char *path, gboolean priv);
+#define gnome_config_clean_key(path) \
+	(_gnome_config_clean_key((path),FALSE))
+#define gnome_config_private_clean_key(path) \
+	(_gnome_config_clean_key((path),TRUE))
+
+/* returns the true filename of the config file */
+#define gnome_config_get_real_path(path) \
+	(g_concat_dir_and_file (gnome_user_dir,(path)))
+#define gnome_config_private_get_real_path(path) \
+	(g_concat_dir_and_file (gnome_user_private_dir,(path)))
+
+/* Set an active prefix and remove an active prefix */
+void gnome_config_push_prefix (const char *path);
+void gnome_config_pop_prefix (void);
+
+/*
+ * Internal routines that we export
+ * Used to go from string->vector and from vector->string
+ */
+void gnome_config_make_vector (const char *string, int *argcp, char ***argvp);
+char *gnome_config_assemble_vector (int argc, const char *const argv []);
+
+/* these two are absolutely obscolete and should not be used */
+void gnome_config_set_set_handler(void (*func)(void *),void *data);
+void gnome_config_set_sync_handler(void (*func)(void *),void *data);
+
+G_END_DECLS
+
+#endif
diff --git a/libgnome/gnome-exec.c b/libgnome/gnome-exec.c
index 93d73dd..85207fc 100644
--- a/libgnome/gnome-exec.c
+++ b/libgnome/gnome-exec.c
@@ -25,6 +25,8 @@
 #  include <config.h>
 #endif
 
+#include "gnome-i18nP.h"
+
 #include <libgnome/gnome-exec.h>
 #include <libgnome/gnome-util.h>
 #include <libgnome/gnome-i18n.h>
diff --git a/libgnome/gnome-i18n.c b/libgnome/gnome-i18n.c
new file mode 100644
index 0000000..8abad02
--- /dev/null
+++ b/libgnome/gnome-i18n.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "gnome-i18nP.h"
+
+static GHashTable *alias_table = NULL;
+
+/*read an alias file for the locales*/
+static void
+read_aliases (char *file)
+{
+  FILE *fp;
+  char buf[256];
+  if (!alias_table)
+    alias_table = g_hash_table_new (g_str_hash, g_str_equal);
+  fp = fopen (file,"r");
+  if (!fp)
+    return;
+  while (fgets (buf,256,fp))
+    {
+      char *p;
+      g_strstrip(buf);
+      if (buf[0]=='#' || buf[0]=='\0')
+        continue;
+      p = strtok (buf,"\t ");
+      if (!p)
+	continue;
+      p = strtok (NULL,"\t ");
+      if(!p)
+	continue;
+      if (!g_hash_table_lookup (alias_table, buf))
+	g_hash_table_insert (alias_table, g_strdup(buf), g_strdup(p));
+    }
+  fclose (fp);
+}
+
+/*return the un-aliased language as a newly allocated string*/
+static char *
+unalias_lang (char *lang)
+{
+  char *p;
+  int i;
+  if (!alias_table)
+    {
+      read_aliases ("/usr/share/locale/locale.alias");
+      read_aliases ("/usr/local/share/locale/locale.alias");
+      read_aliases ("/usr/lib/X11/locale/locale.alias");
+      read_aliases ("/usr/openwin/lib/locale/locale.alias");
+    }
+  i = 0;
+  while ((p=g_hash_table_lookup(alias_table,lang)) && strcmp(p, lang))
+    {
+      lang = p;
+      if (i++ == 30)
+        {
+          static gboolean said_before = FALSE;
+	  if (!said_before)
+            g_warning (_("Too many alias levels for a locale, "
+			 "may indicate a loop"));
+	  said_before = TRUE;
+	  return lang;
+	}
+    }
+  return lang;
+}
+
+/* Mask for components of locale spec. The ordering here is from
+ * least significant to most significant
+ */
+enum
+{
+  COMPONENT_CODESET =   1 << 0,
+  COMPONENT_TERRITORY = 1 << 1,
+  COMPONENT_MODIFIER =  1 << 2
+};
+
+/* Break an X/Open style locale specification into components
+ */
+static guint
+explode_locale (const gchar *locale,
+		gchar **language, 
+		gchar **territory, 
+		gchar **codeset, 
+		gchar **modifier)
+{
+  const gchar *uscore_pos;
+  const gchar *at_pos;
+  const gchar *dot_pos;
+
+  guint mask = 0;
+
+  uscore_pos = strchr (locale, '_');
+  dot_pos = strchr (uscore_pos ? uscore_pos : locale, '.');
+  at_pos = strchr (dot_pos ? dot_pos : (uscore_pos ? uscore_pos : locale), '@');
+
+  if (at_pos)
+    {
+      mask |= COMPONENT_MODIFIER;
+      *modifier = g_strdup (at_pos);
+    }
+  else
+    at_pos = locale + strlen (locale);
+
+  if (dot_pos)
+    {
+      mask |= COMPONENT_CODESET;
+      *codeset = g_new (gchar, 1 + at_pos - dot_pos);
+      strncpy (*codeset, dot_pos, at_pos - dot_pos);
+      (*codeset)[at_pos - dot_pos] = '\0';
+    }
+  else
+    dot_pos = at_pos;
+
+  if (uscore_pos)
+    {
+      mask |= COMPONENT_TERRITORY;
+      *territory = g_new (gchar, 1 + dot_pos - uscore_pos);
+      strncpy (*territory, uscore_pos, dot_pos - uscore_pos);
+      (*territory)[dot_pos - uscore_pos] = '\0';
+    }
+  else
+    uscore_pos = dot_pos;
+
+  *language = g_new (gchar, 1 + uscore_pos - locale);
+  strncpy (*language, locale, uscore_pos - locale);
+  (*language)[uscore_pos - locale] = '\0';
+
+  return mask;
+}
+
+/*
+ * Compute all interesting variants for a given locale name -
+ * by stripping off different components of the value.
+ *
+ * For simplicity, we assume that the locale is in
+ * X/Open format: language[_territory][ codeset][ modifier]
+ *
+ * TODO: Extend this to handle the CEN format (see the GNUlibc docs)
+ *       as well. We could just copy the code from glibc wholesale
+ *       but it is big, ugly, and complicated, so I'm reluctant
+ *       to do so when this should handle 99% of the time...
+ */
+static GList *
+compute_locale_variants (const gchar *locale)
+{
+  GList *retval = NULL;
+
+  gchar *language;
+  gchar *territory;
+  gchar *codeset;
+  gchar *modifier;
+
+  guint mask;
+  guint i;
+
+  g_return_val_if_fail (locale != NULL, NULL);
+
+  mask = explode_locale (locale, &language, &territory, &codeset, &modifier);
+
+  /* Iterate through all possible combinations, from least attractive
+   * to most attractive.
+   */
+  for (i=0; i<=mask; i++)
+    if ((i & ~mask) == 0)
+      {
+	gchar *val = g_strconcat(language,
+				 (i & COMPONENT_TERRITORY) ? territory : "",
+				 (i & COMPONENT_CODESET) ? codeset : "",
+				 (i & COMPONENT_MODIFIER) ? modifier : "",
+				 NULL);
+	retval = g_list_prepend (retval, val);
+      }
+
+  g_free (language);
+  if (mask & COMPONENT_CODESET)
+    g_free (codeset);
+  if (mask & COMPONENT_TERRITORY)
+    g_free (territory);
+  if (mask & COMPONENT_MODIFIER)
+    g_free (modifier);
+
+  return retval;
+}
+
+/* The following is (partly) taken from the gettext package.
+   Copyright (C) 1995, 1996, 1997, 1998 Free Software Foundation, Inc.  */
+
+static const gchar *
+guess_category_value (const gchar *categoryname)
+{
+  const gchar *retval;
+
+  /* The highest priority value is the `LANGUAGE' environment
+     variable.  This is a GNU extension.  */
+  retval = g_getenv ("LANGUAGE");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* `LANGUAGE' is not set.  So we have to proceed with the POSIX
+     methods of looking to `LC_ALL', `LC_xxx', and `LANG'.  On some
+     systems this can be done by the `setlocale' function itself.  */
+
+  /* Setting of LC_ALL overwrites all other.  */
+  retval = g_getenv ("LC_ALL");  
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* Next comes the name of the desired category.  */
+  retval = g_getenv (categoryname);
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  /* Last possibility is the LANG environment variable.  */
+  retval = g_getenv ("LANG");
+  if (retval != NULL && retval[0] != '\0')
+    return retval;
+
+  return NULL;
+}
+
+
+static GHashTable *category_table= NULL;
+
+
+/**
+ * gnome_i18n_get_language_list:
+ * @category_name: Name of category to look up, e.g. "LC_MESSAGES".
+ * 
+ * This computes a list of language strings.  It searches in the
+ * standard environment variables to find the list, which is sorted
+ * in order from most desirable to least desirable.  The `C' locale
+ * is appended to the list if it does not already appear (other routines depend on this behaviour).
+ * If @category_name is %NULL, then LC_ALL is assumed.
+ * 
+ * Return value: the list of languages, this list should not be freed as it is owned by gnome-i18n
+ **/
+const GList *
+gnome_i18n_get_language_list (const gchar *category_name)
+{
+  GList *list;
+
+  if (!category_name)
+    category_name= "LC_ALL";
+
+  if (category_table)
+    {
+      list= g_hash_table_lookup (category_table, (const gpointer) category_name);
+    }
+  else
+    {
+      category_table= g_hash_table_new (g_str_hash, g_str_equal);
+      list= NULL;
+    }
+
+  if (!list)
+    {
+      gint c_locale_defined= FALSE;
+  
+      const gchar *category_value;
+      gchar *category_memory, *orig_category_memory;
+
+      category_value = guess_category_value (category_name);
+      if (! category_value)
+	category_value = "C";
+      orig_category_memory = category_memory =
+	g_malloc (strlen (category_value)+1);
+      
+      while (category_value[0] != '\0')
+	{
+	  while (category_value[0] != '\0' && category_value[0] == ':')
+	    ++category_value;
+	  
+	  if (category_value[0] != '\0')
+	    {
+	      char *cp= category_memory;
+	      
+	      while (category_value[0] != '\0' && category_value[0] != ':')
+		*category_memory++= *category_value++;
+	      
+	      category_memory[0]= '\0'; 
+	      category_memory++;
+	      
+	      cp = unalias_lang(cp);
+	      
+	      if (strcmp (cp, "C") == 0)
+		c_locale_defined= TRUE;
+	      
+	      list= g_list_concat (list, compute_locale_variants (cp));
+	    }
+	}
+
+      g_free (orig_category_memory);
+      
+      if (!c_locale_defined)
+	list= g_list_append (list, "C");
+
+      g_hash_table_insert (category_table, (gpointer) category_name, list);
+    }
+  
+  return list;
+}
+
+static GList *numeric_locale_stack = NULL;
+
+/**
+ * gnome_i18n_push_c_numeric_locale:
+ *
+ * Description:  Pushes the current LC_NUMERIC locale onto a stack, then 
+ * sets LC_NUMERIC to "C".  This way you can safely read write flaoting
+ * point numbers all in the same format.  You should make sure that
+ * code between #gnome_i18n_push_c_numeric_locale and
+ * #gnome_i18n_pop_c_numeric_locale doesn't do any setlocale calls or locale
+ * may end up in a strange setting.  Also make sure to always pop the
+ * c numeric locale after you've pushed it.
+ **/
+void
+gnome_i18n_push_c_numeric_locale (void)
+{
+	char *current;
+
+	current = g_strdup (setlocale (LC_NUMERIC, NULL));
+	numeric_locale_stack = g_list_prepend (numeric_locale_stack,
+					       current);
+	setlocale (LC_NUMERIC, "C");
+}
+
+/**
+ * gnome_i18n_pop_c_numeric_locale:
+ *
+ * Description:  Pops the last LC_NUMERIC locale from the stack (where
+ * it was put with #gnome_i18n_push_c_numeric_locale).  Then resets the
+ * current locale to that one.
+ **/
+void
+gnome_i18n_pop_c_numeric_locale (void)
+{
+	char *old;
+
+	if (numeric_locale_stack == NULL)
+		return;
+
+	old = numeric_locale_stack->data;
+
+	setlocale (LC_NUMERIC, old);
+
+	numeric_locale_stack = g_list_remove (numeric_locale_stack, old);
+
+	g_free (old);
+}
diff --git a/libgnome/gnome-i18n.h b/libgnome/gnome-i18n.h
index e8b22fe..f610a7f 100644
--- a/libgnome/gnome-i18n.h
+++ b/libgnome/gnome-i18n.h
@@ -28,15 +28,14 @@
  * Author: Tom Tromey <tromey creche cygnus com>
  */
 
-#ifndef __LIBGNOME_I18N_H__
-#define __LIBGNOME_I18N_H__ 1
-
-#include <glib/gmacros.h>
+#ifndef __GNOME_I18N_H__
+#define __GNOME_I18N_H__ 1
 
+#include <glib.h>
 
 G_BEGIN_DECLS
 
-#if !defined(__LIBGNOME_I18NP_H__)
+#if !defined(__GNOME_I18NP_H__)
 
 #ifdef ENABLE_NLS
 #    include <libintl.h>
@@ -64,6 +63,44 @@ G_BEGIN_DECLS
 
 #endif
 
+/* 'gnome_i18n_get_language_list' returns a list of language strings.
+ *
+ * It searches for one of following environment variables:
+ * LANGUAGE
+ * LC_ALL
+ * 'category_name'
+ * LANG
+ *
+ * If one of these environment variables was found, it is split into
+ * pieces, whereever a ':' is found. When the environment variable included
+ * no C locale, the C locale is appended to the list of languages.
+ *
+ * Assume, you have the following environment variables set:
+ *
+ * LC_MONETARY="de_DE:es"
+ * LANG="de_DE:de:C:en"
+ * 
+ * In this case 'gnome_i18n_get_language_list ("LC_COLLATE")' returns the
+ * list: ("de_DE" "de" "C" "en").
+ *
+ * 'gnome_i18n_get_language_list ("LC_MONETARY")' returns:
+ * ("de_DE" "es" "C")
+ *
+ * The returned list must not be changed.
+ */
+
+const GList *	gnome_i18n_get_language_list		(const gchar *category_name);
+
+/* Push "C" numeric locale.  Do this before doing any floating
+ * point to/from string conversions, if those are to be done in
+ * a portable manner.  This is a hack really, and there is
+ * no need to generalize it to other cathegories.  But it is
+ * needed whenever things like printing scanning floats from or
+ * to files or other places where you'd like to read them back
+ * later. */
+void		gnome_i18n_push_c_numeric_locale	(void);
+void		gnome_i18n_pop_c_numeric_locale		(void);
+
 G_END_DECLS
 
-#endif /* __LIBGNOME_I18N_H__ */
+#endif /* __GNOME_UTIL_H__ */
diff --git a/libgnome/gnome-i18nP.h b/libgnome/gnome-i18nP.h
new file mode 100644
index 0000000..bbfd7d8
--- /dev/null
+++ b/libgnome/gnome-i18nP.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+/*
+ * Handles i18n for the Gnome libraries. Libraries need to use
+ * dgettext in order to use a non-default translation domain.
+ * Author: Tom Tromey <tromey creche cygnus com>
+ */
+
+#ifndef __GNOME_I18NP_H__
+#define __GNOME_I18NP_H__ 1
+
+#ifdef ENABLE_NLS
+#    include <libintl.h>
+#    undef _
+#    define _(String) dgettext (PACKAGE, String)
+#    ifdef gettext_noop
+#        define N_(String) gettext_noop (String)
+#    else
+#        define N_(String) (String)
+#    endif
+#else
+/* Stubs that do something close enough.  */
+#    define textdomain(String) (String)
+#    define gettext(String) (String)
+#    define dgettext(Domain,Message) (Message)
+#    define dcgettext(Domain,Message,Type) (Message)
+#    define bindtextdomain(Domain,Directory) (Domain)
+#    define _(String) (String)
+#    define N_(String) (String)
+#endif
+
+#include "gnome-i18n.h"
+
+#endif /* __GNOME_I18NP_H__ */
diff --git a/libgnome/gnome-init.c b/libgnome/gnome-init.c
index 8de83ac..ba556d2 100644
--- a/libgnome/gnome-init.c
+++ b/libgnome/gnome-init.c
@@ -37,6 +37,7 @@
 #include <sys/stat.h>
 
 #include <glib.h>
+#include "gnome-i18nP.h"
 
 #include <libgnome/gnome-init.h>
 #include <libgnome/gnome-util.h>
diff --git a/libgnome/gnome-program.c b/libgnome/gnome-program.c
index b18ae8e..5a1bbd6 100644
--- a/libgnome/gnome-program.c
+++ b/libgnome/gnome-program.c
@@ -29,11 +29,15 @@
 /* This module takes care of handling application and library
    initialization and command line parsing */
 
+#include <config.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <gmodule.h>
+
+#include "gnome-i18nP.h"
+
 #include <libgnome/gnome-program.h>
 #include <libgnome/gnome-init.h>
 #include <libgnome/gnome-i18n.h>
diff --git a/libgnome/gnome-sound.c b/libgnome/gnome-sound.c
new file mode 100644
index 0000000..a5b98aa
--- /dev/null
+++ b/libgnome/gnome-sound.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (C) 1997-1998 Stuart Parmenter and Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#include "config.h"
+
+#include "libgnome.h"
+#include "gnome-sound.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+#ifdef HAVE_ESD
+#include <esd.h>
+#endif
+
+#ifdef HAVE_ESD
+static char *esound_hostname = NULL;
+int gnome_sound_connection = -1;
+#endif
+
+typedef struct _sample
+  {
+    int rate, format, samples, id, size;
+    short *data;
+  }
+GnomeSoundSample;
+
+#ifndef HAVE_LIBAUDIOFILE
+typedef struct _WAVFormatChunk
+  {
+    char chunkID[4];
+    int chunkSize;
+
+    unsigned int dwSamplesPerSec;
+    unsigned int dwAvgBytesPerSec;
+    short wFormatTag;
+    unsigned short wChannels;
+    unsigned short wBlockAlign;
+    unsigned short wBitsPerSample;
+  }
+WAVFormatChunk;
+
+#ifdef WORDS_BIGENDIAN
+#define SWAP_SHORT( x ) x = ( ( x & 0x00ff ) << 8 ) | ( ( x >> 8 ) & 0x00ff )
+#define SWAP_LONG( x ) x = ( ( ( x & 0x000000ff ) << 24 ) |\
+( ( x & 0x0000ff00 ) << 8 ) |\
+( ( x & 0x00ff0000 ) >> 8 ) |\
+( ( x & 0xff000000 ) >> 24 ) )
+#endif
+
+/**
+ * gnome_sound_sample_load_wav:
+ * @file: filename to try loading a WAV file from.
+ * 
+ * Used to load a .wav file into esound.
+ *
+ * Returns a GnomeSoundSample or NULL if file did not exist.
+ *
+ */
+#ifdef HAVE_ESD
+static GnomeSoundSample *
+gnome_sound_sample_load_wav(const char *file)
+{
+  FILE *f;
+  GnomeSoundSample *s;
+  char buf[4];
+  WAVFormatChunk fmt;
+  int skipl = 0;
+  int skipr = 0;
+  char bytes = 0;
+  char stereo = 0;
+  int len;
+
+  /* int                 count; */
+
+  f = fopen (file, "r");
+  if (!f)
+    return NULL;
+  s = g_malloc (sizeof (GnomeSoundSample));
+  if (!s)
+    {
+      fclose (f);
+      return NULL;
+    }
+  s->rate = 44100;
+  s->format = ESD_STREAM | ESD_PLAY;
+  s->samples = 0;
+  s->data = NULL;
+  s->id = 0;
+  fread (buf, 1, 4, f);
+  if ((buf[0] != 'R') ||
+      (buf[1] != 'I') ||
+      (buf[2] != 'F') ||
+      (buf[3] != 'F'))
+    {
+      /* not a RIFF WAV file */
+      fclose (f);
+      g_free (s);
+      return NULL;
+    }
+  fread (buf, 1, 4, f);
+  fread (buf, 1, 4, f);
+  fread (fmt.chunkID, 1, 4, f);
+  fread (&(fmt.chunkSize), 1, 4, f);
+
+#ifdef WORDS_BIGENDIAN
+  SWAP_LONG (fmt.chunkSize);
+#endif
+
+  if ((fmt.chunkID[0] == 'f') &&
+      (fmt.chunkID[1] == 'm') &&
+      (fmt.chunkID[2] == 't') &&
+      (fmt.chunkID[3] == ' ') &&
+      16 == fmt.chunkSize)
+    /* fmt chunk */
+    {
+      fread (&(fmt.wFormatTag), 1, 2, f);
+      fread (&(fmt.wChannels), 1, 2, f);
+      fread (&(fmt.dwSamplesPerSec), 1, 4, f);
+      fread (&(fmt.dwAvgBytesPerSec), 1, 4, f);
+      fread (&(fmt.wBlockAlign), 1, 2, f);
+      fread (&(fmt.wBitsPerSample), 1, 2, f);
+#ifdef WORDS_BIGENDIAN
+      SWAP_SHORT (fmt.wFormatTag);
+      SWAP_SHORT (fmt.wChannels);
+      SWAP_LONG (fmt.dwSamplesPerSec);
+      SWAP_LONG (fmt.dwAvgBytesPerSec);
+      SWAP_SHORT (fmt.wBlockAlign);
+      SWAP_SHORT (fmt.wBitsPerSample);
+#endif
+
+      if (fmt.wFormatTag != 1)
+	{
+	  /* unknown WAV encoding format - exit */
+	  fclose (f);
+	  g_free (s);
+	  return NULL;
+	}
+      skipl = 0;
+      skipr = 0;
+      bytes = 0;
+      stereo = 0;
+      if (fmt.wChannels == 1)
+	s->format |= ESD_MONO;
+      else if (fmt.wChannels == 2)
+	{
+	  stereo = 1;
+	  s->format |= ESD_STEREO;
+	}
+      else
+	{
+	  stereo = 1;
+	  s->format |= ESD_STEREO;
+	  if (fmt.wChannels == 3)
+	    {
+	      skipl = 0;
+	      skipr = 1;
+	    }
+	  else if (fmt.wChannels == 4)
+	    {
+	      skipl = 0;
+	      skipr = 2;
+	    }
+	  else if (fmt.wChannels == 4)
+	    {
+	      skipl = 0;
+	      skipr = 2;
+	    }
+	  else if (fmt.wChannels == 6)
+	    {
+	      skipl = 3;
+	      skipr = 1;
+	    }
+	  else
+	    {
+	      /* unknown channel encoding */
+	      fclose (f);
+	      g_free (s);
+	      return NULL;
+	    }
+	}
+      s->rate = fmt.dwSamplesPerSec;
+      if (fmt.wBitsPerSample <= 8)
+	{
+	  bytes = 1;
+	  s->format |= ESD_BITS8;
+	}
+      else if (fmt.wBitsPerSample <= 16)
+	s->format |= ESD_BITS16;
+      else
+	{
+	  /* unknown bits encoding encoding */
+	  fclose (f);
+	  g_free (s);
+	  return NULL;
+	}
+    }
+  for (;;)
+    {
+      if (fread (buf, 1, 4, f) &&
+	  fread (&len, 4, 1, f))
+	{
+#ifdef WORDS_BIGENDIAN
+	  SWAP_LONG (len);
+#endif
+
+	  if ((buf[0] != 'd') ||
+	      (buf[1] != 'a') ||
+	      (buf[2] != 't') ||
+	      (buf[3] != 'a'))
+	    fseek (f, len, SEEK_CUR);
+	  else
+	    {
+	      s->data = g_malloc (len);
+	      if (!s->data)
+		{
+		  fclose (f);
+		  g_free (s);
+		  return NULL;
+		}
+	      if ((skipl == 0) && (skipr == 0))
+		{
+		  fread (s->data, len, 1, f);
+#ifdef WORDS_BIGENDIAN
+		  if (fmt.wBitsPerSample > 8 && fmt.wBitsPerSample <= 16)
+		    {
+		      char *tmp;
+		      char tmpval;
+		      int i;
+
+		      tmp = (char *) (s->data);
+
+		      for (i = 0; i < len; i++)
+			{
+			  tmpval = tmp[i];
+			  tmp[i] = tmp[i + 1];
+			  tmp[i + 1] = tmpval;
+			}
+		    }
+#endif
+		}
+	      else
+		{
+		}
+	      s->samples = len;
+	      if (stereo)
+		s->samples /= 2;
+	      if (!bytes)
+		s->samples /= 2;
+	      fclose (f);
+	      return s;
+	    }
+	}
+      else
+	{
+	  fclose (f);
+	  return NULL;
+	}
+    }
+  fclose (f);
+  g_free (s);
+  if (s->data)
+    g_free (s->data);
+
+  return NULL;
+}
+#endif
+#endif
+
+#ifdef HAVE_ESD
+/*
+ * This does delayed initialization of Esound
+ */
+static gboolean
+use_sound (void)
+{
+  if (gnome_sound_connection == -1){
+    if (esound_hostname){
+      gnome_sound_connection = esd_open_sound (esound_hostname);
+      if (gnome_sound_connection == -1){
+	g_free (esound_hostname);
+	esound_hostname = NULL;
+	return FALSE;
+      }
+    }
+  }
+  return TRUE;
+}
+#endif
+
+#if defined(HAVE_LIBAUDIOFILE) && defined(HAVE_ESD)
+#include <audiofile.h>
+
+static GnomeSoundSample *
+gnome_sound_sample_load_audiofile(const char *file)
+{
+  AFfilehandle in_file;
+  GnomeSoundSample *s;
+  int in_format, in_width, in_channels;
+  double in_rate;
+  int bytes_per_frame;
+  AFframecount frame_count, frames_read;
+
+  int out_bits, out_channels, out_rate;
+  int out_mode = ESD_STREAM, out_func = ESD_PLAY;
+  esd_format_t out_format;
+
+  in_file = afOpenFile(file, "r", NULL);
+  if(!in_file)
+    return NULL;
+
+  frame_count = afGetFrameCount(in_file, AF_DEFAULT_TRACK);
+  in_channels = afGetChannels(in_file, AF_DEFAULT_TRACK);
+  in_rate = afGetRate (in_file, AF_DEFAULT_TRACK);
+  afGetSampleFormat (in_file, AF_DEFAULT_TRACK, &in_format, &in_width);
+  if (in_width == 8)
+    out_bits = ESD_BITS8;
+  else if (in_width == 16)
+    out_bits = ESD_BITS16;
+  else {
+      g_warning ("only sample widths of 8 and 16 supported");
+      return NULL;
+  }
+
+  bytes_per_frame = in_width / 8;
+
+  if (in_channels == 1)
+    out_channels = ESD_MONO;
+  else if (in_channels == 2)
+    out_channels = ESD_STEREO;
+  else {
+      g_warning ("only 1 or 2 channel samples supported");
+      return NULL;
+  }
+
+  out_format = out_bits | out_channels | out_mode | out_func;
+
+  out_rate = (int) in_rate;
+
+  s = g_new0 (GnomeSoundSample, 1);
+
+  s->rate = out_rate;
+  s->format = out_format;
+  s->samples = frame_count;
+  s->data = g_malloc(frame_count * in_channels * bytes_per_frame);
+  s->id = 0;
+
+  frames_read = afReadFrames(in_file, AF_DEFAULT_TRACK, s->data,
+			     frame_count * in_channels);
+
+  afCloseFile(in_file);
+
+  return s;
+}
+#endif
+
+
+/**
+ * gnome_sound_sample_load:
+ * @sample_name: the name of the sample
+ * @filename: the filename where the audio is stored
+ *
+ * Loads the audio on @filename and XXXX
+ *
+ * Returns: a sample_id, or a negative number otherwise.
+ */
+int
+gnome_sound_sample_load(const char *sample_name, const char *filename)
+{
+#ifdef HAVE_ESD
+  GnomeSoundSample *s = NULL;
+  int sample_id;
+  int size;
+  int confirm = 0;
+
+  if (!use_sound ())
+    return -2;
+
+  if(!filename || !*filename)
+    return -2;
+
+#ifdef HAVE_LIBAUDIOFILE
+  s = gnome_sound_sample_load_audiofile(filename);
+#else
+  s = gnome_sound_sample_load_wav(filename);
+#endif
+  if(s)
+    goto playsamp;
+
+  /* XXX: Add handlers for more formats here */
+
+ playsamp:
+  if (!s)
+    return -1;
+
+  size = s->samples;
+  if (s->format & ESD_STEREO)
+    size *= 2;
+  if (s->format & ESD_BITS16)
+    size *= 2;
+
+  if (gnome_sound_connection >= 0)
+    {
+      if (s->data)
+	{
+	  /* "name" of all samples is currently "E", should be name of sound 
+	   * file, or event type, for later identification */
+	  s->id = esd_sample_cache (gnome_sound_connection, s->format, s->rate,
+				    size, (char *)sample_name);
+	  write (gnome_sound_connection, s->data, size);
+	  confirm = esd_confirm_sample_cache (gnome_sound_connection);
+	  if (s->id <= 0 || confirm != s->id)
+	    {
+	      g_warning ("error caching sample <%d>!\n", s->id);
+	      s->id = 0;
+	    }
+	  g_free (s->data);
+	  s->data = NULL;
+	}
+    }
+
+  sample_id = s->id;
+
+  g_free(s->data); g_free(s);
+
+  return sample_id;
+#else
+  return -1;
+#endif
+}
+
+/**
+ * gnome_sound_play:
+ * @filename: file containing the sound sample
+ *
+ * Plays the audio stored in @filename
+ */
+void 
+gnome_sound_play (const char * filename)
+{
+#ifdef HAVE_ESD
+  char buf[23];
+  int sample;
+
+  if(!use_sound ())
+    return;
+
+  srand(time(NULL));
+  g_snprintf(buf, sizeof(buf), "%d-%d", getpid(), rand());
+  sample = gnome_sound_sample_load (buf, filename);
+
+  esd_sample_play(gnome_sound_connection, sample);
+  fsync (gnome_sound_connection);
+  esd_sample_free(gnome_sound_connection, sample);
+#endif
+}
+
+/**
+ * gnome_sound_init:
+ * @hostname: hostname where esd daemon resides.
+ *
+ * Initialize esd connection
+ */
+void
+gnome_sound_init(const char *hostname)
+{
+#ifdef HAVE_ESD
+  if (gnome_sound_connection < 0) {
+	  g_free (esound_hostname);
+	  esound_hostname = g_strdup (hostname);
+	  gnome_sound_connection = esd_open_sound((char *)hostname);
+  }
+#endif
+}
+
+/** 
+ * gnome_sound_shutdown:
+ *
+ * shuts down the gnome sound support
+ */
+void
+gnome_sound_shutdown(void)
+{
+#ifdef HAVE_ESD
+	if(gnome_sound_connection >= 0){
+		esd_close(gnome_sound_connection);
+		gnome_sound_connection = -1;
+		g_free (esound_hostname);
+		esound_hostname = NULL;
+	}
+#endif
+}
diff --git a/libgnome/gnome-sound.h b/libgnome/gnome-sound.h
new file mode 100644
index 0000000..06ace7d
--- /dev/null
+++ b/libgnome/gnome-sound.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 1997-1998 Stuart Parmenter and Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifndef __GNOME_SOUND_H__
+#define __GNOME_SOUND_H__ 1
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/* Use this with the Esound functions */
+extern int gnome_sound_connection;
+
+/* Initialize esd connection */
+void gnome_sound_init(const char *hostname);
+
+/* Closes esd connection */
+void gnome_sound_shutdown(void);
+
+/* Returns the Esound sample ID for the sample */
+int gnome_sound_sample_load(const char *sample_name, const char *filename);
+
+/* Loads sample, plays sample, frees sample */
+void gnome_sound_play (const char * filename);
+
+G_END_DECLS
+
+#endif /* __GNOME_SOUND_H__ */
diff --git a/libgnome/gnome-triggers.c b/libgnome/gnome-triggers.c
new file mode 100644
index 0000000..b67c558
--- /dev/null
+++ b/libgnome/gnome-triggers.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 1997, 1998 Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#include "config.h"
+
+/* By Elliot Lee */
+
+#include "gnome-triggers.h"
+#include "gnome-triggersP.h"
+#include "gnome-config.h"
+#include "gnome-util.h"
+#if 0
+#include "gnome-sound.h"
+
+#ifdef HAVE_ESD
+#include <esd.h>
+#endif
+#endif
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <dirent.h>
+
+/* TYPE DECLARATIONS */
+
+typedef void (*GnomeTriggerTypeFunction)(GnomeTrigger *t, char *msg, char *level, char *supinfo[]);
+
+/* PROTOTYPES */
+static GnomeTrigger* gnome_trigger_dup(GnomeTrigger *dupme);
+static GnomeTriggerList* gnome_triggerlist_new(char *nodename);
+static void gnome_triggerlist_free(GnomeTriggerList* t);
+static void gnome_trigger_free(GnomeTrigger* t);
+static void gnome_trigger_do(GnomeTrigger* t, const char *msg, const char *level,
+			     const char *supinfo[]);
+static void gnome_trigger_do_function(GnomeTrigger* t,
+				      const char *msg, const char *level,
+				      const char *supinfo[]);
+static void gnome_trigger_do_command(GnomeTrigger* t,
+				     const char *msg, const char *level,
+				     const char *supinfo[]);
+static void gnome_trigger_do_mediaplay(GnomeTrigger* t,
+				       const char *msg,
+				       const char *level,
+				       const char *supinfo[]);
+
+/* FILEWIDE VARIABLES */
+
+static GnomeTriggerList* gnome_triggerlist_topnode = NULL;
+
+static const GnomeTriggerTypeFunction actiontypes[] =
+/* This list should have entries for all the trigger types in
+   gnome-triggers.h */
+{
+  (GnomeTriggerTypeFunction)NULL,
+  (GnomeTriggerTypeFunction)gnome_trigger_do_function,
+  (GnomeTriggerTypeFunction)gnome_trigger_do_command,
+  (GnomeTriggerTypeFunction)gnome_trigger_do_mediaplay,
+  (GnomeTriggerTypeFunction)NULL
+};
+
+/* IMPLEMENTATIONS */
+void
+gnome_triggers_init(void)
+{
+}
+
+#if 0
+/* snarfed almost directly from sound-properties. */
+static gint
+gnome_triggers_read_path(const char *config_path)
+{
+  DIR *dirh;
+  char *category_name, *sample_name, *sample_file, *ctmp;
+  gpointer top_iter, event_iter;
+  struct dirent *dent;
+  GnomeTrigger nt;
+  GString *tmpstr;
+
+  nt.type = GTRIG_MEDIAPLAY;
+  nt.level = NULL;
+  nt.u.media.cache_id = -1;
+
+  dirh = opendir(config_path);
+  if(!dirh)
+    return -1;
+
+  tmpstr = g_string_new(NULL);
+
+  while((dent = readdir(dirh))) {
+    /* ignore no-good dir entries.
+       We ignore "gnome" because the system sounds are listed in there.
+    */
+    if (!strcmp(dent->d_name, ".")
+	|| !strcmp(dent->d_name, "..")
+	|| !strcmp(dent->d_name, "gnome")
+	|| !strcmp(dent->d_name, "gnome.soundlist"))
+      continue;
+
+    g_string_sprintf(tmpstr, "=%s/%s=", config_path, dent->d_name);
+
+    gnome_config_push_prefix(tmpstr->str);
+
+    event_iter = gnome_config_init_iterator_sections(tmpstr->str);
+    while((event_iter = gnome_config_iterator_next(event_iter,
+						   &sample_name, NULL))) {
+      if(!strcmp(sample_name, "__section_info__"))
+	goto continue_loop;
+
+      g_string_sprintf(tmpstr, "%s/file", sample_name);
+      sample_file = gnome_config_get_string(tmpstr->str);
+
+      if(!sample_file || !*sample_file) {
+	g_free(sample_name);
+	continue;
+      }
+
+      if(*sample_file != '/') {
+	char *tmp = gnome_sound_file(sample_file);
+	g_free(sample_file);
+	sample_file = tmp;
+      }
+
+      ctmp = g_strdup(dent->d_name);
+      if(strstr(ctmp, ".soundlist"))
+	*strstr(ctmp, ".soundlist") = '\0';
+
+      nt.u.media.file = sample_file;
+      gnome_triggers_add_trigger(&nt, ctmp, sample_name, NULL);
+      
+      g_free(ctmp);
+
+    continue_loop:
+      g_free(sample_name);
+    }
+
+    gnome_config_pop_prefix();
+  }
+  closedir(dirh);
+
+  g_string_free(tmpstr, TRUE);
+
+  return 0;
+}
+/**
+ * gnome_triggers_readfile:
+ * @infilename: A file listing triggers to install in the currently
+ * running program.
+ *
+ * The file should be of the format:
+ *
+ *    level section type params
+ *
+ * Where 'level' indicates the message severity at which this trigger
+ * should be activated, 'section' is a colon-separated list indicating
+ * which part of the "message classification tree" this trigger will
+ * be activated for, 'type' is either "command" (run the command
+ * specified in 'params') or 'play' (play the esd sound sample named
+ * 'params').
+ *
+ * Returns 0 on success.  1 otherwise.
+ *
+ */
+gint
+gnome_triggers_readfile(const char *infilename)
+{
+  GnomeTrigger* nt;
+  char aline[512];
+  char **subnames = NULL;
+  char **parts = NULL;
+  FILE *infile;
+  int i;
+
+  infile = fopen(infilename, "r");
+  if(infile == NULL)
+    return 1;
+
+  nt = gnome_trigger_dup(NULL);
+  while(fgets(aline, sizeof(aline), infile)) {
+    i = strlen(aline) - 1;
+    while(isspace(aline[i])) aline[i--] = '\0';
+
+    if(aline[0] == '\0' || aline[0] == '#')
+      continue;
+
+    parts = g_strsplit(aline, " ", 4);
+    if(!parts || !parts[0] || !parts[1] || !parts[2] || !parts[3]) {
+      g_strfreev(parts);
+      g_warning("Invalid triggers line \'%s\'\n", aline);
+      continue;
+    }
+
+    if(!strcmp(parts[1], "NULL")) {
+      subnames = g_malloc(sizeof(gchar *));
+      subnames[0] = NULL;
+    } else
+      subnames = g_strsplit(parts[1], ":", -1);
+
+    if(!strcmp(parts[2], "command"))
+      nt->type = GTRIG_COMMAND;
+    else if(!strcmp(parts[2], "play"))
+      nt->type = GTRIG_MEDIAPLAY;
+    nt->u.command = parts[3];
+    if(!strcmp(parts[0], "NULL"))
+      nt->level = NULL;
+    else
+      nt->level = parts[0];
+    gnome_triggers_vadd_trigger(nt, subnames);
+
+    g_strfreev(subnames);
+    g_strfreev(parts);
+  }
+  g_free(nt);
+  fclose(infile);
+
+  return 0;
+}
+#endif
+
+/**
+ * gnome_triggers_add_trigger:
+ * @nt: Information on the new trigger to be added.
+ * @...: the 'section' to add the trigger under (see gnome_triggers_readfile())
+ *
+ * Similar to gnome_triggers_readfile(), but gets the trigger information
+ * from the file 'nt' structure and the varargs, instead of from a file.
+ */
+void gnome_triggers_add_trigger(GnomeTrigger* nt, ...)
+{
+  va_list l;
+  gint nstrings, i;
+  gchar **strings;
+  
+  /* Count number of strings */
+  
+  va_start(l, nt);
+  for (nstrings = 0; va_arg(l, gchar *); nstrings++);
+  va_end(l);
+  
+  /* Build list */
+  
+  strings = g_new(gchar *, nstrings + 1);
+  
+  va_start(l, nt);
+  
+  for (i = 0; i < nstrings; i++)
+    strings[i] = va_arg(l, gchar *);
+  strings[i] = NULL;
+  
+  va_end(l);
+  
+  /* And pass them to the real function */
+  
+  gnome_triggers_vadd_trigger(nt, strings);
+
+  g_free (strings);
+}
+
+static GnomeTrigger*
+gnome_trigger_dup(GnomeTrigger* dupme)
+{
+  GnomeTrigger* retval;
+  retval = g_malloc(sizeof(struct _GnomeTrigger));
+  if(dupme) {
+    *retval = *dupme;
+    if(dupme->level)
+      retval->level = g_strdup(dupme->level);
+    else
+      retval->level = NULL;
+    switch(retval->type) {
+    case GTRIG_COMMAND:
+      retval->u.command = g_strdup(dupme->u.command);
+      break;
+    default:
+      break;
+    }
+  } else {
+    retval->level = NULL;
+    retval->type = GTRIG_NONE;
+    memset(&retval->u, 0, sizeof(retval->u));
+  }
+  return retval;
+}
+
+static GnomeTriggerList*
+gnome_triggerlist_new(char *nodename)
+{
+  GnomeTriggerList* retval;
+  retval = g_malloc0(sizeof(GnomeTriggerList));
+  retval->nodename = g_strdup(nodename);
+  return retval;
+}
+
+/**
+ * gnome_triggers_vadd_trigger:
+ * @nt: Information on the new trigger to be added.
+ * @supinfo: the 'section' to add the trigger under (see gnome_triggers_readfile())
+ *
+ * Similar to gnome_triggers_readfile(), but gets the trigger information
+ * from the file 'nt' structure and 'supinfo', instead of from a file.
+ */
+void gnome_triggers_vadd_trigger(GnomeTrigger* nt,
+				 char *supinfo[])
+{
+  g_return_if_fail(nt != NULL);
+  if(!gnome_triggerlist_topnode)
+    gnome_triggerlist_topnode = gnome_triggerlist_new(NULL);
+
+  if(supinfo == NULL || supinfo[0] == NULL) {
+    gnome_triggerlist_topnode->actions = g_realloc(gnome_triggerlist_topnode->actions, ++gnome_triggerlist_topnode->numactions);
+    gnome_triggerlist_topnode->actions[gnome_triggerlist_topnode->numactions - 1] = gnome_trigger_dup(nt);
+  } else {
+    int i, j;
+    GnomeTriggerList* curnode;
+
+    for(i = 0, curnode = gnome_triggerlist_topnode;
+	supinfo[i]; i++) {
+      for(j = 0;
+	  j < curnode->numsubtrees
+	    && strcmp(curnode->subtrees[j]->nodename, supinfo[i]);
+	  j++) /* Do nothing */ ;
+
+      if(j < curnode->numsubtrees) {
+	curnode = curnode->subtrees[j];
+      } else {
+	curnode->subtrees = g_realloc(curnode->subtrees,
+				      ++curnode->numsubtrees
+				      * sizeof(GnomeTriggerList*));
+	curnode->subtrees[curnode->numsubtrees - 1] =
+	  gnome_triggerlist_new(supinfo[i]);
+	curnode = curnode->subtrees[curnode->numsubtrees - 1];
+      } /* end for j */
+    } /* end for i */
+
+    curnode->actions = g_realloc(curnode->actions,
+				 ++curnode->numactions
+				 * sizeof(GnomeTrigger));
+    curnode->actions[curnode->numactions - 1] = gnome_trigger_dup(nt);
+  } /* end if */
+}
+
+/**
+ * gnome_triggers_do:
+ * @msg: The human-readable message describing the event. (Can be NULL).
+ * @level: The level of severity of the event, or NULL.
+ * @...: The classification of the event.
+ *
+ * Notifies GNOME about an event happening, so GNOME can do cool things.
+ */
+void
+gnome_triggers_do(const char *msg, const char *level, ...)
+{
+  va_list l;
+  gint nstrings, i;
+  gchar **strings;
+  
+  /* Count number of strings */
+  va_start(l, level);
+  for (nstrings = 0; va_arg(l, gchar *); nstrings++);
+  va_end(l);
+  
+  /* Build list */
+  
+  strings = g_new (gchar *, nstrings + 1);
+  
+  va_start(l, level);
+  
+  for (i = 0; i < nstrings; i++)
+    strings[i] = va_arg(l, gchar *);
+  strings[i] = NULL;
+  
+  va_end(l);
+  
+  /* And pass them to the real function */
+  
+  gnome_triggers_vdo(msg, level, (const char **)strings);
+
+  g_free (strings);
+}
+
+/* The "add one to the sample ID" is because sample ID's start at 0,
+   and we need a way to distinguish between "not found in sound_ids"
+   and "sample #0" */
+static void
+gnome_triggers_play_sound(const char *sndname)
+{
+#if defined(HAVE_ESD) && 0
+  int sid;
+  static GHashTable *sound_ids = NULL;
+
+  if(gnome_sound_connection < 0) return;
+
+  if(!sound_ids)
+    sound_ids = g_hash_table_new(g_str_hash, g_str_equal);
+
+  sid = GPOINTER_TO_INT(g_hash_table_lookup(sound_ids, sndname));
+
+  if(!sid) {
+    sid = esd_sample_getid(gnome_sound_connection, sndname);
+    if(sid >= 0) sid++;
+    g_hash_table_insert(sound_ids, g_strdup(sndname), GINT_TO_POINTER(sid));
+  }
+
+  if(sid < 0) return;
+  sid--;
+  esd_sample_play(gnome_sound_connection, sid);
+#endif
+  /* If there's no esound, this is just a no-op */
+}
+
+/**
+ * gnome_triggers_vdo:
+ * @msg: The human-readable message describing the event. (Can be NULL).
+ * @level: The level of severity of the event, or NULL.
+ * @supinfo: The classification of the event (NULL terminated array).
+ *
+ * Notifies GNOME about an event happening, so GNOME can do cool things.
+ */
+void
+gnome_triggers_vdo(const char *msg, const char *level, const char *supinfo[])
+{
+  GnomeTriggerList* curnode = gnome_triggerlist_topnode;
+  int i, j;
+  char buf[256], *ctmp;
+
+  if(level) {
+    g_snprintf(buf, sizeof(buf), "gnome/%s", level);
+    gnome_triggers_play_sound(buf);
+  }
+
+  if(!supinfo)
+    return;
+
+  ctmp = g_strjoinv("/", (char **)supinfo);
+  gnome_triggers_play_sound(ctmp);
+  g_free(ctmp);
+
+  for(i = 0; curnode && supinfo[i]; i++)
+    {
+
+    for(j = 0; j < curnode->numactions; j++)
+      {
+	if(!curnode->actions[j]->level
+	   || !level
+	   || !strcmp(level, curnode->actions[j]->level))
+	  gnome_trigger_do(curnode->actions[j], msg, level, supinfo);
+      }
+    
+    for(j = 0;
+	j < curnode->numsubtrees
+	  && strcmp(curnode->subtrees[j]->nodename,supinfo[i]);
+	j++)
+      /* Do nothing */ ;
+    if(j < curnode->numsubtrees)
+      curnode = curnode->subtrees[j];
+    else
+      curnode = NULL;
+  }
+  if(curnode)
+    {
+      for(j = 0; j < curnode->numactions; j++)
+	{
+	  if(!curnode->actions[j]->level
+	     || !level
+	     || !strcmp(level, curnode->actions[j]->level))
+	    gnome_trigger_do(curnode->actions[j], msg, level, supinfo);
+	}
+    }
+}
+
+static void
+gnome_trigger_free(GnomeTrigger* t)
+{
+  if(t->level)
+    g_free(t->level);
+  switch(t->type) {
+  case GTRIG_COMMAND:
+    g_free(t->u.command); break;
+  case GTRIG_MEDIAPLAY:
+    g_free(t->u.media.file); break;
+  default:
+    break;
+  }
+  g_free(t);
+}
+
+static void
+gnome_triggerlist_free(GnomeTriggerList* t)
+{
+  int i;
+
+  g_free(t->nodename);
+
+  for(i = 0; i < t->numsubtrees; i++) {
+    gnome_triggerlist_free(t->subtrees[i]);
+  }
+  g_free(t->subtrees);
+
+  for(i = 0; i < t->numactions; i++) {
+    gnome_trigger_free(t->actions[i]);
+  }
+  g_free(t->actions);
+
+  g_free(t);
+}
+
+static void
+gnome_trigger_do(GnomeTrigger* t,
+		 const char *msg,
+		 const char * level,
+		 const char *supinfo[])
+{
+  g_return_if_fail(t != NULL);
+
+  actiontypes[t->type](t, (char *)msg, (char *)level, (char **)supinfo);
+}
+
+static void
+gnome_trigger_do_function(GnomeTrigger* t,
+			  const char *msg,
+			  const char *level,
+			  const char *supinfo[])
+{
+  t->u.function((char *)msg, (char *)level, (char **)supinfo);
+}
+
+static void
+gnome_trigger_do_command(GnomeTrigger* t,
+			 const char *msg,
+			 const char *level,
+			 const char *supinfo[])
+{
+  char **argv;
+  int nsupinfos, i;
+
+  for(nsupinfos = 0; supinfo[nsupinfos]; nsupinfos++);
+
+  argv = g_malloc(sizeof(char *) * (nsupinfos + 4));
+  argv[0] = (char *)t->u.command;
+  argv[1] = (char *)msg;
+  argv[2] = (char *)level;
+
+  for(i = 0; supinfo[i]; i++) {
+    argv[i + 3] = (char *)supinfo[i];
+  }
+  argv[i + 3] = NULL;
+
+  /* We're all set, let's do it */
+  {
+    pid_t childpid;
+    int status;
+    childpid = fork();
+    if(childpid)
+      waitpid(childpid, &status, 0);
+    else
+      execv(t->u.command, argv);
+  }
+  
+  g_free(argv);
+}
+
+static void
+gnome_trigger_do_mediaplay(GnomeTrigger* t,
+			   const char *msg,
+			   const char *level,
+			   const char *supinfo[])
+{
+#if defined(HAVE_ESD) && 0
+  if(gnome_sound_connection == -1)
+    return;
+
+  if(t->u.media.cache_id >= 0)
+    esd_sample_play(gnome_sound_connection, t->u.media.cache_id);
+  else if(t->u.media.cache_id == -1)
+    gnome_sound_play(t->u.media.file);
+#endif
+}
diff --git a/libgnome/gnome-triggers.h b/libgnome/gnome-triggers.h
new file mode 100644
index 0000000..5afb019
--- /dev/null
+++ b/libgnome/gnome-triggers.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 1997, 1998 Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifndef __GNOME_TRIGGERS_H__
+#define __GNOME_TRIGGERS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+	GTRIG_NONE,
+	GTRIG_FUNCTION,
+	GTRIG_COMMAND,
+	GTRIG_MEDIAPLAY
+} GnomeTriggerType;
+
+typedef void (*GnomeTriggerActionFunction)(char *msg, char *level, char *supinfo[]);
+
+struct _GnomeTrigger {
+	GnomeTriggerType type;
+	union {
+		/*
+		 * These will be passed the same info as
+		 * gnome_triggers_do got
+		 */
+		GnomeTriggerActionFunction function;
+		gchar *command;
+		struct {
+			gchar *file;
+			int cache_id;
+		} media;
+	} u;
+        gchar *level;
+};
+typedef struct _GnomeTrigger GnomeTrigger;
+
+void gnome_triggers_init     (void);
+gint gnome_triggers_readfile (const char *infilename);
+
+/*
+ * The optional arguments in some of these functions are just
+ * a list of strings that help us know
+ * what type of event happened. For example,
+ *
+ * gnome_triggers_do("System is out of disk space on /dev/hda1!",
+ *	             "warning", "system", "device", "disk", "/dev/hda1");
+ */
+
+void gnome_triggers_add_trigger  (GnomeTrigger *nt, ...);
+void gnome_triggers_vadd_trigger (GnomeTrigger *nt,
+				  char *supinfo[]);
+
+void gnome_triggers_do           (const char *msg,
+				  const char *level, ...);
+
+void gnome_triggers_vdo          (const char *msg, const char *level,
+				  const char *supinfo[]);
+
+G_END_DECLS
+
+#endif /* __GNOME_TRIGGERS_H__ */
diff --git a/libgnome/gnome-triggersP.h b/libgnome/gnome-triggersP.h
new file mode 100644
index 0000000..cd8cd8a
--- /dev/null
+++ b/libgnome/gnome-triggersP.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 1997, 1998 Elliot Lee
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifndef GNOME_TRIGGERSP_H
+#define GNOME_TRIGGERSP_H 1
+
+/* Yes, this mechanism is lame, that's why it's hidden :) */
+typedef struct _GnomeTriggerList GnomeTriggerList;
+
+struct _GnomeTriggerList {
+  char *nodename;
+  GnomeTriggerList **subtrees;
+  GnomeTrigger **actions;
+  gint numsubtrees;
+  gint numactions;
+};
+
+#endif
diff --git a/libgnome/gnome-url.c b/libgnome/gnome-url.c
index b7393e5..2f3d0ed 100644
--- a/libgnome/gnome-url.c
+++ b/libgnome/gnome-url.c
@@ -32,6 +32,8 @@
 #include <unistd.h>
 #include <errno.h>
 
+#include "gnome-i18nP.h"
+
 #include <bonobo/bonobo-property-bag-client.h>
 #include <libgnome/gnome-exec.h>
 #include <libgnome/gnome-util.h>
diff --git a/libgnome/gnome-util.c b/libgnome/gnome-util.c
index 80058b7..004a353 100644
--- a/libgnome/gnome-util.c
+++ b/libgnome/gnome-util.c
@@ -94,8 +94,12 @@ gnome_util_user_shell (void)
 		"/bin/csh", "/bin/sh", 0
 	};
 
-	if ((shell = g_getenv ("SHELL"))){
-		return g_strdup (shell);
+	if (geteuid () == getuid () &&
+	    getegid () == getgid ()) {
+		/* only in non-setuid */
+		if ((shell = g_getenv ("SHELL"))){
+			return g_strdup (shell);
+		}
 	}
 	pw = getpwuid(getuid());
 	if (pw && pw->pw_shell) {
diff --git a/libgnome/libgnome.h b/libgnome/libgnome.h
index c66eb2b..8115bb1 100644
--- a/libgnome/libgnome.h
+++ b/libgnome/libgnome.h
@@ -29,6 +29,11 @@
 #include <libgnome/gnome-program.h>
 #include <libgnome/gnome-i18n.h>
 
+#include <libgnome/gnome-config.h>
+
+#include <libgnome/gnome-triggers.h>
+#include <libgnome/gnome-sound.h>
+
 #include <libgnome/gnome-exec.h>
 
 #include <libgnome/gnome-util.h>
diff --git a/libgnome/test-libgnome.c b/libgnome/test-libgnome.c
index 007994a..390f736 100644
--- a/libgnome/test-libgnome.c
+++ b/libgnome/test-libgnome.c
@@ -7,6 +7,8 @@
 #include <unistd.h>
 #include <string.h>
 
+#include "gnome-i18nP.h"
+
 #include "libgnome.h"
 
 #include <libgnome/gnome-url.h>



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