[monkey-bubble: 1/753] Initial revision



commit ac21e25d96c21b9a2d1eef92a9d0ffa1da3c87e0
Author: Elliot Lee <sopwith src gnome org>
Date:   Mon Nov 24 22:32:10 1997 +0000

    Initial revision

 libgnome/.cvsignore       |    6 +
 libgnome/Makefile.am      |   42 +++
 libgnome/gnome-config.c   |  645 +++++++++++++++++++++++++++++++++++++++++++++
 libgnome/gnome-config.h   |   39 +++
 libgnome/gnome-defs.h     |    7 +
 libgnome/gnome-dentry.c   |  199 ++++++++++++++
 libgnome/gnome-dentry.h   |   30 ++
 libgnome/gnome-dns.c      |  517 ++++++++++++++++++++++++++++++++++++
 libgnome/gnome-dns.h      |   80 ++++++
 libgnome/gnome-hook.c     |   85 ++++++
 libgnome/gnome-hook.h     |   22 ++
 libgnome/gnome-i18n.h     |   33 +++
 libgnome/gnome-init.c     |   36 +++
 libgnome/gnome-mime.c     |  273 +++++++++++++++++++
 libgnome/gnome-mime.h     |   34 +++
 libgnome/gnome-string.c   |   92 +++++++
 libgnome/gnome-string.h   |   10 +
 libgnome/gnome-triggers.c |  362 +++++++++++++++++++++++++
 libgnome/gnome-triggers.h |   49 ++++
 libgnome/gnome-util.c     |  231 ++++++++++++++++
 libgnome/gnome-util.h     |   25 ++
 libgnome/gnomelib-init.c  |   36 +++
 libgnome/libgnome.h       |   19 ++
 23 files changed, 2872 insertions(+), 0 deletions(-)
---
diff --git a/libgnome/.cvsignore b/libgnome/.cvsignore
new file mode 100644
index 0000000..2485b2b
--- /dev/null
+++ b/libgnome/.cvsignore
@@ -0,0 +1,6 @@
+Makefile.in
+Makefile
+*.lo
+*.la
+.deps
+_libs
diff --git a/libgnome/Makefile.am b/libgnome/Makefile.am
new file mode 100644
index 0000000..e16f804
--- /dev/null
+++ b/libgnome/Makefile.am
@@ -0,0 +1,42 @@
+## Process this file with automake to produce Makefile.in
+
+LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
+
+libgnomeincludedir = $(includedir)/libgnome
+
+INCLUDES = -I.. -I$(srcdir)/.. -I$(includedir) \
+	-DGNOMELIBDIR=\""$(libdir)"\" \
+	-DGNOMEDATADIR=\""$(datadir)"\" \
+	-DGNOMELOCALEDIR=\""$(libdir)/locale\"" \
+	-I$(top_srcdir)/intl \
+	 -I$(srcdir)/../programs
+
+lib_LTLIBRARIES = libgnome.la
+
+libgnome_la_SOURCES = \
+	gnome-hook.c 		\
+	gnome-util.c		\
+	gnome-config.c		\
+	gnomelib-init.c         \
+	gnome-dentry.c          \
+	gnome-dns.c		\
+	gnome-mime.c		\
+	gnome-string.c		\
+	gnome-triggers.c
+
+libgnomeinclude_HEADERS = \
+        gnome-config.h 		\
+	gnome-defs.h   		\
+	gnome-hook.h   		\
+	gnome-util.h   		\
+	gnome-dns.h    		\
+	gnome-dentry.h 		\
+	gnome-i18n.h 		\
+	gnome-mime.h		\
+	gnome-triggers.h 	\
+	gnome-string.h		\
+	libgnome.h
+
+
+libgnome_la_LDFLAGS = -version-info 0:0:0 -rpath $(libdir)
+libgnome_la_LIBADD = -lgdk -lglib -lm
diff --git a/libgnome/gnome-config.c b/libgnome/gnome-config.c
new file mode 100644
index 0000000..314f0a3
--- /dev/null
+++ b/libgnome/gnome-config.c
@@ -0,0 +1,645 @@
+/*
+ * Configuration-File Functions.
+ *
+ *  Copyright 1993, 1994, 1997 The Free Software Foundation
+ *
+ * Authors: Miguel de Icaza
+
+   This program is g_free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the G_Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the G_Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+   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.
+   
+   */
+
+/* #include <config.h> */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>	/* For g_free() and atoi() */
+#include <sys/types.h>
+#include <glib.h>
+#include "libgnome.h"
+
+#define STRSIZE 4096
+#define overflow (next == &CharBuffer [STRSIZE-1])
+
+enum {
+	FirstBrace,
+	OnSecHeader,
+	IgnoreToEOL,
+	KeyDef,
+	KeyDefOnKey,
+	KeyValue
+};
+
+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;
+} TProfile;
+
+typedef struct {
+	char *file, *section, *key, *def;
+	char *path, *opath;
+} ParsedPath;
+
+/*
+ * Prefix for all the configuration operations
+ * iff the path does not begin with / or with #
+ */
+static char *prefix;
+
+static TProfile *Current = 0;
+
+/*
+ * This one keeps track of all of the opened files
+ */
+static TProfile *Base = 0;
+
+static void
+release_path (ParsedPath *p)
+{
+	g_free (p->opath);
+	g_free (p);
+}
+
+static ParsedPath *
+parse_path (char *path)
+{
+	ParsedPath *p = g_malloc (sizeof (ParsedPath));
+	char *sep;
+
+	g_assert(path != NULL);
+	
+	if (*path == '/' || prefix == NULL)
+		p->opath = strdup (path);
+	else
+		p->opath = g_copy_strings (prefix, path, NULL);
+
+	p->path = p->opath;
+	
+	if (*p->path == '='){
+		sep = "=";
+		p->path++;
+	} else
+		sep = "/=";
+	
+	p->file    = strtok (p->path, sep);
+	p->section = strtok (NULL, "/=");
+	p->key     = strtok (NULL, "=");
+	p->def     = strtok (NULL, "=");
+
+	/* Was it a Gnome-relative pathname? */
+	if (*sep == '/'){
+		char *f = g_concat_dir_and_file (gnome_user_dir, p->file);
+		p->file = f;
+	}
+	return p;
+}
+
+static int 
+is_loaded (char *filename, TSecHeader **section)
+{
+	TProfile *p = Base;
+	
+	while (p){
+		if (!strcasecmp (filename, p->filename)){
+			Current = p;
+			*section = p->section;
+			return 1;
+		}
+		p = p->link;
+	}
+	return 0;
+}
+
+static TSecHeader *
+load (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 (f)) != EOF){
+		if (c == '\r')		/* Ignore Carriage Return */
+			continue;
+		
+		switch (state){
+			
+		case OnSecHeader:
+			if (c == ']' || overflow){
+				*next = '\0';
+				next = CharBuffer;
+				SecHeader->section_name = strdup (CharBuffer);
+				state = IgnoreToEOL;
+			} else
+				*next++ = c;
+			break;
+
+		case IgnoreToEOL:
+			if (c == '\n'){
+				state = KeyDef;
+				next = CharBuffer;
+			}
+			break;
+
+		case FirstBrace:
+		case KeyDef:
+		case KeyDefOnKey:
+			if (c == '['){
+				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;
+	    
+			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 = strdup (CharBuffer);
+				state = KeyValue;
+				next = CharBuffer;
+			} else {
+				*next++ = c;
+				state = KeyDefOnKey;
+			}
+			break;
+
+		case KeyValue:
+			if (overflow || c == '\n'){
+				*next = '\0';
+				SecHeader->keys->value = strdup (CharBuffer);
+				state = c == '\n' ? KeyDef : IgnoreToEOL;
+				next = CharBuffer;
+#ifdef DEBUG
+				printf ("[%s] (%s)=%s\n", SecHeader->section_name,
+					SecHeader->keys->key_name, SecHeader->keys->value);
+#endif
+			} else
+				*next++ = c;
+			break;
+	    
+		} /* switch */
+	
+	} /* while ((c = getc (f)) != EOF) */
+	if (c == EOF && state == KeyValue){
+		*next = '\0';
+		SecHeader->keys->value = strdup (CharBuffer);
+	}
+	fclose (f);
+	return SecHeader;
+}
+
+static void 
+new_key (TSecHeader *section, char *key_name, char *value)
+{
+	TKeys *key;
+    
+	key = (TKeys *) g_malloc (sizeof (TKeys));
+	key->key_name = strdup (key_name);
+	key->value   = strdup (value);
+	key->link = section->keys;
+	section->keys = key;
+}
+
+static char *
+access_config (access_type mode, char *section_name, char *key_name, 
+		   char *def, char *filename)
+{
+    
+	TProfile   *New;
+	TSecHeader *section;
+	TKeys      *key;
+
+	if (!is_loaded (filename, &section)){
+		New = (TProfile *) g_malloc (sizeof (TProfile));
+		New->link = Base;
+		New->filename = strdup (filename);
+		New->section = load (filename);
+		Base = New;
+		section = New->section;
+		Current = New;
+	}
+    
+	/* Start search */
+	for (; section; section = section->link){
+		if (section->section_name == 0)
+			continue;
+		if (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 = strdup (def);
+			}
+			return key->value;
+		}
+
+		/* No key found */
+		if (mode == SET){
+			new_key (section, key_name, def);
+			return 0;
+		}
+	}
+    
+	/* Non existent section */
+	if ((mode == SET) && def){
+		section = (TSecHeader *) g_malloc (sizeof (TSecHeader));
+		section->section_name = strdup (section_name);
+		section->keys = 0;
+		new_key (section, key_name, def);
+		section->link = Current->section;
+		Current->section = section;
+	} 
+	return def;
+}
+
+static void 
+dump_keys (FILE *profile, TKeys *p)
+{
+	if (!p)
+		return;
+	dump_keys (profile, p->link);
+	if (*p->key_name) 
+		fprintf (profile, "%s=%s\n", p->key_name, p->value);
+}
+
+static void 
+dump_sections (FILE *profile, TSecHeader *p)
+{
+	if (!p)
+		return;
+	dump_sections (profile, p->link);
+	if (p->section_name [0]){
+		fprintf (profile, "\n[%s]\n", p->section_name);
+		dump_keys (profile, p->keys);
+	}
+}
+
+static void 
+dump_profile (TProfile *p)
+{
+	FILE *profile;
+    
+	if (!p)
+		return;
+	dump_profile (p->link);
+
+	/* .ado: p->filename can be empty, it's better to jump over */
+	if (p->filename[0] != (char) 0)
+		if ((profile = fopen (p->filename, "w")) != NULL){
+			dump_sections (profile, p->section);
+			fclose (profile);
+		}
+}
+
+/*
+ * Must be called at the end.
+*/
+void 
+gnome_config_sync (void)
+{
+	dump_profile (Base);
+}
+
+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;
+	free_profile (p->link);
+	free_sections (p->section);
+	g_free (p->filename);
+	g_free (p);
+}
+
+void 
+gnome_config_clean_file (char *path)
+{
+	TProfile *p;
+	ParsedPath *pp;
+	
+	if (!path)
+		return;
+
+	pp = parse_path (path);
+	
+	for (p = Base; p; p = p->link){
+		if (strcmp (pp->file, p->filename) != 0)
+			continue;
+		
+		free_sections (p->section);
+		p->section = 0;
+		p->filename [0] = 0;
+		release_path (pp);
+		return;
+	}
+	release_path (pp);
+}
+
+void *
+gnome_config_init_iterator (char *path)
+{
+	TProfile   *New;
+	TSecHeader *section;
+	ParsedPath *pp;
+
+	pp = parse_path (path);
+	
+	if (!is_loaded (pp->file, &section)){
+		New = (TProfile *) g_malloc (sizeof (TProfile));
+		New->link = Base;
+		New->filename = strdup (pp->file);
+		New->section = load (pp->file);
+		Base = New;
+		section = New->section;
+		Current = New;
+	}
+	for (; section; section = section->link){
+		if (strcasecmp (section->section_name, pp->section))
+			continue;
+		return section->keys;
+	}
+	release_path (pp);
+	return 0;
+}
+
+void *
+gnome_config_iterator_next (void *s, char **key, char **value)
+{
+	TKeys *keys = (TKeys *) s;
+
+	if (keys){
+		*key   = g_strdup (keys->key_name);
+		*value = g_strdup (keys->value);
+		keys   = keys->link;
+	}
+	return keys;
+}
+
+void 
+gnome_config_clean_section (char *path)
+	/* *section_name, char *file */
+{
+	TSecHeader *section;
+	ParsedPath *pp;
+
+	pp = parse_path (path);
+	
+	/* We assume the user has called one of the other initialization funcs */
+	if (!is_loaded (pp->file, &section)){
+		fprintf (stderr,"Warning: profile_clean_section called before init\n");
+		release_path (pp);
+		return;
+	}
+	/* We only disable the section, so it will still be g_freed, but it */
+	/* won't be find by further walks of the structure */
+
+	for (; section; section = section->link){
+		if (strcasecmp (section->section_name, pp->section))
+			continue;
+		section->section_name [0] = 0;
+	}
+	release_path (pp);
+}
+
+void 
+gnome_config_clean_key (char *path)
+	/* *section_name, char *file */
+{
+	TSecHeader *section;
+	TKeys *key;
+	ParsedPath *pp;
+	
+	pp = parse_path (path);
+	
+	/* We assume the user has called one of the other initialization funcs */
+	if (!is_loaded (pp->file, &section)){
+		fprintf (stderr,"Warning: profile_clean_section called before init\n");
+		release_path (pp);
+		return;
+	}
+	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;
+		}
+	}
+	release_path (pp);
+}
+
+int 
+gnome_config_has_section (char *path)
+	/* char *section_name, char *profile */
+{
+	TSecHeader *section;
+	ParsedPath *pp;
+
+	pp = parse_path (path);
+	/* We assume the user has called one of the other initialization funcs */
+	if (!is_loaded (pp->file, &section)){
+		release_path (pp);
+		return 0;
+	}
+	for (; section; section = section->link){
+		if (strcasecmp (section->section_name, pp->section))
+			continue;
+		release_path (pp);
+		return 1;
+	}
+	release_path (pp);
+	return 0;
+}
+
+void 
+gnome_config_drop_all (void)
+{
+	free_profile (Base);
+}
+
+int
+gnome_config_get_int (char *path)
+{
+	ParsedPath *pp;
+	char *r;
+	int  v;
+	
+	pp = parse_path (path);
+	r = access_config (LOOKUP, pp->section, pp->key, pp->def, pp->file);
+
+	g_return_val_if_fail(r != NULL, 0);
+
+	if (!strcasecmp (r, "true")){
+		release_path (pp);
+		return 1;
+	}
+	if (!strcasecmp (r, "false")){
+		release_path (pp);
+		return 0;
+	}
+	v = atoi (r);
+	release_path (pp);
+	return v;
+}
+
+char *
+gnome_config_get_string (char *path)
+{
+	ParsedPath *pp;
+	char *r;
+	
+	pp = parse_path (path);
+	r = access_config (LOOKUP, pp->section, pp->key, pp->def, pp->file);
+	if (r)
+		r = strdup (r);
+	release_path (pp);
+	return r;
+}
+
+void
+gnome_config_set_string (char *path, char *new_value)
+{
+	ParsedPath *pp;
+	char *r;
+	
+	pp = parse_path (path);
+	r = access_config (SET, pp->section, pp->key, new_value, pp->file);
+	release_path (pp);
+}
+
+void
+gnome_config_set_int (char *path, int new_value)
+{
+	ParsedPath *pp;
+	char intbuf [40];
+	char *r;
+	
+	pp = parse_path (path);
+	sprintf (intbuf, "%d", new_value);
+	r = access_config (SET, pp->section, pp->key, intbuf, pp->file);
+	release_path (pp);
+}
+
+void
+gnome_config_set_prefix (char *path)
+{
+	prefix = strdup (path);
+}
+
+void
+gnome_config_drop_prefix (void)
+{
+	if (!prefix)
+		return;
+	free (prefix);
+	prefix = 0;
+}
diff --git a/libgnome/gnome-config.h b/libgnome/gnome-config.h
new file mode 100644
index 0000000..5bf8843
--- /dev/null
+++ b/libgnome/gnome-config.h
@@ -0,0 +1,39 @@
+#ifndef GNOME_CONFIG_H
+#define GNOME_CONFIG_H
+
+BEGIN_GNOME_DECLS
+
+/* Prototypes for the profile management functions */
+
+char *gnome_config_get_string    (char *path);
+int  gnome_config_get_int        (char *path);
+void gnome_config_set_string     (char *path, char *value);
+void gnome_config_set_int        (char *path, int value);
+
+/* Returns true if /path/section is defined */
+int  gnome_config_has_section    (char *path);
+
+/* Returns a pointer for iterating on /file/section contents */
+void *gnome_config_init_iterator (char *path);
+
+/* Get next key and value value from a section */
+void *gnome_config_iterator_next (void *s, char **key, char **value);
+
+void gnome_config_drop_all       (void);
+
+void gnome_config_sync           (void);
+
+/* This routine drops the information about /file */
+void gnome_config_clean_file     (char *path);
+
+/* This routine drops all of the information related to /file/section */
+void gnome_config_clean_section  (char *path);
+
+/* Drops the information for a specific key */
+void gnome_config_clean_key (char *path);
+void gnome_config_set_prefix (char *path);
+void gnome_config_drop_prefix (void);
+
+END_GNOME_DECLS
+
+#endif
diff --git a/libgnome/gnome-defs.h b/libgnome/gnome-defs.h
new file mode 100644
index 0000000..0eb284c
--- /dev/null
+++ b/libgnome/gnome-defs.h
@@ -0,0 +1,7 @@
+#ifdef __cplusplus 
+#define BEGIN_GNOME_DECLS extern "C" {
+#define END_GNOME_DECLS }
+#else
+#define BEGIN_GNOME_DECLS
+#define END_GNOME_DECLS
+#endif
diff --git a/libgnome/gnome-dentry.c b/libgnome/gnome-dentry.c
new file mode 100644
index 0000000..6d09d7f
--- /dev/null
+++ b/libgnome/gnome-dentry.c
@@ -0,0 +1,199 @@
+/*
+ * Support for manipulating .desktop files
+ *
+ * (C) 1997 the Free Software Foundation
+ *
+ * Authors: Miguel de Icaza.
+ *          Federico Mena
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "gnome-defs.h"
+#include "gnome-util.h"
+#include "gnome-config.h"
+#include "gnome-dentry.h"
+
+#define free_if_empty(x) { if (x) g_free (x); }
+
+int
+gnome_is_program_in_path (char *program)
+{
+	static char *path;
+	static char **paths;
+	char **p;
+	char *f;
+	
+	if (!path){
+		char *p;
+		int i, pc = 1;
+
+		path = strdup (getenv ("PATH"));
+		for (p = path; *p; p++)
+			if (*p == ':')
+				pc++;
+
+		paths = (char **) g_malloc (sizeof (char *) * (pc+1));
+
+		for (p = path, i = 0; i < pc; i++){
+			paths [i] = strtok (p, ":");
+			p = NULL;
+		}
+		paths [pc] = NULL;
+	}
+	p = paths;
+	while (*p){
+		f = g_concat_dir_and_file (*p, program);
+		if (g_file_exists (f)){
+			g_free (f);
+			return 1;
+		}
+		g_free (f);
+		p++;
+	}
+	return 0;
+}
+	      
+GnomeDesktopEntry *
+gnome_desktop_entry_load (char *file)
+{
+	GnomeDesktopEntry *newitem;
+	char *prefix;
+	char *exec_file, *try_file, *dot;
+
+	g_assert(file != NULL);
+
+	prefix = g_copy_strings ("=", file, "=/Desktop Entry/", NULL);
+
+	gnome_config_set_prefix (prefix);
+	g_free (prefix);
+
+	exec_file = gnome_config_get_string ("Exec");
+	if (!exec_file){
+		gnome_config_drop_prefix ();
+		return 0;
+	}
+	try_file = gnome_config_get_string ("TryExec");
+	if (try_file){
+		if (!gnome_is_program_in_path (try_file)){
+			g_free (try_file);
+			g_free (exec_file);
+			gnome_config_drop_prefix ();
+			return 0;
+		}
+	}
+	newitem = g_new(GnomeDesktopEntry, 1);
+	newitem->exec      = exec_file;
+	newitem->tryexec   = try_file;
+	newitem->icon_base = gnome_config_get_string ("Icon");
+	newitem->docpath   = gnome_config_get_string ("DocPath");
+	newitem->info      = gnome_config_get_string ("Info");
+	newitem->terminal  = gnome_config_get_int    ("Terminal");
+	newitem->type      = gnome_config_get_string ("Type");
+	newitem->location  = strdup (file);
+	
+	if (newitem->icon_base && *newitem->icon_base){
+		dot = strstr (newitem->icon_base, ".xpm");
+
+		if (dot){
+			*dot = 0;
+
+			newitem->small_icon = g_copy_strings (newitem->icon_base,
+					      "-small.xpm", NULL);
+			newitem->transparent_icon = g_copy_strings (newitem->icon_base,
+					      "-transparent.xpm", NULL);
+			*dot = '.';
+		}
+
+		/* Sigh, now we need to make them local to the gnome install */
+		if (*newitem->icon_base != '/'){
+			char *s = newitem->small_icon;
+			char *t = newitem->transparent_icon;
+
+			newitem->small_icon = gnome_pixmap_file (s);
+			newitem->transparent_icon = gnome_pixmap_file (t);
+			g_free (s);
+			g_free (t);
+		}
+	} else {
+		newitem->small_icon = newitem->transparent_icon = 0;
+	}
+	gnome_config_drop_prefix ();
+	return newitem;
+}
+
+void
+gnome_desktop_entry_save (GnomeDesktopEntry *dentry)
+{
+	char *prefix;
+	
+	g_assert(dentry != NULL);
+	g_assert(dentry->location != NULL);
+
+	prefix = g_copy_strings("=", dentry->location, "=/Desktop Entry", NULL);
+
+	gnome_config_clean_section(prefix);
+
+	prefix = g_copy_strings(prefix, "/", NULL);
+	gnome_config_set_prefix(prefix);
+	g_free(prefix);
+
+	if (dentry->exec)
+		gnome_config_set_string("Exec", dentry->exec);
+
+	if (dentry->tryexec)
+		gnome_config_set_string("TryExec", dentry->tryexec);
+
+	if (dentry->icon_base)
+		gnome_config_set_string("Icon", dentry->icon_base);
+
+	if (dentry->docpath)
+		gnome_config_set_string("DocPath", dentry->docpath);
+
+	if (dentry->info)
+		gnome_config_set_string("Info", dentry->info);
+
+	gnome_config_set_int("Terminal", dentry->terminal);
+
+	if (dentry->type)
+		gnome_config_set_string("Type", dentry->type);
+
+	gnome_config_drop_prefix();
+	gnome_config_sync();
+}
+
+void
+gnome_desktop_entry_free (GnomeDesktopEntry *item)
+{
+	g_assert(item != NULL);
+	
+	free_if_empty (item->exec);
+	free_if_empty (item->icon_base);
+	free_if_empty (item->docpath);
+	free_if_empty (item->info);
+	free_if_empty (item->type);
+	free_if_empty (item->small_icon);
+	free_if_empty (item->transparent_icon);
+	free_if_empty (item->location);
+	g_free (item);
+}
+
+void
+gnome_desktop_entry_launch (GnomeDesktopEntry *item)
+{
+	char *command;
+
+	g_assert(item != NULL);
+
+	if (item->terminal)
+		command = g_copy_strings ("(xterm -e \"", item->exec, "\") &", NULL);
+	else
+		command = g_copy_strings ("(true;", item->exec, ") &", NULL);
+	system (command);
+	g_free (command);
+}
+
diff --git a/libgnome/gnome-dentry.h b/libgnome/gnome-dentry.h
new file mode 100644
index 0000000..a3da000
--- /dev/null
+++ b/libgnome/gnome-dentry.h
@@ -0,0 +1,30 @@
+#ifndef __GNOME_DENTRY_H__
+#define __GNOME_DENTRY_H__
+
+BEGIN_GNOME_DECLS
+
+typedef struct {
+	char *exec;
+	char *tryexec;
+	char *icon_base;
+	char *docpath;
+	char *info;
+	int  terminal;
+	char *type;
+	char *location;
+	
+	/* These are computed from icon_base */
+	char *small_icon;
+	char *transparent_icon;
+} GnomeDesktopEntry;
+
+GnomeDesktopEntry *gnome_desktop_entry_load (char *file);
+void gnome_desktop_entry_save (GnomeDesktopEntry *dentry);
+void gnome_desktop_entry_free (GnomeDesktopEntry *item);
+void gnome_desktop_entry_launch (GnomeDesktopEntry *item);
+
+int gnome_is_program_in_path (char *progname);
+
+END_GNOME_DECLS
+
+#endif
diff --git a/libgnome/gnome-dns.c b/libgnome/gnome-dns.c
new file mode 100644
index 0000000..42643d7
--- /dev/null
+++ b/libgnome/gnome-dns.c
@@ -0,0 +1,517 @@
+/* 
+ * Copyright (C) 1997 Ian Main
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <gtk/gtk.h>
+
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>	
+#include <netinet/in.h>	
+#include <errno.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+#include "gnome-defs.h"
+#include "gnome-dns.h"
+
+#undef VERBOSE
+
+/* the maximum nuber of servers to spawn.. just as a safty measure
+ * in case something goes wrong -- so we don't have 
+ * gnome_fork_bombs() */
+
+#define GNOME_DNS_MAX_SERVERS       8
+
+static void gnome_dns_callback(gpointer server_num, gint source,
+			       GdkInputCondition condition);
+static gint gnome_dns_create_server(void);
+static void gnome_dns_server(gint pipefd[2]);
+
+typedef struct
+{
+	/* boolean to tell if server is doing a lookup */
+	gboolean in_use;
+	/* pipefd's to communicate to server with */
+	gint pipefd[2];
+} DnsServer;
+
+static DnsServer dns_server[GNOME_DNS_MAX_SERVERS];
+static int num_servers;
+static int server_init_cnt;
+
+typedef struct
+{
+	/* host hame for cache */
+	char *hostname;
+	gint server; /* -1 if complete, -2 if waiting for server,
+		      otherwise index to dns_server */
+	/* address of host - may be 0 on failure. */
+	guint32 ip_addr;
+} GnomeDnsCache;
+
+static GnomeDnsCache *dns_cache;
+static int dns_cache_size, dns_cache_size_max;
+
+typedef struct
+{
+	gint tag;
+	gint server; /* -1 if waiting, otherwise index to dns_server[] */
+	char *hostname;
+	void (*callback) (guint32 ip_addr, void *callback_data);
+	void *callback_data;
+} GnomeDnsCon;
+
+static GnomeDnsCon *dns_con;
+static gint dns_con_size, dns_con_size_max;
+
+static gint dns_con_tag = 0;
+
+
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_init
+ *
+ *   Initialize the dns functions for use.
+ *
+ * Arguments:
+ *   server_count specifies the number of servers to fork() at
+ *   init, or <= 0 to do dynamic server forking.  If you are
+ *   concerned about virtual mem usage, fork your servers as one of the
+ *   first things in your program.
+ * 
+ *   Note that it will still do dynamic forking if you specify > 0. 
+ *   when it runs out of servers.. a good init value may be 1 or 2.
+ * 
+ * Results:
+ *   gnome_dns_lookup() will be ready for use.
+ *
+ * Side effects:
+ *   The library is initialized.
+ *
+ *--------------------------------------------------------------
+ */
+
+
+void gnome_dns_init (gint server_count)
+{
+	dns_con_size = 0;
+	dns_con_size_max = 16;
+	dns_con = g_new (GnomeDnsCon, dns_con_size_max);
+	
+	dns_cache_size = 0;
+	dns_cache_size_max = 16;
+	dns_cache = g_new (GnomeDnsCache, dns_cache_size_max);
+	
+	num_servers = 0;
+	while (num_servers < server_count) {
+		if ( (gnome_dns_create_server()) < 0) {
+			g_error ("Unable to fork: %s", g_strerror(errno));
+		}
+	}
+}
+
+
+/* Send the request to the server. */
+void
+gnome_dns_server_req (gint server, const char *hostname) {
+	dns_server[server].in_use = TRUE;
+	gdk_input_add(dns_server[server].pipefd[0],
+		      GDK_INPUT_READ,
+		      (GdkInputFunction) gnome_dns_callback,
+		      (gpointer) server);
+	write (dns_server[server].pipefd[1], hostname, strlen (hostname) + 1);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_lookup
+ *
+ * looks up an address and returns a tag for use with
+ * gnome_dns_abort() if desired.  May not return -1 if
+ * hostname was in cache.
+ *
+ * Arguments:
+ * char *hostname - hostname to lookup
+ * callback - function to call when dns lookup is complete.
+ * callback_data - data to pass to this function.
+ *   
+ * Results:
+ * callback function is called when dns_lookup is complete.
+ * returns a tag identifying this lookup or -1 if lookup was
+ * in cache.
+ * 
+ * Side effects:
+ * a new dns server may be spawned if all the current servers
+ * are in use.
+ *
+ *--------------------------------------------------------------
+ */
+
+
+guint32 gnome_dns_lookup (const char *hostname, 
+			  void (* callback) (guint32 ip_addr, void *callback_data),
+			  void *callback_data)
+{
+	gint i;
+	gint tag;
+	gint server;
+	
+	/* check for cache hit. */
+	for (i = 0; i < dns_cache_size; i++)
+		if (!strcmp (hostname, dns_cache[i].hostname))
+			break;
+	
+	/* if it hit, call the callback immediately. */
+	if (i < dns_cache_size && dns_cache[i].server == -1) {
+		callback (dns_cache[i].ip_addr, callback_data);
+		return 0;
+	}
+	
+	/* It didn't hit in the cache with an answer - need to put request
+	 into the dns_con table. */
+	if (i < dns_cache_size) {
+		/* hit in cache but answer hasn't come back yet. */
+		server = dns_cache[i].server;
+	} else {
+		/* missed in cache -- create a cache entry */
+		if (dns_cache_size == dns_cache_size_max) {
+			dns_cache_size_max <<= 1;
+			dns_cache = g_realloc (dns_cache, dns_cache_size_max * sizeof (GnomeDnsCache));
+		}
+		dns_cache[dns_cache_size].hostname = g_strdup (hostname);
+		/* Find a server we can send the request to. */
+		for (server = 0; server < num_servers; server++)
+			if (!dns_server[server].in_use) {
+				break;
+			}
+		if (server < num_servers) {
+			/* found an unused server - give it the request */
+			gnome_dns_server_req (server, hostname);
+			dns_cache[dns_cache_size].server = server;
+		} else {
+			/* no unused servers - fork a new one */
+			dns_cache[dns_cache_size].server = gnome_dns_create_server();
+			if (dns_cache[dns_cache_size].server < 0) {
+				g_error ("Unable to fork: %s", g_strerror(errno));
+			}
+			
+		}
+		dns_cache_size++;
+	}
+	
+	if (dns_con_size == dns_con_size_max) {
+		dns_con_size_max <<= 1;
+		dns_con = g_realloc (dns_con, dns_con_size_max * sizeof (GnomeDnsCon));
+	}
+	tag = dns_con_tag++;
+	dns_con[dns_con_size].tag = tag;
+	dns_con[dns_con_size].server = server;
+	dns_con[dns_con_size].hostname = g_strdup (hostname);
+	dns_con[dns_con_size].callback = callback;
+	dns_con[dns_con_size].callback_data = callback_data;
+	dns_con_size++;
+	
+	return tag;
+}
+
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_abort
+ *
+ * aborts a previous call to gnome_dns_lookup().
+ *
+ * Arguments:
+ * gint tag32 - the tag returned from previous call to gnome_dns_lookup().
+ *   
+ * Results:
+ *   callback function is not called.
+ *
+ * Side effects:
+ * 
+ *--------------------------------------------------------------
+ */
+
+
+void
+gnome_dns_abort (guint32 tag)
+{
+	gint i;
+	
+	for (i = 0; i < dns_con_size; i++) {
+		if (dns_con[i].tag == tag) {
+			g_free (dns_con[i].hostname);
+			dns_con[i] = dns_con[--dns_con_size];
+			return;
+		}
+	}
+	g_warning ("gnome_dns_abort: aborting a nonexistent tag\n");
+}
+
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_callback
+ *
+ * internal function - called when dns lookup completes.. this 
+ * function dispatches the callback passed to gnome_dns_lookup().
+ *
+ * Arguments:
+ * gint server_num - the index into the dns_server struct.
+ * gint source - unkown.
+ * GdkIputCondition - unkown.
+ *   
+ * Results:
+ *   callback function passed to gnome_dns_lookup is called.
+ *
+ * Side effects:
+ * this dns_server[server_num]->in_use set to 0 for future lookups.
+ * ie, the lock is removed.
+ * 
+ *--------------------------------------------------------------
+ */
+
+void gnome_dns_callback(gpointer serv_num, gint source,
+			GdkInputCondition condition)
+{
+	guint32 ip_addr;
+	gint server_num;
+	gint i;
+	gint j;
+	
+	/* cast it back to an integer */
+	server_num = (int) serv_num;
+	
+#ifdef VERBOSE    
+	g_printf("callback called!\n");
+#endif
+	/* read ip from server.  It's done as a single int rather than a string.
+	 * hopefully it works ok */
+	if ( (read(dns_server[server_num].pipefd[0], &ip_addr, sizeof(guint32))) < 0)
+		g_error("reading from pipe: %s\n", g_strerror(errno));
+	
+#ifdef VERBOSE
+	g_printf("ip_addr in callback is %x\n", ip_addr);
+#endif
+	
+	/* write ip address into cache. */
+	for (i = 0; i < dns_cache_size; i++)
+		if (dns_cache[i].server == server_num)
+			break;
+	if (i < dns_cache_size) {
+		dns_cache[i].ip_addr = ip_addr;
+		dns_cache[i].server = -1;
+	} else {
+		g_warning ("gnome_dns_callback: no cache item for server\n");
+	}
+	
+	/* Give answer to all callbacks. */
+	for (i = 0; i < dns_con_size; i++) {
+		if (dns_con[i].server == server_num) {
+			dns_con[i].callback (ip_addr, dns_con[i].callback_data);
+			g_free (dns_con[i].hostname);
+			dns_con[i--] = dns_con[--dns_con_size];
+		}
+	}
+	
+	dns_server[server_num].in_use = FALSE;
+	
+	/* See if there's an outstanding request and, if so, serve it. */
+	for (i = 0; i < dns_cache_size; i++) {
+		if (dns_cache[i].server == -2) {
+			dns_cache[i].server = server_num;
+			for (j = 0; j < dns_con_size; j++) {
+				if (!strcmp (dns_con[j].hostname, dns_cache[i].hostname))
+					dns_con[j].server = server_num;
+			}
+			gnome_dns_server_req (server_num, dns_cache[i].hostname);
+			break;
+		}
+	}
+}
+
+
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_create_server
+ *
+ * internal function - creates a new server (currently using fork()).
+ *
+ * Arguments:
+ *   
+ * Results:
+ * initializes the first free dns_server structure and returns
+ * the index into the dns_server structure which is 
+ * also the tag.  Returns -1 on error.
+ *
+ * Side effects:
+ * 
+ *--------------------------------------------------------------
+ */
+
+gint gnome_dns_create_server(void)
+{
+	
+	int pid;
+	int index = 0;
+	
+	
+	/* for talking to dns server.  Once setup, always write to pipefd[1],
+	 * and read from pipefd[0]. */
+	int pipefd[2];
+	int pipefd0[2];
+	int pipefd1[2];
+	
+	/* check that we're not spawning too many servers.. this should really
+	 * only be a sanity check..  I'm hoping that we'll never really spawn
+	 * anywhere near the max allowed servers. */
+	if (num_servers >= GNOME_DNS_MAX_SERVERS) {
+		fprintf(stderr, "gnome: spawned too many dns processes - limit set to %d.\n", 
+			GNOME_DNS_MAX_SERVERS);
+		return(-1);
+	}
+	
+	/* create pipe to write to dns_server with */
+	if ( (pipe(pipefd0)) < 0) {
+		fprintf(stderr, "gnome: creating pipe: %s\n", strerror(errno));
+		return(-1);
+	}
+	
+	/* create pipe to read from dns_server */
+	if ( (pipe(pipefd1)) < 0) {
+		fprintf(stderr, "gnome: creating pipe: %s\n", strerror(errno));
+		return(-1);
+	}
+	
+	pid = fork();
+	if (pid < 0) {
+		fprintf(stderr, "gnome: forking: %s\n", strerror(errno));
+		return(-1);
+	}
+	
+	/* start server in child */
+	if (pid == 0) {
+		pipefd[0] = pipefd0[0];
+		pipefd[1] = pipefd1[1];
+		gnome_dns_server(pipefd);
+		/* does not return */
+	}
+	
+	index = num_servers;
+	
+	/* initialize structure */
+	
+	dns_server[index].in_use = FALSE;
+	dns_server[index].pipefd[1] = pipefd0[1];
+	dns_server[index].pipefd[0] = pipefd1[0];
+	close(pipefd0[0]);
+	close(pipefd1[1]);
+	/* only used as a sanity check to gnome_dns_abort() */
+	num_servers++;
+	
+	return(index);
+}
+
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_server
+ *
+ * internal function - this is the actual server process.  
+ * Called from gnome_dns_server_create().
+ *
+ *
+ * Arguments:
+ * 
+ * pipefd[2] - an open set of pipes - 0 for writing, 1 for
+ * reading.
+ * 
+ * Results:
+ * sets up a server listening for char *hostnames on pipefd[0], 
+ * and writing results of dns lookups as guints into pipefd[1].
+ *
+ * Side effects:
+ * 
+ *--------------------------------------------------------------
+ */
+
+
+void gnome_dns_server(gint pipefd[2])
+{
+	char hostname[4096];
+	gint nread;
+	struct hostent *host;
+	gint fd;
+	gint max_fd;
+	guint32 ip_addr;
+	
+	
+	/* todo: just close the pipe fd's */
+	/* close all file descriptors except ones used by the pipes. */
+	/* FIXME! getdtablesize is probably not a terribly portable call. */
+	max_fd = getdtablesize();
+	for(fd = 0; fd < max_fd; fd++)
+		if ( (fd != pipefd[0]) && (fd != pipefd[1]) && (fd !=1) && (fd != 2) )
+			close(fd);
+	
+#ifdef VERBOSE
+	g_print ("gnome_dns_server: started\n");
+#endif
+	while(1) {
+		/* block on read from client */
+		nread = read(pipefd[0], hostname, 4096);
+		
+		/* will return 0 if parent exits. */
+		/* where are those errors coming from anyway ?? 
+		 *  "** ERROR **: an x io error occurred" */
+		if (nread == 0) {
+#ifdef VERBOSE
+			g_print("---> dns_server - returned 0 - Exiting.\n");
+#endif
+			exit(0);
+		}
+		
+		if (nread < 0) {
+			g_error("gnome_dns_server: reading from pipe: %s\n", g_strerror(errno));
+		}
+		
+#ifdef VERBOSE
+		g_print("---> dns_server - looking up >%s<\n", hostname);
+#endif
+		
+		host = gethostbyname(hostname);
+		
+		if (host == NULL) {
+#ifdef VERBOSE
+			g_printf("---> dns_server - NULL return\n");
+#endif
+			ip_addr = 0;
+		} else {
+#ifdef VERBOSE
+			g_printf("---> dns_server - good return\n");
+#endif
+			memcpy(&ip_addr, host->h_addr_list[0], sizeof(ip_addr));
+			ip_addr = ntohl(ip_addr);
+		}
+		
+#ifdef VERBOSE
+		g_printf("gnome_dns_server: ip of %s is %x\n", hostname, ip_addr);
+#endif
+		/* write hostname to client */
+		if ( (write(pipefd[1], &ip_addr, sizeof(ip_addr))) < 0)
+			g_error("gnome_dns_server: writing to pipe: %s\n", g_strerror(errno));
+	}
+}
diff --git a/libgnome/gnome-dns.h b/libgnome/gnome-dns.h
new file mode 100644
index 0000000..36e3072
--- /dev/null
+++ b/libgnome/gnome-dns.h
@@ -0,0 +1,80 @@
+#ifndef __GNOME_DNS_H__
+#define __GNOME_DNS_H__
+
+BEGIN_GNOME_DECLS
+
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_init
+ *
+ *   Initialize the dns functions for use.
+ *
+ * Arguments:
+ *   server_count specifies the number of servers to fork() at
+ *   init, or <= 0 to do dynamic server forking.  If you are
+ *   concerned about virtual mem usage, fork your servers as one of the
+ *   first things in your program.
+ * 
+ *   Note that it will still do dynamic forking if you specify > 0. 
+ *   when it runs out of servers.. a good init value may be 1 or 2.
+ * 
+ * Results:
+ *   gnome_dns_lookup() will be ready for use.
+ *
+ * Side effects:
+ *   The library is initialized.
+ *
+ *--------------------------------------------------------------
+ */
+void gnome_dns_init (gint server_count);
+
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_lookup
+ *
+ * looks up an address and returns a tag for use with
+ * gnome_dns_abort() if desired.  May not return -1 if
+ * hostname was in cache.
+ *
+ * Arguments:
+ * char *hostname - hostname to lookup
+ * callback - function to call when dns lookup is complete.
+ * callback_data - data to pass to this function.
+ *   
+ * Results:
+ * callback function is called when dns_lookup is complete.
+ * returns a tag identifying this lookup or -1 if lookup was
+ * in cache.
+ * 
+ * Side effects:
+ * a new dns server may be spawned if all the current servers
+ * are in use.
+ *
+ *--------------------------------------------------------------
+ */
+
+guint32 gnome_dns_lookup (const char *hostname,
+			   void (* callback) (guint32 ip_addr, void *callback_data),
+			   void *callback_data);
+	
+/*
+ *--------------------------------------------------------------
+ * gnome_dns_abort
+ *
+ * aborts a previous call to gnome_dns_lookup().
+ *
+ * Arguments:
+ * gint tag32 - the tag returned from previous call to gnome_dns_lookup().
+ *   
+ * Results:
+ *   callback function is not called.
+ *
+ * Side effects:
+ * 
+ *--------------------------------------------------------------
+ */
+void gnome_dns_abort (guint32 tag);
+
+END_GNOME_DECLS
+
+#endif /* __GNOME_DNS_H__ */
diff --git a/libgnome/gnome-hook.c b/libgnome/gnome-hook.c
new file mode 100644
index 0000000..25149e9
--- /dev/null
+++ b/libgnome/gnome-hook.c
@@ -0,0 +1,85 @@
+/*
+ * Hook management routines.
+ * Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
+ * Written 1994, 1995, 1996 by:
+ * Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
+ * Jakub Jelinek
+ */
+#include <config.h>
+#include <glib.h>
+#include "gnome-defs.h"
+#include "gnome-hook.h"
+
+void
+gnome_add_hook (GnomeHook **hook_list, GnomeHookFunc func, void *data)
+{
+	GnomeHook *new_hook = g_malloc (sizeof (GnomeHook));
+	
+	new_hook->hook_fn   = func;
+	new_hook->hook_data = data;
+	new_hook->next      = *hook_list;
+	
+	*hook_list = new_hook;
+}
+
+void
+gnome_execute_hooks (GnomeHook *hook_list)
+{
+	GnomeHook *new_hook = NULL;
+	GnomeHook *p;
+	
+	/* 
+	 * We copy the hook list first so tahat we let the hook
+	 * function call delete_hook
+	 */
+	
+	while (hook_list) {
+		gnome_add_hook (&new_hook, hook_list->hook_fn, hook_list->hook_data);
+		hook_list = hook_list->next;
+	}
+	
+	p = new_hook;
+	
+	while (new_hook) {
+		(*new_hook->hook_fn) (new_hook->hook_data);
+		new_hook = new_hook->next;
+	}
+	
+	for (hook_list = p; hook_list;) {
+		p = hook_list;
+		hook_list = hook_list->next;
+		g_free (p);
+	}
+}
+
+
+void
+gnome_delete_hook (GnomeHook **hook_list, GnomeHookFunc func)
+{
+	GnomeHook *current, *new_list, *next;
+	
+	new_list = NULL;
+	
+	for (current = *hook_list; current; current = next) {
+		next = current->next;
+		
+		if (current->hook_fn == func)
+			g_free (current);
+		else
+			gnome_add_hook (&new_list, current->hook_fn, current->hook_data);
+	}
+	
+	*hook_list = new_list;
+}
+
+int
+gnome_hook_present (GnomeHook *hook_list, GnomeHookFunc func)
+{
+	GnomeHook *p;
+	
+	for (p = hook_list; p; p = p->next)
+		if (p->hook_fn == func)
+			return TRUE;
+
+	return FALSE;
+}
diff --git a/libgnome/gnome-hook.h b/libgnome/gnome-hook.h
new file mode 100644
index 0000000..a49941d
--- /dev/null
+++ b/libgnome/gnome-hook.h
@@ -0,0 +1,22 @@
+#ifndef GNOME_HOOK_H
+#define GNOME_HOOK_H
+
+BEGIN_GNOME_DECLS
+
+typedef void (*GnomeHookFunc)(void *);
+
+typedef struct GnomeHook {
+	GnomeHookFunc    hook_fn;
+	void             *hook_data;
+	struct GnomeHook *next;
+} GnomeHook;
+
+
+void gnome_add_hook (GnomeHook **hook_list, GnomeHookFunc func, void *data);
+void gnome_execute_hooks (GnomeHook *hook_list);
+void gnome_delete_hook   (GnomeHook **hook_list, GnomeHookFunc func);
+int  gnome_hook_present  (GnomeHook *hook_list, GnomeHookFunc func);
+
+END_GNOME_DECLS
+
+#endif
diff --git a/libgnome/gnome-i18n.h b/libgnome/gnome-i18n.h
new file mode 100644
index 0000000..c11cdd1
--- /dev/null
+++ b/libgnome/gnome-i18n.h
@@ -0,0 +1,33 @@
+/*
+ * Handles all of the internationalization configuration options.
+ * Author: Tom Tromey <tromey creche cygnus com>
+ */
+
+#ifndef __GNOME_I18N_H__
+#define __GNOME_I18N_H__
+
+BEGIN_GNOME_DECLS
+
+#ifdef HAVE_LIBINTL_H
+#    include <libintl.h>
+#    define _(String) gettext (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
+
+END_GNOME_DECLS
+
+#endif __GNOME_UTIL_H__
+
diff --git a/libgnome/gnome-init.c b/libgnome/gnome-init.c
new file mode 100644
index 0000000..3010e76
--- /dev/null
+++ b/libgnome/gnome-init.c
@@ -0,0 +1,36 @@
+#include <config.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include "gnome-defs.h"
+#include "gnome-util.h"
+
+#ifdef HAVE_LIBINTL
+#include "libintl.h"
+#endif
+
+char *gnome_user_home_dir = 0;
+char *gnome_user_dir = 0;
+
+void
+gnomelib_init (int *argc, char ***argv)
+{
+	gnome_user_home_dir = getenv ("HOME");
+	gnome_user_dir = g_concat_dir_and_file (gnome_user_home_dir, ".gnome");
+	mkdir (gnome_user_dir, 0755);
+
+	setlocale (LC_ALL, "");
+#ifdef HAVE_LIBINTL
+	bindtextdomain (PACKAGE, GNOMELOCALEDIR);
+#endif
+}
+
+
+
diff --git a/libgnome/gnome-mime.c b/libgnome/gnome-mime.c
new file mode 100644
index 0000000..2208922
--- /dev/null
+++ b/libgnome/gnome-mime.c
@@ -0,0 +1,273 @@
+/* 
+ * Copyright 1997 Paolo Molaro 
+ *  This is LGPL'ed code.
+ */
+#include "gnome.h"
+#include "gnome-mime.h"
+#include <string.h>
+#include <ctype.h>
+
+static void mime_fill_from_file (gchar * filename);
+static void mcap_fill_from_file (gchar * filename);
+
+static GHashTable *mime_hash = NULL;
+static GHashTable *mcap_hash = NULL;
+
+static void
+mime_fill_from_file (gchar * filename)
+{
+	FILE *f;
+	gchar buf[1024];
+	gchar *p, *s, *mtype;
+	gint used;
+	const gchar *blancks = " \t\n\r";
+	
+	if (!(f = fopen (filename, "r")))
+		return;
+	
+	while (fgets (buf, 1024, f)) {
+		p = buf;
+		while (*p && isspace (*p))
+			++p;
+		if (!*p || *p == '#')
+			continue;
+		used = 0;
+		s = g_strdup (p);
+		mtype = strtok (s, blancks);
+		while ((p = strtok (NULL, blancks))) {
+			g_hash_table_insert (mime_hash, p, mtype);
+			used = 1;
+		}
+		if (!used)
+			g_free (s);
+	}
+	fclose (f);
+}
+
+gchar *
+gnome_mime_type (gchar * filename)
+{
+	gchar *ext;
+	gchar *result;
+	gchar *defaultv = "text/plain";	/* maybe NULL? */
+
+	if (!filename)
+		return defaultv;
+	ext = strrchr (filename, '.');
+	if (!ext)
+		ext = filename;
+	else
+		++ext;
+
+	if (!mime_hash) {
+		gchar *f;
+		mime_hash = g_hash_table_new ((GHashFunc) g_string_hash, (GCompareFunc) g_string_equal);
+		mime_fill_from_file ("/etc/mime.types");
+		f = gnome_util_prepend_user_home (".mime.types");
+		if (f) {
+			mime_fill_from_file (f);
+			g_free (f);
+		}
+	}
+	result = g_hash_table_lookup (mime_hash, ext);
+	if (!result) {
+		gchar *s = alloca (strlen (ext) + 1);
+		gchar *p = s;
+		while (*ext) {
+			*p++ = tolower (*ext);
+			++ext;
+		}
+		*p = 0;
+		result = g_hash_table_lookup (mime_hash, s);
+		if (!result)
+			return defaultv;
+	}
+	return result;
+}
+
+static void
+mcap_fill_from_file (gchar * filename)
+{
+	FILE *f;
+	gchar buf[1024];
+	gchar *p, *s, *mtype;
+	GList *list;
+	GnomeMailCap *mcap;
+	const gchar *blancks = ";";
+
+	if (!(f = fopen (filename, "r")))
+		return;
+	while (fgets (buf, 1024, f)) {
+		p = buf;
+		while (*p && isspace (*p))
+			++p;
+		if (!*p || *p == '#')
+			continue;
+		s = g_strdup (p);
+		mtype = strtok (s, blancks);
+		list = g_hash_table_lookup (mcap_hash, mtype);
+
+		mcap = g_new (GnomeMailCap, 1);
+		mcap->program = NULL;
+		mcap->description = NULL;
+		mcap->nametemplate = NULL;
+		mcap->test = NULL;
+		mcap->composetyped = NULL;
+		mcap->copiousoutput = 0;
+		mcap->needsterminal = 0;
+
+		list = g_list_append (list, mcap);
+		g_hash_table_insert (mcap_hash, mtype, list);
+
+		p = strtok (NULL, blancks);
+		while (*p && isspace (*p))
+			++p;
+		mcap->program = p;
+
+		while ((p = strtok (NULL, blancks))) {
+			while (*p && isspace (*p))
+				++p;
+			/* printf("parsing: %s\n", p); */
+			if (!strncmp ("test=", p, 5))
+				mcap->test = p + 5;
+			else if (!strncmp ("description=", p, 12))
+				mcap->description = p + 12;
+			else if (!strncmp ("nametemplate=", p, 13))
+				mcap->nametemplate = p + 13;
+			else if (!strncmp ("composetyped=", p, 13))
+				mcap->composetyped = p + 13;
+			else if (!strncmp ("copiousoutput", p, 13))
+				mcap->copiousoutput = 1;
+			else if (!strncmp ("needsterminal", p, 13))
+				mcap->needsterminal = 1;
+		}
+	}
+	fclose (f);
+}
+
+GList *
+gnome_mime_entries (gchar * mime_type)
+{
+
+	if (!mcap_hash) {
+		gchar *f;
+		mcap_hash = g_hash_table_new ((GHashFunc) g_string_hash, (GCompareFunc) g_string_equal);
+		f = gnome_util_prepend_user_home (".mailcap");
+		if (f) {
+			mcap_fill_from_file (f);
+			g_free (f);
+		}
+		mcap_fill_from_file ("/etc/mailcap");
+	}
+	return g_hash_table_lookup (mcap_hash, mime_type);
+}
+
+GnomeMailCap *
+gnome_mime_default_entry (gchar * mime_type)
+{
+	GList *list;
+	list = gnome_mime_entries (mime_type);
+	if (list)
+		return (GnomeMailCap *) list->data;
+	return NULL;
+}
+
+gchar *
+gnome_mime_program (gchar * mime_type)
+{
+	GnomeMailCap *mcap;
+
+	mcap = gnome_mime_default_entry (mime_type);
+	if (mcap)
+		return mcap->program;
+	return NULL;
+}
+
+gchar *
+gnome_mime_description (gchar * mime_type)
+{
+	GnomeMailCap *mcap;
+
+	mcap = gnome_mime_default_entry (mime_type);
+	if (mcap)
+		return mcap->description;
+	return NULL;
+}
+
+gchar *
+gnome_mime_nametemplate (gchar * mime_type)
+{
+	GnomeMailCap *mcap;
+
+	mcap = gnome_mime_default_entry (mime_type);
+	if (mcap)
+		return mcap->nametemplate;
+	return NULL;
+}
+
+gchar *
+gnome_mime_test (gchar * mime_type)
+{
+	GnomeMailCap *mcap;
+
+	mcap = gnome_mime_default_entry (mime_type);
+	if (mcap)
+		return mcap->test;
+	return NULL;
+}
+
+gchar *
+gnome_mime_composetyped (gchar * mime_type)
+{
+	GnomeMailCap *mcap;
+
+	mcap = gnome_mime_default_entry (mime_type);
+	if (mcap)
+		return mcap->composetyped;
+	return NULL;
+}
+
+gint
+gnome_mime_copiousoutput (gchar * mime_type)
+{
+	GnomeMailCap *mcap;
+
+	mcap = gnome_mime_default_entry (mime_type);
+	if (mcap)
+		return mcap->copiousoutput;
+	return 0;
+}
+
+gint
+gnome_mime_needsterminal (gchar * mime_type)
+{
+	GnomeMailCap *mcap;
+
+	mcap = gnome_mime_default_entry (mime_type);
+	if (mcap)
+		return mcap->needsterminal;
+	return 0;
+}
+
+#ifdef MIMETEST
+
+int main (int argc, char *argv[])
+{
+	gint i;
+	gchar *mtype;
+	gchar *program;
+	gchar *desc;
+
+	gnome_mime_init ();
+
+	for (i = 1; i < argc; ++i) {
+		mtype = gnome_mime_type (argv[i]);
+		printf ("%-24s\t%s\n", mtype ? mtype : "", argv[i]);
+		program = gnome_mime_program (mtype);
+		desc = gnome_mime_description (mtype);
+		printf ("Program: %s\nDescription: %s\n", program, desc);
+	}
+	return 0;
+}
+
+#endif
diff --git a/libgnome/gnome-mime.h b/libgnome/gnome-mime.h
new file mode 100644
index 0000000..cf7825b
--- /dev/null
+++ b/libgnome/gnome-mime.h
@@ -0,0 +1,34 @@
+#ifndef __GNOME_MIME_H__
+#define __GNOME_MIME_H__
+
+BEGIN_GNOME_DECLS
+
+typedef struct {
+        gchar* program;
+        gchar* description;
+        gchar* nametemplate;
+        gchar* test;
+        gchar* composetyped;
+        gint copiousoutput;
+        gint needsterminal;
+        /* where are the specs for the mailcap format? */
+} GnomeMailCap;
+
+void          gnome_mime_init          (void);
+
+/* do not free() any of the returned values */
+gchar*        gnome_mime_type          (gchar* filename);
+GnomeMailCap* gnome_mime_default_entry (gchar* mime_type);
+GList*        gnome_mime_entries       (gchar* mime_type);
+gchar*        gnome_mime_program       (gchar* mime_type);
+gchar*        gnome_mime_description   (gchar* mime_type);
+gchar*        gnome_mime_nametemplate  (gchar* mime_type);
+gchar*        gnome_mime_test          (gchar* mime_type);
+gchar*        gnome_mime_composetyped  (gchar* mime_type);
+gint          gnome_mime_copiousoutput (gchar* mime_type);
+gint          gnome_mime_needsterminal (gchar* mime_type);
+
+END_GNOME_DECLS
+
+#endif
+
diff --git a/libgnome/gnome-string.c b/libgnome/gnome-string.c
new file mode 100644
index 0000000..4452f30
--- /dev/null
+++ b/libgnome/gnome-string.c
@@ -0,0 +1,92 @@
+#include "gnome-string.h"
+#include <string.h>
+
+#include <glib.h>
+#include <string.h>
+#include <limits.h>
+
+gchar **gnome_split_string(gchar *string, gchar *delim, gint max_tokens)
+{
+	gchar **retval = NULL;
+	GList *items = NULL, *anode;
+	gint numitems = 0, dlen, i;
+	gchar *src, *cur, *nxt;
+
+	g_return_val_if_fail(string != NULL, NULL);
+	g_return_val_if_fail(delim != NULL, NULL);
+
+	if(max_tokens < 0)
+		max_tokens = INT_MAX;
+
+	dlen = strlen(delim);
+	nxt = strstr(string, delim);
+	if(!nxt) {
+		retval = g_malloc(sizeof(gchar *) * 2);
+		retval[0] = g_strdup(string);
+		retval[1] = NULL;
+		return retval;
+	}
+	src = cur = g_strdup(string);
+	nxt = strstr(src, delim);
+	
+	while(nxt && numitems < (max_tokens - 1)) {
+		*nxt = '\0';
+		items = g_list_append(items, g_strdup(cur));
+		cur = nxt + dlen;
+		nxt = strstr(cur, delim);
+		numitems++;
+	}
+	/* We have to take the rest of the string and put it as last token */
+	if(*cur) {
+		items = g_list_append(items, g_strdup(cur));
+		numitems++;
+	}
+	g_free(src);
+
+	retval = g_malloc(sizeof(gchar *) * (numitems + 1));
+	for(anode = items, i = 0; anode; anode = anode->next, i++)
+		retval[i] = anode->data;
+	retval[i] = NULL;
+	g_list_free(items);
+
+	return retval;
+}
+
+gchar *
+gnome_join_strings(gchar *separator, ...)
+{
+	va_list l;
+	va_start(l, separator);
+	/* Elliot: this can not be done like this: */
+	/*	return gnome_join_vstrings(separator, l);*/
+}
+
+gchar *
+gnome_join_vstrings(gchar *separator, gchar **strings)
+{
+	gchar *retval;
+	gint total_size, i, seplen;
+
+	g_return_val_if_fail(separator != NULL, NULL);
+	g_return_val_if_fail(strings != NULL, NULL);
+
+	/* While it's not an error to have no strings to join, it
+	   still needs to be handled differently */
+	if(!strings[0])
+		return g_strdup("");
+
+	total_size = strlen(strings[0]) + 1;
+	retval = g_malloc(total_size);
+	strcpy(retval, strings[0]);
+	seplen = strlen(separator);
+
+	for(i = 1; strings[i]; i++)
+	{
+		total_size += seplen + strlen(strings[i]);
+		retval = g_realloc(retval, total_size);
+		strcat(retval, separator);
+		strcat(retval, strings[i]);
+	}
+
+	return retval;
+}
diff --git a/libgnome/gnome-string.h b/libgnome/gnome-string.h
new file mode 100644
index 0000000..62ee2c7
--- /dev/null
+++ b/libgnome/gnome-string.h
@@ -0,0 +1,10 @@
+#include "gnome-defs.h"
+#include <glib.h>
+#include <stdarg.h>
+
+gchar **gnome_split_string  (gchar *string,
+			     gchar *delim,
+			     gint max_tokens);
+gchar * gnome_join_strings  (gchar *separator, ...);
+gchar * gnome_join_vstrings (gchar *separator,
+			     gchar **strings);
diff --git a/libgnome/gnome-triggers.c b/libgnome/gnome-triggers.c
new file mode 100644
index 0000000..6c1f358
--- /dev/null
+++ b/libgnome/gnome-triggers.c
@@ -0,0 +1,362 @@
+/* By Elliot Lee */
+
+#include "gnome-triggers.h"
+#include "gnome-util.h"
+#include "gnome-string.h"
+#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>
+
+/* TYPE DECLARATIONS */
+
+typedef struct _TriggerList * TriggerList;
+
+struct _TriggerList {
+  char *nodename;
+  TriggerList *subtrees;
+  gint numsubtrees;
+  GnomeTrigger *actions;
+  gint numactions;
+};
+
+typedef void (*GnomeTriggerTypeFunction)(GnomeTrigger t, char *msg, char *level, char *supinfo[]);
+
+/* PROTOTYPES */
+static GnomeTrigger
+gnome_trigger_dup(GnomeTrigger dupme);
+static TriggerList
+gnome_triggerlist_new(char *nodename);
+static void
+gnome_triggerlist_free(TriggerList t);
+static void
+gnome_trigger_free(GnomeTrigger t);
+static void
+gnome_trigger_do(GnomeTrigger t, char *msg, char *level, char *supinfo[]);
+static void
+gnome_trigger_do_function(GnomeTrigger t,
+			  char *msg, char *level, char *supinfo[]);
+static void
+gnome_trigger_do_command(GnomeTrigger t,
+			 char *msg, char *level, char *supinfo[]);
+
+/* FILEWIDE VARIABLES */
+
+static TriggerList topnode = NULL;
+
+static GnomeTriggerTypeFunction actiontypes[] =
+/* This list should have entries for all the trigger types in
+   gnome-triggers.h */
+{
+  (GnomeTriggerTypeFunction)NULL,
+  gnome_trigger_do_function,
+  gnome_trigger_do_command,
+  (GnomeTriggerTypeFunction)NULL,
+  (GnomeTriggerTypeFunction)NULL
+};
+
+/* IMPLEMENTATIONS */
+void
+gnome_triggers_init(void)
+{
+  char *fn;
+  fn = gnome_datadir_file("gnome/triggers/list");
+  if(fn) {
+    gnome_triggers_readfile(fn);
+    g_free(fn);
+  }
+
+  fn = gnome_util_prepend_user_home(".gnome/triggers/list");
+  if(fn) {
+    gnome_triggers_readfile(fn);
+    g_free(fn);
+  }
+}
+
+gint
+gnome_triggers_readfile(gchar *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 = gnome_split_string(aline, " ", -1);
+    if(!parts || !parts[0] || !parts[1] || !parts[2] || !parts[3]) {
+      if(parts) {
+	for(i = 0; parts[i]; i++)
+	  g_free(parts[i]);
+	g_free(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 = gnome_split_string(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);
+
+    for(i = 0; subnames[i]; i++)
+      g_free(subnames[i]);
+    g_free(subnames); subnames = NULL;
+
+    for(i = 0; parts[i]; i++)
+      g_free(parts[i]);
+    g_free(parts); parts = NULL;
+  }
+  g_free(nt);
+
+  return 0;
+}
+
+void gnome_triggers_add_trigger(GnomeTrigger nt, ...)
+{
+  va_list l;
+  va_start(l, nt);
+  /*  gnome_triggers_vadd_trigger(nt, l);*/
+}
+
+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 TriggerList
+gnome_triggerlist_new(char *nodename)
+{
+  TriggerList retval;
+  retval = g_malloc0(sizeof(struct _TriggerList));
+  retval->nodename = g_strdup(nodename);
+  return retval;
+}
+
+void gnome_triggers_vadd_trigger(GnomeTrigger nt,
+				 char *supinfo[])
+{
+  g_return_if_fail(nt != NULL);
+  if(!topnode)
+    topnode = gnome_triggerlist_new(NULL);
+
+  if(supinfo == NULL || supinfo[0] == NULL) {
+    topnode->actions = g_realloc(topnode->actions, ++topnode->numactions);
+    topnode->actions[topnode->numactions - 1] = gnome_trigger_dup(nt);
+  } else {
+    int i, j;
+    TriggerList curnode;
+
+    for(i = 0, curnode = 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(TriggerList));
+	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 */
+}
+
+void
+gnome_triggers_do(char *msg, char *level, ...)
+{
+  va_list l;
+  va_start(l, level);
+  /*  gnome_triggers_vdo(msg, level, l);*/
+}
+
+void
+gnome_triggers_vdo(char *msg, char *level, char *supinfo[])
+{
+  TriggerList curnode = topnode;
+  int i, j;
+
+  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);
+	}
+    }
+}
+
+void
+gnome_triggers_destroy(void)
+{
+  g_return_if_fail(topnode != NULL);
+  gnome_triggerlist_free(topnode);
+  topnode = NULL;
+}
+
+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.mediafile); break;
+  default:
+    break;
+  }
+  g_free(t);
+}
+
+static void
+gnome_triggerlist_free(TriggerList 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, char *msg, char * level, char *supinfo[])
+{
+  g_return_if_fail(t != NULL);
+
+  actiontypes[t->type](t, msg, level, supinfo);
+}
+
+static void
+gnome_trigger_do_function(GnomeTrigger t,
+			  char *msg, char *level, char *supinfo[])
+{
+  t->u.function(msg, level, supinfo);
+}
+
+static void
+gnome_trigger_do_command(GnomeTrigger t, char *msg, char *level, char *supinfo[])
+{
+  char **argv;
+  int nsupinfos, i;
+
+  for(nsupinfos = 0; supinfo[nsupinfos]; nsupinfos++);
+
+  argv = g_malloc(sizeof(char *) * (nsupinfos + 4));
+  argv[0] = t->u.command;
+  argv[1] = msg;
+  argv[2] = level;
+
+  for(i = 0; supinfo[i]; i++) {
+    argv[i + 3] = 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);
+}
diff --git a/libgnome/gnome-triggers.h b/libgnome/gnome-triggers.h
new file mode 100644
index 0000000..284667c
--- /dev/null
+++ b/libgnome/gnome-triggers.h
@@ -0,0 +1,49 @@
+#ifndef __GNOME_TRIGGERS_H__
+#define __GNOME_TRIGGERS_H__
+
+#include "gnome-defs.h"
+#include <glib.h>
+BEGIN_GNOME_DECLS
+
+enum _GnomeTriggerType { GTRIG_NONE, GTRIG_FUNCTION, GTRIG_COMMAND, GTRIG_MEDIAPLAY };
+typedef enum _GnomeTriggerType 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;
+	  gchar *mediafile;
+	} u;
+        gchar *level;
+};
+typedef struct _GnomeTrigger * GnomeTrigger;
+
+/* Must be called before doing any triggers stuff */
+void gnome_triggers_init(void);
+gint gnome_triggers_readfile(gchar *filename);
+
+/* 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(char *msg, char *level, ...);
+
+void gnome_triggers_vdo(char *msg, char *level, char *supinfo[]);
+
+void gnome_triggers_destroy(void);
+
+END_GNOME_DECLS
+
+#endif /* __GNOME_TRIGGERS_H__ */
diff --git a/libgnome/gnome-util.c b/libgnome/gnome-util.c
new file mode 100644
index 0000000..b2476ce
--- /dev/null
+++ b/libgnome/gnome-util.c
@@ -0,0 +1,231 @@
+#include <config.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+#include <sys/stat.h>
+#include "gnome-defs.h"
+#include "gnome-util.h"
+
+static char *
+gnome_dirrelative_file (char *base, char *sub, char *filename, int unconditional)
+{
+        static char *gnomedir = NULL;
+	char *f, *t, *u;
+	
+	/* First try the env GNOMEDIR relative path */
+	if (!gnomedir)
+		gnomedir = getenv ("GNOMEDIR");
+	
+	if (gnomedir){
+		t = g_concat_dir_and_file (gnomedir, sub);
+		u = g_copy_strings (t, "/", filename, NULL);
+		g_free (t);
+		
+		if (g_file_exists (u) || unconditional)
+			return u;
+		
+		g_free (u);
+	}
+	
+	/* Then try the hardcoded path */
+	f = g_concat_dir_and_file (base, filename);
+	
+	if (g_file_exists (f) || unconditional)
+		return f;
+	
+	g_free (f);
+	
+	/* Finally, attempt to find it in the current directory */
+	f = g_concat_dir_and_file (".", filename);
+	
+	if (g_file_exists (f))
+		return f;
+	
+	g_free (f);
+	return NULL;
+}
+
+/* DOC: gnome_libdir_file (char *filename)
+ * Returns a newly allocated pathname pointing to a file in the gnome libdir
+ */
+char *
+gnome_libdir_file (char *filename)
+{
+	return (gnome_dirrelative_file (GNOMELIBDIR, "lib", filename, FALSE));
+}
+
+/* DOC: gnome_sharedir_file (char *filename)
+ * Returns a newly allocated pathname pointing to a file in the gnome sharedir
+ */
+char *
+gnome_datadir_file (char *filename)
+{
+	return (gnome_dirrelative_file (GNOMEDATADIR, "share", filename, FALSE));
+}
+
+char *
+gnome_pixmap_file (char *filename)
+{
+	return (gnome_dirrelative_file (GNOMEDATADIR "/pixmaps", "share/pixmaps", filename, FALSE));
+}
+
+char *
+gnome_unconditional_pixmap_file (char *filename)
+{
+	return (gnome_dirrelative_file (GNOMEDATADIR "/pixmaps", "share/pixmaps", filename, TRUE));
+}
+
+/* DOC: gnome_unconditional_libdir_file (char *filename)
+ * Returns a newly allocated pathname pointing to a (possibly
+ * non-existent) file in the gnome libdir
+ */
+char *
+gnome_unconditional_libdir_file (char *filename)
+{
+	return (gnome_dirrelative_file (GNOMELIBDIR, "lib", filename, TRUE));
+}
+
+/* DOC: gnome_unconditional_datadir_file (char *filename)
+ * Returns a newly allocated pathname pointing to a (possibly
+ * non-existent) file in the gnome libdir
+ */
+char *
+gnome_unconditional_datadir_file (char *filename)
+{
+	return (gnome_dirrelative_file (GNOMEDATADIR, "share", filename, TRUE));
+}
+
+/* DOC: g_file_exists (char *filename)
+ * Returns true if filename exists
+ */
+int
+g_file_exists (char *filename)
+{
+	struct stat s;
+	
+	return stat (filename, &s) == 0;
+}
+
+
+/* DOC: g_copy_strings (const char *first,...)
+ * returns a new allocated char * with the concatenation of its arguments
+ */
+char *
+g_copy_strings (const char *first, ...)
+{
+	va_list ap;
+	int len;
+	char *data, *result;
+	
+	if (!first)
+		return NULL;
+	
+	len = strlen (first);
+	va_start (ap, first);
+	
+	while ((data = va_arg (ap, char *)) != NULL)
+		len += strlen (data);
+	
+	len++;
+	
+	result = (char *) g_malloc (len);
+	va_end (ap);
+	va_start (ap, first);
+	strcpy (result, first);
+	while ((data = va_arg (ap, char *)) != NULL)
+		strcat (result, data);
+	va_end (ap);
+	
+	return result;
+}
+
+
+/* DOC: g_unix_error_string (int error_num)
+ * Returns a pointer to a static location with a description of the errno
+ */
+char *
+g_unix_error_string (int error_num)
+{
+	static char buffer [256];
+	char *error_msg;
+	
+#ifdef HAVE_STRERROR
+	error_msg = strerror (error_num);
+#else
+	extern int sys_nerr;
+	extern char *sys_errlist [];
+	if ((0 <= error_num) && (error_num < sys_nerr))
+		error_msg = sys_errlist[error_num];
+	else
+		error_msg = "strange errno";
+#endif /* HAVE_STRERROR */
+	sprintf (buffer, "%s (%d)", error_msg, error_num);
+	return buffer;
+}
+
+
+/* DOC: g_concat_dir_and_file (const char *dir, const char *file)
+ * returns a new allocated string that is the concatenation of dir and file,
+ * takes care of the exact details for concatenating them.
+ */
+char *
+g_concat_dir_and_file (const char *dir, const char *file)
+{
+	int l = strlen (dir);
+	
+	if (dir [l - 1] == PATH_SEP)
+		return g_copy_strings (dir, file, NULL);
+	else
+		return g_copy_strings (dir, PATH_SEP_STR, file, NULL);
+}
+
+
+/* returns the home directory of the user
+ * This one is NOT to be free'd as it points into the 
+ * env structure.
+ * 
+ */
+
+char *
+gnome_util_user_home(void)
+{
+	static char *home_dir;
+	static int init = 1;
+	
+	if (init) {
+		home_dir = getenv("HOME");
+		init = 0;
+	}
+	
+	return(home_dir);
+}
+
+/* pass in a string, and it will add the users home dir ie,
+ * pass in .gnome/bookmarks.html and it will return
+ * /home/imain/.gnome/bookmarks.html
+ * 
+ * Remember to g_free() returned value! */
+
+char *
+gnome_util_prepend_user_home(char *file)
+{
+	return g_concat_dir_and_file(gnome_util_user_home(), file);
+}
+
+/* very similar to above, but adds $HOME/.gnome/ to beginning
+ * This is meant to be the most useful version.
+ */
+
+char *
+gnome_util_home_file(char *file)
+{
+	char *path = g_concat_dir_and_file(gnome_util_user_home(), ".gnome");
+	char *ret = g_copy_strings(path, "/", file, NULL);
+
+	g_free(path);
+	return ret;
+}
diff --git a/libgnome/gnome-util.h b/libgnome/gnome-util.h
new file mode 100644
index 0000000..8eddef2
--- /dev/null
+++ b/libgnome/gnome-util.h
@@ -0,0 +1,25 @@
+#ifndef __GNOME_UTIL_H__
+#define __GNOME_UTIL_H__
+
+BEGIN_GNOME_DECLS
+
+#define PATH_SEP '/'
+#define PATH_SEP_STR "/"
+
+char *gnome_libdir_file (char *filename);
+char *gnome_datadir_file (char *filename);
+char *gnome_pixmap_file (char *filename);
+char *gnome_unconditional_libdir_file (char *filename);
+char *gnome_unconditional_datadir_file (char *filename);
+char *gnome_unconditional_pixmap_file (char *filename);
+int   g_file_exists (char *filename);
+char *g_copy_strings (const char *first, ...);
+char *g_unix_error_string (int error_num);
+char *g_concat_dir_and_file (const char *dir, const char *file);
+char *gnome_util_user_home(void);
+char *gnome_util_prepend_user_home(char *file);
+char *gnome_util_home_file(char *file);
+
+END_GNOME_DECLS
+
+#endif
diff --git a/libgnome/gnomelib-init.c b/libgnome/gnomelib-init.c
new file mode 100644
index 0000000..3010e76
--- /dev/null
+++ b/libgnome/gnomelib-init.c
@@ -0,0 +1,36 @@
+#include <config.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <glib.h>
+#include "gnome-defs.h"
+#include "gnome-util.h"
+
+#ifdef HAVE_LIBINTL
+#include "libintl.h"
+#endif
+
+char *gnome_user_home_dir = 0;
+char *gnome_user_dir = 0;
+
+void
+gnomelib_init (int *argc, char ***argv)
+{
+	gnome_user_home_dir = getenv ("HOME");
+	gnome_user_dir = g_concat_dir_and_file (gnome_user_home_dir, ".gnome");
+	mkdir (gnome_user_dir, 0755);
+
+	setlocale (LC_ALL, "");
+#ifdef HAVE_LIBINTL
+	bindtextdomain (PACKAGE, GNOMELOCALEDIR);
+#endif
+}
+
+
+
diff --git a/libgnome/libgnome.h b/libgnome/libgnome.h
new file mode 100644
index 0000000..27135b6
--- /dev/null
+++ b/libgnome/libgnome.h
@@ -0,0 +1,19 @@
+#ifndef LIBGNOME_H
+#define LIBGNOME_H
+
+#include "libgnome/gnome-defs.h"
+#include "libgnome/gnome-util.h"
+#include "libgnome/gnome-hook.h"
+#include "libgnome/gnome-config.h"
+#include "libgnome/gnome-dns.h"
+#include "libgnome/gnome-dentry.h"
+#include "libgnome/gnome-i18n.h"
+#include "libgnome/gnome-string.h"
+#include "libgnome/gnome-triggers.h"
+
+extern char *gnome_user_home_dir;
+extern char *gnome_user_dir;
+
+void gnomelib_init (int *argc, char ***argv);
+
+#endif



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