[monkey-bubble: 121/753] This has been moved to libgnome-2/libgnome.



commit 4928e1ebb5fb6c43e9b92fc3bb0d73c3fee753b4
Author: Martin Baulig <martin src gnome org>
Date:   Wed Apr 11 16:48:46 2001 +0000

    This has been moved to libgnome-2/libgnome.

 .cvsignore                              |   36 +
 ChangeLog                               |   29 +
 Makefile.am                             |    4 +
 acconfig.h                              |    7 +
 autogen.sh                              |   52 +
 configure.in                            |  151 ++
 doc/.cvsignore                          |    2 +
 doc/ChangeLog                           |    5 +
 doc/Makefile.am                         |    1 +
 doc/Porting-1.0-2.0.txt                 |  175 ++
 help-converters/info/Makefile.am        |   13 +
 help-converters/info/data.h             |   56 +
 help-converters/info/html.c             |  920 ++++++++
 help-converters/info/html.h             |   25 +
 help-converters/info/main.c             |  286 +++
 help-converters/info/parse.c            |  523 +++++
 help-converters/info/parse.h            |   27 +
 help-converters/info/utils.c            |  275 +++
 help-converters/info/utils.h            |   17 +
 help-converters/info/version.h          |    6 +
 help-converters/man/Makefile.am         |   15 +
 help-converters/man/README              |  284 +++
 help-converters/man/gnome-man2html.c    | 3845 +++++++++++++++++++++++++++++++
 help-converters/man/man2html.8          |  259 +++
 libgnome/.cvsignore                     |   21 +
 libgnome/ChangeLog                      |  687 ++++++
 libgnome/ChangeLog-19991006             | 2082 +++++++++++++++++
 libgnome/DEPENDS.libgnome               |    3 +
 libgnome/Makefile.am                    |  149 ++
 libgnome/gnome-config.c                 | 2091 +++++++++++++++++
 libgnome/gnome-config.h                 |  292 +++
 libgnome/gnome-defs.h                   |   32 +
 libgnome/gnome-ditem.c                  | 2188 ++++++++++++++++++
 libgnome/gnome-ditem.h                  |  155 ++
 libgnome/gnome-exec.c                   |  490 ++++
 libgnome/gnome-exec.h                   |   79 +
 libgnome/gnome-file-selector.c          | 1022 ++++++++
 libgnome/gnome-file-selector.h          |   83 +
 libgnome/gnome-fileconvert.c            |  358 +++
 libgnome/gnome-fileconvert.h            |   45 +
 libgnome/gnome-gconf.c                  |  577 +++++
 libgnome/gnome-gconf.h                  |   87 +
 libgnome/gnome-i18n.c                   |  183 ++
 libgnome/gnome-i18n.h                   |  123 +
 libgnome/gnome-i18nP.h                  |   57 +
 libgnome/gnome-init.c                   |  195 ++
 libgnome/gnome-macros.h                 |   74 +
 libgnome/gnome-marshal-main.c           |   32 +
 libgnome/gnome-marshal.list             |   18 +
 libgnome/gnome-moz-remote.c             |  907 ++++++++
 libgnome/gnome-moz-remote2.c            |  888 +++++++
 libgnome/gnome-paper.c                  |  474 ++++
 libgnome/gnome-paper.h                  |   73 +
 libgnome/gnome-portability.h.in         |   31 +
 libgnome/gnome-program.c                | 1359 +++++++++++
 libgnome/gnome-program.h                |  209 ++
 libgnome/gnome-regex.c                  |  162 ++
 libgnome/gnome-regex.h                  |   64 +
 libgnome/gnome-remote.c                 |  101 +
 libgnome/gnome-remote.h                 |   45 +
 libgnome/gnome-score.c                  |  456 ----
 libgnome/gnome-score.h                  |   63 -
 libgnome/gnome-sound.c                  |  513 ++++
 libgnome/gnome-sound.h                  |   51 +
 libgnome/gnome-triggers.c               |  605 +++++
 libgnome/gnome-triggers.h               |   85 +
 libgnome/gnome-triggersP.h              |   40 +
 libgnome/gnome-url.c                    |  485 ++++
 libgnome/gnome-url.h                    |   91 +
 libgnome/gnome-util.c                   |  211 ++
 libgnome/gnome-util.h                   |   81 +
 libgnome/gnomelib-init.c                |  195 ++
 libgnome/gnomelib-init.h                |   49 +
 libgnome/libgnome-2.0.pc.in             |   11 +
 libgnome/libgnome-boxed.defs            |    6 +
 libgnome/libgnome.h                     |   51 +
 libgnome/libgnomeP.h                    |   39 +
 libgnome/libgnometypes.c                |   51 +
 libgnome/parse-path.cP                  |  100 +
 libgnome/test-libgnome.c                |  172 ++
 libgnome/vroot.h                        |  120 +
 message-of-doom                         |   24 +
 monikers/GNOME_Moniker_std.oaf.in.in    |  111 +
 monikers/Makefile.am-50588              |   60 +
 monikers/bonobo-moniker-extender-file.c |   98 +
 monikers/bonobo-moniker-file.c          |   72 +
 monikers/bonobo-storage-fs.c            |  475 ++++
 monikers/bonobo-storage-fs.h            |   32 +
 monikers/bonobo-storage-vfs.c           |  335 +++
 monikers/bonobo-storage-vfs.h           |   28 +
 monikers/bonobo-stream-fs.c             |  500 ++++
 monikers/bonobo-stream-fs.h             |   48 +
 monikers/bonobo-stream-vfs.c            |  416 ++++
 monikers/bonobo-stream-vfs.h            |   40 +
 monikers/gnome-moniker-std.c            |   70 +
 monikers/gnome-moniker-std.h            |   53 +
 po/.cvsignore                           |   11 +
 tests/test-storage.c                    |  544 +++++
 tools/.cvsignore                        |    3 +
 tools/ChangeLog                         |   21 +
 tools/Makefile.am                       |    9 +
 tools/gnome-makeenums.pl                |  231 ++
 tools/gnome-maketypes.awk.in            |  167 ++
 103 files changed, 28753 insertions(+), 519 deletions(-)
---
diff --git a/.cvsignore b/.cvsignore
new file mode 100644
index 0000000..ddc19bf
--- /dev/null
+++ b/.cvsignore
@@ -0,0 +1,36 @@
+Makefile
+Makefile.in
+aclocal.m4
+confdefs.h
+config.cache
+config.guess
+config.h
+config.log
+config.status
+config.sub
+configure
+configure.scan
+libtool
+ltconfig
+ltmain.sh
+stamp-h
+stamp-h.in
+stamp.h
+version.h
+gnomeConf.sh
+config.h.in
+.exrc
+gnome-bug
+gnome-config
+install-sh
+missing
+mkinstalldirs
+INSTALL
+intl
+ABOUT-NLS
+COPYING
+gnome-libs.spec
+.lclintrc
+libvfs
+compatConf.sh
+libgnome2-*.tar.gz
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e69de29
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..b753d78
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,29 @@
+2001-03-24  Anders Carlsson  <andersca gnu org>
+
+	* configure.in (DB_LIB): It's gnome-vfs-2.0, not gnomevfs-2.0
+
+2001-03-24  Martin Baulig  <baulig suse de>
+
+	* configure.in: Require ORBit >= 2.3.90, not 2.5.7.
+
+2001-03-21  Martin Baulig  <baulig suse de>
+
+	* configure.in: Set package name to `libgnome2', looks better
+	than `libgnome-2'.
+
+2001-03-21  Martin Baulig  <baulig suse de>
+
+	configure.in: Added awk check; use AC_PATH_PROGS in perl check.
+
+	* tools/: New directory.
+
+	* doc/: New directory.
+
+2001-03-05  Martin Baulig  <baulig suse de>
+
+	* configure.in: Enable NLS again.
+	* po/POTFILES.in: New file; currently empty.
+
+	* configure.in: Set package name to `libgnome-2-martin' and
+	version number to 1.96.0.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..faa4f0b
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = tools libgnome po intl doc
+
+EXTRA_DIST = message-of-doom
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644
index 0000000..e69de29
diff --git a/acconfig.h b/acconfig.h
new file mode 100644
index 0000000..3c06e93
--- /dev/null
+++ b/acconfig.h
@@ -0,0 +1,7 @@
+#undef GNOME_ENABLE_DEBUG
+#undef PREFER_DB1
+#undef ENABLE_NLS
+#undef HAVE_CATGETS
+#undef HAVE_GETTEXT
+#undef HAVE_LC_MESSAGES
+#undef HAVE_STPCPY
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..07f331e
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+if test -z "$CERTIFIED_GNOMIE"; then
+# If you can't figure out how to set this envar, please don't come on IRC
+# whining incessantly about how your apps are broken.
+  cat $srcdir/message-of-doom
+  exit 1
+fi
+
+PKG_NAME="libgnome"
+
+(test -f $srcdir/configure.in \
+  && test -f $srcdir/autogen.sh \
+  && test -d $srcdir/libgnome) || {
+    echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+    echo " top-level $PKG_NAME directory"
+    exit 1
+}
+
+DIE=0
+
+rm -f .using-gnome-libs-package
+
+# This is a bit complicated here since we can't use gnome-config yet.
+# It'll be easier after switching to pkg-config since we can then
+# use pkg-config to find the gnome-autogen.sh script.
+
+gnome_autogen=
+gnome_datadir=
+
+ifs_save="$IFS"; IFS=":"
+for dir in $PATH ; do
+  test -z "$dir" && dir=.
+  if test -f $dir/gnome-autogen.sh ; then
+    gnome_autogen="$dir/gnome-autogen.sh"
+    gnome_datadir=`echo $dir | sed -e 's,/bin$,/share,'`
+    break
+  fi
+done
+IFS="$ifs_save"
+
+if test -z "$gnome_autogen" ; then
+  echo "You need to install the gnome-common module and make"
+  echo "sure the gnome-autogen.sh script is in your \$PATH."
+  exit 1
+fi
+
+GNOME_DATADIR="$gnome_datadir" USE_GNOME2_MACROS=1 . $gnome_autogen
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..0ad4711
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,151 @@
+AC_INIT(libgnome)
+
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE(libgnome2, 1.96.0)
+
+AM_MAINTAINER_MODE
+
+if test -z "$CERTIFIED_GNOMIE"; then
+  cat $srcdir/message-of-doom
+  exit 1
+fi
+
+GNOME_COMMON_INIT
+GNOME_PLATFORM_GNOME_2(yes, force)
+
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_ARG_PROGRAM
+AM_PROG_LIBTOOL
+AM_PROG_LEX
+AC_PROG_YACC
+AC_PATH_PROGS(PATH_TO_XRDB, "xrdb")
+
+dnl utility conditional
+AM_CONDITIONAL(FALSE, test "x" = "y")
+
+ALL_LINGUAS=""
+AM_GNOME2_GETTEXT
+gnomelocaledir='${prefix}/${DATADIRNAME}/locale'
+AC_SUBST(gnomelocaledir)
+
+AC_SUBST(CFLAGS)
+AC_SUBST(CPPFLAGS)
+AC_SUBST(LDFLAGS)
+
+GNOME_COMPILE_WARNINGS(maximum)
+
+dnl Define GNOME_ENABLE_DEBUG if the --enable-debug switch was given.
+GNOME_DEBUG_CHECK
+
+AC_PROG_AWK
+
+dnl Don't use AC_PROG_AWK since we need the full pathname.
+AC_PATH_PROGS(AWK, mawk gawk nawk awk, )
+AC_PATH_PROGS(PERL, perl5 perl)
+
+AC_ARG_ENABLE(prefer-db1, [  --enable-prefer-db1     Prefer Berkeley DB 1.x],[prefer_db1="$enableval"],[prefer_db1=yes])
+dnl
+dnl Check for db stuff (gnome-metadata)
+dnl
+DB_LIB=
+AC_CHECK_FUNC(dbopen, [],
+if test "$prefer_db1" = "yes"; then
+ AC_CHECK_LIB(db1, dbopen, DB_LIB="-ldb1",
+  AC_CHECK_LIB(db, dbopen, DB_LIB="-ldb",
+   AC_CHECK_LIB(db-3, __db185_open, DB_LIB="-ldb-3",
+    AC_MSG_ERROR([Your db library is missing db 1.85 compatibility mode])
+   )
+  )
+ )
+else
+ AC_CHECK_LIB(db, dbopen, DB_LIB="-ldb",
+  AC_CHECK_LIB(db1, dbopen, DB_LIB="-ldb1",
+   AC_CHECK_LIB(db-3, __db185_open, DB_LIB="-ldb-3",
+    AC_MSG_ERROR([Your db library is missing db 1.85 compatibility mode])
+   )
+  )
+ )
+fi
+)
+
+dnl look for db headers
+if test "$prefer_db1" = "yes"; then
+	AC_CHECK_HEADERS(db_185.h db1/db.h)
+	if test "$ac_cv_header_db_185_h$ac_cv_header_db1_db_h" = nono; then
+	  AC_MSG_ERROR([Berkeley db library required for Gnome])
+	fi
+	AC_DEFINE(PREFER_DB1)
+else
+	AC_CHECK_HEADERS(db.h db_185.h db1/db.h)
+
+	if test "$ac_cv_header_db_h$ac_cv_header_db_185_h$ac_cv_header_db1_db_h" = nonono; then
+	  AC_MSG_ERROR([Berkeley db library required for Gnome])
+	fi
+fi
+
+dnl
+dnl Start of pkg-config checks
+dnl
+GNOME_PKGCONFIG_CHECK_MODULES(ORBIT, ORBit-2.0:2.3.90)
+AC_PATH_PROG(ORBIT_IDL, orbit-idl, no)
+AC_SUBST(ORBIT_CFLAGS)
+AC_SUBST(ORBIT_LIBS)
+
+GNOME_PKGCONFIG_CHECK_MODULES(GNOMESUPPORT, gnome-support-2.0:1.2.1)
+AC_SUBST(GNOMESUPPORT_CFLAGS)
+AC_SUBST(GNOMESUPPORT_LIBS)
+
+GNOME_PKGCONFIG_CHECK_MODULES(GLIB, glib-2.0:1.3.1)
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+GNOME_PKGCONFIG_CHECK_MODULES(GNOME_VFS, gnome-vfs-2.0)
+GNOME_VFS_VERSION=`$PKG_CONFIG --modversion gnome-vfs-2.0`
+AC_SUBST(GNOME_VFS_VERSION)
+AC_SUBST(GNOME_VFS_CFLAGS)
+AC_SUBST(GNOME_VFS_LIBS)
+
+GNOME_PKGCONFIG_CHECK_MODULES(OAF, oaf-2.0)
+AC_SUBST(OAF_CFLAGS)
+AC_SUBST(OAF_LIBS)
+
+GNOME_PKGCONFIG_CHECK_MODULES(GCONF, gconf-2.0)
+AC_SUBST(GCONF_CFLAGS)
+AC_SUBST(GCONF_LIBS)
+
+GNOME_PKGCONFIG_CHECK_MODULES(LIBXML, libxml-2.0:2.3.1)
+AC_SUBST(LIBXML_CFLAGS)
+AC_SUBST(LIBXML_LIBS)
+
+AC_CHECK_LIB(popt, poptStrippedArgv,, AC_MSG_ERROR([popt 1.5 or newer is required to build
+gnome-libs. You can download the latest version from ftp://people.redhat.com/sopwith/popt/]))
+
+dnl This is installed from GTK+ 2.0's gdk-pixbuf
+AC_PATH_PROG(MAKE_INLINE_PIXBUF, make-inline-pixbuf)
+test -z "$MAKE_INLINE_PIXBUF" && AC_MSG_ERROR([
+*** You need the make-inline-pixbuf tool which is installed
+*** from GTK+ 2.0's gdk-pixbuf.
+***
+*** Either the location where you installed your GTK+ 2.0 is
+*** not in your PATH or something is screwed up with your
+*** GTK+ 2.0 installation
+])
+
+AC_OUTPUT([
+Makefile
+po/Makefile.in
+intl/Makefile
+tools/Makefile
+tools/gnome-maketypes.awk
+libgnome/Makefile
+libgnome/gnome-portability.h
+libgnome/libgnome-2.0.pc
+doc/Makefile
+],[case "$CONFIG_FILES" in
+*tools/gnome-maketypes.awk*)chmod +x tools/gnome-maketypes.awk;;
+esac]
+)
+
+cat $srcdir/message-of-doom
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644
index 0000000..3dda729
--- /dev/null
+++ b/doc/.cvsignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/doc/ChangeLog b/doc/ChangeLog
new file mode 100644
index 0000000..e31d841
--- /dev/null
+++ b/doc/ChangeLog
@@ -0,0 +1,5 @@
+2001-03-21  Martin Baulig  <baulig suse de>
+
+	* Porting-1.0-2.0.txt: Added the libgnome section from
+	our porting document here.
+
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..b34f3fc
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1 @@
+EXTRA_DIST = Porting-1.0-2.0.txt
diff --git a/doc/Porting-1.0-2.0.txt b/doc/Porting-1.0-2.0.txt
new file mode 100644
index 0000000..a9498fd
--- /dev/null
+++ b/doc/Porting-1.0-2.0.txt
@@ -0,0 +1,175 @@
+		Porting GNOME 1.0 Applications to GNOME 2.0
+
+
+[this document is still work-in-progress.]
+
+Notation
+========
+
+* MODIFIED
+
+  The file/widget/feature has been modified in a source incompatible way,
+  but it is possible to reuse old code without completely rewriting it
+  (compatibility layer exists, fixable by scripts, ....)
+
+* CHANGED API
+
+  The API of this file/widget/feature has completely changed; it is not
+  possible to reuse old code without rewriting at least large parts of it.
+
+* ADDED FUNCTIONALITY
+
+  There is some added functionality over GNOME 1.x.
+
+* OBSOLETE
+
+  The file/widget/feature is obsolete and it has been moved to libcompat.
+
+* REMOVED
+
+  The file/widget/feature has been completely removed, it is not in libcompat.
+  This normally means that it is easier to fix code which was using this than
+  to provide a compatibility layer.
+
+* NEW
+
+  The file/widget/feature is completely new in GNOME 2.0.
+
+* UNKNOWN
+
+  I don't know what's up with this.
+
+libgnome stuff:
+===============
+
+* gnome-config - ADDED FUNCTIONALITY
+
+  - uses gbooleans rather then gints
+
+  The following functions have been changed:
+
+  - gnome_config_sync()
+  - gnome_config_sync_file():  Now return a gboolean to indicate if the
+    sync was successful.  Needed for GnomeDItem
+
+* gnome-dentry - OBSOLETE
+
+  - This has been replaced by GnomeDItem (gnome-ditem), and currently resides
+    in libcompat
+
+* GnomeDItem (gnome-ditem) - NEW
+
+  - This is a far more flexible replacement for GnomeDEntry.  It allows adding
+    of arbitrary fields without changing the API, and it does not clobber
+    other info in the .desktop file.
+
+* gnome-dns - OBSOLETE
+
+  - There are other and better way of doing this
+
+* gnome-exec - ADDED FUNCTIONALITY
+
+  The following new functions have been added:
+
+  - gnome_prepend_terminal_to_vector(): prepend the terminal accodring to user
+    preference to the vector
+  - gnome_execute_terminal_shell()
+  - gnome_execute_terminal_shell_fds():  Execute in terminal shell according
+    to user preference.
+
+* gnome-help - OBSOLETE
+
+  - gnome-helpsys from libgnomeui should be used
+
+* gnome-history - OBSOLETE
+
+  - gnome-recently-used from libgnomeui should be used
+
+* gnome-i18n - ADDED FUNCTIONALITY
+
+  - Return values are const correct
+
+  The following new functions have been added:
+
+  - gnome_i18n_push_c_numeric_locale()
+    gnome_i18n_pop_c_numeric_locale():  Fucntions for pushing and popping
+    a "C" numeric locale.  This is neccessary anywhere where a text file is
+    read or written or anywhere where information exchange in numbers takes
+    place as it's neccessary to use the C locale there to make it work in
+    non-C locales.
+
+* gnome-metadata - OBSOLETE
+
+  - This is all now in gnome-vfs
+
+* gnome-mime - OBSOLETE
+
+  - This is all now in gnome-vfs
+
+* gnome-mime-info - OBSOLETE
+
+  - This is all now in gnome-vfs
+  
+* gnome-paper - ADDED FUNCTIONALITY
+
+  - Return values are const correct
+
+  The following new functions have been added:
+
+  - gnome_unit_with_abbrev()
+  - gnome_unit_name()
+  - gnome_unit_abbrev()
+  - gnome_unit_convert()
+
+* gnome-popt - OBSOLETE
+
+  - Apparently the new init stuff in libgnome takes care of this
+
+* gnome-regex
+
+  - Source compatible beautification
+
+* gnome-score
+
+  - const correct
+
+* gnome-url - ADDED FUNCTIONALITY
+
+  The following functions have been modified:
+
+  - gnome_url_show(): const correct, returns a gboolean
+
+  The following new functions have been added:
+
+  - gnome_url_show_full():
+  - gnome_url_display_context_free():  URL showing according to flags,
+    and gets an actual error, and a history.  The history callback api is
+    not nice, and needs to be still changed.
+
+* gnome-util - MODIFIED + ADDED FUNCTIONALITY
+
+  - const correct
+
+  The following functions/macros have been removed:
+
+  - g_filename_index()
+  - g_filename_pointer():  These functions depended on g_basename, which is
+    obscolete in glib 2
+  - g_file_test(): Removed since glib2 includes this function
+  - g_copy_strings()
+  - g_unix_error_string():  Removed since glib2 includes equivalents, and
+    has for quite a while
+  - g_file_exists():  Use g_file_test(,G_FILE_TEST_EXISTS) instead.
+
+  The following functions have been added:
+
+  - gnome_file_locate():  A more flexible file location functions which
+    attempts to solve the issues of gnome_*_file functions.
+
+* gnomelib-init, gnomelib-init2 - UNKNOWN
+
+  - Apparently some sort of more flexible initialization
+
+Last changed Feb 25, 2001.
+Martin Baulig <baulig suse de>
+George Lebl <jirka 5z com>
diff --git a/help-converters/info/Makefile.am b/help-converters/info/Makefile.am
new file mode 100644
index 0000000..1405633
--- /dev/null
+++ b/help-converters/info/Makefile.am
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = 			\
+	-I$(includedir)		\
+	-I$(top_srcdir)/intl -I$(top_builddir)/intl	\
+	$(GNOMEUI_CFLAGS)	
+
+LDADD = \
+	$(GNOME_LIBS) $(Z_LIBS) $(BZ_LIBS)
+
+bin_PROGRAMS = gnome-info2html2
+
+gnome_info2html2_SOURCES = main.c parse.c utils.c html.c data.h html.h parse.h utils.h version.h
diff --git a/help-converters/info/data.h b/help-converters/info/data.h
new file mode 100644
index 0000000..60a2ce7
--- /dev/null
+++ b/help-converters/info/data.h
@@ -0,0 +1,56 @@
+#ifndef DATA_H
+#define DATA_H
+
+/* data.h - first cut at data structures for info2html filter */
+/* many of these are motivated by the source code to the 'info' program */
+
+/* file we're working on */
+char work_filename[1024];
+
+/* node we're working on */
+char work_node[1024];
+
+/* some type's we'll want to use below */
+typedef struct info_menu_entry MENU_ENTRY;
+
+/* the basic component of an info file is a Node */
+/* a node is described by (FILENAME)NODENAME */
+/* .next and .prev are normally along the same branch as current node */
+/* .up is normally 'one branch' up the tree above current branch. */
+/* All can be arbitrary links however                             */
+/* menu entry is just a linked list of references */
+
+typedef struct {
+  char *filename;                /* file in which this node exists */
+  char *nodename;                /* name of this node */
+  char *contents;                /* text within this node */
+  int  contlen;                  /* length of contents */
+  char *next;                    /* node which follows this one */
+  char *prev;                    /* node previous to this one */
+  char *up;                      /* node above this one */
+  MENU_ENTRY *menu;              /* linked list of refs from this node */
+  char *menu_start;              /* ptr to start of menu text in contents */
+} NODE;
+
+/* a reference is a link to a node */
+typedef struct {
+  char *refname;                  /* menu name for reference */
+  NODE *node;                     /* descriptor of node we point at */
+} REFERENCE;
+
+
+struct info_menu_entry{
+  char          *header;          /* header to go before menu */
+  REFERENCE     *ref;
+  struct info_menu_entry    *next;
+};
+
+#define INFO_FF '\014'
+#define INFO_COOKIE '\037'
+
+
+#define MENU_START "* Menu:"
+#define MENU_ENTRY "* "
+
+
+#endif /* DATA_H */
diff --git a/help-converters/info/html.c b/help-converters/info/html.c
new file mode 100644
index 0000000..f5dd8e5
--- /dev/null
+++ b/help-converters/info/html.c
@@ -0,0 +1,920 @@
+/* handles all html operations */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "data.h"
+#include "html.h"
+#include "parse.h"
+#include "utils.h"
+
+#define USE_FILE_URLS
+
+int inTable=0;
+
+char *BaseFilename=NULL;
+char *OverrideBaseFilename=NULL;
+
+/* prototypes */
+char *form_info_tag_href( char *nodefile, char *nodename );
+int make_Top_link( char *destdir, char *destfile );
+int make_info_dir( char *destdir );
+void write_node_link_html( FILE *f, char *nodefile, char *refname, char *ref );
+void start_html_content( FILE *f );
+void make_nav_links( FILE *f, NODE *node );
+void html_error( char *s, char *p, char *q );
+
+
+/* print out the url for a info file */
+char *form_info_tag_href( char *nodefile, char *nodename )
+{
+  char tmp[1024];
+  char *escaped_nodename;
+  char *filename;
+
+  escaped_nodename = escape_html_chars( nodename );
+  if (!strcmp(BaseFilename, nodefile))
+    {
+	  if (OverrideBaseFilename)
+		  filename = OverrideBaseFilename;
+	  else 
+		  filename = BaseFilename;
+    }
+  else
+	  filename = nodefile;
+
+  g_snprintf (tmp, sizeof (tmp), "HREF=\"#%s\"", escaped_nodename);
+
+  if (escaped_nodename)
+    g_free(escaped_nodename);
+  return g_strdup(tmp);
+}
+
+
+/* returns zero if success making link from destfile -> index.html in */
+/* specified directory. If it already exists, just returns with success */
+int make_Top_link( char *destdir, char *destfile )
+{
+  struct stat filestat;
+  char *indexlink;
+  
+  indexlink = (char *) g_malloc( strlen(destdir) + 20);
+  strcpy(indexlink, destdir);
+  strcat(indexlink, "/index.html");
+  
+  if (lstat(indexlink, &filestat))
+    {
+      if (errno == ENOENT)
+	{
+	  if (symlink(destfile, indexlink))
+	    {
+	      fprintf(stderr,"Error creating link to %s\n",indexlink);
+	      perror("Error was");
+	      exit(1);
+	    }
+	}
+      else
+	{
+	  fprintf(stderr,"Error stat'ing file %s\n",indexlink);
+	  perror("Error was");
+	  exit(1);
+	}
+    }
+  else if (!S_ISLNK(filestat.st_mode))
+    {
+      fprintf(stderr, "file %s exists and isnt a link\n",indexlink);
+      fprintf(stderr, "FIX ME!!!\n");
+      g_free(indexlink);
+      return -1;
+    }
+  return 0;
+}
+
+/* return non-zero if error with making directory */
+int make_info_dir( char *destdir )
+{
+  struct stat filestat;
+
+  if (stat(destdir, &filestat))
+    {
+      if (errno == ENOENT)
+	{
+	  if (mkdir(destdir, 01777))
+	    {
+	      fprintf(stderr,"Error creating directory %s\n",destdir);
+	      perror("Error was");
+	      exit(1);
+	    }
+	}
+      else
+	{
+	    fprintf(stderr,"Error stat'ing directory %s\n",destdir);
+	    perror("Error was");
+	    exit(1);
+	}
+    }
+  else if (!S_ISDIR(filestat.st_mode))
+    {
+      fprintf(stderr, "Info dir %s exists and isnt a directory!\n",destdir);
+      fprintf(stderr, "FIX ME!!!\n");
+      return -1;
+    }
+  return 0;
+}
+
+/* write a link to another document */
+void write_node_link_html( FILE *f, char *nodefile, char *refname, char *ref )
+{
+  char *converted_nodename;
+  char *href;
+
+  if (ref) {
+      if (g_strcasecmp(ref, "(dir)")) {
+	  converted_nodename = g_strdup( ref );
+	  map_spaces_to_underscores( converted_nodename );
+	  href = form_info_tag_href(nodefile, converted_nodename);
+	  fprintf(f,"<A %s>%s%s</A>\n", href, refname, ref);
+	  g_free(href);
+	  g_free(converted_nodename);
+	} else {
+	  href = form_info_tag_href("dir", "Top");
+	  fprintf(f,"<A %s>%s(dir)</A>\n",href, refname);
+	  g_free(href);
+
+	}
+    }
+}
+
+/* write out top of a new html file */
+#if 0
+void write_html_header( FILE *f, char *filename, char *nodename)
+{
+  fprintf(f,"<!DOCTYPE HTML PUBLIC \"-//W3C/DTD HTML 3.2//EN\">\n");
+  fprintf(f,"<HTML>\n");
+  fprintf(f,"<HEAD>\n");
+  fprintf(f,"<TITLE>Info Node: (%s)%s</TITLE>\n",filename,nodename);
+  fprintf(f,"<META NAME=\"GENERATOR\" CONTENT=\"info2html\">\n");
+  fprintf(f,"</HEAD>\n");
+  fprintf(f,"<!-- conversion of file \"%s\", node \"%s\" -->\n",work_filename, work_node);
+}
+#endif
+
+/* start of everything after html header */
+void start_html_content( FILE *f )
+{
+  fprintf(f,"<BODY>\n");
+}
+
+/* we want to put links to next, prev, and up nodes */
+void make_nav_links( FILE *f, NODE *node )
+{
+#if 0
+  fprintf(f,"<PRE>\n");
+  write_node_link_html( f, node->filename, "Next:", node->next );
+  write_node_link_html( f, node->filename, "Prev:", node->prev );
+  write_node_link_html( f, node->filename, "Up:", node->up );
+  fprintf(f,"</PRE>\n");
+#else
+  fprintf(f,"<TABLE border=2 cellspacing=1 cellpadding=4 width=100%%>\n");
+  fprintf(f,"<TR bgcolor=\"#eeeee0\">\n");
+  fprintf(f,"\t<TH align=center width=33%%>\n\t");
+  write_node_link_html( f, node->filename, "Next:", node->next );
+  fprintf(f,"\t</TH>\n");
+  fprintf(f,"\t<TH align=center width=33%%>\n\t");
+  write_node_link_html( f, node->filename, "Prev:", node->prev );
+  fprintf(f,"\t</TH>\n");
+  fprintf(f,"\t<TH align=center width=34%%>\n\t");
+  write_node_link_html( f, node->filename, "Up:", node->up );
+  fprintf(f,"\t</TH>\n");
+  fprintf(f,"</TR>\n</TABLE>\n");
+#endif
+
+}
+
+/* s is error message */
+/* p is start of offending line */
+/* q is end of offending line */
+void html_error( char *s, char *p, char *q )
+{
+  fprintf(stderr, "%s:%s\n",work_filename, work_node);
+  fprintf(stderr, "\t%s\n",s);
+  fprintf(stderr, "\tOffending line is:\n\t|");
+  fwrite(p, 1, q-p, stderr);
+  fprintf(stderr, "|\n");
+}
+
+/********************************************************************
+ * here is what we expect in contents of a node: 
+ * 
+ *  headers:   These are identified as a line of text
+ *             followed by a row of '---' or '###' normally.
+ *             These get mapped to <H2> </H2> for now.
+ *
+ *  body text: Format this between <PRE> </PRE> statements.
+ *             Catch any *Note and *note and make into
+ *             links to other documents. Also try to catch
+ *             URLs as well.
+ *
+ *  menus:     Starts with a '* Menu' line. Goes until the
+ *             end of the node, or until the next line which
+ *             starts with something other than a '* ' or '\n'.
+ *
+ *  end of node: The INFO_FF and INFO_COOKIE mark the end of a node.
+ *               Hitting EOF also marks the end of a node.
+ ********************************************************************/
+
+void dump_html_for_node( NODE *node )
+{
+/*  char *destdir; */
+/*  char *destfile; */
+  char *escaped_nodename;
+/*  char *converted_nodename; */
+  char *contents_start, *contents_end;
+  char *header_name;
+  char *p, *q, *r, *skippnt;
+  char *end_menu_entry;
+
+
+  int menu_open, body_open;
+
+  int seen_menu;
+    
+  int prev_was_blank, next_is_blank, current_is_blank;
+
+  int seen_first_header;
+
+  int last_output_was_header;
+
+  int nskip;
+
+  int we_are_in_dir_node;
+
+  int i;
+
+  FILE *f;
+
+/* msf - used to write each node to a separate file - now we're going */
+/*       to just output HTML to stdout.                               */
+/*       Each node will just be concantentated to previous            */
+#if 0
+  destdir = (char *) g_malloc ( strlen(node->filename) + 
+			      strlen(HTML_ROOT) +
+			      strlen(node->filename) + 2);
+  strcpy(destdir, HTML_ROOT);
+  strcat(destdir, "/");
+  strcat(destdir, node->filename);
+  strcat(destdir, "/");
+
+  /* check that the dir for info file exists */
+  make_info_dir( destdir );
+
+  /* ok, we made the dir, lets go */
+  destfile = (char *) g_malloc( strlen(destdir) + strlen(node->nodename) + 10);
+  strcpy(destfile, destdir);
+  converted_nodename = g_strdup( node->nodename );
+  map_spaces_to_underscores( converted_nodename );
+  strcat(destfile, converted_nodename);
+  strcat(destfile, ".html");
+  g_free(converted_nodename);
+
+  if (!(f=fopen(destfile, "w")))
+    {
+      fprintf(f,"Couldnt create node html file %s\n",destfile);
+      perror("Error was");
+      exit(1);
+    }
+#endif
+
+  /* hack - just dump to stdout for now */
+  f = stdout;
+
+  /* see if this is THE dir node */
+  we_are_in_dir_node = !strcmp("Top", node->nodename) && !strcmp("dir", node->filename);
+
+#if 0
+  /* try and make a link between 'index.html' and 'Top.html' */
+  if (!strcmp("Top", node->nodename))
+      make_Top_link( destdir, destfile );
+#endif
+
+#if 0
+  /* do the html header first */
+  write_html_header( f, node->filename, node->nodename );
+#endif
+
+#if 0
+  /* now for the body */
+  start_html_content( f );
+#endif
+
+  /* make an anchor */
+  escaped_nodename = escape_html_chars( node->nodename );
+  map_spaces_to_underscores( escaped_nodename );
+  fprintf(f, "<A name=\"%s\"></A>\n",escaped_nodename);
+  g_free(escaped_nodename);
+
+  /* links to other immediate nodes */
+  make_nav_links( f, node );
+
+  /* setup pointers to textual content of current node */
+  contents_start = node->contents;
+  contents_end   = node->contents+node->contlen;
+
+  /* scan through all of contents and generate html on the fly */
+  /* p points at start of current line */
+  /* q points at the end of current line (at '\n' actually) */
+  /* r points at the start of next line */
+  /* we do this to catch headers */
+  /* scan for a header at the top of the contents */
+  /* if we see a '\n***'3 '*' in a row i */
+  /* then take previous line as a header */
+  header_name = NULL;
+  p = contents_start = node->contents;
+  q = memchr(p, '\n', contents_end - p);
+  r=q+1;
+
+  /* we have several states we could be in */
+  next_is_blank = 0;
+  prev_was_blank = 0;
+  current_is_blank = 0;
+  seen_first_header = 0;
+
+  seen_menu = 0;
+  menu_open = 0;
+  body_open = 0;
+
+  last_output_was_header = 0;
+  for (; q && r <= contents_end; )
+    {
+      nskip = 1;
+      skippnt = NULL;
+      next_is_blank = (*r == '\n');
+      current_is_blank = (*p == '\n');
+
+      /* test some easy things first */
+      if (!strncmp(p, MENU_START, strlen(MENU_START)))
+	{
+	  if (we_are_in_dir_node && !seen_menu)
+	    {
+	      if (body_open)
+		{
+		  close_body_text_html(f);
+		  body_open = 0;
+		}
+
+	      fprintf(f,"<H1> Main Info File Directory </H1>\n");
+
+	      open_body_text_html(f);
+	      body_open = 1;
+
+	      fprintf(f,"This is the main directory of available info files.\n");
+	    }
+
+	  if (body_open)
+	    {
+	      close_body_text_html(f);
+	      body_open = 0;
+	    }
+	  else if (seen_menu)
+	    html_error("Warning:saw new menu start and already in menu!", p, q);
+
+	  if (menu_open)
+	    close_menu_html( f );
+
+	  if (last_output_was_header)
+	    open_menu_html( f, "" );
+	  else
+	    open_menu_html( f, "Contents" );
+
+	  seen_menu = 1;
+	  menu_open = 1;
+	  last_output_was_header = 0;
+	}
+      else if (we_are_in_dir_node && !seen_menu)
+	{
+	  /* do nothing */
+	}
+      else if (seen_menu)
+	{
+	  /* if current line is blank ignore it */
+	  if (current_is_blank)
+	    {
+	      /* do nothing */
+	    }
+	  /* first see if its a menu line */
+	  else if (!strncmp(p, MENU_ENTRY, strlen(MENU_ENTRY)))
+	    {
+	      if (!seen_menu)
+		html_error("Have seen menu start and hit a menu line!", p, q);
+	      else
+		{
+		  if (body_open)
+		    {
+		      if (menu_open)
+			html_error("Hit a menu line, and body and menu are opened!", p, q);
+		      close_body_text_html( f );
+		      body_open = 0;
+		      open_menu_html( f, "" );
+		      menu_open = 1;
+		    }
+		  if (!menu_open)
+		    {
+		      open_menu_html( f, "" );
+		      menu_open = 1;
+		    }
+		  write_menu_entry_html( f, p, node->filename, &end_menu_entry );
+		  if (end_menu_entry != NULL)
+		    skippnt = end_menu_entry;
+		  last_output_was_header = 0;
+		}
+	    }
+	  /* maybe its a header line */
+	  /* man this is getting ridiculous, its like teaching a child */
+	  /* to read! */
+	  else if (is_a_hdr_line(r) || 
+		   (*p != '*' && *r == '*' && *(r+1) == ' ') ||
+		   (*p != '*' && seen_menu && (*p != ' ' && *(p+1) != ' ') &&
+		    !current_is_blank && prev_was_blank && next_is_blank))
+	    {
+	      header_name = (char *) g_malloc( q-p+2 );
+	      memcpy(header_name, p, q-p);
+	      *(header_name + (q - p) ) = '\000';
+
+	      /* if we were writing a particular component, close it */
+	      if (menu_open)
+		{
+		  close_menu_html( f );
+		  menu_open = 0;
+		}
+
+	      if (body_open)
+		{
+		  close_body_text_html( f );
+		  body_open = 0;
+		}
+
+	      if (seen_first_header)
+		write_header_html( f, header_name, HEADER_SIZE_2 );
+	      else
+		{
+		  seen_first_header = 1;
+		  write_header_html( f, header_name, HEADER_SIZE_1 );
+		}
+
+	      g_free(header_name);
+
+	      /* jump ahead another line */
+	      if (!(*r == '*' && *(r+1) == ' ') && !next_is_blank)
+		nskip++;
+
+	      last_output_was_header = 1;
+	    }
+	  /* well, has to be body text then */
+	  else
+	    {
+	      if (menu_open)
+		{
+		  close_menu_html( f );
+		  menu_open = 0;
+
+		  write_html_horiz_rule ( f );
+		}
+	      
+	      if (!body_open)
+		{
+		  open_body_text_html( f );
+		  body_open = 1;
+		}
+
+	      if (*p != '\n' && !last_output_was_header)
+		{
+		  skippnt=write_body_text_html( f, p, q, node->filename );
+		  last_output_was_header = 0;
+		}
+	    }
+	}
+      /* otherwise, no menu seen so things are easier */
+      else
+	{
+	  if (is_a_hdr_line(r))
+	    {
+	      header_name = (char *) g_malloc( q-p+2 );
+	      memcpy(header_name, p, q-p);
+	      *(header_name + (q - p) ) = '\000';
+	      
+	      /* if we were writing a particular component, close it */
+	      if (body_open)
+		{
+		  close_body_text_html( f );
+		  body_open = 0;
+		}
+
+	      if (seen_first_header)
+		write_header_html( f, header_name, HEADER_SIZE_2 );
+	      else
+		{
+		  seen_first_header = 1;
+		  write_header_html( f, header_name, HEADER_SIZE_1 );
+		}
+
+	      g_free(header_name);
+
+	      /* jump ahead another line */
+	      if (!(*r == '*' && *(r+1) == ' ') && !next_is_blank)
+		nskip++;
+
+	      last_output_was_header = 1;
+	    }
+	  /* well, has to be body text then */
+	  else
+	    {
+	      if (!body_open)
+		{
+		  open_body_text_html( f );
+		  body_open = 1;
+		}
+
+	      if (!(*p == '\n' && last_output_was_header))
+		{
+		  skippnt=write_body_text_html( f, p, q, node->filename );
+		  last_output_was_header = 0;
+		}
+	    }
+	}
+
+      /* end of cases, move to next line in contents */
+      prev_was_blank = (*p == '\n');
+      if (skippnt)
+	{
+	  p = skippnt;
+	  q = memchr(p, '\n', contents_end - p);
+	  r = q+1;
+	  skippnt = NULL;
+	}
+      else
+	for (i=0; i< nskip; i++)
+	  {
+	    p = r;
+	    q = memchr(p, '\n', contents_end - p);
+	    r = q+1;
+	  }
+    }
+
+  /* thats all folks */
+  if (menu_open)
+    close_menu_html( f );
+  else if (body_open)
+    close_body_text_html( f );
+
+  /* put nav links at the bottom */
+  make_nav_links(f, node);
+#if 0
+  fprintf(f,"</BODY>\n</HTML>\n");
+#endif
+
+  /* clean up */
+#if 0
+  g_free(destdir);
+  g_free(destfile);
+#endif
+}
+
+
+void write_header_html( FILE *f, char *p, char *hdr )
+{
+  fprintf(f,"<%s> %s </%s>\n",hdr,p,hdr);
+}
+
+
+void open_body_text_html( FILE *f )
+{
+  fprintf(f, "<PRE>\n");
+}
+
+void close_body_text_html( FILE *f )
+{
+  fprintf(f, "</PRE>\n");
+}
+
+/* we have to handle '*note' and '*Note' links in body text */
+/*   p is ptr to start of current line */
+/*   q is ptr to '\n' at end of current line */
+char *write_body_text_html( FILE *f, char *p, char *q, char *nodefile )
+{
+  int curlen;
+  int ref_exists;
+  char *tmp;
+  char *ptr;
+  char *match1;
+  char *note_ptr;
+  char *converted_nodename;
+  char *escaped_refname;
+  char *escaped_refnode;
+  char *escaped_seg;
+  char *refname, *reffile, *refnode, *end;
+  char *href;
+
+  curlen = q - p;
+  tmp = (char *) g_malloc( curlen + 1 );
+  memcpy( tmp, p, curlen );
+  *(tmp+curlen) = '\000';
+
+  /* see if there is a reference in current line */
+  /* and make sure this isnt a '*Note*' instead ! */
+  ref_exists = 0;
+  if ((note_ptr=strstr(tmp, "*Note")) || (note_ptr=strstr(tmp, "*note")))
+    if (*(note_ptr+6) != '*')
+      ref_exists = 1;
+
+  if (ref_exists)
+    {
+      /* find the start of the link */
+      note_ptr = (note_ptr - tmp) + p;
+      match1 = note_ptr + 4;
+
+      /* not needed any more */
+      g_free(tmp);
+
+      for (; 1; )
+	if (*(match1+1) == ' ' || *(match1+1) == '\n')
+	  match1++;
+	else
+	  break;
+      
+      /* find end of the link */
+      if (parse_note_ref( match1, &refname, &reffile, &refnode, &end, 1))
+	{
+	  html_error( "Corrupt *Note link found!", p, q );
+	  return NULL;
+	}
+
+      /* now we assume that parse_note_ref left control chars in ref* */
+      /* if both null, we had a '::' and have to set both */
+      if (reffile == NULL && refnode == NULL)
+	{
+	  reffile = g_strdup(nodefile);
+	  refnode = g_strdup(refname);
+	}
+      /* otherwise we had (file)., and we set node to 'Top' */
+      else if (refnode == NULL)
+	refnode = g_strdup("Top");
+      /* otherwise we had :nodename., and we set node to 'Top' */
+      else if (reffile == NULL)
+	reffile = g_strdup(nodefile);
+      
+/* Here we need to escape everything up to Note.
+ * One caveat: The "*Note*" itself isn't escaped.  Currently we know this is
+ * okay ("*Note" has no characters needing escapes.) but....
+ */
+      curlen = note_ptr - p;
+      tmp = (char *) g_malloc (curlen + 1);
+      memcpy (tmp, p, curlen);
+      *(tmp + curlen) = '\000';
+      escaped_seg = escape_html_chars (tmp);
+      g_free (tmp);
+      
+      /* write out stuff up to Note */
+      fprintf(f, "%s", escaped_seg);
+      fprintf(f, "<STRONG>");
+      fwrite(note_ptr, 1, match1 - note_ptr, f);
+      fprintf(f, " </STRONG>");
+
+      /* we need a nice nodename -> filename translation */
+      /* so we convert newlines to spaces */
+      converted_nodename = g_strdup( refnode );
+      convert_newlines_to_spaces( converted_nodename );
+
+      /* we don't want two spaces in a row */
+      strip_dupspaces( converted_nodename );
+      map_spaces_to_underscores( converted_nodename );
+
+      /* escape HTML chars */
+      escaped_refname = escape_html_chars( refname );
+      escaped_refnode = escape_html_chars( refnode );
+
+      /* now output the link to html doc */
+#if 0
+      fprintf(f,"<A HREF=\"../%s/%s.html\">", reffile, converted_nodename);
+#endif
+      href = form_info_tag_href(reffile, converted_nodename);
+      fprintf(f,"<A %s>", href);
+      for (ptr=escaped_refname; *ptr; ptr++)
+	if (*ptr == '\n')
+	  {
+	    fprintf(f,"</A>\n");
+	    fprintf(f,"<A %s>", href);
+	  }
+	else
+	  fprintf(f,"%c", *ptr);
+	
+      if (strcmp(refname, refnode))
+	{
+	  fprintf(f,": ");
+	  for (ptr=escaped_refnode; *ptr; ptr++)
+	    if (*ptr == '\n')
+	      {
+		fprintf(f,"</A>\n");
+		fprintf(f,"<A %s>", href);
+	      }
+	    else
+	      fprintf(f,"%c", *ptr);
+
+	  fprintf(f,"</A>");
+	  if (end > q && !(strchr(refnode, '\n')))
+	    fprintf(f,"\n");
+	}
+      else
+	fprintf(f,"</A>");
+
+      if (href)
+	g_free(href);
+      if (escaped_refnode)
+	g_free(escaped_refnode);
+      if (escaped_refname)
+	g_free(escaped_refname);
+      if (converted_nodename)
+	g_free(converted_nodename);
+
+      g_free(escaped_seg);
+      g_free(refname);
+      g_free(reffile);
+      g_free(refnode);
+
+      /* write out stuff at end */
+      if (end < q)
+	{
+
+/* Escape up to the end of line. */
+      curlen = q - (end+1);
+      tmp = (char *) g_malloc (curlen + 1);
+      memcpy (tmp, end+1, curlen);
+      *(tmp+curlen) = '\000';
+      escaped_seg = escape_html_chars (tmp);
+      g_free (tmp);
+      
+      fprintf (f, "%s", escaped_seg);
+      fprintf (f, "\n");
+      g_free (escaped_seg);
+	  return NULL;
+	}
+      else
+	  return end+1;
+    }
+  else
+    {
+
+/* Escape the whole thing. */
+      escaped_seg = escape_html_chars (tmp);
+      fprintf (f, "%s", escaped_seg);
+      fprintf (f, "\n");
+      /* not needed any more */
+      g_free(tmp);
+      g_free (escaped_seg);
+      return NULL;
+    }
+}
+
+void open_menu_html( FILE *f, char *p )
+{
+  if (*p != '\000')
+    fprintf(f, "<H2>%s</H2>\n",p);
+  /*  fprintf(f, "<UL>\n"); */
+#if 0
+    fprintf(f, "<dl>\n"); 
+#else
+    if (inTable)
+	    fprintf(stderr, "In a table and starting new one!\n");
+    inTable = 1;
+    fprintf(f, "<table width=100%%><tr><td>&nbsp;</td></tr>\n");
+#endif
+}
+
+void close_menu_html( FILE *f )
+{
+  /* fprintf(f, "</UL>\n"); */
+#if 0
+    fprintf(f, "</dl>\n");
+#else
+    if (!inTable)
+	    fprintf(stderr, "Not in a table and closing one!\n");
+    inTable = 0;
+    fprintf(f, "</table>\n");
+#endif
+}
+
+/* writes menu entry contained in string p */
+/* nodename and nodefile apply to the node which menu entry is in */
+void write_menu_entry_html( FILE *f, char *p, char *nodefile, char **menu_end )
+{
+  char *refname;
+  char *reffile;
+  char *refnode;
+  char *end;
+  char *realend;
+  char *converted_nodename;
+  char *escaped_refnode;
+  char *escaped_refname;
+  char *href;
+
+  int i, done;
+
+  /* skip over the '* ' at the start of the line */
+  if (parse_menu_line( p+2, &refname, &reffile, &refnode, &end, 0 ))
+    {
+      html_error("Error parsing menu", p, memchr(p, '\n', 80));
+      return;
+    }
+
+  /* if both null, we had a '::' and have to set both */
+  if (reffile == NULL && refnode == NULL)
+    {
+      reffile = g_strdup(nodefile);
+      refnode = g_strdup(refname);
+    }
+  /* otherwise we had (file)., and we set node to 'Top' */
+  else if (refnode == NULL)
+    refnode = g_strdup("Top");
+  else if (reffile == NULL)
+    reffile = g_strdup(nodefile);
+
+  /* now find the end of the right hand text for this menu line */
+  /* it can continue for several lines                          */
+  done = 0;
+  for (realend = end+1; !done; realend++)
+    {
+      if (*realend == '\n')
+	{ 
+	  if (*(realend+1) == '\n')
+	    {
+	      done = 1;
+	      continue;
+	    }
+
+	  for (i=1; i<4; i++)
+	    if (!isspace(*(realend+i)) && *(realend+i) != '\n')
+	      {
+		done = 1;
+		break;
+	      }
+	}
+    }
+  *menu_end = realend;
+
+
+  converted_nodename = g_strdup( refnode );
+  map_spaces_to_underscores( converted_nodename );
+
+  escaped_refnode = escape_html_chars( refnode );
+  escaped_refname = escape_html_chars( refname );
+
+#if 0
+  fprintf(f,"<dt><A HREF=\"../%s/%s.html\">%s</A>\n",
+	  reffile, converted_nodename, escaped_refname);
+#endif
+
+  href = form_info_tag_href( reffile, converted_nodename );
+#if 0
+  fprintf(f,"<dt><A %s>%s</A>\n", href, escaped_refname );
+  fprintf(f,"<dd>");
+  if (*end == '.' && *(end+1) == '\n')
+    fprintf(f,"%s.\n",escaped_refnode);
+  else
+    fwrite(end+1, 1, *menu_end - end - 1, f);
+#else
+  fprintf(f,"<tr>\n\t<td width=30%%>\n\t\t<A %s>%s</A>\n\t</td>\n"
+	  "\t<td width=70%%>\n\t\t", 
+	  href, escaped_refname );
+  if (*end == '.' && *(end+1) == '\n')
+    fprintf(f,"%s.\n",escaped_refnode);
+  else
+    fwrite(end+1, 1, *menu_end - end - 1, f);
+  fprintf(f,"\n\t</td>\n</tr>\n");
+#endif
+
+  if (href)
+    g_free(href);
+  if (escaped_refname)
+    g_free(escaped_refname);
+  if (escaped_refnode)
+    g_free(escaped_refnode);
+  if (converted_nodename)
+    g_free(converted_nodename);
+  g_free(refname);
+  g_free(reffile);
+  g_free(refnode);
+}
+
+void write_html_horiz_rule( FILE *f )
+{
+  fprintf(f, "<HR>\n");
+}
diff --git a/help-converters/info/html.h b/help-converters/info/html.h
new file mode 100644
index 0000000..3237b47
--- /dev/null
+++ b/help-converters/info/html.h
@@ -0,0 +1,25 @@
+#ifndef HTML_H
+#define HTML_H
+
+#define HTML_ROOT "./htmltest"
+
+#define HEADER_SIZE_1 "H1"
+#define HEADER_SIZE_2 "H2"
+
+extern char *BaseFilename;
+extern char *OverrideBaseFilename;
+
+void dump_html_for_node( NODE *node );
+
+void open_body_text_html( FILE *f );
+void close_body_text_html( FILE *f );
+char *write_body_text_html( FILE *f, char *p, char *q, char *nodefile );
+
+void open_menu_html( FILE *f, char *p );
+void close_menu_html( FILE *f );
+void write_menu_entry_html( FILE *f, char *p, char *nodefile,char **menu_end );
+
+void write_header_html( FILE *f, char *p, char *hdr );
+
+void write_html_horiz_rule( FILE *f );
+#endif
diff --git a/help-converters/info/main.c b/help-converters/info/main.c
new file mode 100644
index 0000000..3381397
--- /dev/null
+++ b/help-converters/info/main.c
@@ -0,0 +1,286 @@
+/* little test main() to see how we're doing */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnome.h>
+#include <zlib.h>
+#ifdef HAVE_LIBBZ2
+#include <bzlib.h>
+#endif
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+
+#include "data.h"
+#include "html.h"
+#include "parse.h"
+#include "utils.h"
+#include "version.h"
+
+/* be quiet or not? */
+static int be_quiet=1;
+
+/* line_number we're on */
+static int work_line_number;
+static char *requested_nodename=NULL;
+static struct poptOption options[] = {
+  {NULL, 'a', POPT_ARG_STRING, &requested_nodename},
+  {NULL, 'b', POPT_ARG_STRING, &OverrideBaseFilename},
+  {NULL}
+};
+
+static int
+file_exists(const char *fn)
+{
+  struct stat sbuf;
+
+  return (stat(fn, &sbuf) == 0);
+}
+
+int
+main(int argc, char **argv)
+{
+	gzFile f = NULL;
+	int bz = 0;
+#ifdef HAVE_LIBBZ2
+	BZFILE *bf=NULL;
+#endif
+	char line[250];
+	poptContext ctx;
+	int result;
+	int foundit=0;
+	int i, n;
+
+	char convanc[1024];
+	NODE *node;
+
+	const char **args;
+	char *fixup_args[512];
+	int curarg;
+	
+	if (!be_quiet)
+		printf("info2html Version %s\n",INFO2HTML_VERSION);
+
+	ctx = poptGetContext("gnome-info2html2", argc, argv, options, 0);
+
+	while(poptGetNextOpt(ctx) >= 0)
+	  /**/ ;
+
+	args = poptGetArgs(ctx);
+	curarg = 0;
+	if(!args)
+	  return 1;
+
+	for(n = 0; args[n]; n++) /* */;
+	if(n == 1 && !file_exists(args[0]))
+	  {
+	    char *ctmp, *infopath = g_getenv("INFOPATH");
+	    char *dirs[64], *ext = NULL;
+	    int ndirs;
+	    char buf[PATH_MAX];
+
+	    /* First, find the directory that the info file is in. */
+	    dirs[0] = "/usr/info";
+	    dirs[1] = "/usr/share/info";
+	    /* We now have at least one directory to look in. This is
+	     * necessary because we may not have an 'INFOPATH' set */
+	    ndirs = 2;
+	    if(infopath)
+	      for(ndirs = 2, ctmp = strtok((char *)args[0], ":"); ndirs < 64 && ctmp; ndirs++, ctmp = strtok(NULL, ":"))
+		dirs[ndirs] = strdup(ctmp);
+
+	    for(i = 0; i < ndirs; i++)
+	      {
+		ext = "";
+		sprintf(buf, "%s/%s.info", dirs[i], args[0]);
+		if(file_exists(buf))
+		  break;
+		ext = ".gz";
+		sprintf(buf, "%s/%s.info.gz", dirs[i], args[0]);
+		if(file_exists(buf))
+		  break;
+#ifdef HAVE_LIBBZ2
+		ext = ".bz2";
+		sprintf(buf, "%s/%s.info.bz2", dirs[i], args[0]);		
+		if(file_exists(buf)) {
+		  bz = 1;
+		  break;
+		}
+#endif
+	      }
+	    if(i >= ndirs) {
+		    printf ("<HTML><HEAD><TITLE>Document not found</TITLE>\n"
+			    "</HEAD><BODY BGCOLOR=\"#FFFFFF\">The info document \"%s\" could not be found. It may have been removed from your system.\n"
+			    "</BODY></HTML>\n", args[0]);
+		    return 2;
+	    }
+
+	    n = i;
+
+	    for(i = 0; ; i++)
+	      {
+		if(i)
+		  sprintf(buf, "%s/%s.info-%d%s", dirs[n], args[0], i, ext);
+		else
+		  sprintf(buf, "%s/%s.info%s", dirs[n], args[0], ext);
+
+		if(!file_exists(buf))
+		  {
+		    fixup_args[i] = NULL;
+		    break;
+		  }
+
+		fixup_args[i] = strdup(buf);
+	      }
+	    args = (const char **)fixup_args;
+	  }
+	
+	if(requested_nodename)
+	  {
+	    char *s, *t;
+	    int  len;
+	    /* strip off quotes */
+	    for (s=requested_nodename; *s == '\"'; ) {
+	      len = strlen( s );
+	      memmove(s, s+1, len);
+	    }
+
+	    t = s + strlen(s) - 1;
+	    while (*t == '\"')
+	      t--;
+
+	    *(t+1) = '\0';
+
+	    /* convert anchor so matching works */
+	    map_spaces_to_underscores(requested_nodename);
+	  }
+
+	work_line_number = 0;
+
+	/* hack, just send to stdout for now */
+	fprintf(stdout, "<BODY><HTML>\n");
+	
+	/* big loop to identify sections of info files */
+	/* NEW PLAN - format on the fly */
+	/* No need to store all nodes, etc since we let web server */
+	/* handle resolving tags!                                  */
+	for (;1 || !foundit || !requested_nodename;) {
+	  if(bz)
+	    {
+#ifdef HAVE_LIBBZ2
+	      if(!bf)
+		{
+		  if(args && args[curarg])
+		    {
+		      bf = bzopen(args[curarg++], "r");
+		      if(!f)
+			break;
+		      num_files_left = args[curarg]?1:0;
+		      for(work_line_number = 0, bzread(bf, line, sizeof(line)); *line != INFO_COOKIE;
+			  bzread(bf, line, sizeof(line)), work_line_number++)
+			/**/ ;
+		    }
+		  else
+		    break;
+		}
+	      if(!bzread(bf, line, sizeof(line)))
+		{
+		  bzclose(bf);
+		  bf = NULL;
+		  continue;
+		}
+#else
+	      g_assert_not_reached();
+#endif
+	    }
+	  else
+	    {
+	      if(!f)
+		{
+		  if(args && args[curarg])
+		    {
+		      f = gzopen(args[curarg++], "r");
+		      if(!f)
+			break;
+		      num_files_left = args[curarg]?1:0;
+		      for(work_line_number = 0, gzgets(f, line, sizeof(line)); *line != INFO_COOKIE;
+			  gzgets(f, line, sizeof(line)), work_line_number++)
+			/**/ ;
+		    }
+		  else
+		    break;
+		}
+	      if(!gzgets(f, line, sizeof(line)))
+		{
+		  gzclose(f);
+		  f = NULL;
+		  continue;
+		}
+	    }
+		
+	  work_line_number++;
+		
+		/* found a node definition line */
+	  if (!strncmp(line, "File:", 5)) {
+	    node = alloc_node();
+	    result=read_node( f, line, node );
+	    if ( result == READ_ERR ) {
+	      fprintf(stderr, "Error reading the node "
+		      "contents\n");
+	      fprintf(stderr, "line was |%s|\n",line);
+	      continue;
+	    }
+			
+	    /* see if this is the requested node name */
+	    strncpy(convanc, node->nodename, sizeof(convanc));
+	    map_spaces_to_underscores(convanc);
+	    if (requested_nodename && 
+		strcmp(requested_nodename, convanc)) {
+#ifdef DEBUG			    
+	      fprintf(stderr, "skipping ->%s<-\n",
+		      node->nodename);
+#endif				
+
+	      continue;
+	    }
+
+	    foundit = 1;
+	    strcpy(work_node,node->nodename);
+
+	    BaseFilename = node->filename;
+#ifdef DEBUG
+	    printf("NEW NODE\n");
+	    printf("\tFile:|%s|\n\tNode:|%s|\n\tNext:|%s|\n",
+		   node->filename, node->nodename,node->next);
+	    printf("\tPrev:|%s|\n\tUp:|%s|\n\n", 
+		   node->prev, node->up);
+	    printf("-------------------------------------------"
+		   "-----------\n");
+#endif
+	    /* now lets make some html */
+	    dump_html_for_node( node );
+			
+	    if (node) {
+	      if ( node->contents )
+		free(node->contents);
+				
+	      g_free(node);
+	      BaseFilename = NULL;
+	    }
+	  }
+	  else
+	    continue;
+	}
+
+	if (!foundit && requested_nodename) {
+	  fprintf(stderr, "Requested node <b>%s</b> not found\n",
+		  requested_nodename);
+	  exit(1);
+	}
+
+	fprintf(stdout, "</BODY></HTML>\n");
+	return 0;
+}
diff --git a/help-converters/info/parse.c b/help-converters/info/parse.c
new file mode 100644
index 0000000..0177368
--- /dev/null
+++ b/help-converters/info/parse.c
@@ -0,0 +1,523 @@
+/* simple info file parser. */
+/* currently only finds nodes and contructs a tree */
+/* partially motivated by source code of the 'info' program */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <zlib.h>
+
+#include "parse.h"
+#include "data.h"
+#include "utils.h"
+
+int num_files_left;
+
+/* main routine to read in a node once we found its start in file f */
+/* assumes NODE has already been allocated */
+int read_node (gzFile f, char *line, NODE *node)
+{
+  /* we found a node line */
+  if (!parse_node_line( node, line ))
+    return (READ_ERR);
+
+  /* read in the contents, they go until a '\014', or a EOF */
+  return (read_node_contents( f, node ));
+}
+
+/* take a node definition and parse components */
+/* assumes that NODE has already been allocated */
+/* returns pointer to node if ok, or NULL on failure */
+NODE *parse_node_line( NODE *node, char * line )
+{
+  char *result;
+  char *temp;
+
+  /* fill in rest soon */
+  node->filename  = NULL;
+  node->nodename  = NULL;
+  node->contents  = NULL;
+  node->next      = NULL;
+  node->prev      = NULL;
+  node->up        = NULL;
+
+  temp = line;
+
+  /* have trouble on (dir) file which has a slightly diferrent 'File:' line */
+  /* so currently we have a hack here                                       */
+  if (!(result=parse_node_label( &temp, "File:", 0)))
+    return NULL;
+  node->filename = result;
+
+  /* don't allow_eof if we are looking at the 'dir' file, its a special case */
+  if (!(result=parse_node_label(&temp,"Node:",strcmp(node->filename, "dir"))))
+    return NULL;
+  node->nodename = result;
+
+  /* not clear any of the rest are actually necessary */
+  /* keep eye out for hitting end of line             */
+  if ((result=parse_node_label( &temp, "Next:", 1)))
+    node->next = result;
+
+  if ((result=parse_node_label( &temp, "Prev:", 1)))
+    node->prev = result;
+
+  if ((result=parse_node_label( &temp, "Up:", 1)))
+    node->up = result;
+
+  /* cleanup node filename */
+  fixup_info_filename( node->filename );
+
+  return node;
+}
+
+/* grab node name from the label 'label' */
+/* NULL means it doesn't exist */
+/* strdup's a string and returns it, which can be freed */
+char *parse_node_label( char **line, char *label, int allow_eof )
+{
+  char *start, *end;
+  char *temp;
+
+  temp = strdup( *line );
+
+  start = strstr( temp, label );
+  if (start == NULL)
+    return NULL;
+
+  start += strlen(label);
+  if (allow_eof)
+    {
+      end = strstr( start, "," );
+      if (end == NULL)
+	end = strstr( start, "\n" );
+    }
+  else {
+    end = strstr( start, "," );
+    if (!end)
+	    end = strstr( start, "\t" ); /* might help (dir) files */
+  }
+
+  if (end == NULL)
+    return NULL;
+
+  *end = '\000';
+  strip_spaces( start );
+  return start;
+}
+  
+
+/* from current position in file f, read till we hit EOF or */
+/* a end of node marker. Allocate space and set ptr to point at it */
+/* contents of node->contents is a mirror image of what was in  */
+/* the node (menus and all */
+/* assumes that NODE is already allocated */
+#define SEARCH_BUF_SIZE 1024
+#define CONTENTS_BUF_INCR 1024
+
+int read_node_contents( gzFile f, NODE *node )
+{
+  int nread;
+  int found;
+  char *searchbuf;
+  char *ptr;
+
+  char *tmpcontents;
+  int  tmpcontlen;
+  int  linelen;
+
+  char *status;
+
+  searchbuf = (char *) malloc( SEARCH_BUF_SIZE );
+  tmpcontents = (char *) malloc( CONTENTS_BUF_INCR );
+  tmpcontlen = CONTENTS_BUF_INCR;
+  nread = 0;
+
+  /* we read until we hit a '\014' or the end of file */
+  /* since its coming form a pipe we read up to EOL   */
+  /* and save contents as we go along                 */
+  for ( found=0 ; !found ; )
+    {
+      status=gzgets(f,  searchbuf, SEARCH_BUF_SIZE);
+      linelen = strlen( searchbuf );
+      for (found=0, ptr = searchbuf; *ptr && !found; ptr++)
+	if (*ptr == INFO_FF || *ptr == INFO_COOKIE)
+	    found=1;
+
+      /* if we didn't find the magic character, but hit eof, same deal */
+      if (!found && gzeof(f))
+	{
+	  found = 1;
+	  continue;
+	}
+
+      if ((nread+linelen+2) > tmpcontlen)
+	{
+	  tmpcontlen += CONTENTS_BUF_INCR;
+	  tmpcontents = realloc( tmpcontents, tmpcontlen );
+	}
+
+      memcpy(tmpcontents+nread, searchbuf, linelen);
+      nread += linelen;
+      if (!gzeof(f) || num_files_left)
+	*(tmpcontents+nread) = '\14';
+    }
+
+/*tmpcontents=realloc(tmpcontents, nread); */
+  node->contlen = nread;
+  node->contents = tmpcontents;
+  if (searchbuf)
+    free(searchbuf);
+  else
+    fprintf(stderr, "For some reason searchbuf is NULL\n");
+
+  return READ_OK;
+}
+
+/* given pointer to a string, tells us if its the line following */
+/* a info header line        */
+/* ex.                       */
+/*  This is a header         */
+/*  ================         */
+/* r points at the row of '='*/
+int is_a_hdr_line ( char *r )
+{
+ return (!strncmp(r, "***", 3) || 
+	 !strncmp(r, "===", 3) || 
+	 !strncmp(r, "---", 3) ||
+	 !strncmp(r, "...", 3));
+}
+
+
+/* returns 0 if good line found, non-0 otherwise */
+int parse_menu_line( char *line, char **refname, char **reffile,
+                     char **refnode, char **end_of_link,
+		     int span_lines)
+{
+  char *match;
+  char *match2;
+  char *start;
+  char *end_of_line;
+  char *end_refnode;
+  
+
+  start = line;
+  end_of_line = strchr( line, '\n' );
+  *end_of_link = NULL;
+
+  /* ok, we found a menu line, have to convert to a reference */
+  /* four types we worry about */
+  /* only care about stuff up to '.' OR second ':'            */
+  /* 1) 'Link::                   This is a link'             */
+  /* 2) 'Link: (file).            This is another link'       */
+  /* 3) 'Link: (file)node.        This is yet another'        */
+  /* 4) 'Link:                    node.'                      */
+      
+  /* found a variation on #4 in amdref.info-2 !               */
+  /* 5) 'Link:                    node:                       */
+
+  /* find the refname */
+  if (!(match=copy_to_anychar( start, ":", refname )))
+    return -1;
+  strip_spaces( *refname );
+  strip_dupspaces( *refname );
+  match++;
+
+  /* simple case is case #1 above */
+  if (*match == ':')
+    {
+      *reffile = NULL;
+      *refnode = NULL;
+      *end_of_link = match;
+      return 0;
+    }
+  else
+    {
+      /* look for parentheses */
+      match2 = strchr( match, '(' );
+      
+      /* this means it must be form 4 */
+      /* but dont look too far away */
+      /* this is a real hack - should do something more intelligent that 10 chars */
+      if (!match2 || (match2 - match) > 10)
+	{
+	  /* look for a ':' or '.' ending node */
+#if 0
+	  if (!(end_refnode=copy_to_anychar( match, ".", refnode )))
+	    if (!(end_refnode=copy_to_anychar( match, ":", refnode )))
+	      return -1;
+	  /* but it cant be past end of the menu line */
+	  if (end_refnode > end_of_line && !span_lines)
+	    return -1;
+#endif
+	  /* span_lines is ignored now we have parse_note_ref() */
+	  if (!(end_refnode=copy_to_anychar( match, "\n,.", refnode )))
+	    return -1;
+	  *end_of_link = end_refnode;
+	  strip_spaces( *refnode );
+	  strip_dupspaces( *refnode );
+	  if ( *refnode == '\000')
+	    {
+	      free(refnode);
+	      refnode = NULL;
+	    }
+	  *reffile = NULL;
+	  return 0;
+	}
+      else
+	{
+	  match2++;
+	  if (!(match=copy_to_anychar (match2, ")", reffile)))
+	    return -1;
+	  strip_spaces( *reffile );
+	  fixup_info_filename( *reffile );
+	  match++;
+	  /* unsure about having '\n' here */
+	  if (!(match=copy_to_anychar (match, "\n.,", refnode)))
+	    return -1;
+	  *end_of_link = match;
+	  strip_spaces( *refnode );
+	  strip_dupspaces( *refnode );
+	  strip_dupspaces( *refname );
+	  if (!(**refnode))
+	    *refnode = NULL;
+
+	  return 0;
+	}
+    }
+}
+
+/* used for *note and *Note refs */
+/* returns 0 if good line found, non-0 otherwise */
+int parse_note_ref( char *line, char **refname, char **reffile,
+                     char **refnode, char **end_of_link,
+		     int span_lines)
+{
+  char *match;
+  char *match2;
+  char *start;
+  char *end_of_line;
+  char *end_refnode;
+  
+
+  start = line;
+  end_of_line = strchr( line, '\n' );
+  *end_of_link = NULL;
+
+  /* ok, we found a menu line, have to convert to a reference */
+  /* four types we worry about */
+  /* only care about stuff up to '.' OR second ':'            */
+  /* 1) 'Link::                   This is a link'             */
+  /* 2) 'Link: (file).            This is another link'       */
+  /* 3) 'Link: (file)node.        This is yet another'        */
+  /* 4) 'Link:                    node.'                      */
+      
+  /* found a variation on #4 in amdref.info-2 !               */
+  /* 5) 'Link:                    node:                       */
+
+  /* find the refname */
+  if (!(match=copy_to_anychar( start, ":", refname )))
+    return -1;
+  strip_spaces( *refname );
+  strip_dupspaces( *refname );
+  match++;
+
+  /* simple case is case #1 above */
+  if (*match == ':')
+    {
+      *reffile = NULL;
+      *refnode = NULL;
+      *end_of_link = match;
+      return 0;
+    }
+  else
+    {
+      /* look for parentheses */
+      match2 = strchr( match, '(' );
+      
+      /* this means it must be form 4 */
+      /* but dont look too far away */
+      /* this is a real hack - should do something more intelligent that 10 chars */
+      if (!match2 || (match2 - match) > 10)
+	{
+	  /* look for a ',', ':' or '.' ending node */
+#if 0
+	  if (!(end_refnode=copy_to_anychar( match, ",", refnode )))
+	    if (!(end_refnode=copy_to_anychar( match, ".", refnode )))
+	      if (!(end_refnode=copy_to_anychar( match, ":", refnode )))
+#endif
+	  if (!(end_refnode=copy_to_anychar( match, ",.:", refnode )))
+		return -1;
+
+	  /* but it cant be past end of the menu line */
+	  if (end_refnode > end_of_line && !span_lines)
+	    return -1;
+
+	  *end_of_link = end_refnode;
+	  strip_spaces( *refnode );
+	  strip_dupspaces( *refnode );
+	  *reffile = NULL;
+	  return 0;
+	}
+      else
+	{
+	  match2++;
+	  if (!(match=copy_to_anychar (match2, ")", reffile)))
+	    return -1;
+	  strip_spaces( *reffile );
+	  fixup_info_filename( *reffile );
+	  match++;
+	  if (!(match=copy_to_anychar (match, ".,", refnode)))
+	    return -1;
+	  *end_of_link = match;
+	  strip_spaces( *refnode );
+	  strip_dupspaces( *refnode );
+	  strip_dupspaces( *refname );
+	  if (!(**refnode))
+	    *refnode = NULL;
+
+	  return 0;
+	}
+    }
+}
+
+
+/* old version 1.0 stuff */
+#if 0
+
+
+
+void scan_for_menu( NODE *node )
+{
+  char *ptr;
+  char *match;
+  char *line;
+  char *buf;
+  char *refname, *reffile, *refnode;
+  char *junk;
+
+  MENU_ENTRY *head;
+  
+  int  size;
+  int found;
+
+  NODE *newnode;
+  REFERENCE *newref;
+  MENU_ENTRY *newentry;
+  char menu_hdr[8192];
+  char *menu_hdr_ptr;
+
+  /* search for start of a menu */
+  size = node->contlen;
+  found = 0;
+  for (ptr = node->contents ; ptr < (node->contents+node->contlen) && !found;) 
+    {
+      line = get_line_from_contents( ptr, size );
+      match = strstr(line, MENU_START);
+      if (match)
+	{
+	  node->menu_start=ptr;
+	  found = 1;
+	}
+      size = size - strlen(line) - 1;
+      ptr += strlen(line) + 1;
+      free(line);
+    }
+  
+  if (!found)
+    return;
+
+  /* we found a menu start, lets read menu in now */
+  /* keep looking for entries till we hit a end-of-node condition */
+  head = NULL;
+  menu_hdr_ptr = menu_hdr;
+  for ( ; ptr < (node->contents+node->contlen); )
+    {
+      buf = get_line_from_contents( ptr, size );
+      line = buf;
+      size = size - strlen(line) - 1;
+      ptr += strlen(line) + 1;
+      
+      if (*line == '\000')
+	{
+	  free(buf);
+	  continue;
+	}
+
+      if (*line == INFO_FF || *line == INFO_COOKIE)
+	{
+	  free(buf);
+	  break;
+	}
+
+      /* see if its a new menu entry or not */
+      if (*line != '*')
+	{
+#if 0
+	  free(buf);
+	  break;
+#endif
+	  if ( (*line != '=') && (*line != '#') )
+	    {
+	      memcpy(menu_hdr_ptr, line, strlen(line));
+	      menu_hdr_ptr += strlen(line);
+	      *menu_hdr_ptr = '\n';
+	      menu_hdr_ptr++;
+	      *menu_hdr_ptr = '\0';
+	    }
+	  free(buf);
+	  continue;
+	}
+      else
+	{
+	  line += 2;
+
+	  if (parse_menu_line( line, &refname, &reffile, &refnode, &junk, 0 ))
+	    {
+	      free(buf);
+	      continue;
+	    }
+
+	  /* found the end of nodename, so make a new reference */
+	  newref = (REFERENCE *) malloc( sizeof(REFERENCE) );
+	  newref->refname = refname;
+
+	  newentry = (MENU_ENTRY *) malloc( sizeof(MENU_ENTRY) );
+	  newentry->ref = newref;
+	  if (menu_hdr_ptr != menu_hdr)
+	    {
+	      newentry->header = strdup(menu_hdr);
+	      menu_hdr_ptr = menu_hdr;
+	    }
+	  else
+	    newentry->header = NULL;
+	  newentry->next = NULL;
+
+	  newnode = (NODE *) malloc( sizeof(NODE) );
+	  newref->node = newnode;
+	  newnode->next = newnode->prev = newnode->up = NULL;
+	  if (refnode)
+	    newnode->nodename = refnode;
+	  else
+	    newnode->nodename = strdup(refname);
+
+	  if (reffile)
+	    newnode->filename = reffile;
+	  else
+	    newnode->filename = strdup(node->filename);
+
+	      
+	  if (head == NULL)
+	    node->menu = newentry;
+	  else
+	    head->next = newentry; 
+	  head = newentry;
+	}
+      free(buf);
+    }
+}
+
+
+
+#endif
diff --git a/help-converters/info/parse.h b/help-converters/info/parse.h
new file mode 100644
index 0000000..9f539a3
--- /dev/null
+++ b/help-converters/info/parse.h
@@ -0,0 +1,27 @@
+#ifndef PARSE_H
+#define PARSE_H
+
+#include <zlib.h>
+#include "data.h"
+
+#define READ_OK    1
+#define READ_EOF   2
+#define READ_ERR   0
+
+NODE *parse_node_line( NODE *node, char * line );
+char *parse_node_label( char **line, char *label, int allow_eof );
+int parse_menu_line( char *line, char **refname, char **reffile,
+                     char **refnode, char **end_of_link,
+		     int span_lines);
+
+int parse_note_ref( char *line, char **refname, char **reffile,
+                     char **refnode, char **end_of_link,
+		     int span_lines);
+
+int read_node_contents( gzFile f, NODE *node );
+int read_node (gzFile f, char *line, NODE *node);
+
+int is_a_hdr_line (char *r);
+extern int num_files_left;
+
+#endif /* PARSE_H  */
diff --git a/help-converters/info/utils.c b/help-converters/info/utils.c
new file mode 100644
index 0000000..5ab276a
--- /dev/null
+++ b/help-converters/info/utils.c
@@ -0,0 +1,275 @@
+/* various utility functions */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#include <glib.h>
+
+#include "data.h"
+#include "utils.h"
+
+void strip_spaces( char *str )
+{
+  int len;
+
+  len = strlen( str );
+  if (len < 1)
+    return;
+
+  while (*str == ' ')
+    {
+      len = strlen( str );
+      memmove(str, str+1, len);
+    }
+
+  len = strlen( str );
+  while (*(str+len) == '\n')
+    {
+      *(str+len) = '\000';
+      len = strlen( str );
+    }
+	  
+#if 0
+  q = str + strlen( str );
+  for (p=str; *p == ' ' || *p == '\t'; p++);
+  for (r=q-1; *r == ' ' || *r == '\t'; r--);
+  len = r - p + 1;
+  memmove( str, p, len );
+  *(str+len)='\000';
+#endif
+}
+
+void strip_newlines( char *str )
+{
+  char *p;
+  int len;
+
+  len = strlen( str );
+  if (len < 2)
+    return;
+
+  for (p=str; len > 0; len--)
+    if ( *p == '\n' )
+      {
+	if (len > 1)
+	  memmove(p , p+1, len );
+	else
+	  *p = '\000';
+      }
+    else
+      p++;
+}
+
+void strip_dupspaces( char *str )
+{
+  char *p;
+  int len;
+
+  len = strlen( str ) - 1;
+  if (len < 2)
+    return;
+
+  for (p=str+1; len > 0; len--)
+    if ( *p == ' ' && *(p-1) == ' ')
+      {  
+	if (len > 1)
+	  memmove(p , p+1, len );
+	else
+	  *p = '\000';
+      }
+    else
+      p++;
+}
+
+void convert_newlines_to_spaces( char *str )
+{
+  char *p;
+  int len;
+
+  /* trim head and trailing newlines */
+  while (*str == '\n')
+    {
+      len = strlen( str );
+      memmove(str, str+1, len);
+    }
+
+  len = strlen( str );
+  while (*(str+len) == '\n')
+    {
+      *(str+len) = '\000';
+      len = strlen( str );
+    }
+
+  len = strlen( str );
+  for (p=str; len > 0; len--, p++)
+    if ( *p == '\n' )
+      *p = ' ';
+}
+
+char * escape_html_chars( char *str )
+{
+  char *p;
+  char *q;
+  char tmp[2];
+  int len;
+
+  if (!str)
+    return NULL;
+
+  len = strlen( str );
+#if 0
+  if (len <2)
+    fprintf(stderr,"escaped less < 2 chars= |%s|\n",str);
+
+#endif
+
+  q = (char *) g_malloc( len * 5 + 4);
+  *q = '\000';
+  *(tmp+1) = '\000';
+  for (p=str; *p; p++)
+    if ( *p == '>' )
+      strcat(q, "&gt;");
+    else if ( *p == '<' )
+      strcat(q, "&lt;");
+    else if ( *p == '&' )
+      strcat(q, "&amp;");
+    else
+      {
+	*tmp = *p;
+	strcat(q, tmp);
+      }
+  return q;
+}
+
+
+char *get_line_from_contents( char *ptr, int size )
+{
+  char *eoln;
+  char *line;
+  int linelen;
+
+  eoln = memchr(ptr, '\n', size);
+  if (eoln == NULL)
+    return NULL;
+  
+  linelen = (eoln-ptr);
+  line = (char *) g_malloc( linelen+1 );
+  memcpy(line, ptr, linelen);
+  *(line+linelen) = '\000';
+  return line;
+}
+  
+/* copies from string str up to any character in chr */
+/* if chr doesn't exist, return NULL */
+/* otherwise return location of match */
+/* allocates a new string if anything copied */
+char *copy_to_anychar( char *str, char *chr, char **copy  )
+{
+  int len;
+  char *match;
+
+  match = strpbrk(str, chr);
+  if (!match)
+    return NULL;
+
+  len = match - str;
+  *copy = (char *) g_malloc( len+1 );
+  *(*copy+len) = '\000';
+  memcpy(*copy, str, len );
+  return match;
+}
+
+/* allocates a new node */
+NODE *alloc_node()
+{
+  NODE * tmp;
+
+  tmp = (NODE *) g_malloc( sizeof(NODE) );
+
+  if (tmp)
+    {
+      tmp->nodename=NULL;
+      tmp->filename=NULL;
+      tmp->contents=NULL;
+      tmp->contlen=0;
+      tmp->next=NULL;
+      tmp->prev=NULL;
+      tmp->up=NULL;
+      tmp->filename=NULL;
+      tmp->menu=NULL;
+      tmp->menu_start=NULL;
+    }
+  return tmp;
+}
+
+/* deallocates a new node */
+void free_node(NODE *tmp)
+{
+  if (tmp)
+    {
+      if (tmp->nodename)
+	g_free(tmp->nodename);
+      if (tmp->filename)
+	g_free(tmp->filename);
+      if (tmp->contents)
+	g_free(tmp->contents);
+    }
+  g_free(tmp);
+}
+
+#if 0
+void map_spaces_to_underscores( char *str )
+{
+  char *p;
+  
+  for (p=str; *p; p++)
+    if (*p == ' ')
+      *p = '_';
+}
+#endif
+
+void map_spaces_to_underscores( char *str )
+{
+  char *p;
+
+  for (p=str; *p; p++)
+    switch (*p)
+      {
+      case ' ':
+      case '\n':
+      case '\t':
+      case '`':
+      case '\'':
+      case '/': 
+      case '\\':
+      case '"':
+      case '.':
+      case '!':
+	*p = '_';
+	break;
+      }
+}
+
+
+  
+/* reduce infofile filename to basename alone */
+void fixup_info_filename( char *file )
+{
+  char *ptr1;
+  char tail[] = ".info";
+
+  if (strlen(file) < 6)
+    return;
+
+  ptr1 = strrchr( file, '.' );
+  if (!ptr1)
+    return;
+
+  if (!strncmp(ptr1, tail, strlen(tail)))
+    *ptr1 = '\000';
+
+}
+  
diff --git a/help-converters/info/utils.h b/help-converters/info/utils.h
new file mode 100644
index 0000000..25a964c
--- /dev/null
+++ b/help-converters/info/utils.h
@@ -0,0 +1,17 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#include "data.h"
+
+void strip_spaces( char *str );
+void strip_newlines( char *str );
+void strip_dupspaces( char *str );
+void convert_newlines_to_spaces( char *str );
+char *get_line_from_contents( char *ptr, int size );
+char *copy_to_anychar( char *str, char *chr, char **copy  );
+NODE *alloc_node( void );
+void free_node( NODE * );
+void map_spaces_to_underscores( char *str );
+void fixup_info_filename( char *file );
+char *escape_html_chars( char *str );
+#endif
diff --git a/help-converters/info/version.h b/help-converters/info/version.h
new file mode 100644
index 0000000..f1155c3
--- /dev/null
+++ b/help-converters/info/version.h
@@ -0,0 +1,6 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+#define INFO2HTML_VERSION "2.1"
+
+#endif
diff --git a/help-converters/man/Makefile.am b/help-converters/man/Makefile.am
new file mode 100644
index 0000000..004bee0
--- /dev/null
+++ b/help-converters/man/Makefile.am
@@ -0,0 +1,15 @@
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = 			\
+	-I$(includedir)		\
+	-I$(top_srcdir)/intl -I$(top_builddir)/intl
+
+
+LDADD = $(Z_LIBS) $(BZ_LIBS)
+
+bin_PROGRAMS = gnome-man2html2
+
+gnome_man2html2_SOURCES = gnome-man2html.c
+
+#CFLAGS += -Wall
+
diff --git a/help-converters/man/README b/help-converters/man/README
new file mode 100644
index 0000000..e3b79ac
--- /dev/null
+++ b/help-converters/man/README
@@ -0,0 +1,284 @@
+gnome-man2html2
+--------------
+
+Modified version of gnome-man2html2 by Elliot Lee <sopwith redhat com>
+- slight changes made to the man: URL's output, but otherwise it works
+perfectly.
+
+Modified version of VH-Man2html by Michael Fulbright <msf redhat com>
+
+Please do not contact the individuals below if you have problems with
+gnome-man2html2, instead send me an email and I'll try to help.
+
+The README for the original program lies below...
+
+
+VH-Man2html - Modified Verhoeven-man2html
+-----------------------------------------
+Michael Hamilton <michael actrix gen nz>
+http://www.actrix.gen.nz/users/michael
+
+vh = Richard Verhoeven's (rcb5 win tue nl) Man2html as modified and
+packaged by Michael Hamilton.
+
+Featues:
+  - Translate man pages to html from tbl/troff source.
+  - Look up a page by name and section or via full path name.
+  - Links generated html to other pages, include files, email addresses, 
+    and http refs.
+  - Name-title index built from man whatis info.
+  - Name only index built from inspecting the man directories.
+  - Full text search via glimpse (glimpse obtainable separately). 
+  - Works from man and BSD mandoc source files.
+  - Fast troff to HTML translator written in C.
+  - Copes with compressed (gzip etc) source.
+
+New in version 1.5:
+  - fix to mansec for compressed pages.
+  - make now configures ALL scripts, html files, and man pages.
+  - includes section 9.
+
+New in version 1.4:
+  - Uses /etc/man.config to obtain the man path.
+  - Man2html.c now uses decompression filters specified in /etc/man.config.
+  - Glimpse now uses decompression filters (see glimpse_filters file).
+    (Generating indexes will be be slower for compressed hierarchies.)
+  - Safer - more secure from memory overuns.  Man2html now checks for 
+    excessively long input parameters.
+  - All configuration can now be done by editing the Makefile and the
+    glimpse_filters file.
+  - By default (in version 1.4 and above) -M only allows the user to select 
+    what part of the hierarchy to search first - they cannot specify a path
+    outside of the official hierarchy.  Previously the -M option could be
+    used to retrieve any man/mandoc source file that had "man" in it's 
+    path-name/file-name (a compile time switch can restore the previous 
+    behaviour).
+  - Fixed more bugs.
+
+QUICK START INSTRUCTIONS
+------------------------
+
+To use these cgi scripts all you have to do is install the rpm and
+then point your web browser at
+
+ http://localhost/cgi-bin/man2html 
+
+You can either save this location as a bookmark or use an editor to
+insert the following lines into an appropriate place in
+/usr/doc/HTML/calderadoc/caldera.html (or somewhere like
+/home/httpd/index.html if you are using RedHat's http server)
+
+ <H3><A HREF="http:/cgi-bin/man2html"><IMG SRC="book2.gif">
+ Linux Manual Pages</A></H3>
+
+For some of the indexes to work you must generate the necessary
+databases...
+
+Vh-man2html's manwhatis CGI-script uses the /usr/man/whatis file to build
+a man page index.  Caldera 1.0 normally builds the /usr/man/whatis every
+morning at 3:21am.  If this job has never been run (perhaps because
+you turn your machine off at night), you can build it by becoming the
+root user and entering:
+
+ /usr/sbin/makewhatis /usr/man /usr/X11R6/man /usr/local/man
+
+WARNING: makewhatis in Caldera 1.0 takes about 30 minutes on my
+486DX66.  I have a modified version of makewhatis so that it does
+exactly the same job in only 1.5 minutes. My modified version is now
+available as part of man-1.4g (man-1.4g.tar.gz) and above:
+
+ ftp://sunsite.unc.edu/pub/Linux/system/Manual-pagers
+
+To use the Glimpse full text searching, you will need to install
+glimpse in /usr/bin.  Redhat rpm users can get glimpse from 
+
+ ftp://ftp.redhat.com/pub/non-free/glimpse-3.0-1.i386.rpm
+
+The glimpse home ftp site is cs.arizona.edu.  N.B. glimpse is not
+freely redistributable for commercial use, I'd be very interested in a
+more liberal alternative.  Having installed glimpse, you will need to
+build a glimpse index in /var/man2html.  This doesn't take too long -
+about 3 minutes on my 486DX2/66 16MB machine.  As root do:
+
+ /usr/bin/glimpseindex -z -H /var/man2html /usr/man/man* /usr/X11R6/man/man* \
+     /usr/local/man/man* /opt/man/man*
+ chmod ugo+r /var/man2html/.glimpse*
+
+The -z option causes glimpse to apply any filters (for decompression etc)
+specified in /var/man2html/.glimpse_filters.
+
+This could be set up as a cron job in /etc/crontab, e.g. (the following
+must be all on one line):
+
+  21 04 * * 1 root /usr/bin/glimpseindex -z -H /var/man2html /usr/man/man* 
+      /usr/X11R6/man/man* /usr/local/man/man* /opt/man/man* ;
+      chmod +r /var/man2html/.glimpse*
+
+If you don't want to use glimpse you can edit the man.html file that 
+the package installs in /home/http/html/man.html, and remove the 
+references to full text searches and glimpse.  This file can also be
+edited to include any local instructions you might wish to include.
+
+The scripts may generate errors to the httpd error log
+/var/log/httpd/error_log.  The man binary (used to obtain the man-path
+by some of the scripts) seems to always think it's talking to a tty,
+and tries to obtain the screen size, resulting in the following error
+log entries:
+
+  TIOCGWINSZ
+  failed : Bad file number
+
+To serve man pages to remote hosts, all that is required is a httpd 
+daemon that sets the environment variable SERVER_NAME correctly.
+
+END OF QUICK START INSTRUCTIONS
+-------------------------------
+
+Vh-man2html was was written by Richard Verhoeven (NL:5482ZX35) at
+the Eindhoven University of Technology (Email: rcb5 win tue nl).  The
+original source is available from his web page at:
+
+ http://wsinwp01.win.tue.nl:1234/maninfo.html
+
+There are other man2html programs around - Richard's page has links to
+several of them.  Richard's man2html has some useful features for
+Caldera/RedHat Linux -
+
+  Works from the troff/nroff source pages.
+    With linux we almost always have the man source.
+    Doesn't have to run man+tbl+eqn+nroff to generate output.
+    Because man isn't run, no catman pages are generated.
+    Accurate - doesn't have to guess from the man output.
+    Does tables (eg man ascii) (but doesn't do eqn - few pages use eqn).
+  Written in C - efficient speed/memory usage.
+    Fast enough not to need a cache.
+  Intelligent 
+    Makes good guesses on where to find pages.
+    Creates links for man pages and include files.
+
+Richard's original program copes with pages formatted with the man
+macros.  I've enhanced it by adding translations for the mandoc macros
+used in the BSD man pages.  BSD mandoc pages in Caldera/Redhat
+include Mail, ftp, telnet, rlogin, and lpr and other printer man
+pages - so they're pretty important.  
+
+I don't have any documentation on the mandoc macros, so I've had to
+guess what they intend, by looking at man source, man output and the
+gnroff macro definitions.  I've tested it on all the BSD mandoc pages
+in Section 1 that I could find.  It works reasonable well.  There are
+still minor formatting glitches to do with punctuation placement.
+I checked the BSD mandoc with weblint, e.g. in tcsh/csh
+
+ foreach i ( `egrep -l '^\.Bl' /usr/man/man1/* /usr/man/man8/*` )
+     /home/httpd/cgi-bin/man2html $i > tmp/`basename $i`
+ end
+ weblint tmp/*
+
+For broader testing:
+
+ find /usr/man/man* -name '*.[0-9]' \
+ -printf "echo %p; /home/httpd/cgi-bin/man2html %p |weblint -x netscape -\n" \
+ | sh \
+ |& tee weblint.log
+
+If you want to sample the spectrum of mandoc translation, look at
+any of the pages the above grep locates, telnet, lpc, and mail
+are good examples.
+
+For full details of my modifications to man2html.c see the patch
+included in the source archive.
+
+Here's a summary of the rpm's components:
+
+  1)  man.html       - Main page or access to man2html and man indexes.
+  2)  man2html       - CGI binary that converts man pages to html.
+  3)  manwhatis      - CGI script for a name and synopsis index organised
+                       by manual section
+  4)  mansec         - CGI script for a name only index for each section.
+  5)  mansearch      - Glimpse full text searching.
+  6)  mansearch.html - Main page or access to man2html and man indexes.
+  7)  netscape-man   - Front end that starts, or talks to, a running netscape.
+  8)  /var/ma2html   - Cache directory for indexes and glimpse indexes.
+
+All my scripts are written in awk.  In detail...
+
+The manwhatis script creates section contents html files by looking
+for whatis files along the man path.  Each whatis entry is translated
+to a man2html link.  Manwhatis caches it's output in
+/var/man2html/whatis-[0-9].html.  The cache will be regenerated if any
+whatis file in the man path is updated (eg touch /usr/man/whatis).
+
+The mansec script lists the names of all manual pages for a given
+section by using find on the man path.  It caches its output in
+/var/man2html/manindex-[0-9].html.  The cache will be regenerated if
+any associated man[0-9] directory in the man path is updated.
+
+The mansearch script uses glimpse to get back a list of files and
+matches which it links back to the actual man pages.  The mansearch
+script is not pure awk.  It's starts out as a shell script to ensure
+that the parameters are safely passed to awk.  I think it's secure,
+but I'm not a cgi script expert.
+
+To build and install man2html, the scripts, and man.html from the
+source archive - edit the Makefile and then:
+
+ make install
+
+To build binary and source rpms, placing them under /usr/src/...
+
+ make rpm
+
+SECURITY
+--------
+
+I've modified the man2html C code so that it checks all client input
+parameters for length and characters that need escaping.
+
+Man2html will only return man or mandoc files resident in the man
+hierarchy defined in /etc/man.config.
+
+When man2html generates references to include files they are in the
+form file: on the CLIENT host, not the server.
+
+The parameters to the decompression programs are checked for any
+nasties.
+
+It is still possible for the contents of a man page to over-run
+man2html's memory - so I guess a hacker might try to get you to
+install a bogus man page in order to get man2html to do something
+nasty.
+
+The scripts check their parameters for anything suspicious.
+
+The scripts and program write suspicious requests to stderr - so they
+can be found in web server log files.
+
+CREDITS
+-------
+
+See the man page man2html.8 for credits.
+
+---------------
+
+My modifications, packaging and scripts are copyright (c) 1996 
+Michael Hamilton (michael actrix gen nz).  All rights reserved.
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in all
+copies of this software.
+
+IN NO EVENT SHALL MICHAEL HAMILTON BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF MICHAEL
+HAMILTON HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+MICHAEL HAMILTON SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND MICHAEL HAMILTON HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+
+
+Michael
diff --git a/help-converters/man/gnome-man2html.c b/help-converters/man/gnome-man2html.c
new file mode 100644
index 0000000..b2afe3e
--- /dev/null
+++ b/help-converters/man/gnome-man2html.c
@@ -0,0 +1,3845 @@
+/*
+** This program was written by Richard Verhoeven (NL:5482ZX35)
+** at the Eindhoven University of Technology. Email: rcb5 win tue nl
+**
+** Permission is granted to distribute, modify and use this program as long
+** as this comment is not removed or changed.
+* In addition,
+*
+* Copyright (C) 1999 Red Hat Software
+* Changes licensed under the GNU Public License.
+*/
+
+/*
+ * gnome-man2html2
+ * This version modified for GNOME - December 1999
+ * Elliot Lee <sopwith redhat com>
+ * May this code live forever :)
+ */
+
+/* 
+ * gnome-man2html
+ * This version modified for GNOME - February 1998
+ * Michael Fulbright <msf redhat com>
+ */
+
+
+/* 
+ * man2html-linux-1.0/1.1
+ * This version modified for Redhat/Caldera linux - March 1996.
+ * Michael Hamilton <michael actrix gen nz>.
+ *
+ * man2html-linux-1.2
+ * Added support for BSD mandoc pages - I didn't have any documentation
+ * on the mandoc macros, so I may have missed some.
+ * Michael Hamilton <michael actrix gen nz>.
+ *
+ * vh-man2html-1.3
+ * Renamed to avoid confusion (V for Verhoeven, H for Hamilton).
+ *
+ * vh-man2html-1.4
+ * Now uses /etc/man.config
+ * Added support for compressed pages.
+ * Added "length-safe" string operations for client input parameters.
+ * More secure, -M secured, and client input string lengths checked.
+ *
+ */
+
+/*
+** If you want to use this program for your WWW server, adjust the line
+** which defines the CGIBASE or compile it with the -DCGIBASE='"..."' option.
+**
+** You have to adjust the built-in manpath to your local system. Note that
+** every directory should start and end with the '/' and that the first
+** directory should be "/" to allow a full path as an argument.
+**
+** The program first check if PATH_INFO contains some information.
+** If it does (t.i. man2html/some/thing is used), the program will look
+** for a manpage called PATH_INFO in the manpath.
+**
+** Otherwise the manpath is searched for the specified command line argument,
+** where the following options can be used:
+**
+** name      name of manpage (csh, printf, xv, troff)
+** section   the section (1 2 3 4 5 6 7 8 9 n l 1v ...)
+** -M path   an extra directory to look for manpages (replaces "/")
+**
+** If man2html finds multiple manpages that satisfy the options, an index
+** is displayed and the user can make a choice. If only one page is
+** found, that page will be displayed.
+**
+** man2html will add links to the converted manpages. The function add_links
+** is used for that. At the moment it will add links as follows, where   
+**     indicates what should match to start with:
+** ^^^
+** Recognition           Item            Link
+** ----------------------------------------------------------
+** name(*)               Manpage         ../man?/name.*
+**     ^
+** name hostname         Email address   mailto:name hostname
+**     ^
+** method://string       URL             method://string
+**       ^^^
+** www.host.name         WWW server      http://www.host.name
+** ^^^^
+** ftp.host.name         FTP server      ftp://ftp.host.name
+** ^^^^
+** <file.h>              Include file    file:/usr/include/file.h
+**      ^^^
+**
+** Since man2html does not check if manpages, hosts or email addresses exist,
+** some links might not work. For manpages, some extra checks are performed
+** to make sure not every () pair creates a link. Also out of date pages
+** might point to incorrect places.
+**
+** The program will not allow users to get system specific files, such as
+** /etc/passwd. It will check that "man" is part of the specified file and
+** that  "/../" isn't. Even if someone manages to get such file, man2html will
+** handle it like a manpage and will usually not produce any output (or crash).
+**
+** If you find any bugs when normal manpages are converted, please report
+** them to me (rcb5 win tue nl) after you have checked that man(1) can handle
+** the manpage correct.
+**
+** Known bugs and missing features:
+**
+**  * Equations are not converted at all.
+**  * Tables are converted but some features are not possible in html.
+**  * The tabbing environment is converted by counting characters and adding
+**    spaces. This might go wrong (outside <PRE>)
+**  * Some pages look beter if man2html works in troff mode, especially pages
+**    with tables. You can deside at compile time which made you want to use.
+**
+**    -DNROFF=0     troff mode
+**    -DNROFF=1     nroff mode   (default)
+**
+**    if you install both modes, you should compile with the correct CGIBASE.
+**  * Some manpages rely on the fact that troff/nroff is used to convert
+**    them and use features which are not descripted in the man manpages.
+**    (definitions, calculations, conditionals, requests). I can't guarantee
+**    that all these features work on all manpages. (I didn't have the
+**    time to look through all the available manpages.)
+*/
+
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <zlib.h>
+#ifdef HAVE_LIBBZ2
+#include <bzlib.h>
+#endif
+
+static char *URLbasename = NULL;
+
+#define NULL_TERMINATED(n) ((n) + 1)
+
+#define HUGE_STR_MAX  10000
+#define LARGE_STR_MAX 2000
+#define MED_STR_MAX   500
+#define SMALL_STR_MAX 100
+#define TINY_STR_MAX  10
+
+#define MAX_MAN_PATHS 100	/* Max number of directories */
+#define MAX_ZCATS     10	/* Max number of zcat style programs */
+#define MAX_WORDLIST  100
+
+#ifndef NROFF
+#define NROFF 1
+#endif
+
+/* timeformat for signature */
+#define TIMEFORMAT "%T GMT, %B %d, %Y"
+
+/* BSD mandoc Bl/El lists to HTML list types */
+#define BL_DESC_LIST   1
+#define BL_BULLET_LIST 2
+#define BL_ENUM_LIST   4
+
+/* BSD mandoc Bd/Ed example(?) blocks */
+#define BD_LITERAL  1
+#define BD_INDENT   2
+
+/* Don't bother with free(), it will just slow us down, the ultimate
+   free will be exit() anyway.  Hack to fix a malloc bug that I couldn't
+   track down (michael actrix gen nz).
+   */
+#define free(x)
+
+static char
+*stralloc(int len)
+{					
+	/* allocate enough for len + NULL */
+	char *new = malloc((len + 1) * sizeof(char));
+	if (!new) {
+		fprintf(stderr, "man2html: out of memory");
+		exit(EXIT_FAILURE);
+	}
+	return new;
+}
+
+static char
+*strmaxcpy(char *to, char *from, int n)
+{				/* Assumes space for n plus a null */
+	int len = strlen(from);
+	strncpy(to, from, n);
+	to[(len <= n) ? len : n] = '\0';
+	return to;
+}
+
+static char 
+*strlimitcpy(char *to, char *from, int n, int limit)
+{                               /* Assumes space for limit plus a null */
+	int len = n > limit ? limit : n;
+	strmaxcpy(to, from, len);
+	to[len] = '\0';
+	return to;
+}
+
+/* below this you should not change anything unless you know a lot
+** about this program or about troff.
+*/
+
+
+typedef struct STRDEF STRDEF;
+struct STRDEF {
+    int nr,slen;
+    char *st;
+    STRDEF *next;
+};
+
+typedef struct INTDEF INTDEF;
+struct INTDEF {
+    int nr;
+    int val;
+    int incr;
+    INTDEF *next;
+};
+
+static char NEWLINE[2]="\n";
+static char idxlabel[6] = "ixAAA";
+
+#define INDEXFILE "/tmp/manindex.list"
+
+static char *fname;
+
+#ifdef MAXINDEX
+static FILE *idxfile;
+#endif
+
+static STRDEF *chardef, *strdef, *defdef;
+static INTDEF *intdef;
+
+#define V(A,B) ((A)*256+(B))
+
+static INTDEF standardint[] = {
+    { V('n',' '), NROFF,0, NULL },
+    { V('t',' '), 1-NROFF,0, NULL },
+    { V('o',' '), 1,0, NULL },
+    { V('e',' '), 0,0, NULL },
+    { V('.','l'), 70,0,NULL },
+    { V('.','$'), 0,0, NULL },
+    { V('.','A'), NROFF,0, NULL },
+    { V('.','T'), 1-NROFF,0, NULL },
+    { V('.','V'), 1,0, NULL }, /* the me package tests for this */
+    { 0, 0, 0, NULL } };
+
+static STRDEF standardstring[] = {
+    { V('R',' '), 1, "&#174;", NULL },
+    { V('l','q'), 2, "``", NULL },
+    { V('r','q'), 2, "''", NULL },
+    { 0, 0, NULL, NULL}
+};
+
+
+static STRDEF standardchar[] = {
+    { V('*','*'), 1, "*", NULL  },
+    { V('*','A'), 1, "A", NULL  },
+    { V('*','B'), 1, "B", NULL  },
+    { V('*','C'), 2, "Xi", NULL  },
+    { V('*','D'), 5, "Delta", NULL  },
+    { V('*','E'), 1, "E", NULL  },
+    { V('*','F'), 3, "Phi", NULL  },
+    { V('*','G'), 5, "Gamma", NULL  },
+    { V('*','H'), 5, "Theta", NULL  },
+    { V('*','I'), 1, "I", NULL  },
+    { V('*','K'), 1, "K", NULL  },
+    { V('*','L'), 6, "Lambda", NULL  },
+    { V('*','M'), 1, "M", NULL  },
+    { V('*','N'), 1, "N", NULL  },
+    { V('*','O'), 1, "O", NULL  },
+    { V('*','P'), 2, "Pi", NULL  },
+    { V('*','Q'), 3, "Psi", NULL  },
+    { V('*','R'), 1, "P", NULL  },
+    { V('*','S'), 5, "Sigma", NULL  },
+    { V('*','T'), 1, "T", NULL  },
+    { V('*','U'), 1, "Y", NULL  },
+    { V('*','W'), 5, "Omega", NULL  },
+    { V('*','X'), 1, "X", NULL  },
+    { V('*','Y'), 1, "H", NULL  },
+    { V('*','Z'), 1, "Z", NULL  },
+    { V('*','a'), 5, "alpha", NULL },
+    { V('*','b'), 4, "beta", NULL },
+    { V('*','c'), 2, "xi", NULL },
+    { V('*','d'), 5, "delta", NULL },
+    { V('*','e'), 7, "epsilon", NULL },
+    { V('*','f'), 3, "phi", NULL },
+    { V('*','g'), 5, "gamma", NULL },
+    { V('*','h'), 5, "theta", NULL },
+    { V('*','i'), 4, "iota", NULL },
+    { V('*','k'), 5, "kappa", NULL },
+    { V('*','l'), 6, "lambda", NULL },
+    { V('*','m'), 1, "&#181;", NULL  },
+    { V('*','n'), 2, "nu", NULL },
+    { V('*','o'), 1, "o", NULL },
+    { V('*','p'), 2, "pi", NULL },
+    { V('*','q'), 3, "psi", NULL },
+    { V('*','r'), 3, "rho", NULL },
+    { V('*','s'), 5, "sigma", NULL },
+    { V('*','t'), 3, "tau", NULL },
+    { V('*','u'), 7, "upsilon", NULL },
+    { V('*','w'), 5, "omega", NULL },
+    { V('*','x'), 3, "chi", NULL },
+    { V('*','y'), 3, "eta", NULL },
+    { V('*','z'), 4, "zeta", NULL },
+    { V('t','s'), 5, "sigma", NULL },
+    { V('+','-'), 1, "&#177;", NULL  },
+    { V('1','2'), 1, "&#189;", NULL  },
+    { V('1','4'), 1, "&#188;", NULL  },
+    { V('3','4'), 1, "&#190;", NULL  },
+    { V('F','i'), 3, "ffi", NULL  },
+    { V('F','l'), 3, "ffl", NULL  },
+    { V('a','a'), 1, "&#180;", NULL  },
+    { V('a','p'), 1, "~", NULL  },
+    { V('b','r'), 1, "|", NULL  },
+    { V('b','u'), 1, "*", NULL  },
+    { V('b','v'), 1, "|", NULL  },
+    { V('c','i'), 1, "o", NULL  },
+    { V('c','o'), 1, "&#169;", NULL  },
+    { V('c','t'), 1, "&#162;", NULL  },
+    { V('d','e'), 1, "&#176;", NULL  },
+    { V('d','g'), 1, "+", NULL  },
+    { V('d','i'), 1, "&#247;", NULL  },
+    { V('e','m'), 1, "-", NULL  },
+    { V('e','m'), 3, "---", NULL },
+    { V('e','q'), 1, "=", NULL  },
+    { V('e','s'), 1, "&#216;", NULL  },
+    { V('f','f'), 2, "ff", NULL  },
+    { V('f','i'), 2, "fi", NULL  },
+    { V('f','l'), 2, "fl", NULL  },
+    { V('f','m'), 1, "&#180;", NULL  },
+    { V('g','a'), 1, "`", NULL  },
+    { V('h','y'), 1, "-", NULL  },
+    { V('l','c'), 2, "|&#175;", NULL  },
+    { V('l','f'), 2, "|_", NULL  },
+    { V('l','k'), 1, "<FONT SIZE=+2>{</FONT>", NULL  },
+    { V('m','i'), 1, "-", NULL  },
+    { V('m','u'), 1, "&#215;", NULL  },
+    { V('n','o'), 1, "&#172;", NULL  },
+    { V('o','r'), 1, "|", NULL  },
+    { V('p','l'), 1, "+", NULL  },
+    { V('r','c'), 2, "&#175;|", NULL  },
+    { V('r','f'), 2, "_|", NULL  },
+    { V('r','g'), 1, "&#174;", NULL  },
+    { V('r','k'), 1, "<FONT SIZE=+2>}</FONT>", NULL  },
+    { V('r','n'), 1, "&#175;", NULL  },
+    { V('r','u'), 1, "_", NULL  },
+    { V('s','c'), 1, "&#167;", NULL  },
+    { V('s','l'), 1, "/", NULL  },
+    { V('s','q'), 2, "[]", NULL  },
+    { V('u','l'), 1, "_", NULL  },
+    { 0, 0, NULL, NULL  }
+};
+
+/* default: print code */
+
+
+static char escapesym='\\', nobreaksym='\'', controlsym='.', fieldsym=0, padsym=0;
+
+static gzFile infh = NULL;
+#ifdef HAVE_LIBBZ2
+static BZFILE * inbfh = NULL;
+#endif
+static char *buffer=NULL;
+static int buffpos=0, buffmax=0;
+static int scaninbuff=0;
+static int itemdepth=0;
+static int dl_set[20]= { 0 };
+static int still_dd=0;
+static int tabstops[20] = { 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96 };
+static int maxtstop=12;
+static int curpos=0;
+
+static char *scan_troff(char *c, int san, char **result);
+static char *scan_troff_mandoc(char *c, int san, char **result);
+
+static char **argument=NULL;
+
+static char charb[TINY_STR_MAX];
+
+static char
+*expand_char(int nr)
+{
+	STRDEF *h;
+	h=chardef;
+	if (!nr) return NULL;
+	while (h)
+		if (h->nr==nr) {
+			curpos+=h->slen;
+			return h->st;
+		} else
+			h=h->next;
+	charb[0]=nr/256;
+	charb[1]=nr%256;
+	charb[2]='\0';  
+	if (charb[0] == '<') {	/* Fix up <= */
+		charb[4] = charb[1];
+		strncpy(charb, "&lt;", 4);
+		charb[5] = '\0';
+	}
+	curpos+=2;
+	return charb;
+}
+
+static char
+*expand_string(int nr)
+{
+	STRDEF *h=strdef;
+	if (!nr) return NULL;
+	while (h)
+		if (h->nr==nr) {
+			curpos+=h->slen;
+			return h->st;
+		} else
+			h=h->next;
+	return NULL;
+}
+
+/* msf - this will become real simple, as we read from stdin all the time */
+/*       and it is always uncompressed                                    */
+static char
+*read_man_page(void) 
+{
+	char *man_buf = NULL;
+	char buf[8192];
+	int buf_size = 0;
+	int bytes;
+
+	/* input from stdin */
+#ifdef HAVE_LIBBZ2
+	if (inbfh) 
+	  bytes = bzread(inbfh, buf, sizeof(buf));
+	else
+#endif
+	  bytes = gzread(infh, buf, sizeof(buf));
+	while (bytes > 0) {
+		if (!man_buf) {
+			man_buf = malloc(bytes+1);
+			man_buf[0] = '\n';
+			buf_size = 1;
+		} else {
+			man_buf = realloc(man_buf, bytes+buf_size);
+		}
+
+		memcpy(man_buf+buf_size, buf, bytes);
+		buf_size += bytes;
+#ifdef HAVE_LIBBZ2
+		if (inbfh) 
+		  bytes = bzread(inbfh, buf, sizeof(buf));
+		else
+#endif
+		bytes = gzread(infh, buf, sizeof(buf));
+	}
+
+	if (man_buf) {
+			man_buf = realloc(man_buf, buf_size+2);
+			man_buf[buf_size]   = '\n';
+			man_buf[buf_size+1] = '\0';
+	}
+
+	return man_buf;
+}
+
+
+static char outbuffer[NULL_TERMINATED(HUGE_STR_MAX)];
+static int obp=0;
+static int no_newline_output=0;
+static int newline_for_fun=0;
+static int output_possible=0;
+static int out_length=0;
+
+/*
+** Add the links to the output.
+** At the moment the following are recognized:
+**
+** name(*)                 -> ../man?/name.*
+** method://string         -> method://string
+** www.host.name           -> http://www.host.name
+** ftp.host.name           -> ftp://ftp.host.name
+** name host               -> mailto:name host
+** <name.h>                -> file:/usr/include/name.h   (guess)
+**
+** Other possible links to add in the future:
+**
+** /dir/dir/file  -> file:/dir/dir/file
+*/
+static void
+add_links(char *c)
+{
+	int i,j,nr;
+	char *f, *g,*h;
+	char *idtest[6]; /* url, mailto, www, ftp, manpage */
+	out_length+=strlen(c);
+
+	/* search for (section) */
+	nr=0;
+	idtest[0]=strstr(c+1,"://");
+	idtest[1]=strchr(c+1,'@');
+	idtest[2]=strstr(c,"www.");
+	idtest[3]=strstr(c,"ftp.");
+	idtest[4]=strchr(c+1,'(');
+	idtest[5]=strstr(c+1,".h&gt;");
+	for (i=0; i<6; i++) nr += (idtest[i]!=NULL);
+	while (nr) {
+		j=-1;
+		for (i=0; i<6; i++)
+			if (idtest[i] && (j<0 || idtest[i]<idtest[j])) j=i;
+		switch (j) {
+		case 5: /* <name.h> */
+			f=idtest[5];
+			h=f+2;
+			g=f;
+			while (g>c && g[-1]!=';') g--;
+			if (g!=c) {
+				char t;
+				t=*g;
+				*g='\0';
+				fputs(c, stdout);
+				*g=t;*h='\0';
+				printf("<A HREF=\"file:/usr/include/%s\">%s</A>&gt;", g,g);
+				c=f+6;
+			} else {
+				f[5]='\0';
+				fputs(c, stdout);
+				f[5]=';';
+				c=f+5;
+			}
+			break;
+		case 4: /* manpage */
+			f=idtest[j];
+			/* check section */
+			g=strchr(f,')');
+			if (g && f-g<6 && (isalnum(f[-1]) || f[-1]=='>') &&
+			    ((isdigit(f[1]) && f[1]!='0' &&
+			      (f[2]==')' || (isalpha(f[2]) && f[3]==')') ||
+			       f[2]=='X')) ||
+			     (f[2]==')' && (f[1]=='n' || f[1]=='l')))) {
+				/* this might be a link */
+				h=f-1;
+				/* skip html makeup */
+				while (h>c && *h=='>') {
+					while (h!=c && *h!='<') h--;
+					if (h!=c) h--;
+				}
+				if (isalnum(*h)) {
+					char t,sec,subsec, *e;
+					e=h+1;
+					sec=f[1];
+					subsec=f[2];
+					if ((subsec=='X' && f[3]!=')') ||
+					    subsec==')') subsec='\0';
+					while (h>c && (isalnum(h[-1]) ||
+						       h[-1]=='_' ||
+						       h[-1]=='-' || 
+						       h[-1]=='.'))
+						h--;
+					t=*h;
+					*h='\0';
+					fputs(c, stdout);
+					*h=t;
+					t=*e;
+					*e='\0';
+/* old code using file: */
+#if 0
+					if (subsec)
+						/* change to whatever you're using */
+						printf("<A HREF=\""
+						       "file:/usr/man/man%c/%s.%c%c\">%s</A>", 
+						       sec, h, sec, tolower(subsec), h);
+					else
+						printf("<A HREF=\""
+						       "file:/usr/man/man%c/%s.%c\">%s</A>", 
+						       sec, h, sec, h);
+#else
+					/* The code used to take
+					   'subsec' into account, but
+					   (a) 'subsec' can be more than
+					   one character (b) We have
+					   no use for that information */
+
+					printf("<A HREF=\"man:"
+					       "%s.%c\">%s</A>",
+					       h, sec,
+					       h);
+#endif
+					*e=t;
+					c=e;
+				}
+			}
+			*f='\0';
+			fputs(c, stdout);
+			*f='(';
+			idtest[4]=f-1;
+			c=f;
+			break; /* manpage */
+		case 3: /* ftp */
+		case 2: /* www */
+			g=f=idtest[j];
+			while (*g && (isalnum(*g) || *g=='_' || *g=='-' 
+				      || *g=='+' ||
+				      *g=='.')) g++;
+			if (g[-1]=='.') g--;
+			if (g-f>4) {
+				char t;
+				t=*f; *f='\0';
+				fputs(c, stdout);
+				*f=t; t=*g;*g='\0';
+				printf("<A HREF=\"%s://%s\">%s</A>", 
+				       (j==3?"ftp":"http"),
+				       f,f);
+				*g=t;
+				c=g;
+			} else {
+				f[3]='\0';
+				fputs(c, stdout);
+				c=f+3;
+				f[3]='.';
+			}
+			break;
+		case 1: /* mailto */
+			g=f=idtest[1];
+			while (g>c && (isalnum(g[-1]) || g[-1]=='_' 
+				       || g[-1]=='-' ||
+				       g[-1]=='+' || g[-1]=='.' 
+				       || g[-1]=='%')) g--;
+			h=f+1;
+			while (*h && (isalnum(*h) || *h=='_' || *h=='-' 
+				      || *h=='+' ||
+				      *h=='.')) h++;
+			if (*h=='.') h--;
+			if (h-f>4 && f-g>1) {
+				char t;
+				t=*g;
+				*g='\0';
+				fputs(c, stdout);
+				*g=t;t=*h;*h='\0';
+				printf("<A HREF=\"mailto:%s\";>%s</A>",g,g);
+				*h=t;
+				c=h;
+			} else {
+				*f='\0';
+				fputs(c, stdout);
+				*f='@';
+				idtest[1]=c;
+				c=f;
+			}
+			break;
+		case 0: /* url */
+			g=f=idtest[0];
+			while (g>c && isalpha(g[-1]) && islower(g[-1])) g--;
+			h=f+3;
+			while (*h && !isspace(*h) && *h!='<' && *h!='>' 
+			       && *h!='"' &&
+			       *h!='&') h++;
+			if (f-g>2 && f-g<7 && h-f>3) {
+				char t;
+				t=*g;
+				*g='\0';
+				fputs(c, stdout);
+				*g=t; t=*h; *h='\0';
+				printf("<A HREF=\"%s\">%s</A>", g,g);
+				*h=t;
+				c=h;
+			} else {
+				f[1]='\0';
+				fputs(c, stdout);
+				f[1]='/';
+				c=f+1;
+			}
+			break;
+		default:
+			break;
+		}
+		nr=0;
+		if (idtest[0] && idtest[0]<c) idtest[0]=strstr(c+1,"://");
+		if (idtest[1] && idtest[1]<c) idtest[1]=strchr(c+1,'@');
+		if (idtest[2] && idtest[2]<c) idtest[2]=strstr(c,"www.");
+		if (idtest[3] && idtest[3]<c) idtest[3]=strstr(c,"ftp.");
+		if (idtest[4] && idtest[4]<c) idtest[4]=strchr(c+1,'(');
+		if (idtest[5] && idtest[5]<c) idtest[5]=strstr(c+1,".h&gt;");
+		for (i=0; i<6; i++) nr += (idtest[i]!=NULL);
+	}
+	fputs(c, stdout);
+}
+
+static int current_font=0;
+static int current_size=0;
+static int fillout=1;
+
+static void
+out_html(char *c)
+{
+	if (!c) return;
+	if (no_newline_output) {
+		int i=0;
+		no_newline_output=1;
+		while (c[i]) {
+			if (!no_newline_output) c[i-1]=c[i];
+			if (c[i]=='\n') no_newline_output=0;
+			i++;
+		}
+		if (!no_newline_output) c[i-1]=0;
+	}
+	if (scaninbuff) {
+		while (*c) {
+			if (buffpos>=buffmax) {
+				char *h;
+				h=realloc(buffer, buffmax*2);
+				if (!h) return;
+				buffer=h;
+				buffmax=buffmax*2;
+			}
+			buffer[buffpos++]=*c++;
+		}
+	} else
+		if (output_possible) {
+			while (*c) {
+				outbuffer[obp++]=*c;
+				if (*c=='\n' || obp > HUGE_STR_MAX) {
+					outbuffer[obp]='\0';
+					add_links(outbuffer);
+					obp=0;
+				}
+				c++;
+			}
+		}
+}
+
+#define FO0 ""
+#define FC0 ""
+#define FO1 "<I>"
+#define FC1 "</I>"
+#define FO2 "<B>"
+#define FC2 "</B>"
+#define FO3 "<TT>"
+#define FC3 "</TT>"
+
+static char *switchfont[16] = { ""     , FC0 FO1, FC0 FO2, FC0 FO3,
+			 FC1 FO0, ""     , FC1 FO2, FC1 FO3,
+			 FC2 FO0, FC2 FO1, ""     , FC2 FO3,
+			 FC3 FO0, FC3 FO1, FC3 FO2, ""      };
+
+static char
+*change_to_font(int nr)
+{
+	int i;
+	switch (nr) {
+	case '0': nr++;
+	case '1': case '2': case '3': case '4': nr=nr-'1'; break;
+	case V('C','W'): nr=3; break;
+	case 'L': nr=3; break;
+	case 'B': nr=2; break;
+	case 'I': nr=1; break;
+	case 'P': case 'R': nr=0; break;
+	case 0: case 1: case 2: case 3: break;
+	default: nr=0; break;
+	}
+	i= current_font*4+nr%4;
+	current_font=nr%4;
+	return switchfont[i];
+}
+
+static char sizebuf[200];
+
+static char
+*change_to_size(int nr)
+{
+	int i;
+	switch (nr) {
+	case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+	case '7': case '8': case '9': nr=nr-'0'; break;
+	case '\0': break;
+	default: nr=current_size+nr; if (nr>9) nr=9; if (nr< -9) nr=-9; break;
+	}
+	if (nr==current_size) return "";
+	i=current_font;
+	sizebuf[0]='\0';
+	strcat(sizebuf, change_to_font(0));
+	if (current_size) strcat(sizebuf, "</FONT>");
+	current_size=nr;
+	if (nr) {
+		int l;
+		strcat(sizebuf, "<FONT SIZE=");
+		l=strlen(sizebuf);
+		if (nr>0) sizebuf[l++]='+'; else sizebuf[l++]='-',nr=-nr;
+		sizebuf[l++]=nr+'0';
+		sizebuf[l++]='>';
+		sizebuf[l]='\0';
+	}
+	strcat(sizebuf, change_to_font(i));
+	return sizebuf;
+}
+
+static int intresult=0;
+
+#define SKIPEOL while (*c && *c++!='\n')
+
+static int skip_escape=0;
+static int single_escape=0;
+
+static char
+*scan_escape(char *c)
+{
+	char *h=NULL;
+	char b[5];
+	INTDEF *intd;
+	int exoutputp,exskipescape;
+	int i,j;
+
+	intresult=0;
+	switch (*c) {
+	case 'e': h="\\"; curpos++;break;
+	case '0':
+	case ' ': h="&nbsp;";curpos++; break;
+	case '|': h=""; break;
+	case '"': SKIPEOL; c--; h=""; break;
+	case '$':
+		if (argument) {
+			c++;
+			i=(*c -'1');
+			if (!(h=argument[i])) h="";
+		}
+		break;
+	case 'z':
+		c++;
+		if (*c=='\\') { c=scan_escape(c+1); c--;h=""; }
+		else {
+			b[0]=*c;
+			b[1]='\0';
+			h="";
+		}
+		break;
+	case 'k': c++; if (*c=='(') c+=2;
+	case '^':
+	case '!':
+	case '%':
+	case 'a':
+	case 'd':
+	case 'r':
+	case 'u':
+	case '\n':
+	case '&': h=""; break;
+	case '(':
+		c++;
+		i= c[0]*256+c[1];
+		c++;
+		h = expand_char(i);
+		break;
+	case '*':
+		c++;
+		if (*c=='(') {
+			c++;
+			i= c[0]*256+c[1];
+			c++;
+		} else
+			i= *c *256+' ';
+		h = expand_string(i);
+		break;
+	case 'f':
+		c++;	
+		if (*c=='\\') {
+			c++;
+			c=scan_escape(c);
+			c--;
+			i=intresult;
+		} else 	if (*c != '(')
+			i=*c;
+		else {
+			c++;
+			i=c[0]*256+c[1];
+			c++;
+		}
+		if (!skip_escape) h=change_to_font(i); else h="";
+		break;
+	case 's':
+		c++;
+		j=0;i=0;
+		if (*c=='-') {j= -1; c++;} else if (*c=='+') {j=1; c++;}
+		if (*c=='0') c++; else if (*c=='\\') {
+			c++;
+			c=scan_escape(c);
+			i=intresult; if (!j) j=1;
+		} else
+			while (isdigit(*c) && (!i || (!j && i<4)))
+				i=i*10+(*c++)-'0';
+		if (!j) { j=1; if (i) i=i-10; }
+		if (!skip_escape)
+			h=change_to_size(i*j);
+		else
+			h="";
+		c--;
+		break;
+	case 'n':
+		c++;
+		j=0;
+		switch (*c) {
+		case '+': j=1; c++; break;
+		case '-': j=-1; c++; break;
+		default: break;
+		}
+		if (*c=='(') {
+			c++;
+			i=V(c[0],c[1]);
+			c=c+1;
+		} else {
+			i=V(c[0],' ');
+		}
+		intd=intdef;
+		while (intd && intd->nr!=i)
+			intd=intd->next;
+		if (intd) {
+			intd->val=intd->val+j*intd->incr;
+			intresult=intd->val;
+		} else {
+			switch (i) {
+			case V('.','s'): intresult=current_size; break;
+			case V('.','f'): intresult=current_font; break;
+			default: intresult=0; break;
+			}
+		}
+		h="";
+		break;
+	case 'w':
+		c++;
+		i=*c;
+		c++;
+		exoutputp=output_possible;
+		exskipescape=skip_escape;
+		output_possible=0;
+		skip_escape=1;
+		j=0;
+		while (*c!=i) {
+			j++;
+			if (*c==escapesym)
+				c=scan_escape(c+1); 
+			else
+				c++;
+		}
+		output_possible=exoutputp;
+		skip_escape=exskipescape;
+		intresult=j;
+		break;
+	case 'l': h="<HR>"; curpos=0;
+	case 'b':
+	case 'v':
+	case 'x':
+	case 'o':
+	case 'L':
+	case 'h':
+		c++;
+		i=*c;
+		c++;
+		exoutputp=output_possible;
+		exskipescape=skip_escape;
+		output_possible=0;
+		skip_escape=1;
+		while (*c != i)
+			if (*c==escapesym)
+				c=scan_escape(c+1);
+			else
+				c++;
+		output_possible=exoutputp;
+		skip_escape=exskipescape;
+		break;
+	case 'c': no_newline_output=1; break;
+	case '{': newline_for_fun++; h="";break;
+	case '}': if (newline_for_fun) newline_for_fun--; h="";break;
+	case 'p': h="<BR>\n";curpos=0; break;
+	case 't': h="\t";curpos=(curpos+8)&0xfff8; break;
+	case '<': h="&lt;";curpos++; break;
+	case '>': h="&gt;";curpos++; break;
+	case '\\': if (single_escape) { c--; break;}
+	default: b[0]=*c; b[1]=0; h=b; curpos++; break;
+	}
+	c++;
+	if (!skip_escape)
+		out_html(h);
+	return c;
+}
+
+typedef struct TABLEITEM TABLEITEM;
+
+struct TABLEITEM {
+    char *contents;
+    int size,align,valign,colspan,rowspan,font,vleft,vright,space,width;
+    TABLEITEM *next;
+};
+
+static TABLEITEM emptyfield = {NULL,0,0,0,1,1,0,0,0,0,0,NULL};
+
+typedef struct TABLEROW TABLEROW;
+
+struct TABLEROW {
+    TABLEITEM *first;
+    TABLEROW *prev, *next;
+};
+
+static char *tableopt[]= { "center", "expand", "box", "allbox", "doublebox",
+			   "tab", "linesize", "delim", NULL };
+static int tableoptl[] = { 6,6,3,6,9,3,8,5,0};
+
+
+static void clear_table(TABLEROW *table)
+{
+	TABLEROW *tr1,*tr2;
+	TABLEITEM *ti1,*ti2;
+	
+	tr1=table;
+	while (tr1->prev) tr1=tr1->prev;
+	while (tr1) {
+		ti1=tr1->first;
+		while (ti1) {
+			ti2=ti1->next;
+			if (ti1->contents) free(ti1->contents);
+			free(ti1);
+			ti1=ti2;
+		}
+		tr2=tr1;
+		tr1=tr1->next;
+		free(tr2);
+	}
+}
+
+static char *scan_expression(char *c, int *result);
+
+static char
+*scan_format(char *c, TABLEROW **result, int *maxcol)
+{
+	TABLEROW *layout, *currow;
+	TABLEITEM *curfield;
+	int i,j;
+
+	if (*result) {
+		clear_table(*result);
+	}
+
+	layout= currow=(TABLEROW*) malloc(sizeof(TABLEROW));
+	currow->next=currow->prev=NULL;
+	currow->first=curfield=(TABLEITEM*) malloc(sizeof(TABLEITEM));
+	*curfield=emptyfield;
+	while (*c && *c!='.') {
+		switch (*c) {
+		case 'C': case 'c': case 'N': case 'n':
+		case 'R': case 'r': case 'A': case 'a':
+		case 'L': case 'l': case 'S': case 's':
+		case '^': case '_':
+			if (curfield->align) {
+				curfield->next=
+					(TABLEITEM*)malloc(sizeof(TABLEITEM));
+				curfield=curfield->next;
+				*curfield=emptyfield;
+			}
+			curfield->align=toupper(*c);
+			c++;
+			break;
+		case 'i': case 'I': case 'B': case 'b':
+			curfield->font = toupper(*c);
+			c++;
+			break;
+		case 'f': case 'F':
+			c++;
+			curfield->font = toupper(*c);
+			c++;
+			if (!isspace(*c) && *c!='.') c++;
+			break;
+		case 't': case 'T': curfield->valign='t'; c++; break;
+		case 'p': case 'P':
+			c++;
+			i=j=0;
+			if (*c=='+') { j=1; c++; }
+			if (*c=='-') { j=-1; c++; }
+			while (isdigit(*c)) i=i*10+(*c++)-'0';
+			if (j) curfield->size= i*j; else curfield->size=j-10;
+			break;
+		case 'v': case 'V':
+		case 'w': case 'W':
+			c=scan_expression(c+2,&curfield->width);
+			break;
+		case '|':
+			if (curfield->align) curfield->vleft++;
+			else curfield->vright++;
+			c++;
+			break;
+		case 'e': case 'E':
+			c++;
+			break;
+		case '0': case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			i=0;
+			while (isdigit(*c)) i=i*10+(*c++)-'0';
+			curfield->space=i;
+			break;
+		case ',': case '\n':
+			currow->next=(TABLEROW*)malloc(sizeof(TABLEROW));
+			currow->next->prev=currow;
+			currow=currow->next;
+			currow->next=NULL;
+			curfield=currow->first=(TABLEITEM*)malloc(sizeof(TABLEITEM));
+			*curfield=emptyfield;
+			c++;
+			break;
+		default:
+			c++;
+			break;
+		}
+	}
+	if (*c=='.') while (*c++!='\n');
+	*maxcol=0;
+	currow=layout;
+	while (currow) {
+		curfield=layout->first;
+		i=0;
+		while (curfield) {
+			i++;
+			curfield=curfield->next;
+		}
+		if (i>*maxcol) *maxcol=i;
+		currow=currow->next;
+	}
+	*result=layout;
+	return c;
+}
+
+static TABLEROW
+*next_row(TABLEROW *tr)
+{
+	if (tr->next) {
+		tr=tr->next;
+		if (!tr->next) next_row(tr);
+		return tr;
+	} else {
+		TABLEITEM *ti, *ti2;
+		tr->next=(TABLEROW*)malloc(sizeof(TABLEROW));
+		tr->next->prev=tr;
+		ti=tr->first;
+		tr=tr->next;
+		tr->next=NULL;
+		if (ti) tr->first=ti2=(TABLEITEM*) malloc(sizeof(TABLEITEM));
+		else tr->first=ti2=NULL;
+		while (ti!=ti2) {
+			*ti2=*ti;
+			ti2->contents=NULL;
+			if ((ti=ti->next)) {
+				ti2->next=(TABLEITEM*)
+					malloc(sizeof(TABLEITEM));
+			}
+			ti2=ti2->next;
+		}
+		return tr;
+	}
+}
+
+static char itemreset[20]="\\fR\\s0";
+
+static char
+*scan_table(char *c)
+{
+	char *h, *g;
+	int center=0, expand=0, box=0, border=0, linesize=1;
+	int i,j,maxcol=0, finished=0;
+	int oldfont, oldsize,oldfillout;
+	char itemsep='\t';
+	TABLEROW *layout=NULL, *currow;
+	TABLEITEM *curfield;
+
+	while (*c++!='\n');
+	h=c;
+	if (*h=='.') return c-1;
+	oldfont=current_font;
+	oldsize=current_size;
+	oldfillout=fillout;
+	out_html(change_to_font(0));
+	out_html(change_to_size(0));
+	if (!fillout) {
+		fillout=1;
+		out_html("</PRE>");
+	}
+	while (*h && *h!='\n') h++;
+	if (h[-1]==';') {
+		/* scan table options */
+		while (c<h) {
+			while (isspace(*c)) c++;
+			for (i=0; tableopt[i] && 
+				     strncmp(tableopt[i],c,tableoptl[i]);i++);
+			c=c+tableoptl[i];
+			switch (i) {
+			case 0: 
+				center=1;
+				break;
+			case 1: 
+				expand=1;
+				break;
+			case 2: 
+				box=1;
+				break;
+			case 3: 
+				border=1;
+				break;
+			case 4: 
+				box=2;
+				break;
+			case 5: 
+				while (*c++!='(');
+				itemsep=*c++; 
+				break;
+			case 6: 
+				while (*c++!='(');
+				linesize=0;
+				while (isdigit(*c))
+					linesize=linesize*10+(*c++)-'0';
+				break;
+			case 7: 
+				while (*c!=')')
+					c++;
+			default:
+				break;
+			}
+			c++;
+		}
+		c=h+1;
+	}
+	/* scan layout */
+	c=scan_format(c,&layout, &maxcol);
+	currow=layout;
+	next_row(currow);
+	curfield=layout->first;
+	i=0;
+	while (!finished) {
+		/* search item */
+		h=c;
+		if ((*c=='_' || *c=='=') && (c[1]==itemsep || c[1]=='\n')) {
+			if (c[-1]=='\n' && c[1]=='\n') {
+				if (currow->prev) {
+					currow->prev->next=(TABLEROW*)
+						malloc(sizeof(TABLEROW));
+					currow->prev->next->next=currow;
+					currow->prev->next->prev=currow->prev;
+					currow->prev=currow->prev->next;
+				} else {
+					currow->prev=layout=(TABLEROW*)
+						malloc(sizeof(TABLEROW));
+					currow->prev->prev=NULL;
+					currow->prev->next=currow;
+				}
+				curfield=currow->prev->first=
+					(TABLEITEM*) malloc(sizeof(TABLEITEM));
+				*curfield=emptyfield;
+				curfield->align=*c;
+				curfield->colspan=maxcol;
+				curfield=currow->first;
+				c=c+2;
+			} else {
+				if (curfield) {
+					curfield->align=*c;
+					do {
+						curfield=curfield->next;
+					} while (curfield 
+						 && curfield->align=='S');
+				}
+				if (c[1]=='\n') {
+					currow=next_row(currow);
+					curfield=currow->first;
+				}
+				c=c+2;
+			}
+		} else if (*c=='T' && c[1]=='{') {
+			h=c+2;
+			c=strstr(h,"\nT}");
+			c++;
+			*c='\0';
+			g=NULL;
+			scan_troff(h,0,&g);
+			scan_troff(itemreset, 0,&g);
+			*c='T';
+			c+=3;
+			if (curfield) {
+				curfield->contents=g;
+				do {
+					curfield=curfield->next;
+				} while (curfield && curfield->align=='S');
+			} else
+				if (g) free(g);
+			if (c[-1]=='\n') {
+				currow=next_row(currow);
+				curfield=currow->first;
+			}
+		} else if (*c=='.' && c[1]=='T' && c[2]=='&' && c[-1]=='\n') {
+			TABLEROW *hr;
+			while (*c++!='\n');
+			hr=currow;
+			currow=currow->prev;
+			hr->prev=NULL;
+			c=scan_format(c,&hr, &i);
+			hr->prev=currow;
+			currow->next=hr;
+			currow=hr;
+			next_row(currow);
+			curfield=currow->first;
+		} else if (*c=='.' && c[1]=='T' && c[2]=='E' && c[-1]=='\n') {
+			finished=1;
+			while (*c++!='\n');
+			if (currow->prev)
+				currow->prev->next=NULL;
+			currow->prev=NULL;
+			clear_table(currow);
+		} else if (*c=='.' && c[-1]=='\n' && !isdigit(c[1])) {
+			/* skip troff request inside table(usually only .sp )*/
+			while (*c++!='\n');
+		} else {
+			h=c;
+			while (*c && (*c!=itemsep || c[-1]=='\\') &&
+			       (*c!='\n' || c[-1]=='\\')) c++;
+			i=0;
+			if (*c==itemsep) {i=1; *c='\n'; }
+			if (h[0]=='\\' && h[2]=='\n' &&
+			    (h[1]=='_' || h[1]=='^')) {
+				if (curfield) {
+					curfield->align=h[1];
+					do {
+						curfield=curfield->next;
+					} while (curfield && 
+						 curfield->align=='S');
+				}
+				h=h+3;
+			} else {
+				g=NULL;
+				h=scan_troff(h,1,&g);
+				scan_troff(itemreset,0,&g);
+				if (curfield) {
+					curfield->contents=g;
+					do {
+						curfield=curfield->next;
+					} while (curfield && 
+						 curfield->align=='S');
+				} else if (g) free(g);
+			}
+			if (i) *c=itemsep;
+			c=h;
+			if (c[-1]=='\n') {
+				currow=next_row(currow);
+				curfield=currow->first;
+			}
+		}
+	}
+	/* calculate colspan and rowspan */
+	currow=layout;
+	while (currow->next) currow=currow->next;
+	while (currow) {
+		TABLEITEM *ti, *ti1=NULL, *ti2=NULL;
+		ti=currow->first;
+		if (currow->prev)
+			ti1=currow->prev->first;
+		while (ti) {
+			switch (ti->align) {
+			case 'S':
+				if (ti2) {
+					ti2->colspan++;
+					if (ti2->rowspan<ti->rowspan) 
+						ti2->rowspan=ti->rowspan;
+				}
+				break;
+			case '^':
+				if (ti1)
+					ti1->rowspan++;
+			default:
+				if (!ti2)
+					ti2=ti;
+				else {
+					do {
+						ti2=ti2->next;
+					} while (ti2 && curfield->align=='S');
+				}
+				break;
+			}
+			ti=ti->next;
+			if (ti1) ti1=ti1->next;
+		}
+		currow=currow->prev;
+	}
+	/* produce html output */
+	if (center)
+		out_html("<CENTER>");
+	if (box==2)
+		out_html("<TABLE BORDER><TR><TD>");
+	out_html("<TABLE");
+	if (box || border) {
+		out_html(" BORDER");
+		if (!border)
+			out_html("><TR><TD><TABLE");
+		if (expand)
+			out_html(" WIDTH=100%");
+	}
+	out_html(">\n");
+	currow=layout;
+	while (currow) {
+		j=0;
+		out_html("<TR VALIGN=top>");
+		curfield=currow->first;
+		while (curfield) {
+			if (curfield->align!='S' && curfield->align!='^') {
+				out_html("<TD");
+				switch (curfield->align) {
+				case 'N':
+					curfield->space+=4;
+				case 'R':
+					out_html(" ALIGN=right");
+					break;
+				case 'C':
+					out_html(" ALIGN=center");
+				default:
+					break;
+				}
+				if (!curfield->valign && curfield->rowspan>1)
+					out_html(" VALIGN=center");
+				if (curfield->colspan>1) {
+					char buf[5];
+					out_html(" COLSPAN=");
+					sprintf(buf, "%i", curfield->colspan);
+					out_html(buf);
+				}
+				if (curfield->rowspan>1) {
+					char buf[5];
+					out_html(" ROWSPAN=");
+					sprintf(buf, "%i", curfield->rowspan);
+					out_html(buf);
+				}
+				j=j+curfield->colspan;
+				out_html(">");
+				if (curfield->size)
+					out_html(change_to_size(curfield->size));
+				if (curfield->font)
+					out_html(change_to_font(curfield->font));
+				switch (curfield->align) {
+				case '=': 
+					out_html("<HR><HR>");
+					break;
+				case '_':
+					out_html("<HR>");
+					break;
+				default:
+					if (curfield->contents)
+						out_html(curfield->contents);
+					break;
+				}
+				if (curfield->space)
+					for (i=0; i<curfield->space;i++)
+						out_html("&nbsp;");
+				if (curfield->font)
+					out_html(change_to_font(0));
+				if (curfield->size)
+					out_html(change_to_size(0));
+				if (j>=maxcol && curfield->align>'@' && 
+				    curfield->align!='_')
+					out_html("<BR>");
+				out_html("</TD>");
+			}
+			curfield=curfield->next;
+		}
+		out_html("</TR>\n");
+		currow=currow->next;
+	}
+	if (box && !border)
+		out_html("</TABLE>");
+	out_html("</TABLE>");
+	if (box==2)
+		out_html("</TABLE>");
+	if (center)
+		out_html("</CENTER>\n");
+	else
+		out_html("\n");
+	if (!oldfillout)
+		out_html("<PRE>");
+	fillout=oldfillout;
+	out_html(change_to_size(oldsize));
+	out_html(change_to_font(oldfont));
+	return c;
+}
+
+static char
+*scan_expression(char *c, int *result)
+{
+	int value=0,value2,sign=1,opex=0;
+	char oper='c';
+
+	if (*c=='!') {
+		c=scan_expression(c+1, &value);
+		value= (!value);
+	} else if (*c=='n') {
+		c++;
+		value=NROFF;
+	} else if (*c=='t') {
+		c++;
+		value=1-NROFF;
+	} else if (*c=='\'' || *c=='"' || *c<' ' || (*c=='\\' && c[1]=='(')) {
+		/* ?string1?string2?
+		** test if string1 equals string2.
+		*/
+		char *st1=NULL, *st2=NULL, *h;
+		char *tcmp=NULL;
+		char sep;
+		sep=*c;
+		if (sep=='\\') {
+			tcmp=c;
+			c=c+3;
+		}
+		c++;
+		h=c;
+		while (*c!= sep && (!tcmp || strncmp(c,tcmp,4)))
+			c++;
+		*c='\n';
+		scan_troff(h, 1, &st1);
+		*c=sep;
+		if (tcmp)
+			c=c+3;
+		c++;
+		h=c;
+		while (*c!=sep && (!tcmp || strncmp(c,tcmp,4)))
+			c++;
+		*c='\n';
+		scan_troff(h,1,&st2);
+		*c=sep;
+		if (!st1 && !st2)
+			value=1;
+		else if (!st1 || !st2)
+			value=0;
+		else 
+			value=(!strcmp(st1, st2));
+		if (st1) 
+			free(st1);
+		if (st2)
+			free(st2);
+		if (tcmp)
+			c=c+3;
+		c++;
+	} else {
+		while (*c && !isspace(*c) && *c!=')') {
+			opex=0;
+			switch (*c) {
+			case '(':
+				c=scan_expression(c+1, &value2);
+				value2=sign*value2;
+				opex=1;
+				break;
+			case '.':
+			case '0': case '1':
+			case '2': case '3':
+			case '4': case '5':
+			case '6': case '7':
+			case '8': case '9': {
+				int num=0,denum=1;
+				value2=0;
+				while (isdigit(*c))
+					value2=value2*10+((*c++)-'0');
+				if (*c=='.') {
+					c++;
+					while (isdigit(*c)) {
+						num=num*10+((*c++)-'0');
+						denum=denum*10;
+					}
+				}
+				if (isalpha(*c)) {
+					/* scale indicator */
+					switch (*c) {
+					case 'i': /* inch -> 10pt */
+						value2=value2*10+
+							(num*10+denum/2)/denum;
+						num=0;
+						break;
+					default:
+						break;
+					}
+					c++;
+				}
+				value2=value2+(num+denum/2)/denum;
+				value2=sign*value2;
+				opex=1;
+				break;
+			}
+			case '\\':
+				c=scan_escape(c+1);
+				value2=intresult*sign;
+				if (isalpha(*c))
+					c++; /* scale indicator */
+				opex=1;
+				break;
+			case '-':
+				if (oper) { 
+					sign=-1; 
+					c++;
+					break;
+				}
+			case '>':
+			case '<':
+			case '+':
+			case '/':
+			case '*':
+			case '%':
+			case '&':
+			case '=':
+			case ':':
+				if (c[1]=='=')
+					oper=(*c++) + 16;
+				else 
+					oper=*c;
+				c++;
+				break;
+			default: 
+				c++;
+				break;
+			}
+			if (opex) {
+				sign=1;
+				switch (oper) {
+				case 'c': 
+					value=value2; 
+					break;
+				case '-': 
+					value=value-value2;
+					break;
+				case '+': 
+					value=value+value2;
+					break;
+				case '*': 
+					value=value*value2; 
+					break;
+				case '/': 
+					if (value2) 
+						value=value/value2; 
+					break;
+				case '%': 
+					if (value2) 
+						value=value%value2; 
+					break;
+				case '<':
+					value=(value<value2);
+					break;
+				case '>':
+					value=(value>value2); 
+					break;
+				case '>'+16:
+					value=(value>=value2);
+					break;
+				case '<'+16: 
+					value=(value<=value2); 
+					break;
+				case '=':
+				case '='+16: 
+					value=(value==value2);
+					break;
+				case '&':
+					value = (value && value2);
+					break;
+				case ':':
+					value = (value || value2);
+					break;
+				default: 
+					fprintf(stderr, "man2html: unknown "
+						"operator %c.\n", oper);
+				}
+				oper=0;
+			}
+		}
+		if (*c==')')
+			c++;
+	}
+	*result=value;
+	return c;
+}
+
+static void 
+trans_char(char *c, char s, char t)
+{
+	char *sl=c;
+	int slash=0;
+	while (*sl!='\n' || slash) {
+		if (!slash) {
+			if (*sl==escapesym)
+				slash=1;
+			else if (*sl==s)
+				*sl=t;
+		} else slash=0;
+		sl++;
+	}
+}
+
+static char
+*fill_words(char *c, char *words[], int *n)
+{
+	char *sl=c;
+	int slash=0;
+	int skipspace=0;
+	*n=0;
+	words[*n]=sl;
+	while (*sl && (*sl!='\n' || slash)) {
+		if (!slash) {
+			if (*sl=='"') {
+				*sl='\a';
+				skipspace=!skipspace;
+			} else if (*sl==escapesym)
+				slash=1;
+			else if ((*sl==' ' || *sl=='\t') && !skipspace) {
+				*sl='\n';
+				if (words[*n]!=sl)
+					(*n)++;
+				words[*n]=sl+1;
+			}
+		} else {
+			if (*sl=='"') {
+				sl--;
+				*sl='\n';
+				if (words[*n]!=sl)
+					(*n)++;
+				sl++;
+				while (*sl && *sl !='\n') 
+					sl++;
+				words[*n]=sl;
+				sl--;
+			}
+			slash=0;
+		}
+		sl++;
+	}
+	if (sl!=words[*n])
+		(*n)++;
+	return sl;
+}
+
+static char *abbrev_list[] = {
+    "GSBG", "Getting Started ",
+    "SUBG", "Customizing SunOS",
+    "SHBG", "Basic Troubleshooting",
+    "SVBG", "SunView User's Guide",
+    "MMBG", "Mail and Messages",
+    "DMBG", "Doing More with SunOS",
+    "UNBG", "Using the Network",
+    "GDBG", "Games, Demos &amp; Other Pursuits",
+    "CHANGE", "SunOS 4.1 Release Manual",
+    "INSTALL", "Installing SunOS 4.1",
+    "ADMIN", "System and Network Administration",
+    "SECUR", "Security Features Guide",
+    "PROM", "PROM User's Manual",
+    "DIAG", "Sun System Diagnostics",
+    "SUNDIAG", "Sundiag User's Guide",
+    "MANPAGES", "SunOS Reference Manual",
+    "REFMAN", "SunOS Reference Manual",
+    "SSI", "Sun System Introduction",
+    "SSO", "System Services Overview",
+    "TEXT", "Editing Text Files",
+    "DOCS", "Formatting Documents",
+    "TROFF", "Using <B>nroff</B> and <B>troff</B>",
+    "INDEX", "Global Index",
+    "CPG", "C Programmer's Guide",
+    "CREF", "C Reference Manual",
+    "ASSY", "Assembly Language Reference",
+    "PUL", "Programming Utilities and Libraries",
+    "DEBUG", "Debugging Tools",
+    "NETP", "Network Programming",
+    "DRIVER", "Writing Device Drivers",
+    "STREAMS", "STREAMS Programming",
+    "SBDK", "SBus Developer's Kit",
+    "WDDS", "Writing Device Drivers for the SBus",
+    "FPOINT", "Floating-Point Programmer's Guide",
+    "SVPG", "SunView 1 Programmer's Guide",
+    "SVSPG", "SunView 1 System Programmer's Guide",
+    "PIXRCT", "Pixrect Reference Manual",
+    "CGI", "SunCGI Reference Manual",
+    "CORE", "SunCore Reference Manual",
+    "4ASSY", "Sun-4 Assembly Language Reference",
+    "SARCH", "<FONT SIZE=-1>SPARC</FONT> Architecture Manual",
+    "KR", "The C Programming Language",
+    NULL, NULL };
+
+static char *lookup_abbrev(char *c)
+{
+    int i=0;
+
+    if (!c) return "";
+    while (abbrev_list[i] && strcmp(c,abbrev_list[i])) i=i+2;
+    if (abbrev_list[i]) return abbrev_list[i+1];
+    else return c;
+}
+
+static char *section_list[] = {
+    "1", "User Commands ",
+    "1C", "User Commands",
+    "1G", "User Commands",
+    "1S", "User Commands",
+    "1V", "User Commands ",
+    "2", "System Calls",
+    "2V", "System Calls",
+    "3", "C Library Functions",
+    "3C", "Compatibility Functions",
+    "3F", "Fortran Library Routines",
+    "3K", "Kernel VM Library Functions",
+    "3L", "Lightweight Processes Library",
+    "3M", "Mathematical Library",
+    "3N", "Network Functions",
+    "3R", "RPC Services Library",
+    "3S", "Standard I/O Functions",
+    "3V", "C Library Functions",
+    "3X", "Miscellaneous Library Functions",
+    "4", "Devices and Network Interfaces",
+    "4F", "Protocol Families",
+    "4I", "Devices and Network Interfaces",
+    "4M", "Devices and Network Interfaces",
+    "4N", "Devices and Network Interfaces",
+    "4P", "Protocols",
+    "4S", "Devices and Network Interfaces",
+    "4V", "Devices and Network Interfaces",
+    "5", "File Formats",
+    "5V", "File Formats",
+    "6", "Games and Demos",
+    "7", "Environments, Tables, and Troff Macros",
+    "7V", "Environments, Tables, and Troff Macros",
+    "8", "Maintenance Commands",
+    "8C", "Maintenance Commands",
+    "8S", "Maintenance Commands",
+    "8V", "Maintenance Commands",
+    "L", "Local Commands",
+    NULL, "Misc. Reference Manual Pages",
+    NULL, NULL
+};
+
+static char
+*section_name(char *c)
+{
+    int i=0;
+
+    if (!c)
+	    return "";
+    while (section_list[i] && strcmp(c,section_list[i]))
+	    i=i+2;
+    if (section_list[i+1])
+	    return section_list[i+1];
+    else 
+	    return c;
+}
+
+static char manidx[NULL_TERMINATED(HUGE_STR_MAX)];
+static int subs=0;
+static int mip=0;
+static char label[5]="lbAA";
+
+static void 
+add_to_index(int level, char *item)
+{
+	char *c=NULL;
+	label[3]++;
+
+	if (label[3]>'Z') {
+		label[3]='A';
+		label[2]++;
+	}
+	if (level != subs) {
+		if (subs) {
+			strmaxcpy(manidx+mip, "</DL>\n", HUGE_STR_MAX - mip);
+			mip+=6;
+		} else {
+			strmaxcpy(manidx+mip, "<DL>\n", HUGE_STR_MAX - mip);
+			mip+=5;
+		}
+	}
+	subs=level;
+	scan_troff(item, 1, &c);
+	sprintf(manidx+mip, "<DT><A HREF=\"%s#%s\">%s</A><DD>\n", 
+		((URLbasename) ? URLbasename : ""), label, c);
+	if (c)
+		free(c);
+	while (manidx[mip])
+		mip++;
+}
+
+static char 
+*skip_till_newline(char *c)
+{
+	int lvl=0;
+
+	while ((*c && *c!='\n') || lvl>0) {
+		if (*c=='\\') {
+			c++;
+			if (*c=='}') 
+				lvl--;
+			else if (*c=='{') 
+				lvl++;
+		}
+		c++;
+	}
+	c++;
+	if (lvl<0 && newline_for_fun) {
+		newline_for_fun = newline_for_fun+lvl;
+		if (newline_for_fun<0) 
+			newline_for_fun=0;
+	}
+	return c;
+}
+
+static int ifelseval=0;
+
+static char 
+*scan_request(char *c)
+{
+	/* BSD Mandoc stuff */
+	static int mandoc_synopsis=0; /* True if in the synopsis section */
+	static int mandoc_command=0;  /* True if this is mandoc page */
+	static int mandoc_bd_options; /* Only copes with non-nested Bd's */
+
+	int i,j,mode=0;
+	char *h;
+	char *wordlist[MAX_WORDLIST];
+	int words;
+	char *sl;
+	STRDEF *owndef;
+
+	while (*c==' ' || *c=='\t')
+		c++;
+	if (c[0]=='\n')
+		return c+1;
+	if (c[1]=='\n')
+		j=1; 
+	else
+		j=2;
+	while (c[j]==' ' || c[j]=='\t')
+		j++;
+	if (c[0]==escapesym) {
+		/* some pages use .\" .\$1 .\} */
+		/* .\$1 is too difficult/stuppid */
+		if (c[1]=='$') 
+			c=skip_till_newline(c);
+		else
+			c = scan_escape(c+1);
+	} else {
+		i=V(c[0],c[1]);
+		switch (i) {
+		case V('`',' '):
+			out_html(change_to_font('B'));
+			out_html("`");
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c!='\n')
+				c++;
+			c=scan_troff(c, 1, NULL);
+			out_html("'");
+			out_html(change_to_font('R'));
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('a','b'):
+			h=c+j;
+			while (*h && *h !='\n')
+				h++;
+			*h='\0';
+			if (scaninbuff && buffpos) {
+				buffer[buffpos]='\0';
+				puts(buffer);
+			}
+			/* fprintf(stderr, "%s\n", c+2); */
+			exit(0);
+			break;
+		case V('d','i'):
+		{
+			STRDEF *de;
+
+			c=c+j;
+			i=V(c[0],c[1]);
+			if (*c=='\n') {
+				c++;
+				break;
+			}
+			while (*c && *c!='\n')
+				c++;
+			c++;
+			h=c;
+			while (*c && strncmp(c,".di",3)) 
+				while (*c && *c++!='\n');
+			*c='\0';
+			de=strdef;
+			while (de && de->nr !=i)
+				de=de->next;
+			if (!de) {
+				de=(STRDEF*) malloc(sizeof(STRDEF));
+				de->nr=i;
+				de->slen=0;
+				de->next=strdef;
+				de->st=NULL;
+				strdef=de;
+			} else {
+				if (de->st) 
+					free(de->st);
+				de->slen=0;
+				de->st=NULL;
+			}
+			scan_troff(h,0,&de->st);
+			*c='.';
+			while (*c && *c++!='\n');
+			break;
+		}
+		case V('d','s'):
+			mode=1;
+		case V('a','s'):
+		{
+			STRDEF *de;
+			int oldcurpos=curpos;
+
+			c=c+j;
+			i=V(c[0],c[1]);
+			j=0;
+			while (c[j] && c[j]!='\n')
+				j++;
+			if (j<3) {
+				c=c+j;
+				break;
+			}
+			if (c[1]==' ') 
+				c=c+1;
+			else 
+				c=c+2;
+			while (isspace(*c)) 
+				c++;
+			if (*c=='"') 
+				c++;
+			de=strdef;
+			while (de && de->nr != i)
+				de=de->next;
+			single_escape=1;
+			curpos=0;
+			if (!de) {
+				char *h;
+
+				de=(STRDEF*) malloc(sizeof(STRDEF));
+				de->nr=i;
+				de->slen=0;
+				de->next=strdef;
+				de->st=NULL;
+				strdef=de;
+				h=NULL;
+				c=scan_troff(c, 1, &h);
+				de->st=h;
+				de->slen=curpos;
+			} else {
+				if (mode) {
+					char *h=NULL;
+
+					c=scan_troff(c, 1, &h);
+					free(de->st);
+					de->slen=0;
+					de->st=h;
+				} else
+					c=scan_troff(c,1,&de->st);
+				de->slen+=curpos;
+			}
+			single_escape=0;
+			curpos=oldcurpos;
+		}
+		break;
+		case V('b','r'):
+			if (still_dd)
+				out_html("<DD>");
+			else 
+				out_html("<BR>\n");
+			curpos=0;
+			c=c+j;
+			if (c[0]==escapesym)
+				c=scan_escape(c+1);
+			c=skip_till_newline(c);
+			break;
+		case V('c','2'):
+			c=c+j;
+			if (*c!='\n')
+				nobreaksym=*c;
+			else 
+				nobreaksym='\'';
+			c=skip_till_newline(c);
+			break;
+		case V('c','c'):
+			c=c+j;
+			if (*c!='\n')
+				controlsym=*c;
+			else 
+				controlsym='.';
+			c=skip_till_newline(c);
+			break;
+		case V('c','e'):
+			c=c+j;
+			if (*c=='\n') { i=1; }
+			else {
+				i=0;
+				while ('0'<=*c && *c<='9') {
+					i=i*10+*c-'0';
+					c++;
+				}
+			}
+			c=skip_till_newline(c);
+			/* center next i lines */
+			if (i>0) {
+				out_html("<CENTER>\n");
+				while (i && *c) {
+					char *line=NULL;
+					c=scan_troff(c,1, &line);
+					if (line && strncmp(line, "<BR>", 4)) {
+						out_html(line);
+						out_html("<BR>\n");
+						i--;
+					}
+				}
+				out_html("</CENTER>\n");
+				curpos=0;
+			}
+			break;
+		case V('e','c'):
+			c=c+j;
+			if (*c!='\n') 
+				escapesym=*c;
+			else 
+				escapesym='\\';
+			break;
+			c=skip_till_newline(c);
+		case V('e','o'):
+			escapesym='\0';
+			c=skip_till_newline(c);
+			break;
+		case V('e','x'):
+			exit(0);
+			break;
+		case V('f','c'):
+			c=c+j;
+			if  (*c=='\n') {
+				fieldsym=padsym='\0';
+			} else {
+				fieldsym=c[0];
+				padsym=c[1];
+			}
+			c=skip_till_newline(c);
+			break;
+		case V('f','i'):
+			if (!fillout) {
+				out_html(change_to_font(0));
+				out_html(change_to_size('0'));
+				out_html("</PRE>\n");
+			}
+			curpos=0;
+			fillout=1;
+			c=skip_till_newline(c);
+			break;
+		case V('f','t'):
+			c=c+j;
+			if (*c=='\n') {
+				out_html(change_to_font(0));
+			} else {
+				if (*c==escapesym) {
+					int fn;
+
+					c=scan_expression(c, &fn);
+					c--;
+					out_html(change_to_font(fn));
+				} else {
+					out_html(change_to_font(*c));
+					c++;
+				}
+			}
+			c=skip_till_newline(c);
+			break;
+		case V('e','l'):
+			/* .el anything : else part of if else */
+			if (ifelseval) {
+				c=c+j;
+				c[-1]='\n';
+				c=scan_troff(c,1,NULL);
+			} else
+				c=skip_till_newline(c+j);
+			break;
+		case V('i','e'):
+			/* .ie c anything : then part of if else */	
+		case V('i','f'):
+			/* .if c anything
+			 * .if !c anything
+			 * .if N anything
+			 * .if !N anything
+			 * .if 'string1'string2' anything
+			 * .if !'string1'string2' anything
+			 */
+			c=c+j;
+			c=scan_expression(c, &i);
+			ifelseval=!i;
+			if (i) {
+				*c='\n';
+				c++;
+				c=scan_troff(c,1,NULL);
+			} else
+				c=skip_till_newline(c);
+			break;
+		case V('i','g'):
+		{
+			char *endwith="..\n";
+			i=3;
+			c=c+j;
+			if (*c!='\n' && strncmp(c, "\\\"", 2)) {
+				endwith=c-1;i=1;
+				c[-1]='.';
+				while (*c && *c!='\n') {
+					c++;
+					i++;
+				}
+			}
+			c++;
+			while (*c && strncmp(c,endwith,i)) 
+				while (*c && *c++!='\n');
+			while (*c && *c++!='\n');
+			break;
+		}
+		case V('n','f'):
+			if (fillout) {
+				out_html(change_to_font(0));
+				out_html(change_to_size('0'));
+				out_html("<PRE>\n");
+			}
+			curpos=0;
+			fillout=0;
+			c=skip_till_newline(c);
+			break;
+		case V('p','s'):
+			c=c+j;
+			if (*c=='\n') {
+				out_html(change_to_size('0'));
+			} else {
+				j=0;i=0;
+				if (*c=='-') { 
+					j= -1;
+					c++;
+				} else if (*c=='+') {
+					j=1;
+					c++;
+				}
+				c=scan_expression(c, &i);
+				if (!j) {
+					j=1;
+					if (i>5)
+						i=i-10;
+				}
+				out_html(change_to_size(i*j));
+			}
+			c=skip_till_newline(c);
+			break;
+		case V('s','p'):
+			c=c+j;
+			if (fillout)
+				out_html("<P>"); 
+			else {
+				out_html(NEWLINE);
+				NEWLINE[0]='\n';
+			}
+			curpos=0;
+			c=skip_till_newline(c);
+			break;
+		case V('s','o'):
+		{
+			/* msf */
+			curpos=0;
+			c=c+j;
+			if (*c=='/') {
+				h=c;
+			} else {
+				h=c-3;
+				h[0]='.';
+				h[1]='.';
+				h[2]='/';
+			}
+			while (*c!='\n')
+				c++;
+			*c='\0';
+			*c++='\n';
+
+			printf("<B> WARNING - a .so macro slipped "
+			       "through!</B>\n");
+			break;
+		}
+		case V('t','a'):
+			c=c+j;
+			j=0;
+			while (*c!='\n') {
+				sl=scan_expression(c, &tabstops[j]);
+				if (*c=='-' || *c=='+')
+					tabstops[j]+=tabstops[j-1];
+				c=sl;
+				while (*c==' ' || *c=='\t') 
+					c++;
+				j++;
+			}
+			maxtstop=j;
+			curpos=0;
+			break;
+		case V('t','i'):
+			/*while (itemdepth || dl_set[itemdepth]) {
+			  out_html("</DL>\n");
+			  if (dl_set[itemdepth]) dl_set[itemdepth]=0;
+			  else itemdepth--;
+			  }*/
+			out_html("<BR>\n");
+			c=c+j;
+			c=scan_expression(c, &j);
+			for (i=0; i<j; i++)
+				out_html("&nbsp;");
+			curpos=j;
+			c=skip_till_newline(c);
+			break;
+		case V('t','m'):
+			c=c+j;
+			h=c;
+			while (*c!='\n') 
+				c++;
+			*c='\0';
+			/* fprintf(stderr,"%s\n", h); */
+			*c='\n';
+			break;
+		case V('B',' '):
+		case V('B','\n'):
+		case V('I',' '):
+		case V('I','\n'):
+			/* parse one line in a certain font */
+			out_html(change_to_font(*c));
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			c=scan_troff(c, 1, NULL);
+			out_html(change_to_font('R'));
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('O','P'):  /* groff manpages use this construction */
+			/* .OP a b : [ <B>a</B> <I>b</I> ] */
+			mode=1;
+			c[0]='B';
+			c[1]='I';
+			out_html(change_to_font('R'));
+			out_html("[");
+			curpos++;
+		case V('B','R'):
+		case V('B','I'):
+		case V('I','B'):
+		case V('I','R'):
+		case V('R','B'):
+		case V('R','I'):
+		{
+			char font[2] ;
+
+			font[0] = c[0]; 
+			font[1] = c[1];
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			sl=fill_words(c, wordlist, &words);
+			c=sl+1;
+			/* .BR name (section)
+			** indicates a link. It will be added 
+                        ** in the output routine.
+			*/
+			for (i=0; i<words; i++) {
+				if (mode) { 
+					out_html(" ");
+					curpos++;
+				}
+				wordlist[i][-1]=' ';
+				out_html(change_to_font(font[i&1]));
+				scan_troff(wordlist[i],1,NULL);
+			}
+			out_html(change_to_font('R'));
+			if (mode) {
+				out_html(" ]"); 
+				curpos++;
+			}
+			out_html(NEWLINE);
+			if (!fillout)
+				curpos=0;
+			else
+				curpos++;
+		}
+		break;
+		case V('D','T'):
+			for (j=0;j<20; j++)
+				tabstops[j]=(j+1)*8;
+			maxtstop=20;
+			c=skip_till_newline(c); break;
+		case V('I','P'):
+			sl=fill_words(c+j, wordlist, &words);
+			c=sl+1;
+			if (!dl_set[itemdepth]) {
+				out_html("<DL COMPACT>\n");
+				dl_set[itemdepth]=1;
+			}
+			out_html("<DT>");
+			if (words) {
+				scan_troff(wordlist[0], 1,NULL);
+			}
+			out_html("<DD>");
+			curpos=0;
+			break;
+		case V('T','P'):
+			if (!dl_set[itemdepth]) {
+				out_html("<DL COMPACT>\n");
+				dl_set[itemdepth]=1;
+			}
+			out_html("<DT>");
+			c=skip_till_newline(c);
+			/* somewhere a definition ends with '.TP' */
+			if (!*c) 
+				still_dd=1; 
+			else {
+				c=scan_troff(c,1,NULL);
+				out_html("<DD>");
+			}
+			curpos=0;
+			break;
+		case V('I','X'):
+			/* general index */
+			sl = fill_words(c+j, wordlist, &words);
+			c=sl+1;
+			j=4;
+			while (idxlabel[j]=='Z') 
+				idxlabel[j--]='A';
+			idxlabel[j]++;
+#ifdef MAKEINDEX
+			fprintf(idxfile, "%s %s@", fname, idxlabel);
+			for (j=0; j<words; j++) {
+				h=NULL;
+				scan_troff(wordlist[j], 1, &h);
+				fprintf(idxfile, "_\b %s", h);
+				free(h);
+			}
+			fprintf(idxfile,"\n");
+#endif
+			out_html("<A NAME=\"");
+			out_html(idxlabel);
+			/* this will not work in mosaic (due to a bug).
+			** Adding '&nbsp;' between '>' and '<' solves it,
+			** but creates
+			** some space. A normal space does not work.
+			*/
+			out_html("\"></A>");
+			break;
+		case V('L','P'):
+		case V('P','P'):
+			if (dl_set[itemdepth]) {
+				out_html("</DL>\n");
+				dl_set[itemdepth]=0;
+			}
+			if (fillout)
+				out_html("<P>\n");
+			else {
+				out_html(NEWLINE);
+				NEWLINE[0]='\n';
+			}
+			curpos=0;
+			c=skip_till_newline(c);
+			break;
+		case V('H','P'):
+			if (!dl_set[itemdepth]) {
+				out_html("<DL COMPACT>");
+				dl_set[itemdepth]=1;
+			}
+			out_html("<DT>\n");
+			still_dd=1;
+			c=skip_till_newline(c);
+			curpos=0;
+			break;
+		case V('P','D'): 
+			c=skip_till_newline(c); 
+			break;
+		case V('R','s'):	/* BSD mandoc */
+		case V('R','S'):
+			sl=fill_words(c+j, wordlist, &words);
+			j=1;
+			if (words>0)
+				scan_expression(wordlist[0], &j);
+			if (j>=0) {
+				itemdepth++;
+				dl_set[itemdepth]=0;
+				out_html("<DL COMPACT><DT><DD>");
+				c=skip_till_newline(c);
+				curpos=0;
+				break;
+			}
+		case V('R','e'):	/* BSD mandoc */
+		case V('R','E'):
+			if (itemdepth > 0) {
+				if (dl_set[itemdepth])
+					out_html("</DL>");
+				out_html("</DL>\n");
+				itemdepth--;
+			}
+			c=skip_till_newline(c);
+			curpos=0;
+			break;
+		case V('S','B'):
+			out_html(change_to_size(-1));
+			out_html(change_to_font('B'));
+			c=scan_troff(c+j, 1, NULL);
+			out_html(change_to_font('R'));
+			out_html(change_to_size('0'));
+			break;
+		case V('S','M'):
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			out_html(change_to_size(-1));
+			trans_char(c,'"','\a');
+			c=scan_troff(c,1,NULL);
+			out_html(change_to_size('0'));
+			break;
+		case V('S','s'):	/* BSD mandoc */
+			mandoc_command = 1;
+		case V('S','S'):
+			mode=1;
+		case V('S','h'):	/* BSD mandoc */
+				/* hack for fallthru from above */
+			mandoc_command = !mode || mandoc_command; 
+		case V('S','H'):
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			while (itemdepth || dl_set[itemdepth]) {
+				out_html("</DL>\n");
+				if (dl_set[itemdepth])
+					dl_set[itemdepth]=0;
+				else if (itemdepth > 0) 
+					itemdepth--;
+			}
+			out_html(change_to_font(0));
+			out_html(change_to_size(0));
+			if (!fillout) {
+				fillout=1;
+				out_html("</PRE>");
+			}
+			trans_char(c,'"', '\a');
+			add_to_index(mode, c);
+			out_html("<A NAME=\"");
+			out_html(label);
+			/* &nbsp; for mosaic users */
+			if (mode) 
+				out_html("\">&nbsp;</A>\n<H3>");
+			else 
+				out_html("\">&nbsp;</A>\n<H2>");
+			mandoc_synopsis = strncmp(c, "SYNOPSIS", 8) == 0;
+			c = mandoc_command ? 
+				scan_troff_mandoc(c,1,NULL) : 
+					scan_troff(c,1,NULL);
+			if (mode)
+				out_html("</H3>\n");
+			else 
+				out_html("</H2>\n");
+			curpos=0;
+			break;
+		case V('T','S'):
+			c=scan_table(c);
+			break;
+		case V('D','t'):	/* BSD mandoc */
+			mandoc_command = 1;
+		case V('T','H'):
+			if (!output_possible) {
+				sl = fill_words(c+j, wordlist, &words);
+				if (words>1) {
+					for (i=1; i<words; i++)
+						wordlist[i][-1]='\0';
+					*sl='\0';
+					output_possible=1;
+					out_html("<HTML><HEAD><TITLE>"
+						 "Manpage of ");
+					out_html(wordlist[0]);
+					out_html("</TITLE>\n</HEAD><BODY>"
+						 "\n<H1>");
+					out_html(wordlist[0]);
+					out_html("</H1>\nSection: ");
+					if (words>4)
+						out_html(wordlist[4]);
+					else
+						out_html(section_name(
+							wordlist[1]));
+					out_html(" (");
+					out_html(wordlist[1]);
+					if (words>2) {
+						out_html(")<BR>Updated: ");
+						scan_troff(wordlist[2], 
+							   1, NULL);
+					} else out_html(")");
+
+					out_html("\n");
+					printf("<BR><A HREF=\"");
+					if (URLbasename)
+					    printf(URLbasename);
+                                        printf("#index\">Index</A>\n");
+#if 0					
+					out_html("<BR><A HREF=\"");
+                                        out_html("#index\">Index</A>\n");
+#endif					
+					*sl='\n';
+#if 0
+					fputs("<BR><A HREF=\""
+					      "/index.html"
+					      "\">Return to Main Contents</A>\n", stdout);
+#endif
+					out_html("<HR>\n");
+					if (mandoc_command)
+						out_html("<BR>BSD mandoc<BR>");
+				}
+				c=sl+1;
+			} else c=skip_till_newline(c);
+			curpos=0;
+			break;
+		case V('T','X'):
+			sl=fill_words(c+j, wordlist, &words);
+			*sl='\0';
+			out_html(change_to_font('I'));
+			if (words>1)
+				wordlist[1][-1]='\0';
+			c=lookup_abbrev(wordlist[0]);
+			curpos+=strlen(c);
+			out_html(c);
+			out_html(change_to_font('R'));
+			if (words>1)
+				out_html(wordlist[1]);
+			*sl='\n';
+			c=sl+1;
+			break;
+		case V('r','m'):
+			/* .rm xx : Remove request, macro or string */
+		case V('r','n'):
+			/* .rn xx yy : Rename request,macro or 
+			** string xx to yy
+			*/
+		{
+			STRDEF *de;
+			c=c+j;
+			i=V(c[0],c[1]);
+			c=c+2;
+			while (isspace(*c) && *c!='\n')
+				c++;
+			j=V(c[0],c[1]);
+			while (*c && *c!='\n') 
+				c++;
+			c++;
+			de=strdef;
+			while (de && de->nr!=j)
+				de=de->next;
+			if (de) {
+				if (de->st) 
+					free(de->st);
+				de->nr=0;
+			}
+			de=strdef;
+			while (de && de->nr!=i) 
+				de=de->next;
+			if (de) 
+				de->nr=j;
+			break;
+		}
+		case V('n','x'):
+			/* .nx filename : next file. */
+		case V('i','n'):
+			/* .in +-N : Indent */
+			c=skip_till_newline(c);
+			break;
+		case V('n','r'):
+			/* .nr R +-N M: define and set number register R by +-N;
+			**  auto-increment by M
+			*/
+		{
+			INTDEF *intd;
+			c=c+j;
+			i=V(c[0],c[1]);
+			c=c+2;
+			intd=intdef;
+			while (intd && intd->nr!=i) 
+				intd=intd->next;
+			if (!intd) {
+				intd = (INTDEF*) malloc(sizeof(INTDEF));
+				intd->nr=i;
+				intd->val=0;
+				intd->incr=0;
+				intd->next=intdef;
+				intdef=intd;
+			}
+			while (*c==' ' || *c=='\t')
+				c++;
+			c=scan_expression(c,&intd->val);
+			if (*c!='\n') {
+				while (*c==' ' || *c=='\t')
+					c++;
+				c=scan_expression(c,&intd->incr);
+			}
+			c=skip_till_newline(c);
+			break;
+		}
+		case V('a','m'):
+			/* .am xx yy : append to a macro. */
+			/* define or handle as .ig yy */
+			mode=1;
+		case V('d','e'):
+			/* .de xx yy : define or redefine macro xx;
+			**  end at .yy (..) */
+			/* define or handle as .ig yy */
+		{
+			STRDEF *de;
+			int olen=0;
+
+			c=c+j;
+			sl=fill_words(c, wordlist, &words);
+			i=V(c[0],c[1]);j=2;
+			if (words==1) 
+				wordlist[1]=".."; 
+			else {
+				wordlist[1]--;
+				wordlist[1][0]='.';
+				j=3;
+			}
+			c=sl+1;
+			sl=c;
+			while (*c && strncmp(c,wordlist[1],j))
+				c=skip_till_newline(c);
+			de=defdef;
+			while (de && de->nr!= i) 
+				de=de->next;
+			if (mode && de)
+				olen=strlen(de->st);
+			j=olen+c-sl;
+			h = stralloc(j*2+4);
+			if (h) {
+				for (j=0; j<olen; j++)
+					h[j]=de->st[j];
+				if (!j || h[j-1]!='\n')
+					h[j++]='\n';
+				while (sl!=c) {
+					if (sl[0]=='\\' && sl[1]=='\\') {
+						h[j++]='\\'; sl++;
+					} else
+						h[j++]=*sl;
+					sl++;
+				}
+				h[j]='\0';
+				if (de) {
+					if (de->st)
+						free(de->st);
+					de->st=h;
+				} else {
+					de = (STRDEF*) malloc(sizeof(STRDEF));
+					de->nr=i;
+					de->next=defdef;
+					de->st=h;
+					defdef=de;
+				}
+			}
+		}
+		c=skip_till_newline(c);
+		break;
+		case V('B','l'):	/* BSD mandoc */
+		{
+			char list_options[NULL_TERMINATED(MED_STR_MAX)]; 
+			char *nl = strchr(c,'\n');
+
+			c=c+j;
+			if (dl_set[itemdepth]) {  /* These things can nest. */
+				itemdepth++;
+			}
+			if (nl) {		  /* Parse list options */
+				strlimitcpy(list_options,c,nl-c,MED_STR_MAX);
+			}
+			if (strstr(list_options, "-bullet")) {
+				/* HTML Unnumbered List */
+				dl_set[itemdepth] = BL_BULLET_LIST;
+				out_html("<UL>\n");
+			}
+			else if (strstr(list_options, "-enum")) { 
+				/* HTML Ordered List */
+				dl_set[itemdepth] = BL_ENUM_LIST;
+				out_html("<OL>\n");
+			}
+			else {		  /* HTML Descriptive List */
+				dl_set[itemdepth] = BL_DESC_LIST;
+				out_html("<DL COMPACT>\n");
+			}
+			if (fillout)
+				out_html("<P>\n"); 
+			else {
+				out_html(NEWLINE);
+				NEWLINE[0]='\n';
+			}
+			curpos=0;
+			c=skip_till_newline(c);
+			break;
+		}
+		case V('E','l'):	/* BSD mandoc */
+			c=c+j;
+			if (dl_set[itemdepth] & BL_DESC_LIST) {
+				out_html("</DL>\n");
+			}
+			else if (dl_set[itemdepth] & BL_BULLET_LIST) {
+				out_html("</UL>\n");
+			}
+			else if (dl_set[itemdepth] & BL_ENUM_LIST) {
+				out_html("</OL>\n");
+			}
+			dl_set[itemdepth]=0;
+			if (itemdepth > 0) 
+				itemdepth--;
+			if (fillout) 
+				out_html("<P>\n");
+			else {
+				out_html(NEWLINE);
+				NEWLINE[0]='\n';
+			}
+			curpos=0;
+			c=skip_till_newline(c);
+			break;
+		case V('I','t'):	/* BSD mandoc */
+			c=c+j;
+			if (strncmp(c, "Xo", 2) == 0 && isspace(*(c+2))) {
+				c = skip_till_newline(c); 
+			}
+			if (dl_set[itemdepth] & BL_DESC_LIST) {
+				out_html("<DT>");
+				out_html(change_to_font('B'));
+				if (*c=='\n') {	 
+					/* Don't allow embedded comms after 
+					** a newline */
+					c++;	  
+					c=scan_troff(c,1,NULL);
+				}
+				else {  /* Do allow embedded comms on 
+					** the same line. */
+					c=scan_troff_mandoc(c,1,NULL);
+				}
+				out_html(change_to_font('R'));
+				out_html(NEWLINE);
+				out_html("<DD>");
+			}
+			else if (dl_set[itemdepth] & 
+				 (BL_BULLET_LIST | BL_ENUM_LIST)) {
+				out_html("<LI>");
+				c=scan_troff_mandoc(c,1,NULL);
+				out_html(NEWLINE);
+			}
+			if (fillout) 
+				curpos++;
+			else curpos=0;
+			break;
+		case V('B','k'):	/* BSD mandoc */
+		case V('E','k'):	/* BSD mandoc */
+		case V('D','d'):	/* BSD mandoc */
+		case V('O','s'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('B','t'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			out_html(" is currently in beta test.");
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('B','x'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			out_html("BSD ");
+			c=scan_troff_mandoc(c, 1, NULL);
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('D','l'):	/* BSD mandoc */
+			c=c+j;
+			out_html(NEWLINE);
+			out_html("<BLOCKQUOTE>");	    
+			out_html(change_to_font('L'));
+			if (*c=='\n')
+				c++;
+			c=scan_troff_mandoc(c, 1, NULL);	    
+			out_html(change_to_font('R'));
+			out_html("</BLOCKQUOTE>");	    
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('B','d'):	/* BSD mandoc */
+		{			/* Seems like a kind of example/literal mode */
+			char bd_options[NULL_TERMINATED(MED_STR_MAX)]; 
+			char *nl = strchr(c,'\n');
+
+			c=c+j;
+			if (nl) {
+				strlimitcpy(bd_options,c,nl-c,MED_STR_MAX);
+			}
+			out_html(NEWLINE);
+			/* Remember options for terminating Bl */
+			mandoc_bd_options = 0;
+			
+			if (strstr(bd_options, "-offset indent")) {
+				mandoc_bd_options |= BD_INDENT;
+				out_html("<BLOCKQUOTE>\n");
+			}
+			if (strstr(bd_options, "-literal")
+			    || strstr(bd_options, "-unfilled")) {
+				if (fillout) {
+					mandoc_bd_options |= BD_LITERAL;
+					out_html(change_to_font(0));
+					out_html(change_to_size('0'));
+					out_html("<PRE>\n");
+				}
+				curpos=0;
+				fillout=0;
+			}
+			c=skip_till_newline(c);
+			break;
+		}
+		case V('E','d'):	/* BSD mandoc */
+			if (mandoc_bd_options & BD_LITERAL) {
+				if (!fillout) {
+					out_html(change_to_font(0));
+					out_html(change_to_size('0'));
+					out_html("</PRE>\n");
+				}
+			}
+			if (mandoc_bd_options & BD_INDENT)
+				out_html("</BLOCKQUOTE>\n");
+			curpos=0;
+			fillout=1;
+			c=skip_till_newline(c);
+			break;
+		case V('B','e'):	/* BSD mandoc */
+			c=c+j;
+			if (fillout)
+				out_html("<P>");
+			else {
+				out_html(NEWLINE);
+				NEWLINE[0]='\n';
+			}
+			curpos=0;
+			c=skip_till_newline(c);
+			break;
+		case V('X','r'):	/* BSD mandoc */
+		{
+			/* Translate xyz 1 to xyz(1) 
+			 * Allow for multiple spaces.  
+			 * Allow the section to be missing.
+			 */
+			char buff[NULL_TERMINATED(MED_STR_MAX)];
+			char *bufptr;
+
+			trans_char(c,'"','\a');
+			bufptr = buff;
+			c = c+j;
+			if (*c == '\n')
+				c++; /* Skip spaces */
+			while (isspace(*c) && *c != '\n')
+				c++;
+			while (isalnum(*c)) { /* Copy the xyz part */
+				*bufptr = *c;
+				bufptr++;
+				if (bufptr >= buff + MED_STR_MAX)
+					break;
+				c++;
+			}
+			while (isspace(*c) && *c != '\n')
+				c++;	/* Skip spaces */
+			/* Convert the number if there is one */
+			if (isdigit(*c)) {
+				*bufptr = '(';
+				bufptr++; 
+				if (bufptr < buff + MED_STR_MAX) {
+					while (isalnum(*c)) { 
+						*bufptr = *c; 
+						bufptr++; 
+						if (bufptr >= buff + 
+						    MED_STR_MAX)
+							break;
+						c++;
+					}
+					if (bufptr < buff + MED_STR_MAX) {
+						*bufptr = ')';
+						bufptr++;
+					}
+				}
+			}
+
+			while (*c != '\n') { /* Copy the remainder */
+				if (!isspace(*c)) {
+					*bufptr = *c;
+					bufptr++; 
+					if (bufptr >= buff + MED_STR_MAX)
+						break;
+				}
+				c++;
+			}
+			*bufptr = '\n';
+			scan_troff_mandoc(buff, 1, NULL);
+
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else 
+				curpos=0;
+		}
+		break;	  
+		case V('F','l'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			out_html("-");
+			if (*c!='\n') {
+				out_html(change_to_font('B'));
+				c=scan_troff_mandoc(c, 1, NULL);
+				out_html(change_to_font('R'));
+			}
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else 
+				curpos=0;
+			break;
+		case V('P','a'):	/* BSD mandoc */
+		case V('P','f'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else 
+				curpos=0;
+			break;
+		case V('P','p'):	/* BSD mandoc */
+			if (fillout)
+				out_html("<P>\n");
+			else {
+				out_html(NEWLINE);
+				NEWLINE[0]='\n';
+			}
+			curpos=0;
+			c=skip_till_newline(c);
+			break;
+		case V('D','q'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n') 
+				c++;
+			out_html("``");
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html("''");
+			out_html(NEWLINE);
+			if (fillout) 
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('O','p'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			out_html(change_to_font('R'));
+			out_html("[");
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(change_to_font('R'));
+			out_html("]");
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else 
+				curpos=0;
+			break;
+		case V('O','o'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			out_html(change_to_font('R'));
+			out_html("[");
+			c=scan_troff_mandoc(c, 1, NULL);
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('O','c'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(change_to_font('R'));
+			out_html("]");
+			if (fillout)
+				curpos++; 
+			else
+				curpos=0;
+			break;
+		case V('P','q'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			out_html("(");
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(")");
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('Q','l'):	/* BSD mandoc */
+		{		/* Single quote first word in the line */
+			char *sp;
+
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			sp = c;	  
+			do {	/* Find first whitespace after the 
+				 * first word that isn't a mandoc macro 
+				 */
+				while (*sp && isspace(*sp))
+					sp++;
+				while (*sp && !isspace(*sp))
+					sp++;
+			} while (*sp && isupper(*(sp-2)) && islower(*(sp-1)));
+
+				/* Use a newline to mark the end of text to 
+				 * be quoted 
+				 */
+			if (*sp) 
+				*sp = '\n';
+			out_html("`");	/* Quote the text */
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html("'");
+			out_html(NEWLINE);
+			if (fillout) 
+				curpos++;
+			else 
+				curpos=0;
+			break;
+		}
+		case V('S','q'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			out_html("`");
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html("'");
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else 
+				curpos=0;
+			break;
+		case V('A','r'):	/* BSD mandoc */
+			/* parse one line in italics */
+			out_html(change_to_font('I'));
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n') {	/* An empty Ar means "file ..." */
+				out_html("file ...");
+			}
+			else {
+				c=scan_troff_mandoc(c, 1, NULL);
+			}
+			out_html(change_to_font('R'));
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++; 
+			else 
+				curpos=0;
+			break;
+		case V('A','d'):	/* BSD mandoc */
+		case V('E','m'):	/* BSD mandoc */
+		case V('V','a'):	/* BSD mandoc */
+		case V('X','c'):	/* BSD mandoc */
+			/* parse one line in italics */
+			out_html(change_to_font('I'));
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(change_to_font('R'));
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else 
+				curpos=0;
+			break;
+		case V('N','d'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			out_html(" - ");
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++; 
+			else
+				curpos=0;
+			break;
+		case V('N','m'):	/* BSD mandoc */
+		{
+			static char mandoc_name[NULL_TERMINATED(SMALL_STR_MAX)] = "";
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (mandoc_synopsis) { 
+				/* Break lines only in the Synopsis. 
+				 * The Synopsis section seems to be treated
+				 * as a special case - Bummer!
+				 */
+				static int count = 0;
+				/* Don't break on the first Nm */
+				if (count) {
+					out_html("<BR>");
+				}
+				else {
+					char *end = strchr(c, '\n');
+					/* Remember the name for later. */					if (end) {
+						strlimitcpy(mandoc_name, 
+							    c, end - c,
+							    SMALL_STR_MAX);
+					}
+				}
+				count++;
+			}			
+			out_html(change_to_font('B'));
+			while (*c == ' '|| *c == '\t')
+				c++;
+			if (*c == '\n') {
+				/* If Nm has no argument,
+				 * use one from an earlier
+				 * Nm command that did have one. 
+				 * Hope there aren't
+				 * too many commands that do this.
+				 */
+				out_html(mandoc_name);
+			} else {
+				c=scan_troff_mandoc(c, 1, NULL);
+			}
+			out_html(change_to_font('R'));
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		}
+		case V('C','d'):	/* BSD mandoc */
+		case V('C','m'):	/* BSD mandoc */
+		case V('I','c'):	/* BSD mandoc */
+		case V('M','s'):	/* BSD mandoc */
+		case V('O','r'):	/* BSD mandoc */
+		case V('S','y'):	/* BSD mandoc */
+			/* parse one line in bold */
+			out_html(change_to_font('B'));
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(change_to_font('R'));
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else 
+				curpos=0;
+			break;
+		case V('D','v'):	/* BSD mandoc */
+		case V('E','v'):	/* BSD mandoc */
+		case V('F','r'):	/* BSD mandoc */
+		case V('L','i'):	/* BSD mandoc */
+		case V('N','o'):	/* BSD mandoc */
+		case V('N','s'):	/* BSD mandoc */
+		case V('T','n'):	/* BSD mandoc */
+		case V('n','N'):	/* BSD mandoc */
+			trans_char(c,'"','\a');
+			c=c+j;
+			if (*c=='\n') 
+				c++;
+			out_html(change_to_font('B'));
+			c=scan_troff_mandoc(c, 1, NULL);
+			out_html(change_to_font('R'));
+			out_html(NEWLINE);
+			if (fillout)
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('%','A'):	/* BSD mandoc biblio stuff */
+		case V('%','D'):
+		case V('%','N'):
+		case V('%','O'):
+		case V('%','P'):
+		case V('%','Q'):
+		case V('%','V'):
+			c=c+j;
+			if (*c=='\n')
+				c++;
+			/* Don't allow embedded mandoc coms */
+			c=scan_troff(c, 1, NULL);
+			if (fillout) 
+				curpos++;
+			else
+				curpos=0;
+			break;
+		case V('%','B'):
+		case V('%','J'):
+		case V('%','R'):
+		case V('%','T'):
+			c=c+j;
+			out_html(change_to_font('I'));
+			if (*c=='\n')
+				c++;
+			/* Don't allow embedded mandoc coms */
+			c=scan_troff(c, 1, NULL);
+			out_html(change_to_font('R'));
+			if (fillout) 
+				curpos++;
+			else
+				curpos=0;
+			break;
+		default:
+			/* search macro database of self-defined macros */
+			owndef = defdef;
+			while (owndef && owndef->nr!=i)
+				owndef=owndef->next;
+			if (owndef) {
+				char **oldargument;
+				int deflen;
+				int onff;
+
+				sl=fill_words(c+j, wordlist, &words);
+				c=sl+1;
+				*sl='\0';
+				for (i=1;i<words; i++) 
+					wordlist[i][-1]='\0';
+				for (i=0; i<words; i++) {
+					char *h=NULL;
+					if (mandoc_command) {
+						scan_troff_mandoc(wordlist[i],
+								  1,&h);
+					} else {
+						scan_troff(wordlist[i],1,&h);
+					}
+					wordlist[i]=h;
+				}
+				for (i=words;i<20; i++)
+					wordlist[i]=NULL;
+				deflen = strlen(owndef->st);
+				for (i=0; 
+				     (owndef->st[deflen+2+i]=owndef->st[i]);
+				     i++);
+				oldargument=argument;
+				argument=wordlist;
+				onff=newline_for_fun;
+				if (mandoc_command) {
+					scan_troff_mandoc(owndef->st+deflen+2,
+							  0, NULL);
+				} else {
+					scan_troff(owndef->st+deflen+2, 0, 
+						   NULL);
+				}
+				newline_for_fun=onff;
+				argument=oldargument;
+				for (i=0; i<words; i++) 
+					if (wordlist[i])
+						free(wordlist[i]);
+				*sl='\n';
+			}
+			else if (mandoc_command && 
+				 ((isupper(*c) && islower(*(c+1)))
+				  || (islower(*c) && isupper(*(c+1))))
+				) {
+				/* Let through any BSD mandoc commands 
+				 * that haven't
+				 * been delt with.
+				 * I don't want to miss anything out of 
+				 * the text.
+				 */
+				char buf[4];
+
+				strncpy(buf,c,2);
+				buf[2] = ' ';	
+				buf[3] = '\0';
+				/* Print the command(it might just be text). */
+				out_html(buf);
+				c=c+j;
+				trans_char(c,'"','\a');
+				if (*c=='\n') 
+					c++;
+				out_html(change_to_font('R'));
+				c=scan_troff(c, 1, NULL);
+				out_html(NEWLINE);
+				if (fillout) 
+					curpos++;
+				else
+					curpos=0;
+			} else {
+				c=skip_till_newline(c);
+			}
+			break;
+		}
+    }
+    if (fillout) { 
+	    out_html(NEWLINE);
+	    curpos++;
+    }
+    NEWLINE[0]='\n';
+    return c;
+}
+
+static int contained_tab=0;
+static int mandoc_line=0;	/* Signals whether to look for embedded mandoc
+				 * commands.
+				 */
+
+static char
+*scan_troff(char *c, int san, char **result)
+{   /* san : stop at newline */
+	char *h;
+	char intbuff[NULL_TERMINATED(MED_STR_MAX)];
+	int ibp=0;
+#define FLUSHIBP  if (ibp) { intbuff[ibp]=0; out_html(intbuff); ibp=0; }
+	char *exbuffer;
+	int exbuffpos, exbuffmax, exscaninbuff, exnewline_for_fun;
+	int usenbsp=0;
+
+	exbuffer=buffer;
+	exbuffpos=buffpos;
+	exbuffmax=buffmax;
+	exnewline_for_fun=newline_for_fun;
+	exscaninbuff=scaninbuff;
+	newline_for_fun=0;
+	if (result) {
+		if (*result) {
+			buffer=*result;
+			buffpos=strlen(buffer);
+			buffmax=buffpos;
+		} else {
+			buffer = stralloc(LARGE_STR_MAX);
+			buffpos=0;
+			buffmax=LARGE_STR_MAX;
+		}
+		scaninbuff=1;
+	}
+	h=c;
+	/* start scanning */
+	
+	while (*h && (!san || newline_for_fun || *h!='\n')) {
+		
+		if (*h==escapesym) {
+			h++;
+			FLUSHIBP;
+			h = scan_escape(h);
+		} else if (*h==controlsym && h[-1]=='\n') {
+			h++;
+			FLUSHIBP;
+			h = scan_request(h);
+			if (san && h[-1]=='\n')
+				h--;
+		} else if (mandoc_line
+			   && *(h) && isupper(*(h))
+			   && *(h+1) && islower(*(h+1)) 
+			   && *(h+2) && isspace(*(h+2))) {
+			/* BSD imbedded command 
+			   eg ".It Fl Ar arg1 Fl Ar arg2" */
+			FLUSHIBP;
+			h = scan_request(h);
+			if (san && h[-1]=='\n') 
+				h--;
+		} else if (*h==nobreaksym && h[-1]=='\n') {
+			h++;
+			FLUSHIBP;
+			h = scan_request(h);
+			if (san && h[-1]=='\n') 
+				h--;
+		} else {
+			if (h[-1]=='\n' && still_dd && isalnum(*h)) {
+				/* sometimes a .HP request is not 
+				   followed by a .br request */
+				FLUSHIBP;
+				out_html("<DD>");
+				curpos=0;
+				still_dd=0;
+			}
+			switch (*h) {
+			case '&':
+				intbuff[ibp++]='&';
+				intbuff[ibp++]='a';
+				intbuff[ibp++]='m';
+				intbuff[ibp++]='p';
+				intbuff[ibp++]=';';
+				curpos++;
+				break;
+			case '<':
+				intbuff[ibp++]='&';
+				intbuff[ibp++]='l';
+				intbuff[ibp++]='t';
+				intbuff[ibp++]=';';
+				curpos++;
+				break;
+			case '>':
+				intbuff[ibp++]='&';
+				intbuff[ibp++]='g';
+				intbuff[ibp++]='t';
+				intbuff[ibp++]=';';
+				curpos++;
+				break;
+			case '"':
+				intbuff[ibp++]='&';
+				intbuff[ibp++]='q';
+				intbuff[ibp++]='u';
+				intbuff[ibp++]='o';
+				intbuff[ibp++]='t';
+				intbuff[ibp++]=';';
+				curpos++;
+				break;
+			case '\n':
+				if (h[-1]=='\n' && fillout) {
+					intbuff[ibp++]='<';
+					intbuff[ibp++]='P';
+					intbuff[ibp++]='>';
+				}
+				if (contained_tab && fillout) {
+					intbuff[ibp++]='<';
+					intbuff[ibp++]='B';
+					intbuff[ibp++]='R';
+					intbuff[ibp++]='>';
+				}
+				contained_tab=0;
+				curpos=0;
+				usenbsp=0;
+				intbuff[ibp++]='\n';
+				break;
+			case '\t':
+			{
+				int curtab=0;
+				contained_tab=1;
+				FLUSHIBP;
+				/* like a typewriter, not like TeX */
+				tabstops[19]=curpos+1;
+				while (curtab<maxtstop && 
+				       tabstops[curtab]<=curpos)
+					curtab++;
+				if (curtab<maxtstop) {
+					if (!fillout) {
+						while (curpos<tabstops[curtab]) {
+							intbuff[ibp++]=' ';
+							if (ibp>480) {
+								FLUSHIBP; }
+							curpos++;
+						}
+					} else {
+						out_html("<TT>");
+						while (curpos<tabstops[curtab]) {
+							out_html("&nbsp;");
+							curpos++;
+						}
+						out_html("</TT>");
+					}
+				}
+			}
+			break;
+			default:
+				if (*h==' ' && (h[-1]=='\n' || usenbsp)) {
+					FLUSHIBP;
+					if (!usenbsp && fillout) {
+						out_html("<BR>");
+						curpos=0;
+					}
+					usenbsp=fillout;
+					if (usenbsp)
+						out_html("&nbsp;");
+					else
+						intbuff[ibp++]=' ';
+				} else if (*h>31 && *h<127)
+					intbuff[ibp++]=*h;
+				else if (((unsigned char)(*h))>127) {
+					intbuff[ibp++]='&';
+					intbuff[ibp++]='#';
+					intbuff[ibp++]='0'+((unsigned char)(*h))/100;
+					intbuff[ibp++]='0'+(((unsigned char)(*h))%100)/10;
+					intbuff[ibp++]='0'+((unsigned char)(*h))%10;
+					intbuff[ibp++]=';';
+				}
+				curpos++;
+				break;
+			}
+			if (ibp > (MED_STR_MAX - 20))
+				FLUSHIBP;
+			h++;
+		}
+	}
+	FLUSHIBP;
+    if (buffer) 
+	    buffer[buffpos]='\0';
+    if (san && *h)
+	    h++;
+    newline_for_fun=exnewline_for_fun;
+    if (result) {
+	*result = buffer;
+	buffer=exbuffer;
+	buffpos=exbuffpos;
+	buffmax=exbuffmax;
+	scaninbuff=exscaninbuff;
+    }
+    return h;
+}
+
+
+static char 
+*scan_troff_mandoc(char *c, int san, char **result)
+{
+    char *ret, *end = c;
+    int oldval = mandoc_line;
+
+    mandoc_line = 1;
+    while (*end && *end != '\n') {
+        end++;
+    }
+
+    if (end > c + 2
+        && ispunct(*(end - 1)) 
+	&& isspace(*(end - 2)) && *(end - 2) != '\n') {
+      /* Don't format lonely punctuation E.g. in "xyz ," format
+       * the xyz and then append the comma removing the space.
+       */
+        *(end - 2) = '\n';
+	ret = scan_troff(c, san, result);
+        *(end - 2) = *(end - 1);
+        *(end - 1) = ' ';
+    } else {
+	ret = scan_troff(c, san, result);
+    }
+    mandoc_line = oldval;
+    return ret;
+}
+
+int
+main(int argc, char **argv)
+{
+	char *t=NULL;
+	int i;
+	char *buf;
+	char *h = '\0';
+	STRDEF *stdf;
+	char *infile = NULL;
+
+	/* see if they gave us a basename for the URL references */
+
+	for(i = 1; i < argc; i++)
+	  {
+	    if(!strcmp(argv[i], "-n"))
+	      {
+		i++;
+		if(i >= argc)
+		  return 1;
+
+		URLbasename = strdup(argv[i]);		
+	      }
+	    else if(argv[i][0] == '-')
+	      return 2;
+	    else
+	      infile = argv[i];
+	  }
+
+	if(!infile || !strcmp(infile, "-"))
+	  infh = gzdopen(0, "r");
+	else
+	  {
+#ifdef HAVE_LIBBZ2
+	    if (strstr(infile,".bz2"))
+	      inbfh = bzopen(infile, "r");
+	    else
+#endif
+	    infh = gzopen(infile, "r");
+#ifdef HAVE_LIBBZ2
+	    if(!infh && !inbfh)
+#else
+	    if(!infh)
+#endif
+	      {
+		FILE *fh;
+		char cmdline[512], *ctmp, output[512];
+
+		/* Try searching for this as a man page name, instead */
+		ctmp = strrchr(infile, '.');
+		if(ctmp && (isdigit(*(ctmp+1)) || (*(ctmp+1) == 'n')) && *(ctmp+2) == '\0')
+		  {
+		    char section = *(ctmp+1);
+
+		    *ctmp = '\0';
+
+		    snprintf(cmdline, sizeof(cmdline), "man -w %c %s", section, infile);
+		  }
+		else
+		  snprintf(cmdline, sizeof(cmdline), "man -w %s", infile);
+
+		fh = popen(cmdline, "r");
+		fgets(output, sizeof(output), fh);
+		pclose(fh);
+
+		i = strlen(output) - 1;
+		while(isspace(output[i])) output[i--] = '\0';
+
+		if (output[0]) {
+#ifdef HAVE_LIBBZ2
+		  if(strstr(output,".bz2"))
+		    inbfh = bzopen(output, "r");
+		  else
+#endif
+		  infh = gzopen(output, "r");
+		}
+	      }
+	  }
+#ifdef HAVE_LIBBZ2
+	if(!infh && !inbfh) {
+#else	  
+	if(!infh) {
+#endif
+		printf("<HTML><HEAD><TITLE>Document not found</TITLE>\n"
+		       "</HEAD><BODY>The document \"%s\" couldn't be found. It may have been removed from your system.\n"
+		       "</BODY></HTML>\n", infile);
+
+		return 3;
+	}
+
+	buf=read_man_page();
+	if (!buf) {
+		t=strrchr(h,'.');
+		if (t) 
+			*t='\0';
+		t=strrchr(h,'/');
+		if (!t) 
+			t=h;
+		else
+			t++;
+		printf("<HTML><HEAD><TITLE>Bad manpage.</TITLE>\n"
+		       "</HEAD><BODY>\n<H1>Bad manpage.</H1>\n"
+		       "Sorry, unable to convert the manpage.\n"
+		       "</BODY></HTML>\n");
+		exit(0);
+	}
+	fname=h;
+
+	stdf=&standardchar[0];
+	i=0;
+	while (stdf->nr) {
+		stdf->next=&standardchar[i];
+		stdf=stdf->next;
+		i++;
+	}
+	chardef=&standardchar[0];
+	stdf=&standardstring[0];
+	i=0;
+	while (stdf->nr) {
+		stdf->next=&standardstring[i];
+		stdf=stdf->next;
+		i++;
+	}
+	strdef=&standardstring[0];
+	intdef=&standardint[0];
+	i=0;
+	while (intdef->nr) {
+		intdef->next=&standardint[i];
+		intdef=intdef->next;
+		i++;
+	}
+	intdef=&standardint[0];
+	defdef=NULL;
+	scan_troff(buf+1,0,NULL);
+	while (itemdepth || dl_set[itemdepth]) {
+		out_html("</DL>\n");
+		if (dl_set[itemdepth])
+			dl_set[itemdepth]=0;
+		else if (itemdepth > 0)
+			itemdepth--;
+	}
+	out_html(change_to_font(0));
+	out_html(change_to_size(0));
+	if (!fillout) {
+		fillout=1;
+		out_html("</PRE>");
+	}
+	out_html(NEWLINE);
+	if (output_possible) {
+		/* &nbsp; for mosaic users */
+		fputs("<HR>\n<A NAME=\"index\">&nbsp;</A><H2>Index</H2>\n<DL>\n",
+		      stdout);
+		manidx[mip]=0;
+		fputs(manidx,stdout);
+		if (subs) 
+			fputs("</DL>\n", stdout);
+		fputs("</DL>\n", stdout);
+/*		print_sig(); */
+		fputs("</BODY>\n</HTML>\n", stdout);
+	} else {
+		printf("<HTML><HEAD><TITLE>Invalid Manpage</TITLE></HEAD>\n"
+		       "<BODY><H1>Invalid Manpage</H1>\n"
+		       "You tried to retrieve an incorrect manpage.\n"
+		       "The page does not contain a manpage header and will\n"
+		       "not produce any output.\n"
+		       "If the page is a formatted manpage, you might want to use\n"
+		       "a different man2html (or cat2html) converter.\n");
+
+/*		print_sig(); */
+		fputs("</BODY>\n</HTML>\n", stdout);
+	}
+
+	if (buf)
+		free(buf);
+
+	return 0;
+}
diff --git a/help-converters/man/man2html.8 b/help-converters/man/man2html.8
new file mode 100644
index 0000000..431e319
--- /dev/null
+++ b/help-converters/man/man2html.8
@@ -0,0 +1,259 @@
+.\" man2html - UNIX Man Page to HTML translator
+.TH man2html 8 "3 May 1996" "Michael Hamilton" "Linux"
+.SH NAME
+man2html \- UNIX Man Page to HTML translator
+.SH SYNOPSIS
+\fBman2html\fP [options] [pagespec] 
+.SH DESCRIPTION
+\fBMan2html\fP is a UNIX Man Page to HTML translator that can be
+used as a CGI interface for man page access via httpd daemons.
+
+This man2html is more formally called \fBVH-Man2html\fP - Richard 
+Verhoeven's Man2html modified and packaged by Michael Hamilton.
+
+.B Man2html
+can be used to view man pages using your web browser.
+.B Man2html 
+locates compressed or uncompressed man pages
+anywhere in the normal man hierarchy.
+It translates pages in both the man(7) and 
+.I mandoc 
+(BSD) macro styles.  
+It generates html directly from  troff(1) and tbl(1)
+macro source without the need for 
+tbl/troff/nroff (sorry eqn isn't supported).  
+It generates links to other man pages, C include files, include files,
+and http references.
+Supporting CGI scripts allow you to browse HTML  whatis(1)
+subject indexes and name-only indexes.
+You can optionally add glimpse(1)
+(a text indexing package) to do full text searches.
+.PP
+There are five ways of requesting pages:
+
+.TP
+.I "\fBman2html"
+Invoking \fBman2html\fP without parameters causes the starting page
+to be presented.  You can use the search-able index on the starting
+page to enter requests corresponding to following requests.
+.PP
+.TP
+.I "\fBman2html \ \fIpage_name\fP"
+Invoking \fBman2html\fP with a \fIpage_name\fP" as a parameter will
+cause it to search for pages that match the name.  If more than one
+page is located, HTML for selecting any of the pages will be generated.
+If a single page is located, a redirect for full path name will
+be generated - which effectively re-invokes man2html with the full
+reference.
+.PP
+.TP
+.I "\fBman2html \ \fIpage_name \ \fIsection_number\fP"
+Similar to the above, but the required section is supplied to limit
+the search.
+.TP
+.I "\fBman2html \-M \ \fP/\fIman_hierarchy_toplevel \ \fIpage_name \fP"
+Similar to the above but the search is started in a particular
+man page hierarchy, for example /usr/local/man.
+.PP
+.TP
+.I "\fBman2html \ \fP/\fIfull_path_to_page_name\fB.\fIsection_number \fP"
+The specified man page is translated.  The page may optionally be
+compressed with any of the compess utilities defined in /etc/man.config.
+.SH BROWSING 
+To use these cgi scripts from a Web browser all you have to do is
+point your web browser at
+.nf
+        http://localhost/cgi-bin/man2html 
+.fi
+You can either save this location as a bookmark or use an editor to
+insert the following lines into an appropriate place in
+a top level document.
+.nf
+   <H3><A HREF="http://localhost/cgi-bin/man2html";>Linux Manual Pages</A></H3>
+.fi
+The netscape-man(1) script allows you to enter man page requests at
+the command line with the output presented in Netscape.  If you are
+already running netscape, the script will pass the request to the
+existing browser.  You can can use your shell to alias the name to
+something shorter if you wish.
+
+.B Man2html 
+has been tested with netscape(1) version 2.0 (I recommend Helvetica
+fonts) and with lynx(1) (lynx can't do tables).  Output for a large
+number of pages has been verified with weblint(1).
+.B Man2html 
+has also been tested as a server to other UNIX hosts.
+.SH INSTALLATION
+For some of the indexes to work you must generate the necessary
+databases.
+
+The manwhatis CGI script uses the /usr/man/whatis (see whatis(1)) file
+to build a man page index.  If this job has never been run (perhaps
+because you turn your machine off at night when cron might be
+scheduled to run it), you can build it by becoming the root user and
+entering:
+.nf
+   /usr/sbin/makewhatis /usr/man /usr/X11R6/man /usr/local/man
+.fi
+WARNING: makewhatis on my Caldera 1.0 takes about 30 minutes on my
+486DX66.  I have a modified version of makewhatis so that it does
+exactly the same job in only 1.5 minutes. My modified version is now
+available as part of man-1.4g.tar.gz:
+.nf
+   ftp://sunsite.unc.edu/pub/Linux/system/Manual-pagers
+.fi
+To use the Glimpse full text searching, you will need to install
+glimpse in /usr/bin.  
+The glimpse home ftp site is 
+.nf
+   ftp://ftp.cs.arizona.edu/glimpse/
+.fi
+Redhat rpm users can get glimpse from 
+.nf
+   ftp://ftp.redhat.com/pub/non-free/glimpse-3.0-1.i386.rpm
+.fi
+N.B. glimpse is not freely redistributable for commercial use.  
+Having installed glimpse, 
+you will need to
+build a glimpse index in /var/man2html.  This doesn't take too long -
+about 3 minutes on my 486DX2/66 16MB machine.  As root do:
+.nf
+  /usr/bin/glimpseindex -z -H /var/man2html /usr/man/man* /usr/X11R6/man/man* \
+      /usr/local/man/man* /opt/man/man*
+  chmod ugo+r /var/man2html/.glimpse*
+.fi
+The -z option causes glimpse to apply any filters (for decompression etc)
+specified in /var/man2html/.glimpse_filters.
+This could be set up as a cron job in /etc/crontab, e.g. (the following
+must be all on one line):
+.nf
+   21 04 * * 1 root /usr/bin/glimpseindex -H /var/man2html /usr/man/man* 
+       /usr/X11R6/man/man* /usr/local/man/man* /opt/man/man* ;
+       chmod +r /var/man2html/.glimpse*
+.fi
+To serve man pages to remote hosts, all that is required is a httpd 
+daemon that sets the environment variable SERVER_NAME correctly.
+The only problem you might have with this, is if your server machine
+has dual-names.
+.SH SECURITY
+
+I've modified Richard's man2html C code so that it checks all client
+input parameters.  It checks both for length and any characters that
+need escaping.
+
+Man2html will only return man or mandoc files resident in the man
+hierarchy defined in /etc/man.config.  When it returns references to
+any any other kinds of files, for example, include files, they will be
+"file:" references on the CLIENT host, not on the server.
+
+The parameters to the decompression programs are checked for any
+nasties.
+
+It is still possible for the contents of a man page to over-run
+man2html's memory - so I guess a hacker might try to get you to
+install a bogus man page in order to get man2html to do something
+nasty.
+
+The scripts check their parameters for anything suspicious.
+
+The scripts and program write suspicious requests to stderr - so they
+can be found in web server log files.
+.SH FILES
+.TP
+/etc/man.config
+Manpath and decompression configuration info from the man(1) config file.
+.TP
+/home/httpd/html/man.html
+Top level document loaded by man2html.
+.TP
+/home/httpd/html/mansearch.html
+Search page.
+.TP
+/home/httpd/html/mansearchhelp.html
+help for the search page.
+.TP
+/home/httpd/cgi-bin/man2html
+The C program that translates man and mandoc macros to HTML.
+.TP
+/home/httpd/cgi-bin/manwhatis
+Builds name-subject section indexes from the UNIX man whatis files.
+.TP
+/home/httpd/cgi-bin/mansearch
+Does glimpse searches.
+.TP
+/home/httpd/cgi-bin/mansec
+Searches the man page to create name-only indexes.
+.TP
+/usr/bin/netscape-man       
+Front end for netscape.
+.TP
+/var/man2html
+This directory holds a cache of indexes computed by manwhatis and mansec.
+They are updated if the whatis files or man directories are updated.
+The glimpse index is also expected to live here.
+.TP
+\.\.\./man/whatis
+Used by the manwhatis script.
+.SH ENVIRONMENT
+.TP 
+.B SERVER_NAME
+is used to obtain the server-name for redirects when a partial
+man-page specification is translated to a complete man-page path. 
+.SH SEE ALSO
+.IR man (1) ,
+.IR whatis (1) ,
+.IR apropos (1) ,
+.IR netscape-man (1) ,
+.IR netscape (1) ,
+.IR lynx (1)
+.IR glimpse (1) ,
+.B http://www.actrix.gen.nz/users/michael/giveaways.html
+
+.SH DISTRIBUTION
+This program (man2html.c) was written by Richard Verhoeven (NL:5482ZX35)
+at the Eindhoven University of Technology. Email: rcb5 win tue nl
+
+Permission is granted to distribute, modify and use this program as long
+as this comment is not removed or changed.
+
+My modifications, packaging and scripts are copyright (c) 1996 
+Michael Hamilton (michael actrix gen nz).  All rights reserved.
+
+Permission is hereby granted, without written agreement and without
+license or royalty fees, to use, copy, modify, and distribute this
+software and its documentation for any purpose, provided that the
+above copyright notice and the following two paragraphs appear in all
+copies of this software.
+
+IN NO EVENT SHALL MICHAEL HAMILTON BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF MICHAEL
+HAMILTON HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+MICHAEL HAMILTON SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ON AN "AS IS" BASIS, AND MICHAEL HAMILTON HAS NO OBLIGATION TO
+PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+.SH AUTHORS
+VH-Man2html was was written by Richard Verhoeven (NL:5482ZX35) at
+the Eindhoven University of Technology (Email: rcb5 win tue nl).  The
+original source is available from his web page at:
+
+	http://wsinwp01.win.tue.nl:1234/maninfo.html
+
+BSD mandoc support, indexing scripts, Makefile, man pages, and other
+packaging were added by Michael Hamilton (michael actrix gen nz).
+
+Maintenance and enhancement requests for this version should be directed
+to Michael Hamilton (michael actrix gen nz).
+.SH CREDITS
+As well as Richard, thanks are due to the following people for providing feedback
+and assistance:  
+Tim Bird <tbird caldera com>,
+Erick Branderhorst <branderh iaehv nl>,
+Michael De La Rue <mikedlr it com pl>,
+Christoph Lameter <clameter waterf org>,
+and
+Rainer Scholz <jrs startrek franken de>.
+
diff --git a/libgnome/.cvsignore b/libgnome/.cvsignore
new file mode 100644
index 0000000..878bb0a
--- /dev/null
+++ b/libgnome/.cvsignore
@@ -0,0 +1,21 @@
+Makefile.in
+Makefile
+*.lo
+*.la
+.deps
+_libs
+*-helper
+.libs
+so_locations
+gnome-dump-metadata
+gnome-moz-remote
+gconfigger
+gnome-gen-mimedb
+gnome-portability.h
+libgnome-2.0.pc
+test-libgnome
+libgnome.defs
+libgnometypebuiltins.h
+libgnometypebuiltins_evals.c
+libgnometypebuiltins_ids.c
+libgnometypebuiltins_vars.c
diff --git a/libgnome/ChangeLog b/libgnome/ChangeLog
new file mode 100644
index 0000000..b2dd6de
--- /dev/null
+++ b/libgnome/ChangeLog
@@ -0,0 +1,687 @@
+2001-04-11  Martin Baulig  <baulig suse de>
+
+	* gnome-program.c (gnome_program_initv): Call libgnome_type_init ()
+	instead of g_type_init (), moved g_type_init () call into
+	libgnome_type_init ().
+
+	* libgnomeP.h (libgnome_type_init): Added function prototype.
+
+	* Makefile.am: Create libgnome.defs and the type stuff using
+	gnome-maketypes.awk and gnome-makeenums.pl.
+
+	* libgnome-boxed.defs: New file.
+
+	* libgnometypes.c: New file.
+
+2001-04-11  Martin Baulig  <baulig suse de>
+
+	* libgnome.h: Use #include <libgnome/*.h> instead of "libgnome/*.h"
+	and #include <libgnome/gnome-ditem.h>.
+
+2001-04-11  Martin Baulig  <baulig suse de>
+
+	* gnome-util.h (PATH_SEP, PATH_SEP_STR): Moved to libgnomeP.h.
+	(g_is_image_filename): Removed function prototype.
+
+	* gnome-util.h (g_file_exists): Removed; use g_file_test() instead.
+
+2001-03-24  Martin Baulig  <baulig suse de>
+
+	* libgnome-2.0.pc.in: Depend on gconf-2.0.
+
+2001-02-26  jacob berkman  <jacob ximian com>
+
+	* gnome-url.c: default to using nautilus for help browsing if it
+	is available
+
+2000-07-26  John Sullivan  <sullivan eazel com>
+
+	* gnome-sound.c (use_sound): Moved this function out of a
+	#ifndef HAVE_LIBAUDIOFILE and into #ifdef HAVE_ESD.
+	This fixes the build breakage caused earlier today by Miguel's change.
+
+2000-07-11  Miguel de Icaza  <miguel gnu org>
+
+	* gnome-sound.c (gnome_sound_init): Store the esound hostname
+	here.
+	(gnome_sound_play): Use the use_sound routine here.
+	(gnome_sound_sample_load): ditto.
+	(use_sound): Delayed initialization of sound.
+
+2000-05-27  Miguel de Icaza  <miguel helixcode com>
+
+	* gnome-exec.c (gnome_execute_async_with_env_fds): Invoke setsid()
+	before execing the child process, as some applications terminate
+	by doing kill (0, SIGTERM) (mgp), so when we launch them from the
+	file manager they get the SIGTERM Message as well
+
+2000-04-03  Miguel de Icaza  <miguel gnu org>
+
+	* gnome-fileconvert.c (gfc_read_FileConverters): Do not depend on
+	initialization sequence to run.
+
+	* parse-path.cP (parse_path): Do not depend on the initialization sequence
+
+2001-03-21  Martin Baulig  <baulig suse de>
+
+	* Makefile.am: We're now in the new libgnome-2 module.
+	(bin_PROGRAMS): Don't build gnome-moz-remote for the moment since
+	it depends on X.
+
+2001-03-21  Martin Baulig  <baulig suse de>
+
+	* gnome-program.h (GNOME_PARAM_POPT_FLAGS, GNOME_PARAM_POPT_CONTEXT):
+	New properties.
+
+	* gnome-program.[ch]
+	(gnome_program_module_register, gnome_program_module_registered,
+	gnome_program_module_load): Removed the `GnomeProgram *' argument.
+	(gnome_program_install_property): First argument is now
+	`GnomeProgramClass *'.
+	(GnomeModuleInfo): The `init_pass' function no longer has a
+	`GnomeProgram *' argument, added `constructor' function.
+
+2001-03-20  Martin Baulig  <baulig suse de>
+
+	* gnome-program.[ch] (gnome_program_install_property): New
+	function; allows you to add a property to the GnomeProgramClass.
+
+	* gnome-program.h (GnomeFileDomain): New enum.
+	(GNOME_PARAM_GNOME_PATH): New property.
+	(gnome_program_locate_file): New function; this is a slightly
+	modified version of gnome_file_locate().
+
+2001-03-20  Martin Baulig  <baulig suse de>
+
+	* gnome-util.h (gnome_*_file): Use gnome_program_locate_file().
+	(gnome_file_domain_*): Removed.
+	(g_file_exists): #define this to use g_file_test().
+
+	* gnome-util.c (gnome_file_locate): Removed.
+	(g_file_exists): Removed.
+
+2001-03-20  Martin Baulig  <baulig suse de>
+
+	* gnomelib-init.[ch] (gnome_program_get_human_readable_name):
+	Moved to gnome-program.[ch].
+
+	* gnomelib-init.h (LIBGNOME_PARAM_*, libgnome_param_*):
+	Removed #defines and external declarations. There are corresponding
+	`GNOME_PARAM_*' #defines in gnome-program.h which are the names
+	of GnomeProgram's properties.
+
+	* test-libgnome.c: Simple test program.
+
+	* gnomelib-init2.[ch]: Removed, this is now gnome-program.[ch].
+
+	* gnome-program.[ch]: New files. This implements a `GnomeProgram'
+	GObject; most of the code is copied from gnomelib-init2.c, but
+	removed all the GnomeAttribute stuff and use GParam's.
+
+2001-02-28  Mikael Hallendal  <micke codefactory se>
+
+	* libgnome/: Fixed includes (added glib.h and gnome-defs.h
+	to the files needing it. Those are: gnome-config.h, gnome-ditem.h,
+	gnome-exec.h, gnome-fileconvert.h, gnome-i18n.h, gnome-regex.h,
+	gnome-remote.h, gnome-score.h, gnome-sound.h, gnome-triggers.h,
+	gnome-url.h, gnome-util.h, gnome-init.h).
+	
+2001-02-23  Martin Baulig  <baulig suse de>
+
+	* libgnome-2.0.pc.in: New file.
+	* Makefile.am: Install pkg-config file.
+
+2001-02-15  Darin Adler  <darin eazel com>
+
+	* gnomelib-init2.c: (gnome_program_preinita):
+	Mark "Help options" with a N_ so it can be translated.
+
+2000-12-26  Miguel de Icaza  <miguel helixcode com>
+
+	* gnome-moz-remote.c (main): Give preference to mozilla when
+	autodetecting.
+
+2000-12-09  Martin Baulig  <baulig suse de>
+
+	* gnome-dump.c, gnome-gen-mimedb.c, gnome-magic.c, gnome-magic.h,
+	gnome-metadata.c, gnome-metadata.h, gnome-mime-info.c,
+	gnome-mime-info.h, gnome-mime.c, gnome-mime.h: Removed.
+
+2000-12-09  Martin Baulig  <baulig suse de>
+
+	* gnomelibs-init.c (libgnome_loadinit): New static function; add
+	this as `loadinit' function to libgnome's GnomeModuleInfo and
+	call g_thread_init() here.
+
+2000-12-09  Martin Baulig  <baulig suse de>
+
+	* gnome-i18n.c: Comment out g_i18n_get_language_list() and
+	g_i18n_guess_category_value() until someone with a clue has
+	had a look at it.
+
+2000-11-22  Martin Baulig  <martin home-of-linux org>
+
+	* gnome-util.h (g_file_test): Removed.
+
+	* Makefile.am: Use $(GNOMESUPPORT_INCS) and $(GNOMESUPPORT_LIBS).
+
+2000-09-28  Martin Baulig  <baulig suse de>
+
+	* gnome-history.[ch]: Moved to libcompat.
+
+Thu Sep 28 03:34:52 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.c, gnome-moz-remote2.c, gnome-util.c, gnomelib-init2.c:
+	  use g_getenv instead of getenv
+
+Sun Sep 24 15:32:20 2000  George Lebl <jirka 5z com>
+
+	* gnome-exec.[ch]:  Improve some docs, and add function to
+	  deal with terminals according to user prefs.  Also some stylistic
+	  changes.
+
+	* gnome-ditem.c:  Use the gnome-exec function for getting the
+	  terminal command line
+
+	* gnome-portability.h.in:  remove the alloca thing as g_alloca is
+	  apparently now in glib.  The file is now empty and perhaps
+	  should be removed, unless there's further need for it.
+
+Sat Sep 23 17:28:25 2000  George Lebl <jirka 5z com>
+
+	* gnome-i18n.[ch]:  Add gnome_i18n_push_c_numeric_locale and
+	  gnome_i18n_pop_c_numeric_locale functions that do the job of
+	  pushing and poping "C" locale to make float<->string conversions
+	  work right in other locales.
+
+	* gnome-scores.c, gnome-config.c: use the above
+
+	* gnome-ditem.c: include gnome-url.h to avoid warning
+
+Fri Sep 15 18:47:06 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.[ch]: Launch Type=URL entries, and slight
+	  cosmetic updates
+
+Thu Sep 14 18:45:00 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.c: use g_path_get_dirname instead of g_dirname
+
+2000-09-09  Martin Baulig  <baulig suse de>
+
+	* gnome-util.c (g_copy_vector): Allow the argument to be NULL.
+
+Fri Sep 01 19:13:15 2000  George Lebl <jirka 5z com>
+
+	* gnome-url.[ch]: Use GError instead of homebrewed error return
+
+2000-08-31  Martin Baulig  <baulig suse de>
+
+	* gnome-i18n.c (gnome_i18n_get_language_list): Mark this as
+	deprecated and call g_i18n_get_language_list().  Moved most
+	stuff from this file into glib; you need the glib-2.0.patch
+	in the patches/ directory in order to use it.
+
+	* gnomelib-init.c: Initialize the gnome-vfs module.
+
+Wed Aug 30 22:22:47 2000  George Lebl <jirka 5z com>
+
+	* Makefile.am: cosmetic cleanups done in search of errors
+
+Thu Aug 24 03:11:54 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.c: use g_path_get_basename instead of g_basename
+
+Thu Aug 24 02:17:20 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.c: remove g_hash_table_freeze calls as freeze/thaw
+	  on hash tables is deprecated
+
+Thu Aug 24 01:45:11 2000  George Lebl <jirka 5z com>
+
+	* gnome-mime.c: remove include of gtk/gtk.h
+
+	* libgnome.h: remove gnome-dentry.h as it's in libcompat now
+
+	* gnome-init2.c, gnome-ditem.c: whoops, it's g_path_get_basename not
+	  g_path_basename
+
+2000-08-07  Martin Baulig  <baulig suse de>
+
+	Moved all deprecated files (i.e the ones that were linked into
+	libgnome-1-compat and not into libgnome) into their own
+	subdirectory (../libcompat).
+
+	* gnome-dentry.c, gnome-dentry.h, gnome-help.c, gnome-help.h,
+	gnome-popt.c, gnome-popt.h, gnome10-compat.c, gnome10-compat.h,
+	libgnome-compat-1.0.h: Moved to ../libcompat/.
+
+	* gnome-ditem.c: #include <popt.h> directly and not the deprecated
+	"gnome-popt.h"
+	* gnome-url.c: Likewise.
+
+2000-07-31  Karl Eichwalder  <ke suse de>
+
+	* gnome-moz-remote2.c: Add missing dots.
+
+2000-07-16  Jaka Mocnik  <jaka barbara>
+
+	* gnome-help.h (gnome_help_goto, gnome_help_pbox_goto): actually
+	add the const stuff.
+
+Fri Jul 14 01:41:05 2000  George Lebl <jirka 5z com>
+
+	* gnome-dentry.[ch]: s/int/gboolean/
+
+	* gnome-help.[ch]: add const stuff
+
+	* gnome-history.[ch]: add const stuff and GnomeHistoryEnt is a
+	  typedef to the structure and NOT the pointer as this is
+	  inconsistent with the rest of gnome and plain ugly
+
+	* gnome-mime-info.[ch]: const stuff
+
+	* gnome-regex.h: use a standard looking typedef for the structure
+
+	* gnome-score.[ch]: const stuff
+
+	* gnome-url.[ch]: GnomeURLDisplayContext again a typedef to
+	  the structure NOT the pointer so that we are consistent again
+
+	* gnomelib-init.[ch], gnomelib-init2.[ch]: const stuff
+
+Wed Jul 12 02:25:14 2000  George Lebl <jirka 5z com>
+
+	* gnome-config.c, gnome-ditem.c, gnome-i18n.[ch], gnome-mime-info.c,
+	  gnome-paper.[ch]:  Where an internal string or list is returned,
+	  make the return constant.  gnome_i18n_get_preferred_language is
+	  not constant, so remove the "const"
+
+	* gnome-mime-info.c: before reversing the language list, make a copy
+
+	* gnop-util.c: use g_strdup and not strdup
+
+2000-06-15  Jody Goldberg <jgoldberg home com>
+
+	* gnome-score.c (print_ascore) : setlocale returns a static buffer.
+	  Copy it to safety.  Set the locale AFTER storing the current
+	  setting.
+	(log_score) : Ditto.
+	(gnome_score_get_notable) : Ditto.
+
+	* gnome-config.c (_gnome_config_get_float_with_default): Ditto.
+	(_gnome_config_set_float) : Ditto.
+
+Mon Jun 12 18:40:33 2000  George Lebl <jirka 5z com>
+
+	* gnome-util.c: update the comments.  Just to make gtk-doc work on
+	  g_file_test, and take out the "will be removed thing on
+	  g_file_exists as it won't
+
+Fri May 26 12:24:02 2000  George Lebl <jirka 5z com>
+
+	* gnome-score.c: Applied patch from Dennis Bjorklund
+	  <dennisb cs chalmers se> to fix another unprotected atof with
+	  setting locale to "C" and then back.
+
+2000-05-18  Miguel de Icaza  <miguel gnu org>
+
+	* gnome-config.c (gnome_config_iterator_next): Implement as
+	documented.  
+	
+Sat May 06 16:46:13 2000  George Lebl <jirka 5z com>
+
+	* gnome-config.c (_gnome_config_get_float_with_default)
+	  (_gnome_config_set_float): setlocae for LC_NUMERIC to "C" and
+	  then back to original locale when reading and writing floats
+	  so that we can read/write floats over different locales
+
+	* gnome-score.c (gnome_get_score_file_name) (log_score): 
+	  The same as above.  Fixes bugs #10404, #10257
+
+Fri May 05 20:53:11 2000  George Lebl <jirka 5z com>
+
+	* gnome-url.c: gnome_url_show had it's return value inversed, duh!
+
+Fri May 05 19:22:30 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.c: include gnome-i18nP.h rather then gnome-i18n.h
+
+	* gnome-url.[ch]: add an error argument to gnome_url_show_full
+	  Fix one memory leak and one GList corruption bug.  Made it use
+	  gnome_exec_async rather then shell.  It will now correctly handle
+	  URIs with weird characters and no longer uses printf format strings
+	  taken from files.  When the handler is gnome-moz-remote, it
+	  first checks if the program ('netscape' or whatever gnome-moz-remote
+	  uses) actually exists.
+
+	* gnomelib-init2.c: fix a warning
+
+Sun Mar 26 13:31:28 2000  George Lebl <jirka 5z com>
+
+	* gnome-config.[ch],parse-path.cP: return TRUE/FALSE from the sync
+	  functions indicating an error in writing to a file, and do
+	  s/gint/gboolean/ a bit
+
+	* gnome-ditem.[ch]: return TRUE/FALSE from the _save function to
+	  indicate an error in saving
+
+Mon Mar 20 21:10:53 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.c: if no "C" locale setting found for name, set it
+	  to the filename or "Unknown" when saving.  This prevents problem
+	  with created files.  Also eliminate a possible buffer overrun.
+
+Mon Mar 20 20:36:35 2000  George Lebl <jirka 5z com>
+
+	* gnome-config.c: Apply patch from miguel made to gnome-libs-1-0,
+	  fix segfault when loading illegal files by correctly setting state
+	  after ignore.  also correctly set state after premature end of line
+	
+	* gnome-dentry.c: when saving names and comments, save them to the
+	  default (no language) first just in case there was no setting,
+	  fixes first part of #7300
+
+2000-02-24  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-util.c (g_concat_dir_and_file): dir or file being NULL is
+	an error.
+
+2000-02-18 Elliot Lee <sopwith redhat com>
+	* gnome-dentry.c: Try just looking for KDE icons in various common places instead of using
+	KDE_ICONDIR define.
+
+Sun Jan 30 12:49:59 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.c: fix two double free errors by applying a patch from
+	  Peter Wainwright <prw wainpr demon co uk> and fix a small leak
+	  in _unref
+
+Thu Jan 20 00:07:37 2000  George Lebl <jirka 5z com>
+
+	* gnome-mime.[ch]: add a function gnome_uri_extract_filename,
+	  which will take a single uri and return a newly allocated
+	  string with a local filename or NULL if it's not file: and
+	  local.  Use this in extract_filenames so that we actually
+	  get real files for things that specify hostname too
+
+	* gnome-ditem.c: use gnome_uri_extract_filename to test for
+	  something being a local file and use it to extract the filename
+	  itself.  If we actually append ".directory" and read the file,
+	  stat it again to get the correct mtime.  Store full path in
+	  location.  Make sure the type is "Directory" if and only if
+	  the loaded file is a ".directory".  Recognize "<dir>/.directory"
+	  as a directory file as well.  Add _() around the g_warning
+	  messages.  Fix .order file reading by opening the right file.
+
+Tue Jan 18 00:30:56 2000  George Lebl <jirka 5z com>
+
+	* gnome-util.c: (g_file_test) make the tests work sanely again.
+	  This had been changed to test an and of the conditions which
+	  doesn't make sense as something can never be a dir, a regular
+	  file and a link at the same time.  So it now agains properly
+	  tests an OR of the conditions, which also fixes
+	  gnome-pixmap-entry and anything else that used the function.
+
+Mon Jan 17 14:21:09 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.c: test for gnome-terminal's existence and fall back
+	  to xterm otherwise
+
+Sun Jan 16 02:43:14 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.[ch]: Add a basic "Type" attribute to the structure and
+	  gnome_desktop_item_get_type/set_type accessors
+	  Get and store other sections found in the file.
+	  Fix recognition of files by looking at all lines for the initial
+	  section header.
+	  Add a GNOME_DESKTOP_ITEM_LOAD_NO_OTHER_SECTIONS flag that will
+	  inhibit reading of other sections from files to speed up loading.
+	  Use gnome_config_sync_file and not gnome_config_sync
+	  Remove the tree reading/writing support, it's not justifiable
+	  for this to be in ditem, we need a separate simpler loader for
+	  trees.
+	  Add get_order/set_order functions for getting and setting the
+	  order of items for a directory ditem.
+	  Still read and store keys that have an empty value.
+	  Store the entire location in location, not just the basename.
+	  The _get_languages function gets a union of all languages from
+	  name and comment.
+	  The _save function sets the location to the new location.
+	  The _get_file_status no longer takes 'under' as we store the entire
+	  Actually start a terminal if we need to.
+	  Check the type (if set) before a launch (assume
+	  "KonsoleApplication" for kde things is an application for the
+	  terminal)
+	  Make world peace possible.
+	  Fix getting the terminal flag
+	  Allow clearing of names, comments and attributes by passing
+	  nulls as the new value.
+	  Allow mass clearing of names and comments.
+	  For _set_name and _set_comment default language to "C" if NULL.
+
+Sat Jan 15 00:53:48 2000  George Lebl <jirka 5z com>
+
+	* gnome-dentry.c, gnome-exec.c, gnome-moz-remote2.c, gnome-util.c:
+	  fix minor compiler warnings and a sizeof doesn't necessairly
+	  return int error.
+
+Thu Jan 14 23:56:08 2000  George Lebl <jirka 5z com>
+
+	* gnome-mime.c: make a local function static and fix a sizeof
+	is integer assumption when printing with g_message.
+
+	* gnome-url.c: fixed two sizeof(pointer) == sizeof(int) assumtions
+
+2000-01-13  Havoc Pennington  <hp redhat com>
+
+	* gnomelib-init2.c (gnome_program_module_register): Dump
+	bad-module-version message to stderr instead of stdout, and 
+	then exit(1) (we can't really continue, it will segfault
+	most of the time no doubt)
+	(gnome_program_version_check): reverse the version args 
+	to rpmvercmp
+
+Thu Jan 13 14:49:03 2000  George Lebl <jirka 5z com>
+
+	* gnome-i18n.c: fixup the inline doc to be more clear that the
+	  list returned from gnome_i18n_get_language_list should not be
+	  freed at all.
+
+2000-01-11  Havoc Pennington  <hp pobox com>
+
+	* gnomelib-init.c: move human readable name stuff into 
+	libgnome init files.
+
+2000-01-11  Havoc Pennington  <hp redhat com>
+
+	* gnomelib-init2.c: Add GNOME_PARAM_HUMAN_READABLE_NAME
+	(gnome_program_get_human_readable_name): convenience function 
+	to get it
+
+Sat Jan 08 19:06:47 2000  George Lebl <jirka 5z com>
+
+	* gnome-ditem.[ch]:  Switch exec from a vector to a simple string.
+	  change the _get_command and _set_command to return/take a simple
+	  string.  Also changed reading of .order file to not use a fixed
+	  buffer for reading.
+
+Sat Jan 01 18:45:26 2000  George Lebl <jirka 5z com>
+
+	* gnome-config.c,gnome-help.c,gnome-mime-info.c: Use LC_MESSAGES
+	  instead of LC_ALL to get the language to use for translating
+	  messages.  LC_ALL is used as well inside gnome-i18n anyway
+	  and messages need to use LC_MESSAGES if it's set
+
+	* gnome-help.c: s/g_fee/g_free/ in the inline docs for two functions
+
+1999-12-23  Havoc Pennington  <hp redhat com>
+
+	* gnomelib-init.c (libgnome_userdir_setup): Clean up this
+	code. Include strerror() in error messages, don't dump core (just
+	fprintf() then exit(1)), indent reasonably, don't use -1 as a
+	truth value.
+
+1999-12-21  Havoc Pennington  <hp redhat com>
+
+	* gnome-ditem.c: new functions to get the best comment/name to
+	display to the current user (by locale list).
+
+Wed Dec 15 14:15:37 1999  George Lebl <jirka 5z com>
+
+	* gnome-i18n.c: make sure we don't get into an infinite loop by
+	  descending only 30 levels before giving a warning.  This would
+	  only be the case for broken locale.alias, but we wanna handle it.
+	  I could have sworn that I did this before, guess not.
+
+Tue Dec 14 00:04:18 1999  George Lebl <jirka 5z com>
+
+	* gnome-mime-info.c: current_lang is a list of languages.  Also
+	  we store the previous key and it's language level when reading.
+	  (remove_this_key) removed this function as it is replaced by
+	  using g_hash_table_lookup_extended where we don't need to
+	  remove/readd, but just readd with the old key
+	  (context_add_key) take an extra 'lang' argument which is the
+	  language of the current key/value or NULL.  If the current 'lang'
+	  is higher then the previous key's lang level we replace the
+	  previous key with this key, otherwise we just add the key/value
+	  (load_mime_type_info_from) keep track of lang just like we do
+	  of 'key'
+	  (gnome_mime_flag) take the 'key' as an argument and do the right
+	  thing
+	  (gnome_mime_copiousoutput,gnome_mime_needsterminal) call the
+	  gnome_mime_flag with the 'key'
+
+	* gnome-mime-info.h: gnome_mime_nametemplate removed from the
+	  header as it was not actually implemented anywhere.  Also this
+	  file was slightly weirdly formatted and was not all that readable
+	  at 80 cols, so I removed some spurious tabs to make it so
+
+1999-12-13  Havoc Pennington  <hp redhat com>
+
+	* gnome-ditem.h, gnome-ditem.c: Add copyright, add Emacs magic, re-indent.
+
+1999-12-07  Martin Baulig  <martin home-of-linux org>
+
+	* gnome-mime-info.c (gnome_mime_init): Use `gnome_util_home_file'
+	instead of `gnome_util_user_home'
+
+Sun Dec 05 01:32:35 1999  George Lebl <jirka 5z com>
+
+	* gnome-dentry.c: fix the quoting, now we don't quote the exec vector
+	  from the dentry as this is the expected behaviour, but we do quote
+	  the arguments passed to gnome_desktop_entry_launch_with_args so
+	  that we work with filenames with spaces.  This will completely
+	  fix #4010.
+
+Fri Dec 03 21:23:56 1999  George Lebl <jirka 5z com>
+
+	* gnome-dentry.c: fix a segfault in join_with_quotes, fixes #4010
+
+1999-11-24  James Henstridge  <james daa com au>
+
+	* gnome-paper.h: added prototypes for new functions.
+
+	* gnome-paper.c (gnome_unit_with_abbrev): new function to find a
+	GnomeUnit by its abbreviation.
+	(gnome_unit_convert): convert from one set of units to another.
+	(gnome_unit_name): accessor for the name of a GnomeUnit.
+	(gnome_unit_abbrev): accessor for abbreviation of GnomeUnit.
+
+1999-11-17  Iain Holmes  <ih csd abdn ac uk>
+
+	* gnomelib-init.h: Removed gnomelib_init.
+
+	* gnome10-compat.[ch]: Added gnomelib_init as a function to pass fake
+	arguments to gnome_program_init.
+
+1999-11-16  Elliot Lee  <sopwith redhat com>
+
+	* gnome-url.[ch]: Add a callback for history maintainance.
+
+1999-11-15  Elliot Lee  <sopwith redhat com>
+
+	* gnomelib-init2.[ch]: Add gnome_program_module_load() (Dynamic module loading from --load-modules, $GNOME_MODULES).
+
+1999-11-11  Jacob Berkman  <jberkman andrew cmu edu>
+
+	        * gnome-config.c (gnome_config_make_vector): correctly
+	        handle the "a \b c" case (escaped character between 2
+	        spaces)
+	        (gnome_config_make_vector): george also suggested this
+	        fix
+
+	        Fixes bug #3475	
+
+1999-11-09  Elliot Lee  <sopwith redhat com>
+
+	* Makefile.am: Link libgnome to $(LIBGNOME_LIBS), not $(GLIB_LIBS).
+
+	* gnome-i18n.c: Add a comment about implementation behaviour.
+	* gnome-moz-remote2.c: Finish implementation of new gnome-moz-remote
+	* gnome-url.[ch]: Support new API with GnomeURLDisplayContext's, change gnome_url_show to just use this.
+	* gnome-util.[ch]: Add a "help" file domain, for looking up help files.
+	* gnome10-compat.[ch]: No change, stupid CVS.
+	* libgnome{,10compat}.h: Move gnome-help into 1.0 compat library.
+	* gnomelib-init2.c: Don't free the popt context unless that is specifically requested - programs need a sane way
+	to get to the args.
+
+1999-11-05  Havoc Pennington  <hp pobox com>
+
+	* gnome-util.h: Include gnome-defs.h
+
+1999-10-30  Dick Porter <dick acm org>
+
+	* Allow gnome-moz-remote to launch a netscape as a last resort, if
+		--remote cant find a running one.
+
+1999-10-27  Elliot Lee  <sopwith redhat com>
+
+	* gnomelib-init.h: Add attributes for application prefix/libdir/datadir/sysconfdir.
+	* gnome-util.c: Make use of these attributes in gnome_file_locate().
+
+	* gnome-ditem.[ch]: Add save routine, location accessors. Remove run-in-bg flag. Add check-for-changes routine.
+
+1999-10-26  Elliot Lee  <sopwith redhat com>
+
+	* gnome-ditem.[ch]: New files - replacement for gnome-dentry.[ch]
+	* gnome-util.[ch] (gnome_file_locate) Redo the file location stuff
+	                  (g_file_test): Use access() if only testing for existence. Also fix the other tests to
+			                 work slightly more sanely (check that all specified conditions are met,
+					 rather than that all unspecified conditions are not met).
+	                  (gnome_user_shell): Use g_strdup instead of strdup
+	* gnomelib-init2.c (gnome_program_attribute_get): Fix inverted error condition.
+	* gnomelib-init.h: Add an attribute for an application-provided file locator function.
+	* gnome-config.c: Recognize [yYtT1-9].* as TRUE boolean values, all others as FALSE boolean values.
+
+1999-10-21  Federico Mena Quintero  <federico redhat com>
+
+	* gnome-mime.c (add_ext): New helper function to add an
+	extension->mime_type mapping.  It checks for the presence of old
+	mappings of the same extension.  This fixes a memory leak in
+	add_to_key() when there are multiple mappings of an extension to
+	mime types in the .mime files.
+	(add_to_key): Use add_ext().
+
+1999-10-18  Jonathan Blandford  <jrb redhat com>
+
+	* Makefile.am (libgnome10compat_a_SOURCES): new compatibility lib.
+
+	* gnomelib-init2.c (gnome_program_parse_args): fixed so it compiles
+	(gnome_program_get): fixed so it compiles
+	(gnome_program_module_register): fixed so it compiles.
+
+1999-10-07  Elliot Lee  <sopwith redhat com>
+	* gnomelib-init2.[ch]: New implementation.
+	* gnomelib-init.[ch]: Use new init system.
+	* Makefile.am: Add gnome-portability.h, gnomelib-init{,2}.h to headers, remove gnome-popt.h from headers.
+	Add gnomelib-init2.c to sources, remove gnome-popt.c from sources.
+	* gconfigger.c, gnome-gen-mimedb.c, gnome-moz-remote.c: Use new init setup.
+	* gnome-i18n.h, gnome-i18nP.h: Instead of duplicating everything in two header files, add hooks so we can
+	avoid doing that.
+	* gnome-mime-info.c, gnome-util.c, gnome-util.h: Avoid using deprecated functions.
+	* gnome-mime.c: Case-insensitive file extension hashing.
+	* gnome-portability.h.in: New file (gives us a working g_alloca on any system).
+	* libgnome.h: Add new header files
+	* libgnomeP.h: avoid duplication with libgnome.h
+
diff --git a/libgnome/ChangeLog-19991006 b/libgnome/ChangeLog-19991006
new file mode 100644
index 0000000..c85e99a
--- /dev/null
+++ b/libgnome/ChangeLog-19991006
@@ -0,0 +1,2082 @@
+1999-10-06  Owen Taylor  <otaylor redhat com>
+
+	* gnome-config.c (access_config_extended): Always refill
+	the cache with valid values immediately after invalidating
+	this. This simplifies code, and (more importantly) fixes
+	a bug where we could return with cache_filename_value2
+	pointing to freed memory, and then later try to free
+	it again. (Bug #2618)
+
+1999-10-05  Owen Taylor  <otaylor redhat com>
+
+	(Bug #2593)
+	* gnome-i18n.c (read_aliases): Fix a memory leak by not
+	overwriting old entries in the alias hash table.
+
+	* gnome-dentry.c (gnome_desktop_entry_save): Fix a mem-leak
+	when saving desktop entries with comments.
+
+1999-10-04  Elliot Lee  <sopwith redhat com>
+	* gnome-sound.c: Don't set audio stream byte order - use what audiofile gives
+	us.
+
+1999-10-04  Elliot Lee  <sopwith redhat com>
+	* gnome-i18n.c: Revert a bugnum-less commit.
+	
+Mon Oct 04 11:24:51 1999  George Lebl  <jirka 5z com>
+
+	* gnome-i18n.c: in case the aliases would have a real infinite
+	  loop of the kind a=b, b=a, give up after 50 lookups
+
+1999-09-29  Elliot Lee  <sopwith redhat com>
+
+	* gnome-exec.c: Fix strange race condition. I don't think pipes
+ 	are persistent across multiple forks() - in this case the child
+ 	was closing the read end of the pipe, and the child of the child
+ 	was getting SIGPIPE even though the parent had the fd open still.
+
+Sun Sep 26 10:37:26 1999  George Lebl  <jirka 5z com>
+
+	* gnome-i18n.c from KUSANO Takayuki <AE5T-KSN asahi-net or jp> to
+	  avoid infinite loops in alias lookup
+
+1999-09-21  Federico Mena Quintero  <federico redhat com>
+
+	* gnome-i18n.c (gnome_i18n_init): Take out the patch for the
+	umpteenth time.  As was discussed on gnome-hackers, it is
+	Wrong(tm) to set an arbitrary default value for LC_ALL.
+
+1999-09-19  Owen Taylor  <otaylor redhat com>
+
+	* gnome-exec.c (gnome_execute_async_with_env_fds): Return
+	  -1 in case of failure. Also, some code cleanups.
+
+1999-09-17  Anders Carlsson  <anders carlsson tordata se>
+
+	* gnome-i18n.c (gnome_i18n_init): Set LC_CTYPE to en_US if it isn't
+	  already set. This prevents falling back to the "C" locale which
+	  doesn't support 8-bit characters
+
+Mon Sep 13 22:01:29 1999  George Lebl  <jirka 5z com>
+
+	* gnome-i18n.c: gnome_i18n_get_language_list now also tries to
+	  figure out aliases by reading in alias files from some standard
+	  locations
+
+1999-09-08  Martin Baulig  <martin home-of-linux org>
+
+	* gnome-triggers.h (GnomeTriggerType, _GnomeTriggerType):
+	Use `typedef enum { ... } GnomeTriggerType' instead of
+ 	`typedef enum _GnomeTriggerType { ... } GnomeTriggerType'.
+
+1999-09-01  Jacob Berkman  <jberkman andrew cmu edu>
+
+	* gnome-dentry.c (gnome_desktop_entry_load_flags_conditional): 
+	default type to Directory for KDE dentries.  Unfortunately for
+	directories, they do not specify the Type (at least for KDE 1.1.1)
+	Also, look in the KDE_ICONDIR for KDE icons
+
+	This fixes bug #2015
+
+1999-08-31  Federico Mena Quintero  <federico redhat com>
+
+	* gnome-metadata.c: Arrange order of #ifdef tests for db.
+
+	* gnome-dump.c: Likewise.
+
+1999-08-30  Federico Mena Quintero  <federico redhat com>
+
+	* gnome-triggers.h: Make it build.
+
+1999-08-29  Tom Tromey  <tromey cygnus com>
+
+	* gnome-mime.c (mime_mutex): New global.
+	(gnome_mime_type_or_default): Lock mutex.
+	(gnome_mime_type_of_file): Removed redundant call to
+	gnome_mime_type_from_magic.
+
+1999-08-28  Tom Tromey  <tromey cygnus com>
+
+	* gnome-metadata.c (metadata_list_nolock): New function.
+	(gnome_metadata_list): Use it.
+	(worker): Use it.
+	(init): Don't re-check `database'.
+
+	* gnome-metadata.c (database_mu): Now an ordinary static mutex.
+	(TLOCK): Removed.
+	(TUNLOCK): Likewise.
+	(lock): Removed `thread' argument.
+	(unlock): Likewise.
+	(Various): All mutex locking now done around body of exported
+	functions.
+
+Sat Aug 28 10:33:28 1999  George Lebl  <jirka 5z com>
+
+	* gnome-dentry.c: fix warnings
+
+1999-08-28  Ettore Perazzoli  <ettore comm2000 it>
+
+	* gnome-metadata.c: Temporarily #define `TUNLOCK()' and `TLOCK()'
+	to no-ops even if gthreads are available, to let gnome-libs
+	compile with GLib 1.2 again.
+
+1999-08-27  Tom Tromey  <tromey cygnus com>
+
+	* gnome-metadata.c (database_mu): New global.
+	(init): Lock and unlock mutex.
+	(lock): Likewise.  Added `thread' argument.  Updated all callers.
+	(unlock): Likewise.
+	(TLOCK): New macro.
+	(TUNLOCK): Likewise.
+	(try_app_regexs): Likewise.
+	(app_get_by_type): Likewise.
+	(try_regexs): Likewise.  Also, increment `p' inside the loop.
+	(run_file): Enable code.
+
+Fri Aug 27 15:40:57 1999  George Lebl  <jirka 5z com>
+
+	* gnome-dentry.[ch]: add functions for getting the i18n lists,
+	  and implement it using g_dataset instead of hash_table
+
+	* gnome-dentry.c: don't just concatenate the argument list when
+	  launching with argument list, but add quotes around each
+	  argument, and escape quotes inside arguments, and then
+	  concatenate with spaces
+
+Fri Aug 27 10:29:27 1999  George Lebl  <jirka 5z com>
+
+	* gnome-dentry.[ch]: added a structure for translations of
+	  name and comment field and store them in a list that is
+	  in a hashed keyed to the dentry pointer.
+
+Thu Aug 26 20:48:13 1999  George Lebl  <jirka 5z com>
+
+	* parse-path.cP: append current dir to relative filenames to fix
+	  bug #1968
+
+1999-08-26  Federico Mena Quintero  <federico redhat com>
+
+	* gnome-mime.c (add_to_key): Bertrand Guiheneuf
+	<Bertrand Guiheneuf inria fr> showed me how big a doofus I am.
+	Duplicate the key as well when we need to store a regex-based
+	definition.
+
+1999-08-23  Herbert Valerio Riedel  <hvr hvrlab dhs org>
+
+	* gnome-mime-info.c: args to strcmp() casted to (char*)
+
+1999-08-22  Herbert Valerio Riedel  <hvr hvrlab dhs org>
+
+	* gnome-paper.h: redundand extern "C" removed
+
+1999-08-20  Federico Mena Quintero  <federico redhat com>
+
+	* gnome-mime-info.c (context_new): Free the temporary string
+	before returning the context that was found.
+
+	* gnome-mime.c (mime_fill_from_file): Free the current key when we
+	are done.
+
+1999-08-17  Havoc Pennington  <hp pobox com>
+
+	* libgnome.h: comment about gnome-paper.h
+
+1999-08-14  Morten Welinder  <terra diku dk>
+
+	* gnome-config.c (access_config_extended): Add small cache.  Huge
+ 	win on systems with NFS.
+
+1999-08-01  Morten Welinder  <terra diku dk>
+
+	* gnome-i18n.c (explode_locale): Return modifier in "modifier",
+ 	not in "territory".
+	(compute_locale_variants): Plug a pile of leaks.
+	(gnome_i18n_get_language_list): Plug leak.
+
+1999-08-01	<sopwith redhat com>
+	* gnomelib-init.c: g_set_prgname(app_id);
+
+1999-07-13    <hp dhcpd7 redhat com>
+
+	* gnome-util.c: Remove g_filename_index() and g_filename_pointer()
+	cruft (already #if 0)
+	(gnome_datadir_file): wrong function name in inline docs
+	
+1999-06-12  Miguel de Icaza  <miguel gnu org>
+
+	* gnome-paper.c (paper_init): Push an empty configuration prefix. 
+
+1999-07-04  Owen Taylor  <otaylor redhat com>
+
+	* gnome-i18n.c (compute_locale_variants): Look for
+	variants of supplied locale value - e.g., for 
+	ja_JP.ujis, look (in order) for ja_JP.ujis, 
+	ja_JP, ja.ujis, and ja.
+
+1999-06-28  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-magic.c (read_string_val): Added break on default clause
+	to make it compile with some machines.
+
+1999-06-28  Miroslav Silovic  <silovic zesoi fer hr>
+
+	* gnome-config.h (gnome_config_private_clean_section):
+	(gnome_config_private_has_section): replaced Path with path. This
+ 	seems like an obvious typo, and made apps that call these with any
+ 	input paremeter other than path fail to compile
+
+1999-06-20  Michael Zucchi  <mzucchi zedzone mmc com au>
+
+	* gnome-magic.c (read_string_val): Add a limit on the buffer size
+	we will read into, and rewritten to be a little more robust.
+	Too long records will be truncated silently.
+	See bug  #657, #933, #1018 and #591.
+
+	* Makefile.am (INCLUDES): Added ADIOFILE_CFLAGS and ESD_CFLAGS to
+	includes list, to allow different installation location.
+	(see bug #748)
+
+1999-06-02  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-url.c (gnome_url_show): Remove debugging message.
+
+1999-05-24  David KAELBLING <drk sgi com>
+
+	* gnome-paper.c (gnome_paper_with_size): Removed spurious const attributes.
+
+1999-04-30  Owen Taylor  <otaylor redhat com>
+
+	* gnome-moz-remote.c (escape_url): Escape ',' characters
+	in URLs as %2c, since ',' characters are used to
+	separate the parameters to OpenURL.
+
+1999-04-27  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-history.c (gnome_history_get_recently_used): Remove "rt"
+	and use "r" in fopen call.
+	(write_history): ditoo.
+	* gnome-fileconvert.c (load_types_from): ditto
+	* gnome-score.c (log_score): ditto
+	(gnome_score_get_notable): ditto.
+	* gnome-mime.c (mime_fill_from_file): Ditto.
+	* gnome-triggers.c (gnome_triggers_readfile): ditto.
+
+Sat Apr 24 14:04:31 1999  George Lebl  <jirka 5z com>
+
+	* gnome-dentry.c: (gnome_desktop_entry_copy) copy the is_kde flag
+	  as well
+
+Fri Apr 23 01:18:57 1999  George Lebl  <jirka 5z com>
+
+	* gnome-config.c: minor doc fixes, and in make vector, don't
+	  assume that the '\' has a character after it. This function
+	  uses external data and shouldn't assume they are 100% correct
+
+Tue Apr 20 21:03:24 1999  George Lebl  <jirka 5z com>
+
+	* gnome-util.c: (g_file_exists) fix warning by returning FALSE from
+	  the assert
+
+	* gnome-moz-remote.c: fix warning by returning 0 on the end of main
+
+1999-04-16  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-triggersP.h: Remove external declaration as it is static.
+	Bug found by Ian Main on OpenBSD.
+
+1999-04-13  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-mime.c (mime_load): Fix memory leak, thanks again for
+	Morten for his careful reading of the source code.   This was a
+	side effect of the gnome.mime and user.mime additions. 
+
+1999-04-12  Jonathan Blandford  <jrb redhat com>
+
+	* gnome-util.c (g_file_exists): sanity check to make sure filename
+	exists.
+
+Sat Apr 10 20:56:25 1999  ape lrdpf spacetec no  (Asbjorn Pettersen)
+
+	* gnome-triggers.c (gnome_triggers_readfile): 
+	* gnome-fileconvert.c (load_types_from): Open file in TEXT mode.
+
+Fri Apr 09 18:47:46 1999  George Lebl  <jirka 5z com>
+
+	* gnome-config.c: documentation fixes and minor cleanups
+
+	* gnome-dentry.c: fix a problem with _save, as we have to push
+	  an empty section in case our caller pushed a different section
+
+1999-04-08  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-config.c (access_config_extended): Memory leak fix.
+	Thanks to Morten Wellinder for pointing this out again.
+
+	* gnome-help.c (gnome_help_file_find_file): Do not overwrite freed
+	memory. 
+
+Thu Apr  8 21:50:12 1999  ape lrdpf spacetec no  (Asbjorn Pettersen)
+
+	* gnome-score.c (gnome_score_get_notable): Open files in text mode.
+
+1999-04-05 Owen Taylor  <otaylor redhat com>
+
+	* gnome-dentry.c (gnome_desktop_entry_launch_with_args): Always
+	use /bin/sh to launch desktop entries, not the user shell.
+
+1999-03-11 Owen Taylor  <otaylor redhat com>
+
+	* gnome-dentry.[ch]: Add support for reading in .kdelnk
+	files and doing the proper subsitutions when launching
+	.kdelnk files.
+
+1999-04-05  Owen Taylor  <otaylor redhat com>
+
+	* dns-helper.c (main): NULL terminate the input
+	string properly.
+
+Fri Apr  2 20:55:28 1999  ape spacetec no  (Asbjorn Pettersen)
+
+	* gnome-history.c (write_history): 
+	* gnome-mime.c (mime_fill_from_file): Open file in TEXT mode.
+	This is for the OS/2 version.
+
+1999-03-31  James Henstridge  <james daa com au>
+
+	* gnome-config.c (access_config_extended): new function that checks
+	the config entries in more places than just ~/.gnome.  To be exact,
+	it first checks under $(sysconfdir)/gnome/config-override, then
+	~/.gnome, then $(sysconfdir)/gnome/config and as a final fallback,
+	the application specified default.
+	(_gnome_config_get_*_with_default): use access_config_extended to
+	read values provided that it isn't a private config entry, and it
+	wasn't an absolute filename (eg. =/something=/seciton/key).
+
+1999-03-30  Owen Taylor  <otaylor redhat com>
+
+	* gnome-config.c (is_loaded): Fix logic when a
+	config file is changed under us so it at least
+	doesn't segfault. Without locking I wouldn't
+	bet anything about correctness.
+
+1999-03-26  Nuno Ferreira  <nmrf rnl ist utl pt>
+
+	* gnome-dentry.c (gnome_desktop_entry_launch_with_args): free
+	uargv[0] using free(), it's allocated in gnome_util_user_shell()
+	using strdup().
+
+1999-02-23  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-fileconvert.c (gnome_file_convert): Make const correct.
+	
+Tue Mar 23 19:28:41 1999  George Lebl  <jirka 5z com>
+
+	* gnome-score.c,gnome-exec.c,gnome-entry.c: stuff that is allocated
+	  with g_malloc has to be free'd with g_free and vice versa
+
+Sun Mar 21 00:53:26 1999  George Lebl  <jirka 5z com>
+
+	* gnome-fileconvert.c: include string.h
+
+Sat Mar 20 00:52:41 1999  George Lebl  <jirka 5z com>
+
+	* gnome-config.c: doh! the last segfault fix, wasn't a segfault fix,
+	  the code was correct before, however I fixed a couple of memleaks
+	  anyway
+
+Fri Mar 19 12:53:11 1999  George Lebl  <jirka 5z com>
+
+	* gnome-config.c: when we want to reread the file when it was changed
+	  on disk we must wipe our current memory of it, dropping files
+	  caused a possible segfault and current wasn't reset when we
+	  dropped all.
+
+	* parse-path.cP: when we set pp->file to the error string, don't free
+	  it when releasing the path
+
+1999-03-18  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* Makefile.am (libgnome_la_LDFLAGS): Updated library version number.
+
+1999-03-18  James Henstridge  <james daa com au>
+
+	* Makefile.am (gnome_moz_remote_LDADD): removed -lXmu and -lXt.  I
+	don't know why it was linking with Xt before.
+
+	* gnome-moz-remote.c: made a number of changes so that when local URLs
+	(ie. file: ones) are given on the command line only local copies of
+	mozilla are used to display them.  Also fixed up the client window
+	search a bit.  It now uses the GNOME WM hints if available, otherwise
+	using recursive XQueryTree calls.  This also removes the dependency
+	on libXmu (which isn't available on HP-UX unless you compile X
+	yourself).
+
+Tue Mar 16 22:39:04 1999  Tim Janik  <timj gtk org>
+
+	* libgnome.h: 
+	* gnomelib-init.c:
+	(gnomelib_init): 
+	(create_user_gnome_directories):
+	setup and mkdir gnome_user_accels_dir as ~/.gnome/accels, this is used
+	for applications to save their accelerators.
+
+1999-03-12  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-mime-info.c (context_destroy_and_unlink): Splited from
+	context_destroy.  Context_destroy now only destroys the context.
+	(maybe_reload): Tries to find out if it would be wise to reload
+	the contents.  Reloads information if required. 
+	(load_mime_type_info): Use mime_dir_source_t instead of an
+	absolute path name now.
+
+1999-03-09  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-mime.c (maybe_reload): Implement mime-information
+	automatic reloading on changes.  There is a timeout of 5 seconds
+	to reload information to avoid excesive stating as usual.
+
+1999-03-11  Jonathan Blandford  <jrb redhat com>
+
+	* gnome-mime.c (mime_load_from_dir): We want to open gnome.mime
+	first and user.mime last.  This way we have a consistent set of
+	defaults, and a way for the user to override (but not remove) any
+	value.
+
+	* gnome-mime-info.c (load_mime_type_info_from_dir): We want to
+	open gnome.keys first and user.keys last.
+
+1999-03-08  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-exec.c (gnome_execute_async_with_env_fds): Set SIGPIPE to
+	point to SIG_DFL here.
+
+1999-03-07  Raja R Harinath  <harinath cs umn edu>
+
+	* gnome-util.c (gnome_dirrelative_file): Rationalize.  Fix a bug
+	with it not working if prefix == $HOME and $GNOMEDIR is not set.
+
+1999-02-34  Eckehard Berns  <eb berns i-s-o net>
+
+	* gnome-help.c (gnome_help_file_find_file): revert the stripping of '#'
+	anchors after the correct file is found.
+
+1999-02-24  Felix Bellaby <felix pooh u-net com>
+
+	* gnome-exec.c (gnome_execute_async_with_env_fds): clean up fds.
+
+1999-02-23  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-metadata.c (unlock): Do not access database-> here.
+
+	* gnome-sound.c (gnome_sound_shutdown): Make the sound file
+	descriptor be in sync with reality.
+
+	* gnome-mime.c (gnome_mime_type_or_default): If no extension is
+	found, only scan the regular expressions.
+
+Sat Feb 20 03:11:29 1999  Timur Bakeyev <mc bat ru>
+
+	* parse-path.cP (GNOME_CONFIG_PARSE_ERROR): Declared static, as other-
+	wise it polute global namespase (and gives linker errors).
+
+1999-02-18  Felix Bellaby <felix pooh u-net com>
+
+	* parse-path.cP (parse_path): warn when invalid paths are parsed.
+
+1999-02-17  Elliot Lee  <sopwith redhat com>
+
+	* gnome-util.c: As per the warning (which has been there for
+	almost a month) g_copy_strings disappears, replaced by g_strconcat.
+
+1999-02-16  Ulrich Drepper  <drepper cygnus com>
+
+	* libgnome/gnome-mime.c (add_to_key): Likewise.
+	* libgnome/gnome-config.c (check_path): Likewise.
+	* libgnome/gnome-score.c (gnome_score_get_notable): Likewise.
+	
+1999-02-16  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-metadata.c (worker): Added missing call to unlock
+
+1999-02-13  Tom Tromey  <tromey cygnus com>
+
+	* gnome-metadata.c (ZERO): New macro.
+	(metadata_set): Zero DBTs.
+	(metadata_get_list): Likewise.
+	(metadata_get_no_dup): Likewise.
+	(gnome_metadata_list): Likewise.
+	(try_regexs): Likewise.
+	(metadata_remove): Don't reuse return value from db.
+
+Thu Feb 11 23:56:18 1999  George Lebl  <jirka 5z com>
+
+	* gnome-dentry.c,gnome-url.c: use gnome_config_sync_file instead of
+	  gnome_config_sync
+
+1999-02-10  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-metadata.c (app_get_by_type): Do not try to lookup the
+	metadata if no information sources were found or loaded.
+
+	* gnome-mime.c (mime_fill_from_file): Remove trailing ':'
+
+	* gnome-paper.c: Use new names GnomePaper and GnomeUnit.  Keep the
+	old versions for compatibility with other apps.
+
+1999-02-09  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-exec.c (gnome_execute_shell): no semantic changes at this
+	point in the release schedule.  If you need the stuff not to close
+	file descriptors, use the proper API.
+
+1999-02-09  Chris Lahey  <clahey umich edu>
+
+	* gnome-paper.c: Made the conversion factors a bit more accurate.
+
+1999-02-05  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-mime-info.h: Constify
+
+1999-02-06  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* gnome-metadata.c (maybe_scan_app_dir): It is not necessary to
+	cast scan_app_file when passing it to scandir().  Pointed out by
+	Frederic L.W.Meunier (linux urbi com br).
+
+1999-02-05  Felix Bellaby <felix pooh u-net com>
+
+	* gnome-config.c (gnome_config_make_vector): Unescape characters
+	escaped in gnome_config_assemble_vector.
+
+1999-02-05  Jeff Garzik  <jgarzik pobox com>
+
+	* gnome-metadata.c:
+	Fix small API doc typo.
+
+1999-02-03  James Henstridge  <james daa com au>
+
+	* gnome-config.h (gnome_config_private_set_*): most of these macros
+	were broken.  They specified val as an argument, then didn't use it
+	in the expansion.  I changed it to look like the gnome_config_set_*
+	macros.
+
+1999-02-01  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-metadata.c (lock): If the metatada directory is still
+	locked after 30 seconds, claim metadata-lock ownership.
+
+1999-01-27  Jeff Garzik  <jgarzik pobox com>
+
+	* gnome-config.c, gnome-exec.c, gnome-help.c, gnome-metadata.c:
+	Include autoconf incantation for defining alloca.
+	Surround config.h with #ifdef HAVE_CONFIG_H as necessary.
+
+	* gnome-exec.c, gnome-magic.c, gnomelib-init.c:
+	Add break statement to trailing default switch case.
+
+	* gnome-popt.c, gnome-triggers.c:
+	Remove unused alloca.h include.
+
+1999-01-27  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/Makefile.am (INCLUDES): Use a G_LOG_DOMAIN of `Gnome'.
+	Suggested by Tim Janik <timj gtk org>.
+
+1999-01-25  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-util.c: Make the indentation be consistent.
+
+1999-01-25  Ulrich Drepper (drepper cygnus com)
+
+	* libgnome/gnome-config.c, libgnome/gnome-metadata.c,
+	libgnome/gnome-mime-info.c: On systems that define getc_unlocked
+	stdio is thread safe.  With locally opened files it is not
+	necessary to use the locking.  Therefore POSIX (and gnu libc
+	includes this feature) defines some _unlocked functions and they
+	always should be used in these cases.
+
+1999-01-21  Sebastian Wilhelmi  <wilhelmi ira uka de>
+
+	* libgnome/Makefile.am (INCLUDES):
+	s%$(datadir)/locale%$(gnomelocaledir)%
+
+	* libgnome/gnome-util.h (gnome_util_user_home): Use
+	g_get_user_dir() from beloved GLIB instead of reding it from the
+	environment.
+
+	* libgnome/gnomelib-init.c (gnomelib_init): Use
+	gnome_util_user_home() instead of doing it `by hand'.
+
+1999-01-21  Havoc Pennington  <hp pobox com>
+
+	* libgnome/gnome-triggers.c (gnome_triggers_play_sound): Don't 
+	spew warnings if esound is not compiled in.
+
+1999-01-20  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/type.convert: Add files to do file convertions.
+
+	* libgnome/gnome-fileconvert.c (gfc_read_FileConverters): Load
+	convertion types from the system installed directory and from the
+	user directory.. 
+
+1999-01-20  Nat Friedman  <nat nat org>
+
+	* libgnome/gnome-help.c (gnome_help_pbox_goto): This is a new
+ 	function to be used in place of gnome_help_pbox_display when you
+ 	don't want it to append "-sheetnum.html" to the help path.
+
+1999-01-20  Carsten Schaar  <nhadcasc fs-maphy uni-hannover de>
+
+	* libgnome/gnomelib-init.c: Added translation domain to table of
+ 	options.
+
+1999-01-18  Nat Friedman  <nat nat org>
+
+	* libgnome/gnome-help.c (gnome_help_display): Added assertions.
+	(gnome_help_pbox_display): New convenience function to connect to
+ 	the "help" signal of a GnomePropertyBox.
+
+1999-01-18  Jeff Garzik  <jgarzik pobox com>
+
+	* gnome-exec.c:
+	Include string.h for string prototypes
+
+	* gnome-help.c:
+	Include gnome-url.h for gnome_url_show() proto
+
+	* gnome-metadata.c:
+	Eliminated const-ness warnings.
+
+	* gnome-mime.[ch]:
+	Made several functions const-correct.
+
+	* gnome-score.c:
+	s/strdup/g_strdup/ to eliminate ANSI warnings.
+
+1999-01-18  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-score.c: Include sys/fsuid.h only if present.
+
+1999-01-14  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-config.c: TProfile now has a last_checked field
+	that registers when was the last time we statted the file.  This
+	avoid us making expensive system calls while loading a bunch of
+	values from GnomeConfig.
+
+1999-01-13  Havoc Pennington  <hp pobox com>
+
+	* libgnome/gnome-popt.h: Place the inclusion of the popt header
+	inside BEGIN_GNOME_DECLS, because the popt header does not
+	properly #ifdef __cplusplus. This should probably be fixed in 
+	popt itself.
+
+1999-01-12  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-util.c (g_copy_strings): Need to keep this for
+	binary compatibility.
+
+	* libgnome/gnome-help.c (gnome_help_goto): Use gnome_url_show.
+	Document all entry points.
+
+1999-01-12  Christopher Blizzard  <blizzard appliedtheory com>
+
+	* libgnome/gnome-dentry.c: NULL terminate calls to g_strconcat()
+
+	* libgnome/gnome-util.c: NULL terminate list in calls to
+ 	g_strconcat()
+
+Mon Jan 11 11:54:00 1999  Manish Vachharajani <mvachhar vger rutgers edu>
+
+	* libgnome/gnome-exec.c: Remove the _with_fds functions and 
+	add a new _fds API with a flag to ask if you want to close fds or 
+	not.
+
+1999-01-11  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnomelib-init.c (gnomelib_init): Improved
+	gnome_user_home_dir handling.  Instead of using the HOME setting
+	only, it will try to use getpwnam ("USER") or getpwuid (getuid ())
+	if getenv (HOME) fails.
+
+1999-01-08  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-triggers.c (gnome_trigger_do_mediaplay): Removed
+	the warning.
+
+1999-01-10  Jeff Garzik  <jgarzik pobox com>
+
+	* libgnome/gnome-util.[ch], libgnome/gnome-dentry.[ch]:
+	Move gnome_is_program_in_path to gnome-util.
+
+1999-01-10  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-metadata.c (metadata_lock, metadata_unlock): We
+	have no choice but to provide these functions.
+
+Sun Jan 10 14:03:00 1999  Manish Vachharajani <mvachhar vger rutgers edu>
+
+	* libgnome/gnome-exec.c: add _with_fds version of all
+	gnome_execute functions for people who don't want the fd's close on
+	calls to gnome_execute_async
+
+Sat Jan 09 13:43:01 1999  Manish Vachharajani <mvachhar vger rutgers edu>
+
+	* libgnome/gnome-exec.c: make all the gnome_exec functions close
+	all but the 0, 1, and 2 file descriptors
+	
+Sat Jan 09 01:28:21 1999  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: fixed sync_file, it didn't work quite right always
+
+Fri Jan 08 17:51:00 1999  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.[ch]: made the set and sync functions
+	  depreceated and removed their guts, as they were Fundementatly
+	  Broke(tm) anyhow
+
+Fri Jan 08 17:09:11 1999  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.[ch]: don't you hate it when you don't
+	  test if it compiles, oh well, fixed it up, I forgot about the
+	  private thing before
+
+Fri Jan 08 17:01:56 1999  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.[ch]: add a per file sync function
+
+1999-01-07  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-mime-info.c (load_mime_type_info_from): Comments
+	are only allowed at the first column.
+
+1999-01-07  Chris Lahey  <clahey umich edu>
+
+	* libgnome/gnome-paper.h, libgnome/gnome-paper.c: Added
+	gnome_paper_convert_to_points for gnome-paper-selector.
+
+1999-01-06  Martin Baulig  <martin home-of-linux org>
+
+	* libgnome/gnome-triggers.c (gnome_triggers_play_sound): Applied
+	a patch from Gleef to make this work without ESD.
+
+1999-01-06  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-metadata.c (metadata_get_list): Initialize the
+	database if required here.
+
+Tue Jan 05 22:52:46 1999  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-dentry.c: use the alloca macros to squeeze out
+	  some speed for panel menu loading
+
+1999-01-05  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-gen-mimedb.c (main): Removed the ugly hack for
+	including function definitions.
+
+	* libgnome/gnome-magic.h: Expose here the information.
+
+	* libgnome/gnome-magic.c: Added documentation.  Made an internal
+	function static.
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_load_flags): Added
+	in-line documentation to this file as well.
+
+	The gnome-name-server no longer links with the gnome libraries, it
+	only uses the GTK+ libraries.  And if we can go X-only it would be
+	so much better.
+
+1999-01-04  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-mime.c (gnome_mime_type_of_file,
+	gnome_mime_type_or_default_of_file): Hook gnome-magic here.  Note
+	that these are not the fast versions, but the slow versions (as
+	advertised in the documentation).
+
+Sat Jan  2 22:44:37 PST 1999 Manish Singh <yosh gimp org>
+
+	* libgnomeui/Makefile.am: ok, I dunno how this was working before,
+	but it was broken. Use the perl and awk checks and a REBUILD rule
+	like gtk+ for the autogened files.
+
+1998-01-02  Jeff Garzik  <jgarzik pobox com>
+
+	* libgnome/gnome-util.[ch]:
+	Replaced g_copy_strings with compatibility define pointing to
+	g_strconcat.  Left function in place for binary compatibility.
+
+1999-01-02  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-mime-info.c (remove_this_key): Release the
+	correct pointer. 
+
+	* libgnome/gnome-metadata.c: Made this module use g_malloc/g_strdup/g_free.
+
+1999-01-02  Jeff Garzik  <jgarzik pobox com>
+
+	* libgnome/gnome-dump.c, libgnome/gnome-magic.c,
+	  libgnome/gnome-metadata.c, libgnome/gnome-util.c,
+	  libgnorba/gnome-name-server.c, libgnorba/goad.c,
+	  libgnorba/orbitns.c:
+	Wrap _xxx_SOURCE defines in libgnome,
+	add _xxx_SOURCE defines in libgnorba.
+	
+1999-01-01  Jeff Garzik  <jgarzik pobox com>
+
+	* libgnome/gnome-dump.c, libgnome/gnome-magic.c,
+	  libgnome/gnome-metadata.c, libgnome/gnome-util.c,
+	  libgnomeui/gnome-calculator.c, libgnomeui/gnome-canvas-util.c,
+	  libgnomeui/gnome-client.c, libgnomeui/gnome-dock.c,
+	  libgnomeui/gnome_segv.c, libgnomeui/gtkdial.c:
+	Added a few _xxx_SOURCE defines where necessary to get the code
+	to compile under 'gcc -ansi -pedantic'.
+
+1998-12-31  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-config.c (_gnome_config_clean_file): Removed the
+	current optimization, as it was wrong.
+	(_gnome_config_drop_file): Remove the current optimization as it
+	was wrong. 
+
+Wed Dec 30 16:46:56 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: for _file methods accept files ending
+	  in '/'
+
+1998-12-30  Jeff Garzik  <jgarzik pobox com>
+
+	* libgnome/*.c, libgnomeui/*.c, zvt/*.c, etc.:
+	s/g_copy_strings/g_strconcat/
+
+1998-12-30  Jeff Garzik  <jgarzik pobox com>
+
+	* gnome-config.c:
+	s/g_copy_strings/g_strconcat/
+	Added an alloca() call to speed things up.
+	Reformatted a bit.
+
+Wed Dec 30 01:01:58 1998  George Lebl  <jirka 5z com>
+
+        * libgnome/gnome-fileconvert.c, libgnome/gnome-gen-mimedb.c,
+          libgnome/gnome-history.c, libgnome/gnome-magic.c,
+          libgnome/gnome-triggers.c, libgnorba/goad.c: use fclose to
+          close the files we open, we were leaking file descriptors all
+          over the damn place!
+
+Tue Dec 29 22:44:27 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnomelib-init.c: move allocation of the _private
+	  dir to the actual init call to make sure it gets allocated
+
+Tue Dec 29 21:02:57 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-dentry.c: fixed a whole bunch of memory leaks
+	  in search of the "big one"
+
+Tue Dec 29 20:25:08 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: for "section" functions accept string
+	  ending in "/"
+
+        * libgnome/gnome-dentry.c: drop file and fix a memory leak in
+	  _save function
+
+1998-12-17  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-metadata.c (gnome_metadata_list): Database was
+	not auto-initialized on gnome_metadta_list
+
+1998-12-16  Sven Neumanns  <sven gimp org>
+
+	* replaced all occurences of gtk_label_set() with
+	gtk_label_set_text() 
+
+Sun Dec 27 22:13:53 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: prefix_list should be initialized to
+	  NULL, fix memory leak with remove_link, also during drop
+	  file, free the profile if we can
+
+	* libgnorba/goad.c: (goad_server_list_read) fix memory leak by
+	  freeing the dummy GString, and drop the config file that we read
+	  to conserve memory
+
+1998-12-25  Jeff Garzik  <jgarzik pobox com>
+
+	* configure.in:
+	removed 'ru' from ALL_LINGUAS, so that make distcheck works again
+
+1998-12-17  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-metadata.c (gnome_metadata_list): Database was
+	not auto-initialized on gnome_metadta_list
+
+1998-12-16  Sven Neumanns  <sven gimp org>
+
+	* replaced all occurences of gtk_label_set() with
+	gtk_label_set_text() 
+
+1998-12-14  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* gnome-data/mime.types: New format for the mime.type file.
+
+	* libgnome/gnome-mime-info.c (main): Moved the query information
+	here. Renamed the gnome_mime_type_* routines to gnome_mime_*.
+
+	* libgnome/gnome-mime.c: New implementation.  We now use the GNOME
+	provided mime type information instead of the system provided one
+	(This is for several reasons, first is that the mime.types file
+	format is lame; the second one is that mismatches in the mime-type
+	database will produce mistakes; the third one is: most non GNU
+	systems lack mime.types, and if they have one, it is basically
+	old, so we would have to provide ours anyways).
+
+	This file has full API docs.
+
+1998-12-14  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/Makefile.am (EXTRA_DIST): Removed lib_date.README from
+	EXTRA_DIST.
+
+1998-12-14  Sebastian Wilhelmi  <wilhelmi ira uka de>
+
+	* libgnome/lib_date.README, libgnome/lib_date.c,
+	libgnome/lib_date.h, libgnome/lib_defs.h: Removed. Use GDate from
+	glib instead.
+	
+	* libgnome/Makefile.am: Changed accordingly.
+
+Sat Dec 12 11:38:46 1998 Gregory McLean <gregm comstar net>
+	
+	* libgnome/gnome-paper.[c|h] gnome-url.[c|h] : Updated FSF address
+
+1998-12-11  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-mime-info.c: New file.  It implements bindings of
+	keys based on the mime-type.
+
+1998-12-07  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-config.c (dump_profile): Wonder who has been
+	hacking madly at this, as the ->to_be_deleted feature did not seem
+	to work these days at all.  I even wonder when was this introduced.
+	(gnome_config_assemble_vector): Account for the spaces inserted
+	between the strings.
+
+	* libgnorba/orbitgtk.c (gnome_name_service_get): Use a reliable
+	scheme for fetching the name server IOR.  We use the proxy window
+	scheme to find the name service IOR. 
+	
+1998-12-10  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-gen-mimedb.c (main): 
+
+1998-12-08  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-gen-mimedb.c (main): Use stdio for I/O, as we
+	were not checking proper usage of write.  Improved the error
+	messages. 
+
+1998-12-09  Michael Lausch  <mla gams at>
+
+        * corrected CVS trioubles with gnome-regex and gnome-metadata
+	
+	* libgnome/gnome-metadata.c (maybe_scan_app_dir): don't free the
+        list pointer if it's NULL.
+
+        * libgnome/gnome-regex.c (gnome_regex_cache_set_size): fence post 
+        error corrected.
+
+1998-12-08  Herbert Valerio Riedel  <hvr hvrlab ml org>
+
+	* libgnorba/orbitgtk.c (orb_remove_connection): added proper cast
+
+	* libgnome/gnome-magic.c (gnome_magic_parse): made infile_name
+	pointer to constant string
+	(gnome_magic_db_load): added pointer cast
+
+	* libgnome/gnome-remote.[ch] (gnome_remote_set_command): made
+	argv-argument a constant array to constant strings
+
+1998-12-08  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-metadata.c (get_worker): Make sure to call
+	gnome_mime_type_or_default when looking for `type'.  Check mime
+	type after application-installed information.
+
+1998-12-07  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-regex.c (DEFAULT_SIZE): Make the cache larger. 
+	(gnome_regex_cache_compile): Fix test.  
+
+Nov 26, 1998 Elliot Lee
+	
+	. libgnome/gnome-mime.c: read gnomedatadir/mime.types as well
+	. In general, move data files not associated with any specific
+	  directory into a 'gnome-data' directory.
+	
+1998-12-07  James Henstridge  <james daa com au>
+
+	* libgnome/gnome-url.c: Documented this module.
+
+1998-12-06  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-i18n.c: Documented.
+
+	* libgnome/gnome-exec.c: Documented.
+	* libgnome/gnome-remote.c: Documented.
+	(gnome_remote_set_command): Call gnome_config_set_vector.
+	* libgnome/gnome-regex.c: Documented.
+
+1998-12-03  Raja R Harinath  <harinath cs umn edu>
+
+	* configure.in (TEST_INTERNAL): Remove.
+	* acconfig.h (TEST_INTERNAL): Remove.
+	* libgnome/gnome-config.c: Include parse-path.cP.
+	(parse_path): Move to ...
+	* libgnome/parse-path.cP: ... here.  New file.
+	* libgnome/Makefile.am (EXTRA_DIST): Distribute `parse-path.cP'.
+	(gnome-config.o): Add explicit dependency to parse-path.cP.
+
+	* Makefile.am (SUBDIRS): Distribute, but don't build, `libvfs'.
+
+Tue Dec  1 02:43:15 PST 1998 Manish Singh <yosh gimp org>
+
+	* configure.in
+	* libgnome/Makefile.am: sed magic to extract glib stuff from
+	GTK_CFLAGS and GTK_LIBS
+
+1998-11-29  Justin Maurer  <justin openprojects net>
+
+	* libgnome/gnome-hook.[ch]: removed. Updated Makefiles/etc. to reflect 
+	this.
+
+Nov 26, 1998  Elliot Lee  <sopwith redhat com>
+	
+	* libgnome/gnome-mime.c: read gnomedatadir/mime.types as well
+	In general, move data files not associated with any specific
+	directory into a 'gnome-data' directory.
+
+
+1998-11-26  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-util.c (gnome_unconditional_config_file):
+	Document properly most of this file.
+
+	* libgnome/gnome-util.h: Remove ugly macro hack
+
+1998-11-26  Jeff Garzik  <jgarzik pobox com>
+
+	* gnome-config.c, gnome-moz-remote.c:
+	Replaced sprintf calls with g_snprintf.
+	Updated a couple hardcoded length values to instead of sizeof().
+
+Thu Nov 26 02:48:07 1998  George Lebl  <jirka 5z com>
+
+	* gnome-util.c: replace g_file_exists with g_file_test which can
+	test for more things
+
+1998-11-25  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/gnome-moz-remote.c (gnomesupport.h): New include.
+
+1998-11-23  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-config.c (release_path): Free p->file.
+	(parse_path): Make sure p->file is always duplicated.
+
+1998-11-23  Christopher Blizzard  <blizzard appliedtheory com>
+
+	* libgnome/gconfigger.c: Change include to <libgnome.h> not
+ 	<libgnomeP.h>
+
+1998-11-23  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/gnome-metadata.c (try_app_regexs): Patch from Tom
+	Tromey to do a foreach() on the hash table only if it exists.
+
+1998-11-23  Christopher Blizzard  <blizzard appliedtheory com>
+
+	* libgnome/gconfigger.c: Include <libgnomeP.h> not <gnome.h>.
+  	This should take care of the circular dependency problems.
+
+1998-11-20  James Henstridge  <james daa com au>
+
+	* gnome-libs.spec: added %{prefix}/etc/paper.config to the %files
+	section.
+
+Thu Nov 19 01:27:34 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.[ch]: changed the behaviour of
+	  gnome_config_clean_file to be consistent with the functionality
+	  of the other _clean_ function, which fixes a whole bunch of apps
+	  which expected that exact behaviour. Renamed the old _clean_file
+	  to gnome_config_drop_file, which is consistent with the drop_all
+	  function, but only for one file. Also added a whole bunch of
+	  performance tweaks that even show panel improvement with menu
+	  reading on my machine, so this should be more significant on
+	  slower machines.
+
+	* libgnome/gnome-dentry.[ch]: replaced the only usage of clean_file
+	  that was expecting the broken behaviour with drop_file
+
+Tue Nov 17 19:27:50 PST 1998 Manish Singh <yosh gimp org>
+
+	* libgnorba/goad.c
+	* libgnome/gnome-sound.c: some #includes to cleanup declarations
+
+1998-11-17  Martin Baulig  <martin home-of-linux org>
+
+	* libgnome/Makefile.am (gnome_moz_remote_LDADD): Added `-lXext'.
+
+
+1998-11-09  Jeff Garzik  <jgarzik pobox com>
+
+	* acconfig.h, configure.in, libgnome/Makefile.am,
+	  devel-docs/libgnome.sgml, libgnome/Makefile.am,
+	  libgnome/gnome-dl.c, libgnome/gnome-dl.h, libgnome/libgnome.h,
+	  libgnome/libgnomeP.h, libgnomeui/Makefile.am,
+	  libgnomeui/gnome-dateedit.c, libgnomeui/gtkcalendar.c,
+	  libgnomeui/gtkcalendar.h, libgnomeui/libgnomeui.h,
+	  test-gnome/testgnome.c:
+
+	  	Removed gnome-dl and gtkcalendar modules.
+
+1998-11-09  Seth Alves  <alves hungry com>
+
+	* libgnome/gnome-dl.c (gnome_dl_load): added a this-is-obsolete
+	printf
+
+1998-11-04  Raja R Harinath  <harinath cs umn edu>
+
+	* configure.in: Don't check $need_gnome_support.  Always use
+	gnomesupport.
+	(popt): Remove check.  It is in `gnomesupport' now.
+	* gnome.h: Include `gnomesupport.h' unconditionally.
+	* libgnome/libgnome.h: Reorder headers.
+	* libgnome/libgnomeP.h: Sync to libgnome.h.
+
+1998-10-30  Seth Alves  <alves hungry com>
+
+	* libgnome/gnome-paper.c: attempt to fix scaling ps values
+	to other units
+	(gnome_paper_Xmargin): add calls to retrieve margin values
+
+1998-10-29  Seth Alves  <alves hungry com>
+
+	* libgnome/paper.config: added more paper sizes along
+	with default margin sizes
+
+1998-10-28  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/gnome-fileconvert.c (gfc_read_FileConverters): 
+	Made static.
+	(gfc_reset_path): Likewise.
+
+	* libgnome/gnome-triggers.c (actiontypes): Made const.
+
+	* libgnome/gnome-util.c (image_extensions): Made const.
+
+	* libgnome/gnome-paper.c (units): Made const.
+
+	* libgnome/lib_date.c: Made the data arrays const so that they can
+	be shared.
+
+1998-10-20  Ettore Perazzoli  <ettore comm2000 it>
+
+	* libgnome/Makefile.am (gnome_moz_remote_LDADD): Added `-lXt'.
+  	Otherwise, Red Hat 5.x links the old libXt for libc5 by default.
+
+Sun Oct 18 02:08:20 1998  Owen Taylor  <otaylor gtk org>
+
+	* libgnome/libgnome.h: Add in gnome-mime.h, since 
+	gnome_uri_list_* is (temporarily?) there.
+
+	* libgnome/gnome-mime.[ch]: Added functions to decompose
+	data of the type text/uri-list.
+
+1998-10-16  Martin Baulig  <martin home-of-linux org>
+
+	* configure.in (--enable-test-internals): New parameter. Define
+	`TEST_INTERNALS' if enabled and add new `TEST_INTERNALS' automake
+	conditional. This is used to add wrapper functions for some
+	static functions so they can be used in the test suite.
+
+	* acconfig.h (TEST_INTERNALS): Define this if configured with
+	`--enable-test-internals'.
+
+	* libgnome/gnome-config.c (_test_suite_gnome_config_parse_path):
+	If `TEST_INTERNALS' is defined, define this function which is a
+	wrapper for parse_path ().
+
+1998-10-14  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-metadata.c (unlock): Synchronize the database
+	before unlocking.
+
+1998-10-13  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-metadata.c: Added documentation.
+
+1998-10-10  Carsten Schaar  <nhadcasc fs-maphy uni-hannover de>
+
+	* libgnome/Makefile.am (gnome_moz_remote_LDADD): Added '$(INTLLIBS)'.
+
+1998-10-09  James Henstridge  <james daa com au>
+
+	* libgnome/Makefile.am:  Checked in the changes to the Makefile
+	that Havoc hadn't fixed for me (sorry).
+
+1998-10-08  Havoc Pennington  <hp pobox com>
+
+	* libgnome/Makefile.am, libgnomeui/Makefile.am: Build and install
+	gnome-url.h, gnome-url.c, gnome-href.h, gnome-href.c, since they
+	are in the header files.
+
+1998-10-08  James Henstridge  <james daa com au>
+
+	* libgnome/gnome-url.[ch]: Added gnome-url code.  It currently
+	defaults to using netscape (If you don't edit ~/.gnome/Gnome).
+	* libgnome/gnome-moz-remote.c libgnome/vroot.h:  Added a wrapper
+	that can be used for starting netscape.  If netscape it will
+	tell that copy to display the given URL, optionally in a new
+	window.  It also contains the 'netscape -remote' functionality
+	using the --remote argument.
+
+		
+
+1998-10-01  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	(free_keys): I am a dork.  Revert last change.
+
+	* libgnome/gnome-config.c (free_keys): Fixed the memory leaks
+	introduced by the "private" handling.
+	(parse_path): Same.
+
+	* Makefile.am: Use '?' to separate the sed
+	commands as ',' is used when people pass -Wl,something.
+
+1998-09-28  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/libgnomeP.h: Sync with `libgnome.h'.
+
+1998-09-28  Elliot Lee  <sopwith redhat com>
+
+	* libgnome/Makefile.am
+	* configure.in
+	* libgnome/gnomelib-init.c
+	* libgnome/gnome-sound.[ch]
+	  Add some convenience wrappers for using sound in gnome programs.
+	  The configure.in hack needs improvement - perhaps esound needs an
+	  esound-config?
+
+Sun Sep 27 19:26:43 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-exec.c: Use LGPL.
+	* libgnome/gnome-exec.h: Use LGPL.
+	* libgnome/gnome-config.c: Fixed license to use "Library"
+	everywhere (was missing in two paragraphs).
+
+
+Thu Sep 24 00:59:41 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-regex.c: Include gnome-regex.h.
+	* libgnome/gnome-metadata.c: Include gnome-regex.h.
+	* libgnome/libgnomeP.h: Don't include gnome-regex.h.
+	* libgnome/libgnome.h: Don't include gnome-regex.h.
+
+1998-09-14  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnomelib-init.c (gnomelib_init): Provide a way to not
+	create the $HOME/.gnome* directories.
+
+1998-09-18  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/gnome-metadata.c: Protect `gnomesupport.h' with
+	NEED_GNOMESUPPORT_H.
+
+1998-09-18  Sebastian Wilhelmi  <wilhelmi ira uka de>
+
+	* libgnome/gnome-metadata.c: Include gnomesupport.h in order to
+	use alphasort.
+
+Thu Sep 17 00:24:19 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-metadata.c (try_app_regexs): Return
+	GNOME_METADATA_NOT_FOUND.
+	(app_get_by_type): Likewise.
+	(try_regexs): Likewise.
+	(get_worker): Special-case lookups for `type'.
+	(type_desired): New global.
+	(try_one_app_regex): Possibly exit quickly if looking for `type'.
+	(try_app_regexs): Set type_desired.
+
+	* libgnome/gnome-metadata.c (gnome_metadata_app_dir): Renamed from
+	app_dir.
+	(maybe_scan_app_dir): Only free list if scandir succeeds.
+	(free_hash_entry): Free key.
+	(add_hash_entry): Set type_set field if required.
+
+	* libgnome/gnome-metadata.c (lock): Use mkdir, not fcntl.
+	(unlock): Use rmdir, not fcntl.
+	(lock_directory): New global.
+	(init): Initialize lock_directory.
+	(maybe_scan_app_dir): New function.
+	(app_dir_mtime): New global.
+	(app_dir): New global.
+	(scan_app_file): New function.
+	(try_app_regexs): New function.
+	(get_worker): Check application-installed information.
+	(app_get_by_type): New function.
+	(struct kv): New structure.
+	(free_mapping): New function.
+	(free_hash_entry): New function.
+	(struct app_entry): New structure.
+	(short_circuit): New global.
+	(try_one_app_regex): New function.
+	(desired_key): New global.
+	(app_rx_hash): New global.
+	(app_type_hash): New global.
+	(add_hash_entry): New function.
+
+1998-09-15  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/gnome-metadata.c: Fixed some compiler warnings.
+
+1998-09-14  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/gnome-metadata.c (lock): Use `fcntl' locks.
+	(unlock): Likewise.
+
+1998-09-13  Raja R Harinath  <harinath cs umn edu>
+
+	* configure.in: Look for `db_185.h' compatibility header.
+
+	* libgnome/gnome-dump.c: Include <db_185.h> if present,
+	instead of <db.h>.
+	* libgnome/gnome-metadata.c: Likewise.
+
+
+Wed Sep  9 00:01:56 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-metadata.c (get_worker): Use
+	gnome_mime_type_or_default.
+	* libgnome/gnome-mime.c (gnome_mime_type_or_default): New function.
+	* libgnome/gnome-mime.h (gnome_mime_type_or_default): Declare.
+
+	* libgnome/gnome-metadata.c (LIST): New macro.
+	(LISTLEN): Use it.
+	(metadata_set): Use new macros.  Compute special key length
+	correctly.
+	(metadata_remove): Likewise.
+	(metadata_get_list): Likewise.
+	(metadata_remove): Correctly handle error when deleting record.
+
+Tue Sep  8 14:09:22 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/Makefile.am (bin_PROGRAMS): Added gnome-dump-metadata.
+	(gnome_dump_metadata_SOURCES): New macro
+	(gnome_dump_metadata_LDADD): New macro.
+
+	* libgnome/gnome-dump.c: New file.
+
+	* libgnome/gnome-metadata.c (init): Changed return value and all
+	callers.
+	(lock): New function.
+	(unlock): Likewise.
+	(lock_count): New global.
+	(worker): Lock and unlock database.
+	(gnome_metadata_get): Likewise.
+	(gnome_metadata_get_fast): Likewise.
+	(metadata_get_list): Likewise.
+	(metadata_remove): Likewise.
+	(metadata_set): Likewise.
+	(metadata_get_no_dup): Likewise.
+
+	* configure.in: Add -ldb to GNOME_LIBS and LIBGNOME_LIBS.  If db
+	checks fail, then configure fails.
+
+	* libgnome/gnome-metadata.h (GnomeMetadataError_t): New enum.
+	* libgnome/gnome-metadata.c (init): Wrote.
+	(gnome_metadata_db_file_name): New global.
+
+	* libgnome/gnome-score.c (log_score): Removed unused variable.
+	Don't use `%as', as that is not ANSI C.
+
+	* libgnome/libgnomeP.h: Added gnome-regex.h, gnome-metadata.h,
+	gnome-help.h.
+	* libgnome/libgnome.h: Added gnome-regex.h, gnome-metadata.h.
+	* libgnome/Makefile.am (libgnome_la_SOURCES): Added gnome-regex.c,
+	gnome-metadata.c.
+	(libgnomeinclude_HEADERS): Added gnome-regex.h, gnome-metadata.h.
+	* libgnome/gnome-regex.c: New file.
+	* libgnome/gnome-regex.h: New file.
+
+Sat Sep  5 19:37:17 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-metadata.c (metadata_set): Finished.
+	(try_regexps): Wrote.
+	(metadata_remove): Finished.
+
+1998-09-07  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/Makefile.am (install-data-local): Setgid $(scoredir)
+	only if `chgrp' succeeds.
+
+Tue Sep  1 00:48:02 CDT 1998  Frank Belew <frb umr edu>
+	
+	* configure.in: Use imlib.m4 instead of kludge.
+	* libgnome/Makefile.am, libgnomeui/Makefile.am,
+	test-gnome/Makefile.am, gnome-hello/Makefile.am: Use new
+	GDK_IMLIB_CFLAGS instead of GTK_CFLAGS.
+	
+Mon Aug 24 11:51:03 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-metadata.h: New file.
+	* libgnome/gnome-metadata.c: New file.
+
+Sun Aug 16 19:42:41 1998  Tom Tromey  <tromey cygnus com>
+
+	A couple of -Wall -Wmissing-prototypes fixes:
+	* libgnome/gnomelib-init.c: Include libgnomeP.h.
+	* libgnome/gnome-i18nP.h: Add prototypes for
+	gnome_i18n_set_preferred_language and
+	gnome_i18n_get_preferred_language.
+
+	* libgnome/libgnomeP.h: Include gnome-remote.h.
+	* libgnome/libgnome.h: Include gnome-remote.h.
+	* libgnome/Makefile.am (libgnome_la_SOURCES): Added
+	gnome-remote.c.
+	(libgnomeinclude_HEADERS): Added gnome-remote.h.
+	* libgnome/gnome-remote.c: New file.
+	* libgnome/gnome-remote.h: New file.
+
+Sun Aug 09 13:46:12 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: store a dirty flag in the profile
+	  structure. that way we don't dump to disk everything we have
+	  in memory, even stuff we have just read. (or stuff which was
+	  already synced)
+
+1998-08-05  Nuno Ferreira  <nmrf rnl ist utl pt>
+
+	* libgnome/gnome-help.h: Added #ifndef #define aroud the whole
+	file to allow including it more than once.
+
+1998-08-04  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/libgnome.h: #include "libgnome/gnome-help.h".
+
+	* configure.in: Added gnome-canvas-widget to the sources.
+
+Wed Jul 22 16:47:14 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-config.c (_gnome_config_get_int_with_default):
+	Used wrong sense in previous change.  Duh.
+	(_gnome_config_get_float_with_default): Likewise.
+	(_gnome_config_get_bool_with_default): Likewise.
+
+	* libgnome/gnome-config.c (_gnome_config_get_int_with_default): It
+	isn't an error if the key is not found.
+	(_gnome_config_get_float_with_default): Likewise.
+	(_gnome_config_get_bool_with_default): Likewise.
+	(_gnome_config_get_translated_string_with_default): Removed legacy
+	"C" locale code.
+
+Sat Jul 18 20:18:57 1998  John Ellis  <johne bellatlantic net>
+
+        * libgnome/gnome-dentry.[ch] (gnome_desktop_entry_load_unconditional):
+        new function necessary for loading/editing 'broken' .desktop entries.
+
+Tue Jul  7 00:01:19 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-parse.c: Don't include <malloc.h>.
+
+Sun Jul  5 18:21:31 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-exec.h: Declare gnome_execute_async_with_env.
+	* libgnome/gnome-exec.c (gnome_execute_async_with_env): New function.
+	(gnome_execute_async): Use it.
+
+1998-07-02  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/Makefile.am (dns_helper_LDADD): Cosmetic cleanups.
+
+Tue Jun 30 16:12:55 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-config.c: Removed backwards-compatibility hack.
+	(_gnome_config_get_translated_string_with_default): Handle
+	language specs like `pt_PT foo'.
+
+	* libgnome/gnome-i18n.c: Include libgnomeP.h.
+	* libgnome/gnome-help.c: Include gnome-i18nP.h, sys/wait.h.
+	* libgnome/gnomelib-init.c: Include gnome-i18nP.h.
+	* libgnome/gnome-mime.c: Include libgnomeP.h.
+	* libgnome/gnome-config.c: Include libgnomeP.h.
+	* libgnome/Makefile.am (noinst_HEADERS): Added libgnomeP.h.
+	* libgnome/libgnomeP.h: New file.
+
+1998-06-29  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-config.c (gnome_config_pop_prefix,
+	gnome_config_remove_prefix_list): Removed.  If any application
+	relied on this stuff it was broken.  That is what push/pop prefix
+	are for. 
+
+Mon Jun 29 00:18:10 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-config.c (_gnome_config_set_float): Use %.17g
+	format, to ensure full precision.
+
+1998-06-28  Raja R Harinath  <harinath cs umn edu>
+
+	New, improved, gnome-config script. (Not related to
+	libgnome/gnome-config.[ch]).
+	* Makefile.am (gnome-config): Move generation to ...
+	* configure.in (AC_SUBST): ... here.
+	(GNOME_LIBDIR,GNOME_INCLUDEDIR): Use ${..}, not $(..) for variable
+	substitution. 
+	* gnome-config.in: Rehaul.
+
+Thu Jun 18 23:52:07 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.[ch]: made it possible to call, set and
+	  sync handlers, this is usefull for autosyncing that can be
+	  done in libgnomeui .. or any toolkit specific lib
+
+Thu Jun 18 00:24:21 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.[ch]: added two calls, _remove_prefix_list
+	  and _set_prefix_list, these functions can be used by routines
+	  which want to set it's own prefix stack, but don't wanna corrupt
+	  the prefix stack for the rest of the application.
+
+	* libgnome/gnome-i18n.c: added #include <string.h>
+
+Tue Jun 16 15:24:46 1998  Havoc Pennington  <hp pobox com>
+
+	* libgnome/gnome-util.h, gnome-util.c (gnome_dirrelative_file):
+	make char * args const.
+	(gnome_datadir_file, gnome_libdir_file, gnome_pixmap_file,
+	gnome_unconditional_pixmap_file, gnome_unconditional_libdir_file, 
+	gnome_unconditional_datadir_file): const char *
+	(g_filename_pointer): Return a pointer to the last part of a
+	path. Maybe this should replace g_filename_index.
+	(g_extension_pointer): Return a pointer to the filename extension.
+	(g_copy_vector): Copy char **. const isn't right, needs fixing.
+	(g_flatten_vector): Make a vector into a single string.
+	(g_is_image_filename): Determine if a filename's extension
+	suggests an image file.
+
+	* libgnome/gnome-dentry.h, gnome-dentry.c
+	(gnome_is_program_in_path): put const on the char * arg. Shouldn't
+	this function go in gnome-util?
+	(gnome_desktop_entry_load): const char *
+	(gnome_desktop_entry_load_flags): const char *
+	(gnome_desktop_entry_copy): copy the struct. I guess I didn't end
+	up using this, but here it is anyway.
+	
+Sun Jun 14 18:03:14 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-exec.c (gnome_execute_async): Removed redundant
+	exit (report_errno never returns).  Set errno after waitpid, not
+	before it.
+	(gnome_execute_shell): Added cast to avoid warning.
+
+Sun Jun 14 19:16:00 1998  Manish Vachharajani <mvachhar vger rutgers edu>
+
+	* libgnome/gnome-exec.c gnome_execute_async: We need to call
+	waitpid, even on failure, since if the second child fails to exec,
+	the first will become a zombie until the SIGCHLD is handled via
+	waitpid.  Also, if the second child fails to exec, exit, don't
+	fall through.
+
+Sun Jun 14 13:33:50 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/Makefile.am (INCLUDES): Look in ../intl.  Don't look in
+	../support (the need for this is discovered by configure).
+
+Thu Jun 11 09:55:25 1998  Radek Doulik  <gis academy cas cz>
+
+	* libgnome/gnome-help.h: added GNOME_DECLS
+	* libgnome/gnome-string.h: added GNOME_DECLS
+
+Wed Jun 10 00:47:12 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-parse.c (our_options): New global.
+	(help_parser): New global.
+	(gnome_parse_arguments): Register help_parser.
+	(GROUP): New define.
+
+Mon Jun  8 22:49:28 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-exec.c (gnome_execute_shell): Free element of
+	argv.
+
+Mon Jun  8 19:13:50 1998  Havoc Pennington  <hp pobox com>
+
+	* libgnome/gnome-util.h, gnome-util.c (g_filename_index): 
+	Get the starting index of the last component of a path. 
+	Sort of the reverse of g_concat_dir_and_file.
+	
+1998-06-01  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_destroy): Remove
+	references to the gnome-config entry when discarding a
+	gnome-dentry and release the memory associated with the
+	GnomeDesktopEntry. 
+
+Mon Jun  1 13:23:26 1998  Havoc Pennington  <hp pobox com>
+
+	* libgnome/gnome-exec.h, gnome-exec.c (gnome_execute_async):
+ 	 Change arg 3 to char * const argv[] to match execvp	
+	(gnome_execute_shell): New function. Like system(), but
+ 	backgrounds the process and uses the user's shell.
+
+1998-05-25  Marc Ewing  <marc germ labs redhat com>
+
+	* libgnome/gnome-help.c (gnome_help_goto): make sure
+	the help browser process lives on.
+
+Sat May 23 12:24:39 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-dentry.c: fixed two small bugs in the launch
+	  stuff.
+
+Fri May 22 18:24:09 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-util.c (g_file_exists): `filename' argument now
+	const.
+
+	Some -Wall fixes:
+	* libgnome/lib_date.c: Include <stdio.h> for sprintf.
+	* libgnome/gnome-triggers.c (gnome_triggers_add_trigger): Removed
+	unused variable.
+	(gnome_triggers_do): Likewise.
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_launch_with_args):
+	Removed unused variable.
+	* libgnome/gnome-config.c: Declare strndup if required.
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_launch_with_args):
+	Use `SHELL -c' to execute command.
+
+	* libgnome/gnome-util.c (gnome_util_user_shell): New function;
+	modified from gnome-terminal.
+	* libgnome/gnome-util.h: Declare gnome_util_user_shell.
+
+1998-05-20  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/gnome-dentry.h: Added prototype for gnome_desktop_entry_launch_with_args().
+
+1998-05-20  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-config.c (gnome_config_make_vector,
+	gnome_config_assemble_vector): export the routines that make a
+	vector out from a string and the routine that assembles a vector
+	into a string.  We need them outside as well.
+
+1998-05-19  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_launch_with_args):
+	New function.  Allows to launch a dentry with optional extra
+	arguments.  In the future we should probably scan ->exec vector
+	for ocurrences of '%f' and relpace that with the argumnets.  For
+	now, we just appendm them.
+
+	* libgnome/gnome-config.c (_gnome_config_get_vector_with_default):
+	Set the entire argvp array to NULL.  
+	Count correctly the number of arguments.
+
+Tue May 19 14:42:32 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: (escape_string_and_dup) fixed a segfault
+
+1998-05-19  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_free): We were
+	leaking item->geometry.
+
+	* configure.in (GLIB_LIBS): use the correct glib depending on what
+	is installed.  Bug reported by Mark Galassi.  Thanks to Owen for
+	suggesting the proper approach to this. 
+
+1998-05-18  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_free): Do not free
+	item->exec as the gnome_string_arry_free already freed that.
+	
+Mon May 18 14:10:42 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-config.c (_gnome_config_set_vector): Also quote
+	`\' characters.
+	(_gnome_config_get_vector_with_default): Don't duplicate result of
+	access_config.  Allocate each element of array separately.
+
+1998-05-18  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-config.c (_gnome_config_get_vector_with_default):
+	Fix the routine.  Simplify the parsing code with a slicker
+	routine.  This should fix the panel problems, at least it works
+	for me.
+	
+1998-04-30  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-util.c (g_copy_strings): Put back optimized and
+	non-leaking copy_strings. 
+Sat May 16 00:44:21 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-string.c: Removed dead check for delim==NULL.
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_launch): Look up
+	desired terminal program in config database.
+
+	* libgnome/gnome-i18n.c (LANGKEY): Changed value.
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_load_flags): Treat
+	"Exec" entry as a vector.
+	(gnome_desktop_entry_save): Likewise.
+	(gnome_desktop_entry_free): Likewise.
+	(gnome_desktop_entry_launch): Likewse.  Also use
+	gnome_execute_async.
+	* libgnome/gnome-dentry.h (GnomeDesktopEntry): Added `exec_length'
+	member.  `exec' member now a `char**'.
+	* libgnome/libgnome.h: Include gnome-exec.h.
+	* libgnome/Makefile.am (libgnome_la_SOURCES): Added gnome-exec.c.
+	(libgnomeinclude_HEADERS): Added gnome-exec.h.
+	* libgnome/gnome-exec.h: New file.
+	* libgnome/gnome-exec.c: New file.
+
+	* libgnome/gnome-config.c (_gnome_config_get_vector_with_default):
+	If no value available, set *argvp to NULL.
+
+1998-05-14  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/gnome-i18n.c (gnome_i18n_init): It is not safe to pass
+	an `auto' variable to `putenv'.
+
+Wed May 13 13:34:10 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-i18n.h: Declare new functions.
+	* libgnome/gnome-i18n.c (LANGKEY): New macro.
+	(gnome_i18n_set_preferred_language): New function.
+	(gnome_i18n_init): Likewise.
+	(gnome_i18n_get_preferred_language): Likewise.
+	(guess_category_value): Return NULL as default domain.
+	(gnome_i18n_get_language_list): Handle NULL return from
+	guess_category_value.
+	* libgnome/gnomelib-init.c (gnomelib_init): Call gnome_i18n_init().
+
+Sat May  9 20:25:49 1998  Szekeres István  <szekeres cyberspace mht bme hu>
+
+	* libgnome/gnome-string.c (gnome_string_join):
+	Pass terminator NULL to gnome_string_joinv so it will not sigsegv
+
+1998-04-29  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/gnome-config.c
+	(_gnome_config_get_translated_string_with_default): Added fallback
+	mechanism to read old files that did have the [C] suffix on
+	translated strings.
+
+	* libgnome/gnome-config.c (_gnome_config_set_translated_string):
+	If the language is the default "C", we don't want to write the [C]
+	suffix to the file.  This is so that this function will work in
+	pairs with gnome_config_get_translated_string().
+
+1998-04-27  Michael Fulbright  <msf redhat com>
+
+        * libgnome/gnome-help.c (gnome_help_file_find_file):
+	  strip off last '#' in the requested path, since most help
+	  requests are going to be URLs.
+	
+	* libgnome/gnome-help.c (gnome_help_display):
+	  use gnome_help_file_find_file() function
+
+	* libgnomeui/gnome-app-helper.c (gnome_app_add_help_menu_entries):
+	  use gnome_help_file_find_file() function to find topic.dat
+
+
+1998-04-27  Carsten Schaar  <nhadcasc fs-maphy uni-hannover de>
+
+	* libgnome/gnome-help.c (gnome_help_file_find_file): Changed to
+	look for more than one language.
+	(gnome_help_file_path): Changed to use
+	gnome_help_file_find_file. If no file is found, than return a
+	value like in former times.
+
+	* libgnome/gnome-config.c
+	(_gnome_config_get_translated_string_with_default): Changed to
+	look for more than one language.
+	(_gnome_config_set_translated_string): Changed to support language 
+	lists.
+
+	* libgnome/gnome-i18n.c (guess_category_value): New function.
+	(gnome_i18n_get_language_list): New function.
+
+	* libgnome/gnome-i18n.h: Added gnome_i18n_get_language_list, that
+	returns a list of languages, depending on the users environment.
+
+	* libgnome/gnome-i18nP.h: Likewise.
+
+1998-04-27  Michael Fulbright  <msf redhat com>
+
+	* libgnome/gnome-help.c (gnome_help_file_find_file):
+	  A new function which is similar to gnome_help_file_path(), except
+	  that if the desired file is not found in the default locale,
+	  the 'C' locale is also searched. The gnome_help_*
+	  code may need to be rethought when handling i18n issues.
+
+Sat Apr 25 23:29:54 CEST 1998  Eckehard Berns  <eb berns prima de>
+
+	* libgnome/gnome-config.c (_gnome_config_get_vector_with_default):
+	  escaped spaces have to get unescaped after reading.
+
+1998-04-21  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-config.c (gnome_config_get_string_with_default):
+	Added ultra-nasty binary compatibility hack for those hackers
+	without dual-p2 machines so that they dont have to recompile
+	everything.  This will be gone soon.
+
+Thu Apr 23 01:53:44 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: added some missing compatibility
+	  functions.
+
+Tue Apr 21 15:23:58 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.h: added gnome_config_get_real_path
+	  and gnome_config_private_get_real_path macros, that
+	  return the real path of a file in the config dir
+
+Tue Apr 21 14:30:25 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnomelib-init.c: create .gnome_private and
+	  set mode to 0700 on every initialization, added
+	  gnome_user_private_dir constant
+
+	* libgnome/libgnome.c: add gnome_user_private_dir extern
+	  declaration
+
+	* libgnome/gnome-config.[ch]: made parse_path use either
+	  private or normal path, and made defines for source
+	  compatibility to new functions which have one more
+	  argument which is gint priv, added gnome_config_private
+	  defines to these functions that use the private directory
+
+Mon Apr 20 23:38:55 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: made it check for the entire
+	  path first as a special case so that it doesn't end
+	  up walking though the entire path if it exists
+
+Mon Apr 20 22:41:44 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: new function check_path
+	  called before a file is opened for writing,
+	  it will try to check if a the directory exists
+	  and create it if neccessary. needs a bit of
+	  a bit of optimization maybe and uses 755 by default
+	  now which probably should be either 700 or specified
+	  by user.
+
+1998-04-16  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c (gnome_is_program_in_path): Return the
+	full pathname for the program if it is found on the path. 
+	(gnome_desktop_entry_load_flags): Free the pathname according to
+	the new convention.
+
+1998-04-13  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/gnome-help.c (gnome_help_file_path): Be more
+	`const'-correct. 
+
+Mon Apr  6 00:05:34 1998  Havoc Pennington  <hp pobox com>
+
+	* libgnome/gnome-i18nP.h: new file
+	* libgnome/gnome-i18n.h: #warning if used together with
+	gnome-i18nP.h
+	* libgnome/Makefile.am: noinst_HEADERS = gnome-i18nP.h
+
+Sat Apr 04 12:12:47 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-config.c: do init on functions that
+	  previously errored out with "called before init"
+
+1998-03-31  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/lib_date.c, lib_date.h, lib_defs.h, lib_date.README:
+	Added the lib_date routines from Steffen Beyer. 
+
+Sat Mar 28 19:28:48 MST 1998 Nathan Summers <rock gimp org>
+
+	* libgnome/gnome_dl.c: changed lib_path to libpath in the hpux code
+
+Thu Mar 19 18:57:05 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-parse.h: Added copyright info.
+	* libgnome/gnome-parse.c: Likewise.
+
+	* libgnome/gnome-history.c (gnome_history_recently_used): Changed
+	interface.
+	Added copyright info.
+	* libgnome/gnome-history.h: Added comments, updated
+	gnome_history_recently_used decl.
+	Added copyright info.
+
+Wed Mar 18 20:33:30 1998  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_save): Save the
+	geometry field of the gnome-dentry.
+
+Tue Mar 17 21:34:35 1998  George Lebl  <jirka 5z com>
+
+	* libgnomeui/gtk-{plug,socket}.[ch]: added Owen's plugsocket
+	  code to libgnomeui
+
+Sun Mar 15 15:24:41 1998  Owen Taylor  <owt1 cornell edu>
+
+	* Makefile.am configure.in gnomeConf.sh.in: 
+	Add GTK_CFLAGS to GNOME_INCLUDEDIR, and GTK_LIBS to the
+	approriate *LIBS variables.
+
+	* libgnome/Makefile.am libgnomeui/Makefile.am: 
+	Added GTK_CFLAGS to INCLUDES
+
+Tue Mar 10 11:58:38 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-parse.h: Just look for <argp.h>.
+
+Mon Mar  9 20:37:56 1998  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-parse.h: Add BEGIN_GNOME_DECLS and
+	END_GNOME_DECLS: they are *required* for C++ compilation.
+
+Sun Mar  8 17:15:17 1998  Tom Tromey  <tromey cygnus com>
+
+	* version.h.in: Removed.
+	* configure.in: Don't create version.h.
+
+	* libgnome/Makefile.am (INCLUDES): Added @SUPPORTINCS  
+
+	* configure.in (SUPPORTINCS, LIBSUPPORT): New defines.
+	(GNOME_LIBS): Include -lgnomesupport if required.
+	(GNOME_INCLUDEDIR): Include -I for libgnomesupport if required.
+
+	* gnomeConf.sh.in (GNOME_INCLUDEDIR, GNOMELIBDIR): Quote values.
+
+Fri Mar  6 21:42:09 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/libgnome.h: Include gnome-parse.h.
+
+Fri Mar 06 20:31:13 1998  George Lebl  <jirka 5z com>
+
+	* libgnome/gnome-dentry.c: fixed the _load function to always set
+	  ->icon, at least to NULL, this was causing the panel to segfault
+
+Wed Mar  4 01:06:58 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/libgnome.h (gnomelib_register_arguments): Declare.
+	* libgnome/gnomelib-init.c (gnomelib_register_arguments): New
+	function.
+
+	* libgnome/Makefile.am (libgnome_la_SOURCES): Added
+	gnome-parse.c.
+	(libgnomeinclude_HEADERS): Added gnome-parse.h.
+	* libgnome/gnome-parse.h: New file.
+	* libgnome/gnome-parse.c: New file.
+
+	* libgnome/gnomelib-init.c (gnomelib_init): Removed argc, argv
+	arguments.
+	* libgnome/libgnome.h (gnomelib_init): Likewise.
+
+	* acconfig.h (HAVE_PROGRAM_INVOCATION_SHORT_NAME,
+	HAVE_PROGRAM_INVOCATION_NAME): Added.
+
+1998-02-28  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/gnome-config.c (dump_sections): Don't crash if
+	p->section_name == NULL.
+	(*): Use `g_strdup' and `g_free' uniformly, throughout.
+
+Sat Feb 28 15:46:51 1998  Miguel de Icaza  <miguel nuclecu unam mx>
+	
+	* libgnome/gnome-config.c (parse_path): Reverse Raja Harinath's
+	change that used "" instead of NULL.  
+
+	If we use NULL here, the gnome-config-get-string routines can
+	distinguish between:
+
+		- NULL if they key was non-existant.
+		- "" if the key had an empty value.
+	
+Thu Feb 26 21:12:26 1998  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-util.c (gnome_dirrelative_file): Check inside the
+	user relative home directory for more files. 
+
+1998-02-28  Carsten Schaar  <nhadcasc fs-maphy uni-hannover de>
+
+	* libgnome/gnome-dentry.c (get_translated_string): Due to the
+ 	changes in libgnome/gnome-config.c (parse_path), empty strings
+ 	instead of the untranslated strings have beed returned, if a
+ 	translated string was not available. This is fixed now.
+
+Thu Feb 26 18:08:15 1998  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c, libgnome/gnome-dentry.h: Dropped the
+	computed icon filenames, things will be scaled now by the panel. 
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_load_flags): More
+	fields; a new parameter that avoids dumping the loaded
+	information. 
+
+1998-02-25  Raja R Harinath  <harinath cs umn edu>
+
+	* libgnome/gnome-config.c (parse_path): Use "" instead of NULL.
+
+Wed Feb 25 20:16:13 1998  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_load): Drop known
+	information on a dentry after loading.
+
+	Add more fields.
+
+1998-02-23  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/gnome-dl.c: 
+	* libgnome/gnome-help.c: #include <string.h>
+
+	* configure.in (ALL_LINGUAS): Added "it" to ALL_LINGUAS
+
+1998-02-19  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/gnome-score.h: Added missing #include <glib.h>
+
+1998-02-20  Carsten Schaar  <nhadcasc fs-maphy uni-hannover de>
+
+	* libgnome/gnome-mime.c: Now includes 'libgnome.h' and 'gtk/gtk.h'
+ 	instead of 'gnome.h'. This removes the dependence from
+ 	'libgnomeui.h'.
+
+	* devel-docs/.cvsignore: Added 'Makefile' and 'Makefile.in'.
+
+	* configure.in (ALL_LINGUAS): Added german translations.
+
+1998-02-19  Federico Mena Quintero  <federico nuclecu unam mx>
+
+	* libgnome/gnomelib-init.c (gnomelib_init): Added app_id parameter
+	to this function.  Changes to the rest of Gnome are in progress.
+
+Tue Feb 17 23:37:50 1998  Miguel de Icaza  <miguel nuclecu unam mx>
+
+	* libgnome/gnome-dentry.c (gnome_desktop_entry_load): Provide a
+	default for the Terminal entry. 
+
+Mon Feb 16 13:13:19 1998  Tom Tromey  <tromey cygnus com>
+
+	* libgnome/gnome-config.c (gnome_config_get_vector_with_default):
+	Don't include space separator at start of a vector element.
diff --git a/libgnome/DEPENDS.libgnome b/libgnome/DEPENDS.libgnome
new file mode 100644
index 0000000..2f34774
--- /dev/null
+++ b/libgnome/DEPENDS.libgnome
@@ -0,0 +1,3 @@
+libglib
+libpopt
+libdb
diff --git a/libgnome/Makefile.am b/libgnome/Makefile.am
new file mode 100644
index 0000000..f13b577
--- /dev/null
+++ b/libgnome/Makefile.am
@@ -0,0 +1,149 @@
+## Process this file with automake to produce Makefile.in
+
+#
+# Targets
+#
+
+LIB_VERSION=0:0:0
+LIB_VERSION_NUM=0.0.0
+
+GNOME_MAKEENUMS = $(top_srcdir)/tools/gnome-makeenums.pl
+GNOME_MAKETYPES = $(top_builddir)/tools/gnome-maketypes.awk
+
+lib_LTLIBRARIES = libgnome-2.la
+
+LINK = $(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(LDFLAGS) -o $@
+
+libgnomeincludedir = $(includedir)/gnome/$(GNOME_INTERFACE_VERSION)/libgnome
+
+INCLUDES = \
+	-I..					\
+	-I$(srcdir)/..				\
+	$(WARN_CFLAGS)				\
+	$(GNOMESUPPORT_CFLAGS)			\
+	$(GLIB_CFLAGS)				\
+	$(OAF_CFLAGS)				\
+	$(GCONF_CFLAGS)				\
+	$(LIBXML_CFLAGS)			\
+	$(GNOME_VFS_CFLAGS)			\
+	-DGNOMEPREFIX=\""$(prefix)"\"		\
+	-DGNOMELIBDIR=\""$(libdir)"\"		\
+	-DGNOMEDATADIR=\""$(datadir)"\"		\
+	-DGNOMEBINDIR=\""$(bindir)"\"		\
+	-DGNOMELOCALSTATEDIR=\""$(localstatedir)"\" \
+	-DGNOMELOCALEDIR=\""$(gnomelocaledir)"\" \
+	-DGNOMESYSCONFDIR=\""$(sysconfdir)"\"	\
+	-DVERSION=\""$(VERSION)"\"		\
+	-DGNOMEVFSVERSION=\""$(GNOME_VFS_VERSION)"\" \
+	-DG_LOG_DOMAIN=\"Gnome\"
+
+libgnome_2_la_SOURCES = \
+	gnome-program.c		\
+	gnome-config.c		\
+	gnome-ditem.c		\
+	gnome-exec.c		\
+	gnome-fileconvert.c	\
+	gnome-i18n.c		\
+	gnome-regex.c		\
+	gnome-remote.c		\
+	gnome-score.c		\
+	gnome-triggers.c	\
+	gnome-url.c		\
+	gnome-util.c		\
+	gnome-paper.c		\
+	gnomelib-init.c		\
+	libgnometypes.c
+
+libgnome_headers = \
+	gnome-program.h		\
+        gnome-config.h 		\
+	gnome-defs.h   		\
+	gnome-fileconvert.h	\
+	gnome-ditem.h		\
+	gnome-exec.h		\
+	gnome-i18n.h 		\
+	gnome-regex.h		\
+	gnome-remote.h		\
+	gnome-score.h		\
+	gnome-triggers.h 	\
+	gnome-url.h		\
+	gnome-util.h   		\
+	gnome-paper.h		\
+	libgnome.h		\
+	gnomelib-init.h		\
+	gnome-portability.h
+
+libgnomeinclude_HEADERS = \
+	libgnometypebuiltins.h	\
+	$(libgnome_headers)
+
+noinst_HEADERS = \
+	gnome-i18nP.h				\
+	gnome-triggersP.h			\
+	libgnomeP.h
+
+# generate libgnome.defs file from libgnome-boxed.defs and *.h
+libgnome.defs: $(GNOME_MAKEENUMS) libgnome-boxed.defs $(libgnome_headers)
+	cd $(srcdir) \
+	&& $(GNOME_MAKEENUMS) defs $(libgnome_headers) > gd.tmp \
+	&& cat libgnome-boxed.defs >> gd.tmp \
+	&& mv gd.tmp libgnome.defs
+
+# generate type identifier header (GTK_TYPE_WIDGET_FLAGS)
+libgnometypebuiltins.h: libgnome.defs $(GNOME_MAKETYPES)
+	cd $(srcdir) \
+	&& LC_COLLATE=C $(GNOME_MAKETYPES) libgnome.defs macros > gtb.tmp \
+	&& mv gtb.tmp libgnometypebuiltins.h
+
+# generate type identifier variables (GTK_TYPE_WIDGET_FLAGS)
+libgnometypebuiltins_vars.c: libgnome.defs $(GNOME_MAKETYPES)
+	cd $(srcdir) \
+	&& LC_COLLATE=C $(GNOME_MAKETYPES) libgnome.defs variables > gtbv.tmp \
+	&& mv gtbv.tmp libgnometypebuiltins_vars.c
+
+# generate type entries for type-id registration
+libgnometypebuiltins_ids.c: libgnome.defs $(GNOME_MAKETYPES)
+	cd $(srcdir) \
+	&& LC_COLLATE=C $(GNOME_MAKETYPES) libgnome.defs entries > gtbi.tmp \
+	&& mv gtbi.tmp libgnometypebuiltins_ids.c
+
+# generate enum value arrays
+libgnometypebuiltins_evals.c: $(GNOME_MAKEENUMS) libgnome.defs
+	cd $(srcdir) \
+	&& $(GNOME_MAKEENUMS) arrays $(libgnome_headers) > gtbe.tmp \
+	&& mv gtbe.tmp libgnometypebuiltins_evals.c
+
+EXTRA_DIST = \
+	parse-path.cP			\
+	gnome-portability.h.in		\
+	libgnome-2.0.pc.in
+
+BUILT_SOURCES = \
+	gnome-portability.h		\
+	libgnometypebuiltins.h		\
+	libgnometypebuiltins_evals.c	\
+	libgnometypebuiltins_ids.c	\
+	libgnometypebuiltins_vars.c
+
+#just to be sure, add an explicit dependency
+gnome-config.o: parse-path.cP
+
+libgnome_2_la_LDFLAGS = -version-info $(LIB_VERSION)
+libgnome_2_la_LIBADD =		\
+	$(GNOMESUPPORT_LIBS)	\
+	$(OAF_LIBS)		\
+	$(GCONF_LIBS)		\
+	$(LIBXML_LIBS)		\
+	$(GNOME_VFS_LIBS)	\
+	$(GLIB_LIBS)
+
+noinst_PROGRAMS = \
+	test-libgnome
+
+test_libgnome_SOURCES = test-libgnome.c
+test_libgnome_LDADD = \
+	libgnome-2.la
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libgnome-2.0.pc
+
diff --git a/libgnome/gnome-config.c b/libgnome/gnome-config.c
new file mode 100644
index 0000000..e97ead6
--- /dev/null
+++ b/libgnome/gnome-config.c
@@ -0,0 +1,2091 @@
+/*
+ * 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 <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 "libgnomeP.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_config_file (tmp);
+ 			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_config_file (tmp);
+			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;
+}
+
+/**
+ * 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)
+{
+	const GList *language_list;
+
+	char *value= NULL;
+
+	language_list = gnome_i18n_get_language_list ("LC_MESSAGES");
+
+	while (!value && language_list) {
+		const char *lang= language_list->data;
+		gchar *tkey;
+
+		tkey = g_strconcat (path, "[", lang, "]", NULL);
+		value = _gnome_config_get_string_with_default (tkey, def, priv);
+		g_free (tkey);
+
+		if (!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);
+				tkey = g_strconcat (path, "[",
+						    copy, "]",
+						    NULL);
+				value = _gnome_config_get_string_with_default (tkey, def, priv);
+				g_free (tkey);
+				g_free (copy);
+				if (! value || *value == '\0') {
+					g_free (value);
+					value = NULL;
+				}
+			}
+		}
+		language_list = language_list->next;
+	}
+
+	if (!value){
+		value = _gnome_config_get_string_with_default (path, def, priv);
+
+		if (!value || *value == '\0'){
+			g_free (value);
+			value = NULL;
+		}
+	}
+	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;
+	const char *r;
+	char *ret = NULL;
+	
+	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);
+	if (r)
+		ret = g_strdup (r);
+	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, 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..b307f39
--- /dev/null
+++ b/libgnome/gnome-config.h
@@ -0,0 +1,292 @@
+/*
+ * 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>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_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);
+
+END_GNOME_DECLS
+
+#endif
diff --git a/libgnome/gnome-defs.h b/libgnome/gnome-defs.h
new file mode 100644
index 0000000..b274962
--- /dev/null
+++ b/libgnome/gnome-defs.h
@@ -0,0 +1,32 @@
+/*
+ * 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@
+ */
+
+#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-ditem.c b/libgnome/gnome-ditem.c
new file mode 100644
index 0000000..5286156
--- /dev/null
+++ b/libgnome/gnome-ditem.c
@@ -0,0 +1,2188 @@
+/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gnome-ditem.h - GNOME Desktop File Representation 
+
+   Copyright (C) 1999, 2000 Red Hat Inc.
+   All rights reserved.
+
+   This file is part of the Gnome Library.
+
+   Developed by Elliot Lee <sopwith redhat com>
+   
+   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"
+
+#define DI_DEBUG 1
+
+#include <limits.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <glib.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <string.h>
+#include "libgnomeP.h"
+#include "gnome-defs.h"
+#include "gnome-portability.h"
+#include "gnome-ditem.h"
+#include "gnome-util.h"
+#include "gnome-config.h"
+#include "gnome-exec.h"
+#include "gnome-i18nP.h"
+#include "gnome-url.h"
+#include <popt.h>
+
+#include <libgnomevfs/gnome-vfs-mime.h>
+
+struct _GnomeDesktopItem {
+        GHashTable *name; /* key is language, value is translated string */
+        GHashTable *comment; /* key is language, value is translated string */
+
+	char *type; /* type as in Application, Directory, URL, ... will
+		       indicate what do do with the Exec line */
+
+        char *exec;
+
+        char *icon_path;
+
+        char *location;
+
+        GHashTable *other_attributes; /* string key, string value */
+
+        GSList *order; /* If GNOME_DESKTOP_ITEM_IS_DIRECTORY */
+
+        time_t mtime;
+
+        guchar refcount;
+
+        GnomeDesktopItemFormat item_format : 4;
+        GnomeDesktopItemFlags item_flags : 8;
+};
+
+/**
+ * gnome_desktop_item_new:
+ *
+ * Creates a GnomeDesktopItem object. The reference count on the returned value is set to '1'.
+ *
+ * Returns: The new GnomeDesktopItem
+ */
+GnomeDesktopItem *
+gnome_desktop_item_new(void)
+{
+        GnomeDesktopItem *retval;
+
+        retval = g_new0(GnomeDesktopItem, 1);
+
+        retval->refcount++;
+
+        return retval;
+}
+
+static void
+ditem_copy_key_value(gpointer key, gpointer value, gpointer user_data)
+{
+        g_hash_table_insert(user_data, g_strdup(key), g_strdup(value));
+}
+
+/**
+ * gnome_desktop_item_copy:
+ * @item: The item to be copied
+ *
+ * Creates a copy of a GnomeDesktopItem.  The new copy has a refcount of 1.
+ *
+ * Returns: The new copy 
+ */
+GnomeDesktopItem *
+gnome_desktop_item_copy (const GnomeDesktopItem *item)
+{
+        GnomeDesktopItem *retval;
+	GSList *li;
+
+        g_return_val_if_fail(item, NULL);
+
+        retval = gnome_desktop_item_new();
+
+        retval->item_format = item->item_format;
+        retval->item_flags = item->item_flags;
+
+	/* g_strdup handles NULLs correctly */
+        retval->icon_path = g_strdup(item->icon_path);
+        retval->location = g_strdup(item->location);
+        retval->exec = g_strdup(item->exec);
+        retval->type = g_strdup(item->type);
+
+        if(item->name
+           && g_hash_table_size(item->name) > 0) {
+                retval->name = g_hash_table_new (g_str_hash, g_str_equal);
+                g_hash_table_foreach(item->name, ditem_copy_key_value, retval->name);      
+        }
+
+        if(item->comment
+           && g_hash_table_size(item->comment) > 0) {
+                retval->comment = g_hash_table_new (g_str_hash, g_str_equal);
+                g_hash_table_foreach(item->comment, ditem_copy_key_value, retval->comment);
+        }
+
+        if(item->other_attributes
+           && g_hash_table_size(item->other_attributes) > 0) {
+                retval->other_attributes = g_hash_table_new (g_str_hash, g_str_equal);
+                g_hash_table_foreach(item->other_attributes, ditem_copy_key_value, retval->other_attributes);
+        }
+
+        retval->order = g_slist_copy(item->order);
+	for(li = retval->order; li; li = li->next)
+		li->data = g_strdup(li->data);
+
+        return retval;
+}
+
+/* If you find a bug here, odds are that it exists in ditem_gnome_load() too */
+static GnomeDesktopItem *
+ditem_kde_load (const char *data_file, GnomeDesktopItemLoadFlags flags,
+		GnomeDesktopItemFlags item_flags)
+{
+        GnomeDesktopItem *retval = gnome_desktop_item_new();
+        char confpath[PATH_MAX];
+        char *key, *value;
+        void *iter;
+
+        g_snprintf(confpath, sizeof(confpath), "=%s=/KDE Desktop Entry", data_file);
+
+        retval->item_flags = item_flags;
+        retval->name = g_hash_table_new(g_str_hash, g_str_equal);
+        retval->comment = g_hash_table_new(g_str_hash, g_str_equal);
+        retval->other_attributes = g_hash_table_new(g_str_hash, g_str_equal);
+
+        iter = gnome_config_init_iterator(confpath);
+        while((iter = gnome_config_iterator_next(iter, &key, &value))) {
+		/* we need to keep things where the value is empty however */
+                if(!*key) {
+                        g_free(key);
+                        g_free(value);
+                        continue;
+                }
+
+                if(!strcmp(key, "Name")) {
+                        g_hash_table_insert(retval->name, g_strdup("C"), value);
+                } else if(!strncmp(key, "Name[", 5)) {
+                        char *mylang, *ctmp;
+
+                        mylang = key + 5;
+                        ctmp = strchr(mylang, ']');
+                        if(ctmp) *ctmp = '\0';
+
+                        g_hash_table_insert(retval->name, g_strdup(mylang), value);
+                        g_free(key);
+                } else if(!strcmp(key, "Comment")) {
+                        g_hash_table_insert(retval->comment, g_strdup("C"), value);
+                } else if(!strncmp(key, "Comment[", strlen("Comment["))) {
+                        char *mylang, *ctmp;
+
+                        mylang = key + strlen("Comment[");
+                        ctmp = strchr(mylang, ']');
+                        if(ctmp) *ctmp = '\0';
+
+                        g_hash_table_insert(retval->name, g_strdup(mylang), value);
+                        g_free(key);
+                } else if(!strcmp(key, "Icon")) {
+                        retval->icon_path = value;
+                        g_free(key);
+                } else if(!strcmp(key, "Terminal")) {
+                        if(tolower(*value) == 'y' || tolower(*value) == 't' || atoi(value))
+                                retval->item_flags |= GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL;
+                        else
+                                retval->item_flags &= (~GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL);
+
+                        g_free(key);
+                        g_free(value);
+                } else if(!strcmp(key, "Exec")) {
+			retval->exec = value;
+			if(strstr(value,"%f")) {
+				retval->item_flags |= GNOME_DESKTOP_ITEM_NO_URL_DROP;
+			} else if(strstr(value,"%F")) {
+				retval->item_flags |= GNOME_DESKTOP_ITEM_NO_URL_DROP |
+					GNOME_DESKTOP_ITEM_SINGLE_FILE_DROP_ONLY;
+			} else if(strstr(value,"%u")) {
+				/* everything is set just right :), don't touch it */
+			} else 
+				retval->item_flags |= GNOME_DESKTOP_ITEM_OLD_STYLE_DROP;
+                        g_free(key);
+                } else if(!strcmp(key, "Type")) {
+			retval->type = value;
+			if(strcmp(value,"KonsoleApplication")==0)
+				retval->item_flags |=
+					GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL;
+                        g_free(key);
+                } else if(!strcmp(key, "SortOrder")) {
+			char *p;
+                        g_free(key);
+			p = strtok(value,",");
+			while(p) {
+				retval->order = g_slist_prepend(retval->order,
+								g_strdup(p));
+				p = strtok(NULL,",");
+			}
+                        g_free(value);
+			retval->order = g_slist_reverse(retval->order);
+                } else {
+                        g_hash_table_insert(retval->other_attributes,
+					    key, value);
+                }
+        }
+
+        if ((flags & GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS)
+            && !(retval->item_flags & GNOME_DESKTOP_ITEM_IS_DIRECTORY)) {
+                char *tryme;
+                /* We don't use gnome_desktop_item_exists() here because it is more thorough than the TryExec stuff
+                   which GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS specifies */
+
+                if(!retval->exec)
+                        goto errout;
+
+                tryme = g_hash_table_lookup(retval->other_attributes, "TryExec");
+
+                if(tryme && !(tryme = gnome_is_program_in_path(tryme))) {
+			g_free(tryme);
+                        goto errout;
+		}
+        }
+
+        return retval;
+
+ errout:
+        gnome_desktop_item_unref(retval);
+        return NULL;
+}
+
+/* There is entirely too much duplication between this function and ditem_kde_load() */
+static GnomeDesktopItem *
+ditem_gnome_load (const char *data_file, GnomeDesktopItemLoadFlags flags,
+		  GnomeDesktopItemFlags item_flags)
+{
+        GnomeDesktopItem *retval = gnome_desktop_item_new();
+        char confpath[PATH_MAX];
+        char *key, *value;
+        void *iter;
+	int got_drop_keys = FALSE; /* if any new drop keys were set, otherwise use
+				      OLD_STYLE_DROP */
+
+        g_snprintf(confpath, sizeof(confpath), "=%s=/Desktop Entry", data_file);
+
+        retval->item_flags = item_flags;
+        retval->name = g_hash_table_new(g_str_hash, g_str_equal);
+        retval->comment = g_hash_table_new(g_str_hash, g_str_equal);
+        retval->other_attributes = g_hash_table_new(g_str_hash, g_str_equal);
+
+        iter = gnome_config_init_iterator(confpath);
+        while((iter = gnome_config_iterator_next(iter, &key, &value))) {
+		/* we need to keep things where the value is empty however */
+                if(!*key) {
+                        g_free(key);
+                        g_free(value);
+                        continue;
+                }
+
+		if(strcmp(key, "FileDropExec")==0 ||
+		   strcmp(key, "URLDropExec")==0)
+			got_drop_keys = TRUE;
+
+                if(!strcmp(key, "Name")) {
+                        g_hash_table_insert(retval->name, g_strdup("C"), value);
+                } else if(!strncmp(key, "Name[", 5)) {
+                        char *mylang, *ctmp;
+
+                        mylang = key + strlen("Name[");
+                        ctmp = strchr(mylang, ']');
+                        if(ctmp) *ctmp = '\0';
+
+                        g_hash_table_insert(retval->name, g_strdup(mylang), value);
+                        g_free(key);
+                } else if(!strcmp(key, "Comment")) {
+                        g_hash_table_insert(retval->comment, g_strdup("C"), value);
+                } else if(!strncmp(key, "Comment[", strlen("Comment["))) {
+                        char *mylang, *ctmp;
+
+                        mylang = key + strlen("Comment[");
+                        ctmp = strchr(mylang, ']');
+                        if(ctmp) *ctmp = '\0';
+
+                        g_hash_table_insert(retval->name, g_strdup(mylang), value);
+                        g_free(key);
+                } else if(!strcmp(key, "Icon")) {
+                        retval->icon_path = value;
+                        g_free(key);
+                } else if(!strcmp(key, "Terminal")) {
+                        if(tolower(*value) == 'y' || tolower(*value) == 't' || atoi(value))
+                                retval->item_flags |= GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL;
+                        else
+                                retval->item_flags &= (~GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL);
+
+                        g_free(key);
+                        g_free(value);
+                } else if(!strcmp(key, "SingleFileDropOnly")) {
+                        if(tolower(*value) == 'y' || tolower(*value) == 't' || atoi(value))
+                                retval->item_flags |= GNOME_DESKTOP_ITEM_SINGLE_FILE_DROP_ONLY;
+                        else
+                                retval->item_flags &= (~GNOME_DESKTOP_ITEM_SINGLE_FILE_DROP_ONLY);
+                        g_free(key);
+                        g_free(value);
+                } else if(!strcmp(key, "SingleURLDropOnly")) {
+                        if(tolower(*value) == 'y' || tolower(*value) == 't' || atoi(value))
+                                retval->item_flags |= GNOME_DESKTOP_ITEM_SINGLE_URL_DROP_ONLY;
+                        else
+                                retval->item_flags &= (~GNOME_DESKTOP_ITEM_SINGLE_URL_DROP_ONLY);
+                        g_free(key);
+                        g_free(value);
+                } else if(!strcmp(key, "Exec")) {
+                        retval->exec = value;
+                        g_free(key);
+                } else if(!strcmp(key, "Type")) {
+                        retval->type = value;
+                        g_free(key);
+                } else {
+                        g_hash_table_insert(retval->other_attributes, key, value);
+                }
+        }
+
+	if(got_drop_keys) {
+		char *s;
+                s = g_hash_table_lookup(retval->other_attributes, "FileDropExec");
+		if(!s || !*s)
+			retval->item_flags |= GNOME_DESKTOP_ITEM_NO_FILE_DROP;
+                s = g_hash_table_lookup(retval->other_attributes, "URLDropExec");
+		if(!s || !*s)
+			retval->item_flags |= GNOME_DESKTOP_ITEM_NO_URL_DROP;
+	} else
+		retval->item_flags |= GNOME_DESKTOP_ITEM_OLD_STYLE_DROP;
+
+        if ((flags & GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS)
+            && !(retval->item_flags & GNOME_DESKTOP_ITEM_IS_DIRECTORY)) {
+                char *tryme;
+
+                if(!retval->exec)
+                        goto errout;
+
+                tryme = g_hash_table_lookup(retval->other_attributes, "TryExec");
+
+                if(tryme && !(tryme = gnome_is_program_in_path(tryme))) {
+			g_free(tryme);
+                        goto errout;
+		}
+        }
+
+        /* Read the .order file */
+        if(retval->item_flags & GNOME_DESKTOP_ITEM_IS_DIRECTORY) {
+                FILE *fh;
+		char *dn;
+
+		dn = g_path_get_dirname(data_file);
+                g_snprintf(confpath, sizeof(confpath), "%s/.order", dn);
+		g_free(dn);
+
+                fh = fopen(confpath, "r");
+
+                if(fh) {
+                        char buf[PATH_MAX];
+
+			/* we prepend the things onto the list so the
+			   list will actually be the reverse of the file */
+			while(fgets(buf, PATH_MAX, fh)) {
+				retval->order = g_slist_prepend(retval->order,
+								g_strdup(buf));
+			}
+
+			retval->order = g_slist_reverse(retval->order);
+
+                        fclose(fh);
+                }
+        }
+
+        return retval;
+
+ errout:
+        gnome_desktop_item_unref(retval);
+        return NULL;
+}
+
+/* load all the extra sections and store them as attributes in form of
+   section/attribute */
+static void
+ditem_load_other_sections(GnomeDesktopItem *item, const char *data_file,
+			  GSList *other_sections)
+{
+	GSList *li;
+
+	for(li = other_sections; li!=NULL; li = li->next) {
+		char confpath[PATH_MAX];
+		char *key, *value;
+		void *iter;
+		char *secname = li->data;
+
+		g_snprintf(confpath, sizeof(confpath),
+			   "=%s=/%s", data_file, secname);
+
+		iter = gnome_config_init_iterator(confpath);
+		while((iter = gnome_config_iterator_next(iter, &key, &value))) {
+			char *realkey;
+			if(!*key) {
+				g_free(key);
+				g_free(value);
+				continue;
+			}
+			realkey = g_strconcat(secname,"/",key,NULL);
+
+			g_hash_table_insert(item->other_attributes,
+					    realkey, value);
+			g_free(key);
+		}
+        }
+}
+
+/**
+ * gnome_desktop_item_new_from_file:
+ * @file: The filename or directory path to load the GnomeDesktopItem from
+ * @flags: Flags to influence the loading process
+ *
+ * This function loads 'file' and turns it into a GnomeDesktopItem.
+ * If 'file' is a directory, it loads all the items under that
+ * directory as subitems of the directory's GnomeDesktopItem.
+ *
+ * Returns: The newly loaded item.
+ */
+GnomeDesktopItem *
+gnome_desktop_item_new_from_file (const char *file, GnomeDesktopItemLoadFlags flags)
+{
+        GnomeDesktopItem *retval;
+        char subfn[PATH_MAX], headbuf[256], confpath[PATH_MAX];
+        FILE *fh;
+        GnomeDesktopItemFlags item_flags;
+        GnomeDesktopItemFormat fmt;
+        struct stat sbuf;
+	GSList *other_sections = NULL; /* names of other sections */
+
+        g_return_val_if_fail (file, NULL);
+
+#ifdef DI_DEBUG
+        /*  g_print("Loading file %s\n", file); */
+#endif
+
+        if (stat(file, &sbuf) != 0)
+                return NULL;
+
+        /* Step one - figure out what type of file this is */
+        flags = 0;
+        fmt = GNOME_DESKTOP_ITEM_UNKNOWN;
+        item_flags = 0;
+        if (S_ISDIR(sbuf.st_mode)) {
+                item_flags |= GNOME_DESKTOP_ITEM_IS_DIRECTORY;
+                g_snprintf(subfn, sizeof(subfn), "%s/.directory", file);
+		/* get the correct time for this file */
+		if (stat(subfn, &sbuf) != 0)
+			sbuf.st_mtime = 0;
+        } else {
+		char *base;
+		/* here we figure out if we're talking about a directory
+		   but have passed the .directory file */
+		base = g_path_get_basename(file);
+		if(strcmp(base, ".directory") == 0)
+			item_flags |= GNOME_DESKTOP_ITEM_IS_DIRECTORY;
+		g_free(base);
+                strcpy(subfn, file);
+        }
+
+
+        fh = fopen(subfn, "r");
+
+        if(!fh && (item_flags & GNOME_DESKTOP_ITEM_IS_DIRECTORY))
+                fmt = GNOME_DESKTOP_ITEM_GNOME; /* Empty dir becomes a GNOME thingie */
+        else if(fh) {
+		/* we go through the entire file looking for section headers,
+		   we do this as the right section header does not have to
+		   be at the top.  We however assume that it's either a
+		   GNOME desktop entry or a KDE one, and never both,
+		   perhaps we should us gnome_config_* for this already
+		   as it would probably speed things up, as gnome_config_*
+		   would already cache the file for later reading, we could
+		   also just do this from the file extention! */
+		while(fgets(headbuf, sizeof(headbuf), fh)) {
+			char *p;
+			g_strchug(headbuf);
+			if(headbuf[0] != '[')
+				continue;
+
+			if(!strncmp(headbuf, "[Desktop Entry]", strlen("[Desktop Entry]"))) {
+				fmt = GNOME_DESKTOP_ITEM_GNOME;
+				if(flags & GNOME_DESKTOP_ITEM_LOAD_NO_OTHER_SECTIONS)
+					break;
+			} else if(!strncmp(headbuf, "[KDE Desktop Entry]", strlen("[KDE Desktop Entry]"))) {
+				fmt = GNOME_DESKTOP_ITEM_KDE;
+				if(flags & GNOME_DESKTOP_ITEM_LOAD_NO_OTHER_SECTIONS)
+					break;
+			}
+
+			if(flags & GNOME_DESKTOP_ITEM_LOAD_NO_OTHER_SECTIONS)
+				continue;
+
+			p = strchr(headbuf,']');
+			if(!p) continue;
+			*p = '\0';
+			/* store a list of other sections to read */
+			other_sections =
+				g_slist_prepend(other_sections,
+						g_strdup(&headbuf[1]));
+		}
+
+                fclose(fh);
+        }
+
+        switch (fmt) {
+        case GNOME_DESKTOP_ITEM_KDE:
+                retval = ditem_kde_load(subfn, flags, item_flags);
+                break;
+        case GNOME_DESKTOP_ITEM_GNOME:
+                retval = ditem_gnome_load(subfn, flags, item_flags);
+                break;
+        default:
+                g_warning(_("Unknown desktop file format %d"), fmt);
+		/* if we have names of other sections, free that list */
+		if(other_sections) {
+			g_slist_foreach(other_sections,(GFunc)g_free,NULL);
+			g_slist_free(other_sections);
+		}
+                return NULL;
+                break;
+        }
+
+        if(!retval)
+                goto out;
+
+	ditem_load_other_sections(retval, subfn, other_sections);
+
+	/* make the 'Type' sane */
+        if(item_flags & GNOME_DESKTOP_ITEM_IS_DIRECTORY) {
+		/* perhaps a little ineficent way to ensure this
+		   is the correct type */
+		g_free(retval->type);
+		retval->type = g_strdup("Directory");
+	} else {
+		/* this is not a directory so sanitize it by killing the
+		   type altogether if type happens to be "Directory" */
+		if(retval->type && strcmp(retval->type, "Directory")==0) {
+			g_free(retval->type);
+			retval->type = NULL;
+		}
+	}
+
+	if(subfn[0] == '/')
+		retval->location = g_strdup(subfn);
+	else {
+		char *curdir = g_get_current_dir();
+		retval->location = g_concat_dir_and_file(curdir,subfn);
+		g_free(curdir);
+	}
+        retval->item_format = fmt;
+        retval->mtime = sbuf.st_mtime;
+
+        if(!g_hash_table_size(retval->name)) {
+                g_hash_table_destroy(retval->name);
+                retval->name = NULL;
+        }
+        if(!g_hash_table_size(retval->comment)) {
+                g_hash_table_destroy(retval->comment);
+                retval->comment = NULL;
+        }
+        if(!g_hash_table_size(retval->other_attributes)) {
+                g_hash_table_destroy(retval->other_attributes);
+                retval->other_attributes = NULL;
+        }
+
+ out:
+	/* if we have names of other sections, free that list */
+	if(other_sections) {
+		g_slist_foreach(other_sections,(GFunc)g_free,NULL);
+		g_slist_free(other_sections);
+	}
+        if(!(flags & GNOME_DESKTOP_ITEM_LOAD_NO_SYNC)) {
+		g_snprintf(confpath, sizeof(confpath), "=%s=", subfn);
+                gnome_config_sync_file(confpath);
+	}
+
+        return retval;
+}
+
+static void
+save_lang_val(gpointer key, gpointer value, gpointer user_data)
+{
+        char *valptr, tmpbuf[256];
+
+        if(!key || !strcmp(key, "C"))
+                valptr = user_data;
+        else
+                g_snprintf((valptr = tmpbuf), sizeof(tmpbuf), "%s[%s]", (char *)user_data, (char *)key);
+
+        gnome_config_set_string(valptr, value);
+}
+
+static void
+save_key_val(gpointer key, gpointer value, gpointer user_data)
+{
+	GnomeDesktopItem *item = user_data;
+	
+	/* in case the user set the OLD_STYLE_DROP flag on ignore
+	   the FileDropExec and URLDropExec so that next time we
+	   load we get the OLD_STYLE_DROP behaviour */
+	if(item->item_flags == GNOME_DESKTOP_ITEM_OLD_STYLE_DROP &&
+	   (strcmp(key,"FileDropExec")==0 ||
+	    strcmp(key,"URLDropExec")==0))
+		return;
+
+        gnome_config_set_string(key, value);
+}
+
+/**
+ * gnome_desktop_item_save:
+ * @item: A desktop item
+ * @under: The directory to save the tree underneath, can be NULL
+ *
+ * Writes the specified item to disk.  If the 'under' is NULL, the original
+ * location is used.  It sets the location of this entry to point to the
+ * new location.
+ *
+ * Returns: boolean. %TRUE if the file was saved, %FALSE otherwise
+ */
+gboolean
+gnome_desktop_item_save (GnomeDesktopItem *item, const char *under)
+{
+        char fnbuf[PATH_MAX + sizeof("==/KDE Desktop Entry/")];
+
+        g_return_val_if_fail(item, FALSE);
+        g_return_val_if_fail(under, FALSE);
+        g_return_val_if_fail(item->location, FALSE);
+
+	/* first we setup the new location if we need to */
+	if(under) {
+		char *old_loc = item->location;
+		char *base;
+		base = g_path_get_basename(item->location);
+		item->location = g_concat_dir_and_file(under, base);
+		g_free(base);
+		g_free(old_loc);
+	}
+
+	/* save the .order for gnome directory entries */
+	if(item->item_flags & GNOME_DESKTOP_ITEM_IS_DIRECTORY &&
+	   item->item_format == GNOME_DESKTOP_ITEM_GNOME) {
+                FILE *fh;
+		char *dir = g_path_get_dirname(item->location);
+
+                g_snprintf(fnbuf, sizeof(fnbuf), "%s/.order", dir);
+
+		g_free(dir);
+
+		fh = fopen(fnbuf, "w");
+
+		if(fh) {
+			GSList *li;
+			for(li = item->order; li; li = li->next)
+				fprintf(fh, "%s\n", (char *)li->data);
+			fclose(fh);
+		} else
+			return FALSE;
+	}
+
+	/* clean the file first, do not drop as if we dropped it the old
+	   stuff would be realoded on the next gnome_config_set_*, also
+	   this saves a syscall for the file remove */
+	g_snprintf(fnbuf, sizeof(fnbuf), "=%s=", item->location);
+	gnome_config_clean_file(fnbuf);
+
+	g_snprintf(fnbuf, sizeof(fnbuf), "=%s=/%sDesktop Entry/",
+		   item->location,
+		   (item->item_format==GNOME_DESKTOP_ITEM_KDE)?"KDE ":"");
+
+        gnome_config_push_prefix(fnbuf);
+
+        if(item->icon_path)
+                gnome_config_set_string("Icon", item->icon_path);
+
+        if(item->exec)
+                gnome_config_set_string("Exec", item->exec);
+
+	/* set the type, if we haven't got one, make one up, trying to
+	   guess the correct one */
+        if(item->type)
+                gnome_config_set_string("Type", item->type);
+	else
+                gnome_config_set_string("Type", (item->item_flags & GNOME_DESKTOP_ITEM_IS_DIRECTORY)?"Directory":"Application");
+
+        if(item->name)
+                g_hash_table_foreach(item->name, save_lang_val, "Name");
+	if(!gnome_desktop_item_get_name(item, "C")) {
+		/* whoops, there is not default for name if no language is
+		 * found, this could cause this not to be loaded so set it
+		 * to the name of the file if possible, or "Unknown"
+		 * (not to be translated "C" is supposed to be english) */
+		char *name;
+		name = g_path_get_basename(item->location);
+		if(!name)
+			name = g_strdup("Unknown");
+		gnome_config_set_string("Name", name);
+		g_free(name);
+	}
+
+        if(item->comment)
+                g_hash_table_foreach(item->comment, save_lang_val, "Comment");
+        if(item->other_attributes)
+                g_hash_table_foreach(item->other_attributes,
+				     save_key_val,
+				     item);
+        if(item->item_flags & GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL)
+                gnome_config_set_bool("Terminal", TRUE);
+
+        if(item->item_format == GNOME_DESKTOP_ITEM_KDE &&
+	   item->order) {
+		GString *gs;
+		GSList *li;
+
+		gs = g_string_new("");
+		for(li = item->order; li; li = li->next) {
+			if(li != item->order)
+				g_string_append_c(gs,',');
+			g_string_append(gs,li->data);
+		}
+
+                gnome_config_set_string("SortOrder", gs->str);
+		g_string_free(gs,TRUE);
+        }
+
+        gnome_config_pop_prefix();
+
+        item->mtime = time(NULL);
+
+	/* sync the file onto disk */
+	g_snprintf(fnbuf, sizeof(fnbuf), "=%s=", item->location);
+
+	return gnome_config_sync_file(fnbuf);
+}
+
+/**
+ * gnome_desktop_item_ref:
+ * @item: A desktop item
+ *
+ * Increases the reference count of the specified item.
+ */
+void
+gnome_desktop_item_ref (GnomeDesktopItem *item)
+{
+        g_return_if_fail(item);
+
+        item->refcount++;
+}
+
+static gboolean
+ditem_free_key_value(gpointer key, gpointer value, gpointer user_data)
+{
+        g_free(key);
+        g_free(value);
+        return TRUE;
+}
+
+/**
+ * gnome_desktop_item_ref:
+ * @item: A desktop item
+ *
+ * Decreases the reference count of the specified item, and destroys the item if there are no more references left.
+ */
+void
+gnome_desktop_item_unref (GnomeDesktopItem *item)
+{
+        g_return_if_fail(item);
+
+        item->refcount--;
+
+        if(item->refcount != 0)
+                return;
+
+        g_free(item->type);
+        g_free(item->exec);
+        g_free(item->icon_path);
+        g_free(item->location);
+
+        if(item->name) {
+                g_hash_table_foreach_remove(item->name, ditem_free_key_value, NULL);
+                g_hash_table_destroy(item->name);
+        }
+
+        if(item->comment) {
+                g_hash_table_foreach_remove(item->comment, ditem_free_key_value, NULL);
+                g_hash_table_destroy(item->comment);
+        }
+
+        if(item->other_attributes) {
+                g_hash_table_foreach_remove(item->other_attributes, ditem_free_key_value, NULL);
+                g_hash_table_destroy(item->other_attributes);
+        }
+
+        g_slist_foreach(item->order, (GFunc)g_free, NULL);
+        g_slist_free(item->order);
+
+        g_free(item);
+}
+
+/* replace %? (ps) with a string, the string can be NULL which is the same
+   as "", it works on a vector and appends the 'tofree' with strings which
+   should be freed later, returns TRUE if it replaced something, FALSE
+   otherwise, if only_once is true we jump out after the first, it can actually
+   only replace one 'ps' per argument to avoid infinite loops (in case 'string'
+   would contain 'ps' */
+static gboolean
+replace_percentsign(int argc, char **argv, const char *ps,
+		    const char *string, GSList **tofree,
+		    gboolean only_once)
+{
+	int i;
+	gboolean ret = FALSE;
+	if(!string) string = "";
+	for(i=0;i<argc;i++) {
+		char *arg = argv[i];
+		char *p = strstr(arg,ps);
+		char *s;
+		int start, string_len, ps_len;
+		if(!p) continue;
+		string_len = strlen(string);
+		ps_len = strlen(ps);
+		s = g_new(char, strlen(arg) - ps_len + string_len + 1);
+		start = p - arg;
+		strncpy(s,arg,start);
+		strcpy(&s[start],string);
+		strcpy(&s[start+string_len],&arg[start+ps_len]);
+		argv[i] = s;
+		*tofree = g_slist_prepend(*tofree, s);
+		ret = TRUE;
+		if(only_once) return ret;
+	}
+	return ret;
+}
+
+/* the appargv, will get modified but not freed, the replacekdefiles
+   tells us to replace the %f %u and %F for kde files with nothing */
+static int
+ditem_execute(const GnomeDesktopItem *item, int appargc, const char *appargv[], int argc, const char *argv[], gboolean replacekdefiles)
+{
+        char **real_argv;
+        int real_argc;
+        int i, j, ret;
+	char **term_argv = NULL;
+	int term_argc = 0;
+	GSList *tofree = NULL;
+
+        g_return_val_if_fail(item, -1);
+        g_return_val_if_fail(item->exec, -1);
+
+        if(!argv)
+                argc = 0;
+
+
+	/* check the type, if there is one set */
+	if(item->type) {
+		if(item->item_format == GNOME_DESKTOP_ITEM_KDE) {
+			if(strcmp(item->type,"KonsoleApplication")!=0 &&
+			   strcmp(item->type,"Application")!=0) {
+				/* we are not an application so just exit
+				   with an error */
+				g_warning(_("Attempting to launch a non-application"));
+				return -1;
+			}
+		} else if(item->item_format == GNOME_DESKTOP_ITEM_GNOME) {
+			if(strcmp(item->type,"Application")!=0) {
+				/* we are not an application so just exit
+				   with an error */
+				g_warning(_("Attempting to launch a non-application"));
+				return -1;
+			}
+		} else {
+			g_warning(_("Unknown desktop file format %d"),
+				  item->item_format);
+		}
+	}
+
+	if(item->item_flags & GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL) {
+		/* somewhat hackish I guess, we should use this in
+		 * the prepend mode rather then just getting a new
+		 * vector, but I didn't want to rewrite this whole
+		 * function */
+		term_argc = 0;
+		term_argv = NULL;
+		gnome_prepend_terminal_to_vector (&term_argc, &term_argv);
+	}
+
+        real_argc = term_argc + argc + appargc;
+        real_argv = g_alloca((real_argc + 1) * sizeof(char *));
+
+        for(i = 0; i < term_argc; i++)
+                real_argv[i] = term_argv[i];
+
+        for(j = 0; j < appargc; j++, i++)
+                real_argv[i] = (char *)appargv[j];
+
+        for(j = 0; j < argc; j++, i++)
+                real_argv[i] = (char *)argv[j];
+
+	/* if we are kde, replace the standard %? thingies */
+	if(item->item_format == GNOME_DESKTOP_ITEM_KDE) {
+		if(replacekdefiles) {
+			replace_percentsign(real_argc, real_argv, "%f", NULL, &tofree, TRUE);
+			replace_percentsign(real_argc, real_argv, "%F", NULL, &tofree, TRUE);
+			replace_percentsign(real_argc, real_argv, "%u", NULL, &tofree, TRUE);
+		}
+		replace_percentsign(real_argc, real_argv, "%d", g_getenv("PWD"), &tofree, FALSE);
+		replace_percentsign(real_argc, real_argv, "%i", item->icon_path, &tofree, FALSE);
+		replace_percentsign(real_argc, real_argv, "%m", 
+				    gnome_desktop_item_get_attribute(item,"MiniIcon"), &tofree, FALSE);
+		replace_percentsign(real_argc, real_argv, "%c", 
+				    gnome_desktop_item_get_local_comment(item), &tofree, FALSE);
+	}
+
+        ret = gnome_execute_async(NULL, real_argc, real_argv);
+
+	if(tofree) {
+		g_slist_foreach(tofree,(GFunc)g_free,NULL);
+		g_slist_free(tofree);
+	}
+
+	if(term_argv)
+		g_strfreev(term_argv);
+
+	return ret;
+}
+
+/* strip any trailing &, return FALSE if bad things happen and
+   we end up with an empty string */
+static gboolean
+strip_the_amp(char *exec)
+{
+	int exec_len;
+
+	g_strstrip(exec);
+	if(!*exec) return FALSE;
+
+	exec_len = strlen(exec);
+	/* kill any trailing '&' */
+	if(exec[exec_len-1] == '&') {
+		exec[exec_len-1] = '\0';
+		g_strchomp(exec);
+	}
+
+	/* can't exactly launch an empty thing */
+	if(!*exec) return FALSE;
+
+	return TRUE;
+}
+
+/**
+ * gnome_desktop_item_launch:
+ * @item: A desktop item
+ * @argc: An optional count of arguments to be added to the arguments defined.
+ * @argv: An optional argument array, of length 'argc', to be appended
+ *        to the command arguments specified in 'item'. Can be NULL.
+ *
+ * This function runs the program listed in the specified 'item',
+ * optionally appending additional arguments to its command line.  It uses
+ * poptParseArgvString to parse the the exec string into a vector which is
+ * then passed to gnome_exec_async for execution with argc and argv appended.
+ *
+ * Returns: The value returned by gnome_execute_async() upon execution of
+ * the specified item or -1 on error.  It may also return a 0 on success
+ * if pid is not available, such as in a case where the entry is a URL
+ * entry.
+ */
+int
+gnome_desktop_item_launch (const GnomeDesktopItem *item, int argc, const char **argv)
+{
+	const char **temp_argv = NULL;
+	int temp_argc = 0;
+	char *the_exec;
+	int ret;
+
+        g_return_val_if_fail(item, -1);
+
+	if(!item->exec) {
+		g_warning(_("Trying to execute an item with no 'Exec'"));
+		return -1;
+	}
+
+	/* This is a URL, so launch it as a url */
+	if (item->type != NULL &&
+	    item->item_format == GNOME_DESKTOP_ITEM_GNOME &&
+	    strcmp (item->type, "URL") == 0) {
+		if (gnome_url_show (item->exec))
+			return 0;
+		else
+			return -1;
+	}
+
+	/* make a new copy and get rid of spaces */
+	the_exec = g_alloca(strlen(item->exec)+1);
+	strcpy(the_exec,item->exec);
+
+	if(!strip_the_amp(the_exec))
+		return -1;
+
+	/* we use a popt function as it does exactly what we want to do and
+	   gnome already uses popt */
+	if(poptParseArgvString(item->exec, &temp_argc, &temp_argv) != 0) {
+		/* no we have failed in making this a vector what should
+		   we do? we can pretend that the exec failed and return -1,
+		   perhaps we should give a little better error? */
+		return -1;
+	}
+
+	ret = ditem_execute(item, temp_argc, temp_argv, argc, argv, TRUE);
+
+	/* free the array done by poptParseArgvString, not by
+	   g_free but free, this is not a memory leak the whole thing
+	   is one allocation */
+	free(temp_argv);
+
+	return ret;
+}
+
+/* replace %s, %f, %u or %F in exec with file and run */
+static int
+ditem_exec_single_file (const GnomeDesktopItem *item, const char *exec, char *file)
+{
+	const char **temp_argv = NULL;
+	int temp_argc = 0;
+	char *the_exec;
+	GSList *tofree = NULL;
+	int ret;
+
+        g_return_val_if_fail(item, -1);
+	if(!exec) {
+		g_warning(_("No exec field for this drop"));
+		return -1;
+	}
+
+	/* make a new copy and get rid of spaces */
+	the_exec = g_alloca(strlen(exec)+1);
+	strcpy(the_exec,exec);
+
+	if(!strip_the_amp(the_exec))
+		return -1;
+
+	/* we use a popt function as it does exactly what we want to do and
+	   gnome already uses popt */
+	if(poptParseArgvString(exec, &temp_argc, &temp_argv) != 0) {
+		/* no we have failed in making this a vector what should
+		   we do? we can pretend that the exec failed and return -1,
+		   perhaps we should give a little better error? */
+		return -1;
+	}
+
+	/* we are gnomish and we want to use %s, but if someone uses %f, %u or %F
+	   we forgive them and do it too */
+	if(replace_percentsign(temp_argc, (char **)temp_argv, "%s", file, &tofree,TRUE))
+		goto perc_replaced;
+	if(replace_percentsign(temp_argc, (char **)temp_argv, "%f", file, &tofree,TRUE))
+		goto perc_replaced;
+	if(replace_percentsign(temp_argc, (char **)temp_argv, "%u", file, &tofree,TRUE))
+		goto perc_replaced;
+	if(replace_percentsign(temp_argc, (char **)temp_argv, "%F", file, &tofree,TRUE))
+		goto perc_replaced;
+	g_free(temp_argv);
+	g_warning(_("Nothing to replace with a file in the exec string"));
+	return -1;
+perc_replaced:
+
+	ret = ditem_execute(item, temp_argc, temp_argv, 0, NULL, FALSE);
+
+	if(tofree) {
+		g_slist_foreach(tofree,(GFunc)g_free,NULL);
+		g_slist_free(tofree);
+	}
+
+	/* free the array done by poptParseArgvString, not by
+	   g_free but free, this is not a memory leak the whole thing
+	   is one allocation */
+	free(temp_argv);
+
+	return ret;
+}
+
+/* works sort of like strcmp(g_strstrip(s1),s2), but returns only
+ * TRUE or FALSE and does not modify s1, basically it tells if s2
+ * is the same as s1 stripped */
+static gboolean
+stripstreq(const char *s1, const char *s2)
+{
+	int len2;
+
+	/* skip over initial spaces */
+	while(*s1 == ' ' || *s1 == '\t')
+		s1++;
+	len2 = strlen(s2);
+	/* compare inner parts */
+	if(strncmp(s1, s2, len2) != 0)
+		return FALSE;
+	/* skip over beyond the equal parts */
+	s1 += len2;
+	for(; *s1; s1++) {
+		/* if we find anything but whitespace that bad */
+		if(*s1 != ' ' && *s1 != '\t')
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+/* replace %s, %f, %u or %F in exec with files and run, the trick here is
+   that we will only replace %? in case it is a complete argument */
+static int
+ditem_exec_multiple_files (const GnomeDesktopItem *item, const char *exec,
+			   GList *files)
+{
+	const char **temp_argv = NULL;
+	int temp_argc = 0;
+	char *the_exec;
+	int ret;
+	int real_argc;
+	const char **real_argv;
+	int i,j;
+	gboolean replaced = FALSE;
+
+        g_return_val_if_fail(item, -1);
+	if(!exec) {
+		g_warning(_("No exec field for this drop"));
+		return -1;
+	}
+
+	/* make a new copy and get rid of spaces */
+	the_exec = g_alloca(strlen(exec)+1);
+	strcpy(the_exec,exec);
+
+	if(!strip_the_amp(the_exec))
+		return -1;
+
+	/* we use a popt function as it does exactly what we want to do and
+	   gnome already uses popt */
+	if(poptParseArgvString(exec, &temp_argc, &temp_argv) != 0) {
+		/* no we have failed in making this a vector what should
+		   we do? we can pretend that the exec failed and return -1,
+		   perhaps we should give a little better error? */
+		return -1;
+	}
+
+	real_argc = temp_argc - 1 + g_list_length(files);
+	/* we allocate +2, one for NULL, one as a buffer in case
+	   we don't find anything to replace */
+	real_argv = g_alloca((real_argc + 2) * sizeof(char *));
+
+	for(i=0,j=0; i < real_argc && j < temp_argc; i++, j++) {
+		GList *li;
+		real_argv[i] = temp_argv[j];
+		/* we only replace once */
+		if(replaced)
+			continue;
+
+		if(!stripstreq(real_argv[i],"%s") &&
+		   !stripstreq(real_argv[i],"%f")!=0 &&
+		   !stripstreq(real_argv[i],"%u")!=0 &&
+		   !stripstreq(real_argv[i],"%F")!=0)
+			continue;
+
+		/* replace the argument with the files we got passed */
+		for(li = files; li!=NULL; li=li->next)
+			real_argv[i++] = li->data;
+
+		/* since we will increment in the for loop itself */
+		i--;
+
+		/* don't replace again! */
+		replaced = TRUE;
+	}
+
+	/* we haven't replaced anything */
+	if(!replaced) {
+		g_warning(_("There was no argument to replace with dropped files"));
+		return -1;
+	}
+
+	ret = ditem_execute(item, real_argc, real_argv, 0, NULL, FALSE);
+
+	/* free the array done by poptParseArgvString, not by
+	   g_free but free, this is not a memory leak the whole thing
+	   is one allocation */
+	free(temp_argv);
+
+	return ret;
+}
+
+
+/**
+ * gnome_desktop_item_drop_uri_list:
+ * @item: A desktop item
+ * @uri_list: an uri_list as if gotten from #gnome_uri_list_extract_uris
+ *
+ * A list of files or urls dropped onto an icon, the proper (Url or File)
+ * exec is run you can pass directly the output of 
+ * #gnome_uri_list_extract_uris.  The input thus must be a GList of
+ * strings in the URI format.  If the ditem didn't specify any DND
+ * options we assume old style and drop by appending the list to the end
+ * of 'Exec' (see #gnome_desktop_item_get_command).  If there were any urls
+ * dropped the item must have specified being able to run URLs or you'll get
+ * a warning and an error.  Basically if there are ANY urls in the list
+ * it's taken as a list of urls and works only on apps that can take urls.
+ * If the program can't take that many arguments, as many instances as
+ * necessary will be started.
+ *
+ * Returns: The value returned by gnome_execute_async() upon execution of
+ * the specified item or -1 on error.  If multiple instances are run, the
+ * return of the last one is returned.
+ */
+/*FIXME: perhaps we should be able to handle mixed url/file lists better
+  rather then treating it as a list of urls */
+int
+gnome_desktop_item_drop_uri_list (const GnomeDesktopItem *item,
+				  GList *uri_list)
+{
+	GList *li;
+	gboolean any_urls = FALSE;
+	GList *file_list = NULL;
+	int ret = -1;
+
+	g_return_val_if_fail (item != NULL, -1);
+	g_return_val_if_fail (uri_list != NULL, -1);
+
+	/* How could you drop something on a URL entry, that would
+	 * be bollocks */
+	if (item->type != NULL &&
+	    item->item_format == GNOME_DESKTOP_ITEM_GNOME &&
+	    strcmp (item->type, "URL") == 0) {
+		return -1;
+	}
+
+	/* do we even allow drops? */
+	if(item->item_flags & GNOME_DESKTOP_ITEM_NO_FILE_DROP &&
+	   item->item_flags & GNOME_DESKTOP_ITEM_NO_URL_DROP)
+		return -1;
+
+	/* the simple case */
+	if(item->item_flags & GNOME_DESKTOP_ITEM_OLD_STYLE_DROP) {
+		int i;
+		int argc = g_list_length(uri_list);
+		const char **argv = g_alloca((argc + 1) * sizeof(char *));
+
+		for(i=0,li=uri_list; li; i++, li=li->next) {
+			char *p = gnome_uri_extract_filename(li->data);
+			if(p) {
+				char *s = g_alloca(strlen(p)+1);
+				strcpy(s, p);
+				g_free(p);
+				argv[i] = s;
+			} else {
+				argv[i] = li->data;
+			}
+		}
+		argv[i] = NULL;
+		return gnome_desktop_item_launch(item, argc, argv);
+	}
+
+	/* figure out if we have any urls in the dropped files,
+	   this also builds a list of all the files */
+	for(li=uri_list; li; li=li->next) {
+		char *p = gnome_uri_extract_filename(li->data);
+		if(p)
+			file_list = g_list_prepend(file_list, p);
+		else
+			any_urls = TRUE;
+	}
+	if(file_list)
+		file_list = g_list_reverse(file_list);
+
+	/* if there are any urls, or if the app didn't specify a command
+	   for files use the URL command */
+	if(any_urls || item->item_flags & GNOME_DESKTOP_ITEM_NO_FILE_DROP) {
+		if(item->item_flags & GNOME_DESKTOP_ITEM_NO_URL_DROP) {
+			g_warning(_("Dropped URLs on an app that can only take files"));
+			return -1;
+		}
+
+		if(item->item_flags & GNOME_DESKTOP_ITEM_SINGLE_URL_DROP_ONLY) {
+			GList *li;
+			const char *exec = NULL;
+			if(item->item_format == GNOME_DESKTOP_ITEM_GNOME)
+				exec = gnome_desktop_item_get_attribute(item,"URLDropExec");
+			if(!exec) exec = item->exec;
+			for(li = uri_list; li; li=li->next)
+				ret = ditem_exec_single_file(item, exec, li->data);
+		} else {
+			const char *exec = NULL;
+			if(item->item_format == GNOME_DESKTOP_ITEM_GNOME)
+				exec = gnome_desktop_item_get_attribute(item,"URLDropExec");
+			if(!exec) exec = item->exec;
+			ret = ditem_exec_multiple_files(item, exec, uri_list);
+		}
+	} else {
+		if(item->item_flags & GNOME_DESKTOP_ITEM_SINGLE_FILE_DROP_ONLY) {
+			GList *li;
+			const char *exec = NULL;
+			if(item->item_format == GNOME_DESKTOP_ITEM_GNOME)
+				exec = gnome_desktop_item_get_attribute(item,"FileDropExec");
+			if(!exec) exec = item->exec;
+			for(li = file_list; li; li=li->next)
+				ret = ditem_exec_single_file(item, exec,
+							     li->data);
+		} else {
+			const char *exec = NULL;
+			if(item->item_format == GNOME_DESKTOP_ITEM_GNOME)
+				exec = gnome_desktop_item_get_attribute(item,"FileDropExec");
+			if(!exec) exec = item->exec;
+			ret = ditem_exec_multiple_files(item, exec, file_list);
+		}
+	}
+
+	if(file_list) {
+		g_list_foreach(file_list,(GFunc)g_free,NULL);
+		g_list_free(file_list);
+	}
+
+	return ret;
+}
+
+/**
+ * gnome_desktop_item_exists:
+ * @item: A desktop item
+ *
+ * Attempt to figure out if the program that can be executed by this item
+ * actually exists.  First it tries the TryExec attribute to see if that
+ * contains a program that is in the path.  Then if there is no such
+ * attribute, it tries the first word of the Exec attribute.
+ *
+ * Returns: A boolean, %TRUE if it exists, %FALSE otherwise.
+ */
+gboolean
+gnome_desktop_item_exists (const GnomeDesktopItem *item)
+{
+        g_return_val_if_fail(item, FALSE);
+
+        if(item->other_attributes) {
+                char *tryme;
+
+                tryme = g_hash_table_lookup(item->other_attributes, "TryExec");
+                if(tryme) {
+                        tryme = gnome_is_program_in_path(tryme);
+                        if(tryme) {
+                                g_free(tryme);
+                                return TRUE;
+                        }
+                        else
+                                return FALSE;
+                }
+        }
+
+        if(item->exec) {
+		const char **temp_argv = NULL;
+		int temp_argc = 0;
+		gboolean ret = FALSE;
+
+		/* we use a popt function as it does exactly what we want to
+		   do and gnome already uses popt */
+		if(poptParseArgvString(item->exec,
+				       &temp_argc,
+				       &temp_argv) != 0) {
+			/* we have failed, so we can't actually parse the
+			   exec string and do the only sane thing and
+			   return FALSE */
+			return FALSE;
+		}
+
+                if(temp_argv[0][0] == PATH_SEP)
+                        ret = g_file_test(temp_argv[0], G_FILE_TEST_EXISTS);
+                else {
+                        char *tryme = gnome_is_program_in_path(temp_argv[0]);
+                        if(tryme) {
+                                g_free(tryme);
+                                ret = TRUE;
+                        }
+                        else
+                                ret = FALSE;
+                }
+		/* free the array done by poptParseArgvString, not by
+		   g_free but free, this is not a memory leak the whole
+		   thing is one allocation */
+		free(temp_argv);
+		return ret;
+        }
+
+        return TRUE;
+}
+
+/**
+ * gnome_desktop_item_get_flags:
+ * @item: A desktop item
+ *
+ * Returns: The flags associated with the specified 'item'
+ */
+GnomeDesktopItemFlags
+gnome_desktop_item_get_flags (const GnomeDesktopItem *item)
+{
+        g_return_val_if_fail(item, 0);
+
+        return item->item_flags;
+}
+
+/**
+ * gnome_desktop_item_get_type:
+ * @item: A desktop item
+ *
+ * Gets the type attribute (the 'Type' field) of the item.  This should
+ * usually be 'Application' for an application, but it can be 'Directory'
+ * for a directory description.  There are other types available as well.
+ * The type usually indicates how the desktop item should be handeled and
+ * how the 'Exec' field should be handeled.
+ *
+ * Returns: The type of the specified 'item'. The returned
+ * memory remains owned by the GnomeDesktopItem and should not be freed.
+ */
+const char *
+gnome_desktop_item_get_type (const GnomeDesktopItem *item)
+{
+        g_return_val_if_fail(item, NULL);
+
+        return item->type;
+}
+
+/**
+ * gnome_desktop_item_get_command:
+ * @item: A desktop item
+ *
+ * Gets the command attribute (the 'Exec' field) of the item.  
+ * The command should be a single string which can be parsed into
+ * a vector directly for execution.  Note that it is NOT a shell
+ * expression.  It is allowed to have escapes and quoting as per
+ * the standard quoting rules however.
+ *
+ * Returns: The command associated with the specified 'item'. The returned
+ * memory remains owned by the GnomeDesktopItem and should not be freed.
+ */
+const char *
+gnome_desktop_item_get_command (const GnomeDesktopItem *item)
+{
+        g_return_val_if_fail(item, NULL);
+
+        return item->exec;
+}
+
+/**
+ * gnome_desktop_item_get_icon_path:
+ * @item: A desktop item
+ *
+ * Returns: The icon filename associated with the specified 'item'.
+ * The returned memory remains owned by the GnomeDesktopItem
+ * and should not be freed.
+ */
+const char *
+gnome_desktop_item_get_icon_path (const GnomeDesktopItem *item)
+{
+        g_return_val_if_fail(item, NULL);
+
+        return item->icon_path;
+}
+
+/**
+ * gnome_desktop_item_get_name:
+ * @item: A desktop item
+ * @language: The language translation for which the name should be returned. If NULL is passed, it defaults to "C".
+ *
+ * Returns: The human-readable name for the specified 'item', in the
+ *          specified 'language'. The returned memory remains owned by
+ *          the GnomeDesktopItem and should not be freed.
+ * */
+const char *
+gnome_desktop_item_get_name (const GnomeDesktopItem *item, const char *language)
+{
+        g_return_val_if_fail(item, NULL);
+
+        if(item->name)
+                return g_hash_table_lookup(item->name, language?language:"C");
+        else
+                return NULL;
+}
+
+/**
+ * gnome_desktop_item_get_comment:
+ * @item: A desktop item
+ * @language: The language translation for which the comment should be returned. If NULL is passed, it defaults to "C".
+ *
+ * Returns: The human-readable comment for the specified 'item', in the
+ *          specified 'language'. The returned memory remains owned by
+ *          the GnomeDesktopItem and should not be freed.
+ *
+ */
+const char *
+gnome_desktop_item_get_comment (const GnomeDesktopItem *item, const char *language)
+{
+        g_return_val_if_fail(item, NULL);
+
+        if(item->comment)
+                return g_hash_table_lookup(item->comment, language?language:"C");
+        else
+                return NULL;
+}
+
+/**
+ * gnome_desktop_item_get_local_name:
+ * @item: A desktop item
+ *
+ * Returns: The human-readable name for the specified @item, in
+ *          the user's preferred locale or a fallback if
+ *          necessary. The returned memory remains owned by the
+ *          GnomeDesktopItem and should not be freed. If no
+ *          name is set in any relevant locale, NULL is returned.
+ * */
+
+const char *
+gnome_desktop_item_get_local_name   (const GnomeDesktopItem     *item)
+{
+	g_return_val_if_fail(item, NULL);
+
+	if(item->name) {
+		const GList *iter;
+
+		iter = gnome_i18n_get_language_list(NULL);
+
+		while (iter != NULL) {
+			const gchar* name;
+
+			name = g_hash_table_lookup(item->name, iter->data);
+
+			if (name)
+				return name;
+			else
+				iter = g_list_next(iter);
+		}
+		return NULL;
+	} else
+                return NULL;
+}
+
+/**
+ * gnome_desktop_item_get_local_comment:
+ * @item: A desktop item
+ *
+ * Returns: The human-readable comment for the specified @item, in
+ *          the user's preferred locale or a fallback if
+ *          necessary. The returned memory remains owned by the
+ *          GnomeDesktopItem and should not be freed. If no comment
+ *          exists then NULL is returned.
+ * */
+const char *
+gnome_desktop_item_get_local_comment(const GnomeDesktopItem     *item)
+{
+        g_return_val_if_fail(item, NULL);
+
+	if(item->comment) {
+		const GList *iter;
+
+		iter = gnome_i18n_get_language_list(NULL);
+
+		while (iter != NULL) {
+			const gchar* comment;
+
+			comment = g_hash_table_lookup(item->comment, iter->data);
+
+			if (comment)
+				return comment;
+			else
+				iter = g_list_next(iter);
+		}
+		return NULL;
+	} else
+                return NULL;
+}
+
+
+/**
+ * gnome_desktop_item_get_attribute:
+ * @item: A desktop item
+ * @attr_name: Name of the attribute to get
+ *
+ * Gets an extra attribute from the desktop item.  If there were other
+ * sections in the item, they can be accessed as "section/key".  If you
+ * attribute is a translatable string, use the
+ * #gnome_desktop_item_get_local_attribute function.
+ *
+ * Returns: The value of the attribute 'attr_name' on the 'item'. The
+ *          returned memory remains owned by the GnomeDesktopItem and
+ *          should not be freed.
+ *
+ */
+const char *
+gnome_desktop_item_get_attribute (const GnomeDesktopItem *item, const char *attr_name)
+{
+        g_return_val_if_fail(item, NULL);
+        g_return_val_if_fail(attr_name, NULL);
+
+        if(item->other_attributes)
+                return g_hash_table_lookup(item->other_attributes, attr_name);
+        else
+                return NULL;
+}
+
+/**
+ * gnome_desktop_item_get_local_attribute:
+ * @item: A desktop item
+ * @attr_name: Name of the attribute to get
+ *
+ * Gets an extra attribute as a local string (if it was a translatable
+ * attribute) from the desktop item.  If there were other
+ * sections in the item, they can be accessed as "section/key".  If you
+ * attribute is not a translatable string, use the
+ * #gnome_desktop_item_get_attribute function.
+ *
+ * Returns: The value of the attribute 'attr_name' on the 'item'. The
+ *          returned memory remains owned by the GnomeDesktopItem and
+ *          should not be freed.
+ *
+ */
+const char *
+gnome_desktop_item_get_local_attribute (const GnomeDesktopItem *item,
+					const char *attr_name)
+{
+        g_return_val_if_fail(item, NULL);
+        g_return_val_if_fail(attr_name, NULL);
+
+        if(item->other_attributes) {
+		const GList *iter;
+
+		iter = gnome_i18n_get_language_list(NULL);
+
+		while (iter != NULL) {
+			char *key;
+			const gchar* value;
+			char *lang = iter->data;
+
+			if(lang && strcmp(lang,"C")!=0)
+				key = g_strconcat(attr_name,"[",lang,"]",NULL);
+			else
+				key = (char *)attr_name;
+
+			value = g_hash_table_lookup(item->other_attributes,
+						    key);
+			if(key != attr_name) g_free(key);
+
+			if (value)
+				return value;
+			else
+				iter = g_list_next(iter);
+		}
+	} 
+	return NULL;
+}
+
+/**
+ * gnome_desktop_item_get_order:
+ * @item: A desktop item
+ *
+ * Get the order of the items in a subdirectory which this item describes.
+ * When you load a directory you should load these first and then load
+ * any remaining ones after.
+ *
+ * Returns: A GSList of strings which are base filesnames in the correct
+ * order.  The returned list should not be freed as it is owned by the item.
+ *
+ */
+const GSList *
+gnome_desktop_item_get_order (const GnomeDesktopItem *item)
+{
+        g_return_val_if_fail(item, NULL);
+
+        return item->order;
+}
+
+static void
+ditem_add_key(gpointer key, gpointer value, gpointer user_data)
+{
+        GSList **list = user_data;
+
+        *list = g_slist_prepend(*list, key);
+}
+
+/* add key to the list (in user_data), but test to see if it's
+   there first */
+static void
+ditem_add_key_test(gpointer key, gpointer value, gpointer user_data)
+{
+        GSList **list = user_data;
+
+	if(g_slist_find_custom(*list, key, (GCompareFunc)strcmp)==NULL)
+		*list = g_slist_prepend(*list, key);
+}
+
+/**
+ * gnome_desktop_item_get_languages:
+ * @item: A desktop item
+ * 
+ * Gets a list of languages that you can use to get names and comments.
+ *
+ * Returns: A GSList of the language name strings.  The returned GSList
+ * should be freed with g_slist_free, but the strings inside the list
+ * should not.
+ *
+ */
+GSList *
+gnome_desktop_item_get_languages(const GnomeDesktopItem *item)
+{
+        GSList *retval = NULL;
+
+        g_return_val_if_fail(item, NULL);
+
+        if(item->name) {
+                g_hash_table_foreach(item->name, ditem_add_key, &retval);
+        }
+        if(item->comment) {
+                g_hash_table_foreach(item->name, ditem_add_key_test, &retval);
+        }
+
+        return retval;
+}
+
+/**
+ * gnome_desktop_item_get_attributes:
+ * @item: A desktop item
+ *
+ * Gets the list of the attributes which you can can get with the
+ * #gnome_desktop_item_get_attribute function.
+ *
+ * Returns: A GSList of the attribute name strings.  The returned GSList
+ * should be freed with g_slist_free, but the strings inside the list
+ * should not.
+ *
+ */
+GSList *
+gnome_desktop_item_get_attributes(const GnomeDesktopItem *item)
+{
+        GSList *retval = NULL;
+
+        g_return_val_if_fail(item, NULL);
+
+        if(item->other_attributes) {
+                g_hash_table_foreach(item->other_attributes, ditem_add_key, &retval);
+        }
+
+        return retval;
+}
+
+/**
+ * gnome_desktop_item_get_format:
+ * @item: A desktop item
+ *
+ * Returns: The format that the specified 'item' is stored on disk with
+ */
+GnomeDesktopItemFormat
+gnome_desktop_item_get_format (const GnomeDesktopItem *item)
+{
+        g_return_val_if_fail(item, GNOME_DESKTOP_ITEM_UNKNOWN);
+
+        return item->item_format;
+}
+
+/**
+ * gnome_desktop_item_get_file_status:
+ * @item: A desktop item
+ *
+ * This function checks the modification time of the on-disk file to
+ * see if it is more recent than the in-memory data.
+ *
+ * Returns: An enum value that specifies whether the item has changed since being loaded.
+ */
+GnomeDesktopItemStatus
+gnome_desktop_item_get_file_status (GnomeDesktopItem *item)
+{
+        struct stat sbuf;
+        GnomeDesktopItemStatus retval;
+
+        g_return_val_if_fail(item, GNOME_DESKTOP_ITEM_DISAPPEARED);
+        g_return_val_if_fail(item->location, GNOME_DESKTOP_ITEM_DISAPPEARED);
+
+        if(stat(item->location, &sbuf) != 0)
+                return GNOME_DESKTOP_ITEM_DISAPPEARED;
+
+        retval = (sbuf.st_mtime > item->mtime)?GNOME_DESKTOP_ITEM_CHANGED:GNOME_DESKTOP_ITEM_UNCHANGED;
+
+        item->mtime = sbuf.st_mtime;
+
+        return retval;
+}
+
+/**
+ * gnome_desktop_item_get_location:
+ * @item: A desktop item
+ *
+ * Returns: The file location associated with 'item'. The returned
+ *          memory remains owned by the GnomeDesktopItem and should
+ *          not be freed.
+ *
+ */
+const char *
+gnome_desktop_item_get_location (const GnomeDesktopItem *item)
+{
+        return item->location;
+}
+
+/******* Set... ******/
+
+/**
+ * gnome_desktop_item_clear_name:
+ * @item: A desktop item
+ *
+ * Clear the name field for this item for all the languages.
+ *
+ * Returns:
+ */
+void
+gnome_desktop_item_clear_name(GnomeDesktopItem *item)
+{
+        if(item->name) {
+                g_hash_table_foreach_remove(item->name,
+					    ditem_free_key_value, NULL);
+                g_hash_table_destroy(item->name);
+		item->name = NULL;
+        }
+}
+
+/**
+ * gnome_desktop_item_set_name:
+ * @item: A desktop item
+ * @language: The language for which to set the item name
+ * @name: The item's name in the specified 'language'
+ *
+ * Set the name for language 'language' to 'name'.  If 'language' is
+ * NULL it defaults to "C".  If 'name' is NULL it removes the name
+ * for that language.
+ *
+ * Returns:
+ */
+void
+gnome_desktop_item_set_name (GnomeDesktopItem *item, const char *language, const char *name)
+{
+        gpointer old_val = NULL, old_key = NULL;
+
+        g_return_if_fail(item);
+
+	if(!language) language = "C";
+
+	if(!name) {
+		if(!item->name ||
+		   !g_hash_table_lookup_extended(item->name,
+						 language,
+						 &old_key, &old_val))
+			return;
+		g_hash_table_remove(item->name, old_key);
+		g_free(old_key);
+		g_free(old_val);
+		return;
+	}
+
+        if(!item->name)
+                item->name = g_hash_table_new(g_str_hash,
+					      g_str_equal);
+
+	if(g_hash_table_lookup_extended(item->name, language,
+					&old_key, &old_val)) {
+		g_hash_table_insert(item->name,
+				    old_key, g_strdup(name));
+		g_free(old_val);
+        } else
+		g_hash_table_insert(item->name,
+				    g_strdup(language), g_strdup(name));
+}
+
+/**
+ * gnome_desktop_item_set_type:
+ * @item: A desktop item
+ * @type: A string with the type
+ *
+ * Sets the type attribute (the 'Type' field) of the item.  This should
+ * usually be 'Application' for an application, but it can be 'Directory'
+ * for a directory description.  There are other types available as well.
+ * The type usually indicates how the desktop item should be handeled and
+ * how the 'Exec' field should be handeled.
+ *
+ * Returns:
+ *
+ */
+void
+gnome_desktop_item_set_type (GnomeDesktopItem *item, const char *type)
+{
+        g_return_if_fail(item);
+
+        g_free(item->type);
+        if(type)
+                item->type = g_strdup(type);
+        else
+                item->type = NULL;
+}
+
+/**
+ * gnome_desktop_item_set_command:
+ * @item: A desktop item
+ * @command: A string with the command
+ *
+ * Sets the command attribute (the 'Exec' field) of the item.  
+ * The command should be a single string which can be parsed into
+ * a vector directly for execution.  Note that it is NOT a shell
+ * expression.  It is allowed to have escapes and quoting as per
+ * the standard quoting rules however.
+ *
+ * Returns:
+ *
+ */
+void
+gnome_desktop_item_set_command (GnomeDesktopItem *item, const char *command)
+{
+        g_return_if_fail(item);
+
+        g_free(item->exec);
+        if(command)
+                item->exec = g_strdup(command);
+        else
+                item->exec = NULL;
+}
+
+/**
+ * gnome_desktop_item_set_icon_path:
+ * @item: A desktop item
+ * @icon_path: A string specifying the path to the icon file for this item.
+ *
+ */
+void
+gnome_desktop_item_set_icon_path (GnomeDesktopItem *item, const char *icon_path)
+{
+        g_return_if_fail(item);
+
+        g_free(item->icon_path);
+        if(icon_path)
+                item->icon_path = g_strdup(icon_path);
+        else
+                item->icon_path = NULL;
+}
+
+/**
+ * gnome_desktop_item_clear_comment:
+ * @item: A desktop item
+ *
+ * Clear the comment field for this item for all the languages.
+ *
+ * Returns:
+ */
+void
+gnome_desktop_item_clear_comment(GnomeDesktopItem *item)
+{
+
+        if(item->comment) {
+                g_hash_table_foreach_remove(item->comment,
+					    ditem_free_key_value, NULL);
+                g_hash_table_destroy(item->comment);
+		item->comment = NULL;
+        }
+}
+
+/**
+ * gnome_desktop_item_set_comment:
+ * @item: A desktop item
+ * @language: The language for which to set the item comment
+ * @comment: The item's comment in the specified 'language'
+ *
+ * Set the comment for language 'language' to 'comment'.  If 'language' is
+ * NULL it defaults to "C".  If 'comment' is NULL it removes the comment
+ * for that language.
+ *
+ * Returns:
+ */
+void
+gnome_desktop_item_set_comment (GnomeDesktopItem *item, const char *language, const char *comment)
+{
+        gpointer old_val = NULL, old_key = NULL;
+
+        g_return_if_fail(item);
+
+	if(!language) language = "C";
+
+	if(!comment) {
+		if(!item->comment ||
+		   !g_hash_table_lookup_extended(item->comment,
+						 language,
+						 &old_key, &old_val))
+			return;
+		g_hash_table_remove(item->comment, old_key);
+		g_free(old_key);
+		g_free(old_val);
+		return;
+	}
+
+        if(!item->comment)
+                item->comment = g_hash_table_new(g_str_hash,
+						 g_str_equal);
+
+        if(g_hash_table_lookup_extended(item->comment, language,
+					&old_key, &old_val)) {
+		g_hash_table_insert(item->comment,
+				    old_key, g_strdup(comment));
+		g_free(old_val);
+        } else
+		g_hash_table_insert(item->comment,
+				    g_strdup(language), g_strdup(comment));
+}
+
+/**
+ * gnome_desktop_item_set_attribute:
+ * @item: A desktop item
+ * @attr_name: The name of the attribute
+ * @attr_value: The value of the attribute
+ *
+ * Set an attribute of name 'attr_name' to 'attr_value'.  If attr_value
+ * is NULL it removes the attribute completely.
+ *
+ */
+void
+gnome_desktop_item_set_attribute (GnomeDesktopItem *item,
+				  const char *attr_name,
+				  const char *attr_value)
+{
+        gpointer old_val = NULL, old_key = NULL;
+
+        g_return_if_fail(item);
+        g_return_if_fail(attr_name);
+
+	if(!attr_value) {
+		if(!item->other_attributes ||
+		   !g_hash_table_lookup_extended(item->other_attributes,
+						 attr_name,
+						 &old_key, &old_val))
+			return;
+		g_hash_table_remove(item->other_attributes, old_key);
+		g_free(old_key);
+		g_free(old_val);
+		return;
+	}
+
+        if(!item->other_attributes)
+                item->other_attributes = g_hash_table_new(g_str_hash,
+							  g_str_equal);
+
+        if(g_hash_table_lookup_extended(item->other_attributes, attr_name,
+					&old_key, &old_val)) {
+		g_hash_table_insert(item->other_attributes,
+				    old_key, g_strdup(attr_value));
+		g_free(old_val);
+        } else
+		g_hash_table_insert(item->other_attributes,
+				    g_strdup(attr_name), g_strdup(attr_value));
+}
+
+/**
+ * gnome_desktop_item_set_order:
+ * @item: A desktop item for a directory
+ * @order: A GSList strings of the basenames of the files in this order
+ *
+ * This function sets the list of strings 'order' as the order of this item
+ * which is assumed is a directory item.  It makes a local copy of the
+ * 'order' list and the strings within it.
+ *
+ * Returns:
+ */
+void
+gnome_desktop_item_set_order (GnomeDesktopItem *item, GSList *order)
+{
+	GSList *li;
+
+        g_return_if_fail(item);
+        g_return_if_fail(item->item_flags & GNOME_DESKTOP_ITEM_IS_DIRECTORY);
+
+        g_slist_foreach(item->order, (GFunc)g_free, NULL);
+        g_slist_free(item->order);
+
+	/* copy the items */
+        item->order = g_slist_copy(order);
+	for(li = item->order; li; li = li->next)
+		li->data = g_strdup(li->data);
+}
+
+/**
+ * gnome_desktop_item_set_flags:
+ * @item: A desktop item
+ * @flags: The flags to be set
+ *
+ * Sets the flags of 'item' to 'flags'
+ *
+ * Returns:
+ */
+void
+gnome_desktop_item_set_flags (GnomeDesktopItem *item, GnomeDesktopItemFlags flags)
+{
+        g_return_if_fail(item);
+
+        item->item_flags = flags;
+}
+
+/**
+ * gnome_desktop_item_set_format:
+ * @item: A desktop item
+ * @fmt: The format to be set
+ */
+void
+gnome_desktop_item_set_format (GnomeDesktopItem *item, GnomeDesktopItemFormat fmt)
+{
+        g_return_if_fail(item);
+
+	/* correctly convert from kde to gnome if the type is
+	   KonsoleApplication */
+	if(fmt == GNOME_DESKTOP_ITEM_GNOME &&
+	   item->item_format == GNOME_DESKTOP_ITEM_KDE &&
+	   item->type &&
+	   strcmp(item->type,"KonsoleApplication")==0) {
+		g_free(item->type);
+		item->type = g_strdup("Application");
+		item->item_flags |= GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL;
+	}
+
+        item->item_format = fmt;
+
+}
+
+/**
+ * gnome_desktop_item_set_location:
+ * @item: A desktop item
+ * @location: A string specifying the file location of this particular item.
+ *
+ * Set's the 'location' of this item.  It should be a full path to the item.
+ *
+ * Returns:
+ */
+void
+gnome_desktop_item_set_location (GnomeDesktopItem *item, const char *location)
+{
+        g_free(item->location);
+        item->location = g_strdup(location);
+}
diff --git a/libgnome/gnome-ditem.h b/libgnome/gnome-ditem.h
new file mode 100644
index 0000000..83996f2
--- /dev/null
+++ b/libgnome/gnome-ditem.h
@@ -0,0 +1,155 @@
+/* -*- Mode: C; c-set-style: linux indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gnome-ditem.h - GNOME Desktop File Representation 
+
+   Copyright (C) 1999, 2000 Red Hat Inc.
+   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_DITEM_H
+#define GNOME_DITEM_H
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_DECLS
+
+typedef enum {
+	/* Start a terminal to run this */
+        GNOME_DESKTOP_ITEM_RUN_IN_TERMINAL = 1<<0,
+	/* Directory type */
+        GNOME_DESKTOP_ITEM_IS_DIRECTORY = 1<<1,
+	/* drop by appending arguments after Exec */
+        GNOME_DESKTOP_ITEM_OLD_STYLE_DROP = 1<<2,
+	/* never drop files (always off for OLD_STYLE_DROP items) */
+ 	GNOME_DESKTOP_ITEM_NO_FILE_DROP = 1<<3,
+	/* never drop urls (always off for OLD_STYLE_DROP items) */
+        GNOME_DESKTOP_ITEM_NO_URL_DROP = 1<<4,
+	/* if multiple files are dropped start multiple instances */
+        GNOME_DESKTOP_ITEM_SINGLE_FILE_DROP_ONLY = 1<<5,
+	/* if multiple urls are dropped start multiple instances */
+        GNOME_DESKTOP_ITEM_SINGLE_URL_DROP_ONLY = 1<<6
+} GnomeDesktopItemFlags;
+
+typedef enum {
+        GNOME_DESKTOP_ITEM_UNKNOWN=0,
+        GNOME_DESKTOP_ITEM_GNOME=1,
+        GNOME_DESKTOP_ITEM_KDE=2
+        /* More types can be added here as needed */
+} GnomeDesktopItemFormat;
+
+typedef enum {
+        GNOME_DESKTOP_ITEM_UNCHANGED = 0,
+        GNOME_DESKTOP_ITEM_CHANGED = 1,
+        GNOME_DESKTOP_ITEM_DISAPPEARED = 2
+} GnomeDesktopItemStatus;
+
+typedef struct _GnomeDesktopItem GnomeDesktopItem;
+
+typedef enum {
+        GNOME_DESKTOP_ITEM_LOAD_ONLY_IF_EXISTS = 1<<0,
+        GNOME_DESKTOP_ITEM_LOAD_NO_SYNC = 1<<1,
+        GNOME_DESKTOP_ITEM_LOAD_NO_OTHER_SECTIONS = 1<<2 /* don't try to load
+							    other sections */
+} GnomeDesktopItemLoadFlags;
+
+/* Returned item from new*() and copy() methods have a refcount of 1 */
+GnomeDesktopItem *     gnome_desktop_item_new             (void);
+GnomeDesktopItem *     gnome_desktop_item_new_from_file   (const char                 *file,
+                                                           GnomeDesktopItemLoadFlags   flags);
+GnomeDesktopItem *     gnome_desktop_item_copy            (const GnomeDesktopItem     *item);
+
+/* if under is NULL save in original location */
+gboolean               gnome_desktop_item_save            (GnomeDesktopItem           *item,
+                                                           const char                 *under);
+void                   gnome_desktop_item_ref             (GnomeDesktopItem           *item);
+void                   gnome_desktop_item_unref           (GnomeDesktopItem           *item);
+int                    gnome_desktop_item_launch          (const GnomeDesktopItem     *item,
+                                                           int                         argc,
+                                                           const char                **argv);
+
+/* A list of files or urls dropped onto an icon, the proper (Url or File
+   exec is run you can pass directly the output of 
+   gnome_uri_list_extract_filenames */
+int                    gnome_desktop_item_drop_uri_list   (const GnomeDesktopItem     *item,
+							   GList                      *uri_list);
+
+gboolean               gnome_desktop_item_exists          (const GnomeDesktopItem     *item);
+GnomeDesktopItemFlags  gnome_desktop_item_get_flags       (const GnomeDesktopItem     *item);
+const char *           gnome_desktop_item_get_location    (const GnomeDesktopItem     *item);
+const char *           gnome_desktop_item_get_type        (const GnomeDesktopItem     *item);
+const char *           gnome_desktop_item_get_command     (const GnomeDesktopItem     *item);
+const char *           gnome_desktop_item_get_icon_path   (const GnomeDesktopItem     *item);
+
+/* Note: you want to search each language in the user's search path */
+const char *           gnome_desktop_item_get_name        (const GnomeDesktopItem     *item,
+                                                           const char                 *language);
+const char *           gnome_desktop_item_get_comment     (const GnomeDesktopItem     *item,
+                                                           const char                 *language);
+
+const char *           gnome_desktop_item_get_local_name   (const GnomeDesktopItem     *item);
+const char *           gnome_desktop_item_get_local_comment(const GnomeDesktopItem     *item);
+
+const char *           gnome_desktop_item_get_attribute   (const GnomeDesktopItem     *item,
+                                                           const char                 *attr_name);
+/* get a translated version of the attribute */
+const char *           gnome_desktop_item_get_local_attribute (const GnomeDesktopItem *item,
+							       const char *attr_name);
+const GSList *         gnome_desktop_item_get_order    (const GnomeDesktopItem     *item);
+GnomeDesktopItemFormat gnome_desktop_item_get_format      (const GnomeDesktopItem     *item);
+GnomeDesktopItemStatus gnome_desktop_item_get_file_status (GnomeDesktopItem           *item);
+
+
+/* Free the return value but not the contained strings */
+GSList *               gnome_desktop_item_get_languages   (const GnomeDesktopItem     *item);
+GSList *               gnome_desktop_item_get_attributes  (const GnomeDesktopItem     *item);
+void                   gnome_desktop_item_set_format      (GnomeDesktopItem           *item,
+                                                           GnomeDesktopItemFormat      fmt);
+/* the _clear_name clears the name for all languages */
+void                   gnome_desktop_item_clear_name      (GnomeDesktopItem           *item);
+void                   gnome_desktop_item_set_name        (GnomeDesktopItem           *item,
+                                                           const char                 *language,
+                                                           const char                 *name);
+void                   gnome_desktop_item_set_type        (GnomeDesktopItem           *item,
+                                                           const char                 *type);
+void                   gnome_desktop_item_set_command     (GnomeDesktopItem           *item,
+                                                           const char                 *command);
+void                   gnome_desktop_item_set_icon_path   (GnomeDesktopItem           *item,
+                                                           const char                 *icon_path);
+/* the _clear_comment clears the comment for all languages */
+void                   gnome_desktop_item_clear_comment   (GnomeDesktopItem           *item);
+void                   gnome_desktop_item_set_comment     (GnomeDesktopItem           *item,
+                                                           const char                 *language,
+                                                           const char                 *comment);
+void                   gnome_desktop_item_set_attribute   (GnomeDesktopItem           *item,
+                                                           const char                 *attr_name,
+                                                           const char                 *attr_value);
+void                   gnome_desktop_item_set_order       (GnomeDesktopItem           *item,
+                                                           GSList                     *order);
+void                   gnome_desktop_item_set_flags       (GnomeDesktopItem           *item,
+                                                           GnomeDesktopItemFlags       flags);
+void                   gnome_desktop_item_set_location    (GnomeDesktopItem           *item,
+                                                           const char                 *location);
+
+
+END_GNOME_DECLS
+
+#endif /* GNOME_DITEM_H */
diff --git a/libgnome/gnome-exec.c b/libgnome/gnome-exec.c
new file mode 100644
index 0000000..111788d
--- /dev/null
+++ b/libgnome/gnome-exec.c
@@ -0,0 +1,490 @@
+/* gnome-exec.c - Execute some command.
+
+   Copyright (C) 1998 Tom Tromey
+   All rights reserved.
+
+   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@
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "gnome-defs.h"
+#include "gnome-exec.h"
+#include "gnome-portability.h"
+#include "gnome-util.h"
+#include "gnome-config.h"
+#include "gnome-i18nP.h"
+#include <glib.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+#include <errno.h>
+#ifndef errno
+extern int errno;
+#endif
+
+static void
+set_cloexec (gint fd)
+{
+  fcntl (fd, F_SETFD, FD_CLOEXEC);
+}
+
+/**
+ * gnome_execute_async_with_env_fds:
+ * @dir: Directory in which child should be execd, or NULL for current
+ *       directory
+ * @argc: Number of arguments
+ * @argv: Argument vector to exec child
+ * @envc: Number of environment slots
+ * @envv: Environment vector
+ * @close_fds: If TRUE will close all fds but 0,1, and 2
+ * 
+ * Description:  Like #gnome_execute_async_with_env() but has a flag to
+ * decide whether or not to close fd's
+ * 
+ * Returns: the process id, or %-1 on error.
+ **/
+int
+gnome_execute_async_with_env_fds (const char *dir, int argc, 
+				  char * const argv[], int envc, 
+				  char * const envv[], 
+				  gboolean close_fds)
+{
+  int parent_comm_pipes[2], child_comm_pipes[2];
+  int child_errno, itmp, i, open_max;
+  int res;
+  char **cpargv;
+  pid_t child_pid, immediate_child_pid; /* XXX this routine assumes
+					   pid_t is signed */
+
+  if(pipe(parent_comm_pipes))
+    return -1;
+
+  child_pid = immediate_child_pid = fork();
+
+  switch(child_pid) {
+  case -1:
+    close(parent_comm_pipes[0]);
+    close(parent_comm_pipes[1]);
+    return -1;
+
+  case 0: /* START PROCESS 1: child */
+    child_pid = -1;
+    res = pipe(child_comm_pipes);
+    close(parent_comm_pipes[0]);
+    if(!res)
+      child_pid = fork();
+
+    switch(child_pid) {
+    case -1:
+      itmp = errno;
+      child_pid = -1; /* simplify parent code */
+      write(parent_comm_pipes[1], &child_pid, sizeof(child_pid));
+      write(parent_comm_pipes[1], &itmp, sizeof(itmp));
+      close(child_comm_pipes[0]);
+      close(child_comm_pipes[1]);
+      _exit(0); break;      /* END PROCESS 1: monkey in the middle dies */
+
+    default:
+      {
+	char buf[16];
+	
+	close(child_comm_pipes[1]);
+	while((res = read(child_comm_pipes[0], buf, sizeof(buf))) > 0)
+	  write(parent_comm_pipes[1], buf, res);
+	close(child_comm_pipes[0]);
+	_exit(0); /* END PROCESS 1: monkey in the middle dies */
+      }
+      break;
+
+    case 0:                 /* START PROCESS 2: child of child */
+      close(parent_comm_pipes[1]);
+      /* pre-exec setup */
+      close (child_comm_pipes[0]);
+      set_cloexec (child_comm_pipes[1]);
+      child_pid = getpid();
+      res = write(child_comm_pipes[1], &child_pid, sizeof(child_pid));
+
+      if(envv) {
+	for(itmp = 0; itmp < envc; itmp++)
+	  putenv(envv[itmp]);
+      }
+
+      if(dir) chdir(dir);
+
+      cpargv = alloca((argc + 1) * sizeof(char *));
+      memcpy(cpargv, argv, argc * sizeof(char *));
+      cpargv[argc] = NULL;
+
+      if(close_fds)
+	{
+	  int stdinfd;
+	  /* Close all file descriptors but stdin stdout and stderr */
+	  open_max = sysconf (_SC_OPEN_MAX);
+	  for (i = 3; i < open_max; i++)
+	    set_cloexec (i);
+
+	  if(child_comm_pipes[1] != 0) {
+	    close(0);
+	    /* Open stdin as being nothingness, so that if someone tries to
+	       read from this they don't hang up the whole GNOME session. BUGFIX #1548 */
+	    stdinfd = open("/dev/null", O_RDONLY);
+	    g_assert(stdinfd >= 0);
+	    if(stdinfd != 0)
+	      {
+		dup2(stdinfd, 0);
+		close(stdinfd);
+	      }
+	  }
+	}
+      setsid ();
+      signal (SIGPIPE, SIG_DFL);
+      /* doit */
+      execvp(cpargv[0], cpargv);
+
+      /* failed */
+      itmp = errno;
+      write(child_comm_pipes[1], &itmp, sizeof(itmp));
+      _exit(1); break;      /* END PROCESS 2 */
+    }
+    break;
+
+  default: /* parent process */
+    /* do nothing */
+    break;
+  }
+
+  close(parent_comm_pipes[1]);
+
+  res = read (parent_comm_pipes[0], &child_pid, sizeof(child_pid));
+  if (res != sizeof(child_pid))
+    {
+      g_message("res is %d instead of %d", res, (int)sizeof(child_pid));
+      child_pid = -1; /* really weird things happened */
+    }
+  else if (read (parent_comm_pipes[0], &child_errno, sizeof(child_errno))
+	  == sizeof(child_errno))
+    {
+      errno = child_errno;
+      child_pid = -1;
+    }
+
+  /* do this after the read's in case some OS's handle blocking on pipe writes
+     differently */
+  waitpid(immediate_child_pid, &itmp, 0); /* eat zombies */
+
+  close(parent_comm_pipes[0]);
+
+  if(child_pid < 0)
+    g_message("gnome_execute_async_with_env_fds: returning %d", child_pid);
+
+  return child_pid;
+}
+
+/**
+ * gnome_execute_async_with_env:
+ * @dir: Directory in which child should be execd, or NULL for current
+ *       directory
+ * @argc: Number of arguments
+ * @argv: Argument vector to exec child
+ * @envc: Number of environment slots
+ * @envv: Environment vector
+ * 
+ * Description: This function forks and executes some program in the
+ * background.  On error, returns %-1; in this case, errno should hold a useful
+ * value.  Searches the path to find the child.  Environment settings in @envv
+ * are added to the existing environment -- they do not completely replace it.
+ * This function closes all fds besides 0, 1, and 2 for the child
+ * 
+ * Returns: the process id, or %-1 on error.
+ **/
+int
+gnome_execute_async_with_env (const char *dir, int argc, char * const argv[], 
+			      int envc, char * const envv[])
+{
+  return gnome_execute_async_with_env_fds (dir, argc, argv, envc, envv, TRUE);
+}
+
+
+/**
+ * gnome_execute_async:
+ * @dir: Directory in which child should be execd, or NULL for current
+ *       directory
+ * @argc: Number of arguments
+ * @argv: Argument vector to exec child
+ * 
+ * Description: Like gnome_execute_async_with_env(), but doesn't add anything
+ * to child's environment.
+ * 
+ * Returns: process id of child, or %-1 on error.
+ **/
+int
+gnome_execute_async (const char *dir, int argc, char * const argv[])
+{
+  return gnome_execute_async_with_env (dir, argc, argv, 0, NULL);
+}
+
+/**
+ * gnome_execute_async_fds:
+ * @dir: Directory in which child should be execd, or NULL for current
+ *       directory
+ * @argc: Number of arguments
+ * @argv: Argument vector to exec child
+ * @close_fds: 
+ *
+ * Description: Like #gnome_execute_async_with_env_fds, but doesn't add
+ * anything to child's environment.
+ * 
+ * Returns: process id of child, or %-1 on error.
+ **/
+int
+gnome_execute_async_fds (const char *dir, int argc, 
+			 char * const argv[], gboolean close_fds)
+{
+  return gnome_execute_async_with_env_fds (dir, argc, argv, 0, NULL, 
+					   close_fds);
+}
+
+/**
+ * gnome_execute_shell_fds:
+ * @dir: Directory in which child should be execd, or NULL for current
+ *       directory
+ * @commandline: Shell command to execute
+ * @close_fds: Like close_fds in gnome_execute_async_with_env_fds()
+ *
+ * Description: Like #gnome_execute_async_with_env_fds, but uses the user's
+ * shell to run the desired program.  Note that the pid of the shell is
+ * returned, not the pid of the user's program.
+ * 
+ * Returns: process id of shell, or %-1 on error.
+ **/
+int
+gnome_execute_shell_fds (const char *dir, const char *commandline,
+			 gboolean close_fds)
+{
+  char *user_shell;
+  char * argv[4];
+  int r;
+
+  g_return_val_if_fail(commandline != NULL, -1);
+
+  user_shell = gnome_util_user_shell ();
+
+  argv[0] = user_shell;
+  argv[1] = "-c";
+  /* neccessary cast, to avoid warning, but safe */
+  argv[2] = (char *)commandline;
+  argv[3] = NULL;
+
+  r = gnome_execute_async_with_env_fds (dir, 4, argv, 0, NULL, close_fds);
+
+  g_free (user_shell);
+  return r;
+}
+
+/**
+ * gnome_execute_shell:
+ * @dir: Directory in which child should be execd, or NULL for current
+ *       directory
+ * @commandline: Shell command to execute
+ * 
+ * Description: Like #gnome_execute_async_with_env, but uses the user's shell
+ * to run the desired program.  Note that the pid of the shell is returned, not
+ * the pid of the user's program.
+ * 
+ * Returns: process id of shell, or %-1 on error.
+ **/
+int
+gnome_execute_shell (const char *dir, const char *commandline)
+{
+  return gnome_execute_shell_fds(dir, commandline, TRUE);
+}
+
+/**
+ * gnome_prepend_terminal_to_vector:
+ * @argc: a pointer to the vector size
+ * @argv: a pointer to the vector
+ *
+ * Description:  Prepends the selected terminal to the
+ * passed in vector, modifying it in the process.  The vector should
+ * be allocated with g_malloc, as this will g_free the original vector.
+ * Also all elements must have been allocated separately.  That is the
+ * standard glib/gnome way of doing vectors however.  If the integer
+ * that @argc points to is negative, the size will first be computed.
+ * Also note that passing in pointers to a vector that is empty, will
+ * just create a new vector for you.
+ **/
+void
+gnome_prepend_terminal_to_vector (int *argc, char ***argv)
+{
+        char **real_argv;
+        int real_argc;
+        int i, j;
+	char **term_argv = NULL;
+	int term_argc = 0;
+
+	char **the_argv;
+
+        g_return_if_fail (argc != NULL);
+        g_return_if_fail (argv != NULL);
+
+	/* sanity */
+        if(*argv == NULL)
+                *argc = 0;
+
+	the_argv = *argv;
+
+	/* compute size if not given */
+	if (*argc < 0) {
+		for (i = 0; the_argv[i] != NULL; i++)
+			;
+		*argc = i;
+	}
+
+	gnome_config_get_vector ("/Gnome/Applications/Terminal",
+				 &term_argc, &term_argv);
+	if (term_argv == NULL) {
+		char *check;
+
+		term_argc = 2;
+		term_argv = g_new0 (char *, 3);
+
+		check = gnome_is_program_in_path("gnome-terminal");
+		if (check != NULL) {
+			term_argv[0] = check;
+			/* Note that gnome-terminal takes -x and
+			 * as -e in gnome-terminal is broken */
+			term_argv[1] = g_strdup ("-x");
+		} else {
+			if (check == NULL)
+				check = gnome_is_program_in_path("nxterm");
+			if (check == NULL)
+				check = gnome_is_program_in_path("color-xterm");
+			if (check == NULL)
+				check = gnome_is_program_in_path("rxvt");
+			if (check == NULL)
+				check = gnome_is_program_in_path("xterm");
+			if (check == NULL)
+				check = gnome_is_program_in_path("dtterm");
+			if (check == NULL) {
+				g_warning (_("Cannot find a terminal, using "
+					     "xterm, even if it may not work"));
+				check = g_strdup ("xterm");
+			}
+			term_argv[0] = check;
+			term_argv[1] = g_strdup ("-e");
+		}
+	}
+
+        real_argc = term_argc + *argc;
+        real_argv = g_new (char *, real_argc + 1);
+
+        for (i = 0; i < term_argc; i++)
+                real_argv[i] = term_argv[i];
+
+        for (j = 0; j < *argc; j++, i++)
+                real_argv[i] = (char *)the_argv[j];
+
+	real_argv[i] = NULL;
+
+	g_free (*argv);
+	*argv = real_argv;
+	*argc = real_argc;
+
+	/* we use g_free here as we sucked all the inner strings
+	 * out from it into real_argv */
+	g_free (term_argv);
+}
+
+/**
+ * gnome_execute_terminal_shell_fds:
+ * @dir: Directory in which child should be execd, or NULL for current
+ *       directory
+ * @commandline: Shell command to execute
+ * @close_fds: Like close_fds in gnome_execute_async_with_env_fds()
+ *
+ * Description:  Like #gnome_execute_shell_fds, except that it runs the
+ * terminal as well.  Note that the pid of the terminal is
+ * returned, not the pid of the user's program.
+ * If commandline is %NULL, just the shell is run.
+ * 
+ * Returns: process id of terminal, or %-1 on error.
+ **/
+int
+gnome_execute_terminal_shell_fds (const char *dir, const char *commandline,
+				  gboolean close_fds)
+{
+	char ** argv;
+	int argc;
+	int r;
+
+	argv = g_new (char *, 4);
+
+	argv[0] = gnome_util_user_shell ();
+	if (commandline != NULL) {
+		argc = 3;
+		argv[1] = g_strdup ("-c");
+		argv[2] = g_strdup (commandline);
+		argv[3] = NULL;
+	} else {
+		/* FIXME: really this should more be a 
+		 * --login terminal, but the user preference includes
+		 * the -e, -x or whatever flag which makes this impossible,
+		 * change the preference in 2.0 to be two keys, and one
+		 * of them for a login terminal */
+		argc = 1;
+		argv[1] = NULL;
+	}
+
+	gnome_prepend_terminal_to_vector (&argc, &argv);
+
+	r = gnome_execute_async_with_env_fds (dir, argc, argv, 0, NULL,
+					      close_fds);
+
+	g_strfreev (argv);
+
+	return r;
+}
+
+/**
+ * gnome_execute_terminal_shell:
+ * @dir: Directory in which child should be execd, or NULL for current
+ *       directory
+ * @commandline: Shell command to execute
+ * 
+ * Description:  Like #gnome_execute_async, except that it runs the
+ * terminal as well.  Note that the pid of the terminal is
+ * returned, not the pid of the user's program.
+ * If commandline is %NULL, just the shell is run.
+ * 
+ * Returns: process id of terminal, or %-1 on error.
+ **/
+int
+gnome_execute_terminal_shell (const char *dir, const char *commandline)
+{
+	return gnome_execute_terminal_shell_fds (dir, commandline, TRUE);
+}
diff --git a/libgnome/gnome-exec.h b/libgnome/gnome-exec.h
new file mode 100644
index 0000000..1a9efb4
--- /dev/null
+++ b/libgnome/gnome-exec.h
@@ -0,0 +1,79 @@
+/* gnome-exec.h - Execute some command.
+
+   Copyright (C) 1998 Tom Tromey
+   Copyright (C) 1999, 2000 Red Hat, Inc.
+   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_EXEC_H
+#define GNOME_EXEC_H
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_DECLS
+
+
+/* Fork and execute some program in the background.  Returns -1 on
+   error.  Returns PID on success.  Should correctly report errno
+   returns from a failing child invocation.  DIR is the directory in
+   which to exec the child; if NULL the current directory is used.
+   Searches $PATH to find the child.  */
+int gnome_execute_async (const char *dir, int argc, char * const argv[]);
+int gnome_execute_async_fds (const char *dir, int argc, char * const argv[], 
+			     gboolean close_fds);
+
+
+/* Like gnome_execute_async, but each string in ENVV is added to the
+   child's environment.  If you want to set the environment exactly,
+   you must set the global `environ' variable instead.  If ENVV is
+   NULL, the child inherits the parent's environment.  In this case,
+   the value of ENVC is ignored.  */
+int gnome_execute_async_with_env (const char *dir,
+				  int argc, char * const argv[],
+				  int envc, char * const envv[]);
+int gnome_execute_async_with_env_fds (const char *dir, int argc, 
+				      char * const argv[], int envc, 
+				      char * const envv[], gboolean close_fds);
+
+
+
+/* Fork and execute commandline using the user's shell. Calls 
+   gnome_execute_async so it does the same things and returns 
+   the same things. */
+int gnome_execute_shell (const char *dir, const char *commandline);
+int gnome_execute_shell_fds (const char *dir, const char *commandline,
+			     gboolean close_fds);
+
+/* prepend the terminal command to a vector */
+void gnome_prepend_terminal_to_vector (int *argc, char ***argv);
+
+/* run a shell in the terminal, here commandline can be NULL
+ * for just a shell, unlike in gnome_execute_shell */
+int gnome_execute_terminal_shell (const char *dir, const char *commandline);
+int gnome_execute_terminal_shell_fds (const char *dir,
+				      const char *commandline,
+				      gboolean close_fds);
+
+END_GNOME_DECLS
+
+#endif /* GNOME_EXEC_H */
diff --git a/libgnome/gnome-file-selector.c b/libgnome/gnome-file-selector.c
new file mode 100644
index 0000000..8fa0607
--- /dev/null
+++ b/libgnome/gnome-file-selector.c
@@ -0,0 +1,1022 @@
+/* -*- Mode: C; c-set-style: gnu indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2000 SuSE GmbH
+ * Author: Martin Baulig <baulig suse de>
+ *
+ * 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@
+ */
+
+/* GnomeFileSelector widget - a file selector widget.
+ *
+ * Author: Martin Baulig <baulig suse de>
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <gtk/gtkfilesel.h>
+#include <gtk/gtklist.h>
+#include <gtk/gtklistitem.h>
+#include <gtk/gtksignal.h>
+#include "gnome-macros.h"
+#include "gnome-i18nP.h"
+#include "gnome-file-selector.h"
+#include "gnome-selectorP.h"
+#include "gnome-entry.h"
+
+#include <libgnomevfs/gnome-vfs.h>
+
+#undef DEBUG_ASYNC_STUFF
+
+typedef struct _GnomeFileSelectorAsyncData      GnomeFileSelectorAsyncData;
+typedef struct _GnomeFileSelectorSubAsyncData   GnomeFileSelectorSubAsyncData;
+
+struct _GnomeFileSelectorAsyncData {
+    GnomeSelectorAsyncHandle *async_handle;
+
+    GnomeSelectorAsyncType type;
+    GnomeFileSelector *fselector;
+
+    GSList *async_ops;
+    gboolean completed;
+
+    GnomeVFSAsyncHandle *vfs_handle;
+    GnomeVFSURI *uri;
+    GSList *uri_list;
+    gint position;
+    guint list_id;
+};
+
+struct _GnomeFileSelectorSubAsyncData {
+    GnomeSelectorAsyncHandle *async_handle;
+
+    GnomeFileSelectorAsyncData *async_data;
+};
+
+struct _GnomeFileSelectorPrivate {
+    GnomeVFSDirectoryFilter *filter;
+    GnomeVFSFileInfoOptions file_info_options;
+
+    GtkWidget *browse_dialog;
+};
+
+
+static void gnome_file_selector_class_init  (GnomeFileSelectorClass *class);
+static void gnome_file_selector_init        (GnomeFileSelector      *fselector);
+static void gnome_file_selector_destroy     (GtkObject              *object);
+static void gnome_file_selector_finalize    (GObject                *object);
+
+static void      add_uri_handler                (GnomeSelector            *selector,
+                                                 const gchar              *uri,
+                                                 gint                      position,
+						 guint                     list_id,
+						 GnomeSelectorAsyncHandle *async_handle);
+
+static void      add_uri_list_handler           (GnomeSelector            *selector,
+						 GSList                   *list,
+						 gint                      position,
+						 guint                     list_id,
+						 GnomeSelectorAsyncHandle *async_handle);
+
+static void      add_directory_handler          (GnomeSelector            *selector,
+                                                 const gchar              *uri,
+                                                 gint                      position,
+						 guint                     list_id,
+						 GnomeSelectorAsyncHandle *async_handle);
+static void      check_filename_handler         (GnomeSelector            *selector,
+                                                 const gchar              *filename,
+						 GnomeSelectorAsyncHandle *async_handle);
+static void      check_directory_handler        (GnomeSelector            *selector,
+                                                 const gchar              *directory,
+						 GnomeSelectorAsyncHandle *async_handle);
+
+static void      activate_entry_handler         (GnomeSelector   *selector);
+
+static void      do_construct_handler           (GnomeSelector   *selector);
+
+
+static GObject*
+gnome_file_selector_constructor (GType                  type,
+				 guint                  n_construct_properties,
+				 GObjectConstructParam *construct_properties);
+
+
+/**
+ * gnome_file_selector_get_type
+ *
+ * Returns the type assigned to the GnomeFileSelector widget.
+ **/
+/* The following defines the get_type */
+GNOME_CLASS_BOILERPLATE (GnomeFileSelector, gnome_file_selector,
+			 GnomeEntry, gnome_entry)
+
+static void
+gnome_file_selector_class_init (GnomeFileSelectorClass *class)
+{
+    GnomeSelectorClass *selector_class;
+    GtkObjectClass *object_class;
+    GObjectClass *gobject_class;
+
+    selector_class = (GnomeSelectorClass *) class;
+    object_class = (GtkObjectClass *) class;
+    gobject_class = (GObjectClass *) class;
+
+    object_class->destroy = gnome_file_selector_destroy;
+    gobject_class->finalize = gnome_file_selector_finalize;
+
+    gobject_class->constructor = gnome_file_selector_constructor;
+
+    selector_class->add_uri = add_uri_handler;
+
+    selector_class->add_uri_list = add_uri_list_handler; 
+
+    selector_class->add_directory = add_directory_handler;
+
+    selector_class->activate_entry = activate_entry_handler;
+
+    selector_class->check_filename = check_filename_handler;
+    selector_class->check_directory = check_directory_handler;
+
+    selector_class->do_construct = do_construct_handler;
+}
+
+static void
+free_the_async_data (gpointer data)
+{
+    GnomeFileSelectorAsyncData *async_data = data;
+    GnomeFileSelector *fselector;
+
+    g_return_if_fail (async_data != NULL);
+    g_assert (GNOME_IS_FILE_SELECTOR (async_data->fselector));
+
+    fselector = async_data->fselector;
+
+    /* free the async data. */
+    gtk_object_unref (GTK_OBJECT (async_data->fselector));
+    _gnome_selector_deep_free_slist (async_data->uri_list);
+    if (async_data->uri)
+	gnome_vfs_uri_unref (async_data->uri);
+    g_free (async_data);
+}
+
+static void
+add_uri_async_done_cb (GnomeFileSelectorAsyncData *async_data)
+{
+    GnomeSelectorAsyncHandle *async_handle;
+    gchar *path;
+
+    g_return_if_fail (async_data != NULL);
+
+    /* When we finish our async reading, we set async_data->completed -
+     * but we need to wait until all our async operations are completed as
+     * well.
+     */
+
+#ifdef DEBUG_ASYNC_STUFF
+    g_message (G_STRLOC ": %p - %d - %p", async_data, async_data->completed,
+	       async_data->async_ops);
+#endif
+
+    if (!async_data->completed || async_data->async_ops != NULL)
+	return;
+
+    async_handle = async_data->async_handle;
+
+    path = gnome_vfs_uri_to_string (async_data->uri,
+				    GNOME_VFS_URI_HIDE_NONE);
+    GNOME_CALL_PARENT_HANDLER (GNOME_SELECTOR_CLASS, add_uri,
+			       (GNOME_SELECTOR (async_data->fselector), path,
+				async_data->position, async_data->list_id,
+				async_handle));
+
+#ifdef DEBUG_ASYNC_STUFF
+    g_message (G_STRLOC ": %p - async reading completed (%s).",
+	       async_data->fselector, path);
+#endif
+
+    g_free (path);
+
+    _gnome_selector_async_handle_remove (async_handle, async_data);
+}
+
+static void
+add_uri_async_add_cb (GnomeSelector *selector,
+		      GnomeSelectorAsyncHandle *async_handle,
+		      GnomeSelectorAsyncType async_type,
+		      const char *uri, GError *error,
+		      gboolean success, gpointer user_data)
+{
+    GnomeFileSelectorSubAsyncData *sub_async_data = user_data;
+    GnomeFileSelectorAsyncData *async_data;
+
+    g_return_if_fail (sub_async_data != NULL);
+    g_assert (sub_async_data->async_data != NULL);
+    async_data = sub_async_data->async_data;
+
+    /* This operation is completed, remove it from the list and call
+     * add_uri_async_done_cb() - this function will check whether
+     * this was the last one and the uri checking is done as well.
+     */
+
+    async_data->async_ops = g_slist_remove (async_data->async_ops,
+					    sub_async_data);
+
+#ifdef DEBUG_ASYNC_STUFF
+    g_message (G_STRLOC ": %p - %p - `%s'", async_data->async_ops,
+	       sub_async_data, uri);
+#endif
+
+    add_uri_async_done_cb (async_data);
+}
+
+
+static void
+add_uri_async_cb (GnomeVFSAsyncHandle *handle, GList *results,
+		  gpointer callback_data)
+{
+    GnomeFileSelectorAsyncData *async_data;
+    GnomeFileSelector *fselector;
+    GList *list;
+
+    g_return_if_fail (callback_data != NULL);
+
+    async_data = callback_data;
+    g_assert (async_data->vfs_handle == handle);
+    g_assert (GNOME_IS_FILE_SELECTOR (async_data->fselector));
+    g_assert (async_data->type == GNOME_SELECTOR_ASYNC_TYPE_ADD_URI);
+
+    fselector = GNOME_FILE_SELECTOR (async_data->fselector);
+
+    for (list = results; list; list = list->next) {
+	GnomeVFSGetFileInfoResult *file = list->data;
+	gchar *uri;
+
+	/* better assert this than risking a crash. */
+	g_assert (file != NULL);
+
+	uri = gnome_vfs_uri_to_string (file->uri, GNOME_VFS_URI_HIDE_NONE);
+
+	if (file->result != GNOME_VFS_OK) {
+	    g_message (G_STRLOC ": `%s': %s", uri,
+		       gnome_vfs_result_to_string (file->result));
+	    g_free (uri);
+	    continue;
+	}
+
+	if (file->file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
+	    GnomeFileSelectorSubAsyncData *sub_async_data;
+
+	    sub_async_data = g_new0 (GnomeFileSelectorSubAsyncData, 1);
+	    sub_async_data->async_data = async_data;
+
+	    async_data->async_ops = g_slist_prepend
+		(async_data->async_ops, sub_async_data);
+
+	    gnome_selector_add_directory (GNOME_SELECTOR (fselector),
+					  &sub_async_data->async_handle, uri,
+					  async_data->position,
+					  async_data->list_id,
+					  add_uri_async_add_cb,
+					  sub_async_data);
+
+	    g_free (uri);
+	    continue;
+	}
+
+	if (fselector->_priv->filter &&
+	    !gnome_vfs_directory_filter_apply (fselector->_priv->filter,
+					       file->file_info)) {
+
+	    g_message (G_STRLOC ": dropped by directory filter");
+
+	    g_free (uri);
+	    continue;
+	}
+
+	if (file->file_info->type == GNOME_VFS_FILE_TYPE_REGULAR) {
+	    GnomeFileSelectorSubAsyncData *sub_async_data;
+
+	    sub_async_data = g_new0 (GnomeFileSelectorSubAsyncData, 1);
+	    sub_async_data->async_data = async_data;
+
+	    async_data->async_ops = g_slist_prepend
+		(async_data->async_ops, sub_async_data);
+
+	    gnome_selector_add_file (GNOME_SELECTOR (fselector),
+				     &sub_async_data->async_handle, uri,
+				     async_data->position, async_data->list_id,
+				     add_uri_async_add_cb,
+				     sub_async_data);
+
+	    g_free (uri);
+	    continue;
+	}
+
+	g_free (uri);
+    }
+
+    /* Completed, but we may have async operations running. We set
+     * async_data->completed here to inform add_uri_async_done_cb()
+     * that we're done with our async operation.
+     */
+    async_data->completed = TRUE;
+    add_uri_async_done_cb (async_data);
+}
+
+void
+add_uri_handler (GnomeSelector *selector, const gchar *uri, gint position,
+		 guint list_id, GnomeSelectorAsyncHandle *async_handle)
+{
+    GnomeFileSelector *fselector;
+    GnomeFileSelectorAsyncData *async_data;
+    GList fake_list;
+
+    g_return_if_fail (selector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (selector));
+    g_return_if_fail (position >= -1);
+    g_return_if_fail (uri != NULL);
+    g_return_if_fail (async_handle != NULL);
+
+    fselector = GNOME_FILE_SELECTOR (selector);
+
+    async_data = g_new0 (GnomeFileSelectorAsyncData, 1);
+    async_data->async_handle = async_handle;
+    async_data->type = GNOME_SELECTOR_ASYNC_TYPE_ADD_URI;
+    async_data->fselector = fselector;
+    async_data->uri = gnome_vfs_uri_new (uri);
+    async_data->position = position;
+    async_data->list_id = list_id;
+
+    gnome_vfs_uri_ref (async_data->uri);
+    gtk_object_ref (GTK_OBJECT (async_data->fselector));
+
+    fake_list.data = async_data->uri;
+    fake_list.prev = NULL;
+    fake_list.next = NULL;
+
+    _gnome_selector_async_handle_add (async_handle, async_data,
+				      free_the_async_data);
+
+    gnome_vfs_async_get_file_info (&async_data->vfs_handle, &fake_list,
+				   fselector->_priv->file_info_options,
+				   add_uri_async_cb, async_data);
+
+    gnome_vfs_uri_unref (fake_list.data);
+}
+
+static void
+add_uri_list_async_done_cb (GnomeFileSelectorAsyncData *async_data)
+{
+    GnomeSelectorAsyncHandle *async_handle;
+
+    g_return_if_fail (async_data != NULL);
+
+    /* When we finish our directory reading, we set async_data->completed -
+     * but we need to wait until all our async operations are completed as
+     * well.
+     */
+
+    if (!async_data->completed || async_data->async_ops != NULL)
+	return;
+
+    async_handle = async_data->async_handle;
+
+    GNOME_CALL_PARENT_HANDLER (GNOME_SELECTOR_CLASS, add_uri_list,
+			       (GNOME_SELECTOR (async_data->fselector),
+				async_data->uri_list, async_data->position,
+				async_data->list_id, async_handle));
+
+    _gnome_selector_async_handle_remove (async_handle, async_data);
+}
+
+static void
+add_uri_list_async_cb (GnomeSelector *selector,
+		       GnomeSelectorAsyncHandle *async_handle,
+		       GnomeSelectorAsyncType async_type,
+		       const char *uri, GError *error,
+		       gboolean success, gpointer user_data)
+{
+    GnomeFileSelectorSubAsyncData *sub_async_data = user_data;
+    GnomeFileSelectorAsyncData *async_data;
+
+    g_return_if_fail (sub_async_data != NULL);
+    g_assert (sub_async_data->async_data != NULL);
+    async_data = sub_async_data->async_data;
+
+    /* This operation is completed, remove it from the list and call
+     * add_uri_list_async_done_cb() - this function will check whether
+     * this was the last one and the directory reading is done as well.
+     */
+
+    async_data->async_ops = g_slist_remove (async_data->async_ops,
+					    sub_async_data);
+
+    add_uri_list_async_done_cb (async_data);
+}
+
+static void
+add_uri_list_handler (GnomeSelector *selector, GSList *list,
+		      gint position, guint list_id,
+		      GnomeSelectorAsyncHandle *async_handle)
+{
+    GnomeFileSelectorAsyncData *async_data;
+    GnomeFileSelector *fselector;
+    GSList *c;
+
+    g_return_if_fail (selector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (selector));
+    g_return_if_fail (async_handle != NULL);
+
+    fselector = GNOME_FILE_SELECTOR (selector);
+
+    async_data = g_new0 (GnomeFileSelectorAsyncData, 1);
+    async_data->async_handle = async_handle;
+    async_data->type = GNOME_SELECTOR_ASYNC_TYPE_ADD_URI_LIST;
+    async_data->fselector = fselector;
+    async_data->position = position;
+    async_data->uri_list = _gnome_selector_deep_copy_slist (list);
+    async_data->list_id = list_id;
+
+    gtk_object_ref (GTK_OBJECT (async_data->fselector));
+
+    _gnome_selector_async_handle_add (async_handle, async_data,
+				      free_the_async_data);
+
+    for (c = list; c; c = c->next) {
+	GnomeFileSelectorSubAsyncData *sub_async_data;
+
+	sub_async_data = g_new0 (GnomeFileSelectorSubAsyncData, 1);
+	sub_async_data->async_data = async_data;
+
+	async_data->async_ops = g_slist_prepend
+	    (async_data->async_ops, sub_async_data);
+
+	gnome_selector_add_uri (GNOME_SELECTOR (fselector),
+				&sub_async_data->async_handle,
+				c->data, position, list_id,
+				add_uri_list_async_cb,
+				sub_async_data);
+    }
+
+    async_data->completed = TRUE;
+    add_uri_list_async_done_cb (async_data);
+}
+
+static void
+add_directory_async_done_cb (GnomeFileSelectorAsyncData *async_data)
+{
+    GnomeSelectorAsyncHandle *async_handle;
+    gchar *path;
+
+    g_return_if_fail (async_data != NULL);
+
+    /* When we finish our directory reading, we set async_data->completed -
+     * but we need to wait until all our async operations are completed as
+     * well.
+     */
+
+    if (!async_data->completed || async_data->async_ops != NULL)
+	return;
+
+    async_handle = async_data->async_handle;
+
+    path = gnome_vfs_uri_to_string (async_data->uri,
+				    GNOME_VFS_URI_HIDE_NONE);
+    GNOME_CALL_PARENT_HANDLER (GNOME_SELECTOR_CLASS, add_directory,
+			       (GNOME_SELECTOR (async_data->fselector), path,
+				async_data->position, async_data->list_id,
+				async_handle));
+
+    g_free (path);
+
+    _gnome_selector_async_handle_remove (async_handle, async_data);
+}
+
+static void
+add_directory_async_file_cb (GnomeSelector *selector,
+			     GnomeSelectorAsyncHandle *async_handle,
+			     GnomeSelectorAsyncType async_type,
+			     const char *uri, GError *error,
+			     gboolean success, gpointer user_data)
+{
+    GnomeFileSelectorSubAsyncData *sub_async_data = user_data;
+    GnomeFileSelectorAsyncData *async_data;
+
+    g_return_if_fail (sub_async_data != NULL);
+    g_assert (sub_async_data->async_data != NULL);
+    async_data = sub_async_data->async_data;
+
+    /* This operation is completed, remove it from the list and call
+     * add_directory_async_done_cb() - this function will check whether
+     * this was the last one and the directory reading is done as well.
+     */
+
+    async_data->async_ops = g_slist_remove (async_data->async_ops,
+					    sub_async_data);
+
+    add_directory_async_done_cb (async_data);
+}
+
+static void
+add_directory_async_cb (GnomeVFSAsyncHandle *handle, GnomeVFSResult result,
+			GList *list, guint entries_read, gpointer callback_data)
+{
+    GnomeFileSelectorAsyncData *async_data;
+    GnomeFileSelector *fselector;
+
+    g_return_if_fail (callback_data != NULL);
+
+    async_data = callback_data;
+    g_assert (async_data->vfs_handle == handle);
+    g_assert (GNOME_IS_FILE_SELECTOR (async_data->fselector));
+    g_assert (async_data->type == GNOME_SELECTOR_ASYNC_TYPE_ADD_DIRECTORY);
+
+    fselector = GNOME_FILE_SELECTOR (async_data->fselector);
+
+    if (list != NULL) {
+	GList *c;
+
+	for (c = list; c; c = c->next) {
+	    GnomeVFSFileInfo *info = c->data;
+	    GnomeFileSelectorSubAsyncData *sub_async_data;
+	    GnomeVFSURI *uri;
+	    gchar *text;
+
+	    if (fselector->_priv->filter &&
+		!gnome_vfs_directory_filter_apply (fselector->_priv->filter,
+						   info)) {
+		continue;
+	    }
+
+	    uri = gnome_vfs_uri_append_file_name (async_data->uri, info->name);
+	    text = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
+
+	    /* We keep a list of currently running async operations in
+	     * async_data->async_ops. This is that add_directory_async_done_cb()
+	     * knows whether we're really done or whether we still need to wait.
+	     */
+
+	    sub_async_data = g_new0 (GnomeFileSelectorSubAsyncData, 1);
+	    sub_async_data->async_data = async_data;
+
+	    async_data->async_ops = g_slist_prepend
+		(async_data->async_ops, sub_async_data);
+
+	    gnome_selector_add_file (GNOME_SELECTOR (fselector),
+				     &sub_async_data->async_handle,
+				     text, async_data->position,
+				     async_data->list_id,
+				     add_directory_async_file_cb,
+				     sub_async_data);
+
+	    gnome_vfs_uri_unref (uri);
+	    g_free (text);
+	}
+    }
+
+    if (result == GNOME_VFS_ERROR_EOF) {
+	/* Completed, but we may have async operations running. We set
+	 * async_data->completed here to inform add_directory_async_done_cb()
+	 * that we're done with our directory reading.
+	 */
+	async_data->completed = TRUE;
+	add_directory_async_done_cb (async_data);
+    }
+}
+
+static void
+add_directory_handler (GnomeSelector *selector, const gchar *uri,
+		       gint position, guint list_id,
+		       GnomeSelectorAsyncHandle *async_handle)
+{
+    GnomeFileSelector *fselector;
+    GnomeFileSelectorAsyncData *async_data;
+    GnomeVFSURI *vfs_uri;
+
+    g_return_if_fail (selector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (selector));
+    g_return_if_fail (position >= -1);
+    g_return_if_fail (uri != NULL);
+    g_return_if_fail (async_handle != NULL);
+
+    fselector = GNOME_FILE_SELECTOR (selector);
+
+#ifdef DEBUG_ASYNC_STUFF
+    g_message (G_STRLOC ": %p - starting async reading (%s).",
+	       selector, uri);
+#endif
+
+    vfs_uri = gnome_vfs_uri_new (uri);
+
+    async_data = g_new0 (GnomeFileSelectorAsyncData, 1);
+    async_data->type = GNOME_SELECTOR_ASYNC_TYPE_ADD_DIRECTORY;
+    async_data->fselector = fselector;
+    async_data->uri = vfs_uri;
+    async_data->position = position;
+    async_data->list_id = list_id;
+    async_data->async_handle = async_handle;
+
+    gnome_vfs_uri_ref (async_data->uri);
+    gtk_object_ref (GTK_OBJECT (async_data->fselector));
+
+    _gnome_selector_async_handle_add (async_handle, async_data,
+				      free_the_async_data);
+
+    gnome_vfs_async_load_directory_uri (&async_data->vfs_handle, vfs_uri,
+					fselector->_priv->file_info_options,
+					GNOME_VFS_DIRECTORY_FILTER_NONE,
+					GNOME_VFS_DIRECTORY_FILTER_NODIRS,
+					NULL, 1, add_directory_async_cb,
+					async_data);
+
+    gnome_vfs_uri_unref (vfs_uri);
+}
+
+void
+gnome_file_selector_set_filter (GnomeFileSelector *fselector,
+				GnomeVFSDirectoryFilter *filter)
+{
+    GnomeVFSDirectoryFilterNeeds needs;
+
+    g_return_if_fail (fselector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (fselector));
+    g_return_if_fail (filter != NULL);
+
+    if (fselector->_priv->filter)
+	gnome_vfs_directory_filter_destroy (fselector->_priv->filter);
+
+    fselector->_priv->filter = filter;
+    fselector->_priv->file_info_options = GNOME_VFS_FILE_INFO_DEFAULT;
+
+    needs = gnome_vfs_directory_filter_get_needs (filter);
+    if (needs & GNOME_VFS_DIRECTORY_FILTER_NEEDS_MIMETYPE)
+	fselector->_priv->file_info_options |=
+	    GNOME_VFS_FILE_INFO_GET_MIME_TYPE |
+	    GNOME_VFS_FILE_INFO_FORCE_FAST_MIME_TYPE;
+}
+
+void
+gnome_file_selector_clear_filter (GnomeFileSelector *fselector)
+{
+    g_return_if_fail (fselector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (fselector));
+
+    if (fselector->_priv->filter)
+	gnome_vfs_directory_filter_destroy (fselector->_priv->filter);
+
+    fselector->_priv->filter = NULL;
+    fselector->_priv->file_info_options = GNOME_VFS_FILE_INFO_DEFAULT;
+}
+
+static void
+activate_entry_handler (GnomeSelector *selector)
+{
+    GnomeFileSelector *fselector;
+    gchar *text;
+
+    g_return_if_fail (selector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (selector));
+
+    fselector = GNOME_FILE_SELECTOR (selector);
+
+    GNOME_CALL_PARENT_HANDLER (GNOME_SELECTOR_CLASS, activate_entry,
+			       (selector));
+
+    text = gnome_selector_get_entry_text (selector);
+    gnome_selector_add_uri (selector, NULL, text, 0, FALSE, NULL, NULL);
+    g_free (text);
+}
+
+static void
+gnome_file_selector_init (GnomeFileSelector *fselector)
+{
+    fselector->_priv = g_new0 (GnomeFileSelectorPrivate, 1);
+}
+
+static void
+browse_dialog_cancel (GtkWidget *widget, gpointer data)
+{
+    GnomeFileSelector *fselector;
+    GtkFileSelection *fs;
+
+    g_assert (GNOME_IS_FILE_SELECTOR (data));
+
+    fselector = GNOME_FILE_SELECTOR (data);
+    fs = GTK_FILE_SELECTION (fselector->_priv->browse_dialog);
+
+    if (GTK_WIDGET (fs)->window)
+	gdk_window_lower (GTK_WIDGET (fs)->window);
+    gtk_widget_hide (GTK_WIDGET (fs));
+}
+
+static void
+browse_dialog_ok (GtkWidget *widget, gpointer data)
+{
+    GnomeFileSelector *fselector;
+    GtkFileSelection *fs;
+    const gchar *filename;
+
+    g_assert (GNOME_IS_FILE_SELECTOR (data));
+
+    fselector = GNOME_FILE_SELECTOR (data);
+
+    fs = GTK_FILE_SELECTION (fselector->_priv->browse_dialog);
+    filename = gtk_file_selection_get_filename (fs);
+
+    gnome_selector_set_uri (GNOME_SELECTOR (fselector), NULL, filename,
+			    NULL, NULL);
+
+    if (GTK_WIDGET (fs)->window)
+	gdk_window_lower (GTK_WIDGET (fs)->window);
+    gtk_widget_hide (GTK_WIDGET (fs));
+}
+
+static void
+check_uri_async_cb (GnomeVFSAsyncHandle *handle, GList *results, gpointer callback_data)
+{
+    GnomeFileSelectorAsyncData *async_data;
+    GnomeFileSelector *fselector;
+    GList *list;
+
+    g_return_if_fail (callback_data != NULL);
+
+    async_data = callback_data;
+    g_assert (async_data->vfs_handle == handle);
+    g_assert (GNOME_IS_FILE_SELECTOR (async_data->fselector));
+    g_assert ((async_data->type == GNOME_SELECTOR_ASYNC_TYPE_CHECK_FILENAME) ||
+	      (async_data->type == GNOME_SELECTOR_ASYNC_TYPE_CHECK_DIRECTORY));
+
+    fselector = GNOME_FILE_SELECTOR (async_data->fselector);
+
+    g_assert ((results == NULL) || (results->next == NULL));
+
+    for (list = results; list; list = list->next) {
+	GnomeVFSGetFileInfoResult *file = list->data;
+	GnomeSelectorAsyncHandle *async_handle = async_data->async_handle;
+
+	/* better assert this than risking a crash. */
+	g_assert (file != NULL);
+
+	_gnome_selector_async_handle_remove (async_handle, async_data);
+
+	if (file->result != GNOME_VFS_OK) {
+	    _gnome_selector_async_handle_completed (async_handle, FALSE);
+	    return;
+	}
+
+	if ((file->file_info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) &&
+	    (async_data->type != GNOME_SELECTOR_ASYNC_TYPE_CHECK_DIRECTORY)) {
+	    _gnome_selector_async_handle_completed (async_handle, FALSE);
+	    return;
+	}
+
+	if (fselector->_priv->filter &&
+	    !gnome_vfs_directory_filter_apply (fselector->_priv->filter,
+					       file->file_info)) {
+	    _gnome_selector_async_handle_completed (async_handle, FALSE);
+	    return;
+	}
+
+	_gnome_selector_async_handle_completed (async_handle, TRUE);
+	return;
+    }
+}
+
+static void
+check_uri_handler (GnomeSelector *selector, const gchar *uri,
+		   GnomeSelectorAsyncType async_type,
+		   GnomeSelectorAsyncHandle *async_handle)
+{
+    GnomeFileSelectorAsyncData *async_data;
+    GnomeFileSelector *fselector;
+    GList fake_list;
+
+    g_return_if_fail (selector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (selector));
+    g_return_if_fail (uri != NULL);
+    g_return_if_fail (async_handle != NULL);
+
+    fselector = GNOME_FILE_SELECTOR (selector);
+
+    async_data = g_new0 (GnomeFileSelectorAsyncData, 1);
+    async_data->async_handle = async_handle;
+    async_data->type = GNOME_SELECTOR_ASYNC_TYPE_CHECK_FILENAME;
+    async_data->fselector = fselector;
+    async_data->uri = gnome_vfs_uri_new (uri);
+
+    gnome_vfs_uri_ref (async_data->uri);
+    gtk_object_ref (GTK_OBJECT (async_data->fselector));
+
+    fake_list.data = async_data->uri;
+    fake_list.prev = NULL;
+    fake_list.next = NULL;
+
+    _gnome_selector_async_handle_add (async_handle, async_data,
+				      free_the_async_data);
+
+    gnome_vfs_async_get_file_info (&async_data->vfs_handle, &fake_list,
+				   fselector->_priv->file_info_options,
+				   check_uri_async_cb, async_data);
+
+    gnome_vfs_uri_unref (fake_list.data);
+}
+
+static void
+check_filename_handler (GnomeSelector *selector, const gchar *filename,
+			GnomeSelectorAsyncHandle *async_handle)
+{
+    g_return_if_fail (selector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (selector));
+    g_return_if_fail (filename != NULL);
+    g_return_if_fail (async_handle != NULL);
+
+    check_uri_handler (selector, filename, GNOME_SELECTOR_ASYNC_TYPE_CHECK_FILENAME, async_handle);
+}
+
+static void
+check_directory_handler (GnomeSelector *selector, const gchar *directory,
+			 GnomeSelectorAsyncHandle *async_handle)
+{
+    g_return_if_fail (selector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (selector));
+    g_return_if_fail (directory != NULL);
+    g_return_if_fail (async_handle != NULL);
+
+    check_uri_handler (selector, directory, GNOME_SELECTOR_ASYNC_TYPE_CHECK_DIRECTORY, async_handle);
+}
+
+static gboolean
+get_value_boolean (GnomeFileSelector *fselector, const gchar *prop_name)
+{
+    GValue value = { 0, };
+    gboolean retval;
+
+    g_value_init (&value, G_TYPE_BOOLEAN);
+    g_object_get_property (G_OBJECT (fselector), prop_name, &value);
+    retval = g_value_get_boolean (&value);
+    g_value_unset (&value);
+
+    return retval;
+}
+
+static gboolean
+has_value_widget (GnomeFileSelector *fselector, const gchar *prop_name)
+{
+	GValue value = { 0, };
+	gboolean retval;
+
+	g_value_init (&value, GTK_TYPE_WIDGET);
+	g_object_get_property (G_OBJECT (fselector), prop_name, &value);
+	retval = g_value_get_object (&value) != NULL;
+	g_value_unset (&value);
+
+	return retval;
+}
+
+static void
+do_construct_handler (GnomeSelector *selector)
+{
+    GnomeFileSelector *fselector;
+
+    g_return_if_fail (selector != NULL);
+    g_return_if_fail (GNOME_IS_FILE_SELECTOR (selector));
+
+    fselector = GNOME_FILE_SELECTOR (selector);
+
+    if (get_value_boolean (fselector, "want_default_behaviour")) {
+	g_object_set (G_OBJECT (fselector),
+		      "want_default_behaviour", FALSE,
+		      "use_default_entry_widget", TRUE,
+		      "use_default_selector_widget", TRUE,
+		      "use_default_browse_dialog", TRUE,
+		      "want_browse_button", TRUE,
+		      "want_clear_button", FALSE,
+		      "want_default_button", FALSE,
+		      NULL);
+    }
+
+    /* Create the default browser dialog if requested. */
+    if (get_value_boolean (fselector, "use_default_browse_dialog") &&
+	!has_value_widget (fselector, "browse_dialog")) {
+	GtkWidget *filesel_widget;
+	GtkFileSelection *filesel;
+	GValue value = { 0, };
+
+	g_value_init (&value, G_TYPE_STRING);
+	g_object_get_property (G_OBJECT (fselector), "dialog_title", &value);
+
+	filesel_widget = gtk_file_selection_new (g_value_get_string (&value));
+	filesel = GTK_FILE_SELECTION (filesel_widget);
+
+	g_value_unset (&value);
+
+	gtk_signal_connect (GTK_OBJECT (filesel->cancel_button),
+			    "clicked", GTK_SIGNAL_FUNC (browse_dialog_cancel),
+			    fselector);
+	gtk_signal_connect (GTK_OBJECT (filesel->ok_button),
+			    "clicked", GTK_SIGNAL_FUNC (browse_dialog_ok),
+			    fselector);
+
+	fselector->_priv->browse_dialog = GTK_WIDGET (filesel);
+
+	g_value_init (&value, GTK_TYPE_WIDGET);
+	g_value_set_object (&value, G_OBJECT (filesel));
+	g_object_set_property (G_OBJECT (fselector), "browse_dialog", &value);
+	g_value_unset (&value);
+    }
+
+    GNOME_CALL_PARENT_HANDLER (GNOME_SELECTOR_CLASS, do_construct, (selector));
+}
+
+
+static GObject*
+gnome_file_selector_constructor (GType                  type,
+				 guint                  n_construct_properties,
+				 GObjectConstructParam *construct_properties)
+{
+    GObject *object = G_OBJECT_CLASS (parent_class)->constructor (type,
+								  n_construct_properties,
+								  construct_properties);
+    GnomeFileSelector *fselector = GNOME_FILE_SELECTOR (object);
+
+    g_message (G_STRLOC ": %d - %d", type, GNOME_TYPE_FILE_SELECTOR);
+
+    if (type == GNOME_TYPE_FILE_SELECTOR)
+	gnome_selector_do_construct (GNOME_SELECTOR (fselector));
+
+    return object;
+}
+
+/**
+ * gnome_file_selector_new
+ * @history_id: If not %NULL, the text id under which history data is stored
+ *
+ * Description: Creates a new GnomeFileSelector widget.  If  @history_id
+ * is not %NULL, then the history list will be saved and restored between
+ * uses under the given id.
+ *
+ * Returns: Newly-created GnomeFileSelector widget.
+ */
+GtkWidget *
+gnome_file_selector_new (const gchar *history_id,
+			 const gchar *dialog_title)
+{
+    GnomeFileSelector *fselector;
+
+    fselector = g_object_new (gnome_file_selector_get_type (),
+			      "history_id", history_id,
+			      "dialog_title", dialog_title,
+			       NULL);
+
+    return GTK_WIDGET (fselector);
+}
+
+static void
+gnome_file_selector_destroy (GtkObject *object)
+{
+    GnomeFileSelector *fselector;
+
+    /* remember, destroy can be run multiple times! */
+
+    g_return_if_fail (object != NULL);
+    g_return_if_fail (GNOME_IS_SELECTOR (object));
+
+    fselector = GNOME_FILE_SELECTOR (object);
+
+    GNOME_CALL_PARENT_HANDLER (GTK_OBJECT_CLASS, destroy, (object));
+}
+
+static void
+gnome_file_selector_finalize (GObject *object)
+{
+    GnomeFileSelector *fselector;
+
+    g_return_if_fail (object != NULL);
+    g_return_if_fail (GNOME_IS_SELECTOR (object));
+
+    fselector = GNOME_FILE_SELECTOR (object);
+
+    g_free (fselector->_priv);
+    fselector->_priv = NULL;
+
+    GNOME_CALL_PARENT_HANDLER (G_OBJECT_CLASS, finalize, (object));
+}
diff --git a/libgnome/gnome-file-selector.h b/libgnome/gnome-file-selector.h
new file mode 100644
index 0000000..60f5ec8
--- /dev/null
+++ b/libgnome/gnome-file-selector.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; c-set-style: gnu indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2000 SuSE GmbH
+ * Author: Martin Baulig <baulig suse de>
+ *
+ * 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@
+ */
+
+/* GnomeFileSelector widget - a file selector widget.
+ *
+ * Author: Martin Baulig <baulig suse de>
+ */
+
+#ifndef GNOME_FILE_SELECTOR_H
+#define GNOME_FILE_SELECTOR_H
+
+
+#include <gtk/gtkvbox.h>
+#include <libgnome/gnome-defs.h>
+#include "gnome-entry.h"
+
+#include <libgnomevfs/gnome-vfs-types.h>
+#include <libgnomevfs/gnome-vfs-directory-filter.h>
+
+
+BEGIN_GNOME_DECLS
+
+
+#define GNOME_TYPE_FILE_SELECTOR            (gnome_file_selector_get_type ())
+#define GNOME_FILE_SELECTOR(obj)            (GTK_CHECK_CAST ((obj), GNOME_TYPE_FILE_SELECTOR, GnomeFileSelector))
+#define GNOME_FILE_SELECTOR_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), GNOME_TYPE_FILE_SELECTOR, GnomeFileSelectorClass))
+#define GNOME_IS_FILE_SELECTOR(obj)         (GTK_CHECK_TYPE ((obj), GNOME_TYPE_FILE_SELECTOR))
+#define GNOME_IS_FILE_SELECTOR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_FILE_SELECTOR))
+#define GNOME_FILE_SELECTOR_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), GNOME_TYPE_FILE_SELECTOR, GnomeFileSelectorClass))
+
+
+typedef struct _GnomeFileSelector         GnomeFileSelector;
+typedef struct _GnomeFileSelectorPrivate  GnomeFileSelectorPrivate;
+typedef struct _GnomeFileSelectorClass    GnomeFileSelectorClass;
+
+struct _GnomeFileSelector {
+        GnomeEntry entry;
+        
+        /*< private >*/
+        GnomeFileSelectorPrivate *_priv;
+};
+
+struct _GnomeFileSelectorClass {
+        GnomeEntryClass parent_class;
+};
+
+
+guint      gnome_file_selector_get_type      (void) G_GNUC_CONST;
+
+GtkWidget *gnome_file_selector_new           (const gchar *history_id,
+                                              const gchar *dialog_title);
+
+void       gnome_file_selector_set_filter    (GnomeFileSelector *fselector,
+                                              GnomeVFSDirectoryFilter *filter);
+
+void       gnome_file_selector_clear_filter  (GnomeFileSelector *fselector);
+
+END_GNOME_DECLS
+
+#endif
diff --git a/libgnome/gnome-fileconvert.c b/libgnome/gnome-fileconvert.c
new file mode 100644
index 0000000..ce253f8
--- /dev/null
+++ b/libgnome/gnome-fileconvert.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 1997, 1998, 1999 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 <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <glib.h>
+#include <dirent.h>
+
+#include "gnome-defs.h"
+#include "gnome-fileconvert.h"
+#include "gnome-util.h"
+#include "libgnomeP.h"
+
+typedef gint Cost;
+#define UNREACHABLE 32000 /*MAXINT or something*/
+#define NOCOST 0
+#define MINCOST 1
+
+#define IMPOSSIBLE_PATH NULL
+
+typedef struct _FileConverter FileConverter;
+typedef struct _FileType FileType;
+
+struct _FileConverter {
+	FileType *fromtype;
+	FileType *totype;
+	gchar *cmdline;
+	gint cost;
+};
+
+struct _FileType {
+	gchar *name;
+	GList *arcs;
+	FileConverter *best_way_here;
+	gint cost;
+	gint done;
+};
+
+static GList *gfc_get_path(const char *fromtype, const char *totype);
+static gint   gfc_run_pipe(gchar *acmd, gint infd);
+
+/**
+ * gnome_file_convert:
+ * @filename: file to convert
+ * @fromtype: mime type of the file
+ * @totype:   target mime type we want
+ *
+ * Converts @filename to the @totype format.
+ *
+ * Returns -1 on failure, or a file descriptor to the converted
+ * file.
+ */
+gint
+gnome_file_convert (const char *filename, const char *fromtype, const char *totype)
+{
+	gint fd = open (filename, O_RDONLY);
+
+	if (fd >= 0)
+		return gnome_file_convert_fd (fd, fromtype, totype);
+	else
+		return -1;
+}
+
+/**
+ * gnome_file_convert_fd:
+ * @fd: file desciptor pointing to the file to convert.
+ * @fromtype: mime type of the file
+ * @totype:   target mime type we want
+ *
+ * Converts the file opened by @fd to the @totype format.
+ *
+ * Returns -1 on failure, or a file descriptor to the converted
+ * file.
+ */
+gint
+gnome_file_convert_fd (gint fd, const char *fromtype, const char *totype)
+{
+	GList *convlist, *l;
+	gint infd, outfd;
+	FileConverter *converter;
+	
+	convlist = gfc_get_path (fromtype, totype);
+	if (!convlist)
+		return -1;
+	
+	for (l = convlist, infd = fd; l; l = l->next){
+		if (!(converter = l->data)){
+			infd = -1;
+			break;
+		}
+#ifdef GNOME_ENABLE_DEBUG
+		g_print("%s %s: %s\n", converter->fromtype->name, converter->totype->name,
+			converter->cmdline);
+#endif
+		if (converter->cmdline == NULL)
+			continue;
+		outfd = gfc_run_pipe (converter->cmdline, infd);
+		if (infd != fd)
+			close (infd);
+		infd = outfd;
+	}
+	g_list_free (convlist);
+	return infd;
+}
+
+/* Probably could use gnome_config routines for this,
+   as soon as miguel redoes it */
+static void
+load_types_from (GHashTable *file_types, char *fname)
+{
+	gchar aline[512];
+	gchar **parts;
+	FILE *conffile;
+	FileConverter *newarc;
+	FileType *fromtype, *totype;
+
+	conffile = fopen (fname, "r");
+	
+	if (!conffile)
+		return;
+	
+	while (fgets(aline, sizeof(aline), conffile)){
+		g_strchomp (aline);
+		if (aline[0] == '#' || aline[0] == '\0')
+			continue;
+		
+		parts = g_strsplit (aline, " ", 3);
+		
+		if (! (fromtype = g_hash_table_lookup(file_types, parts[0])))
+		{
+			fromtype = g_new(FileType, 1);
+			fromtype->name = parts[0];
+			fromtype->arcs = NULL;
+			g_hash_table_insert(file_types, fromtype->name, fromtype);
+		}
+		if (! (totype = g_hash_table_lookup(file_types, parts[1])))
+		{
+			totype = g_new(FileType, 1);
+			totype->name = parts[1];
+			totype->arcs = NULL;
+			g_hash_table_insert(file_types, totype->name, totype);
+		}
+		
+		newarc = g_new(FileConverter, 1);
+		newarc->fromtype = fromtype;
+		newarc->totype = totype;
+		newarc->cost = 1; /* replace this with something from the config file */
+		if(newarc->cost < MINCOST) /* non-positive costs cause infinite loops */
+			newarc->cost = MINCOST;
+		newarc->cmdline = parts[2];
+		fromtype->arcs = g_list_prepend(fromtype->arcs, newarc);
+		
+		g_free(parts);
+	}
+	fclose(conffile);
+}
+
+static GHashTable *
+gfc_read_FileConverters(void)
+{
+	char *file, *dirname;
+	GHashTable *file_types;
+	DIR *dir;
+	struct dirent *dent;
+	const int extlen = sizeof (".convert") - 1;
+	
+	file_types = g_hash_table_new(g_str_hash, g_str_equal);
+	
+	dirname = gnome_unconditional_datadir_file ("type-convert");
+
+	dir = opendir (dirname);
+	if (dir){
+		while ((dent = readdir (dir)) != NULL){
+			int len = strlen (dent->d_name);
+
+			if (len <= extlen)
+				continue;
+
+			if (strcmp (dent->d_name + len - extlen, ".convert"))
+				continue;
+
+			file = g_concat_dir_and_file (dirname, dent->d_name);
+			load_types_from (file_types, file);
+			g_free (file);
+		}
+	}
+	g_free (dirname);
+
+	file = gnome_util_home_file ("type.convert");
+	load_types_from (file_types, file);
+	g_free (file);
+	
+
+	return file_types;
+}
+
+
+/* Used as callback from g_hash_table_foreach */
+static void 
+gfc_reset_path(gpointer key, FileType *node, gpointer userdata)
+{
+	node->best_way_here = NULL;
+	node->cost = UNREACHABLE;
+}
+
+/* Calculates shortest paths from from_node using Dijkstra's algorithm.
+ * Returns list of converters to get from from_node to to_node.
+ * The queue is just a GList but that'll be OK for these small graphs. 
+ */
+static GList *
+gfc_shortest_path (GHashTable *file_types,
+		   FileType *from_node,  
+		   FileType *to_node)
+{
+	GList *nodes_to_do, *best, *best_route=NULL, *tmp;
+	FileType *node, *current_node;
+	FileConverter *arc;
+	Cost  new_cost;
+	
+	/* Reset all the path data */
+	g_hash_table_foreach(file_types, (GHFunc)gfc_reset_path, NULL);
+	
+	/* Start with from_node */
+	from_node->cost = NOCOST;
+	from_node->best_way_here = NULL;
+	nodes_to_do = g_list_append(NULL, from_node);
+	
+	/* Find shortest paths */
+	while(nodes_to_do)
+	{
+		/* Find cheapest remaining reachable node */
+		best = NULL;
+		for(tmp = nodes_to_do; tmp; tmp = tmp->next)
+			if(!best || ((FileType *)tmp->data)->cost < ((FileType *)best->data)->cost)
+				best = tmp;
+		current_node = ((FileType *)best->data);
+		nodes_to_do = g_list_remove_link(nodes_to_do, best);
+		g_list_free(best);
+		
+		/* if to_node is found we are done, retrace the path here and return it*/
+		if(current_node == to_node) {
+			for(arc = to_node->best_way_here; arc; arc = arc->fromtype->best_way_here)
+				best_route = g_list_prepend(best_route, arc);
+			return best_route;
+		}
+		
+		/* Explore all converters available from current_node */    
+		for(tmp = current_node->arcs; tmp; tmp = tmp->next)
+		{
+			arc = tmp->data;
+			new_cost = current_node->cost + arc->cost;
+			node = arc->totype;
+			if(new_cost < node->cost)
+			{
+				if(node->cost == UNREACHABLE)
+					nodes_to_do = g_list_prepend(nodes_to_do, node);
+				node->cost = new_cost;
+				node->best_way_here = arc;
+			}
+		}
+	}
+	/* no route to to_node found */
+	return IMPOSSIBLE_PATH;
+}
+
+
+/* Get the list of converters required to convert fromtype to totype */
+static GList *
+gfc_get_path (const char *fromtype, const char *totype)
+{
+	static GHashTable *file_types;
+	static gboolean read_datfile = FALSE;
+	FileType *from_node, *to_node;
+	
+	if(!read_datfile)
+	{
+		file_types = gfc_read_FileConverters();
+		read_datfile = TRUE;
+	}
+	
+	/* Look up the start and goal types */
+	from_node = (FileType *) g_hash_table_lookup(file_types,  fromtype);
+	to_node = (FileType *) g_hash_table_lookup(file_types,  totype);
+	
+	/* Give up if asked for an unknown file type */
+	if(from_node == NULL || to_node == NULL)
+		return IMPOSSIBLE_PATH;
+	
+	return gfc_shortest_path(file_types, from_node, to_node);
+}
+
+static gint
+gfc_run_pipe (gchar *acmd, gint infd)
+{
+	gchar **parts;
+	gint childpid;
+	gint fds[2];
+	
+	if (pipe (fds))
+		return -1;
+	
+	childpid = fork ();
+	if (childpid < 0)
+		return -1;
+	
+	if (childpid){
+		close (fds [1]);
+		waitpid (childpid, &childpid, 0);
+		return fds [0];
+	}
+	
+	/* else */
+	
+	parts = g_strsplit (acmd, " ", -1);
+	dup2 (infd, 0);
+	dup2 (fds [1], 1);
+	dup2 (fds [1], 2);
+	if (fds [1] > 2)
+		close (fds [1]);
+	if (infd > 2)
+		close (infd);
+	if (fork()) /* Double-forking is good for the (zombified) soul ;-) */
+		exit (0);
+	else
+		execvp (parts [0], parts);
+	
+	/* ERROR IF REACHED */
+	close (0);
+	close (1);
+	exit (69);
+}
diff --git a/libgnome/gnome-fileconvert.h b/libgnome/gnome-fileconvert.h
new file mode 100644
index 0000000..4bc5088
--- /dev/null
+++ b/libgnome/gnome-fileconvert.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 1997, 1998, 1999 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_FILECONVERT_H__
+#define __GNOME_FILECONVERT_H__ 1
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+
+/* WARNING ____ IMMATURE API ____ liable to change */
+
+BEGIN_GNOME_DECLS
+
+/* Returns -1 if no conversion is possible */
+gint
+gnome_file_convert_fd(gint fd, const char *fromtype, const char *totype);
+/* Convenience wrapper for the above function */
+gint
+gnome_file_convert(const char *filename, const char *fromtype, const char *totype);
+
+END_GNOME_DECLS
+
+#endif /* __GNOME_FILECONVERT_H__ */
diff --git a/libgnome/gnome-gconf.c b/libgnome/gnome-gconf.c
new file mode 100644
index 0000000..9e5702c
--- /dev/null
+++ b/libgnome/gnome-gconf.c
@@ -0,0 +1,577 @@
+/*  -*- Mode: C; c-set-style: linux; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GNOME GUI Library - gnome-gconf.h
+ * Copyright (C) 2000  Red Hat Inc.,
+ * All rights reserved.
+ *
+ * Author: Jonathan Blandford  <jrb redhat com>
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
+ */
+/*
+  @NOTATION@
+*/
+
+#include <libgnome/gnome-defs.h>
+#include <stdlib.h>
+#include <liboaf/liboaf.h>
+
+#define GCONF_ENABLE_INTERNALS 1
+#include <gconf/gconf.h>
+extern struct poptOption gconf_options[];
+
+#include <libgnome/libgnome.h>
+#include "oafgnome.h"
+#include "gnome-gconf.h"
+#include "gnome-messagebox.h"
+#include "gnome-stock-ids.h"
+#include <gtk/gtkmain.h>
+
+
+GConfValue *
+gnome_gconf_gtk_entry_get (GtkEntry       *entry,
+			   GConfValueType  type)
+{
+	GConfValue *retval = NULL;
+	const char *text;
+	gint i;
+	gfloat f;
+
+	g_return_val_if_fail (entry != NULL, NULL);
+	g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
+	g_return_val_if_fail ((type == GCONF_VALUE_STRING) ||
+			      (type == GCONF_VALUE_INT) ||
+			      (type == GCONF_VALUE_FLOAT), NULL);
+
+	text = gtk_entry_get_text (entry);
+	retval = gconf_value_new (type);
+	switch (type) {
+	case GCONF_VALUE_STRING:
+		gconf_value_set_string (retval, text);
+		break;
+	case GCONF_VALUE_INT:
+		i = strtol (text, NULL, 0);
+		gconf_value_set_int (retval, i);
+		break;
+	case GCONF_VALUE_FLOAT:
+		f = strtod (text, NULL);
+		gconf_value_set_float (retval, f);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	return retval;
+
+}
+
+void
+gnome_gconf_gtk_entry_set (GtkEntry       *entry,
+			   GConfValue     *value)
+{
+	gchar string[33];
+
+	g_return_if_fail (entry != NULL);
+	g_return_if_fail (GTK_IS_ENTRY (entry));
+	g_return_if_fail (value != NULL);
+	g_return_if_fail ((value->type == GCONF_VALUE_STRING) ||
+			      (value->type == GCONF_VALUE_INT) ||
+			      (value->type == GCONF_VALUE_FLOAT));
+
+	switch (value->type) {
+	case GCONF_VALUE_STRING:
+		gtk_entry_set_text (entry, gconf_value_get_string (value));
+		break;
+	case GCONF_VALUE_INT:
+		g_snprintf (string, 32, "%d", gconf_value_get_int (value));
+		gtk_entry_set_text (entry, string);
+		break;
+	case GCONF_VALUE_FLOAT:
+		g_snprintf (string, 32, "%f", gconf_value_get_float (value));
+		gtk_entry_set_text (entry, string);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+}
+
+GConfValue *
+gnome_gconf_spin_button_get (GtkSpinButton *spin_button,
+			     GConfValueType  type)
+{
+	GConfValue *retval = NULL;
+	gint i;
+	gfloat f;
+
+	g_return_val_if_fail (spin_button != NULL, NULL);
+	g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spin_button), NULL);
+	g_return_val_if_fail ((type == GCONF_VALUE_INT) ||
+			      (type == GCONF_VALUE_FLOAT), NULL);
+
+	retval = gconf_value_new (type);
+	switch (type) {
+	case GCONF_VALUE_INT:
+		i = gtk_spin_button_get_value_as_int (spin_button);
+		gconf_value_set_int (retval, i);
+		break;
+	case GCONF_VALUE_FLOAT:
+		f = gtk_spin_button_get_value_as_float (spin_button);
+		gconf_value_set_float (retval, f);
+		break;
+	default:
+		break;
+	}
+
+	return retval;
+}
+
+void
+gnome_gconf_spin_button_set (GtkSpinButton *spin_button,
+			     GConfValue    *value)
+{
+	float f;
+
+	g_return_if_fail (spin_button != NULL);
+	g_return_if_fail (GTK_IS_SPIN_BUTTON (spin_button));
+	g_return_if_fail (value != NULL);
+	g_return_if_fail ((value->type == GCONF_VALUE_INT) ||
+			  (value->type == GCONF_VALUE_FLOAT));
+
+	switch (value->type) {
+	case GCONF_VALUE_INT:
+		f = gconf_value_get_int (value);
+		gtk_spin_button_set_value (spin_button, f);
+		break;
+	case GCONF_VALUE_FLOAT:
+		f = gconf_value_get_float (value);
+		gtk_spin_button_set_value (spin_button, f);
+		break;
+	default:
+		break;
+	}
+}
+
+GConfValue *
+gnome_gconf_gtk_radio_button_get (GtkRadioButton  *radio,
+				  GConfValueType   type)
+{
+	GConfValue *retval;
+	int i = 0;
+	GSList *group;
+	
+	g_return_val_if_fail (radio != NULL, NULL);
+	g_return_val_if_fail (GTK_IS_RADIO_BUTTON (radio), NULL);
+	g_return_val_if_fail (((type == GCONF_VALUE_BOOL) ||
+			       (type == GCONF_VALUE_INT)), NULL);
+
+	retval = gconf_value_new (type);
+	for (i = 0, group = radio->group; group != NULL; i++, group = group->next) {
+		if (GTK_TOGGLE_BUTTON (group->data)->active) {
+			if (type == GCONF_VALUE_BOOL) {
+				if (i > 1)
+					g_warning ("more then two radio buttons used with a boolean\n");
+				else
+					gconf_value_set_bool (retval, i);
+			} else {
+				gconf_value_set_int (retval, i);
+			}
+			break;
+		}
+	}
+	return retval;
+}
+
+void
+gnome_gconf_gtk_radio_button_set (GtkRadioButton  *radio,
+				  GConfValue      *value)
+{
+	gint i, j = 0;
+	GSList *list;
+
+	g_return_if_fail (radio != NULL);
+	g_return_if_fail (GTK_IS_RADIO_BUTTON (radio));
+	g_return_if_fail (value != NULL);
+	g_return_if_fail ((value->type == GCONF_VALUE_BOOL) ||
+			  (value->type == GCONF_VALUE_INT));
+
+	switch (value->type) {
+	case GCONF_VALUE_BOOL:
+		j = gconf_value_get_bool (value);
+		break;
+	case GCONF_VALUE_INT:
+		j = gconf_value_get_int (value);
+		break;
+	default:
+		g_assert_not_reached();
+	}
+
+	for (list = radio->group, i = 0 ; i != j && list != NULL; i ++, list = list->next)
+		;
+	if (list)
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (list->data), TRUE);
+}
+
+GConfValue *
+gnome_gconf_gtk_range_get (GtkRange       *range,
+			   GConfValueType  type)
+{
+	GtkAdjustment *adjustment;
+	GConfValue *retval;
+	int i;
+
+	g_return_val_if_fail (range != NULL, NULL);
+	g_return_val_if_fail (GTK_IS_RANGE (range), NULL);
+	g_return_val_if_fail ((type == GCONF_VALUE_FLOAT) ||
+			      (type == GCONF_VALUE_INT), NULL);
+
+	adjustment = gtk_range_get_adjustment (range);
+	retval = gconf_value_new (type);
+	switch (type) {
+	case GCONF_VALUE_INT:
+		i = adjustment->value;
+		gconf_value_set_int (retval, i);
+		break;
+	case GCONF_VALUE_FLOAT:
+		gconf_value_set_float (retval, adjustment->value);
+		break;
+	default:
+		break;
+	}
+	return retval;
+}
+
+void
+gnome_gconf_gtk_range_set (GtkRange       *range,
+			   GConfValue     *value)
+{
+	GtkAdjustment *adjustment;
+	gdouble f = 0.0;
+
+	g_return_if_fail (range != NULL);
+	g_return_if_fail (GTK_IS_RANGE (range));
+	g_return_if_fail ((value->type == GCONF_VALUE_FLOAT) ||
+			  (value->type == GCONF_VALUE_INT));
+
+	switch (value->type) {
+	case GCONF_VALUE_FLOAT:
+		f = gconf_value_get_float (value);
+		break;
+	case GCONF_VALUE_INT:
+		f = gconf_value_get_int (value);
+		break;
+	default:
+		g_assert_not_reached();
+	}
+	adjustment = gtk_range_get_adjustment (range);
+	gtk_adjustment_set_value (adjustment, f);
+}
+
+GConfValue *
+gnome_gconf_gtk_toggle_button_get (GtkToggleButton *toggle,
+				   GConfValueType   type)
+{
+	GConfValue *retval;
+
+	g_return_val_if_fail (toggle != NULL, NULL);
+	g_return_val_if_fail (GTK_IS_TOGGLE_BUTTON (toggle), NULL);
+	g_return_val_if_fail (((type == GCONF_VALUE_BOOL)||
+			       (type == GCONF_VALUE_INT)), NULL);
+
+	retval = gconf_value_new (type);
+	switch (type) {
+	case GCONF_VALUE_BOOL:
+		gconf_value_set_bool (retval, toggle->active);
+		break;
+	case GCONF_VALUE_INT:
+		gconf_value_set_int (retval, toggle->active);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+	return retval;
+}
+
+void
+gnome_gconf_gtk_toggle_button_set (GtkToggleButton *toggle,
+				   GConfValue      *value)
+{
+	g_return_if_fail (toggle != NULL);
+	g_return_if_fail (GTK_IS_TOGGLE_BUTTON (toggle));
+	g_return_if_fail (value != NULL);
+	g_return_if_fail ((value->type == GCONF_VALUE_BOOL)||
+			  (value->type == GCONF_VALUE_INT));
+
+	switch (value->type) {
+	case GCONF_VALUE_BOOL:
+		gtk_toggle_button_set_active (toggle, gconf_value_get_bool (value));
+		break;
+	case GCONF_VALUE_INT:
+		gtk_toggle_button_set_active (toggle, gconf_value_get_int (value));
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+}
+
+GConfValue *
+gnome_gconf_gnome_color_picker_get (GnomeColorPicker *picker,
+				    GConfValueType    type)
+{
+	GConfValue *retval;
+	gushort r, g, b, a;
+	gchar color[18];
+
+	g_return_val_if_fail (picker != NULL, NULL);
+	g_return_val_if_fail (GNOME_IS_COLOR_PICKER (picker), NULL);
+	g_return_val_if_fail ((type == GCONF_VALUE_STRING), NULL);
+
+	retval = gconf_value_new (type);
+	switch (type) {
+	case GCONF_VALUE_STRING:
+		gnome_color_picker_get_i16 (picker, &r, &g, &b, &a);
+		g_snprintf (color, 18, "#%04X%04X%04X%04X", r, g, b, a);
+		gconf_value_set_string (retval, color);
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+	return retval;
+}
+
+void
+gnome_gconf_gnome_color_picker_set (GnomeColorPicker *picker,
+				    GConfValue       *value)
+{
+	gushort r, g, b, a;
+	gchar *color;
+
+	g_return_if_fail (picker != NULL);
+	g_return_if_fail (GNOME_IS_COLOR_PICKER (picker));
+	g_return_if_fail (value != NULL);
+	g_return_if_fail (value->type == GCONF_VALUE_STRING);
+
+	color = g_strndup (gconf_value_get_string (value), 17);
+	a = strtol (color  + 13, (char **)NULL, 16);
+	*(color +13) = '\0';
+	b = strtol (color  + 9, (char **)NULL, 16);
+	*(color +9) = '\0';
+	g = strtol (color  + 5, (char **)NULL, 16);
+	*(color +5) = '\0';
+	r = strtol (color  + 1, (char **)NULL, 16);
+	gnome_color_picker_set_i16 (picker, r, g, b, a);
+	g_free (color);
+}
+
+gchar*
+gnome_gconf_get_gnome_libs_settings_relative (const gchar *subkey)
+{
+        gchar *dir;
+        gchar *key;
+
+        dir = g_strconcat("/apps/gnome-settings/",
+                          gnome_program_get_name(gnome_program_get()),
+                          NULL);
+
+        if (subkey && *subkey) {
+                key = gconf_concat_dir_and_key(dir, subkey);
+                g_free(dir);
+        } else {
+                /* subkey == "" */
+                key = dir;
+        }
+
+        return key;
+}
+
+gchar*
+gnome_gconf_get_app_settings_relative (const gchar *subkey)
+{
+        gchar *dir;
+        gchar *key;
+
+        dir = g_strconcat("/apps/",
+                          gnome_program_get_name(gnome_program_get()),
+                          NULL);
+
+        if (subkey && *subkey) {
+                key = gconf_concat_dir_and_key(dir, subkey);
+                g_free(dir);
+        } else {
+                /* subkey == "" */
+                key = dir;
+        }
+
+        return key;
+}
+
+/*
+ * Our global GConfClient, and module stuff
+ */
+static void gnome_default_gconf_client_error_handler (GConfClient                  *client,
+                                                      GError                       *error);
+
+
+static GConfClient* global_client = NULL;
+
+GConfClient*
+gnome_get_gconf_client (void)
+{
+        g_return_val_if_fail(global_client != NULL, NULL);
+        
+        return global_client;
+}
+
+static void
+gnome_gconf_pre_args_parse(GnomeProgram *app, const GnomeModuleInfo *mod_info)
+{
+        gconf_preinit(app, (GnomeModuleInfo*)mod_info);
+
+        gconf_client_set_global_default_error_handler(gnome_default_gconf_client_error_handler);
+}
+
+static void
+gnome_gconf_post_args_parse(GnomeProgram *app, const GnomeModuleInfo *mod_info)
+{
+        gchar *settings_dir;
+        
+        gconf_postinit(app, (GnomeModuleInfo*)mod_info);
+
+        global_client = gconf_client_get_default();
+
+        gconf_client_add_dir(global_client,
+                             "/desktop/gnome",
+                             GCONF_CLIENT_PRELOAD_NONE, NULL);
+
+        settings_dir = gnome_gconf_get_gnome_libs_settings_relative("");
+
+        gconf_client_add_dir(global_client,
+                             settings_dir,
+                             /* Possibly we should turn preload on for this */
+                             GCONF_CLIENT_PRELOAD_NONE,
+                             NULL);
+        g_free(settings_dir);
+}
+
+extern GnomeModuleInfo gtk_module_info;
+
+static GnomeModuleRequirement gnome_gconf_requirements[] = {
+        { "1.2.5", &gtk_module_info },
+        /* VERSION is also our version note - it's all libgnomeui */
+        { VERSION, &liboafgnome_module_info },
+        { NULL, NULL }
+};
+
+GnomeModuleInfo gnome_gconf_module_info = {
+        "gnome-gconf", VERSION, N_("GNOME GConf Support"),
+        gnome_gconf_requirements,
+        gnome_gconf_pre_args_parse, gnome_gconf_post_args_parse,
+        gconf_options
+};
+
+
+typedef struct {
+        GConfClient                  *client;
+} ErrorIdleData;
+
+static guint error_handler_idle = 0;
+static GSList *pending_errors = NULL;
+static ErrorIdleData eid = { NULL };
+
+static gint
+error_idle_func(gpointer data)
+{
+        GtkWidget *dialog;
+        GSList *iter;
+        gboolean have_overridden = FALSE;
+        gchar* mesg = NULL;
+        const gchar* fmt = NULL;
+        
+        error_handler_idle = 0;
+
+        g_return_val_if_fail(eid.client != NULL, FALSE);
+        g_return_val_if_fail(pending_errors != NULL, FALSE);
+        
+        iter = pending_errors;
+        while (iter != NULL) {
+                GError *error = iter->data;
+
+                if (g_error_matches (error, GCONF_ERROR, GCONF_ERROR_OVERRIDDEN))
+                        have_overridden = TRUE;
+                
+                iter = g_slist_next(iter);
+        }
+        
+        if (have_overridden) {
+                fmt = _("You attempted to change an aspect of your configuration that your system administrator or operating system vendor does not allow you to change. Some of the settings you have selected may not take effect, or may not be restored next time you use this application (%s).");
+                
+        } else {
+                fmt = _("An error occurred while loading or saving configuration information for %s. Some of your configuration settings may not work properly.");
+        }
+
+        mesg = g_strdup_printf(fmt, gnome_program_get_human_readable_name(gnome_program_get()));
+        
+        dialog = gnome_message_box_new(mesg,
+                                       GNOME_MESSAGE_BOX_ERROR,
+                                       GNOME_STOCK_BUTTON_OK,
+                                       NULL);
+
+        g_free(mesg);
+        
+        gtk_widget_show_all(dialog);
+
+
+        /* FIXME put this in a "Technical Details" optional part of the dialog
+           that can be opened up if users are interested */
+        iter = pending_errors;
+        while (iter != NULL) {
+                GError *error = iter->data;
+                iter->data = NULL;
+
+                fprintf(stderr, _("GConf error details: %s\n"), error->message);
+
+                g_error_free(error);
+                
+                iter = g_slist_next(iter);
+        }
+
+        g_slist_free(pending_errors);
+
+        pending_errors = NULL;
+        
+        g_object_unref(G_OBJECT(eid.client));
+        eid.client = NULL;
+
+        return FALSE;
+}
+
+static void
+gnome_default_gconf_client_error_handler (GConfClient                  *client,
+                                          GError                       *error)
+{
+        g_object_ref(G_OBJECT(client));
+        
+        if (eid.client) {
+                g_object_unref(G_OBJECT(eid.client));
+        }
+        
+        eid.client = client;
+        
+        pending_errors = g_slist_append(pending_errors, g_error_copy(error));
+
+        if (error_handler_idle == 0) {
+                error_handler_idle = gtk_idle_add(error_idle_func, NULL);
+        }
+}
+
+
diff --git a/libgnome/gnome-gconf.h b/libgnome/gnome-gconf.h
new file mode 100644
index 0000000..d596ae3
--- /dev/null
+++ b/libgnome/gnome-gconf.h
@@ -0,0 +1,87 @@
+/*  -*- Mode: C; c-set-style: linux; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/* GNOME GUI Library - gnome-gconf.h
+ * Copyright (C) 2000  Red Hat Inc.,
+ * All rights reserved.
+ *
+ * Author: Jonathan Blandford  <jrb redhat com>
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
+ */
+/*
+  @NOTATION@
+*/
+
+#ifndef GNOME_GCONF_H
+#define GNOME_GCONF_H
+
+#include <gconf/gconf-value.h>
+#include <gconf/gconf-client.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkrange.h>
+#include <gtk/gtkspinbutton.h>
+#include <gtk/gtktogglebutton.h>
+#include <gtk/gtkradiobutton.h>
+#include <libgnome/gnome-program.h>
+#include "gnome-color-picker.h"
+/* GTK Widgets */
+GConfValue *gnome_gconf_gtk_entry_get          (GtkEntry         *entry,
+						GConfValueType    type);
+void        gnome_gconf_gtk_entry_set          (GtkEntry         *entry,
+						GConfValue       *value);
+GConfValue *gnome_gconf_spin_button_get        (GtkSpinButton    *spin_button,
+						GConfValueType    type);
+void        gnome_gconf_spin_button_set        (GtkSpinButton   *spin_button,
+						GConfValue      *value);
+GConfValue *gnome_gconf_gtk_radio_button_get   (GtkRadioButton   *radio,
+						GConfValueType    type);
+void        gnome_gconf_gtk_radio_button_set   (GtkRadioButton   *radio,
+						GConfValue       *value);
+GConfValue *gnome_gconf_gtk_range_get          (GtkRange         *range,
+						GConfValueType    type);
+void        gnome_gconf_gtk_range_set          (GtkRange         *range,
+						GConfValue       *value);
+GConfValue *gnome_gconf_gtk_toggle_button_get  (GtkToggleButton  *toggle,
+						GConfValueType    type);
+void        gnome_gconf_gtk_toggle_button_set  (GtkToggleButton  *toggle,
+						GConfValue       *value);
+
+
+/* GNOME Widgets */
+GConfValue *gnome_gconf_gnome_color_picker_get (GnomeColorPicker *picker,
+						GConfValueType    type);
+void        gnome_gconf_gnome_color_picker_set (GnomeColorPicker *picker,
+						GConfValue       *value);
+/* Get keys relative to the gnome-libs internal per-app directory and the
+   application author per-app directory */
+gchar      *gnome_gconf_get_gnome_libs_settings_relative (const gchar *subkey);
+gchar      *gnome_gconf_get_app_settings_relative        (const gchar *subkey);
+
+/* GNOME GConf module; basically what this does is
+   create a global GConfClient for a GNOME application; it's used
+   by libgnomeui, and applications can either use it or create
+   their own. However note that signals will be emitted for
+   libgnomeui settings and errors! Also the module inits
+   GConf
+*/
+
+GConfClient *gnome_get_gconf_client (void);
+
+extern GnomeModuleInfo gnome_gconf_module_info;
+#define GNOME_GCONF_INIT GNOME_PARAM_MODULE,&gnome_gconf_module_info
+
+#endif
+
+
+
diff --git a/libgnome/gnome-i18n.c b/libgnome/gnome-i18n.c
new file mode 100644
index 0000000..ffef89d
--- /dev/null
+++ b/libgnome/gnome-i18n.c
@@ -0,0 +1,183 @@
+/*
+ * 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 <locale.h>	/* setlocale() */
+
+#include "libgnomeP.h"
+
+/* Name of config key we use when looking up preferred language. */
+#define LANGKEY "/Gnome/i18n/LANG"
+
+/**
+ * gnome_i18n_get_language:
+ * 
+ * Returns current language (contents of "LANG" environment variable).
+ * 
+ * Return value: 
+ **/
+const char *
+gnome_i18n_get_language(void)
+{
+  return g_getenv("LANG");
+}
+
+/**
+ * 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)
+{
+  g_warning (G_STRLOC ": This function is deprecated, "
+	     "use g_i18n_get_language_list instead.");
+
+#if 0
+  return g_i18n_get_language_list (category_name);
+#else
+  return NULL;
+#endif
+}
+
+/**
+ * gnome_i18n_set_preferred_language:
+ * @val: Preferred language
+ * 
+ * This sets the user's preferred language in the Gnome config
+ * database.  This value can always be overridden by the standard
+ * environment variables.  It exists so that a config applet which
+ * chooses the preferred language has a standard place to put the
+ * resulting information.
+ **/
+void
+gnome_i18n_set_preferred_language (const char *val)
+{
+  gnome_config_set_string (LANGKEY, val);
+}
+
+/**
+ * gnome_i18n_init:
+ * 
+ * Initialize the i18n environment variables (if not already set) from
+ * the Gnome config database.  Ordinarily this should not be called by
+ * user code.
+ **/
+void
+gnome_i18n_init (void)
+{
+#if 0
+  const gchar *val = g_i18n_guess_category_value ("LC_ALL");
+#else
+  const gchar *val = NULL;
+#endif
+
+  if (val == NULL)
+    {
+      /* No value in environment.  So we might set up environment
+	 according to what is in the config database.  We do this so
+	 that the user can override the config db using the
+	 environment.  */
+      val = gnome_config_get_string (LANGKEY);
+      if (val != NULL) 
+        {
+#ifdef HAVE_SETENV      
+	  setenv ("LC_ALL", val, 1);
+#else
+#ifdef HAVE_PUTENV
+	  /* It is not safe to free the value passed to putenv.  */
+	  putenv (g_strconcat ("LC_ALL=", val, NULL));
+#endif
+#endif
+	}
+    }
+}
+
+/**
+ * gnome_i18n_get_preferred_language:
+ * 
+ * Return value: the preferred language as set in the Gnome config database.
+ **/
+char *
+gnome_i18n_get_preferred_language (void)
+{
+  return gnome_config_get_string (LANGKEY);
+}
+
+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
new file mode 100644
index 0000000..c7adeb9
--- /dev/null
+++ b/libgnome/gnome-i18n.h
@@ -0,0 +1,123 @@
+/*
+ * 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 all of the internationalization configuration options.
+ * Author: Tom Tromey <tromey creche cygnus com>
+ */
+
+#ifndef __GNOME_I18N_H__
+#define __GNOME_I18N_H__ 1
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_DECLS
+
+#if !defined(__GNOME_I18NP_H__)
+
+#ifdef ENABLE_NLS
+#    include <libintl.h>
+#    ifdef GNOME_EXPLICIT_TRANSLATION_DOMAIN
+#        undef _
+#        define _(String) dgettext (GNOME_EXPLICIT_TRANSLATION_DOMAIN, String)
+#    else 
+#        define _(String) gettext (String)
+#    endif
+#    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
+
+#endif
+
+const char *	gnome_i18n_get_language			(void);
+
+/* '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);
+
+/* `gnome_i18n_set_preferred_language' sets the preferred language in
+   the config database.  The value VAL should be a language name like
+   `fr'.  */
+void		gnome_i18n_set_preferred_language	(const char *val);
+
+/* `gnome_i18n_get_preferred_language' returns the preferred language
+   name.  It will return NULL if no preference is set.  */
+char *		gnome_i18n_get_preferred_language	(void);
+
+/* 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);
+
+/* `gnome_i18n_init' initializes the i18n environment variables from
+   the preferences in the config database.  It ordinarily should not
+   be called by user code.  */
+void		gnome_i18n_init				(void);
+
+END_GNOME_DECLS
+
+#endif /* __GNOME_UTIL_H__ */
diff --git a/libgnome/gnome-i18nP.h b/libgnome/gnome-i18nP.h
new file mode 100644
index 0000000..4021cd4
--- /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 "libgnome/gnome-i18n.h"
+
+#endif /* __GNOME_I18NP_H__ */
diff --git a/libgnome/gnome-init.c b/libgnome/gnome-init.c
new file mode 100644
index 0000000..b2ad29b
--- /dev/null
+++ b/libgnome/gnome-init.c
@@ -0,0 +1,195 @@
+/* gnomelib-init.c - Implement libgnome module
+   Copyright (C) 1997, 1998, 1999 Free Software Foundation
+   Copyright (C) 1999, 2000 Red Hat, Inc.
+   All rights reserved.
+
+   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 <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 <pwd.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include "libgnomeP.h"
+#include <errno.h>
+
+#include <gobject/gobject.h>
+#include <gobject/gvaluetypes.h>
+
+#include <libgnomevfs/gnome-vfs-init.h>
+
+char *gnome_user_dir = NULL, *gnome_user_private_dir = NULL, *gnome_user_accels_dir = NULL;
+
+static void libgnome_post_args_parse(GnomeProgram *app, const GnomeModuleInfo *mod_info);
+static void libgnome_loadinit(const GnomeModuleInfo *mod_info);
+static void libgnome_option_cb(poptContext ctx, enum poptCallbackReason reason,
+			       const struct poptOption *opt, const char *arg,
+			       void *data);
+static void libgnome_userdir_setup(gboolean create_dirs);
+
+enum { ARG_VERSION=1 };
+
+static struct poptOption gnomelib_options[] = {
+        { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
+
+	{ NULL, '\0', POPT_ARG_CALLBACK, (void *) libgnome_option_cb, 0, NULL, NULL},
+
+	{"version", '\0', POPT_ARG_NONE, NULL, },
+
+	{ NULL, '\0', 0, NULL, 0 }
+};
+
+static GnomeModuleInfo gnome_vfs_module_info = {
+    "gnome-vfs", GNOMEVFSVERSION, "GNOME Virtual Filesystem",
+    NULL,
+    (GnomeModuleHook) gnome_vfs_preinit, (GnomeModuleHook) gnome_vfs_postinit,
+    NULL,
+    (GnomeModuleInitHook) gnome_vfs_loadinit,
+    NULL
+};
+
+static GnomeModuleRequirement libgnome_requirements[] = {
+  {"0.3.0", &gnome_vfs_module_info},
+  {NULL}
+};
+
+GnomeModuleInfo libgnome_module_info = {
+  "libgnome", VERSION, "GNOME Library",
+  libgnome_requirements,
+  NULL, libgnome_post_args_parse,
+  gnomelib_options,
+  libgnome_loadinit
+};
+
+static void
+libgnome_post_args_parse (GnomeProgram *program,
+			  const GnomeModuleInfo *mod_info)
+{
+    GValue value = { 0, };
+    gboolean create_dirs_val;
+
+    g_value_init (&value, G_TYPE_BOOLEAN);
+    g_object_get_property (G_OBJECT (program), "create-directories", &value);
+    create_dirs_val = g_value_get_boolean (&value);
+    g_value_unset (&value);
+
+    gnome_triggers_init ();
+
+    libgnome_userdir_setup (create_dirs_val);
+
+    setlocale (LC_ALL, "");
+    /* XXX todo - handle multiple installation dirs */
+    bindtextdomain (PACKAGE, GNOMELOCALEDIR);
+    gnome_i18n_init ();
+}
+
+static void
+libgnome_loadinit (const GnomeModuleInfo *mod_info)
+{
+    /* Initialize threads. */
+    g_thread_init (NULL);
+}
+
+static void
+libgnome_option_cb (poptContext ctx, enum poptCallbackReason reason,
+		    const struct poptOption *opt, const char *arg,
+		    void *data)
+{
+    GnomeProgram *program;
+
+    program = gnome_program_get ();
+	
+    switch(reason) {
+    case POPT_CALLBACK_REASON_OPTION:
+	switch(opt->val) {
+	case ARG_VERSION:
+	    g_print ("Gnome %s %s\n",
+		     gnome_program_get_name (program),
+		     gnome_program_get_version (program));
+	    exit(0);
+	    break;
+	}
+    default:
+	/* do nothing */
+	break;
+    }
+}
+
+static void
+libgnome_userdir_setup (gboolean create_dirs)
+{
+    if(!gnome_user_dir) {
+	gnome_user_dir = g_concat_dir_and_file (g_get_home_dir(), ".gnome");
+	gnome_user_private_dir = g_concat_dir_and_file (g_get_home_dir(),
+							".gnome_private");
+	gnome_user_accels_dir = g_concat_dir_and_file (gnome_user_dir, "accels");
+    }
+
+    if (!create_dirs)
+	return;
+	
+    if (mkdir (gnome_user_dir, 0700) < 0) { /* private permissions, but we
+					       don't check that we got them */
+	if (errno != EEXIST) {
+	    fprintf(stderr, _("Could not create per-user gnome configuration directory `%s': %s\n"),
+		    gnome_user_dir, strerror(errno));
+	    exit(1);
+	}
+    }
+    
+  if (mkdir (gnome_user_private_dir, 0700) < 0) { /* This is private
+						     per-user info mode
+						     700 will be
+						     enforced!  maybe
+						     even other security
+						     meassures will be
+						     taken */
+      if (errno != EEXIST) {
+	  fprintf (stderr, _("Could not create per-user gnome configuration directory `%s': %s\n"),
+		   gnome_user_private_dir, strerror(errno));
+	  exit(1);
+      }
+  }
+
+
+  /* change mode to 0700 on the private directory */
+  if (chmod (gnome_user_private_dir, 0700) < 0) {
+      fprintf(stderr, _("Could not set mode 0700 on private per-user gnome configuration directory `%s': %s\n"),
+	      gnome_user_private_dir, strerror(errno));
+      exit(1);
+  }
+  
+  if (mkdir (gnome_user_accels_dir, 0700) < 0) {
+      if (errno != EEXIST) {
+	  fprintf(stderr, _("Could not create gnome accelerators directory `%s': %s\n"),
+		  gnome_user_accels_dir, strerror(errno));
+	  exit(1);
+      }
+  }
+}
+
+
diff --git a/libgnome/gnome-macros.h b/libgnome/gnome-macros.h
new file mode 100644
index 0000000..2f31cdb
--- /dev/null
+++ b/libgnome/gnome-macros.h
@@ -0,0 +1,74 @@
+/* gnome-macros.h
+ *   Macros for making GTK+ objects to avoid typos and reduce code size
+ * Copyright (C) 2000  Eazel, Inc.
+ *
+ * Authors: George Lebl <jirka 5z com>
+ *
+ * All rights reserved.
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+*/
+
+#ifndef GNOME_MACROS_H
+#define GNOME_MACROS_H
+
+/* Macros for defining classes.  Ideas taken from Nautilus and GOB. */
+
+/* Define the boilerplate type stuff to reduce typos and code size.  Defines
+ * the get_type method and the parent_class static variable. */
+#define GNOME_CLASS_BOILERPLATE(type, type_as_function,			\
+				parent_type, parent_type_as_function)	\
+static parent_type *parent_class = NULL;				\
+GtkType									\
+type_as_function ## _get_type (void)					\
+{									\
+	static GtkType object_type = 0;					\
+	if (object_type == 0) {						\
+		GtkType type_of_parent;					\
+		static const GtkTypeInfo object_info = {		\
+			#type,						\
+			sizeof (type),					\
+			sizeof (type ## Class),				\
+			(GtkClassInitFunc) type_as_function ## _class_init, \
+			(GtkObjectInitFunc) type_as_function ## _init,	\
+			/* reserved_1 */ NULL,				\
+			/* reserved_2 */ NULL,				\
+			(GtkClassInitFunc) NULL				\
+		};							\
+		type_of_parent = parent_type_as_function ## _get_type (); \
+		object_type = gtk_type_unique (type_of_parent, &object_info); \
+		parent_class = gtk_type_class (type_of_parent);		\
+	}								\
+	return object_type;						\
+}
+
+/* Just call the parent handler.  This assumes that there is a variable
+ * named parent_class that points to the (duh!) parent class */
+#define GNOME_CALL_PARENT_HANDLER(parent_class_cast, name, args)	\
+	((parent_class_cast(parent_class)->name != NULL) ?		\
+	 parent_class_cast(parent_class)->name args : 0)
+
+/* Same as above, but in case there is no implementation, it evaluates
+ * to def_return */
+#define GNOME_CALL_PARENT_HANDLER_WITH_DEFAULT(parent_class_cast,	\
+					       name, args, def_return)	\
+	((parent_class_cast(parent_class)->name != NULL) ?		\
+	 parent_class_cast(parent_class)->name args : def_return)
+
+#endif /* GNOME_MACROS_H */
diff --git a/libgnome/gnome-marshal-main.c b/libgnome/gnome-marshal-main.c
new file mode 100644
index 0000000..b9a9f63
--- /dev/null
+++ b/libgnome/gnome-marshal-main.c
@@ -0,0 +1,32 @@
+/* -*- Mode: C; c-set-style: gnu indent-tabs-mode: t; c-basic-offset: 4; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2000 SuSE GmbH
+ * Author: Martin Baulig <baulig suse de>
+ *
+ * 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 "libgnomeuiP.h"
+
+#include <gobject/genums.h>
+#include <gobject/gvaluetypes.h>
+
+#include "gnomemarshal.c"
diff --git a/libgnome/gnome-marshal.list b/libgnome/gnome-marshal.list
new file mode 100644
index 0000000..57116df
--- /dev/null
+++ b/libgnome/gnome-marshal.list
@@ -0,0 +1,18 @@
+VOID:DOUBLE
+VOID:UINT
+VOID:INT,BOXED
+VOID:STRING,INT
+VOID:STRING,INT,BOXED
+VOID:STRING,INT,UINT,BOXED
+VOID:POINTER,INT,BOOLEAN,BOXED
+VOID:UINT,UINT,UINT,UINT
+VOID:STRING,BOXED
+INT:VOID
+ENUM:VOID
+BOOLEAN:OBJECT
+BOOLEAN:INT,STRING
+BOOLEAN:INT,ENUM,BOOLEAN,ENUM,BOOLEAN
+POINTER:INT,INT
+POINTER:BOOLEAN
+POINTER:VOID
+STRING:VOID
diff --git a/libgnome/gnome-moz-remote.c b/libgnome/gnome-moz-remote.c
new file mode 100644
index 0000000..2d146f3
--- /dev/null
+++ b/libgnome/gnome-moz-remote.c
@@ -0,0 +1,907 @@
+/* -*- Mode:C; tab-width: 8 -*- */
+/* gnome-moz-remote.c -- open a URL in a current netscape, or start a new
+ *    copy of netscape, pointing at the given page.
+ * This is a modified version of http://home.netscape.com/newsref/std/remote.c
+ * You can find documentation of --remote commands at
+ *   http://home.netscape.com/newsref/std/x-remote.html
+ * My changes fall under the GPL2 (where the previous license allows).  The
+ * original copyright message follows:
+ */
+/* remote.c --- remote control of Netscape Navigator for Unix.
+ * version 1.1.3, for Netscape Navigator 1.1 and newer.
+ *
+ * Copyright © 1996 Netscape Communications Corporation, all rights reserved.
+ * Created: Jamie Zawinski <jwz netscape com>, 24-Dec-94.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ *
+ * To compile:
+ *
+ *    cc -o netscape-remote remote.c -DSTANDALONE -lXmu -lX11
+ *
+ * To use:
+ *
+ *    netscape-remote -help
+ *
+ * Documentation for the protocol which this code implements may be found at:
+ *
+ *    http://home.netscape.com/newsref/std/x-remote.html
+ *
+ * Bugs and commentary to x_cbug netscape com 
+ */
+/*
+  @NOTATION@
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gnomesupport.h"
+#include <libgnome/libgnome.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+
+/* vroot.h is a header file which lets a client get along with `virtual root'
+   window managers like swm, tvtwm, olvwm, etc.  If you don't have this header
+   file, you can find it at "http://home.netscape.com/newsref/std/vroot.h";.
+   If you don't care about supporting virtual root window managers, you can
+   comment this line out.
+ */
+#include "vroot.h"
+
+static void
+parseAnArg(poptContext ctx,
+	   enum poptCallbackReason reason,
+	   const struct poptOption *opt,
+	   const char *arg, void *data);
+
+#define MOZILLA_VERSION_PROP   "_MOZILLA_VERSION"
+#define MOZILLA_LOCK_PROP      "_MOZILLA_LOCK"
+#define MOZILLA_COMMAND_PROP   "_MOZILLA_COMMAND"
+#define MOZILLA_RESPONSE_PROP  "_MOZILLA_RESPONSE"
+static Atom XA_MOZILLA_VERSION  = 0;
+static Atom XA_MOZILLA_LOCK     = 0;
+static Atom XA_MOZILLA_COMMAND  = 0;
+static Atom XA_MOZILLA_RESPONSE = 0;
+
+/* these are needed for the machine check and client list check */
+#define WM_STATE_PROP                  "WM_STATE"
+#define GNOME_SUPPORTING_WM_CHECK_PROP "_WIN_SUPPORTING_WM_CHECK"
+#define GNOME_PROTOCOLS_PROP           "_WIN_PROTOCOLS"
+#define GNOME_CLIENT_LIST_PROP         "_WIN_CLIENT_LIST"
+static Atom XA_WM_STATE                = 0;
+static Atom XA_WIN_SUPPORTING_WM_CHECK = 0;
+static Atom XA_WIN_PROTOCOLS           = 0;
+static Atom XA_WIN_CLIENT_LIST         = 0;
+
+static void
+mozilla_remote_init_atoms (Display *dpy)
+{
+  if (! XA_MOZILLA_VERSION)
+    XA_MOZILLA_VERSION = XInternAtom (dpy, MOZILLA_VERSION_PROP, False);
+  if (! XA_MOZILLA_LOCK)
+    XA_MOZILLA_LOCK = XInternAtom (dpy, MOZILLA_LOCK_PROP, False);
+  if (! XA_MOZILLA_COMMAND)
+    XA_MOZILLA_COMMAND = XInternAtom (dpy, MOZILLA_COMMAND_PROP, False);
+  if (! XA_MOZILLA_RESPONSE)
+    XA_MOZILLA_RESPONSE = XInternAtom (dpy, MOZILLA_RESPONSE_PROP, False);
+
+  if (! XA_WM_STATE)
+    XA_WM_STATE = XInternAtom (dpy, WM_STATE_PROP, False);
+  if (! XA_WIN_SUPPORTING_WM_CHECK)
+    XA_WIN_SUPPORTING_WM_CHECK = XInternAtom (dpy, GNOME_SUPPORTING_WM_CHECK_PROP, False);
+  if (! XA_WIN_PROTOCOLS)
+    XA_WIN_PROTOCOLS = XInternAtom (dpy, GNOME_PROTOCOLS_PROP, False);
+  if (! XA_WIN_CLIENT_LIST)
+    XA_WIN_CLIENT_LIST = XInternAtom (dpy, GNOME_CLIENT_LIST_PROP, False);
+}
+
+/* returns true if the window manager supports the _WIN_CLIENT_LIST
+ * gnome wm hint */
+static Bool
+gnomewm_check_wm(Display *dpy)
+{
+  Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
+  Atom r_type;
+  int r_format;
+  unsigned long count, i;
+  unsigned long bytes_remain;
+  unsigned char *prop, *prop2, *prop3;
+
+  if (XGetWindowProperty(dpy, root,
+                         XA_WIN_SUPPORTING_WM_CHECK, 0, 1, False, XA_CARDINAL,
+                         &r_type, &r_format,
+                         &count, &bytes_remain, &prop) == Success && prop) {
+    if (r_type == XA_CARDINAL && r_format == 32 && count == 1) {
+      Window n = *(long *)prop;
+      if (XGetWindowProperty(dpy, n,
+			     XA_WIN_SUPPORTING_WM_CHECK, 0, 1, False, 
+			     XA_CARDINAL,
+			     &r_type, &r_format, &count, &bytes_remain, 
+			     &prop2) == Success && prop2) {
+	if (r_type == XA_CARDINAL && r_format == 32 && count == 1) {
+	  if (XGetWindowProperty(dpy, root,
+				 XA_WIN_PROTOCOLS, 0,0x7fffffff,False, XA_ATOM,
+				 &r_type, &r_format, &count, &bytes_remain,
+				 &prop3) == Success && prop3) {
+	    if (r_type == XA_ATOM && r_format == 32) {
+	      /* I heard George saying format==32 requires this type */
+	      unsigned long *list = (unsigned long *)prop3;
+	      XFree(prop);
+	      XFree(prop2);
+
+	      for (i = 0; i < count; i++)
+		if (list[i] == XA_WIN_CLIENT_LIST) {
+		  XFree(prop3);
+		  return TRUE;
+		}
+	    }
+	    XFree(prop3);
+	  }
+	}
+	XFree(prop2);
+      }       
+    }
+    XFree(prop);
+  }
+  return FALSE;
+}
+
+static char localhostname[1024] = "\0";
+
+/* this function is called on each client window to deduce whether it is
+ * a mozilla window (by checking the _MOZILLA_VERSION property) and, if
+ * isLocal is set, it is a local copy of netscape (by checking if the
+ * WM_CLIENT_MACHINE property is set to the local hostname).
+ */
+static Bool
+mozilla_remote_test_window(Display *dpy, Window win, Bool isLocal)
+{
+  Atom type;
+  int format, status;
+  unsigned long nitems, bytesafter;
+  unsigned char *version = 0, *hostname = 0;
+
+  g_assert(win != 0);
+  status = XGetWindowProperty (dpy, win, XA_MOZILLA_VERSION,
+			       0, (65536 / sizeof (long)),
+			       False, XA_STRING,
+			       &type, &format, &nitems, &bytesafter,
+			       &version);
+  if (! version)
+    return False;
+  XFree (version);
+  if (status != Success || type == None)
+    return False;
+  if (!isLocal) {
+    /* for non-local URLs, any netscape prog is good enough */
+    return True;
+  }
+  status = XGetWindowProperty (dpy, win, XA_WM_CLIENT_MACHINE,
+			       0, 0x7fffffff, False, XA_STRING,
+			       &type, &format, &nitems, &bytesafter,
+			       &hostname);
+  if (! hostname || status != Success || type == None) {
+    if (hostname) XFree(hostname);
+    return False;
+  }
+  if (! g_strcasecmp(hostname, localhostname)) {
+    XFree(hostname);
+    return True;
+  }
+  XFree(hostname);
+  return False;
+}
+
+/* This function uses the _WIN_CLIENT_LIST GNOME window manager hint to find
+ * the list of client windows.  It then calls mozilla_remote_test_window on
+ * each until it finds a matching mozilla window
+ */
+static Window
+gnomewm_find_window(Display *dpy, Bool isLocal)
+{
+  Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
+  Atom r_type;
+  int r_format;
+  unsigned long count, i;
+  unsigned long bytes_remain, *wins;
+  unsigned char *prop;
+
+  XGetWindowProperty(dpy, root, XA_WIN_CLIENT_LIST,
+		     0, 0x7fffffff, False, XA_CARDINAL,
+		     &r_type, &r_format, &count, &bytes_remain, &prop);
+  if (!prop || count <= 0 || r_type != XA_CARDINAL || r_format != 32) {
+    if (prop) XFree(prop);
+    return 0;
+  }
+  wins = (unsigned long *)prop;
+  for (i = 0; i < count; i++)
+    if (mozilla_remote_test_window(dpy, wins[i], isLocal)) {
+      Window ret = wins[i];
+      XFree(prop);
+      return ret;
+    }
+  XFree(prop);
+  return 0;
+}
+
+/* this function recurses down the X window heirachy, finding windows with the
+ * WM_STATE property set (which indicates that we have a client window), and
+ * calls mozilla_remote_test_window on each until it finds a match
+ */
+static Window
+mozilla_remote_find_window_recurse(Display *dpy, Window win,
+				   Bool isLocal)
+{
+  Atom r_type;
+  int r_format;
+  unsigned long count, after;
+  unsigned char *data;
+
+  XGetWindowProperty(dpy, win, XA_WM_STATE, 0, 0, False, AnyPropertyType,
+		     &r_type, &r_format, &count, &after, &data);
+  if (r_type) {
+    /* this is a client window */
+    XFree(data);
+    if (mozilla_remote_test_window(dpy, win, isLocal))
+      return win;
+    else
+      return 0;
+  } else {
+    Window ret_root, ret_parent, *ret_children;
+    unsigned int ret_nchildren, i;
+
+    if (XQueryTree(dpy, win, &ret_root, &ret_parent,
+		   &ret_children, &ret_nchildren) != True)
+      return 0;
+    for (i = 0; i < ret_nchildren; i++) {
+      Window check = mozilla_remote_find_window_recurse(dpy, ret_children[i],
+							isLocal);
+      if (check) {
+	XFree(ret_children);
+	return check;
+      }
+    }
+  }
+  return 0;
+}
+
+/* this function finds the first matching mozilla window (using GNOME WM
+ * hints or querying the X window heirachy) and returns it
+ */
+static Window
+mozilla_remote_find_window (Display *dpy, Bool isLocal)
+{
+  Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
+
+  if (isLocal && gethostname(localhostname, sizeof(localhostname)) < 0)
+    return 0;
+
+  if (gnomewm_check_wm(dpy))
+    return gnomewm_find_window(dpy, isLocal);
+  else
+    return mozilla_remote_find_window_recurse(dpy, root, isLocal);
+}
+
+static void
+mozilla_remote_check_window (Display *dpy, Window window)
+{
+  Atom type;
+  int format, status;
+  unsigned long nitems, bytesafter;
+  unsigned char *version = 0;
+
+  g_return_if_fail(window != 0);
+  status = XGetWindowProperty (dpy, window, XA_MOZILLA_VERSION,
+				   0, (65536 / sizeof (long)),
+				   False, XA_STRING,
+				   &type, &format, &nitems, &bytesafter,
+				   &version);
+  if (status != Success || !version)
+    {
+      g_printerr("gnome-moz-remote: window 0x%x is not a Netscape window.\n",
+		 (unsigned int) window);
+      exit (6);
+    }
+  XFree (version);
+}
+
+
+static char *lock_data = 0;
+
+static void
+mozilla_remote_obtain_lock (Display *dpy, Window window)
+{
+  Bool locked = False;
+  Bool waited = False;
+
+  g_return_if_fail(window != 0);
+  if (! lock_data)
+    {
+      lock_data = (char *) malloc (255);
+      g_snprintf (lock_data, 255, "pid%d@", getpid ());
+
+      if (gethostname (lock_data + strlen (lock_data), 100))
+	{
+	  perror ("gethostname");
+	  exit (-1);
+	}
+    }
+
+  do
+    {
+      int result;
+      Atom actual_type;
+      int actual_format;
+      unsigned long nitems, bytes_after;
+      unsigned char *data = 0;
+
+      XGrabServer (dpy);   /* ################################# DANGER! */
+
+      result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
+				   0, (65536 / sizeof (long)),
+				   False, /* don't delete */
+				   XA_STRING,
+				   &actual_type, &actual_format,
+				   &nitems, &bytes_after,
+				   &data);
+      if (result != Success || actual_type == None)
+	{
+	  /* It's not now locked - lock it. */
+#ifdef DEBUG_PROPS
+	  g_printerr("gnome-moz-remote: (writing " MOZILLA_LOCK_PROP
+		     " \"%s\" to 0x%x)\n"
+		     lock_data, (unsigned int) window);
+#endif
+	  XChangeProperty (dpy, window, XA_MOZILLA_LOCK, XA_STRING, 8,
+			   PropModeReplace, (unsigned char *) lock_data,
+			   strlen (lock_data));
+	  locked = True;
+	}
+
+      XUngrabServer (dpy); /* ################################# danger over */
+      XSync (dpy, False);
+
+      if (! locked)
+	{
+	  /* We tried to grab the lock this time, and failed because someone
+	     else is holding it already.  So, wait for a PropertyDelete event
+	     to come in, and try again. */
+
+	  g_printerr("gnome-moz-remote: window 0x%x is locked by %s; waiting...\n",
+		     (unsigned int) window, data);
+	  waited = True;
+
+	  while (1)
+	    {
+	      XEvent event;
+	      XNextEvent (dpy, &event);
+	      if (event.xany.type == DestroyNotify &&
+		  event.xdestroywindow.window == window)
+		{
+		  g_printerr("gnome-moz-remote: window 0x%x unexpectedly destroyed.\n",
+			      (unsigned int) window);
+		  exit (6);
+		}
+	      else if (event.xany.type == PropertyNotify &&
+		       event.xproperty.state == PropertyDelete &&
+		       event.xproperty.window == window &&
+		       event.xproperty.atom == XA_MOZILLA_LOCK)
+		{
+		  /* Ok!  Someone deleted their lock, so now we can try
+		     again. */
+#ifdef DEBUG_PROPS
+		  g_printerr("gnome-moz-remote: (0x%x unlocked, trying again...)\n",
+			     (unsigned int) window);
+#endif
+		  break;
+		}
+	    }
+	}
+      if (data)
+	XFree (data);
+    }
+  while (! locked);
+
+  if (waited)
+    g_printerr("gnome-moz-remote: obtained lock.\n");
+}
+
+
+static void
+mozilla_remote_free_lock (Display *dpy, Window window)
+{
+  int result;
+  Atom actual_type;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  unsigned char *data = 0;
+
+  g_return_if_fail(window != 0);
+#ifdef DEBUG_PROPS
+  g_printerr("gnome-moz-remote: (deleting " MOZILLA_LOCK_PROP
+	     " \"%s\" from 0x%x)\n",
+	     lock_data, (unsigned int) window);
+#endif
+
+  result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
+			       0, (65536 / sizeof (long)),
+			       True, /* atomic delete after */
+			       XA_STRING,
+			       &actual_type, &actual_format,
+			       &nitems, &bytes_after,
+			       &data);
+  if (result != Success)
+    {
+      g_printerr("gnome-moz-remote: unable to read and delete "
+		 MOZILLA_LOCK_PROP " property\n");
+      return;
+    }
+  else if (!data || !*data)
+    {
+      g_printerr("gnome-moz-remote: invalid data on " MOZILLA_LOCK_PROP
+		 " of window 0x%x.\n",
+		 (unsigned int) window);
+      return;
+    }
+  else if (strcmp ((char *) data, lock_data))
+    {
+      g_printerr("gnome-moz-remote: " MOZILLA_LOCK_PROP
+		 " was stolen!  Expected \"%s\", saw \"%s\"!\n",
+		 lock_data, data);
+      return;
+    }
+
+  if (data)
+    XFree (data);
+}
+
+
+static int
+mozilla_remote_command (Display *dpy, Window window, const char *command,
+			Bool raise_p)
+{
+  int result = 0;
+  Bool done = False;
+  char *new_command = 0;
+
+  g_return_val_if_fail(window != 0, 1);
+  /* The -noraise option is implemented by passing a "noraise" argument
+     to each command to which it should apply.
+   */
+  if (! raise_p)
+    {
+      char *close;
+      new_command = (char *) malloc (strlen (command) + 20);
+      strcpy (new_command, command);
+      close = strrchr (new_command, ')');
+      if (close)
+	strcpy (close, ", noraise)");
+      else
+	strcat (new_command, "(noraise)");
+      command = new_command;
+    }
+
+#ifdef DEBUG_PROPS
+  g_printerr("gnome-moz-remote: (writing " MOZILLA_COMMAND_PROP
+	     " \"%s\" to 0x%x)\n", command, (unsigned int) window);
+#endif
+
+  XChangeProperty (dpy, window, XA_MOZILLA_COMMAND, XA_STRING, 8,
+		   PropModeReplace, (unsigned char *) command,
+		   strlen (command));
+
+  while (!done)
+    {
+      XEvent event;
+      XNextEvent (dpy, &event);
+      if (event.xany.type == DestroyNotify &&
+	  event.xdestroywindow.window == window)
+	{
+	  /* Print to warn user...*/
+	  g_printerr("gnome-moz-remote: window 0x%x was destroyed.\n",
+		     (unsigned int) window);
+	  result = 6;
+	  goto DONE;
+	}
+      else if (event.xany.type == PropertyNotify &&
+	       event.xproperty.state == PropertyNewValue &&
+	       event.xproperty.window == window &&
+	       event.xproperty.atom == XA_MOZILLA_RESPONSE)
+	{
+	  Atom actual_type;
+	  int actual_format;
+	  unsigned long nitems, bytes_after;
+	  unsigned char *data = 0;
+
+	  result = XGetWindowProperty (dpy, window, XA_MOZILLA_RESPONSE,
+				       0, (65536 / sizeof (long)),
+				       True, /* atomic delete after */
+				       XA_STRING,
+				       &actual_type, &actual_format,
+				       &nitems, &bytes_after,
+				       &data);
+#ifdef DEBUG_PROPS
+	  if (result == Success && data && *data)
+	    {
+	      g_printerr("gnome-moz-remote: (server sent "MOZILLA_RESPONSE_PROP
+			 " \"%s\" to 0x%x.)\n",
+			 data, (unsigned int) window);
+	    }
+#endif
+
+	  if (result != Success)
+	    {
+	      g_printerr("gnome-moz-remote: failed reading "
+			 MOZILLA_RESPONSE_PROP " from window 0x%0x.\n",
+			 (unsigned int) window);
+	      result = 6;
+	      done = True;
+	    }
+	  else if (!data || strlen((char *) data) < 5)
+	    {
+	      g_printerr("gnome-moz-remote: invalid data on "
+			 MOZILLA_RESPONSE_PROP " property of window 0x%0x.\n",
+			 (unsigned int) window);
+	      result = 6;
+	      done = True;
+	    }
+	  else if (*data == '1')	/* positive preliminary reply */
+	    {
+	      g_printerr("gnome-moz-remote: %s\n", data + 4);
+	      /* keep going */
+	      done = False;
+	    }
+#if 1
+	  else if (!strncmp ((char *)data, "200", 3)) /* positive completion */
+	    {
+	      result = 0;
+	      done = True;
+	    }
+#endif
+	  else if (*data == '2')		/* positive completion */
+	    {
+	      g_printerr("gnome-moz-remote: %s\n", data + 4);
+	      result = 0;
+	      done = True;
+	    }
+	  else if (*data == '3')	/* positive intermediate reply */
+	    {
+	      g_printerr("gnome-moz-remote: internal error: "
+			 "server wants more information?  (%s)\n",
+			 data);
+	      result = 3;
+	      done = True;
+	    }
+	  else if (*data == '4' ||	/* transient negative completion */
+		   *data == '5')	/* permanent negative completion */
+	    {
+	      g_printerr("gnome-moz-remote: %s\n", data + 4);
+	      result = (*data - '0');
+	      done = True;
+	    }
+	  else
+	    {
+	      g_printerr(
+		       "gnome-moz-remote: unrecognised " MOZILLA_RESPONSE_PROP
+		       " from window 0x%x: %s\n",
+		       (unsigned int) window, data);
+	      result = 6;
+	      done = True;
+	    }
+
+	  if (data)
+	    XFree (data);
+	}
+#ifdef DEBUG_PROPS
+      else if (event.xany.type == PropertyNotify &&
+	       event.xproperty.window == window &&
+	       event.xproperty.state == PropertyDelete &&
+	       event.xproperty.atom == XA_MOZILLA_COMMAND)
+	{
+	  g_printerr("gnome-moz-remote: (server 0x%x has accepted "
+		   MOZILLA_COMMAND_PROP ".)\n",
+		   (unsigned int) window);
+	}
+#endif /* DEBUG_PROPS */
+    }
+
+ DONE:
+
+  if (new_command)
+    free (new_command);
+
+  return result;
+}
+
+static int
+mozilla_remote_commands (Display *dpy, Window window,
+			 char **commands, Bool isLocal)
+{
+  Bool raise_p = True;
+  int status = 0;
+  mozilla_remote_init_atoms (dpy);
+
+  if (window == 0)
+    window = mozilla_remote_find_window (dpy, isLocal);
+  else
+    mozilla_remote_check_window (dpy, window);
+  g_return_val_if_fail(window != 0, 1);
+
+  XSelectInput (dpy, window, (PropertyChangeMask|StructureNotifyMask));
+
+  mozilla_remote_obtain_lock (dpy, window);
+
+  while (*commands)
+    {
+      if (!strcmp (*commands, "-raise"))
+	raise_p = True;
+      else if (!strcmp (*commands, "-noraise"))
+	raise_p = False;
+      else
+	status = mozilla_remote_command (dpy, window, *commands, raise_p);
+
+      if (status != 0)
+	break;
+      commands++;
+    }
+
+  /* When status = 6, it means the window has been destroyed */
+  /* It is invalid to free the lock when window is destroyed. */
+
+  if ( status != 6 )
+  mozilla_remote_free_lock (dpy, window);
+
+  return status;
+}
+
+
+static int
+mozilla_remote_cmd(Display *dpy, Window window, char *command,
+		   Bool raise_p, Bool isLocal)
+{
+  int status = 0;
+
+  mozilla_remote_init_atoms(dpy);
+  if (window == 0)
+    window = mozilla_remote_find_window(dpy, isLocal);
+  else
+    mozilla_remote_check_window(dpy, window);
+  if (window == 0)
+    return 1;
+  XSelectInput(dpy, window, (PropertyChangeMask|StructureNotifyMask));
+  mozilla_remote_obtain_lock(dpy, window);
+  status = mozilla_remote_command(dpy, window, command, raise_p);
+  if (status != 6)
+    mozilla_remote_free_lock(dpy, window);
+  return status;
+}
+
+static struct poptOption x_options[] = {
+  { NULL, '\0', POPT_ARG_CALLBACK, parseAnArg, 0, NULL, NULL},
+  {"display", '\0', POPT_ARG_STRING, NULL, -6, "Specify X display to use.", "DISPLAY"},
+  {"id", '\0', POPT_ARG_STRING, NULL, -7, "Specify the X window ID of Netscape.", "WIN-ID"},
+  {"sync", '\0', POPT_ARG_NONE, NULL, -8, "Put X connection in synchronous mode.", NULL},
+  {NULL, '\0', 0, NULL, 0}
+};
+
+static struct poptOption options[] = {
+  { NULL, '\0', POPT_ARG_CALLBACK|POPT_CBFLAG_POST, parseAnArg, 0, NULL, NULL},
+  { "version", 'V', POPT_ARG_NONE, NULL, -42, "Display version", NULL },
+  { "remote", '\0', POPT_ARG_STRING, NULL, -1, "Execute a command inside Netscape", "CMD"},
+  {"raise", '\0', POPT_ARG_NONE, NULL, -2, "Raise the Netscape window after commands.", NULL},
+  {"noraise", '\0', POPT_ARG_NONE, NULL, -3, "Don't raise the Netscape window.", NULL},
+  {"newwin", '\0', POPT_ARG_NONE, NULL, -4, "Show the given URL in a new window", NULL},
+  {"local", '\0', POPT_ARG_NONE, NULL, -5, "Copy of netscape must be local", NULL},
+  {NULL, '\0', POPT_ARG_INCLUDE_TABLE, x_options, 0, "X Options", NULL},
+  {NULL, '\0', 0, NULL, 0}
+};
+
+char *dpy_string = NULL, *url_string = NULL;
+char **remote_commands = NULL;
+int remote_command_count = 0;
+int remote_command_size = 0;
+unsigned long remote_window = 0;
+Bool sync_p = False, raise_p = False, isLocal = False;
+gboolean new_window = FALSE;
+int i;
+
+static void
+parseAnArg(poptContext ctx,
+	   enum poptCallbackReason reason,
+	   const struct poptOption *opt,
+	   const char *arg, void *data)
+{
+  char c;
+
+  if (reason == POPT_CALLBACK_REASON_POST) {
+    url_string = poptGetArg(ctx);
+    return;
+  }
+  /* reason == POPT_CALLBACK_REASON_OPTION */
+  switch (opt->val) {
+  case -1: /* --remote */
+    if (remote_command_count == remote_command_size) {
+      remote_command_size += 20;
+      remote_commands =
+	(remote_commands
+	 ? realloc(remote_commands, remote_command_size * sizeof(char *))
+	 : calloc(remote_command_size, sizeof(char *)));
+    }
+    remote_commands[remote_command_count++] = (char *)arg;
+    break;
+  case -2: /* --raise */
+    if (remote_command_count == remote_command_size) {
+      remote_command_size += 20;
+      remote_commands =
+	(remote_commands
+	 ? realloc(remote_commands, remote_command_size * sizeof(char *))
+	 : calloc(remote_command_size, sizeof(char *)));
+    }
+    remote_commands[remote_command_count++] = "-raise";
+    raise_p = True;
+    break;
+  case -3: /* --noraise */
+    if (remote_command_count == remote_command_size) {
+      remote_command_size += 20;
+      remote_commands =
+	(remote_commands
+	 ? realloc(remote_commands, remote_command_size * sizeof(char *))
+	 : calloc(remote_command_size, sizeof(char *)));
+    }
+    remote_commands[remote_command_count++] = "-noraise";
+    raise_p = False;
+    break;
+  case -4: /* --newwin */
+    new_window = TRUE;
+    break;
+  case -5: /* --local */
+    isLocal = TRUE;
+    break;
+  case -6: /* --display */
+    dpy_string = (char *)arg;
+    break;
+  case -7: /* --id */
+    if (remote_command_count > 0) {
+      g_printerr("gnome-moz-remote: '--id' option must precede '--remote' options.\n");
+      poptPrintUsage(ctx, stdout, 0);
+      exit(1);
+    }
+    if (sscanf(arg, " %ld %c", &remote_window, &c))
+      ;
+    else if (sscanf(arg, "0x%lx %c", &remote_window, &c))
+      ;
+    else {
+      g_printerr("gnome-moz-remote: invalid '--id' option \"%s\"\n", arg);
+      poptPrintUsage(ctx, stdout, 0);
+      exit(1);
+    }
+    break;
+  case -8: /* --sync */
+    sync_p = True;
+    break;
+  case -42:
+    g_print("Gnome mozilla-remote %s\n", VERSION);
+    exit(0);
+    break;
+  }
+}
+
+/* We need to escape all ',' characters in the URL */
+static char *
+escape_url (char *url) 
+{
+  gint n_escaped = 0;
+  char *escaped_url, *p, *q;
+  
+  p = url;
+  while ((p = strchr (p, ','))) {
+    n_escaped++;
+    p++;
+  }
+  
+  escaped_url = g_new (char, strlen(url) + 2 * n_escaped + 1);
+  
+  p = url;
+  q = escaped_url;
+  while ((p = strchr (p, ','))) {
+    strncpy (q, url, p-url);
+    q += p-url;
+    strcpy (q, "%2c");
+    q += 3;
+
+    p++;
+    url = p;
+  }
+  strcpy (q, url);
+
+  if(!strncmp("ghelp:", escaped_url, strlen("ghelp:"))) {
+    /* Try to do some fixups so we can display ghelp: URL's */
+    char *retval;
+
+    /* This is really bad-hacky, and won't work for a bunch of ghelp:
+       URL's (e.g. the ones that don't have absolute filenames). Oh
+       well */
+    retval = g_strdup_printf("file:%s", escaped_url + 6);
+
+    g_free(escaped_url);
+
+    return retval;
+  } else
+    return escaped_url;
+}
+
+int
+main (int argc, char **argv)
+{
+  Display *dpy;
+  char *def;
+  
+  /* Parse arguments ... */
+  gnome_program_init("gnome-moz-remote", VERSION, argc, argv, GNOME_PARAM_POPT_TABLE, options, NULL);
+
+  dpy = XOpenDisplay (dpy_string);
+  if (! dpy)
+    return (-1);
+
+  if (sync_p)
+    XSynchronize (dpy, True);
+
+  if (url_string && !remote_commands) {
+    char *argv[3];
+    char *buf, *escaped_url;
+
+    escaped_url = escape_url (url_string);
+
+    if (!g_strncasecmp(escaped_url, "file:", 5))
+      isLocal = True;;
+    buf = g_strdup_printf("openURL(%s%s)",
+			  escaped_url, new_window ? ",new-window" : "");
+    if (!mozilla_remote_cmd(dpy, (Window) remote_window, buf,
+			    raise_p, isLocal))
+      exit(0);
+
+    if (gnome_is_program_in_path ("mozilla"))
+	    def = "/gnome-moz-remote/Mozilla/filename=mozilla";
+    else
+	    def = "/gnome-moz-remote/Mozilla/filename=netscape";
+    
+    argv[0] = gnome_config_get_string(def);
+    argv[1] = escaped_url;
+    argv[2] = NULL;
+    return (gnome_execute_async(NULL, 2, argv) >= 0);
+  } else
+    if (remote_commands) {
+        int ret=mozilla_remote_commands (dpy, (Window) remote_window,
+					 remote_commands, isLocal);
+	if(ret==1) {
+	    /* mozilla_remote_commands couldnt find a running netscape */
+	    if(url_string) {
+		/* fall back to exec()ing netscape with a url */
+		char *argv[3];
+		char *escaped_url;
+
+		escaped_url = escape_url (url_string);
+
+		argv[0] = gnome_config_get_string("/gnome-moz-remote/Mozilla/filename=netscape");
+		argv[1] = escaped_url;
+		argv[2] = NULL;
+		return (gnome_execute_async(NULL, 2, argv) >= 0);
+	    }
+	}
+    }
+  return 0;
+}
diff --git a/libgnome/gnome-moz-remote2.c b/libgnome/gnome-moz-remote2.c
new file mode 100644
index 0000000..4802aae
--- /dev/null
+++ b/libgnome/gnome-moz-remote2.c
@@ -0,0 +1,888 @@
+/*
+ * Copyright (C) 1999 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * 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 the Gnome Library; see the file COPYING.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+/******
+ * gnome-moz-remote2.c:
+ *   A netscape remote control. Written by Elliot Lee, with lots of code stolen from the original gnome-moz-remote
+ *   (by jamesh, I think).
+ *   My changes are under the GPL, Copyright (C) 1999 Red Hat Software.
+ ******/
+/* gnome-moz-remote.c -- open a URL in a current netscape, or start a new
+ *    copy of netscape, pointing at the given page.
+ * This is a modified version of http://home.netscape.com/newsref/std/remote.c
+ * You can find documentation of --remote commands at
+ *   http://home.netscape.com/newsref/std/x-remote.html
+ * My changes fall under the GPL2 (where the previous license allows).  The
+ * original copyright message follows:
+ */
+/* remote.c --- remote control of Netscape Navigator for Unix.
+ * version 1.1.3, for Netscape Navigator 1.1 and newer.
+ *
+ * Copyright © 1996 Netscape Communications Corporation, all rights reserved.
+ * Created: Jamie Zawinski <jwz netscape com>, 24-Dec-94.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or 
+ * implied warranty.
+ *
+ * To compile:
+ *
+ *    cc -o netscape-remote remote.c -DSTANDALONE -lXmu -lX11
+ *
+ * To use:
+ *
+ *    netscape-remote -help
+ *
+ * Documentation for the protocol which this code implements may be found at:
+ *
+ *    http://home.netscape.com/newsref/std/x-remote.html
+ *
+ * Bugs and commentary to x_cbug netscape com 
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gnomesupport.h"
+#include "libgnome.h"
+#include "gnome-program.h"
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+/* vroot.h is a header file which lets a client get along with `virtual root'
+   window managers like swm, tvtwm, olvwm, etc.  If you don't have this header
+   file, you can find it at "http://home.netscape.com/newsref/std/vroot.h";.
+   If you don't care about supporting virtual root window managers, you can
+   comment this line out.
+ */
+#include "vroot.h"
+
+#define CMD_TIMEOUT 10000
+
+typedef struct {
+  Window cmd_window, result_window;
+
+  Display *dpy;
+  GMainLoop *ml;
+  enum { LOCK_WAIT, STARTING_PROCESS, SENT_COMMAND, PROCESSING, FINISHED } state;
+
+  guint timeout_tag;
+  gboolean got_response : 1;
+
+} AppContext;
+
+static AppContext global_ctx = {0};
+static const char *dpy_name;
+static int dpy_sync = 0, win_noraise=0, win_new=0, win_ids_print=-1, win_close = 0;
+static char *win_id = NULL;
+
+static struct poptOption options[] = {
+  {"display", '\0', POPT_ARG_STRING, &dpy_name, 0, N_("Specify X display to use."), "DISPLAY"},
+  {"sync", '\0', POPT_ARG_NONE, &dpy_sync, 0, N_("Put the X connection in synchronous mode."), NULL},
+  {"id", '\0', POPT_ARG_STRING, &win_id, 0, N_("Specify the X window ID of Netscape."), "WIN-ID"},
+  
+  {"noraise", '\0', POPT_ARG_NONE, &win_noraise, 0, N_("Don't raise the Netscape window."), NULL},
+  {"newwin", '\0', POPT_ARG_NONE, &win_new, 0, N_("Show the given URL in a new window."), NULL},
+  {"closewin", '\0', POPT_ARG_NONE, &win_close, 0, N_("Close the specified window."), NULL},
+  {"print-id", '\0', POPT_ARG_INT, &win_ids_print, 0, N_("Print the X window ID of the utilized window."), NULL},
+  {NULL}
+};
+
+static Window mozilla_remote_find_window (Display *dpy);
+static void mozilla_remote_init_atoms (Display *dpy);
+static gboolean mozilla_handle_xevents(GIOChannel *source, GIOCondition condition, gpointer data);
+static gboolean mozilla_remote_check_window (Display *dpy, Window window);
+static void mozilla_remote_obtain_lock (Display *dpy, Window window);
+static void mozilla_remote_free_lock (Display *dpy, Window window);
+static Window mozilla_remote_command (Display *dpy, Window window, const char *command, Bool raise_p);
+static int handle_xerror(Display *dpy, XErrorEvent *ev);
+
+static gboolean
+do_main_quit(gpointer data)
+{
+  AppContext *ctx = (AppContext *) data;
+  gboolean retval;
+
+  g_main_quit(ctx->ml);
+
+  retval = FALSE;
+  ctx->timeout_tag = 0;
+
+  return retval;
+}
+
+static Window
+mozilla_loop_run(AppContext *ctx, Window cmd_window, Window result_window, int state)
+{
+  Window retval;
+
+  ctx->state = state;
+  ctx->result_window = result_window;
+  ctx->cmd_window = cmd_window;
+  ctx->got_response = FALSE;
+  if(!ctx->ml)
+    ctx->ml = g_main_new(FALSE);
+
+  if(cmd_window)
+    XSelectInput(ctx->dpy, cmd_window, (PropertyChangeMask|StructureNotifyMask));
+  XSelectInput(ctx->dpy, DefaultRootWindow(ctx->dpy), (PropertyChangeMask|SubstructureNotifyMask));
+  XFlush(ctx->dpy);
+
+  if(!ctx->timeout_tag)
+    ctx->timeout_tag = g_timeout_add(CMD_TIMEOUT, do_main_quit, ctx);
+
+  g_main_run(ctx->ml);
+
+  if(ctx->timeout_tag)
+    {
+      g_source_remove(ctx->timeout_tag); ctx->timeout_tag = 0;
+    }
+
+  if(global_ctx.result_window == -1)
+    retval = 0;
+  else
+    {
+      retval = global_ctx.result_window;
+      if(retval)
+	XSelectInput(ctx->dpy, retval, 0);
+    }
+
+  return retval;
+}
+
+static gboolean
+mozilla_loop_quit(AppContext *ctx)
+{
+  switch(ctx->state)
+    {
+    case STARTING_PROCESS:
+      if(ctx->result_window != 0)
+	g_main_quit(ctx->ml);
+      break;
+    case SENT_COMMAND:
+      if(ctx->result_window && ctx->got_response)
+	{
+	  g_main_quit(ctx->ml);
+	}
+      break;
+    case LOCK_WAIT:
+      if(ctx->got_response)
+	{
+	  ctx->result_window = ctx->cmd_window;
+	  g_main_quit(ctx->ml);
+	}
+      break;
+    case PROCESSING:
+    case FINISHED:
+      g_warning("Main loop running in illegal state");
+      g_main_quit(ctx->ml);
+      break;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+mozilla_process_start(gpointer data)
+{
+  char *argv[2];
+
+  argv[0] = gnome_config_get_string("/gnome-moz-remote/Mozilla/filename=netscape");
+  argv[1] = NULL;
+
+  gnome_execute_async(NULL, 1, argv);
+
+  g_free(argv[0]);
+
+  return FALSE;
+}
+
+static Window
+mozilla_window_spawn(Display *dpy)
+{
+  g_idle_add(mozilla_process_start, &global_ctx);
+  return mozilla_loop_run(&global_ctx, 0, 0, STARTING_PROCESS);
+}
+
+/* We need to escape all ',' characters in the URL */
+static char *
+escape_url (const char *url) 
+{
+  gint n_escaped = 0;
+  char *escaped_url;
+  const char *p;
+  char *q;
+  
+  p = url;
+  while ((p = strchr (p, ','))) {
+    n_escaped++;
+    p++;
+  }
+  
+  escaped_url = g_new (char, strlen(url) + 2 * n_escaped + 1);
+  
+  p = url;
+  q = escaped_url;
+  while ((p = strchr (p, ','))) {
+    strncpy (q, url, p-url);
+    q += p-url;
+    strcpy (q, "%2c");
+    q += 3;
+
+    p++;
+    url = p;
+  }
+  strcpy (q, url);
+
+  return escaped_url;
+}
+
+static Window
+mozilla_window_goto(Display *dpy, Window winid, const char *url)
+{
+  char command[2048], *escaped_url;
+  if(!winid)
+    winid = mozilla_remote_find_window(dpy);
+  if(!winid)
+    {
+      winid = mozilla_window_spawn(dpy);
+      win_new = 0;
+    }
+  if(!winid)
+    return 0;
+
+  escaped_url = escape_url(url);
+  g_snprintf(command, sizeof(command), "openURL(%s%s%s)", escaped_url, win_new?", new-window":"", win_noraise?", noraise":"");
+  winid = mozilla_remote_command(dpy, winid, command, !win_noraise);
+  g_free(escaped_url);
+
+  return winid;
+}
+
+int main(int argc, char **argv)
+{
+  const char **args;
+  poptContext ctx;
+  int i;
+  Display *dpy;
+  GnomeProgram *program;
+
+  dpy_name = g_getenv("DISPLAY");
+
+  program = gnome_program_get();
+  g_object_set(G_OBJECT(program), "popt_table", options, LIBGNOME_INIT, NULL);
+  ctx = gnome_program_preinit(program, "gnome_moz_remote", VERSION, argc, argv);
+  args = poptGetArgs(ctx);
+
+  dpy = XOpenDisplay(dpy_name);
+  XSetErrorHandler(handle_xerror);
+
+  if (!dpy)
+    return 1;
+
+  g_io_add_watch(g_io_channel_unix_new(ConnectionNumber(dpy)), G_IO_IN, mozilla_handle_xevents, &global_ctx);
+
+  mozilla_remote_init_atoms(dpy);
+
+  if(dpy_sync)
+    XSynchronize (dpy, True);
+
+  global_ctx.dpy = dpy;
+
+  if(args && args[1])
+    {
+      g_print("%s: Only one URL on the cmdline\n", argv[0]);
+      goto out;
+    }
+  if((!args || !args[0]) && !win_close)
+    return 0; /* Nothing to do */
+
+  if(win_new)
+    win_noraise = TRUE; /* This makes the new window wind up on the current screen, at least with NSCP 4.7 */
+
+  mozilla_remote_obtain_lock(dpy, DefaultRootWindow(dpy));
+
+  if(win_close)
+    {
+      Window utwin;
+
+      if(!win_id)
+	goto out;
+
+      utwin = strtol(win_id, NULL, 0);
+
+      mozilla_remote_command(dpy, utwin, "close", FALSE);
+    }
+  else
+    {
+      if(win_id)
+	{
+	  global_ctx.cmd_window = strtol(win_id, NULL, 0);
+	  if(!mozilla_remote_check_window(dpy, global_ctx.cmd_window))
+	    global_ctx.cmd_window = 0;
+	}
+      else
+	global_ctx.cmd_window = mozilla_remote_find_window(dpy);
+
+      if (!global_ctx.cmd_window)
+	global_ctx.cmd_window = mozilla_window_spawn(dpy);
+
+      for(i = 0; args[i]; i++)
+	{
+	  Window utwin;
+
+	  utwin = mozilla_window_goto(dpy, global_ctx.cmd_window, args[i]);
+	  if((win_ids_print >= 0) && utwin)
+	    {
+	      static FILE *fh = NULL;
+
+	      if(!fh)
+		fh = fdopen(win_ids_print, "w");
+	      fprintf(fh, "%#lx\n", utwin);
+	    }
+
+	  if(!utwin)
+	    break;
+	}
+    }
+
+ out:
+  mozilla_remote_free_lock(dpy, DefaultRootWindow(dpy));
+
+  return 0;
+}
+
+/****************************************** find/check a window, any window :) *********************************/
+#define MOZILLA_VERSION_PROP   "_MOZILLA_VERSION"
+#define MOZILLA_LOCK_PROP      "_MOZILLA_LOCK"
+#define MOZILLA_COMMAND_PROP   "_MOZILLA_COMMAND"
+#define MOZILLA_RESPONSE_PROP  "_MOZILLA_RESPONSE"
+static Atom XA_MOZILLA_VERSION  = 0;
+static Atom XA_MOZILLA_LOCK     = 0;
+static Atom XA_MOZILLA_COMMAND  = 0;
+static Atom XA_MOZILLA_RESPONSE = 0;
+
+/* these are needed for the machine check and client list check */
+#define WM_STATE_PROP                  "WM_STATE"
+#define GNOME_SUPPORTING_WM_CHECK_PROP "_WIN_SUPPORTING_WM_CHECK"
+#define GNOME_PROTOCOLS_PROP           "_WIN_PROTOCOLS"
+#define GNOME_CLIENT_LIST_PROP         "_WIN_CLIENT_LIST"
+static Atom XA_WM_STATE                = 0;
+static Atom XA_WIN_SUPPORTING_WM_CHECK = 0;
+static Atom XA_WIN_PROTOCOLS           = 0;
+static Atom XA_WIN_CLIENT_LIST         = 0;
+
+static void
+mozilla_remote_init_atoms (Display *dpy)
+{
+  if (! XA_MOZILLA_VERSION)
+    XA_MOZILLA_VERSION = XInternAtom (dpy, MOZILLA_VERSION_PROP, False);
+  if (! XA_MOZILLA_LOCK)
+    XA_MOZILLA_LOCK = XInternAtom (dpy, MOZILLA_LOCK_PROP, False);
+  if (! XA_MOZILLA_COMMAND)
+    XA_MOZILLA_COMMAND = XInternAtom (dpy, MOZILLA_COMMAND_PROP, False);
+  if (! XA_MOZILLA_RESPONSE)
+    XA_MOZILLA_RESPONSE = XInternAtom (dpy, MOZILLA_RESPONSE_PROP, False);
+
+  if (! XA_WM_STATE)
+    XA_WM_STATE = XInternAtom (dpy, WM_STATE_PROP, False);
+  if (! XA_WIN_SUPPORTING_WM_CHECK)
+    XA_WIN_SUPPORTING_WM_CHECK = XInternAtom (dpy, GNOME_SUPPORTING_WM_CHECK_PROP, False);
+  if (! XA_WIN_PROTOCOLS)
+    XA_WIN_PROTOCOLS = XInternAtom (dpy, GNOME_PROTOCOLS_PROP, False);
+  if (! XA_WIN_CLIENT_LIST)
+    XA_WIN_CLIENT_LIST = XInternAtom (dpy, GNOME_CLIENT_LIST_PROP, False);
+}
+
+/* returns true if the window manager supports the _WIN_CLIENT_LIST
+ * gnome wm hint */
+static Bool
+gnomewm_check_wm(Display *dpy)
+{
+  Window root = DefaultRootWindow(dpy);
+  Atom r_type;
+  int r_format;
+  unsigned long count, i;
+  unsigned long bytes_remain;
+  unsigned char *prop, *prop2, *prop3;
+
+  if (XGetWindowProperty(dpy, root,
+                         XA_WIN_SUPPORTING_WM_CHECK, 0, 1, False, XA_CARDINAL,
+                         &r_type, &r_format,
+                         &count, &bytes_remain, &prop) == Success && prop) {
+    if (r_type == XA_CARDINAL && r_format == 32 && count == 1) {
+      Window n = *(long *)prop;
+      if (XGetWindowProperty(dpy, n,
+			     XA_WIN_SUPPORTING_WM_CHECK, 0, 1, False, 
+			     XA_CARDINAL,
+			     &r_type, &r_format, &count, &bytes_remain, 
+			     &prop2) == Success && prop2) {
+	if (r_type == XA_CARDINAL && r_format == 32 && count == 1) {
+	  if (XGetWindowProperty(dpy, root,
+				 XA_WIN_PROTOCOLS, 0,0x7fffffff,False, XA_ATOM,
+				 &r_type, &r_format, &count, &bytes_remain,
+				 &prop3) == Success && prop3) {
+	    if (r_type == XA_ATOM && r_format == 32) {
+	      /* I heard George saying format==32 requires this type */
+	      unsigned long *list = (unsigned long *)prop3;
+	      XFree(prop);
+	      XFree(prop2);
+
+	      for (i = 0; i < count; i++)
+		if (list[i] == XA_WIN_CLIENT_LIST) {
+		  XFree(prop3);
+		  return TRUE;
+		}
+	    }
+	    XFree(prop3);
+	  }
+	}
+	XFree(prop2);
+      }       
+    }
+    XFree(prop);
+  }
+  return FALSE;
+}
+
+/* This function uses the _WIN_CLIENT_LIST GNOME window manager hint to find
+ * the list of client windows.  It then calls mozilla_remote_test_window on
+ * each until it finds a matching mozilla window
+ */
+static Window
+gnomewm_find_window(Display *dpy)
+{
+  Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
+  Atom r_type;
+  int r_format;
+  unsigned long count, i;
+  unsigned long bytes_remain, *wins;
+  unsigned char *prop;
+
+  XGetWindowProperty(dpy, root, XA_WIN_CLIENT_LIST,
+		     0, 0x7fffffff, False, XA_CARDINAL,
+		     &r_type, &r_format, &count, &bytes_remain, &prop);
+  if (!prop || count <= 0 || r_type != XA_CARDINAL || r_format != 32) {
+    if (prop) XFree(prop);
+    return 0;
+  }
+  wins = (unsigned long *)prop;
+  for (i = 0; i < count; i++)
+    if (mozilla_remote_check_window(dpy, wins[i])) {
+      Window ret = wins[i];
+      XFree(prop);
+      return ret;
+    }
+  XFree(prop);
+  return 0;
+}
+
+/* this function recurses down the X window heirachy, finding windows with the
+ * WM_STATE property set (which indicates that we have a client window), and
+ * calls mozilla_remote_test_window on each until it finds a match
+ */
+static Window
+mozilla_remote_find_window_recurse(Display *dpy, Window win)
+{
+  Atom r_type;
+  int r_format;
+  unsigned long count, after;
+  unsigned char *data;
+
+  XGetWindowProperty(dpy, win, XA_WM_STATE, 0, 0, False, AnyPropertyType,
+		     &r_type, &r_format, &count, &after, &data);
+
+  if (r_type) {
+    /* this is a client window */
+    XFree(data);
+
+    if (mozilla_remote_check_window(dpy, win))
+      return win;
+    else
+      return 0;
+  } else {
+    Window ret_root, ret_parent, *ret_children;
+    unsigned int ret_nchildren, i;
+
+    if (XQueryTree(dpy, win, &ret_root, &ret_parent,
+		   &ret_children, &ret_nchildren) != True)
+      return 0;
+
+    for (i = 0; i < ret_nchildren; i++) {
+      Window check = mozilla_remote_find_window_recurse(dpy, ret_children[i]);
+      if (check) {
+	XFree(ret_children);
+	return check;
+      }
+    }
+  }
+
+  return 0;
+}
+
+/* this function finds the first matching mozilla window (using GNOME WM
+ * hints or querying the X window heirachy) and returns it
+ */
+static Window
+mozilla_remote_find_window (Display *dpy)
+{
+  Window root = RootWindowOfScreen (DefaultScreenOfDisplay (dpy));
+
+  if (gnomewm_check_wm(dpy))
+    return gnomewm_find_window(dpy);
+  else
+    return mozilla_remote_find_window_recurse(dpy, root);
+}
+
+static gboolean
+mozilla_remote_check_window (Display *dpy, Window window)
+{
+  Atom type;
+  int format, status;
+  unsigned long nitems, bytesafter;
+  unsigned char *version = 0;
+
+  g_return_val_if_fail(window != 0, 0);
+  status = XGetWindowProperty (dpy, window, XA_MOZILLA_VERSION,
+				   0, (65536 / sizeof (long)),
+				   False, XA_STRING,
+				   &type, &format, &nitems, &bytesafter,
+				   &version);
+  if (status != Success || !version)
+    return FALSE;
+
+  XFree (version);
+
+  return TRUE;
+}
+
+static Window
+mozilla_remote_command (Display *dpy, Window window, const char *command,
+			Bool raise_p)
+{
+  g_return_val_if_fail(window != 0, 0);
+
+#ifdef DEBUG_PROPS
+  g_printerr("gnome-moz-remote: (writing " MOZILLA_COMMAND_PROP
+	     " \"%s\" to 0x%x)\n", command, (unsigned int) window);
+#endif
+
+  XChangeProperty (dpy, window, XA_MOZILLA_COMMAND, XA_STRING, 8,
+		   PropModeReplace, (unsigned char *) command,
+		   strlen (command));
+
+  return mozilla_loop_run(&global_ctx, window, win_new?0:window, SENT_COMMAND);
+}
+
+static gboolean
+mozilla_handle_xevents(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+  XEvent ev;
+  AppContext *ctx = (AppContext *)data;
+  Window tmpwin;
+
+  XNextEvent(ctx->dpy, &ev);
+
+  switch(ev.xany.type)
+    {
+    case MapNotify:
+      if ((ctx->state != SENT_COMMAND || ctx->result_window)
+	  && ctx->state != STARTING_PROCESS)
+	break;
+
+      tmpwin = mozilla_remote_find_window_recurse(ctx->dpy, ev.xmap.window);
+      if(tmpwin)
+	{
+	  ctx->result_window = tmpwin;
+	  mozilla_loop_quit(ctx);
+	}
+      break;
+    case DestroyNotify:
+      if(ev.xdestroywindow.window != ctx->cmd_window)
+	break;
+
+      ctx->got_response = TRUE;
+      ctx->result_window = -1;
+      mozilla_loop_quit(ctx);
+      break;
+    case PropertyNotify:
+      if (ctx->state != SENT_COMMAND && ctx->state != LOCK_WAIT)
+	break;
+      if(ev.xproperty.atom != XA_MOZILLA_COMMAND
+	 && ev.xproperty.atom != XA_MOZILLA_LOCK)
+	break;
+      if(ev.xproperty.window != ctx->cmd_window)
+	break;
+      switch(ev.xproperty.state)
+	{
+	case PropertyNewValue:
+	  if (ev.xproperty.atom == XA_MOZILLA_COMMAND) {
+	    Atom actual_type;
+	    int actual_format;
+	    unsigned long nitems, bytes_after;
+	    unsigned char *data = 0;
+	    int result;
+
+	    result = XGetWindowProperty (ctx->dpy, ctx->cmd_window, XA_MOZILLA_RESPONSE,
+					 0, (65536 / sizeof (long)),
+					 True, /* atomic delete after */
+					 XA_STRING,
+					 &actual_type, &actual_format,
+					 &nitems, &bytes_after,
+					 &data);
+
+#ifdef DEBUG_PROPS
+	    if (result == Success && data && *data)
+	      {
+		g_printerr("gnome-moz-remote: (server sent "MOZILLA_RESPONSE_PROP
+			   " \"%s\" to 0x%x.)\n",
+			   data, (unsigned int) window);
+	      }
+#endif
+
+	    if (result != Success)
+	      {
+		g_printerr("gnome-moz-remote: failed reading "
+			   MOZILLA_RESPONSE_PROP " from window 0x%0x.\n",
+			   (unsigned int) ctx->cmd_window);
+		result = 6;
+		ctx->got_response = TRUE;
+	      }
+	    else if (!data || strlen((char *) data) < 5)
+	      {
+		g_printerr("gnome-moz-remote: invalid data on "
+			   MOZILLA_RESPONSE_PROP " property of window 0x%0x.\n",
+			   (unsigned int) ctx->cmd_window);
+		ctx->result_window = -1;
+		ctx->got_response = TRUE;
+	      }
+	    else if (*data == '1')	/* positive preliminary reply */
+	      {
+		g_printerr("gnome-moz-remote: %s\n", data + 4);
+	      }
+	    else if (!strncmp ((char *)data, "200", 3)) /* positive completion */
+	      {
+		result = 0;
+		ctx->got_response = TRUE;
+	      }
+	    else if (*data == '2')		/* positive completion */
+	      {
+		g_printerr("gnome-moz-remote: %s\n", data + 4);
+		ctx->got_response = TRUE;
+	      }
+	    else if (*data == '3')	/* positive intermediate reply */
+	      {
+		g_printerr("gnome-moz-remote: internal error: "
+			   "server wants more information?  (%s)\n",
+			   data);
+		ctx->got_response = TRUE;
+	      }
+	    else if (*data == '4' ||	/* transient negative completion */
+		     *data == '5')	/* permanent negative completion */
+	      {
+		g_printerr("gnome-moz-remote: %s\n", data + 4);
+		result = (*data - '0');
+		ctx->got_response = TRUE;
+		ctx->result_window = -1;
+	      }
+	    else
+	      {
+		g_printerr(
+			   "gnome-moz-remote: unrecognised " MOZILLA_RESPONSE_PROP
+			   " from window 0x%x: %s\n",
+			   (unsigned int) ctx->cmd_window, data);
+		ctx->got_response = TRUE;
+		ctx->result_window = -1;
+	      }
+
+	    if (data)
+	      XFree (data);
+
+	    mozilla_loop_quit(ctx);
+	  }
+	  break;
+	case PropertyDelete:
+	  if(ev.xproperty.atom == XA_MOZILLA_COMMAND)
+	    {
+	      ctx->got_response = TRUE;
+	      mozilla_loop_quit(ctx);
+	    }
+	  else if(ctx->state == LOCK_WAIT
+		  && ev.xproperty.atom == XA_MOZILLA_LOCK)
+	    {
+	      ctx->got_response = TRUE;
+	      mozilla_loop_quit(ctx);
+	    }
+	  break;
+	}      
+      break;
+    }
+
+  return TRUE;
+}
+
+/****** locking *******/
+static char *lock_data = NULL;
+
+static void
+mozilla_remote_obtain_lock (Display *dpy, Window window)
+{
+  Bool locked = False;
+  Bool waited = False;
+
+  g_return_if_fail(window != 0);
+  if (! lock_data)
+    {
+      lock_data = (char *) malloc (255);
+      g_snprintf (lock_data, 255, "pid%d@", getpid ());
+
+      if (gethostname (lock_data + strlen (lock_data), 100))
+	{
+	  perror ("gethostname");
+	  mozilla_remote_free_lock(dpy, window);
+	  exit(1);
+	}
+    }
+
+  do
+    {
+      int result;
+      Atom actual_type;
+      int actual_format;
+      unsigned long nitems, bytes_after;
+      unsigned char *data = 0;
+
+      XGrabServer (dpy);   /* ################################# DANGER! */
+
+      result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
+				   0, (65536 / sizeof (long)),
+				   False, /* don't delete */
+				   XA_STRING,
+				   &actual_type, &actual_format,
+				   &nitems, &bytes_after,
+				   &data);
+      if (result != Success || actual_type == None)
+	{
+	  /* It's not now locked - lock it. */
+#ifdef DEBUG_PROPS
+	  g_printerr("gnome-moz-remote: (writing " MOZILLA_LOCK_PROP
+		     " \"%s\" to 0x%x)\n"
+		     lock_data, (unsigned int) window);
+#endif
+	  XChangeProperty (dpy, window, XA_MOZILLA_LOCK, XA_STRING, 8,
+			   PropModeReplace, (unsigned char *) lock_data,
+			   strlen (lock_data));
+	  locked = True;
+	}
+
+      XUngrabServer (dpy); /* ################################# danger over */
+      XSync (dpy, False);
+
+      if (! locked)
+	{
+	  /* We tried to grab the lock this time, and failed because someone
+	     else is holding it already.  So, wait for a PropertyDelete event
+	     to come in, and try again. */
+
+	  g_printerr("gnome-moz-remote: window 0x%x is locked by %s; waiting...\n",
+		     (unsigned int) window, data);
+	  waited = True;
+
+	  mozilla_loop_run(&global_ctx, window, window, LOCK_WAIT);
+	}
+      if (data)
+	XFree (data);
+    }
+  while (! locked);
+
+  if (waited)
+    g_printerr("gnome-moz-remote: obtained lock.\n");
+}
+
+
+static void
+mozilla_remote_free_lock (Display *dpy, Window window)
+{
+  int result;
+  Atom actual_type;
+  int actual_format;
+  unsigned long nitems, bytes_after;
+  unsigned char *data = 0;
+
+  g_return_if_fail(window != 0);
+#ifdef DEBUG_PROPS
+  g_printerr("gnome-moz-remote: (deleting " MOZILLA_LOCK_PROP
+	     " \"%s\" from 0x%x)\n",
+	     lock_data, (unsigned int) window);
+#endif
+
+  result = XGetWindowProperty (dpy, window, XA_MOZILLA_LOCK,
+			       0, (65536 / sizeof (long)),
+			       True, /* atomic delete after */
+			       XA_STRING,
+			       &actual_type, &actual_format,
+			       &nitems, &bytes_after,
+			       &data);
+  if (result != Success)
+    {
+      g_printerr("gnome-moz-remote: unable to read and delete "
+		 MOZILLA_LOCK_PROP " property\n");
+      return;
+    }
+  else if (!data || !*data)
+    {
+      g_printerr("gnome-moz-remote: invalid data on " MOZILLA_LOCK_PROP
+		 " of window 0x%x.\n",
+		 (unsigned int) window);
+      return;
+    }
+  else if (strcmp ((char *) data, lock_data))
+    {
+      g_printerr("gnome-moz-remote: " MOZILLA_LOCK_PROP
+		 " was stolen!  Expected \"%s\", saw \"%s\"!\n",
+		 lock_data, data);
+      return;
+    }
+
+  if (data)
+    XFree (data);
+}
+
+static int
+handle_xerror(Display *dpy, XErrorEvent *ev)
+{
+  mozilla_remote_free_lock(dpy, DefaultRootWindow(dpy));
+
+  exit(1);
+}
diff --git a/libgnome/gnome-paper.c b/libgnome/gnome-paper.c
new file mode 100644
index 0000000..5f708ac
--- /dev/null
+++ b/libgnome/gnome-paper.c
@@ -0,0 +1,474 @@
+/* GnomePaper
+ * Copyright (C) 1998 the Free Software Foundation
+ * All rights reserved.
+ *
+ * Author: Dirk Luetjens <dirk luedi oche de>
+ * a few code snippets taken from libpaper written by 
+ * Yves Arrouye <Yves Arrouye marin fdn fr>
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc.,  59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#include "libgnomeP.h"
+
+struct _GnomePaper
+{
+  char* name;
+  double pswidth, psheight;
+  double lmargin, tmargin, rmargin, bmargin;
+};
+
+struct _GnomeUnit
+{
+  char* name;
+  char* unit;
+  float factor;
+};
+
+
+static const GnomeUnit units[] =
+{
+  /* XXX does anyone *really* measure paper size in feet?  meters? */
+
+  /* human name, abreviation, points per unit */
+  { "Feet",       "ft",	864 },
+  { "Meter",      "m",  2834.6457 },
+  { "Decimeter",  "dm",	283.46457 },
+  { "Millimeter", "mm",	2.8346457 },
+  { "Point",      "pt",	1. },
+  { "Centimeter", "cm",	28.346457 },
+  { "Inch",       "in",	72 },
+  { 0 }
+};
+
+static GList* paper_list = NULL;
+static GList* unit_list = NULL;
+static GList* paper_name_list = NULL;
+static GList* unit_name_list = NULL;
+
+/**
+ * paper_init: initialize paper data structures
+ * 
+ **/
+static void
+paper_init (void)
+{
+  void	*config_iterator;
+  gchar *name, *size;
+  GnomePaper	*paper;
+  const GnomeUnit *unit;
+  char *str;
+
+  gnome_config_push_prefix (NULL);
+  
+  config_iterator =
+    gnome_config_init_iterator("="GNOMESYSCONFDIR"/paper.config=/Paper/");
+  gnome_config_pop_prefix ();
+  
+  if (!config_iterator)
+    return;
+
+  while ((config_iterator =
+	  gnome_config_iterator_next(config_iterator, &name, &size)))
+    {
+      paper = g_new (GnomePaper, 1);
+
+      paper->name = name;
+      g_strdelimit (size, "{},", ' ');
+      paper->pswidth  = g_strtod (size, &str);
+      paper->psheight = g_strtod (str, &str);
+      paper->lmargin = g_strtod (str, &str);
+      paper->tmargin = g_strtod (str, &str);
+      paper->rmargin = g_strtod (str, &str);
+      paper->bmargin = g_strtod (str, NULL);
+      g_free(size);
+
+      paper_list = g_list_prepend(paper_list, paper);
+      paper_name_list = g_list_prepend(paper_name_list, paper->name);
+    }
+
+  for (unit=units; unit->name; unit++)
+    {
+      unit_list = g_list_prepend(unit_list, (gpointer) unit);
+      unit_name_list = g_list_prepend(unit_name_list, unit->name);
+    }
+}
+
+static int 
+paper_name_compare (const GnomePaper* a, const gchar *b)
+{
+  return (g_strcasecmp(a->name, b));
+}
+
+static int 
+unit_name_compare (const GnomeUnit* a, const gchar *b)
+{
+  return (g_strcasecmp(a->name, b));
+}
+
+static int
+unit_abbrev_compare (const GnomeUnit *a, const gchar *b)
+{
+  return (g_strcasecmp(a->unit, b));
+}
+
+/**
+ * gnome_paper_name_list: get internal list of paper specifications
+ * 
+ * grants access to the hardcoded internal list of paper specifications
+ *
+ * Returns: internal list of paper specifications
+ **/
+const GList*
+gnome_paper_name_list (void)
+{
+  if (!paper_name_list)
+    paper_init();
+  return paper_name_list;
+}
+
+/**
+ * gnome_paper_with_name: get paper specification by name
+ * @papername: human name of desired paper type
+ * 
+ * searches internal list of paper sizes, searching
+ * for one with the name 'papername'
+ * 
+ * Returns: paper specification with given name, or NULL
+ **/
+const GnomePaper*
+gnome_paper_with_name (const gchar *papername)
+{
+  GList	*l;
+  
+  if (!paper_list)
+    paper_init();
+
+  l = g_list_find_custom (paper_list,
+			  (gpointer) papername,
+			  (GCompareFunc)paper_name_compare);
+
+  return l ? l->data : NULL;
+}
+
+/**
+ * gnome_paper_with_size: create paper specification with size
+ * @pswidth: width of paper
+ * @psheight: height of paper
+ * 
+ * create a custom paper type with given dimensions
+ * 
+ * Returns: paper specification
+ **/
+const GnomePaper*
+gnome_paper_with_size (double pswidth, double psheight)
+{
+  GList *l = paper_list;
+  GnomePaper	*pp;
+
+  if (!paper_list)
+    paper_init();
+
+  while (l) {
+    pp = l->data;
+    if (pp->pswidth == pswidth && pp->psheight == psheight)
+      return pp;
+    l = l->next;
+  }
+  return NULL;
+}
+
+/**
+ * gnome_paper_name_default: get the name of the default paper
+ * 
+ * Returns: human readable name for default paper type
+ **/
+const gchar*
+gnome_paper_name_default(void)
+{
+  static gchar *systempapername = "a4";
+  
+  return systempapername;
+}
+
+/**
+ * gnome_paper_name: get name of paper
+ * @paper: paper specification
+ * 
+ * 
+ * 
+ * Returns: human readable name for paper type
+ **/
+const gchar*
+gnome_paper_name (const GnomePaper *paper)
+{
+  g_return_val_if_fail(paper, NULL);
+  
+  return paper->name;
+}
+
+/**
+ * gnome_paper_pswidth: get width of paper
+ * @paper: paper specification
+ * 
+ * returns the width of the paper, including the margins
+ * 
+ * Returns: width of paper (in points)
+ **/
+gdouble
+gnome_paper_pswidth (const GnomePaper *paper)
+{
+  g_return_val_if_fail(paper, 0.0);
+  
+  return paper->pswidth;
+}
+
+/**
+ * gnome_paper_psheight: get height of paper
+ * @paper: paper specification
+ * 
+ * returns the height of the paper, including the margins
+ * 
+ * Returns: height of paper (in points)
+ **/
+gdouble
+gnome_paper_psheight (const GnomePaper *paper)
+{
+  g_return_val_if_fail(paper, 0.0);
+  
+  return paper->psheight;
+}
+
+/**
+ * gnome_paper_lmargin: get size of left margin
+ * @paper: paper specification
+ * 
+ * 
+ * 
+ * Returns: paper specification
+ **/
+gdouble
+gnome_paper_lmargin	(const GnomePaper *paper)
+{
+  g_return_val_if_fail(paper, 0.0);
+  
+  return paper->lmargin;
+}
+
+/**
+ * gnome_paper_tmargin: get size of top margin
+ * @paper: paper specification
+ * 
+ * 
+ * 
+ * Returns: size of top margin (in points)
+ **/
+gdouble
+gnome_paper_tmargin	(const GnomePaper *paper)
+{
+  g_return_val_if_fail(paper, 0.0);
+  
+  return paper->tmargin;
+}
+
+/**
+ * gnome_paper_rmargin: get size of right margin
+ * @paper: paper specification
+ * 
+ * 
+ * 
+ * Returns: size of right margin (in points)
+ **/
+gdouble
+gnome_paper_rmargin	(const GnomePaper *paper)
+{
+  g_return_val_if_fail(paper, 0.0);
+  
+  return paper->rmargin;
+}
+
+/**
+ * gnome_paper_bmargin: get size of bottom margin
+ * @paper: paper specification
+ * 
+ * 
+ * 
+ * Returns: size of bottom margin (in points)
+ **/
+gdouble
+gnome_paper_bmargin (const GnomePaper *paper)
+{
+  g_return_val_if_fail(paper, 0.0);
+  
+  return paper->bmargin;
+}
+
+/**
+ * gnome_unit_name_list: get internal list of units
+ * 
+ * grants access to the hardcoded internal list
+ * of units
+ * 
+ * Returns: internal list of units
+ **/
+const GList*
+gnome_unit_name_list (void)
+{
+  if (!unit_name_list)
+    paper_init();
+  return unit_name_list;
+}
+
+/**
+ * gnome_unit_with_name: get Unit by name
+ * @unitname: name of desired unit
+ * 
+ * searches internal list of units, searching
+ * for one with the name 'unitname'
+ * 
+ * Returns: Unit with given name or NULL
+ **/
+const GnomeUnit * 
+gnome_unit_with_name (const gchar *unitname)
+{
+  GList	*l;
+  
+  if (!unit_list)
+    paper_init();
+
+  l = g_list_find_custom (unit_list,
+			  (gpointer) unitname,
+			  (GCompareFunc)unit_name_compare);
+
+  return l ? l->data : NULL;
+}
+
+/**
+ * gnome_unit_with_abbrev: get Unit by name
+ * @unitname: name of desired unit
+ * 
+ * searches internal list of units, searching
+ * for one with the name 'unitname'
+ * 
+ * Returns: Unit with given name or NULL
+ **/
+const GnomeUnit * 
+gnome_unit_with_abbrev (const gchar *abbreviation)
+{
+  GList	*l;
+  
+  if (!unit_list)
+    paper_init();
+
+  l = g_list_find_custom (unit_list,
+			  (gpointer) abbreviation,
+			  (GCompareFunc)unit_abbrev_compare);
+
+  return l ? l->data : NULL;
+}
+
+/**
+ * gnome_unit_name: get name of unit
+ * @unit: unit name
+ * 
+ * 
+ * 
+ * Returns: human readable name for unit
+ **/
+const gchar*
+gnome_unit_name (const GnomeUnit *unit)
+{
+  g_return_val_if_fail(unit != NULL, NULL);
+  
+  return unit->name;
+}
+
+/**
+ * gnome_unit_abbrev: get abbreviation of unit
+ * @unit: unit name
+ * 
+ * 
+ * 
+ * Returns: abbreviated name for unit
+ **/
+const gchar*
+gnome_unit_abbrev (const GnomeUnit *unit)
+{
+  g_return_val_if_fail(unit != NULL, NULL);
+  
+  return unit->unit;
+}
+
+/**
+ * gnome_paper_convert: convert from points to other units
+ * @psvalue: value in points
+ * @unit: unit to convert to
+ * 
+ * converts from value represented in points
+ * to value represented in given units.
+ * 
+ * Returns: value in given units
+ **/
+double 
+gnome_paper_convert (double psvalue, const GnomeUnit *unit)
+{
+  g_return_val_if_fail (unit, psvalue);
+  g_return_val_if_fail (unit->factor, psvalue);
+
+  return psvalue / unit->factor;
+}
+
+/**
+ * gnome_paper_convert_to_points: convert from other units to points.
+ * @othervalue: value in points
+ * @unit: unit to convert to
+ * 
+ * Needed for gnome-paper-selector.
+ * converts from value represented in points
+ * to value represented in given units.
+ * 
+ * Returns: value in points
+ **/
+double 
+gnome_paper_convert_to_points (double othervalue, const GnomeUnit *unit)
+{
+  g_return_val_if_fail (unit, othervalue);
+
+  return othervalue * unit->factor;
+}
+
+/**
+ * gnome_unit_convert: convert from one set of units to another
+ * @value: the value in the `from' units
+ * @from: the unit to convert from
+ * @to: the unit to convert to
+ *
+ * Convert from one set of units to another set.
+ *
+ * Returns: the value in the `to' units
+ **/
+double 
+gnome_unit_convert (double othervalue, const GnomeUnit *from,
+		    const GnomeUnit *to)
+{
+  g_return_val_if_fail (from != NULL, othervalue);
+  g_return_val_if_fail (to != NULL, othervalue);
+  g_return_val_if_fail (to->factor != 0, othervalue);
+
+  return othervalue * from->factor / to->factor;
+}
diff --git a/libgnome/gnome-paper.h b/libgnome/gnome-paper.h
new file mode 100644
index 0000000..51bd73a
--- /dev/null
+++ b/libgnome/gnome-paper.h
@@ -0,0 +1,73 @@
+/* GnomePaper
+ * Copyright (C) 1998 the Free Software Foundation
+ * All rights reserved.
+ *
+ * Author: Dirk Luetjens <dirk luedi oche de>
+ * a few code snippets taken from libpaper written by 
+ * Yves Arrouye <Yves Arrouye marin fdn fr>
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc.,  59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifndef GNOME_PAPER_H
+#define GNOME_PAPER_H
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_DECLS
+
+typedef struct _GnomePaper GnomePaper;
+typedef struct _GnomeUnit  GnomeUnit;
+	
+/* These definitions are deprecated, they will be gone in the next
+ * version of GNOME, 
+ */
+typedef GnomePaper Paper;
+typedef GnomeUnit Unit;
+
+const GList	 *gnome_paper_name_list	(void);
+const GnomePaper *gnome_paper_with_name	(const gchar *papername);
+const GnomePaper *gnome_paper_with_size	(double pswidth, double psheight);
+
+const gchar	 *gnome_paper_name	(const GnomePaper *paper);
+gdouble		 gnome_paper_pswidth	(const GnomePaper *paper);
+gdouble		 gnome_paper_psheight	(const GnomePaper *paper);
+gdouble		 gnome_paper_lmargin	(const GnomePaper *paper);
+gdouble		 gnome_paper_tmargin	(const GnomePaper *paper);
+gdouble		 gnome_paper_rmargin	(const GnomePaper *paper);
+gdouble		 gnome_paper_bmargin	(const GnomePaper *paper);
+
+const gchar	 *gnome_paper_name_default	(void);
+
+const GList*	 gnome_unit_name_list	(void);
+const GnomeUnit	 *gnome_unit_with_name	(const gchar *unitname);
+const GnomeUnit  *gnome_unit_with_abbrev(const gchar *abbreviation);
+
+const gchar      *gnome_unit_name       (const GnomeUnit *unit);
+const gchar      *gnome_unit_abbrev     (const GnomeUnit *unit);
+
+gdouble		 gnome_paper_convert	(double psvalue, const GnomeUnit *unit);
+double           gnome_paper_convert_to_points (double othervalue, const GnomeUnit *unit);
+double           gnome_unit_convert     (double othervalue,
+					 const GnomeUnit *from,
+					 const GnomeUnit *to);
+
+END_GNOME_DECLS
+
+#endif 
diff --git a/libgnome/gnome-portability.h.in b/libgnome/gnome-portability.h.in
new file mode 100644
index 0000000..1bbc28f
--- /dev/null
+++ b/libgnome/gnome-portability.h.in
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
+ * 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_PORTABILITY_H
+#define GNOME_PORTABILITY_H 1
+
+/* Empty for now, will it ever again be needed? */
+
+#endif /* GNOME_PORTABILITY_H */
diff --git a/libgnome/gnome-program.c b/libgnome/gnome-program.c
new file mode 100644
index 0000000..ce4047f
--- /dev/null
+++ b/libgnome/gnome-program.c
@@ -0,0 +1,1359 @@
+/*
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
+ * 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@
+ */
+
+
+/* This module takes care of handling application and library
+   initialization and command line parsing */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gmodule.h>
+#include "libgnomeP.h"
+#include "gnome-defs.h"
+#include "gnome-i18nP.h"
+#include "gnome-portability.h"
+#include "gnome-program.h"
+
+#include <gobject/gboxed.h>
+#include <gobject/gvaluearray.h>
+#include <gobject/gvaluetypes.h>
+#include <gobject/gparamspecs.h>
+
+struct _GnomeProgramPrivate {
+    enum {
+	APP_UNINIT=0,
+	APP_CREATE_DONE=1,
+	APP_PREINIT_DONE=2,
+	APP_POSTINIT_DONE=3
+    } state;
+
+    /* Construction properties */
+    GnomeModuleInfo *prop_module_info;
+    gchar *prop_module_list;
+    int prop_popt_flags;
+    struct poptOptions *prop_popt_table;
+    gchar *prop_human_readable_name;
+    gchar *prop_app_prefix;
+    gchar *prop_app_libdir;
+    gchar *prop_app_sysconfdir;
+    gchar *prop_app_datadir;
+    gboolean prop_create_directories;
+
+    gchar **gnome_path;
+
+    /* valid-while: state > APP_CREATE_DONE */
+    char *app_id;
+    char *app_version;
+    char **argv;
+    int argc;
+
+    /* valid-while: state == APP_PREINIT_DONE */
+    poptContext arg_context;
+
+    /* valid-while: state == APP_PREINIT_DONE */
+    struct poptOptions *app_options;
+
+    /* valid-while: state == APP_PREINIT_DONE */
+    int app_popt_flags;
+
+    /* valid-while: state == APP_PREINIT_DONE */
+    GArray *top_options_table;
+};
+
+enum {
+    PROP_0,
+    PROP_MODULE_INFO,
+    PROP_MODULES,
+    PROP_APP_ID,
+    PROP_APP_VERSION,
+    PROP_HUMAN_READABLE_NAME,
+    PROP_GNOME_PATH,
+    PROP_APP_PREFIX,
+    PROP_APP_LIBDIR,
+    PROP_APP_DATADIR,
+    PROP_APP_SYSCONFDIR,
+    PROP_CREATE_DIRECTORIES,
+    PROP_POPT_TABLE,
+    PROP_POPT_FLAGS,
+    PROP_POPT_CONTEXT,
+    PROP_LAST
+};
+
+static void gnome_program_class_init    (GnomeProgramClass *klass);
+static void gnome_program_instance_init (GnomeProgram      *program);
+static void gnome_program_finalize      (GObject           *object);
+
+static GQuark quark_get_prop = 0;
+static GQuark quark_set_prop = 0;
+
+static GPtrArray *program_modules = NULL;
+static GPtrArray *program_module_list = NULL;
+static gboolean program_initialized = FALSE;
+static GnomeProgram *global_program = NULL;
+
+static guint last_property_id = PROP_LAST;
+static gpointer parent_class = NULL;
+
+#define	PREALLOC_CPARAMS (8)
+#define	PREALLOC_MODINFOS (8)
+
+GType
+gnome_program_get_type (void)
+{
+    static GType program_type = 0;
+
+    if (!program_type) {
+	static const GTypeInfo program_info = {
+	    sizeof (GnomeProgramClass),
+	    (GBaseInitFunc)         NULL,
+	    (GBaseFinalizeFunc)     NULL,
+	    (GClassInitFunc)        gnome_program_class_init,
+	    NULL,                   /* class_finalize */
+	    NULL,                   /* class_data */
+	    sizeof (GnomeProgram),
+	    0,                      /* n_preallocs */
+	    (GInstanceInitFunc)     gnome_program_instance_init
+	};
+
+	program_type = g_type_register_static
+	    (G_TYPE_OBJECT, "GnomeProgram", &program_info, 0);
+    }
+
+    return program_type;
+}
+
+static void
+gnome_program_set_property (GObject *object, guint param_id,
+			    const GValue *value, GParamSpec *pspec)
+{
+    GnomeProgram *program;
+
+    g_return_if_fail (object != NULL);
+    g_return_if_fail (GNOME_IS_PROGRAM (object));
+
+    program = GNOME_PROGRAM (object);
+
+    switch (param_id) {
+    case PROP_MODULE_INFO:
+	program->_priv->prop_module_info = g_value_dup_boxed ((GValue *) value);
+	break;
+    case PROP_MODULES:
+	program->_priv->prop_module_list = g_value_dup_string (value);
+	break;
+    case PROP_POPT_TABLE:
+	program->_priv->prop_popt_table = g_value_peek_pointer (value);
+	break;
+    case PROP_POPT_FLAGS:
+	program->_priv->prop_popt_flags = g_value_get_int (value);
+	break;
+    case PROP_HUMAN_READABLE_NAME:
+	program->_priv->prop_human_readable_name = g_value_dup_string (value);
+	break;
+    case PROP_GNOME_PATH:
+	if (program->_priv->gnome_path) {
+	    g_strfreev (program->_priv->gnome_path);
+	    program->_priv->gnome_path = NULL;
+	}
+	if (g_value_get_string (value))
+	    program->_priv->gnome_path = g_strsplit
+		(g_value_get_string (value), ":", -1);
+	break;
+    case PROP_APP_PREFIX:
+	program->_priv->prop_app_prefix = g_value_dup_string (value);
+	break;
+    case PROP_APP_SYSCONFDIR:
+	program->_priv->prop_app_sysconfdir = g_value_dup_string (value);
+	break;
+    case PROP_APP_DATADIR:
+	program->_priv->prop_app_datadir = g_value_dup_string (value);
+	break;
+    case PROP_APP_LIBDIR:
+	program->_priv->prop_app_libdir = g_value_dup_string (value);
+	break;
+    case PROP_CREATE_DIRECTORIES:
+	program->_priv->prop_create_directories = g_value_get_boolean (value);
+	break;
+    default: {
+	    GObjectSetPropertyFunc set_func;
+
+	    set_func = g_param_spec_get_qdata (pspec, quark_set_prop);
+	    if (set_func)
+		set_func (object, param_id, value, pspec);
+	    else
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+
+	    break;
+	}
+    }
+}
+
+static void
+gnome_program_get_property (GObject *object, guint param_id, GValue *value,
+			    GParamSpec *pspec)
+{
+    GnomeProgram *program;
+
+    g_return_if_fail (object != NULL);
+    g_return_if_fail (GNOME_IS_PROGRAM (object));
+
+    program = GNOME_PROGRAM (object);
+
+    switch (param_id) {
+    case PROP_APP_ID:
+	g_value_set_string (value, program->_priv->app_id);
+	break;
+    case PROP_APP_VERSION:
+	g_value_set_string (value, program->_priv->app_version);
+	break;
+    case PROP_HUMAN_READABLE_NAME:
+	g_value_set_string (value, program->_priv->prop_human_readable_name);
+	break;
+    case PROP_GNOME_PATH:
+	if (program->_priv->gnome_path)
+	    g_value_set_string (value, g_strjoinv (":", program->_priv->gnome_path));
+	else
+	    g_value_set_string (value, NULL);
+	break;
+    case PROP_APP_PREFIX:
+	g_value_set_string (value, program->_priv->prop_app_prefix);
+	break;
+    case PROP_APP_SYSCONFDIR:
+	g_value_set_string (value, program->_priv->prop_app_sysconfdir);
+	break;
+    case PROP_APP_DATADIR:
+	g_value_set_string (value, program->_priv->prop_app_datadir);
+	break;
+    case PROP_APP_LIBDIR:
+	g_value_set_string (value, program->_priv->prop_app_libdir);
+	break;
+    case PROP_CREATE_DIRECTORIES:
+	g_value_set_boolean (value, program->_priv->prop_create_directories);
+	break;
+    default: {
+	    GObjectSetPropertyFunc get_func;
+
+	    get_func = g_param_spec_get_qdata (pspec, quark_set_prop);
+	    if (get_func)
+		get_func (object, param_id, value, pspec);
+	    else
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+
+	    break;
+	}
+    }
+}
+
+static void
+add_to_module_list (const gchar *module_name)
+{
+    char **modnames;
+    int i, j;
+
+    if (!module_name)
+	return;
+
+    if (!program_module_list)
+	program_module_list = g_ptr_array_new ();
+
+    modnames = g_strsplit (module_name, ",", -1);
+    for (i = 0; modnames && modnames[i]; i++) {
+	for (j = 0; j < program_module_list->len; j++)
+	    if (!strcmp (modnames[i], g_ptr_array_index (program_module_list, j)))
+		return;
+
+	g_ptr_array_add (program_module_list, g_strdup (modnames[i]));
+    }
+    g_strfreev (modnames);
+}
+
+static int
+find_module_in_array (GnomeModuleInfo *ptr, GnomeModuleInfo **array)
+{
+    int i;
+
+    for (i = 0; array[i] && array[i] != ptr; i++) {
+	if (!strcmp(array[i]->name, ptr->name))
+	    break;
+    }
+
+    if (array[i])
+	return i;
+    else
+	return -1;
+}
+
+static void /* recursive */
+gnome_program_module_addtolist (GnomeModuleInfo **new_list,
+				int *times_visited,
+				int *num_items_used,
+				int new_item_idx)
+{
+    GnomeModuleInfo *new_item;
+    int i;
+
+    g_assert (new_item >= 0);
+
+    new_item = g_ptr_array_index (program_modules, new_item_idx);
+    if(!new_item)
+	return;
+
+    if (find_module_in_array (new_item, new_list) >= 0)
+	return; /* already cared for */
+
+    /* Does this item have any dependencies? */
+    if (times_visited[new_item_idx] > 0) {
+	/* We already tried to satisfy all the dependencies for this module,
+	 *  and we've come back to it again. There's obviously a loop going on.
+	 */
+	g_error ("Module '%s' version '%s' has a requirements loop.",
+		 new_item->name, new_item->version);
+    }
+    times_visited[new_item_idx]++;
+
+    if (new_item->requirements) {
+	for (i = 0; new_item->requirements[i].required_version; i++) {
+	    int n;
+
+	    n = find_module_in_array (new_item->requirements[i].module_info,
+				      (GnomeModuleInfo **)program_modules->pdata);
+	    gnome_program_module_addtolist
+		(new_list, times_visited, num_items_used, n);
+	}
+    }
+
+    /* now add this module on */
+    new_list[*num_items_used] = new_item;
+    (*num_items_used)++;
+    new_list[*num_items_used] = NULL;
+}
+
+static void
+gnome_program_module_list_order (void)
+{
+    int i;
+    GnomeModuleInfo **new_list;
+    int *times_visited; /* Detects dependency loops */
+    int num_items_used;
+
+    new_list = alloca (program_modules->len * sizeof(gpointer));
+    new_list[0] = NULL;
+    num_items_used = 0;
+  
+    times_visited = alloca (program_modules->len * sizeof(int));
+    memset(times_visited, '\0', program_modules->len * sizeof(int));
+
+    /* Create the new list with proper ordering */
+    for(i = 0; i < (program_modules->len - 1); i++) {
+	gnome_program_module_addtolist (new_list, times_visited,
+					&num_items_used, i);
+    }
+
+    /* Now stick the new, ordered list in place */
+    memcpy (program_modules->pdata, new_list,
+	    program_modules->len * sizeof(gpointer));
+}
+
+static GObject*
+gnome_program_constructor (GType type, guint n_construct_properties,
+			   GObjectConstructParam *construct_properties)
+{
+    GnomeProgram *program = NULL;
+    GnomeModuleInfo *module_info = NULL;
+    GObjectConstructParam *cparams = NULL;
+    guint n_modinfos = 0, n_cparams = 0, i;
+
+    if (!program_module_list)
+	program_module_list = g_ptr_array_new ();
+
+    if (!program_modules)
+	program_modules = g_ptr_array_new ();
+
+    /*
+     * First walk the list of construction properties and sort out
+     * GNOME_PARAM_MODULES and GNOME_PARAM_MODULE_INFO; we need to
+     * handle this here so we can load the modules before we create
+     * the GnomeProgram object.
+     */
+
+    for (i = 0; i < n_construct_properties; i++) {
+	GValue *value = construct_properties[i].value;
+	GParamSpec *pspec = construct_properties[i].pspec;
+
+	if (!strcmp (pspec->name, GNOME_PARAM_MODULES)) {
+	    if (program_initialized)
+		g_warning (G_STRLOC ": cannot use construction property \"%s\" "
+			   "when program is already initialized", pspec->name);
+	    else
+		add_to_module_list (g_value_get_string (value));
+	} else if (!strcmp (pspec->name, GNOME_PARAM_MODULE_INFO)) {
+	    if (!n_modinfos || n_modinfos >= PREALLOC_MODINFOS)
+		module_info = g_renew (GnomeModuleInfo, module_info,
+				       MAX (n_modinfos + 1, PREALLOC_MODINFOS));
+	    module_info[n_modinfos] = * (GnomeModuleInfo *)
+		g_value_get_boxed (value);
+	    n_modinfos++;
+	} else {
+	    if (!n_cparams || n_cparams >= PREALLOC_CPARAMS)
+		cparams = g_renew (GObjectConstructParam, cparams,
+				   MAX (n_cparams + 1, PREALLOC_CPARAMS));
+	    cparams[n_cparams].pspec = pspec;
+	    cparams[n_cparams].value = value;
+	    n_cparams++;
+	}
+    }
+
+    if (!program_initialized) {
+	/*
+	 * Load all the modules.
+	 */
+
+	for (i = 0; i < n_modinfos; i++)
+	    gnome_program_module_register (&module_info[i]);
+
+	for (i = 0; i < program_module_list->len; i++) {
+	    gchar *modname = g_ptr_array_index (program_module_list, i);
+
+	    gnome_program_module_load (modname);
+	}
+
+	for (i = 0; i < program_modules->len; i++) {
+	    GnomeModuleInfo *a_module = g_ptr_array_index (program_modules, i);
+
+	    if (a_module && a_module->init_pass)
+		a_module->init_pass (a_module);
+	}
+
+	/* Make sure the array is NULL-terminated */
+	g_ptr_array_add (program_modules, NULL);
+
+	/* 2. Order the module list for dependencies */
+	gnome_program_module_list_order ();
+
+	for (i = 0; i < program_modules->len; i++) {
+	    GnomeModuleInfo *a_module = g_ptr_array_index (program_modules, i);
+
+	    if (a_module && a_module->constructor)
+		a_module->constructor (type, n_cparams, cparams, a_module);
+	}
+    }
+
+    program = (GnomeProgram *) G_OBJECT_CLASS (parent_class)->constructor
+	(type, n_cparams, cparams);
+
+    if (!program_initialized) {
+	global_program = program;
+	g_object_ref (G_OBJECT (global_program));
+
+	program_initialized = TRUE;
+    }
+
+    return G_OBJECT (program);
+}
+
+static void
+gnome_program_class_init (GnomeProgramClass *class)
+{
+    GObjectClass *object_class;
+
+    object_class = (GObjectClass*) class;
+    parent_class = g_type_class_peek_parent (class);
+
+    quark_set_prop = g_quark_from_static_string ("gnome-program-set-property");
+    quark_get_prop = g_quark_from_static_string ("gnome-program-g-property");
+
+    object_class->constructor = gnome_program_constructor;
+    object_class->set_property = gnome_program_set_property;
+    object_class->get_property = gnome_program_get_property;
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_MODULE_INFO,
+	 g_param_spec_boxed (GNOME_PARAM_MODULE_INFO, NULL, NULL,
+			     GNOME_TYPE_MODULE_INFO,
+			     (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_MODULES,
+	 g_param_spec_string (GNOME_PARAM_MODULES, NULL, NULL,
+			      NULL,
+			      (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_POPT_TABLE,
+	 g_param_spec_pointer (GNOME_PARAM_POPT_TABLE, NULL, NULL,
+			       (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_POPT_FLAGS,
+	 g_param_spec_int (GNOME_PARAM_POPT_FLAGS, NULL, NULL,
+			   G_MININT, G_MAXINT, 0,
+			   (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_POPT_CONTEXT,
+	 g_param_spec_pointer (GNOME_PARAM_POPT_CONTEXT, NULL, NULL,
+			       (G_PARAM_READABLE)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_HUMAN_READABLE_NAME,
+	 g_param_spec_string (GNOME_PARAM_HUMAN_READABLE_NAME, NULL, NULL,
+			      NULL,
+			      (G_PARAM_READABLE | G_PARAM_WRITABLE |
+			       G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_GNOME_PATH,
+	 g_param_spec_string (GNOME_PARAM_GNOME_PATH, NULL, NULL,
+			      g_getenv ("GNOME2_PATH"),
+			      (G_PARAM_READABLE | G_PARAM_WRITABLE |
+			       G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_APP_ID,
+	 g_param_spec_string (GNOME_PARAM_APP_ID, NULL, NULL,
+			      NULL, G_PARAM_READABLE));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_APP_VERSION,
+	 g_param_spec_string (GNOME_PARAM_APP_VERSION, NULL, NULL,
+			      NULL, G_PARAM_READABLE));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_APP_PREFIX,
+	 g_param_spec_string (GNOME_PARAM_APP_PREFIX, NULL, NULL,
+			      GNOMEPREFIX,
+			      (G_PARAM_READABLE | G_PARAM_WRITABLE |
+			       G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_APP_LIBDIR,
+	 g_param_spec_string (GNOME_PARAM_APP_LIBDIR, NULL, NULL,
+			      GNOMELIBDIR,
+			      (G_PARAM_READABLE | G_PARAM_WRITABLE |
+			       G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_APP_DATADIR,
+	 g_param_spec_string (GNOME_PARAM_APP_DATADIR, NULL, NULL,
+			      GNOMEDATADIR,
+			      (G_PARAM_READABLE | G_PARAM_WRITABLE |
+			       G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_APP_SYSCONFDIR,
+	 g_param_spec_string (GNOME_PARAM_APP_SYSCONFDIR, NULL, NULL,
+			      GNOMESYSCONFDIR,
+			      (G_PARAM_READABLE | G_PARAM_WRITABLE |
+			       G_PARAM_CONSTRUCT_ONLY)));
+
+    g_object_class_install_property
+	(object_class,
+	 PROP_CREATE_DIRECTORIES,
+	 g_param_spec_boolean (GNOME_PARAM_CREATE_DIRECTORIES, NULL, NULL,
+			       TRUE,
+			       (G_PARAM_READABLE | G_PARAM_WRITABLE |
+				G_PARAM_CONSTRUCT_ONLY)));
+
+    object_class->finalize  = gnome_program_finalize;
+}
+
+static void
+gnome_program_instance_init (GnomeProgram *program)
+{
+    program->_priv = g_new0 (GnomeProgramPrivate, 1);
+
+    program->_priv->state = APP_CREATE_DONE;
+}
+
+static void
+gnome_program_finalize (GObject* object)
+{
+    GnomeProgram *program = GNOME_PROGRAM (object);
+
+    g_free (program->_priv);
+    program->_priv = NULL;
+  
+    if (G_OBJECT_CLASS (parent_class)->finalize)
+	(* G_OBJECT_CLASS (parent_class)->finalize) (object);
+}
+
+static gpointer
+gnome_module_info_init (void)
+{
+    return g_new0 (GnomeModuleInfo, 1);
+}
+
+static gpointer
+gnome_module_info_copy (gpointer boxed)
+{
+    return g_memdup (boxed, sizeof (GnomeModuleInfo));
+}
+
+static void
+gnome_module_info_free (gpointer boxed)
+{
+    g_free (boxed);
+}
+
+GType
+gnome_module_info_get_type (void)
+{
+    static GType module_info_type = 0;
+
+    if (!module_info_type)
+	module_info_type = g_boxed_type_register_static
+	    ("GnomeModuleInfo", gnome_module_info_init,
+	     gnome_module_info_copy, gnome_module_info_free,
+	     FALSE);
+
+    return module_info_type;
+}
+
+/**
+ * gnome_program_get:
+ *
+ * Returns an object that stores information on the GNOME application's state.
+ * If the object does not exist, it is created.
+ *
+ * Other functions assume that this will always return an appobject
+ * with state > APP_UNINIT
+ */
+
+GnomeProgram *
+gnome_program_get (void)
+{
+    return global_program;
+}
+
+/**
+ * gnome_program_get_name
+ * @program: The program object
+ *
+ * Description:
+ * This function returns a pointer to a static string that the
+ * application has provided as an identifier. This is not meant as a
+ * human-readable identifier so much as a unique identifier for
+ * programs and libraries.
+ *
+ * Returns: application ID string.
+ */
+const char *
+gnome_program_get_name (GnomeProgram *program)
+{
+    g_return_val_if_fail (program != NULL, NULL);
+    g_return_val_if_fail (GNOME_IS_PROGRAM (program), NULL);
+    g_return_val_if_fail (program->_priv->state >= APP_PREINIT_DONE, NULL);
+
+    return program->_priv->app_id;
+}
+
+/**
+ * gnome_program_get_version
+ * @app: The application object
+ *
+ * Description:
+ * This function returns a pointer to a static string that the
+ * application has provided as a version number. This is not meant as a
+ * human-readable identifier so much as a unique identifier for
+ * programs and libraries.
+ *
+ * Returns: application version string.
+ */
+const char *
+gnome_program_get_version (GnomeProgram *program)
+{
+    g_return_val_if_fail (program != NULL, NULL);
+    g_return_val_if_fail (GNOME_IS_PROGRAM (program), NULL);
+    g_return_val_if_fail (program->_priv->state >= APP_PREINIT_DONE, NULL);
+
+    return program->_priv->app_version;
+}
+
+/**
+ * gnome_program_get_human_readable_name
+ * @app: The application object
+ *
+ * Description:
+ * This function returns a pointer to a static string that the
+ * application has provided as a human readable name. The app
+ * should provide the name with the GNOME_PARAM_HUMAN_READABLE_NAME
+ * init argument. Returns NULL if no name was set.
+ *
+ * Returns: application human-readable name string.
+ */
+const char *
+gnome_program_get_human_readable_name (GnomeProgram *program)
+{
+    g_return_val_if_fail (program != NULL, NULL);
+    g_return_val_if_fail (GNOME_IS_PROGRAM (program), NULL);
+    g_return_val_if_fail (program->_priv->state >= APP_PREINIT_DONE, NULL);
+
+    return program->_priv->prop_human_readable_name;
+}
+
+guint
+gnome_program_install_property (GnomeProgramClass *pclass,
+				GObjectGetPropertyFunc get_fn,
+				GObjectSetPropertyFunc set_fn,
+				GParamSpec *pspec)
+{
+    g_return_val_if_fail (pclass != NULL, -1);
+    g_return_val_if_fail (GNOME_IS_PROGRAM_CLASS (pclass), -1);
+    g_return_val_if_fail (pspec != NULL, -1);
+
+    g_param_spec_set_qdata (pspec, quark_get_prop, get_fn);
+    g_param_spec_set_qdata (pspec, quark_set_prop, set_fn);
+
+    g_object_class_install_property (G_OBJECT_CLASS (pclass),
+				     last_property_id, pspec);
+
+    return last_property_id++;
+}
+
+/**
+ * gnome_program_locate_file:
+ * @domain: A domain (see GnomeFileDomain in gnome-program.h).
+ * @filename: A file name or path inside the 'domain' to find.
+ * @only_if_exists: Only return a full pathname if the specified file
+ *                  actually exists
+ * @ret_locations: If this is not NULL, a list of all the possible locations
+ *                 of the file will be returned.
+ *
+ * This function finds the full path to a file located in the specified
+ * "domain". A domain is a name for a collection of related files.
+ * For example, common domains are "libdir", "pixmap", and "config".
+ *
+ * The ret_locations list and its contents should be freed by the caller.
+ *
+ * Returns: The full path to the file (if it exists or only_if_exists is
+ *          FALSE) or NULL.
+ */
+gchar *
+gnome_program_locate_file (GnomeProgram *program, GnomeFileDomain domain,
+			   const gchar *file_name, gboolean only_if_exists,
+			   GSList **ret_locations)
+{
+    gchar *prefix_rel = NULL, *attr_name = NULL, *attr_rel = NULL;
+    gchar fnbuf [PATH_MAX], *retval = NULL, *lastval = NULL, **ptr;
+    gboolean append_app_id = FALSE;
+    GValue value = { 0, };
+
+    g_return_val_if_fail (program != NULL, NULL);
+    g_return_val_if_fail (GNOME_IS_PROGRAM (program), NULL);
+    g_return_val_if_fail (program->_priv->state >= APP_PREINIT_DONE, NULL);
+    g_return_val_if_fail (file_name != NULL, NULL);
+
+#define ADD_FILENAME(x) { \
+lastval = (x); \
+if(lastval) { if(ret_locations) *ret_locations = g_slist_append(*ret_locations, lastval); \
+if(!retval) retval = lastval; } \
+}
+
+    switch (domain) {
+    case GNOME_FILE_DOMAIN_LIBDIR:
+	prefix_rel = "/lib";
+	attr_name = GNOME_PARAM_APP_LIBDIR;
+	attr_rel = "";
+	break;
+    case GNOME_FILE_DOMAIN_DATADIR:
+	prefix_rel = "/share";
+	attr_name = GNOME_PARAM_APP_DATADIR;
+	attr_rel = "";
+	break;
+    case GNOME_FILE_DOMAIN_SOUND:
+	prefix_rel = "/share/sounds";
+	attr_name = GNOME_PARAM_APP_DATADIR;
+	attr_rel = "/sounds";
+	break;
+    case GNOME_FILE_DOMAIN_PIXMAP:
+	prefix_rel = "/share/pixmaps";
+	attr_name = GNOME_PARAM_APP_DATADIR;
+	attr_rel = "/pixmaps";
+	break;
+    case GNOME_FILE_DOMAIN_CONFIG:
+	prefix_rel = "/etc";
+	attr_name = GNOME_PARAM_APP_SYSCONFDIR;
+	attr_rel = "";
+	break;
+    case GNOME_FILE_DOMAIN_HELP:
+	prefix_rel = "/share/gnome/help";
+	attr_name = GNOME_PARAM_APP_DATADIR;
+	attr_rel = "/gnome/help";
+	break;
+    case GNOME_FILE_DOMAIN_APP_HELP:
+	prefix_rel = "/share/gnome/help";
+	attr_name = GNOME_PARAM_APP_DATADIR;
+	attr_rel = "/gnome/help";
+	append_app_id = TRUE;
+	break;
+    default:
+	g_warning (G_STRLOC ": unknown file domain %d", domain);
+	return NULL;
+    }
+
+    if (attr_name) {
+	const gchar *dir;
+
+	g_value_init (&value, G_TYPE_STRING);
+	g_object_get_property (G_OBJECT (program), attr_name, &value);
+	dir = g_value_get_string (&value);
+
+	if (dir) {
+	    if (append_app_id)
+		g_snprintf (fnbuf, sizeof (fnbuf), "%s%s/%s/%s",
+			    dir, attr_rel, program->_priv->app_id, file_name);
+	    else
+		g_snprintf (fnbuf, sizeof (fnbuf), "%s%s/%s",
+			    dir, attr_rel, file_name);
+
+	    if (!only_if_exists || g_file_test (fnbuf, G_FILE_TEST_EXISTS))
+		ADD_FILENAME (g_strdup (fnbuf));
+	}
+
+	g_value_unset (&value);
+    }
+    if (retval && !ret_locations)
+	goto out;
+
+    /* Now check the GNOME_PATH. */
+    for (ptr = program->_priv->gnome_path; ptr && *ptr; ptr++) {
+	if (append_app_id)
+	    g_snprintf (fnbuf, sizeof (fnbuf), "%s%s/%s/%s",
+			*ptr, prefix_rel, program->_priv->app_id, file_name);
+	else
+	    g_snprintf (fnbuf, sizeof (fnbuf), "%s%s/%s",
+			*ptr, prefix_rel, file_name);
+
+	if (!only_if_exists || g_file_test (fnbuf, G_FILE_TEST_EXISTS))
+	    ADD_FILENAME (g_strdup (fnbuf));
+    }
+    if (retval && !ret_locations)
+	goto out;
+
+ out:
+    return retval;
+}
+
+/******** modules *******/
+
+/* Stolen verbatim from rpm/lib/misc.c 
+   RPM is Copyright (c) 1998 by Red Hat Software, Inc.,
+   and may be distributed under the terms of the GPL and LGPL.
+*/
+/* compare alpha and numeric segments of two versions */
+/* return 1: a is newer than b */
+/*        0: a and b are the same version */
+/*       -1: b is newer than a */
+static int rpmvercmp(const char * a, const char * b) {
+    char oldch1, oldch2;
+    char * str1, * str2;
+    char * one, * two;
+    int rc;
+    int isnum;
+    
+    /* easy comparison to see if versions are identical */
+    if (!strcmp(a, b)) return 0;
+
+    str1 = g_alloca(strlen(a) + 1);
+    str2 = g_alloca(strlen(b) + 1);
+
+    strcpy(str1, a);
+    strcpy(str2, b);
+
+    one = str1;
+    two = str2;
+
+    /* loop through each version segment of str1 and str2 and compare them */
+    while (*one && *two) {
+	while (*one && !isalnum(*one)) one++;
+	while (*two && !isalnum(*two)) two++;
+
+	str1 = one;
+	str2 = two;
+
+	/* grab first completely alpha or completely numeric segment */
+	/* leave one and two pointing to the start of the alpha or numeric */
+	/* segment and walk str1 and str2 to end of segment */
+	if (isdigit(*str1)) {
+	    while (*str1 && isdigit(*str1)) str1++;
+	    while (*str2 && isdigit(*str2)) str2++;
+	    isnum = 1;
+	} else {
+	    while (*str1 && isalpha(*str1)) str1++;
+	    while (*str2 && isalpha(*str2)) str2++;
+	    isnum = 0;
+	}
+		
+	/* save character at the end of the alpha or numeric segment */
+	/* so that they can be restored after the comparison */
+	oldch1 = *str1;
+	*str1 = '\0';
+	oldch2 = *str2;
+	*str2 = '\0';
+
+	/* take care of the case where the two version segments are */
+	/* different types: one numeric and one alpha */
+	if (one == str1) return -1;	/* arbitrary */
+	if (two == str2) return -1;
+
+	if (isnum) {
+	    /* this used to be done by converting the digit segments */
+	    /* to ints using atoi() - it's changed because long  */
+	    /* digit segments can overflow an int - this should fix that. */
+	  
+	    /* throw away any leading zeros - it's a number, right? */
+	    while (*one == '0') one++;
+	    while (*two == '0') two++;
+
+	    /* whichever number has more digits wins */
+	    if (strlen(one) > strlen(two)) return 1;
+	    if (strlen(two) > strlen(one)) return -1;
+	}
+
+	/* strcmp will return which one is greater - even if the two */
+	/* segments are alpha or if they are numeric.  don't return  */
+	/* if they are equal because there might be more segments to */
+	/* compare */
+	rc = strcmp(one, two);
+	if (rc) return rc;
+	
+	/* restore character that was replaced by null above */
+	*str1 = oldch1;
+	one = str1;
+	*str2 = oldch2;
+	two = str2;
+    }
+
+    /* this catches the case where all numeric and alpha segments have */
+    /* compared identically but the segment sepparating characters were */
+    /* different */
+    if ((!*one) && (!*two)) return 0;
+
+    /* whichever version still has characters left over wins */
+    if (!*one) return -1; else return 1;
+}
+
+static gboolean
+gnome_program_version_check (const char *required_version,
+			     const char *provided_version)
+{
+    if (required_version && provided_version)
+	return (rpmvercmp (provided_version, required_version) >= 0);
+    else
+	return TRUE;
+}
+
+/**
+ * gnome_program_module_registered:
+ * @module_info: A pointer to a GnomeModuleInfo structure describing the module
+ *               to be queried
+ *
+ * Description: This method checks to see whether a specific module has been
+ *              initialized in the specified program.
+ *
+ * Returns: A value indicating whether the specified module has been
+ *          registered/initialized in the current program
+ */
+gboolean
+gnome_program_module_registered (const GnomeModuleInfo *module_info)
+{
+    int i;
+    GnomeModuleInfo *curmod;
+
+    g_return_val_if_fail (module_info, FALSE);
+
+    if (!program_modules)
+	program_modules = g_ptr_array_new ();
+
+    for(i = 0; i < program_modules->len; i++) {
+	curmod = g_ptr_array_index (program_modules, i);
+	if(curmod == module_info
+	   || !strcmp (curmod->name, module_info->name))
+	    return TRUE;
+    }
+
+    return FALSE;
+}
+
+/**
+ * gnome_program_module_register:
+ * @module_info: A pointer to a GnomeModuleInfo structure describing the module
+ *               to be initialized
+ *
+ * Description:
+ * This function is used to register a module to be initialized by the
+ * GNOME library framework. The memory pointed to by 'module_info' must be
+ * valid during the whole application initialization process, and the module
+ * described by 'module_info' must only use the 'module_info' pointer to
+ * register itself.
+ *
+ */
+void
+gnome_program_module_register (const GnomeModuleInfo *module_info)
+{
+    int i;
+
+    g_return_if_fail (module_info);
+
+    if (program_initialized) {
+	g_warning (G_STRLOC ": cannot load modules after program is initialized");
+	return;
+    }
+
+    if (!program_modules)
+	program_modules = g_ptr_array_new();
+
+    /* Check that it's not already registered. */
+
+    if (gnome_program_module_registered (module_info))
+	return;
+
+    g_ptr_array_add (program_modules, (GnomeModuleInfo *)module_info);
+
+    /* We register requirements *after* the module itself to avoid loops.
+       Initialization order gets sorted out later on. */
+    if (module_info->requirements) {
+	for(i = 0; module_info->requirements[i].required_version; i++) {
+	    GnomeModuleInfo *dep_mod;
+
+	    dep_mod = module_info->requirements[i].module_info;
+	    if (gnome_program_version_check (module_info->requirements[i].required_version,
+					     dep_mod->version))
+		gnome_program_module_register (dep_mod);
+	    else
+		/* The required version is not installed */
+		/* I18N needed */
+		g_error ("Module '%s' requires version '%s' of module '%s' "
+			 "to be installed, and you only have version '%s' of '%s'. "
+			 "Aborting application.",
+			 module_info->name,
+			 module_info->requirements[i].required_version,
+			 dep_mod->name,
+			 dep_mod->version,
+			 dep_mod->name);
+	}
+    }
+}
+
+/**
+ * gnome_program_preinit:
+ * @program: Application object
+ * @app_id: application ID string
+ * @app_version: application version string
+ * @argc: The number of commmand line arguments contained in 'argv'
+ * @argv: A string array of command line arguments
+ *
+ * Description:
+ * This function performs the portion of application initialization that
+ * needs to be done prior to command line argument parsing. The poptContext
+ * returned can be used for getopt()-style option processing.
+ *
+ * Returns: A poptContext representing the argument parsing state.
+ */
+poptContext
+gnome_program_preinit (GnomeProgram *program,
+		       const char *app_id, const char *app_version,
+		       int argc, char **argv)
+{
+    GnomeModuleInfo *a_module;
+    poptContext argctx;
+    int i;
+
+    g_return_val_if_fail (program != NULL, NULL);
+    g_return_val_if_fail (GNOME_IS_PROGRAM (program), NULL);
+
+    if (program->_priv->state != APP_CREATE_DONE)
+	return NULL;
+
+    /* On non-glibc systems, this is not set up for us.  */
+    if (!program_invocation_name) {
+	program_invocation_name = argv[0];
+	program_invocation_short_name = g_path_get_basename (program_invocation_name);
+    }
+
+    /* 0. Misc setup */
+    if (program->_priv->app_id)
+	g_free (program->_priv->app_id);
+    program->_priv->app_id = g_strdup (app_id);
+    g_set_prgname (app_id);
+    if (program->_priv->app_version)
+	g_free (program->_priv->app_version);
+    program->_priv->app_version = g_strdup (app_version);
+    program->_priv->argc = argc;
+    program->_priv->argv = argv;
+
+    if (!program_modules)
+	program_modules = g_ptr_array_new();
+
+    /* Major steps in this function:
+       1. Process all framework attributes in 'attrs'
+       2. Order the module list for dependencies
+       3. Call the preinit functions for the modules
+       4. Process other attributes 
+       5. Create a top-level 'struct poptOption *' for use in arg-parsing.
+       6. Create a poptContext
+       7. Cleanup/return
+    */
+
+    /* 3. call the pre-init functions */
+    for (i = 0; (a_module = g_ptr_array_index (program_modules, i)); i++) {
+	if (a_module->pre_args_parse)
+	    a_module->pre_args_parse (program, a_module);
+    }
+
+    /* 5. Create a top-level 'struct poptOption *' for use in arg-parsing. */
+    {
+	struct poptOption includer = {NULL, '\0', POPT_ARG_INCLUDE_TABLE,
+				      NULL, 0, NULL, NULL};
+
+	program->_priv->top_options_table = g_array_new
+	    (TRUE, TRUE, sizeof (struct poptOption));
+
+	/* Put the special popt table in first */
+	includer.arg = poptHelpOptions;
+	includer.descrip = N_("Help options");
+	g_array_append_val (program->_priv->top_options_table, includer);
+
+	if (program->_priv->prop_popt_table) {
+	    includer.arg = program->_priv->prop_popt_table;
+	    includer.descrip = N_("Application options");
+	    g_array_append_val (program->_priv->top_options_table,
+				includer);
+	}
+
+	for (i = 0; (a_module = g_ptr_array_index(program_modules, i)); i++) {
+	    if (a_module->options) {
+		includer.arg = a_module->options;
+		includer.descrip = (char *)a_module->description;
+
+		g_array_append_val (program->_priv->top_options_table, includer);
+	    }
+	}
+
+	includer.longName = "load-modules";
+	includer.argInfo = POPT_ARG_STRING;
+	includer.descrip = N_("Dynamic modules to load");
+	includer.argDescrip = N_("MODULE1,MODULE2,...");
+	g_array_append_val (program->_priv->top_options_table, includer);
+    }
+
+    argctx = program->_priv->arg_context = poptGetContext
+	(program->_priv->app_id, argc, (const char **) argv,
+	 (struct poptOption *) program->_priv->top_options_table->data,
+	 program->_priv->prop_popt_flags);
+  
+    /* 7. Cleanup/return */
+    program->_priv->state = APP_PREINIT_DONE;
+
+    return argctx;
+}
+
+/**
+ * gnome_program_module_load:
+ * @program: Application object
+ * @mod_name: module name
+ *
+ * Loads a shared library that contains a
+ * 'GnomeModuleInfo dynamic_module_info' structure.
+ */
+void
+gnome_program_module_load (const char *mod_name)
+{
+    GModule *mh;
+    GnomeModuleInfo *gmi;
+    char tbuf[1024];
+
+    g_return_if_fail (mod_name != NULL);
+
+    if (program_initialized) {
+	g_warning (G_STRLOC ": cannot load modules after program is initialized");
+	return;
+    }
+
+    g_snprintf (tbuf, sizeof(tbuf), "lib%s.so.0", mod_name);
+
+    mh = g_module_open (mod_name, G_MODULE_BIND_LAZY);
+    if(!mh) {
+	g_snprintf (tbuf, sizeof(tbuf), "lib%s.so", mod_name);
+
+	mh = g_module_open (mod_name, G_MODULE_BIND_LAZY);
+    }
+
+    if (!mh)
+	return;
+
+    if (g_module_symbol (mh, "dynamic_module_info", (gpointer *)&gmi)) {
+	gnome_program_module_register (gmi);
+	g_module_make_resident (mh);
+    } else
+	g_module_close (mh);
+}
+
+/**
+ * gnome_program_parse_args:
+ * @app: Application object
+ *
+ * Description: Parses the command line arguments for the application
+ */
+void
+gnome_program_parse_args (GnomeProgram *program)
+{
+    int nextopt;
+    poptContext ctx;
+
+    g_return_if_fail (program != NULL);
+    g_return_if_fail (GNOME_IS_PROGRAM (program));
+
+    if (program->_priv->state != APP_PREINIT_DONE)
+	return;
+
+    ctx = program->_priv->arg_context;
+    while ((nextopt = poptGetNextOpt (ctx)) > 0 || nextopt == POPT_ERROR_BADOPT)
+	/* do nothing */ ;
+
+    if (nextopt != -1) {
+	g_print ("Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n",
+		 poptBadOption (ctx, 0),
+		 poptStrerror (nextopt),
+		 program->_priv->argv[0]);
+	exit (1);
+    }
+}
+
+/**
+ * gnome_program_postinit:
+ * @program: Application object
+ *
+ * Description: Called after gnome_program_parse_args(), this function
+ * takes care of post-parse initialization and cleanup
+ */
+void
+gnome_program_postinit (GnomeProgram *program)
+{
+    int i;
+    GnomeModuleInfo *a_module;
+
+    g_return_if_fail (program != NULL);
+    g_return_if_fail (GNOME_IS_PROGRAM (program));
+
+    if (program->_priv->state != APP_PREINIT_DONE)
+	return;
+
+    /* Call post-parse functions */
+    for (i = 0; (a_module = g_ptr_array_index(program_modules, i)); i++) {
+	if (a_module->post_args_parse)
+	    a_module->post_args_parse (program, a_module);
+    }
+
+    /* Free up stuff we don't need to keep around for the lifetime of the app */
+#if 0
+    g_ptr_array_free (program_modules, TRUE);
+    program_modules = NULL;
+#endif
+
+    g_array_free (program->_priv->top_options_table, TRUE);
+    program->_priv->top_options_table = NULL;
+
+    g_blow_chunks(); /* Try to compact memory usage a bit */
+
+    program->_priv->state = APP_POSTINIT_DONE;
+}
+
+/**
+ * gnome_program_init:
+ * @program_id: Application ID string
+ * @app_version: Application version string
+ * @argc: The number of commmand line arguments contained in 'argv'
+ * @argv: A string array of command line arguments
+ * @...: a NULL-terminated list of attribute name/value pairs
+ *
+ * Description:
+ * Performs application initialization.
+ */
+GnomeProgram *
+gnome_program_init (const char *app_id, const char *app_version,
+		    int argc, char **argv,
+		    const char *first_property_name, ...)
+{
+    GnomeProgram *program;
+    va_list args;
+
+    va_start(args, first_property_name);
+    program = gnome_program_initv (app_id, app_version, argc, argv,
+				   first_property_name, args);
+    va_end(args);
+
+    return program;
+}
+
+GnomeProgram *
+gnome_program_initv (const char *app_id, const char *app_version,
+		     int argc, char **argv,
+		     const char *first_property_name, va_list args)
+{
+    GnomeProgram *program;
+    int i;
+
+    libgnome_type_init ();
+
+    if (!program_initialized) {
+	const char *ctmp;
+
+	program_module_list = g_ptr_array_new ();
+	program_modules = g_ptr_array_new ();
+
+	/* We have to handle --load-modules=foo,bar,baz specially */
+	for (i = 0; i < argc; i++) {
+	    if (!strncmp (argv[i], "--load-modules=", strlen ("--load-modules=")))
+		add_to_module_list (argv[i] + strlen("--load-modules="));
+	}
+
+	if ((ctmp = g_getenv ("GNOME_MODULES")))
+	    add_to_module_list (ctmp);
+    }
+
+    program = g_object_new_valist (GNOME_TYPE_PROGRAM,
+				   first_property_name, args);
+
+    gnome_program_preinit (program, app_id, app_version, argc, argv);
+    gnome_program_parse_args (program);
+    gnome_program_postinit (program);
+
+    return program;
+}
diff --git a/libgnome/gnome-program.h b/libgnome/gnome-program.h
new file mode 100644
index 0000000..d61f56b
--- /dev/null
+++ b/libgnome/gnome-program.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
+ * 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@
+ */
+
+
+/* This module takes care of handling application and library
+   initialization and command line parsing */
+
+#ifndef GNOME_PROGRAM_H
+#define GNOME_PROGRAM_H
+
+#include <glib.h>
+#include <popt.h>
+#include <stdarg.h>
+
+#include "gnome-defs.h"
+#include <gobject/gobject.h>
+
+BEGIN_GNOME_DECLS
+
+#define GNOME_TYPE_PROGRAM            (gnome_program_get_type ())
+#define GNOME_PROGRAM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GNOME_TYPE_PROGRAM, GnomeProgram))
+#define GNOME_PROGRAM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GNOME_TYPE_PROGRAM, GnomeProgramClass))
+#define GNOME_IS_PROGRAM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GNOME_TYPE_PROGRAM))
+#define GNOME_IS_PROGRAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GNOME_TYPE_PROGRAM))
+
+typedef struct _GnomeProgram          GnomeProgram;
+typedef struct _GnomeProgramPrivate   GnomeProgramPrivate;
+typedef struct _GnomeProgramClass     GnomeProgramClass;
+
+typedef enum _GnomeFileDomain         GnomeFileDomain;
+
+enum _GnomeFileDomain {
+    GNOME_FILE_DOMAIN_UNKNOWN = 0,
+    GNOME_FILE_DOMAIN_LIBDIR,
+    GNOME_FILE_DOMAIN_DATADIR,
+    GNOME_FILE_DOMAIN_SOUND,
+    GNOME_FILE_DOMAIN_PIXMAP,
+    GNOME_FILE_DOMAIN_CONFIG,
+    GNOME_FILE_DOMAIN_HELP,
+    GNOME_FILE_DOMAIN_APP_HELP
+};
+
+struct _GnomeProgram
+{
+    GObject object;
+
+    GnomeProgramPrivate *_priv;
+};
+
+struct _GnomeProgramClass
+{
+    GObjectClass object_class;
+};
+
+GType
+gnome_program_get_type                  (void);
+
+GnomeProgram *
+gnome_program_get                       (void);
+
+const char*
+gnome_program_get_human_readable_name   (GnomeProgram *program);
+
+const char *
+gnome_program_get_name                  (GnomeProgram *program);
+
+const char *
+gnome_program_get_version               (GnomeProgram *program);
+
+gchar *
+gnome_program_locate_file               (GnomeProgram    *program,
+					 GnomeFileDomain  domain,
+					 const gchar     *file_name,
+					 gboolean         only_if_exists,
+					 GSList         **ret_locations);
+
+#define GNOME_PARAM_MODULE_INFO         "module-info"
+#define GNOME_PARAM_MODULES             "modules"
+#define GNOME_PARAM_POPT_TABLE          "popt-table"
+#define GNOME_PARAM_POPT_FLAGS          "popt-flags"
+#define GNOME_PARAM_POPT_CONTEXT        "popt-context"
+#define GNOME_PARAM_CREATE_DIRECTORIES  "create-directories"
+#define GNOME_PARAM_ESPEAKER            "espeaker"
+#define GNOME_PARAM_ENABLE_SOUND        "enable-sound"
+#define GNOME_PARAM_FILE_LOCATOR        "file-locator"
+#define GNOME_PARAM_APP_ID              "app-id"
+#define GNOME_PARAM_APP_VERSION         "app-version"
+#define GNOME_PARAM_APP_PREFIX          "app-prefix"
+#define GNOME_PARAM_APP_SYSCONFDIR      "app-sysconfdir"
+#define GNOME_PARAM_APP_DATADIR         "app-datadir"
+#define GNOME_PARAM_APP_LIBDIR          "app-libdir"
+#define GNOME_PARAM_HUMAN_READABLE_NAME "human-readable-name"
+#define GNOME_PARAM_GNOME_PATH          "gnome-path"
+
+/***** application modules (aka libraries :) ******/
+#define GNOME_TYPE_MODULE_INFO          (gnome_module_info_get_type ())
+
+GType
+gnome_module_info_get_type              (void);
+
+typedef struct _GnomeModuleInfo GnomeModuleInfo;
+typedef struct _GnomeModuleRequirement GnomeModuleRequirement;
+
+struct _GnomeModuleRequirement {
+    const char *required_version;
+    GnomeModuleInfo *module_info;
+};
+
+typedef void (*GnomeModuleInitHook) (const GnomeModuleInfo *mod_info);
+typedef void (*GnomeModuleConstructor) (GType type, guint n_construct_props,
+					GObjectConstructParam *construct_props,
+					const GnomeModuleInfo *mod_info);
+typedef void (*GnomeModuleHook) (GnomeProgram *program,
+				 const GnomeModuleInfo *mod_info);
+
+struct _GnomeModuleInfo {
+    const char *name, *version, *description;
+    GnomeModuleRequirement *requirements; /* last element has NULL version */
+
+    GnomeModuleHook pre_args_parse, post_args_parse;
+
+    struct poptOption *options;
+
+    GnomeModuleInitHook init_pass; /* This gets run before the preinit
+				      function to allow the module to
+				      register other modules as needed. The
+				      module cannot assume its required
+				      modules are initialized (they aren't). */
+
+    GnomeModuleConstructor constructor;
+
+    gpointer expansion1, expansion2;
+};
+
+/* This function should be called before gnomelib_preinit() - it's an
+ * alternative to the "module" property passed by the app.
+ */
+void
+gnome_program_module_register (const GnomeModuleInfo *module_info);
+
+gboolean
+gnome_program_module_registered (const GnomeModuleInfo *module_info);
+
+void
+gnome_program_module_load (const char *mod_name);
+
+guint
+gnome_program_install_property (GnomeProgramClass *pclass,
+				GObjectGetPropertyFunc get_fn,
+				GObjectSetPropertyFunc set_fn,
+				GParamSpec *pspec);
+
+/*
+ * If the application writer wishes to use getopt()-style arg
+ * processing, they can do it using a while looped sandwiched between
+ * calls to these two functions.
+ */
+poptContext
+gnome_program_preinit (GnomeProgram *program,
+		       const char *app_id,
+		       const char *app_version,
+		       int argc, char **argv);
+
+void
+gnome_program_parse_args (GnomeProgram *program);
+
+void
+gnome_program_postinit (GnomeProgram *program);
+
+/* These are convenience functions that calls gnomelib_preinit(...), have
+   popt parse all args, and then call gnomelib_postinit() */
+GnomeProgram *
+gnome_program_init (const char *app_id, const char *app_version,
+		    int argc, char **argv,
+		    const char *first_property_name, ...);
+
+GnomeProgram *
+gnome_program_initv (const char *app_id, const char *app_version,
+		     int argc, char **argv,
+		     const char *first_property_name, va_list args);
+
+/* Some systems, like Red Hat 4.0, define these but don't declare
+   them.  Hopefully it is safe to always declare them here.  */
+extern char *program_invocation_short_name;
+extern char *program_invocation_name;
+
+#endif
diff --git a/libgnome/gnome-regex.c b/libgnome/gnome-regex.c
new file mode 100644
index 0000000..8d20b3e
--- /dev/null
+++ b/libgnome/gnome-regex.c
@@ -0,0 +1,162 @@
+/* gnome-regex.c - Implementation of regex cache object.
+
+   Copyright (C) 1998 Tom Tromey
+   All rights reserved.
+
+   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 "libgnomeP.h"
+#include "gnome-regex.h"
+
+#define DEFAULT_SIZE 96
+
+/**
+ * gnome_regex_cache_new:
+ * 
+ * Creates a new regular expression cache object.
+ * 
+ * Return value: the new cache object.
+ **/
+GnomeRegexCache *
+gnome_regex_cache_new (void)
+{
+	GnomeRegexCache *rxc = g_new (GnomeRegexCache, 1);
+	rxc->size = DEFAULT_SIZE;
+	rxc->next = 0;
+	rxc->regexs = g_new0 (char *, rxc->size);
+	rxc->patterns = g_new (regex_t, rxc->size);
+	return rxc;
+}
+
+static void
+free_element (GnomeRegexCache *rxc, int elt)
+{
+	if (rxc->regexs[elt]) {
+		g_free (rxc->regexs[elt]);
+
+		/* We only want to try to free a pattern if we know it
+		   has been allocated.  Hence this is inside the
+		   `if'. */
+		regfree (&rxc->patterns[elt]);
+	}
+}
+
+/**
+ * gnome_regex_cache_destroy:
+ * @rxc: A regular expression cache object
+ * 
+ * Destroys a regular expression cache object.
+ **/
+void
+gnome_regex_cache_destroy (GnomeRegexCache *rxc)
+{
+	int i;
+
+	for (i = 0; i < rxc->size; ++i) {
+		free_element (rxc, i);
+	}
+
+	g_free (rxc->regexs);
+	g_free (rxc->patterns);
+	g_free (rxc);
+}
+
+/**
+ * gnome_regex_cache_set_size:
+ * @rxc: A regular expression cache object
+ * @new_size: new size of cache
+ * 
+ * Sets the maxiumum number of regular expressions the cache can
+ * hold.  If this is less than the number of currently cached
+ * expressions, then the oldest expressions are deleted.
+ **/
+void
+gnome_regex_cache_set_size (GnomeRegexCache *rxc, int new_size)
+{
+	if (new_size == rxc->size)
+		return;
+
+	if (new_size < rxc->size) {
+		int i;
+		for (i = new_size + 1; i < rxc->size; ++i) {
+			free_element (rxc, i);
+		}
+	}
+	rxc->regexs = (char **) g_realloc (rxc->regexs,
+					   new_size * sizeof (char *));
+	rxc->patterns = (regex_t *) g_realloc (rxc->patterns,
+					       new_size * sizeof (regex_t));
+	if (new_size > rxc->size) {
+		memset (&rxc->regexs[rxc->size + 1], 0,
+			(new_size - rxc->size) * sizeof (char *));
+	}
+	rxc->size = new_size;
+	if (rxc->next >= new_size) {
+		rxc->next = 0;
+	}
+}
+
+/**
+ * gnome_regex_cache_compile:
+ * @rxc: A regular expression cache object
+ * @pattern: A string representing a regular expression
+ * @flags: Flags to pass to regcomp()
+ * 
+ * This compiles a regular expression.  If the expression is cached,
+ * the previously computed value is returned.  Otherwise, the
+ * expression is compiled, cached, and then returned.
+ * 
+ * Return value: a compiled regular expression, or %NULL on error.
+ **/
+regex_t *
+gnome_regex_cache_compile (GnomeRegexCache *rxc, const char *pattern,
+			   int flags)
+{
+	int i;
+	regex_t rx;
+
+	for (i = 0; i < rxc->size; ++i) {
+		if (! rxc->regexs[i])
+			break;
+		if (! strcmp (rxc->regexs[i], pattern)) {
+			return &rxc->patterns[i];
+		}
+	}
+
+	free_element (rxc, rxc->next);
+
+	/* FIXME: use GNU regex call here?  */
+	if (regcomp (&rx, pattern, flags)) {
+		/* Failure.  */
+		return NULL;
+	}
+
+	rxc->regexs[rxc->next] = g_strdup (pattern);
+	memcpy (&rxc->patterns[rxc->next], &rx, sizeof (regex_t));
+
+	i = rxc->next;
+	if (++rxc->next >= rxc->size)
+		rxc->next = 0;
+
+	return &rxc->patterns[i];
+}
diff --git a/libgnome/gnome-regex.h b/libgnome/gnome-regex.h
new file mode 100644
index 0000000..380dda5
--- /dev/null
+++ b/libgnome/gnome-regex.h
@@ -0,0 +1,64 @@
+/* gnome-regex.h - Regular expression cache object.
+
+   Copyright (C) 1998 Tom Tromey
+   All rights reserved.
+
+   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_REGEX_H
+#define GNOME_REGEX_H
+
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_DECLS
+
+#include <sys/types.h>
+#include <regex.h>
+
+typedef struct _GnomeRegexCache GnomeRegexCache;
+struct _GnomeRegexCache {
+	char **regexs;		/* Regular expression strings.  */
+	regex_t *patterns;	/* Compiled expressions.  */
+	int size;		/* Total number of cache slots.  */
+	int next;		/* Next available slot.  */
+	/* FIXME: probably should cache compilation flags along with
+	   regex and use those to determine caching.  For now we
+	   assume that the flags never change.  Another option would
+	   be to put the flag info into this structure and just not
+	   let the user ever change it.  */
+};
+
+/* Create a new regular expression cache with default number of
+   items.  */
+GnomeRegexCache *gnome_regex_cache_new (void);
+
+/* Free a regular expression cache.  */
+void gnome_regex_cache_destroy (GnomeRegexCache *rxc);
+
+/* Change number of cache slots.  */
+void gnome_regex_cache_set_size (GnomeRegexCache *rxc, int new_size);
+
+/* Compile a regular expression.  */
+regex_t *gnome_regex_cache_compile (GnomeRegexCache *rxc, const char *pattern,
+				    int flags);
+
+
+END_GNOME_DECLS
+
+#endif /* GNOME_REGEX_H */
diff --git a/libgnome/gnome-remote.c b/libgnome/gnome-remote.c
new file mode 100644
index 0000000..f306c4e
--- /dev/null
+++ b/libgnome/gnome-remote.c
@@ -0,0 +1,101 @@
+/* gnome-remote.c - Handle remote execution configuration.
+
+   Copyright (C) 1998 Tom Tromey
+   All rights reserved.
+
+   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 "libgnomeP.h"
+
+/* Name of key where remote config stored.  */
+#define BASE "/Gnome/Remote/"
+
+/* Subkey where default command stored.  Try to pick something
+   unlikely to be the name of an actual host.  */
+#define DEFAULT "__default__"
+
+/**
+ * gnome_remote_get_command:
+ * @host: Host where command should be run
+ * @argcp: Result parameter; number of elements in rsh command
+ * @argvp: Result parameter; the actual rsh command to use
+ * 
+ * Given a host, this function will return the user's desired
+ * `rsh'-like command to use to contact that host.  This lets the user
+ * choose how to log in on a host-by-host basis.  If @host is %NULL,
+ * then the user's default remote shell command is chosen.
+ **/
+void
+gnome_remote_get_command (const char *host, gint *argcp, char ***argvp)
+{
+  gboolean def = TRUE;
+
+  if (host)
+    {
+      gchar *path = g_strconcat (BASE, host, NULL);
+      gnome_config_get_vector_with_default (path, argcp, argvp, &def);
+      g_free (path);
+    }
+
+  if (def)
+    {
+      /* No entry for this host, or we were requested to return the
+	 default.  So try that.  */
+      gnome_config_get_vector_with_default (BASE DEFAULT, argcp, argvp, &def);
+      if (def)
+	{
+	  /* No default.  So use built-in default.  FIXME on some
+	     machines this should be "remsh".  Enter configure... */
+	  *argvp = (char **) g_malloc (2 * sizeof (char *));
+	  (*argvp)[0] = g_strdup ("rsh");
+	  (*argvp)[1] = NULL;
+	  *argcp = 1;
+	}
+    }
+}
+
+/**
+ * gnome_remote_set_command:
+ * @host: Name of host
+ * @argc: Number of elements in argument vector
+ * @argv: Command line to use to contact host
+ * 
+ * This sets the appropriate options in the config database so that
+ * subsequent calls to gnome_remote_get_command() will return @argv.
+ * If @host is %NULL, then the user's default remote shell is set.
+ * If @argc is %0, then this instance of the command is deleted.
+ **/
+void
+gnome_remote_set_command (const char *host, gint argc, const char * const argv[])
+{
+  gchar *path;
+
+  if (host)
+    path = g_strconcat (BASE, host, NULL);
+  else
+    path = BASE DEFAULT;
+
+  gnome_config_clean_key (path);
+
+  if (argc)
+    gnome_config_set_vector (path, argc, argv);
+
+  if (host)
+    g_free (path);
+}
diff --git a/libgnome/gnome-remote.h b/libgnome/gnome-remote.h
new file mode 100644
index 0000000..da161a0
--- /dev/null
+++ b/libgnome/gnome-remote.h
@@ -0,0 +1,45 @@
+/* gnome-remote.h - Handle remote execution configuration.
+
+   Copyright (C) 1998 Tom Tromey
+   All rights reserved.
+
+   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_REMOTE_H
+#define GNOME_REMOTE_H
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_DECLS
+
+/* Return a command which should be used to run a program on HOST.
+   Typically this command will be something like "rsh".  If HOST is
+   NULL, this returns the default command that should be used; typical
+   programs should not use this information.  */
+void gnome_remote_get_command (const char *host, gint *argcp, char ***argvp);
+
+/* Set the command which should be used to run a program on HOST.  If
+   ARGC is 0, then any current binding for HOST is removed.  If HOST
+   is NULL, the default command is set.  */
+void gnome_remote_set_command (const char *host, gint argc, const char * const argv[]);
+
+END_GNOME_DECLS
+
+#endif /* GNOME_REMOTE_H */
diff --git a/libgnome/gnome-sound.c b/libgnome/gnome-sound.c
new file mode 100644
index 0000000..69666c0
--- /dev/null
+++ b/libgnome/gnome-sound.c
@@ -0,0 +1,513 @@
+/*
+ * 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
+
+static char *esound_hostname;
+
+int gnome_sound_connection = -1;
+
+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.
+ *
+ */
+static GnomeSoundSample *
+gnome_sound_sample_load_wav(const char *file)
+{
+#ifdef HAVE_ESD
+  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);
+#endif
+
+  return NULL;
+}
+#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
+  esound_hostname = g_strdup (hostname);
+  if(gnome_sound_connection < 0)
+    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..1071f75
--- /dev/null
+++ b/libgnome/gnome-sound.h
@@ -0,0 +1,51 @@
+/*
+ * 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>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_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);
+
+END_GNOME_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..1ca42fc
--- /dev/null
+++ b/libgnome/gnome-triggers.h
@@ -0,0 +1,85 @@
+/*
+ * 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>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_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[]);
+
+END_GNOME_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
new file mode 100644
index 0000000..fa4c7de
--- /dev/null
+++ b/libgnome/gnome-url.c
@@ -0,0 +1,485 @@
+/* gnome-url.c
+ * Copyright (C) 1998, James Henstridge <james daa com au>
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc.,  59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include <glib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <libgnome/gnome-defs.h>
+#include <libgnome/gnome-config.h>
+#include <libgnome/gnome-exec.h>
+#include <libgnome/gnome-util.h>
+#include <libgnome/gnome-portability.h>
+#include "gnome-url.h"
+#include "gnome-i18nP.h"
+#include <popt.h>
+
+#define DEFAULT_HANDLER "gnome-moz-remote \"%s\""
+#define INFO_HANDLER  "gnome-help-browser \"%s\""
+#define MAN_HANDLER   "gnome-help-browser \"%s\""
+#define GHELP_HANDLER "gnome-help-browser \"%s\""
+
+static GSList *free_atexit = NULL;
+GnomeURLHistoryCallback gnome_url_history_callback = NULL;
+
+struct _GnomeURLDisplayContext {
+  char *command;
+  char *id;
+};
+
+static gchar *
+gnome_url_default_handler (void)
+{
+	static gchar *default_handler = NULL;
+	
+	if (!default_handler) {
+		gchar *str, *app;
+		gboolean def;
+		str = gnome_config_get_string_with_default ("/Gnome/URL Handlers/default-show",
+							    &def);
+		if (def) {
+			app = gnome_is_program_in_path ("nautilus");
+			if (app) {
+				g_free (app);
+				app = "nautilus \"%s\"";
+			} else
+				app = "gnome-help-browser \"%s\"";
+
+			/* first time gnome_url_show is run -- set up some useful defaults */
+			default_handler = DEFAULT_HANDLER;
+			gnome_config_set_string ("/Gnome/URL Handlers/default-show", default_handler);
+
+			g_free (gnome_config_get_string_with_default(
+				"/Gnome/URL Handlers/info-show", &def));
+			if (def)
+				gnome_config_set_string ("/Gnome/URL Handlers/info-show", app);
+			g_free (gnome_config_get_string_with_default(
+				"/Gnome/URL Handlers/man-show", &def));
+			if (def)
+				gnome_config_set_string ("/Gnome/URL Handlers/man-show", app);
+			g_free (gnome_config_get_string_with_default(
+				"/Gnome/URL Handlers/ghelp-show", &def));
+			if (def)
+				gnome_config_set_string ("/Gnome/URL Handlers/ghelp-show", app);
+
+			gnome_config_sync_file ("/Gnome/");
+		} else
+			default_handler = str;
+	}
+	return default_handler;
+}
+
+/* returns FALSE and sets error if an error was encountered */
+static gboolean
+create_cmd(GnomeURLDisplayContext *rdc, const char *template,
+	   const char *url, GnomeURLDisplayFlags flags, int pipe,
+	   char ***cmd, int *argc,
+	   GError **error)
+{
+	int temp_argc;
+	const char **temp_argv;
+	int i;
+
+	/* we use a popt function as it does exactly what we want to do and
+	   gnome already uses popt */
+	if(poptParseArgvString(template, &temp_argc, &temp_argv) != 0) {
+		g_set_error (error,
+			     GNOME_URL_ERROR,
+			     GNOME_URL_ERROR_PARSE,
+			     "Error parsing '%s'",
+			     template);
+		return FALSE;
+	}
+	if(temp_argc == 0) {
+		free(temp_argv);
+		g_set_error (error,
+			     GNOME_URL_ERROR,
+			     GNOME_URL_ERROR_PARSE,
+			     _("Error parsing '%s' (empty result)"),
+			     template);
+		return FALSE;
+	}
+
+	/* sort of a hack, if the command is gnome-moz-remote, first look
+	 * if mozilla is in path */
+	if(strcmp(temp_argv[0], "gnome-moz-remote") == 0) {
+		char *moz = gnome_config_get_string("/gnome-moz-remote/Mozilla/filename=netscape");
+		char *foo;
+
+		foo = gnome_is_program_in_path(moz);
+		if (foo == NULL) {
+			g_set_error (error,
+				     GNOME_URL_ERROR,
+				     GNOME_URL_ERROR_NO_MOZILLA,
+				     _("Mozilla not found as '%s'"),
+				     moz);
+			g_free(moz);
+			return FALSE;
+		}
+		g_free(moz);
+		g_free(foo);
+	}
+		
+
+	*argc = temp_argc;
+
+	if(flags & GNOME_URL_DISPLAY_NEWWIN)
+		(*argc) ++;
+
+	if(rdc && rdc->id)
+		(*argc) ++;
+
+	if(flags & GNOME_URL_DISPLAY_CLOSE)
+		(*argc) ++;
+
+	if(!(flags & GNOME_URL_DISPLAY_NO_RETURN_CONTEXT))
+		(*argc) ++;
+
+	*cmd = g_new(char *, *argc + 1);
+
+	for(i = 0; i < temp_argc; i++) {
+		if(strcmp(temp_argv[i], "%s") == 0)
+			(*cmd)[i] = g_strdup(url);
+		else
+			(*cmd)[i] = g_strdup(temp_argv[i]);
+	}
+
+	/* this must be free and not g_free because of how poptParseArgvString
+	 * works.  This also frees all the strings inside the array */
+	free(temp_argv);
+
+	if(flags & GNOME_URL_DISPLAY_NEWWIN)
+		(*cmd)[i++] = g_strdup("--newwin");
+
+	if(rdc && rdc->id)
+		(*cmd)[i++] = g_strdup_printf("--id=%s", rdc->id);
+
+	if(flags & GNOME_URL_DISPLAY_CLOSE)
+		(*cmd)[i++] = g_strdup("--closewin");
+
+	if(!(flags & GNOME_URL_DISPLAY_NO_RETURN_CONTEXT))
+		(*cmd)[i++] = g_strdup_printf("--print-id=%d", pipe);
+
+	(*cmd)[i++] = NULL;
+
+	return TRUE;
+}
+
+/**
+ * gnome_url_show_full
+ * @display_context: An existing GnomeURLDisplayContext to use for displaying this URL in. May be NULL.
+ * @url: URL to show
+ * @url_type: The type of the URL (e.g. "help")
+ * @flags: Flags changing the way the URL is displayed or handled.
+ * @error: if an error happens GError will be set with domain of GNOME_URL_ERROR and code one of the GnomeURLError enum values.  May be NULL.
+ *
+ * Description:
+ * Loads the given URL in an appropriate viewer.  The viewer is deduced from
+ * the url_type and the protocol part of the URL.  That is all that the caller should know
+ * about the function.
+ *
+ * 'display_context' is not presently used.
+ *
+ *
+ * Internally, the handler for a given URL is deduced by looking in the
+ * /Gnome/URL Handlers/<protocol>-show key in the user's configuration
+ * files.  The key is a string that will be passed to gnome_execute_shell(),
+ * after the %s is replaced with with the URL.  If that key can't be found,
+ * it falls back to /Gnome/URL Handlers/default-show, and if that isn't
+ * found, uses the contents of the DEFAULT_HANDLER macro in this file
+ * (libgnome/gnome-url.c).
+ *
+ * If no /Gnome/URL Handlers keys are set, some sensible defaults are added
+ * to the user's configuration files.
+ *
+ **/
+GnomeURLDisplayContext *
+gnome_url_show_full(GnomeURLDisplayContext *display_context, const char *url,
+		    const char *url_type, GnomeURLDisplayFlags flags,
+		    GError **error)
+{
+  char *retid = NULL;
+  char *pos, *template = NULL;
+  char path[PATH_MAX];
+  gboolean def, free_template = FALSE;
+  GnomeURLDisplayContext *rdc = display_context;
+
+  g_return_val_if_fail (!(flags & GNOME_URL_DISPLAY_CLOSE) || display_context, display_context);
+
+  if(flags & GNOME_URL_DISPLAY_CLOSE)
+    url = url_type = ""; /* Stick in a dummy URL to make code happy */
+
+  g_return_val_if_fail (url != NULL, display_context);
+
+  if (gnome_url_history_callback && !(flags & GNOME_URL_DISPLAY_NO_HISTORY))
+    {
+      if(!gnome_url_history_callback(display_context, url, url_type, flags))
+	return display_context;
+    }
+
+  if(!rdc)
+    {
+      if (url_type)
+	{
+	  g_snprintf(path, sizeof(path), "/Gnome/URL Handlers/%s-show", url_type);
+	  template = gnome_config_get_string_with_default (path, &def);
+	  if(def)
+	    {
+	      g_free(template);
+	      template = NULL;
+	    }
+	  else
+	    free_template = TRUE;
+	}
+
+      if (!template && (pos = strstr (url, "://")))
+	{
+	  char protocol[64];
+
+	  g_snprintf(protocol, sizeof(protocol), "%.*s", (int)(pos - url - 3), url);
+	  g_strdown (protocol);
+
+	  g_snprintf (path, sizeof(path), "/Gnome/URL Handlers/%.*s-show", (int)(pos - url - 3), url);
+
+	  template = gnome_config_get_string_with_default (path, &def);
+
+	  if (def) {
+	    g_free(template);
+	    template = gnome_url_default_handler ();
+	  } else
+	    free_template = TRUE;
+	}
+      else
+	/* no : ? -- this shouldn't happen.  Use default handler */
+	template = gnome_url_default_handler ();
+    }
+  else
+    {
+      template = rdc->command;
+    }
+
+
+  if(!(flags & GNOME_URL_DISPLAY_NO_RETURN_CONTEXT))
+    {
+      int pipes[2];
+      char aline[LINE_MAX];
+      FILE *fh;
+      char **argv = NULL;
+      int argc;
+      int pid;
+
+      if(pipe(pipes) != 0) {
+	      g_warning(_("Cannot open a pipe: %s"), g_strerror(errno));
+	      g_set_error (error,
+			   GNOME_URL_ERROR,
+			   GNOME_URL_ERROR_PIPE,
+			   _("Cannot open a pipe: %s"),
+			   g_strerror(errno));
+	      flags |= GNOME_URL_DISPLAY_NO_RETURN_CONTEXT;
+	      goto about_to_return;
+      }
+
+      if(!create_cmd(rdc, template, url, flags, pipes[1],
+		     &argv, &argc, error)) {
+	      close(pipes[0]);
+	      close(pipes[1]);
+	      g_warning(_("Cannot parse handler template: %s"), template);
+	      flags |= GNOME_URL_DISPLAY_NO_RETURN_CONTEXT;
+	      goto about_to_return;
+      }
+
+      pid = gnome_execute_async_fds (NULL, argc, argv, FALSE);
+      close(pipes[1]);
+
+      if(pid == -1) {
+	      close(pipes[0]);
+	      g_warning(_("Cannot execute command '%s'!"), argv[0]);
+	      g_set_error (error,
+			   GNOME_URL_ERROR,
+			   GNOME_URL_ERROR_PIPE,
+			   _("Cannot execute command '%s'!"),
+			   argv[0]);
+	      flags |= GNOME_URL_DISPLAY_NO_RETURN_CONTEXT;
+	      goto about_to_return;
+      }
+
+      g_strfreev(argv);
+
+      fh = fdopen(pipes[0], "r");
+
+      if(fh)
+	{
+	  while(fgets(aline, sizeof(aline), fh))
+	    {
+	      g_strstrip(aline);
+	      if(aline[0] == '0' && aline[1] == 'x')
+		{
+		  retid = g_strdup(aline);
+		  break;
+		}
+	    }
+
+	  fclose(fh);
+	}
+      close(pipes[0]);
+
+      /* if no ID was found this will free the context as it would be bogus
+       * anyway, and return an error */
+      if(retid == NULL) {
+	      g_set_error (error,
+			   GNOME_URL_ERROR,
+			   GNOME_URL_ERROR_NO_ID,
+			   _("Command '%s' did not return an ID!"),
+			   argv[0]);
+	      flags |= GNOME_URL_DISPLAY_NO_RETURN_CONTEXT;
+	      goto about_to_return;
+      }
+    }
+  else
+    {
+      char **argv = NULL;
+      int argc = 0;
+
+      if(!create_cmd(rdc, template, url, flags, 0, &argv, &argc, error)) {
+	      g_warning(_("Cannot parse handler template: %s"), template);
+	      goto about_to_return;
+      }
+
+      if(gnome_execute_async (NULL, argc, argv) == -1) {
+	      g_warning(_("Cannot execute command '%s'!"), argv[0]);
+	      g_set_error (error,
+			   GNOME_URL_ERROR,
+			   GNOME_URL_ERROR_PIPE,
+			   _("Cannot execute command '%s'!"),
+			   argv[0]);
+	      goto about_to_return;
+      }
+
+      g_strfreev(argv);
+    }
+
+about_to_return:
+
+  if (flags & GNOME_URL_DISPLAY_NO_RETURN_CONTEXT &&
+      rdc)
+    {
+      gnome_url_display_context_free(rdc, 0, NULL);
+      rdc = NULL;
+    }
+
+  if (!(flags & GNOME_URL_DISPLAY_NO_RETURN_CONTEXT)
+      && !rdc)
+    {
+      rdc = g_new0(struct _GnomeURLDisplayContext, 1);
+
+      rdc->command = free_template?template:g_strdup(template);
+      rdc->id = retid;
+    }
+  else if(rdc && retid)
+    {
+      g_free(rdc->id);
+      rdc->id = retid;
+    }
+  else
+    {
+      if (free_template)
+	g_free (template);
+
+      g_free(retid);
+    }
+
+  return rdc;
+}
+
+gboolean
+gnome_url_show(const gchar *url)
+{
+  GError *error = NULL;
+  gnome_url_show_full(NULL, url, NULL, GNOME_URL_DISPLAY_NO_RETURN_CONTEXT,
+		      &error);
+  if (error == NULL)
+	  return TRUE;
+  g_error_free (error);
+  return FALSE;
+}
+
+static void
+gnome_udc_free_all(void)
+{
+  /* with GNOME_URL_DISPLAY_CLOSE it removes the context from free_atexit,
+   * we cannot normally iterate through the list for that very reason here
+   * since the list would be changing from underneath us */
+  while(free_atexit)
+      gnome_url_display_context_free((GnomeURLDisplayContext *)free_atexit->data,
+				     GNOME_URL_DISPLAY_CLOSE, NULL);
+}
+
+/**
+ * gnome_url_display_context_free:
+ * @display_context: The url context
+ * @flags: the flags
+ * @error: if an error happens GError will be set with domain of GNOME_URL_ERROR and code one of the GnomeURLError enum values.  May be NULL.
+ *
+ * Description:
+ **/
+void
+gnome_url_display_context_free(GnomeURLDisplayContext *display_context,
+			       GnomeURLDisplayFlags flags,
+			       GError **error)
+{
+  if(flags & GNOME_URL_DISPLAY_CLOSE_ATEXIT)
+    {
+      if(!free_atexit)
+	g_atexit(gnome_udc_free_all);
+
+      free_atexit = g_slist_prepend(free_atexit, display_context);
+    }
+  else
+    {
+      if(flags & GNOME_URL_DISPLAY_CLOSE)
+	gnome_url_show_full(display_context, "", "", flags, error);
+
+      free_atexit = g_slist_remove(free_atexit, display_context);
+
+      g_free(display_context->command);
+      g_free(display_context);
+    }
+}
+
+GQuark
+gnome_url_error_quark (void)
+{
+	static GQuark error_quark = 0;
+
+	if (error_quark == 0)
+		error_quark =
+			g_quark_from_static_string ("gnome-url-error-quark");
+
+	return error_quark;
+}
diff --git a/libgnome/gnome-url.h b/libgnome/gnome-url.h
new file mode 100644
index 0000000..61866d4
--- /dev/null
+++ b/libgnome/gnome-url.h
@@ -0,0 +1,91 @@
+/* gnome-url.h
+ * Copyright (C) 1998 James Henstridge <james daa com au>
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This 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.
+ *
+ * This 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 this library; if not, write to the Free Software
+ * Foundation, Inc.,  59 Temple Place - Suite 330, Cambridge, MA 02139, USA.
+ */
+/*
+  @NOTATION@
+ */
+
+#ifndef GNOME_URL_H
+#define GNOME_URL_H
+
+#include <glib.h>
+#include <libgnome/gnome-defs.h>
+
+BEGIN_GNOME_DECLS
+
+typedef struct _GnomeURLDisplayContext GnomeURLDisplayContext;
+
+typedef enum {
+  GNOME_URL_DISPLAY_CLOSE_ATEXIT = 1<<0,
+  GNOME_URL_DISPLAY_CLOSE = 1<<1,
+  GNOME_URL_DISPLAY_NO_RETURN_CONTEXT = 1<<2,
+  GNOME_URL_DISPLAY_NEWWIN = 1<<3,
+  GNOME_URL_DISPLAY_NO_HISTORY = 1<<4 /* Don't call the history callback for this URL */
+} GnomeURLDisplayFlags;
+
+typedef enum {
+  GNOME_URL_ERROR_EXEC, /* could not execute handler */
+  GNOME_URL_ERROR_PARSE, /* if the parsing of the handler failed */
+  GNOME_URL_ERROR_PIPE, /* if 'pipe' did not work when getting id,
+			 * handler has not been executed */
+  GNOME_URL_ERROR_NO_ID, /* if id could not be gotten, the handler has however
+			  * been executed */
+  GNOME_URL_ERROR_NO_MOZILLA /* could not find mozilla for gnome-moz-remote */
+} GnomeURLError;
+
+#define GNOME_URL_ERROR (gnome_url_error_quark ())
+GQuark gnome_url_error_quark (void) G_GNUC_CONST;
+
+typedef gboolean (*GnomeURLHistoryCallback)(GnomeURLDisplayContext *display_context,
+					    const char *url,
+					    const char *url_type,
+					    GnomeURLDisplayFlags flags);
+
+/* One callback for everyone, sorry folks. */
+extern GnomeURLHistoryCallback gnome_url_history_callback;
+
+/* This function displays the given URL in the appropriate viewer.  The
+ * Appropriate viewer is user definable, according to these rules:
+ *  1) Extract the protocol from URL.  This is defined as everything before
+ *     the first colon
+ *  2) Check if the key /Gnome/URL Handlers/<protocol>-show exists in the
+ *     gnome config database.  If it does, use use this as a command
+ *     template.  If it doesn't, check for the key
+ *     /Gnome/URL Handlers/default-show, and if that doesn't exist fallback
+ *     on the compiled in default.
+ *  3) substitute the %s in the template with the URL.
+ *  4) call gnome_execute_shell, with this expanded command as the second
+ *     argument.
+ */
+
+/* if error is not NULL, it is set to one of the errors above */
+GnomeURLDisplayContext *gnome_url_show_full(GnomeURLDisplayContext *display_context,
+					    const char *url,
+					    const char *url_type,
+					    GnomeURLDisplayFlags flags,
+					    GError **error);
+void gnome_url_display_context_free(GnomeURLDisplayContext *display_context,
+				    GnomeURLDisplayFlags flags,
+				    GError **error);
+
+/* returns FALSE on error, TRUE if everything went fine */
+gboolean gnome_url_show(const char *url);
+
+END_GNOME_DECLS
+#endif
diff --git a/libgnome/gnome-util.c b/libgnome/gnome-util.c
new file mode 100644
index 0000000..9d60be6
--- /dev/null
+++ b/libgnome/gnome-util.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
+ * 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@
+ */
+
+/*
+ *
+ * Gnome utility routines.
+ * (C)  1997, 1998, 1999 the Free Software Foundation.
+ *
+ * Author: Miguel de Icaza, 
+ */
+#include <config.h>
+
+/* needed for S_ISLNK with 'gcc -ansi -pedantic' on GNU/Linux */
+#ifndef _BSD_SOURCE
+#  define _BSD_SOURCE 1
+#endif
+#include <sys/types.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 <pwd.h>
+#include <limits.h>
+#include "libgnomeP.h"
+#include "gnome-portability.h"
+#include "gnome-defs.h"
+#include "gnome-util.h"
+#include "gnome-program.h"
+#include "gnomelib-init.h"
+
+/**
+ * g_concat_dir_and_file:
+ * @dir:  directory name
+ * @file: filename.
+ *
+ * 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)
+{
+	g_return_val_if_fail (dir != NULL, NULL);
+	g_return_val_if_fail (file != NULL, NULL);
+
+        /* If the directory name doesn't have a / on the end, we need
+	   to add one so we get a proper path to the file */
+	if (dir[0] != '\0' && dir [strlen(dir) - 1] != PATH_SEP)
+		return g_strconcat (dir, PATH_SEP_STR, file, NULL);
+	else
+		return g_strconcat (dir, file, NULL);
+}
+
+/**
+ * gnome_util_user_shell:
+ *
+ * Returns a newly allocated string that is the path to the user's
+ * preferred shell.
+ */
+char *
+gnome_util_user_shell (void)
+{
+	struct passwd *pw;
+	int i;
+	const char *shell;
+	static char *shells [] = {
+		"/bin/bash", "/bin/zsh", "/bin/tcsh", "/bin/ksh",
+		"/bin/csh", "/bin/sh", 0
+	};
+
+	if ((shell = g_getenv ("SHELL"))){
+		return g_strdup (shell);
+	}
+	pw = getpwuid(getuid());
+	if (pw && pw->pw_shell) {
+		return g_strdup (pw->pw_shell);
+	} 
+
+	for (i = 0; shells [i]; i++) {
+		if (g_file_test (shells [i], G_FILE_TEST_EXISTS)) {
+			return g_strdup (shells[i]);
+		}
+	}
+
+	/* If /bin/sh doesn't exist, your system is truly broken.  */
+	abort ();
+
+	/* Placate compiler.  */
+	return NULL;
+}
+
+/**
+ * g_extension_pointer:
+ * @path: a filename or file path
+ *
+ * Returns a pointer to the extension part of the filename, or a
+ * pointer to the end of the string if the filename does not
+ * have an extension.
+ *
+ */
+const char *
+g_extension_pointer (const char * path)
+{
+	char * s, * t;
+	
+	g_return_val_if_fail(path != NULL, NULL);
+
+	/* get the dot in the last element of the path */
+	t = strrchr(path, G_DIR_SEPARATOR);
+	if (t != NULL)
+		s = strrchr(t, '.');
+	else
+		s = strrchr(path, '.');
+	
+	if (s == NULL)
+		return path + strlen(path); /* There is no extension. */
+	else {
+		++s;      /* pass the . */
+		return s;
+	}
+}
+
+/**
+ * g_copy_vector:
+ * @vec: an array of strings.  NULL terminated
+ *
+ * Returns a copy of a NULL-terminated string array.
+ */
+char **
+g_copy_vector (const char **vec)
+{
+	char ** new_vec;
+	int size = 0;
+	
+	if (vec == NULL)
+	    return NULL;
+
+	while (vec [size] != NULL){
+		++size;
+	}
+	
+	new_vec = g_malloc (sizeof(char *) * (size + 1));
+	
+	size = 0;
+	while (vec [size]){
+		new_vec [size] = g_strdup (vec [size]);
+		++size;
+	}
+	new_vec [size] = NULL;
+	
+	return new_vec;
+}
+
+/**
+ * gnome_is_program_in_path:
+ * @program: a program name.
+ *
+ * Looks for program in the PATH, if it is found, a g_strduped
+ * string with the full path name is returned.
+ *
+ * Returns NULL if program is not on the path or a string 
+ * allocated with g_malloc with the full path name of the program
+ * found
+ */
+char *
+gnome_is_program_in_path (const gchar *program)
+{
+	static gchar **paths = NULL;
+	gchar **p;
+	gchar *f;
+	
+	if (!paths)
+	  paths = g_strsplit(g_getenv("PATH"), ":", -1);
+
+	p = paths;
+	while (*p){
+		f = g_strconcat (*p,"/",program, NULL);
+		if (g_file_test (f, G_FILE_TEST_EXISTS))
+			return f;
+		g_free (f);
+		p++;
+	}
+	return 0;
+}
diff --git a/libgnome/gnome-util.h b/libgnome/gnome-util.h
new file mode 100644
index 0000000..c7ab89b
--- /dev/null
+++ b/libgnome/gnome-util.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * Copyright (C) 1999, 2000 Red Hat, Inc.
+ * 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_UTIL_H__
+#define __GNOME_UTIL_H__
+
+#include <stdlib.h>
+#include <glib.h>
+#include "gnome-defs.h"
+#include "gnome-program.h"
+
+BEGIN_GNOME_DECLS
+
+#define gnome_libdir_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_LIBDIR, (filename), TRUE, NULL)
+#define gnome_datadir_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_DATADIR, (filename), TRUE, NULL)
+#define gnome_sound_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_SOUND, (filename), TRUE, NULL)
+#define gnome_pixmap_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_PIXMAP, (filename), TRUE, NULL)
+#define gnome_config_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_CONFIG, (filename), TRUE, NULL)
+#define gnome_help_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_HELP, (filename), TRUE, NULL)
+#define gnome_app_help_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_HELP, (filename), TRUE, NULL)
+#define gnome_unconditional_libdir_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_LIBDIR, (filename), FALSE, NULL)
+#define gnome_unconditional_datadir_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_DATADIR, (filename), FALSE, NULL)
+#define gnome_unconditional_sound_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_SOUND, (filename), FALSE, NULL)
+#define gnome_unconditional_pixmap_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_PIXMAP, (filename), FALSE, NULL)
+#define gnome_unconditional_config_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_CONFIG, (filename), FALSE, NULL)
+#define gnome_unconditional_help_file(filename) gnome_program_locate_file(gnome_program_get(), GNOME_FILE_DOMAIN_CONFIG, (filename), FALSE, NULL)
+
+/* locate a program in $PATH, or return NULL if not found */
+char *gnome_is_program_in_path (const gchar *program);
+
+/* Make a dir and a file into a full path, handling / issues. */
+char *g_concat_dir_and_file (const char *dir, const char *file);
+
+/* Return pointer to the character after the last .,
+   or "" if no dot. */
+const char * g_extension_pointer (const char * path);
+
+/* vec has to be NULL-terminated */
+char ** g_copy_vector    (const char ** vec);
+
+/* 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! */
+#define gnome_util_prepend_user_home(x) (g_concat_dir_and_file(g_get_home_dir(), (x)))
+
+/* very similar to above, but adds $HOME/.gnome/ to beginning
+ * This is meant to be the most useful version.
+ */
+#define gnome_util_home_file(afile) (g_strconcat(g_get_home_dir(), "/.gnome/", (afile), NULL))
+
+/* Find the name of the user's shell.  */
+char *gnome_util_user_shell (void);
+
+END_GNOME_DECLS
+
+#endif
diff --git a/libgnome/gnomelib-init.c b/libgnome/gnomelib-init.c
new file mode 100644
index 0000000..b2ad29b
--- /dev/null
+++ b/libgnome/gnomelib-init.c
@@ -0,0 +1,195 @@
+/* gnomelib-init.c - Implement libgnome module
+   Copyright (C) 1997, 1998, 1999 Free Software Foundation
+   Copyright (C) 1999, 2000 Red Hat, Inc.
+   All rights reserved.
+
+   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 <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 <pwd.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include "libgnomeP.h"
+#include <errno.h>
+
+#include <gobject/gobject.h>
+#include <gobject/gvaluetypes.h>
+
+#include <libgnomevfs/gnome-vfs-init.h>
+
+char *gnome_user_dir = NULL, *gnome_user_private_dir = NULL, *gnome_user_accels_dir = NULL;
+
+static void libgnome_post_args_parse(GnomeProgram *app, const GnomeModuleInfo *mod_info);
+static void libgnome_loadinit(const GnomeModuleInfo *mod_info);
+static void libgnome_option_cb(poptContext ctx, enum poptCallbackReason reason,
+			       const struct poptOption *opt, const char *arg,
+			       void *data);
+static void libgnome_userdir_setup(gboolean create_dirs);
+
+enum { ARG_VERSION=1 };
+
+static struct poptOption gnomelib_options[] = {
+        { NULL, '\0', POPT_ARG_INTL_DOMAIN, PACKAGE, 0, NULL, NULL},
+
+	{ NULL, '\0', POPT_ARG_CALLBACK, (void *) libgnome_option_cb, 0, NULL, NULL},
+
+	{"version", '\0', POPT_ARG_NONE, NULL, },
+
+	{ NULL, '\0', 0, NULL, 0 }
+};
+
+static GnomeModuleInfo gnome_vfs_module_info = {
+    "gnome-vfs", GNOMEVFSVERSION, "GNOME Virtual Filesystem",
+    NULL,
+    (GnomeModuleHook) gnome_vfs_preinit, (GnomeModuleHook) gnome_vfs_postinit,
+    NULL,
+    (GnomeModuleInitHook) gnome_vfs_loadinit,
+    NULL
+};
+
+static GnomeModuleRequirement libgnome_requirements[] = {
+  {"0.3.0", &gnome_vfs_module_info},
+  {NULL}
+};
+
+GnomeModuleInfo libgnome_module_info = {
+  "libgnome", VERSION, "GNOME Library",
+  libgnome_requirements,
+  NULL, libgnome_post_args_parse,
+  gnomelib_options,
+  libgnome_loadinit
+};
+
+static void
+libgnome_post_args_parse (GnomeProgram *program,
+			  const GnomeModuleInfo *mod_info)
+{
+    GValue value = { 0, };
+    gboolean create_dirs_val;
+
+    g_value_init (&value, G_TYPE_BOOLEAN);
+    g_object_get_property (G_OBJECT (program), "create-directories", &value);
+    create_dirs_val = g_value_get_boolean (&value);
+    g_value_unset (&value);
+
+    gnome_triggers_init ();
+
+    libgnome_userdir_setup (create_dirs_val);
+
+    setlocale (LC_ALL, "");
+    /* XXX todo - handle multiple installation dirs */
+    bindtextdomain (PACKAGE, GNOMELOCALEDIR);
+    gnome_i18n_init ();
+}
+
+static void
+libgnome_loadinit (const GnomeModuleInfo *mod_info)
+{
+    /* Initialize threads. */
+    g_thread_init (NULL);
+}
+
+static void
+libgnome_option_cb (poptContext ctx, enum poptCallbackReason reason,
+		    const struct poptOption *opt, const char *arg,
+		    void *data)
+{
+    GnomeProgram *program;
+
+    program = gnome_program_get ();
+	
+    switch(reason) {
+    case POPT_CALLBACK_REASON_OPTION:
+	switch(opt->val) {
+	case ARG_VERSION:
+	    g_print ("Gnome %s %s\n",
+		     gnome_program_get_name (program),
+		     gnome_program_get_version (program));
+	    exit(0);
+	    break;
+	}
+    default:
+	/* do nothing */
+	break;
+    }
+}
+
+static void
+libgnome_userdir_setup (gboolean create_dirs)
+{
+    if(!gnome_user_dir) {
+	gnome_user_dir = g_concat_dir_and_file (g_get_home_dir(), ".gnome");
+	gnome_user_private_dir = g_concat_dir_and_file (g_get_home_dir(),
+							".gnome_private");
+	gnome_user_accels_dir = g_concat_dir_and_file (gnome_user_dir, "accels");
+    }
+
+    if (!create_dirs)
+	return;
+	
+    if (mkdir (gnome_user_dir, 0700) < 0) { /* private permissions, but we
+					       don't check that we got them */
+	if (errno != EEXIST) {
+	    fprintf(stderr, _("Could not create per-user gnome configuration directory `%s': %s\n"),
+		    gnome_user_dir, strerror(errno));
+	    exit(1);
+	}
+    }
+    
+  if (mkdir (gnome_user_private_dir, 0700) < 0) { /* This is private
+						     per-user info mode
+						     700 will be
+						     enforced!  maybe
+						     even other security
+						     meassures will be
+						     taken */
+      if (errno != EEXIST) {
+	  fprintf (stderr, _("Could not create per-user gnome configuration directory `%s': %s\n"),
+		   gnome_user_private_dir, strerror(errno));
+	  exit(1);
+      }
+  }
+
+
+  /* change mode to 0700 on the private directory */
+  if (chmod (gnome_user_private_dir, 0700) < 0) {
+      fprintf(stderr, _("Could not set mode 0700 on private per-user gnome configuration directory `%s': %s\n"),
+	      gnome_user_private_dir, strerror(errno));
+      exit(1);
+  }
+  
+  if (mkdir (gnome_user_accels_dir, 0700) < 0) {
+      if (errno != EEXIST) {
+	  fprintf(stderr, _("Could not create gnome accelerators directory `%s': %s\n"),
+		  gnome_user_accels_dir, strerror(errno));
+	  exit(1);
+      }
+  }
+}
+
+
diff --git a/libgnome/gnomelib-init.h b/libgnome/gnomelib-init.h
new file mode 100644
index 0000000..d170595
--- /dev/null
+++ b/libgnome/gnomelib-init.h
@@ -0,0 +1,49 @@
+/* gnomelib-init.h - Export libgnome module
+   Copyright (C) 1997, 1998, 1999 Free Software Foundation
+   Copyright (C) 1999, 2000 Red Hat, Inc.
+   All rights reserved.
+
+   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 GNOMELIB_INIT_H
+#define GNOMELIB_INIT_H 1
+
+#include <glib.h>
+#include "gnome-defs.h"
+#include "gnome-program.h"
+
+BEGIN_GNOME_DECLS
+
+extern GnomeModuleInfo libgnome_module_info;
+#define LIBGNOME_INIT GNOME_PARAM_MODULE_INFO,&libgnome_module_info
+
+typedef char * (*GnomeFileLocatorFunc)(const char *domain, const char *filename, gboolean only_if_exists);
+
+extern char *gnome_user_home_dir;
+extern char *gnome_user_dir;
+extern char *gnome_user_private_dir;
+extern char *gnome_user_accels_dir;
+
+/* Backwards compat */
+#define gnome_app_id gnome_program_get_name (gnome_program_get())
+#define gnome_app_version gnome_program_get_version (gnome_program_get())
+
+END_GNOME_DECLS
+
+#endif /* GNOMELIB_INIT_H */
diff --git a/libgnome/libgnome-2.0.pc.in b/libgnome/libgnome-2.0.pc.in
new file mode 100644
index 0000000..6e5cd84
--- /dev/null
+++ b/libgnome/libgnome-2.0.pc.in
@@ -0,0 +1,11 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+
+Name: libgnome
+Description: libgnome
+Requires: glib-2.0 ORBit-2.0 gconf-2.0
+Version: @VERSION@
+Libs: -L${libdir} -lgnome- GNOME_INTERFACE_VERSION@
+Cflags: -I${includedir}/gnome/@GNOME_INTERFACE_VERSION@
diff --git a/libgnome/libgnome-boxed.defs b/libgnome/libgnome-boxed.defs
new file mode 100644
index 0000000..f6fc839
--- /dev/null
+++ b/libgnome/libgnome-boxed.defs
@@ -0,0 +1,6 @@
+; -*- scheme -*-
+
+; These definitions here cause the creation of some new GTK_TYPE_* ids
+; The code doesn't benefit most C programs directly, but is very useful
+; for language bindings.
+
diff --git a/libgnome/libgnome.h b/libgnome/libgnome.h
new file mode 100644
index 0000000..da29816
--- /dev/null
+++ b/libgnome/libgnome.h
@@ -0,0 +1,51 @@
+/*
+ * 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@
+ */
+
+#ifndef LIBGNOME_H
+#define LIBGNOME_H
+
+#include <libgnome/gnome-portability.h>
+#include <libgnome/gnome-defs.h>
+
+#include <libgnome/gnome-config.h>
+#include <libgnome/gnome-exec.h>
+#include <libgnome/gnome-i18n.h>
+
+/* Should this be in gnome-print? */
+#include <libgnome/gnome-paper.h>
+#include <libgnome/gnome-remote.h>
+#include <libgnome/gnome-score.h>
+#include <libgnome/gnome-triggers.h>
+#include <libgnome/gnome-util.h>
+#include <libgnome/gnome-url.h>
+#include <libgnome/gnome-program.h>
+#include <libgnome/gnome-ditem.h>
+#include <libgnome/gnomelib-init.h>
+
+#ifdef COMPAT_1_0
+#include <compat/1.0/libgnome/libgnome-compat-1.0.h>
+#endif
+
+#endif /* LIBGNOME_H */
diff --git a/libgnome/libgnomeP.h b/libgnome/libgnomeP.h
new file mode 100644
index 0000000..25d16d2
--- /dev/null
+++ b/libgnome/libgnomeP.h
@@ -0,0 +1,39 @@
+/*
+ * 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@
+ */
+
+#ifndef LIBGNOMEP_H
+#define LIBGNOMEP_H
+
+#include <glib.h>
+#include "libgnome/gnome-defs.h"
+#include "libgnome/gnome-i18nP.h"
+#include "libgnome/libgnome.h"
+
+#define PATH_SEP '/'
+#define PATH_SEP_STR "/"
+
+void libgnome_type_init (void);
+
+#endif /* LIBGNOMEP_H */
diff --git a/libgnome/libgnometypes.c b/libgnome/libgnometypes.c
new file mode 100644
index 0000000..55ab256
--- /dev/null
+++ b/libgnome/libgnometypes.c
@@ -0,0 +1,51 @@
+#include <config.h>
+#include <gobject/genums.h>
+#include <gobject/gboxed.h>
+#include "libgnome.h"
+
+#include "libgnometypebuiltins.h"
+#include "libgnometypebuiltins_vars.c"
+#include "libgnometypebuiltins_evals.c"
+void libgnome_type_init(void);
+
+void
+libgnome_type_init(void) {
+  static gboolean initialized = FALSE;
+
+  if (!initialized) {
+    int i;
+
+    static struct {
+      gchar           *type_name;
+      GType           *type_id;
+      GType            parent;
+      gconstpointer    pointer1;
+      gconstpointer    pointer2;
+      gconstpointer    pointer3;
+      gboolean         boolean1;
+    } builtin_info[GNOME_TYPE_NUM_BUILTINS + 1] = {
+#include "libgnometypebuiltins_ids.c"
+      { NULL }
+    };
+
+    initialized = TRUE;
+
+    g_type_init (G_TYPE_DEBUG_NONE);
+
+    for (i = 0; i < GNOME_TYPE_NUM_BUILTINS; i++)
+      {
+	GType type_id = G_TYPE_INVALID;
+	g_assert (builtin_info[i].type_name != NULL);
+	if ( builtin_info[i].parent == G_TYPE_ENUM )
+	  type_id = g_enum_register_static (builtin_info[i].type_name, (GEnumValue *)builtin_info[i].pointer1);
+	else if ( builtin_info[i].parent == G_TYPE_FLAGS )
+	  type_id = g_flags_register_static (builtin_info[i].type_name, (GFlagsValue *)builtin_info[i].pointer1);
+	else if ( builtin_info[i].parent == G_TYPE_BOXED )
+	  type_id = g_boxed_type_register_static (builtin_info[i].type_name, (GBoxedInitFunc)builtin_info[i].pointer1, (GBoxedCopyFunc)builtin_info[i].pointer2, (GBoxedFreeFunc)builtin_info[i].pointer3, builtin_info[1].boolean1);
+
+	g_assert (type_id != G_TYPE_INVALID);
+	(*builtin_info[i].type_id) = type_id;
+      }
+  }
+}
+
diff --git a/libgnome/parse-path.cP b/libgnome/parse-path.cP
new file mode 100644
index 0000000..5a6442c
--- /dev/null
+++ b/libgnome/parse-path.cP
@@ -0,0 +1,100 @@
+/* This is a -*- C -*- file fragment.  Please don't compile it, however.  */
+
+typedef struct {
+	char *file, *section, *key, *def;
+	char *path, *opath;
+} ParsedPath;
+
+static const char * GNOME_CONFIG_PARSE_ERROR = "__(null)__";
+
+static void
+release_path (ParsedPath *p)
+{
+	if(p->file != GNOME_CONFIG_PARSE_ERROR)
+		g_free (p->file);
+	g_free (p->opath);
+	g_free (p);
+}
+
+static ParsedPath *
+parse_path (const char *path, gboolean priv)
+{
+	ParsedPath *p = g_malloc (sizeof (ParsedPath));
+
+	g_assert(path != NULL);
+	
+	if (*path == '/' || prefix == NULL)
+		p->opath = g_strdup (path);
+	else
+		p->opath = g_strconcat (prefix, path,NULL);
+		/*p->opath = g_concat_dir_and_file (prefix, path);*/
+
+	p->path    = p->opath;
+	p->file    = (char *)GNOME_CONFIG_PARSE_ERROR;
+	p->section = (char *)GNOME_CONFIG_PARSE_ERROR;
+	p->key     = (char *)GNOME_CONFIG_PARSE_ERROR;
+
+	if (*p->path == '='){
+		char *token;
+		/* If it is an absolute path name */
+		p->path++;
+		if ((token = strtok (p->path, "="))) {
+			if (token[0]=='/')
+				p->file = g_strdup (token);
+			else {
+				char *cwd = g_get_current_dir();
+				p->file = g_concat_dir_and_file(cwd,token);
+				g_free(cwd);
+			}
+		}
+		if ((token = strtok (NULL, "/=")))
+			p->section = token;
+		if ((token = strtok (NULL, "=")))
+			p->key     = token;
+		p->def     = strtok (NULL, "=");
+	} else {
+		char *end;
+
+		p->file    = p->path;
+		p->def     = NULL;
+		if ((end = strchr (p->path, '='))) {
+			*end = 0;
+			p->def = end + 1;
+		} else 
+			end = p->path + strlen (p->path);
+
+		/* Look backwards for a slash, to split key from the filename/section */
+		while (end > p->path){
+			end--;
+			if (*end == '/'){
+				*end = 0;
+				p->key = end + 1;
+				break;
+			}
+		}
+
+		/* Look backwards for the next slash, to get the section name */
+		while (end > p->path){
+			end--;
+			if (*end == '/'){
+				*end = 0;
+				p->section = end + 1;
+				break;
+			}
+		}
+		if (*p->file == '/')
+			p->file++;
+
+		if (priv){
+			p->file = g_strconcat (g_get_home_dir(), "/.gnome_private/", (p->file), NULL);
+		} else {
+			p->file = g_strconcat (g_get_home_dir(), "/.gnome/", (p->file), NULL);
+		}
+	}
+	if (p->file    == GNOME_CONFIG_PARSE_ERROR ||
+	    p->section == GNOME_CONFIG_PARSE_ERROR ||
+	    p->section == GNOME_CONFIG_PARSE_ERROR) {
+		g_warning ("invalid gnome config path \'%s\'\n", path);
+	}
+	return p;
+}
diff --git a/libgnome/test-libgnome.c b/libgnome/test-libgnome.c
new file mode 100644
index 0000000..d3d6597
--- /dev/null
+++ b/libgnome/test-libgnome.c
@@ -0,0 +1,172 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "libgnome.h"
+
+#include <gobject/gvaluetypes.h>
+#include <gobject/gparamspecs.h>
+
+static int foo = 0;
+
+static struct poptOption options[] = {
+    {"foo", '\0', POPT_ARG_INT, &foo, 0, N_("Test option."), NULL},
+    {NULL}
+};
+
+static void
+get_property (GObject *object, guint param_id, GValue *value,
+	      GParamSpec *pspec)
+{
+    GnomeProgram *program;
+
+    g_return_if_fail (object != NULL);
+    g_return_if_fail (GNOME_IS_PROGRAM (object));
+
+    program = GNOME_PROGRAM (object);
+
+    switch (param_id) {
+    default:
+	g_message (G_STRLOC);
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+	break;
+    }
+}
+
+static void
+set_property (GObject *object, guint param_id,
+	      const GValue *value, GParamSpec *pspec)
+{
+    GnomeProgram *program;
+
+    g_return_if_fail (object != NULL);
+    g_return_if_fail (GNOME_IS_PROGRAM (object));
+
+    program = GNOME_PROGRAM (object);
+
+    switch (param_id) {
+    default:
+	g_message (G_STRLOC);
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+	break;
+    }
+}
+
+static void
+test_pre_args_parse (GnomeProgram *program, const GnomeModuleInfo *mod_info)
+{
+    g_message (G_STRLOC ": %p", program);
+}
+
+static void
+test_post_args_parse (GnomeProgram *program, const GnomeModuleInfo *mod_info)
+{
+    g_message (G_STRLOC ": %p", program);
+}
+
+static void
+test_init_pass (const GnomeModuleInfo *mod_info)
+{
+    g_message (G_STRLOC);
+}
+
+static void
+test_constructor (GType type, guint n_construct_properties,
+		  GObjectConstructParam *construct_properties,
+		  const GnomeModuleInfo *mod_info)
+{
+    GnomeProgramClass *pclass;
+    guint test_id;
+
+    pclass = GNOME_PROGRAM_CLASS (g_type_class_peek (type));
+
+    test_id = gnome_program_install_property
+	(pclass, get_property, set_property,
+	 g_param_spec_boolean ("test", NULL, NULL,
+			       FALSE,
+			       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+    g_message (G_STRLOC ": %p - %d", pclass, test_id);
+}
+
+GnomeModuleInfo test_moduleinfo = {
+    "test", VERSION, "Test Application",
+    NULL,
+    test_pre_args_parse, test_post_args_parse,
+    NULL,
+    test_init_pass, test_constructor,
+    NULL, NULL
+};
+
+static void
+test_file_locate (GnomeProgram *program) 
+{
+    GSList *locations = NULL, *c;
+
+    gnome_program_locate_file (program, GNOME_FILE_DOMAIN_CONFIG,
+			       "test.config", FALSE, &locations);
+
+    for (c = locations; c; c = c->next)
+	g_message (G_STRLOC ": `%s'", (gchar *) c->data);
+}
+
+static void
+test_properties (GnomeProgram *program) 
+{
+    g_object_set (G_OBJECT (program), "test", TRUE, NULL);
+}
+
+int
+main (int argc, char **argv)
+{
+    GValue value = { 0, };
+    GnomeProgram *program;
+    gchar *app_prefix, *app_id, *app_version;
+    const gchar *human_readable_name;
+    gchar *gnome_path;
+
+    program = gnome_program_init ("test-libgnome", VERSION, argc, argv,
+				  GNOME_PARAM_POPT_TABLE, options,
+				  GNOME_PARAM_HUMAN_READABLE_NAME,
+				  _("The Application Name"),
+				  GNOME_PARAM_MODULE_INFO,
+				  &test_moduleinfo, NULL);
+
+    g_value_init (&value, G_TYPE_STRING);
+    g_object_get_property (G_OBJECT (program), "app_prefix", &value);
+    app_prefix = g_value_dup_string (&value);
+    g_value_unset (&value);
+
+    g_value_init (&value, G_TYPE_STRING);
+    g_object_get_property (G_OBJECT (program), "app_id", &value);
+    app_id = g_value_dup_string (&value);
+    g_value_unset (&value);
+
+    g_value_init (&value, G_TYPE_STRING);
+    g_object_get_property (G_OBJECT (program), "app_version", &value);
+    app_version = g_value_dup_string (&value);
+    g_value_unset (&value);
+
+    g_value_init (&value, G_TYPE_STRING);
+    g_object_get_property (G_OBJECT (program), "gnome_path", &value);
+    gnome_path = g_value_dup_string (&value);
+    g_value_unset (&value);
+
+    human_readable_name = gnome_program_get_human_readable_name (program);
+
+    g_message (G_STRLOC ": %d - `%s' - `%s' - `%s' - `%s'", foo, app_prefix,
+	       app_id, app_version, human_readable_name);
+
+    g_message (G_STRLOC ": GNOME_PATH == `%s'", gnome_path);
+
+    test_file_locate (program);
+
+    test_properties (program);
+
+    return 0;
+}
diff --git a/libgnome/vroot.h b/libgnome/vroot.h
new file mode 100644
index 0000000..cb73254
--- /dev/null
+++ b/libgnome/vroot.h
@@ -0,0 +1,120 @@
+/*****************************************************************************/
+/**                   Copyright 1991 by Andreas Stolcke                     **/
+/**               Copyright 1990 by Solbourne Computer Inc.                 **/
+/**                          Longmont, Colorado                             **/
+/**                                                                         **/
+/**                           All Rights Reserved                           **/
+/**                                                                         **/
+/**    Permission to use, copy, modify, and distribute this software and    **/
+/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
+/**    granted, provided that the above copyright notice appear  in  all    **/
+/**    copies and that both  that  copyright  notice  and  this  permis-    **/
+/**    sion  notice appear in supporting  documentation,  and  that  the    **/
+/**    name of Solbourne not be used in advertising                         **/
+/**    in publicity pertaining to distribution of the  software  without    **/
+/**    specific, written prior permission.                                  **/
+/**                                                                         **/
+/**    ANDREAS STOLCKE AND SOLBOURNE COMPUTER INC. DISCLAIMS ALL WARRANTIES **/
+/**    WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF    **/
+/**    MERCHANTABILITY  AND  FITNESS,  IN  NO  EVENT SHALL ANDREAS STOLCKE  **/
+/**    OR SOLBOURNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL    **/
+/**    DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA   **/
+/**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
+/**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
+/**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
+/*****************************************************************************/
+/*
+  @NOTATION@
+ */
+
+/*
+ * vroot.h -- Virtual Root Window handling header file
+ *
+ * This header file redefines the X11 macros RootWindow and DefaultRootWindow,
+ * making them look for a virtual root window as provided by certain `virtual'
+ * window managers like swm and tvtwm. If none is found, the ordinary root
+ * window is returned, thus retaining backward compatibility with standard
+ * window managers.
+ * The function implementing the virtual root lookup remembers the result of
+ * its last invocation to avoid overhead in the case of repeated calls
+ * on the same display and screen arguments. 
+ * The lookup code itself is taken from Tom LaStrange's ssetroot program.
+ *
+ * Most simple root window changing X programs can be converted to using
+ * virtual roots by just including
+ *
+ * #include <X11/vroot.h>
+ *
+ * after all the X11 header files.  It has been tested on such popular
+ * X clients as xphoon, xfroot, xloadimage, and xaqua.
+ * It also works with the core clients xprop, xwininfo, xwd, and editres
+ * (and is necessary to get those clients working under tvtwm).
+ * It does NOT work with xsetroot; get the xsetroot replacement included in
+ * the tvtwm distribution instead.
+ *
+ * Andreas Stolcke <stolcke ICSI Berkeley EDU>, 9/7/90
+ * - replaced all NULL's with properly cast 0's, 5/6/91
+ * - free children list (suggested by Mark Martin <mmm cetia fr>), 5/16/91
+ * - include X11/Xlib.h and support RootWindowOfScreen, too 9/17/91
+ */
+
+#ifndef _VROOT_H_
+#define _VROOT_H_
+
+
+static Window
+VirtualRootWindowOfScreen(screen)
+        Screen *screen;
+{
+        static Screen *save_screen = (Screen *)0;
+        static Window root = (Window)0;
+
+        if (screen != save_screen) {
+                Display *dpy = DisplayOfScreen(screen);
+                Atom __SWM_VROOT = None;
+                int i;
+                Window rootReturn, parentReturn, *children;
+                unsigned int numChildren;
+
+                root = RootWindowOfScreen(screen);
+
+                /* go look for a virtual root */
+                __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
+                if (XQueryTree(dpy, root, &rootReturn, &parentReturn,
+                                 &children, &numChildren)) {
+                        for (i = 0; i < numChildren; i++) {
+                                Atom actual_type;
+                                int actual_format;
+                                unsigned long nitems, bytesafter;
+                                Window *newRoot = (Window *)0;
+
+                                if (XGetWindowProperty(dpy, children[i],
+                                        __SWM_VROOT, 0, 1, False, XA_WINDOW,
+                                        &actual_type, &actual_format,
+                                        &nitems, &bytesafter,
+                                        (unsigned char **) &newRoot) == Success
+                                    && newRoot) {
+                                    root = *newRoot;
+                                    break;
+                                }
+                        }
+                        if (children)
+                                XFree((char *)children);
+                }
+
+                save_screen = screen;
+        }
+
+        return root;
+}
+
+#undef RootWindowOfScreen
+#define RootWindowOfScreen(s) VirtualRootWindowOfScreen(s)
+
+#undef RootWindow
+#define RootWindow(dpy,screen) VirtualRootWindowOfScreen(ScreenOfDisplay(dpy,screen))
+
+#undef DefaultRootWindow
+#define DefaultRootWindow(dpy) VirtualRootWindowOfScreen(DefaultScreenOfDisplay(dpy))
+
+#endif /* _VROOT_H_ */
diff --git a/message-of-doom b/message-of-doom
new file mode 100644
index 0000000..c71bda9
--- /dev/null
+++ b/message-of-doom
@@ -0,0 +1,24 @@
+ *** IMPORTANT *** 
+
+This is a development version of gnome-libs.  You should be using a stable
+version, which is available at ftp://ftp.gnome.org/pub/GNOME/stable/sources/gnome-libs/
+The version you just configured is meant for developers of gnome-libs only:
+
+  * You should not base ANY software on this version of gnome-libs.
+
+Distributions should *NOT* ship a development package of this gnome-libs.
+Do not ship the headers and do not ship the gnome-config script. These
+things will conflict with the stable 1.0 series.  Package only enough
+to satisfy the requirements of some other package.  Package only the
+library itself.  Doing otherwise will do no favors to the community.
+
+ *** You should be using gnome-libs 1.0 instead. ***
+
+If you are using this source tree from CVS, please run:
+	cvs update -r gnome-libs-1-0"
+now.
+
+			....
+     Do not bother the mailing lists, IRC channels, or other forums if you cannot
+     figure out how to build gnome-libs HEAD. It is not in working condition.
+			....
diff --git a/monikers/GNOME_Moniker_std.oaf.in.in b/monikers/GNOME_Moniker_std.oaf.in.in
new file mode 100644
index 0000000..a895f9a
--- /dev/null
+++ b/monikers/GNOME_Moniker_std.oaf.in.in
@@ -0,0 +1,111 @@
+<oaf_info>
+
+<oaf_server iid="OAFIID:Bonobo_Moniker_std_Factory"
+	type="shlib" location="@MONIKER_LIBDIR@/libmoniker_std.so">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:GNOME/GenericFactory:1.0"/>
+	</oaf_attribute>
+
+	<oaf_attribute name="name" type="string" _value="Standard Moniker factory"/>
+</oaf_server>
+
+<oaf_server iid="OAFIID:Bonobo_Moniker_File" type="factory"
+	location="OAFIID:Bonobo_Moniker_std_Factory">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:Bonobo/Moniker:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+	<oaf_attribute name="name" type="string" _value="generic file moniker"/>
+	<oaf_attribute name="bonobo:moniker" type="stringv">
+		<item value="file:"/>
+	</oaf_attribute>
+</oaf_server>
+
+<oaf_server iid="OAFIID:Bonobo_Moniker_Item" type="factory"
+	location="OAFIID:Bonobo_Moniker_std_Factory">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:Bonobo/Moniker:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+	<oaf_attribute name="name" type="string" _value="generic item moniker"/>
+	<oaf_attribute name="bonobo:moniker" type="stringv">
+		<item value="!"/>
+	</oaf_attribute>
+</oaf_server>
+
+<oaf_server iid="OAFIID:Bonobo_Moniker_Cache" type="factory"
+	location="OAFIID:Bonobo_Moniker_std_Factory">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:Bonobo/Moniker:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+	<oaf_attribute name="name" type="string" _value="HTTP Moniker"/>
+	<oaf_attribute name="bonobo:moniker" type="stringv">
+		<item value="cache:"/>
+	</oaf_attribute>
+</oaf_server>
+
+<oaf_server iid="OAFIID:Bonobo_Moniker_Oaf" type="factory"
+	location="OAFIID:Bonobo_Moniker_std_Factory">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:Bonobo/Moniker:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+	<oaf_attribute name="name" type="string" _value="generic Oaf activation moniker"/>
+	<oaf_attribute name="bonobo:moniker" type="stringv">
+		<item value="oafiid:"/>
+	</oaf_attribute>
+</oaf_server>
+
+<oaf_server iid="OAFIID:Bonobo_Moniker_Query" type="factory"
+	location="OAFIID:Bonobo_Moniker_std_Factory">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:Bonobo/Moniker:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+	<oaf_attribute name="name" type="string" _value="generic Oaf query moniker"/>
+	<oaf_attribute name="bonobo:moniker" type="stringv">
+		<item value="query:"/>
+	</oaf_attribute>
+</oaf_server>
+
+<oaf_server iid="OAFIID:Bonobo_Moniker_New" type="factory"
+	location="OAFIID:Bonobo_Moniker_std_Factory">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:Bonobo/Moniker:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+	<oaf_attribute name="name" type="string" _value="generic factory 'new' moniker"/>
+	<oaf_attribute name="bonobo:moniker" type="stringv">
+		<item value="new:"/>
+	</oaf_attribute>
+</oaf_server>
+
+<oaf_server iid="OAFIID:Bonobo_MonikerExtender_file" type="factory"
+	location="OAFIID:Bonobo_Moniker_std_Factory">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:Bonobo/MonikerExtender:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+	<oaf_attribute name="bonobo:moniker_extender" type="stringv">
+		<item value="file:"/>
+	</oaf_attribute>
+	<oaf_attribute name="name" type="string" _value="file MonikerExtender"/>
+</oaf_server>
+
+<oaf_server iid="OAFIID:Bonobo_MonikerExtender_stream" type="factory"
+	location="OAFIID:Bonobo_Moniker_std_Factory">
+	<oaf_attribute name="repo_ids" type="stringv">
+		<item value="IDL:Bonobo/MonikerExtender:1.0"/>
+		<item value="IDL:Bonobo/Unknown:1.0"/>
+	</oaf_attribute>
+	<oaf_attribute name="bonobo:moniker_extender" type="stringv">
+		<item value="file:"/>
+		<item value="http:"/>
+		<item value="gunzip:"/>
+		<item value="untar:"/>
+	</oaf_attribute>
+	<oaf_attribute name="name" type="string" _value="stream MonikerExtender"/>
+</oaf_server>
+
+</oaf_info>
diff --git a/monikers/Makefile.am-50588 b/monikers/Makefile.am-50588
new file mode 100644
index 0000000..57e34df
--- /dev/null
+++ b/monikers/Makefile.am-50588
@@ -0,0 +1,60 @@
+PLUGIN_DIR=$(libdir)/bonobo/plugin
+
+INCLUDES =                                              \
+        -DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
+	-I$(srcdir) -I$(top_srcdir) 			\
+	-I$(top_builddir)				\
+	-DPLUGIN_DIR=\""$(PLUGIN_DIR)"\"		\
+	-I$(top_srcdir)/libefs/src			\
+        -I$(includedir)                                 \
+	$(VFS_CFLAGS)					\
+        $(GNOME_INCLUDEDIR)
+
+common_ldflags = -avoid-version
+
+bonobo_plugindir =  $(PLUGIN_DIR)
+bonobo_plugin_LTLIBRARIES = libstorage_efs.la libstorage_fs.la 
+
+#
+# EFS storage module
+#
+libstorage_efs_la_SOURCES = 	\
+	bonobo-storage-efs.c	\
+	bonobo-storage-efs.h	\
+	bonobo-stream-efs.c	\
+	bonobo-stream-efs.h
+
+libstorage_efs_la_LDFLAGS = 			\
+	$(common_ldflags) 			\
+	-L$(shell pwd)/$(top_builddir)/libefs/src/.libs\
+	-lefs
+
+#
+# File-system based storage
+#
+libstorage_fs_la_SOURCES =	\
+	bonobo-storage-fs.c	\
+	bonobo-storage-fs.h	\
+	bonobo-stream-fs.c	\
+	bonobo-stream-fs.h
+
+libstorage_fs_la_LDFLAGS = 	\
+	$(common_ldflags)
+
+#
+# VFS storage module - disabled for now.
+#
+if HAVE_VFS
+libstoragedir = $(PLUGIN_DIR)
+libstorage_LTLIBRARIES =	\
+	libstorage_vfs.la
+
+libstorage_vfs_la_SOURCES =	\
+	bonobo-storage-vfs.c	\
+	bonobo-storage-vfs.h	\
+	bonobo-stream-vfs.c	\
+	bonobo-stream-vfs.h
+
+libstorage_vfs_la_LIBADD = 	\
+	$(VFS_LIBS)
+endif
diff --git a/monikers/bonobo-moniker-extender-file.c b/monikers/bonobo-moniker-extender-file.c
new file mode 100644
index 0000000..e882c08
--- /dev/null
+++ b/monikers/bonobo-moniker-extender-file.c
@@ -0,0 +1,98 @@
+/*
+ * bonobo-moniker-extender-file.c: 
+ *
+ * Author:
+ *	Dietmar Maurer (dietmar helixcode com)
+ *
+ * Copyright 2000, Helix Code, Inc.
+ */
+#include <config.h>
+#include <bonobo/bonobo-storage.h>
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-moniker.h>
+#include <bonobo/bonobo-moniker-extender.h>
+#include <bonobo/bonobo-moniker-util.h>
+#include <libgnome/gnome-mime.h>
+#include <liboaf/liboaf.h>
+
+#include "bonobo-moniker-std.h"
+
+Bonobo_Unknown
+bonobo_file_extender_resolve (BonoboMonikerExtender *extender,
+			      const Bonobo_Moniker   m,
+			      const Bonobo_ResolveOptions *options,
+			      const CORBA_char      *display_name,
+			      const CORBA_char      *requested_interface,
+			      CORBA_Environment     *ev)
+{
+	const char         *mime_type;
+	char               *oaf_requirements;
+	Bonobo_Unknown      object;
+	Bonobo_Persist      persist;
+	OAF_ActivationID    ret_id;
+	const char         *fname;
+	OAF_ServerInfoList *result;
+	char               *oafiid;
+
+	if (strchr (display_name, ':'))
+		fname = strchr (display_name, ':') + 1;
+	else
+		fname = display_name;
+
+	g_warning ("Filename : '%s'", fname);
+
+	mime_type = gnome_mime_type (fname);
+
+	oaf_requirements = g_strdup_printf (
+		"bonobo:supported_mime_types.has ('%s') AND repo_ids.has ('%s') AND "
+		"repo_ids.has ('IDL:Bonobo/PersistFile:1.0')",
+		mime_type, requested_interface);
+		
+	result = oaf_query (oaf_requirements, NULL, ev);
+	if (BONOBO_EX (ev) || result == NULL || result->_buffer == NULL ||
+	    !result->_buffer[0].iid)
+		return CORBA_OBJECT_NIL;
+
+	g_free (oaf_requirements);
+
+	oafiid = g_strdup (result->_buffer[0].iid);
+
+	CORBA_free (result);
+
+	object = bonobo_url_lookup (oafiid, display_name, ev);
+	if (!BONOBO_EX (ev) && object != CORBA_OBJECT_NIL) {
+		g_free (oafiid);
+		Bonobo_Unknown_ref (object, ev);
+		if (!BONOBO_EX (ev))
+			return bonobo_moniker_util_qi_return (object, 
+			        requested_interface, ev);
+	}
+	
+	CORBA_exception_init (ev);
+
+	object = oaf_activate_from_id (oafiid, 0, &ret_id, ev);
+
+	g_free (oafiid);	
+
+	if (BONOBO_EX (ev) || object == CORBA_OBJECT_NIL)
+		return CORBA_OBJECT_NIL;
+
+	persist = Bonobo_Unknown_queryInterface (
+		object, "IDL:Bonobo/PersistFile:1.0", ev);
+
+	if (BONOBO_EX (ev) || persist == CORBA_OBJECT_NIL) {
+		bonobo_object_release_unref (object, ev);
+		return CORBA_OBJECT_NIL;
+	}
+
+	if (persist != CORBA_OBJECT_NIL) {
+		Bonobo_PersistFile_load (persist, fname, ev);
+
+		bonobo_object_release_unref (persist, ev);
+
+		return bonobo_moniker_util_qi_return (
+			object, requested_interface, ev);
+	}
+	
+	return CORBA_OBJECT_NIL;
+}
diff --git a/monikers/bonobo-moniker-file.c b/monikers/bonobo-moniker-file.c
new file mode 100644
index 0000000..b23d74b
--- /dev/null
+++ b/monikers/bonobo-moniker-file.c
@@ -0,0 +1,72 @@
+/*
+ * bonobo-moniker-file.c: Sample file-system based Moniker implementation
+ *
+ * This is the file-system based Moniker implementation.
+ *
+ * Author:
+ *	Michael Meeks (michael helixcode com)
+ *
+ * Copyright 2000, Helix Code, Inc.
+ */
+#include <config.h>
+
+#include <bonobo/bonobo-exception.h>
+#include <bonobo/bonobo-storage.h>
+#include <bonobo/bonobo-moniker-util.h>
+
+#include "bonobo-moniker-std.h"
+
+Bonobo_Unknown
+bonobo_moniker_file_resolve (BonoboMoniker               *moniker,
+			     const Bonobo_ResolveOptions *options,
+			     const CORBA_char            *requested_interface,
+			     CORBA_Environment           *ev)
+{
+	const char    *fname = bonobo_moniker_get_name (moniker);
+	Bonobo_Unknown retval;
+
+	if (!strcmp (requested_interface, "IDL:Bonobo/Stream:1.0")) {
+		BonoboStream *stream;
+		
+		stream = bonobo_stream_open ("fs", fname,
+					     Bonobo_Storage_READ, 0664);
+
+		if (!stream) {
+			g_warning ("Failed to open stream '%s'", fname);
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+					     ex_Bonobo_Moniker_InterfaceNotFound, NULL);
+			return CORBA_OBJECT_NIL;
+		}
+
+		return CORBA_Object_duplicate (BONOBO_OBJREF (stream), ev);
+
+	} else if (!strcmp (requested_interface, "IDL:Bonobo/Storage:1.0")) {
+		BonoboStorage *storage;
+		
+		storage = bonobo_storage_open ("fs", fname,
+					       Bonobo_Storage_READ, 0664);
+
+		if (!storage) {
+			g_warning ("Failed to open storage '%s'", fname);
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+					     ex_Bonobo_Moniker_InterfaceNotFound, NULL);
+			return CORBA_OBJECT_NIL;
+		}
+
+		return CORBA_Object_duplicate (BONOBO_OBJREF (storage), ev);
+	}
+
+	retval = bonobo_moniker_use_extender (
+		"OAFIID:Bonobo_MonikerExtender_file",
+		moniker, options, requested_interface, ev);
+
+	if (BONOBO_EX (ev))
+		return CORBA_OBJECT_NIL;
+	
+	if (retval == CORBA_OBJECT_NIL)
+		retval = bonobo_moniker_use_extender (
+			"OAFIID:Bonobo_MonikerExtender_stream",
+			moniker, options, requested_interface, ev);
+
+	return retval;
+}
diff --git a/monikers/bonobo-storage-fs.c b/monikers/bonobo-storage-fs.c
new file mode 100644
index 0000000..ae4ba20
--- /dev/null
+++ b/monikers/bonobo-storage-fs.c
@@ -0,0 +1,475 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * bonobo-storage-fs.c: Sample file-system based Storage implementation
+ *
+ * This is just a sample file-system based Storage implementation.
+ * it is only used for debugging purposes
+ *
+ * Author:
+ *   Miguel de Icaza (miguel gnu org)
+ */
+#include <config.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <libgnome/gnome-defs.h>
+#include <libgnome/gnome-util.h>
+#include <libgnome/gnome-mime.h>
+#include <storage-modules/bonobo-storage-fs.h>
+#include <storage-modules/bonobo-stream-fs.h>
+#include <bonobo/bonobo-storage-plugin.h>
+
+static BonoboStorageClass *bonobo_storage_fs_parent_class;
+
+static void
+bonobo_storage_fs_destroy (GtkObject *object)
+{
+	BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (object);
+
+	g_free (storage_fs->path);
+}
+
+static Bonobo_StorageInfo*
+fs_get_info (BonoboStorage *storage,
+	     const CORBA_char *path,
+	     const Bonobo_StorageInfoFields mask,
+	     CORBA_Environment *ev)
+{
+	BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (storage);
+	Bonobo_StorageInfo *si;
+	struct stat st;
+	char *full = NULL;
+	gboolean dangling = FALSE;
+
+	if (mask & ~(Bonobo_FIELD_CONTENT_TYPE | Bonobo_FIELD_SIZE |
+		     Bonobo_FIELD_TYPE)) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotSupported, NULL);
+		return CORBA_OBJECT_NIL;
+	}
+
+	full = g_concat_dir_and_file (storage_fs->path, path);
+	if (stat (full, &st) == -1) {
+		if (lstat (full, &st) == -1)
+			goto get_info_except;
+		else
+			dangling = TRUE;
+	}
+
+	si = Bonobo_StorageInfo__alloc ();
+	
+	si->size = st.st_size;
+	si->name = CORBA_string_dup (path);
+
+	if (S_ISDIR (st.st_mode)) {
+		si->type = Bonobo_STORAGE_TYPE_DIRECTORY;
+		si->content_type = CORBA_string_dup ("x-directory/normal");
+	} else {
+		si->type = Bonobo_STORAGE_TYPE_REGULAR;
+		if (dangling)
+			si->content_type =
+				CORBA_string_dup ("x-symlink/dangling");
+		else
+			si->content_type = 
+				CORBA_string_dup (gnome_mime_type_of_file (full));
+	}
+
+	g_free (full);
+
+	return si;
+
+ get_info_except:
+
+	if (full)
+		g_free (full);
+	
+	if (errno == EACCES) 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NoPermission, 
+				     NULL);
+	else if (errno == ENOENT) 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotFound, 
+				     NULL);
+	else 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_IOError, NULL);
+	
+	return CORBA_OBJECT_NIL;
+}
+
+static void
+fs_set_info (BonoboStorage *storage,
+	     const CORBA_char *path,
+	     const Bonobo_StorageInfo *info,
+	     const Bonobo_StorageInfoFields mask,
+	     CORBA_Environment *ev)
+{
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+			     ex_Bonobo_Storage_NotSupported, 
+			     NULL);
+}
+
+static BonoboStream *
+fs_open_stream (BonoboStorage *storage, 
+		const CORBA_char *path, 
+		Bonobo_Storage_OpenMode mode, 
+		CORBA_Environment *ev)
+{
+	BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (storage);
+	BonoboStream *stream;
+	char *full;
+
+	full = g_concat_dir_and_file (storage_fs->path, path);
+	stream = bonobo_stream_fs_open (full, mode, 0644, ev);
+	g_free (full);
+
+	return stream;
+}
+
+static BonoboStorage *
+fs_open_storage (BonoboStorage *storage, const CORBA_char *path, 
+		 Bonobo_Storage_OpenMode mode, CORBA_Environment *ev)
+{
+	BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (storage);
+	BonoboStorage *new_storage;
+	char *full;
+
+	full = g_concat_dir_and_file (storage_fs->path, path);
+	new_storage = bonobo_storage_fs_open (full, mode, 0644, ev);
+	g_free (full);
+
+	return new_storage;
+}
+
+
+static void
+fs_rename (BonoboStorage *storage, const CORBA_char *path, 
+	   const CORBA_char *new_path, CORBA_Environment *ev)
+{
+	BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (storage);
+	char *full_old, *full_new;
+
+	full_old = g_concat_dir_and_file (storage_fs->path, path);
+	full_new = g_concat_dir_and_file (storage_fs->path, new_path);
+
+	if (rename (full_old, full_new) == -1) {
+
+		if ((errno == EACCES) || (errno == EPERM) || (errno == EROFS)) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NoPermission, 
+					     NULL);
+		else if (errno == ENOENT) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NotFound, 
+					     NULL);
+		else if ((errno == EEXIST) || (errno == ENOTEMPTY)) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NameExists, 
+					     NULL);
+		else 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_IOError, 
+					     NULL);
+	}
+
+	g_free (full_old);
+	g_free (full_new);
+}
+
+static void
+fs_commit (BonoboStorage *storage, CORBA_Environment *ev)
+{
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+			     ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+static void
+fs_revert (BonoboStorage *storage, CORBA_Environment *ev)
+{
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+			     ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+static Bonobo_Storage_DirectoryList *
+fs_list_contents (BonoboStorage *storage, const CORBA_char *path, 
+		  Bonobo_StorageInfoFields mask, CORBA_Environment *ev)
+{
+	BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (storage);
+	Bonobo_Storage_DirectoryList *list = NULL;
+	Bonobo_StorageInfo *buf;
+	struct dirent *de;
+	struct stat st;
+	DIR *dir = NULL;
+	gint i, max, v, num_entries = 0;
+	gchar *full = NULL;
+
+	if (mask & ~(Bonobo_FIELD_CONTENT_TYPE | Bonobo_FIELD_SIZE |
+		     Bonobo_FIELD_TYPE)) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotSupported, NULL);
+		return CORBA_OBJECT_NIL;
+	}
+
+	if (!(dir = opendir (storage_fs->path)))
+			goto list_contents_except;
+	
+	for (max = 0; readdir (dir); max++)
+		/* do nothing */;
+
+	rewinddir (dir);
+
+	buf = CORBA_sequence_Bonobo_StorageInfo_allocbuf (max);
+	list = Bonobo_Storage_DirectoryList__alloc();
+	list->_buffer = buf;
+	CORBA_sequence_set_release (list, TRUE); 
+	
+	for (i = 0; (de = readdir (dir)) && (i < max); i++) {
+		
+		if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
+		    (de->d_name[0] == '.' && de->d_name[1] == '.' 
+		     && de->d_name[2] == '\0')) {
+			i--;
+			continue; /* Ignore . and .. */
+		}
+
+		buf [i].name = CORBA_string_dup (de->d_name);
+		buf [i].size = 0;
+		buf [i].content_type = NULL;
+
+		full = g_concat_dir_and_file (storage_fs->path, de->d_name);
+		v = stat (full, &st);
+
+		if (v == -1) {
+			/*
+			 * The stat failed -- two common cases are where
+			 * the file was removed between the call to readdir
+			 * and the iteration, and where the file is a dangling
+			 * symlink.
+			 */
+			if (errno == ENOENT || errno == ELOOP) {
+				v = lstat (full, &st);
+				if (v == 0) {
+					/* FIXME - x-symlink/dangling is odd */
+					buf [i].size = st.st_size;
+					buf [i].type = Bonobo_STORAGE_TYPE_REGULAR;
+					buf [i].content_type =
+						CORBA_string_dup ("x-symlink/dangling");
+					g_free (full);
+					num_entries++;
+					continue;
+				}
+			}
+
+			/* Unless it's something grave, just skip the file */
+			if (errno != ENOMEM && errno != EFAULT && errno != ENOTDIR) {
+				i--;
+				g_free (full);
+				continue;
+			}
+
+			goto list_contents_except;
+		}
+
+		buf [i].size = st.st_size;
+	
+		if (S_ISDIR (st.st_mode)) { 
+			buf [i].type = Bonobo_STORAGE_TYPE_DIRECTORY;
+			buf [i].content_type = 
+				CORBA_string_dup ("x-directory/normal");
+		} else { 
+			buf [i].type = Bonobo_STORAGE_TYPE_REGULAR;
+			buf [i].content_type = 
+				CORBA_string_dup (gnome_mime_type_of_file (full));
+		}
+
+		g_free (full);
+
+		num_entries++;
+	}
+
+	list->_length = num_entries; 
+
+	closedir (dir);
+	
+	return list; 
+
+ list_contents_except:
+
+	if (dir)
+		closedir (dir);
+
+	if (list) 
+		CORBA_free (list);
+
+	if (full)
+		g_free (full);
+	
+	if (errno == ENOENT) 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotFound, 
+				     NULL);
+	else if (errno == ENOTDIR) 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotStorage, 
+				     NULL);
+	else 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_IOError, NULL);
+	
+	return CORBA_OBJECT_NIL;
+}
+
+static void
+fs_erase (BonoboStorage *storage,
+	  const CORBA_char *path,
+	  CORBA_Environment *ev)
+{
+	BonoboStorageFS *storage_fs = BONOBO_STORAGE_FS (storage);
+	char *full;
+
+	full = g_concat_dir_and_file (storage_fs->path, path);
+
+	if (remove (full) == -1) {
+
+		if (errno == ENOENT) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NotFound, 
+					     NULL);
+		else if (errno == ENOTEMPTY) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NotEmpty, 
+					     NULL);
+		else if ((errno == EACCES) || (errno = EPERM)) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NoPermission, 
+					     NULL);
+		else 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_IOError, NULL);
+	}
+
+	g_free (full);
+}
+
+static void
+bonobo_storage_fs_class_init (BonoboStorageFSClass *class)
+{
+	GtkObjectClass *object_class = (GtkObjectClass *) class;
+	BonoboStorageClass *sclass = BONOBO_STORAGE_CLASS (class);
+	
+	bonobo_storage_fs_parent_class = 
+		gtk_type_class (bonobo_storage_get_type ());
+
+	sclass->get_info       = fs_get_info;
+	sclass->set_info       = fs_set_info;
+	sclass->open_stream    = fs_open_stream;
+	sclass->open_storage   = fs_open_storage;
+	sclass->copy_to        = NULL; /* use the generic method */
+	sclass->rename         = fs_rename;
+	sclass->commit         = fs_commit;
+	sclass->revert         = fs_revert;
+	sclass->list_contents  = fs_list_contents;
+	sclass->erase          = fs_erase;
+	
+	object_class->destroy = bonobo_storage_fs_destroy;
+}
+
+
+static void 
+bonobo_storage_fs_init (GtkObject *object)
+{
+	/* nothing to do */
+}
+
+BONOBO_X_TYPE_FUNC (BonoboStorageFS, 
+		      bonobo_storage_get_type (),
+		      bonobo_storage_fs);
+
+/*
+ * Creates the Gtk object and the corba server bound to it
+ */
+static BonoboStorage *
+do_bonobo_storage_fs_create (const char *path)
+{
+	BonoboStorageFS *storage_fs;
+
+	storage_fs = gtk_type_new (bonobo_storage_fs_get_type ());
+	storage_fs->path = g_strdup (path);
+
+	return BONOBO_STORAGE (storage_fs);
+}
+
+/** 
+ * bonobo_storage_fs_open:
+ * @path: path to existing directory that represents the storage
+ * @flags: open flags.
+ * @mode: mode used if @flags containst Bonobo_Storage_CREATE for the storage.
+ *
+ * Returns a BonoboStorage object that represents the storage at @path
+ */
+BonoboStorage *
+bonobo_storage_fs_open (const char *path, gint flags, gint mode,
+			CORBA_Environment *ev)
+{
+	struct stat st;
+	
+	g_return_val_if_fail (path != NULL, NULL);
+	g_return_val_if_fail (ev != NULL, NULL);
+
+	/* Most storages are files */
+	mode = mode | 0111;
+
+	if ((flags & Bonobo_Storage_CREATE) &&
+	    (mkdir (path, mode) == -1) && (errno != EEXIST)) {
+
+		if (errno == EACCES) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NoPermission, 
+					     NULL);
+		else 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_IOError, NULL);
+		return NULL;
+	}
+
+	if (stat (path, &st) == -1) {
+		
+		if (errno == ENOENT) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NotFound, 
+					     NULL);
+		else 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_IOError,
+					     NULL);
+		return NULL;
+	}
+
+	if (!S_ISDIR (st.st_mode)) { 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotStorage, NULL);
+		return NULL;
+	}
+
+	return do_bonobo_storage_fs_create (path);
+}
+
+gint 
+init_storage_plugin (StoragePlugin *plugin)
+{
+	g_return_val_if_fail (plugin != NULL, -1);
+
+	plugin->name = "fs";
+	plugin->description = "Native Filesystem Driver";
+	plugin->version = BONOBO_STORAGE_VERSION;
+	
+	plugin->storage_open = bonobo_storage_fs_open; 
+	plugin->stream_open = bonobo_stream_fs_open; 
+
+	return 0;
+}
+
diff --git a/monikers/bonobo-storage-fs.h b/monikers/bonobo-storage-fs.h
new file mode 100644
index 0000000..f8aed93
--- /dev/null
+++ b/monikers/bonobo-storage-fs.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+#ifndef _BONOBO_STORAGE_FS_H_
+#define _BONOBO_STORAGE_FS_H_
+
+#include <bonobo/bonobo-storage.h>
+
+BEGIN_GNOME_DECLS
+
+#define BONOBO_STORAGE_FS_TYPE        (bonobo_storage_fs_get_type ())
+#define BONOBO_STORAGE_FS(o)          (GTK_CHECK_CAST ((o), BONOBO_STORAGE_FS_TYPE, BonoboStorageFS))
+#define BONOBO_STORAGE_FS_CLASS(k)    (GTK_CHECK_CLASS_CAST((k), BONOBO_STORAGE_FS_TYPE, BonoboStorageFSClass))
+#define BONOBO_IS_STORAGE_FS(o)       (GTK_CHECK_TYPE ((o), BONOBO_STORAGE_FS_TYPE))
+#define BONOBO_IS_STORAGE_FS_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), BONOBO_STORAGE_FS_TYPE))
+
+typedef struct {
+	BonoboStorage storage;
+	char *path;
+} BonoboStorageFS;
+
+typedef struct {
+	BonoboStorageClass parent_class;
+} BonoboStorageFSClass;
+
+GtkType        bonobo_storage_fs_get_type  (void);
+BonoboStorage *bonobo_storage_fs_open      (const char        *path,
+					    gint               flags, 
+					    gint               mode,
+					    CORBA_Environment *ev);
+
+END_GNOME_DECLS
+
+#endif /* _BONOBO_STORAGE_FS_H_ */
diff --git a/monikers/bonobo-storage-vfs.c b/monikers/bonobo-storage-vfs.c
new file mode 100644
index 0000000..a7cdbe7
--- /dev/null
+++ b/monikers/bonobo-storage-vfs.c
@@ -0,0 +1,335 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * gnome-storage-vfs.c: Gnome VFS based storage implementation
+ *
+ * Author:
+ *   Michael Meeks <michael helixcode com>
+ */
+#include <config.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libgnome/gnome-defs.h>
+#include <libgnome/gnome-util.h>
+#include <storage-modules/bonobo-storage-vfs.h>
+#include <storage-modules/bonobo-stream-vfs.h>
+#include <bonobo/bonobo-storage-plugin.h>
+
+static BonoboStorageClass *bonobo_storage_vfs_parent_class;
+
+static Bonobo_StorageInfo*
+vfs_get_info (BonoboStorage *storage,
+	      const CORBA_char *path,
+	      const Bonobo_StorageInfoFields mask,
+	      CORBA_Environment *ev)
+{
+	g_warning ("FIXME: get_info not yet implemented");
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+			     ex_Bonobo_Storage_NotSupported, 
+			     NULL);
+	return CORBA_OBJECT_NIL;
+}
+
+static void
+vfs_set_info (BonoboStorage *storage,
+	      const CORBA_char *path,
+	      const Bonobo_StorageInfo *info,
+	      const Bonobo_StorageInfoFields mask,
+	      CORBA_Environment *ev)
+{
+	g_warning ("FIXME: set_info not yet implemented");
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+			     ex_Bonobo_Storage_NotSupported, 
+			     NULL);
+}
+
+static BonoboStream *
+vfs_open_stream (BonoboStorage *storage, const CORBA_char *path,
+		Bonobo_Storage_OpenMode mode, CORBA_Environment *ev)
+{
+	BonoboStorageVfs *storage_vfs = BONOBO_STORAGE_VFS (storage);
+	BonoboStream *stream;
+	char *full;
+
+	full = g_concat_dir_and_file (storage_vfs->path, path);
+	stream = bonobo_stream_vfs_open (full, 0664, mode, ev);
+	g_free (full);
+
+	return stream;
+}
+
+/*
+ * Creates the Gtk object and the corba server bound to it
+ */
+static BonoboStorage *
+do_bonobo_storage_vfs_create (const char *path)
+{
+	BonoboStorageVfs *storage_vfs;
+	Bonobo_Storage corba_storage;
+
+	storage_vfs = gtk_type_new (bonobo_storage_vfs_get_type ());
+	storage_vfs->path = g_strdup (path);
+	
+	corba_storage = bonobo_storage_corba_object_create (
+		BONOBO_OBJECT (storage_vfs));
+	if (corba_storage == CORBA_OBJECT_NIL) {
+		bonobo_object_unref (BONOBO_OBJECT (storage_vfs));
+		return NULL;
+	}
+
+	return bonobo_storage_construct (
+		BONOBO_STORAGE (storage_vfs), corba_storage);
+}
+
+static void
+vfs_rename (BonoboStorage *storage, const CORBA_char *path,
+	   const CORBA_char *new_path, CORBA_Environment *ev)
+{
+	g_warning ("Not yet implemented");
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+			     ex_Bonobo_Stream_IOError, NULL);
+}
+
+static void
+vfs_commit (BonoboStorage *storage, CORBA_Environment *ev)
+{
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+			     ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+static void
+vfs_revert (BonoboStorage *storage, CORBA_Environment *ev)
+{
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+			     ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+static Bonobo_Storage_DirectoryList *
+vfs_list_contents (BonoboStorage *storage, const CORBA_char *path, 
+		   Bonobo_StorageInfoFields mask, CORBA_Environment *ev)
+{
+	BonoboStorageVfs              *storage_vfs;
+	Bonobo_Storage_DirectoryList  *list = NULL;
+	GnomeVFSResult                 result;
+	GnomeVFSDirectoryList         *dir_list;
+	GnomeVFSFileInfo              *info;
+	char                          *uri;
+	int                            len, i;
+
+	storage_vfs = BONOBO_STORAGE_VFS (storage);
+
+	uri = g_concat_dir_and_file (storage_vfs->path, path);
+
+	result = gnome_vfs_directory_list_load (
+		&dir_list, uri, 
+		(mask & Bonobo_FIELD_CONTENT_TYPE) ?
+		GNOME_VFS_FILE_INFO_GET_MIME_TYPE :
+		GNOME_VFS_FILE_INFO_DEFAULT, NULL);
+
+	if (result != GNOME_VFS_OK) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotFound, NULL);
+		g_free (uri);
+		return NULL;
+	}
+
+	len  = gnome_vfs_directory_list_get_num_entries (dir_list);
+	list = Bonobo_Storage_DirectoryList__alloc      ();
+	list->_buffer = CORBA_sequence_Bonobo_StorageInfo_allocbuf (len);
+	list->_length = len;
+	CORBA_sequence_set_release (list, TRUE); 
+
+	i = 0;
+	for (info = gnome_vfs_directory_list_first (dir_list);
+	     info; info = gnome_vfs_directory_list_next (dir_list))
+
+		bonobo_stream_vfs_storageinfo_from_file_info (
+			&list->_buffer [i++], info);
+
+	gnome_vfs_directory_list_destroy (dir_list);
+
+	g_free (uri);
+
+	return list;
+}
+
+/** 
+ * bonobo_storage_vfs_open:
+ * @path: path to existing directory that represents the storage
+ * @flags: open flags.
+ * @mode: mode used if @flags containst BONOBO_SS_CREATE for the storage.
+ *
+ * Returns a BonoboStorage object that represents the storage at @path
+ */
+static BonoboStorage *
+bonobo_storage_vfs_open (const char *path, gint flags, gint mode,
+			 CORBA_Environment *ev)
+{
+	GnomeVFSResult    result;
+	GnomeVFSFileInfo *info;
+	gboolean          create = FALSE;
+	
+	g_return_val_if_fail (path != NULL, NULL);
+
+	info = gnome_vfs_file_info_new ();
+	result = gnome_vfs_get_file_info (
+		path, info, GNOME_VFS_FILE_INFO_DEFAULT);
+
+	if (result == GNOME_VFS_ERROR_NOT_FOUND &&
+	    (flags & Bonobo_Storage_CREATE))
+		create = TRUE;
+	    
+	else if (flags & Bonobo_Storage_READ) {
+		if (result != GNOME_VFS_OK) {
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+					     ex_Bonobo_Stream_NoPermission, NULL);
+			return NULL;
+		}
+
+		if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) &&
+		    (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)) {
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+					     ex_Bonobo_Stream_IOError, NULL);
+			return NULL;
+		}
+
+	} else if (flags & (Bonobo_Storage_WRITE)) {
+		if (result == GNOME_VFS_ERROR_NOT_FOUND)
+			create = TRUE;
+		else
+			if ((info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_TYPE) &&
+			    (info->type == GNOME_VFS_FILE_TYPE_DIRECTORY)) {
+				CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+						     ex_Bonobo_Stream_IOError, NULL);
+				return NULL;
+			}
+	}
+	gnome_vfs_file_info_unref (info);
+
+	if (create) {
+		result = gnome_vfs_make_directory (
+			path, GNOME_VFS_PERM_USER_ALL |
+			GNOME_VFS_PERM_GROUP_ALL);
+
+		if (result != GNOME_VFS_OK) {
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+					     ex_Bonobo_Stream_NoPermission, NULL);
+			return NULL;
+		}
+	}
+
+	return do_bonobo_storage_vfs_create (path);
+}
+
+static BonoboStorage *
+vfs_open_storage (BonoboStorage *storage,
+		  const CORBA_char *path,
+		  Bonobo_Storage_OpenMode mode,
+		  CORBA_Environment *ev)
+{
+	BonoboStorageVfs *storage_vfs = BONOBO_STORAGE_VFS (storage);
+	BonoboStorage    *new_storage;
+	GnomeVFSResult    result;
+	char *full;
+
+	full = g_concat_dir_and_file (storage_vfs->path, path);
+
+	result = gnome_vfs_make_directory (full, GNOME_VFS_PERM_USER_ALL);
+	if (result == GNOME_VFS_OK ||
+	    result == GNOME_VFS_ERROR_FILE_EXISTS)
+		new_storage = do_bonobo_storage_vfs_create (full);
+	else
+		new_storage = NULL;
+
+	g_free (full);
+
+	return new_storage;
+}
+
+static void
+vfs_erase (BonoboStorage *storage,
+	   const CORBA_char *path,
+	   CORBA_Environment *ev)
+{
+	BonoboStorageVfs *storage_vfs = BONOBO_STORAGE_VFS (storage);
+	GnomeVFSResult    result;
+	char *full;
+
+	full = g_concat_dir_and_file (storage_vfs->path, path);
+
+	result = gnome_vfs_unlink (full);
+
+	g_free (full);
+
+	if (result != GNOME_VFS_OK)
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NoPermission, 
+				     NULL);
+}
+
+static void
+bonobo_storage_vfs_destroy (GtkObject *object)
+{
+	BonoboStorageVfs *storage_vfs = BONOBO_STORAGE_VFS (object);
+
+	g_free (storage_vfs->path);
+}
+
+static void
+bonobo_storage_vfs_class_init (BonoboStorageVfsClass *class)
+{
+	GtkObjectClass *object_class = (GtkObjectClass *) class;
+	BonoboStorageClass *sclass = BONOBO_STORAGE_CLASS (class);
+	
+	bonobo_storage_vfs_parent_class = gtk_type_class (bonobo_storage_get_type ());
+
+	sclass->get_info       = vfs_get_info;
+	sclass->set_info       = vfs_set_info;
+	sclass->open_stream    = vfs_open_stream;
+	sclass->open_storage   = vfs_open_storage;
+	sclass->copy_to        = NULL; /* use the generic method */
+	sclass->rename         = vfs_rename;
+	sclass->commit         = vfs_commit;
+	sclass->revert         = vfs_revert;
+	sclass->list_contents  = vfs_list_contents;
+	sclass->erase          = vfs_erase;
+
+	object_class->destroy = bonobo_storage_vfs_destroy;
+}
+
+GtkType
+bonobo_storage_vfs_get_type (void)
+{
+	static GtkType type = 0;
+
+	if (!type){
+		GtkTypeInfo info = {
+			"IDL:GNOME/StorageVfs:1.0",
+			sizeof (BonoboStorageVfs),
+			sizeof (BonoboStorageVfsClass),
+			(GtkClassInitFunc) bonobo_storage_vfs_class_init,
+			(GtkObjectInitFunc) NULL,
+			NULL, /* reserved 1 */
+			NULL, /* reserved 2 */
+			(GtkClassInitFunc) NULL
+		};
+
+		type = gtk_type_unique (bonobo_storage_get_type (), &info);
+	}
+
+	return type;
+}
+
+gint 
+init_storage_plugin (StoragePlugin *plugin)
+{
+	g_return_val_if_fail (plugin != NULL, -1);
+
+	plugin->name = "vfs";
+	plugin->description = "Gnome Virtual Filesystem Driver";
+	plugin->version = BONOBO_STORAGE_VERSION;
+	
+	plugin->storage_open = bonobo_storage_vfs_open; 
+	plugin->stream_open  = bonobo_stream_vfs_open; 
+
+	return 0;
+}
diff --git a/monikers/bonobo-storage-vfs.h b/monikers/bonobo-storage-vfs.h
new file mode 100644
index 0000000..6d1613f
--- /dev/null
+++ b/monikers/bonobo-storage-vfs.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+#ifndef _BONOBO_STORAGE_VFS_H_
+#define _BONOBO_STORAGE_VFS_H_
+
+#include <bonobo/bonobo-storage.h>
+
+BEGIN_GNOME_DECLS
+
+#define BONOBO_STORAGE_VFS_TYPE        (bonobo_storage_vfs_get_type ())
+#define BONOBO_STORAGE_VFS(o)          (GTK_CHECK_CAST ((o), BONOBO_STORAGE_VFS_TYPE, BonoboStorageVfs))
+#define BONOBO_STORAGE_VFS_CLASS(k)    (GTK_CHECK_CLASS_CAST((k), BONOBO_STORAGE_VFS_TYPE, BonoboStorageVfsClass))
+#define BONOBO_IS_STORAGE_VFS(o)       (GTK_CHECK_TYPE ((o), BONOBO_STORAGE_VFS_TYPE))
+#define BONOBO_IS_STORAGE_VFS_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), BONOBO_STORAGE_VFS_TYPE))
+
+typedef struct {
+	BonoboStorage storage;
+	char *path;
+} BonoboStorageVfs;
+
+typedef struct {
+	BonoboStorageClass parent_class;
+} BonoboStorageVfsClass;
+
+GtkType         bonobo_storage_vfs_get_type     (void);
+
+END_GNOME_DECLS
+
+#endif /* _BONOBO_STORAGE_VFS_H_ */
diff --git a/monikers/bonobo-stream-fs.c b/monikers/bonobo-stream-fs.c
new file mode 100644
index 0000000..a54f8af
--- /dev/null
+++ b/monikers/bonobo-stream-fs.c
@@ -0,0 +1,500 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/**
+ * bonobo-stream-fs.c: Sample file-system based Stream implementation
+ *
+ * This is just a sample file-system based Stream implementation.
+ * it is only used for debugging purposes
+ *
+ * Author:
+ *   Miguel de Icaza (miguel gnu org)
+ */
+#include <config.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <libgnome/gnome-defs.h>
+#include <libgnome/gnome-util.h>
+#include <libgnome/gnome-mime.h>
+#include <storage-modules/bonobo-stream-fs.h>
+#include <errno.h>
+
+struct _BonoboStreamFSPrivate {
+	gchar *mime_type;
+};
+
+static BonoboStreamClass *bonobo_stream_fs_parent_class;
+
+static gint
+bonobo_mode_to_fs (Bonobo_Storage_OpenMode mode)
+{
+	gint fs_mode = 0;
+
+	if (mode & Bonobo_Storage_READ)
+		fs_mode |= O_RDONLY;
+	if (mode & Bonobo_Storage_WRITE)
+		fs_mode |= O_RDWR;
+	if (mode & Bonobo_Storage_CREATE)
+		fs_mode |= O_CREAT | O_RDWR;
+	if (mode & Bonobo_Storage_FAILIFEXIST)
+		fs_mode |= O_EXCL;
+
+	return fs_mode;
+}
+
+static Bonobo_StorageInfo*
+fs_get_info (BonoboStream                   *stream,
+	     const Bonobo_StorageInfoFields  mask,
+	     CORBA_Environment              *ev)
+{
+	BonoboStreamFS *stream_fs = BONOBO_STREAM_FS (stream);
+	Bonobo_StorageInfo *si;
+	struct stat st;
+
+	if (mask & ~(Bonobo_FIELD_CONTENT_TYPE | Bonobo_FIELD_SIZE |
+		     Bonobo_FIELD_TYPE)) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotSupported, NULL);
+		return CORBA_OBJECT_NIL;
+	}
+
+	if (fstat (stream_fs->fd, &st) == -1)
+		goto get_info_except;
+		
+	si = Bonobo_StorageInfo__alloc ();
+
+	si->size = st.st_size;
+	si->type = Bonobo_STORAGE_TYPE_REGULAR;
+	si->name = CORBA_string_dup ("");
+	si->content_type = CORBA_string_dup (stream_fs->priv->mime_type);
+
+	return si;
+
+ get_info_except:
+
+	if (errno == EACCES) 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Stream_NoPermission, NULL);
+	else 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Stream_IOError, NULL);
+	
+
+	return CORBA_OBJECT_NIL;
+}
+
+static void
+fs_set_info (BonoboStream                   *stream,
+	     const Bonobo_StorageInfo       *info,
+	     const Bonobo_StorageInfoFields  mask,
+	     CORBA_Environment              *ev)
+{
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+			     ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+static void
+fs_write (BonoboStream *stream, const Bonobo_Stream_iobuf *buffer,
+	  CORBA_Environment *ev)
+{
+	BonoboStreamFS *stream_fs = BONOBO_STREAM_FS (stream);
+
+	errno = EINTR;
+	while ((write (stream_fs->fd, buffer->_buffer, buffer->_length) == -1)
+	       && (errno == EINTR));
+
+	if (errno == EINTR) return;
+
+	if ((errno == EBADF) || (errno == EINVAL))
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Stream_NoPermission, NULL);
+	else 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Stream_IOError, NULL);
+}
+
+static void
+fs_read (BonoboStream         *stream,
+	 CORBA_long            count,
+	 Bonobo_Stream_iobuf **buffer,
+	 CORBA_Environment    *ev)
+{
+	BonoboStreamFS *stream_fs = BONOBO_STREAM_FS (stream);
+	CORBA_octet *data;
+	int bytes_read;
+	
+	if (count < 0) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Stream_IOError, NULL);
+		return;
+	}
+
+	*buffer = Bonobo_Stream_iobuf__alloc ();
+	CORBA_sequence_set_release (*buffer, TRUE);
+	data = CORBA_sequence_CORBA_octet_allocbuf (count);
+	(*buffer)->_buffer = data;
+	(*buffer)->_length = 0;
+
+	do {
+		bytes_read = read (stream_fs->fd, data, count);
+	} while ((bytes_read == -1) && (errno == EINTR));
+
+
+	if (bytes_read == -1) {
+		CORBA_free (*buffer);
+		*buffer = NULL;
+
+		if (errno == EACCES) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Stream_NoPermission, 
+					     NULL);
+		else 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+					     ex_Bonobo_Stream_IOError, NULL);
+	} else
+		(*buffer)->_length = bytes_read;
+}
+
+static CORBA_long
+fs_seek (BonoboStream           *stream,
+	 CORBA_long              offset, 
+	 Bonobo_Stream_SeekType  whence,
+	 CORBA_Environment      *ev)
+{
+	BonoboStreamFS *stream_fs = BONOBO_STREAM_FS (stream);
+	int fs_whence;
+	CORBA_long pos;
+
+	if (whence == Bonobo_Stream_SEEK_CUR)
+		fs_whence = SEEK_CUR;
+	else if (whence == Bonobo_Stream_SEEK_END)
+		fs_whence = SEEK_END;
+	else
+		fs_whence = SEEK_SET;
+
+	if ((pos = lseek (stream_fs->fd, offset, fs_whence)) == -1) {
+
+		if (errno == ESPIPE) 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Stream_NotSupported, 
+					     NULL);
+		else
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Stream_IOError, NULL);
+		return 0;
+	}
+
+	return pos;
+}
+
+static void
+fs_truncate (BonoboStream      *stream,
+	     const CORBA_long   new_size, 
+	     CORBA_Environment *ev)
+{
+	BonoboStreamFS *stream_fs = BONOBO_STREAM_FS (stream);
+
+	if (ftruncate (stream_fs->fd, new_size) == 0)
+		return;
+
+	if (errno == EACCES)
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+				     ex_Bonobo_Stream_NoPermission, NULL);
+	else 
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+				     ex_Bonobo_Stream_IOError, NULL);
+}
+
+static void
+fs_copy_to  (BonoboStream      *stream,
+	     const CORBA_char  *dest,
+	     const CORBA_long   bytes,
+	     CORBA_long        *read_bytes,
+	     CORBA_long        *written_bytes,
+	     CORBA_Environment *ev)
+{
+	BonoboStreamFS *stream_fs = BONOBO_STREAM_FS (stream);
+	gchar data[4096];
+	CORBA_unsigned_long more = bytes;
+	int v, w;
+	int fd_out;
+
+	*read_bytes = 0;
+	*written_bytes = 0;
+
+	if ((fd_out = creat(dest, 0644)) == -1)
+		goto copy_to_except;
+     
+	do {
+		if (bytes == -1) 
+			more = sizeof (data);
+
+		do {
+			v = read (stream_fs->fd, data, 
+				  MIN (sizeof (data), more));
+		} while ((v == -1) && (errno == EINTR));
+
+		if (v == -1) 
+			goto copy_to_except;
+
+		if (v <= 0) 
+			break;
+
+		*read_bytes += v;
+		more -= v;
+
+		do {
+			w = write (fd_out, data, v);
+		} while (w == -1 && errno == EINTR);
+		
+		if (w == -1)
+			goto copy_to_except;
+
+		*written_bytes += w;
+			
+	} while ((more > 0 || bytes == -1) && v > 0);
+
+	close (fd_out);
+
+	return;
+
+ copy_to_except:
+
+	if (fd_out != -1)
+		close (fd_out);
+
+	if (errno == EACCES)
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Stream_NoPermission, NULL);
+	else
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Stream_IOError, NULL);
+}
+
+static void
+fs_commit (BonoboStream *stream,
+	   CORBA_Environment *ev)
+{
+        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+                             ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+static void
+fs_revert (BonoboStream *stream,
+	   CORBA_Environment *ev)
+{
+        CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+                             ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+
+static void
+fs_destroy (GtkObject *object)
+{
+	BonoboStreamFS *stream_fs = BONOBO_STREAM_FS (object);
+	
+	if (close (stream_fs->fd)) 
+		g_warning ("Close failed");
+	stream_fs->fd = -1;
+
+	if (stream_fs->path)
+		g_free (stream_fs->path);
+	stream_fs->path = NULL;
+
+	if (stream_fs->priv->mime_type)
+		g_free (stream_fs->priv->mime_type);
+	stream_fs->priv->mime_type = NULL;
+}
+
+static void
+fs_finalize (GtkObject *object)
+{
+	BonoboStreamFS *stream_fs = BONOBO_STREAM_FS (object);
+	
+	if (stream_fs->priv)
+		g_free (stream_fs->priv);
+	stream_fs->priv = NULL;
+}
+
+static void
+bonobo_stream_fs_class_init (BonoboStreamFSClass *klass)
+{
+	GtkObjectClass    *oclass = (GtkObjectClass *) klass;
+	BonoboStreamClass *sclass = BONOBO_STREAM_CLASS (klass);
+	
+	bonobo_stream_fs_parent_class = 
+		gtk_type_class (bonobo_stream_get_type ());
+
+	sclass->get_info = fs_get_info;
+	sclass->set_info = fs_set_info;
+	sclass->write    = fs_write;
+	sclass->read     = fs_read;
+	sclass->seek     = fs_seek;
+	sclass->truncate = fs_truncate;
+	sclass->copy_to  = fs_copy_to;
+        sclass->commit   = fs_commit;
+        sclass->revert   = fs_revert;
+
+	oclass->destroy = fs_destroy;
+	oclass->finalize = fs_finalize;
+}
+
+static void
+bonobo_stream_fs_init (BonoboStreamFS *stream_fs)
+{
+	stream_fs->priv = g_new0 (BonoboStreamFSPrivate,1);
+	stream_fs->priv->mime_type = NULL;
+}
+
+/**
+ * bonobo_stream_fs_get_type:
+ *
+ * Returns the GtkType for the BonoboStreamFS class.
+ */
+GtkType
+bonobo_stream_fs_get_type (void)
+{
+	static GtkType type = 0;
+
+	if (!type){
+		GtkTypeInfo info = {
+			"BonoboStreamFS",
+			sizeof (BonoboStreamFS),
+			sizeof (BonoboStreamFSClass),
+			(GtkClassInitFunc) bonobo_stream_fs_class_init,
+			(GtkObjectInitFunc) bonobo_stream_fs_init,
+			NULL, /* reserved 1 */
+			NULL, /* reserved 2 */
+			(GtkClassInitFunc) NULL
+		};
+
+		type = gtk_type_unique (bonobo_stream_get_type (), &info);
+	}
+
+	return type;
+}
+
+/**
+ * bonobo_stream_fs_construct:
+ * @stream: The BonoboStreamFS object to initialize.
+ * @corba_stream: The CORBA server which implements the BonoboStreamFS service.
+ *
+ * This function initializes an object of type BonoboStreamFS using the
+ * provided CORBA server @corba_stream.
+ *
+ * Returns the constructed BonoboStreamFS @stream.
+ */
+BonoboStream *
+bonobo_stream_fs_construct (BonoboStreamFS *stream,
+			   Bonobo_Stream corba_stream)
+{
+	g_return_val_if_fail (stream != NULL, NULL);
+	g_return_val_if_fail (BONOBO_IS_STREAM (stream), NULL);
+	g_return_val_if_fail (corba_stream != CORBA_OBJECT_NIL, NULL);
+
+	bonobo_object_construct (
+		BONOBO_OBJECT (stream), corba_stream);
+
+	return BONOBO_STREAM (stream);
+}
+
+static BonoboStream *
+bonobo_stream_create (int fd, const char *path)
+{
+	BonoboStreamFS *stream_fs;
+	Bonobo_Stream corba_stream;
+
+	stream_fs = gtk_type_new (bonobo_stream_fs_get_type ());
+	if (stream_fs == NULL)
+		return NULL;
+	
+	stream_fs->fd = fd;
+	stream_fs->priv->mime_type = g_strdup (gnome_mime_type_of_file (path));
+	
+	corba_stream = bonobo_stream_corba_object_create (
+		BONOBO_OBJECT (stream_fs));
+
+	if (corba_stream == CORBA_OBJECT_NIL) {
+		bonobo_object_unref (BONOBO_OBJECT (stream_fs));
+		return NULL;
+	}
+
+	return bonobo_stream_fs_construct (stream_fs, corba_stream);
+}
+
+
+/**
+ * bonobo_stream_fs_open:
+ * @path: The path to the file to be opened.
+ * @flags: The flags with which the file should be opened.
+ *
+ * Creates a new BonoboStream object for the filename specified by
+ * @path.  
+ */
+BonoboStream *
+bonobo_stream_fs_open (const char *path, gint flags, gint mode,
+		       CORBA_Environment *ev)
+{
+	BonoboStream *stream;
+	struct stat st;
+	int v, fd;
+	gint fs_flags;
+
+	if (!path || !ev) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_IOError, NULL);
+		return NULL;
+	}
+
+	if (((v = stat (path, &st)) == -1) && 
+	    !(flags & Bonobo_Storage_CREATE)) {
+		
+		if ((errno == ENOENT) || (errno == ENOTDIR))
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NotFound, 
+					     NULL);
+		else if (errno == EACCES)
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NoPermission, 
+					     NULL);
+		else 
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_IOError, NULL);
+		return NULL;
+	}
+
+	if ((v != -1) && S_ISDIR(st.st_mode)) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotStream, 
+				     NULL);
+		return NULL;
+	}
+
+
+	fs_flags = bonobo_mode_to_fs (flags);
+ 
+	if ((fd = open (path, fs_flags, mode)) == -1) {
+
+		if ((errno == ENOENT) || (errno == ENOTDIR))
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NotFound, 
+					     NULL);
+		else if (errno == EACCES)
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NoPermission, 
+					     NULL);
+		else if (errno == EEXIST)
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_NameExists, 
+					     NULL);
+		else
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+					     ex_Bonobo_Storage_IOError, NULL);
+		return NULL;
+	}
+
+	if (!(stream = bonobo_stream_create (fd, path)))
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_IOError, NULL);
+
+	return stream;
+}
diff --git a/monikers/bonobo-stream-fs.h b/monikers/bonobo-stream-fs.h
new file mode 100644
index 0000000..49cd71e
--- /dev/null
+++ b/monikers/bonobo-stream-fs.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/**
+ * bonobo-stream-fs.c: Sample file-system based Stream implementation
+ *
+ * This is just a sample file-system based Stream implementation.
+ * it is only used for debugging purposes
+ *
+ * Author:
+ *   Miguel de Icaza (miguel gnu org)
+ */
+#ifndef _BONOBO_STREAM_FS_H_
+#define _BONOBO_STREAM_FS_H_
+
+#include <bonobo/bonobo-stream.h>
+
+BEGIN_GNOME_DECLS
+
+#define BONOBO_STREAM_FS_TYPE        (bonobo_stream_fs_get_type ())
+#define BONOBO_STREAM_FS(o)          (GTK_CHECK_CAST ((o), BONOBO_STREAM_FS_TYPE, BonoboStreamFS))
+#define BONOBO_STREAM_FS_CLASS(k)    (GTK_CHECK_CLASS_CAST((k), BONOBO_STREAM_FS_TYPE, BonoboStreamFSClass))
+#define BONOBO_IS_STREAM_FS(o)       (GTK_CHECK_TYPE ((o), BONOBO_STREAM_FS_TYPE))
+#define BONOBO_IS_STREAM_FS_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), BONOBO_STREAM_FS_TYPE))
+
+typedef struct _BonoboStreamFS BonoboStreamFS;
+typedef struct _BonoboStreamFSPrivate BonoboStreamFSPrivate;
+
+struct _BonoboStreamFS {
+	BonoboStream stream;
+	int fd;
+	char *path;
+
+	BonoboStreamFSPrivate *priv;
+};
+
+typedef struct {
+	BonoboStreamClass parent_class;
+} BonoboStreamFSClass;
+
+GtkType          bonobo_stream_fs_get_type     (void);
+BonoboStream    *bonobo_stream_fs_construct    (BonoboStreamFS *stream,
+						Bonobo_Stream corba_stream);
+BonoboStream    *bonobo_stream_fs_open         (const char *path, 
+						gint flags,
+						gint mode, 
+						CORBA_Environment *ev);	
+END_GNOME_DECLS
+
+#endif /* _BONOBO_STREAM_FS_H_ */
diff --git a/monikers/bonobo-stream-vfs.c b/monikers/bonobo-stream-vfs.c
new file mode 100644
index 0000000..ca7dc5e
--- /dev/null
+++ b/monikers/bonobo-stream-vfs.c
@@ -0,0 +1,416 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/**
+ * gnome-stream-vfs.c: Gnome VFS based stream implementation
+ *
+ * Author:
+ *   Michael Meeks <michael helixcode com>
+ *
+ * Copyright 2000, Helix Code Inc.
+ */
+#include <config.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <libgnome/gnome-defs.h>
+#include <libgnome/gnome-util.h>
+#include "bonobo-stream-vfs.h"
+#include <errno.h>
+
+static BonoboStreamClass *bonobo_stream_vfs_parent_class;
+
+void
+bonobo_stream_vfs_storageinfo_from_file_info (Bonobo_StorageInfo *si,
+					      GnomeVFSFileInfo   *fi)
+{
+	g_return_if_fail (si != NULL);
+	g_return_if_fail (fi != NULL);
+
+	si->name = CORBA_string_dup (fi->name);
+
+	if (fi->flags & GNOME_VFS_FILE_INFO_FIELDS_SIZE)
+		si->size = fi->size;
+	else
+		si->size = 0;
+
+	if (fi->flags & GNOME_VFS_FILE_INFO_FIELDS_TYPE &&
+	    fi->type == GNOME_VFS_FILE_TYPE_DIRECTORY)
+		si->type = Bonobo_STORAGE_TYPE_DIRECTORY;
+	else
+		si->type = Bonobo_STORAGE_TYPE_REGULAR;
+
+	if (fi->flags & GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE &&
+	    fi->mime_type)
+		si->content_type = CORBA_string_dup (fi->mime_type);
+	else
+		si->content_type = CORBA_string_dup ("");
+}
+
+static Bonobo_StorageInfo *
+vfs_get_info (BonoboStream                   *stream,
+	      const Bonobo_StorageInfoFields  mask,
+	      CORBA_Environment              *ev)
+{
+	BonoboStreamVfs    *sfs = BONOBO_STREAM_VFS (stream);
+	Bonobo_StorageInfo *si;
+	GnomeVFSFileInfo    fi;
+	GnomeVFSResult      result;
+
+	if (mask & ~(Bonobo_FIELD_CONTENT_TYPE | Bonobo_FIELD_SIZE |
+		     Bonobo_FIELD_TYPE)) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+				     ex_Bonobo_Storage_NotSupported, NULL);
+		return CORBA_OBJECT_NIL;
+	}
+
+	gnome_vfs_file_info_init (&fi);
+	result = gnome_vfs_get_file_info_from_handle (
+		sfs->handle, &fi,
+		(mask & Bonobo_FIELD_CONTENT_TYPE) ?
+		GNOME_VFS_FILE_INFO_GET_MIME_TYPE :
+		GNOME_VFS_FILE_INFO_DEFAULT);
+
+	if (result != GNOME_VFS_OK) {
+		if (result == GNOME_VFS_ERROR_ACCESS_DENIED)
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+					     ex_Bonobo_Stream_NoPermission, NULL);
+		else
+			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+					     ex_Bonobo_Stream_IOError, NULL);
+		return NULL;
+	}
+
+	si = Bonobo_StorageInfo__alloc ();
+
+	bonobo_stream_vfs_storageinfo_from_file_info (si, &fi);
+
+	gnome_vfs_file_info_clear (&fi);
+
+	return si;
+}
+
+static void
+vfs_set_info (BonoboStream                   *stream,
+	      const Bonobo_StorageInfo       *info,
+	      const Bonobo_StorageInfoFields  mask,
+	      CORBA_Environment              *ev)
+{
+	g_warning ("FIXME: set_info: a curious and not yet implemented API");
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION, 
+			     ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+static void
+vfs_write (BonoboStream *stream,
+	   const Bonobo_Stream_iobuf *buffer,
+	   CORBA_Environment *ev)
+{
+	BonoboStreamVfs *sfs = BONOBO_STREAM_VFS (stream);
+	GnomeVFSResult   result;
+	GnomeVFSFileSize bytes_written;
+
+	do {
+		result = gnome_vfs_write (sfs->handle, buffer->_buffer,
+					  buffer->_length, &bytes_written);
+	} while (bytes_written < 1 && result == GNOME_VFS_ERROR_INTERRUPTED);
+
+	if (result != GNOME_VFS_OK)
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+				     ex_Bonobo_Stream_IOError, NULL);
+}
+
+static void
+vfs_read (BonoboStream *stream, CORBA_long count,
+	  Bonobo_Stream_iobuf **buffer,
+	  CORBA_Environment    *ev)
+{
+	BonoboStreamVfs *sfs = BONOBO_STREAM_VFS (stream);
+	GnomeVFSResult   result;
+	GnomeVFSFileSize bytes_read;
+	CORBA_octet     *data;
+
+	*buffer = Bonobo_Stream_iobuf__alloc ();
+	CORBA_sequence_set_release (*buffer, TRUE);
+
+	data = CORBA_sequence_CORBA_octet_allocbuf (count);
+
+	do {
+		result = gnome_vfs_read (sfs->handle, data,
+					 count, &bytes_read);
+	} while (bytes_read < 1 && result == GNOME_VFS_ERROR_INTERRUPTED);
+
+	if (result == GNOME_VFS_ERROR_EOF) {
+		(*buffer)->_length = 0;
+		(*buffer)->_buffer = NULL;
+		CORBA_free (data);
+	} else if (result != GNOME_VFS_OK) {
+		CORBA_free (data);
+		CORBA_free (*buffer);
+		*buffer = NULL;
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+				     ex_Bonobo_Stream_IOError, NULL);
+	} else {
+		(*buffer)->_buffer = data;
+		(*buffer)->_length = bytes_read;
+	}
+}
+
+static CORBA_long
+vfs_seek (BonoboStream *stream,
+	  CORBA_long offset, Bonobo_Stream_SeekType whence,
+	  CORBA_Environment *ev)
+{
+	BonoboStreamVfs     *sfs = BONOBO_STREAM_VFS (stream);
+	GnomeVFSSeekPosition pos;
+	GnomeVFSResult       result;
+	GnomeVFSFileOffset   where;
+	
+	switch (whence) {
+	case Bonobo_Stream_SEEK_CUR:
+		pos = GNOME_VFS_SEEK_CURRENT;
+		break;
+	case Bonobo_Stream_SEEK_END:
+		pos = GNOME_VFS_SEEK_END;
+		break;
+	case Bonobo_Stream_SEEK_SET:
+		pos = GNOME_VFS_SEEK_START;
+		break;
+	default:
+		g_warning ("Seek whence %d unknown; fall back to SEEK_SET",
+			   whence);
+		pos = GNOME_VFS_SEEK_START;
+		break;
+	}
+	
+	result = gnome_vfs_seek (sfs->handle, pos, offset);
+
+	if (result != GNOME_VFS_OK) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+				     ex_Bonobo_Stream_IOError, NULL);
+		return -1;
+	}
+       
+	result = gnome_vfs_tell (sfs->handle, &where);
+	
+	if (result != GNOME_VFS_OK) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+				     ex_Bonobo_Stream_IOError, NULL);
+		return -1;
+	}
+
+	return where;
+}
+
+static void
+vfs_truncate (BonoboStream *stream,
+	      const CORBA_long new_size, 
+	      CORBA_Environment *ev)
+{
+	BonoboStreamVfs *sfs = BONOBO_STREAM_VFS (stream);
+	GnomeVFSResult result;
+
+	result = gnome_vfs_truncate_handle (sfs->handle, new_size);
+	if (result == GNOME_VFS_OK)
+		return;
+
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+			     ex_Bonobo_Stream_NoPermission, NULL);
+}
+
+static void
+vfs_copy_to  (BonoboStream      *stream,
+	      const CORBA_char  *dest,
+	      const CORBA_long  bytes,
+	      CORBA_long       *read_bytes,
+	      CORBA_long       *written_bytes,
+	      CORBA_Environment *ev)
+{
+	BonoboStreamVfs *sfs = BONOBO_STREAM_VFS (stream);
+#define READ_CHUNK_SIZE 65536
+	CORBA_octet      data [READ_CHUNK_SIZE];
+	CORBA_unsigned_long more = bytes;
+	GnomeVFSHandle  *fd_out;
+	GnomeVFSResult   res;
+	GnomeVFSFileSize rsize, wsize;
+
+	*read_bytes = 0;
+	*written_bytes = 0;
+
+	res = gnome_vfs_create (&fd_out, dest, GNOME_VFS_OPEN_WRITE, FALSE, 0666);
+	if (res != GNOME_VFS_OK) {
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+				     ex_Bonobo_Stream_NoPermission, NULL);
+		return;
+	}
+
+	do {
+		if (bytes == -1) 
+			more = READ_CHUNK_SIZE;
+
+		res = gnome_vfs_read (sfs->handle, data,
+				      MIN (READ_CHUNK_SIZE, more), &rsize);
+
+		if (res == GNOME_VFS_OK) {
+			*read_bytes += rsize;
+			more -= rsize;
+			res = gnome_vfs_write (fd_out, data, rsize, &wsize);
+			if (res == GNOME_VFS_OK)
+				*written_bytes += wsize;
+			else
+				break;
+		} else
+			rsize = 0;
+
+	} while ((more > 0 || bytes == -1) && rsize > 0);
+
+	if (res != GNOME_VFS_OK)
+		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+				     ex_Bonobo_Stream_IOError, NULL);
+
+	gnome_vfs_close (fd_out);
+}
+
+static void
+vfs_commit (BonoboStream *stream,
+	    CORBA_Environment *ev)
+{
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+			     ex_Bonobo_Stream_NotSupported, NULL);
+}
+
+static void
+vfs_revert (BonoboStream *stream,
+	    CORBA_Environment *ev)
+{
+	CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+			     ex_Bonobo_Stream_NotSupported, NULL);
+}
+	
+static void
+bonobo_stream_vfs_destroy (GtkObject *object)
+{
+	BonoboStreamVfs *sfs = BONOBO_STREAM_VFS (object);
+
+	if (sfs->handle)
+		if (gnome_vfs_close (sfs->handle) != GNOME_VFS_OK)
+			g_warning ("VFS Close failed");
+
+	sfs->handle = NULL;
+
+	GTK_OBJECT_CLASS (bonobo_stream_vfs_parent_class)->destroy (object);	
+}
+
+static void
+bonobo_stream_vfs_class_init (BonoboStreamVfsClass *klass)
+{
+	BonoboStreamClass *sclass = BONOBO_STREAM_CLASS (klass);
+	GtkObjectClass    *object_class = GTK_OBJECT_CLASS (klass);
+	
+	bonobo_stream_vfs_parent_class = gtk_type_class (bonobo_stream_get_type ());
+
+	sclass->get_info = vfs_get_info;
+	sclass->set_info = vfs_set_info;
+	sclass->write    = vfs_write;
+	sclass->read     = vfs_read;
+	sclass->seek     = vfs_seek;
+	sclass->truncate = vfs_truncate;
+	sclass->copy_to  = vfs_copy_to;
+	sclass->commit   = vfs_commit;
+	sclass->commit   = vfs_revert;
+
+	object_class->destroy = bonobo_stream_vfs_destroy;
+}
+
+/**
+ * bonobo_stream_vfs_get_type:
+ *
+ * Returns the GtkType for the BonoboStreamVfs class.
+ */
+GtkType
+bonobo_stream_vfs_get_type (void)
+{
+	static GtkType type = 0;
+
+	if (!type){
+		GtkTypeInfo info = {
+			"BonoboStreamVfs",
+			sizeof (BonoboStreamVfs),
+			sizeof (BonoboStreamVfsClass),
+			(GtkClassInitFunc) bonobo_stream_vfs_class_init,
+			(GtkObjectInitFunc) NULL,
+			NULL, /* reserved 1 */
+			NULL, /* reserved 2 */
+			(GtkClassInitFunc) NULL
+		};
+
+		type = gtk_type_unique (bonobo_stream_get_type (), &info);
+	}
+
+	return type;
+}
+
+static BonoboStream *
+bonobo_stream_create (GnomeVFSHandle *handle)
+{
+	BonoboStreamVfs *stream_vfs;
+	Bonobo_Stream corba_stream;
+
+	stream_vfs = gtk_type_new (bonobo_stream_vfs_get_type ());
+	if (stream_vfs == NULL)
+		return NULL;
+	
+	stream_vfs->handle = handle;
+	
+	corba_stream = bonobo_stream_corba_object_create (
+		BONOBO_OBJECT (stream_vfs));
+
+	if (corba_stream == CORBA_OBJECT_NIL){
+		bonobo_object_unref (BONOBO_OBJECT (stream_vfs));
+		return NULL;
+	}
+
+	return BONOBO_STREAM (
+		bonobo_object_construct (
+			BONOBO_OBJECT (stream_vfs), corba_stream));
+}
+
+
+/**
+ * bonobo_stream_vfs_open:
+ * @path: The path to the file to be opened.
+ * @mode: The mode with which the file should be opened.
+ *
+ * Creates a new BonoboStream object for the filename specified by
+ * @path.  
+ */
+BonoboStream *
+bonobo_stream_vfs_open (const char *path, gint flags, gint mode,
+			CORBA_Environment *ev)
+{
+	GnomeVFSResult   result;
+	GnomeVFSHandle  *handle;
+	GnomeVFSOpenMode vfs_mode = GNOME_VFS_OPEN_NONE;
+
+	g_return_val_if_fail (path != NULL, NULL);
+
+	if (mode == Bonobo_Storage_READ)
+		vfs_mode |= GNOME_VFS_OPEN_READ;
+
+	else if (mode == Bonobo_Storage_WRITE)
+		vfs_mode |= GNOME_VFS_OPEN_WRITE;
+	
+	else {
+		g_warning ("Unhandled open mode %d", mode);
+		return NULL;
+	}
+	
+	result = gnome_vfs_open (&handle, path, vfs_mode);
+	if (vfs_mode & GNOME_VFS_OPEN_WRITE &&
+	    result == GNOME_VFS_ERROR_NOT_FOUND)
+		result = gnome_vfs_create (&handle, path, vfs_mode,
+					   FALSE, S_IRUSR | S_IWUSR);
+	
+	if (result != GNOME_VFS_OK)
+		return NULL;
+
+	return bonobo_stream_create (handle);
+}
diff --git a/monikers/bonobo-stream-vfs.h b/monikers/bonobo-stream-vfs.h
new file mode 100644
index 0000000..0470432
--- /dev/null
+++ b/monikers/bonobo-stream-vfs.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+#ifndef _BONOBO_STREAM_VFS_H_
+#define _BONOBO_STREAM_VFS_H_
+
+#include <bonobo/bonobo-stream.h>
+#include <libgnomevfs/gnome-vfs.h>
+
+BEGIN_GNOME_DECLS
+
+typedef struct _BonoboStreamVfs BonoboStreamVfs;
+
+#define BONOBO_STREAM_VFS_TYPE        (bonobo_stream_vfs_get_type ())
+#define BONOBO_STREAM_VFS(o)          (GTK_CHECK_CAST ((o), BONOBO_STREAM_VFS_TYPE, BonoboStreamVfs))
+#define BONOBO_STREAM_VFS_CLASS(k)    (GTK_CHECK_CLASS_CAST((k), BONOBO_STREAM_VFS_TYPE, BonoboStreamVfsClass))
+#define BONOBO_IS_STREAM_VFS(o)       (GTK_CHECK_TYPE ((o), BONOBO_STREAM_VFS_TYPE))
+#define BONOBO_IS_STREAM_VFS_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), BONOBO_STREAM_VFS_TYPE))
+
+typedef struct _BonoboStreamVfsPrivate BonoboStreamVfsPrivate;
+
+struct _BonoboStreamVfs {
+	BonoboStream    stream;
+	GnomeVFSHandle *handle;
+
+	BonoboStreamVfsPrivate *priv;
+};
+
+typedef struct {
+	BonoboStreamClass parent_class;
+} BonoboStreamVfsClass;
+
+GtkType       bonobo_stream_vfs_get_type (void);
+BonoboStream *bonobo_stream_vfs_open     (const char *path,
+					  gint flags, gint mode,
+					  CORBA_Environment *ev);
+void bonobo_stream_vfs_storageinfo_from_file_info (Bonobo_StorageInfo *si,
+						   GnomeVFSFileInfo   *fi);
+	
+END_GNOME_DECLS
+
+#endif /* _BONOBO_STREAM_VFS_H_ */
diff --git a/monikers/gnome-moniker-std.c b/monikers/gnome-moniker-std.c
new file mode 100644
index 0000000..d8b05f4
--- /dev/null
+++ b/monikers/gnome-moniker-std.c
@@ -0,0 +1,70 @@
+#include <config.h>
+
+#include <bonobo/bonobo-shlib-factory.h>
+#include "bonobo-moniker-std.h"
+
+static BonoboObject *
+bonobo_std_moniker_factory (BonoboGenericFactory *this,
+			    const char           *object_id,
+			    void                 *data)
+{
+	g_return_val_if_fail (object_id != NULL, NULL);
+
+	if (!strcmp (object_id, "OAFIID:Bonobo_Moniker_File"))
+
+		return BONOBO_OBJECT (bonobo_moniker_simple_new (
+			"file:", bonobo_moniker_file_resolve));
+
+	else if (!strcmp (object_id, "OAFIID:Bonobo_Moniker_Item"))
+
+		return BONOBO_OBJECT (bonobo_moniker_simple_new (
+			"!", bonobo_moniker_item_resolve));
+	
+	else if (!strcmp (object_id, "OAFIID:Bonobo_Moniker_Oaf"))
+
+		return BONOBO_OBJECT (bonobo_moniker_simple_new (
+			"oafiid:", bonobo_moniker_oaf_resolve));
+
+	else if (!strcmp (object_id, "OAFIID:Bonobo_Moniker_Cache"))
+
+		return BONOBO_OBJECT (bonobo_moniker_simple_new (
+			"cache:", bonobo_moniker_cache_resolve));
+
+	else if (!strcmp (object_id, "OAFIID:Bonobo_Moniker_New"))
+
+		return BONOBO_OBJECT (bonobo_moniker_simple_new (
+			"new:", bonobo_moniker_new_resolve));
+
+/*
+ * Deprecated until Miguel likes it.
+ *
+ *	else if (!strcmp (object_id, "OAFIID:Bonobo_Moniker_Query"))
+ *		
+ *		return BONOBO_OBJECT (bonobo_moniker_simple_new (
+ *			"query:", bonobo_moniker_query_resolve));
+ */
+
+
+	else if (!strcmp (object_id, "OAFIID:Bonobo_MonikerExtender_file"))
+		
+		return BONOBO_OBJECT (bonobo_moniker_extender_new (
+			bonobo_file_extender_resolve, NULL));
+
+	else if (!strcmp (object_id, "OAFIID:Bonobo_MonikerExtender_stream"))
+		
+		return BONOBO_OBJECT (bonobo_moniker_extender_new (
+			bonobo_stream_extender_resolve, NULL));
+
+	else
+		g_warning ("Failing to manufacture a '%s'", object_id);
+
+	return NULL;
+}
+
+
+BONOBO_OAF_SHLIB_FACTORY_MULTI ("OAFIID:Bonobo_Moniker_std_Factory",
+				"bonobo standard moniker",
+				bonobo_std_moniker_factory,
+				NULL);
+
+
diff --git a/monikers/gnome-moniker-std.h b/monikers/gnome-moniker-std.h
new file mode 100644
index 0000000..4b06bca
--- /dev/null
+++ b/monikers/gnome-moniker-std.h
@@ -0,0 +1,53 @@
+#ifndef _BONOBO_MONIKER_STD_H_
+#define _BONOBO_MONIKER_STD_H_
+
+#include <bonobo/bonobo-moniker-simple.h>
+#include <bonobo/bonobo-moniker-extender.h>
+
+Bonobo_Unknown bonobo_moniker_file_resolve    (BonoboMoniker               *moniker,
+					       const Bonobo_ResolveOptions *options,
+					       const CORBA_char            *requested_interface,
+					       CORBA_Environment           *ev);
+
+Bonobo_Unknown bonobo_moniker_item_resolve    (BonoboMoniker               *moniker,
+					       const Bonobo_ResolveOptions *options,
+					       const CORBA_char            *requested_interface,
+					       CORBA_Environment           *ev);
+
+Bonobo_Unknown bonobo_moniker_oaf_resolve     (BonoboMoniker               *moniker,
+					       const Bonobo_ResolveOptions *options,
+					       const CORBA_char            *requested_interface,
+					       CORBA_Environment           *ev);
+
+Bonobo_Unknown bonobo_moniker_cache_resolve   (BonoboMoniker               *moniker,
+					       const Bonobo_ResolveOptions *options,
+					       const CORBA_char            *requested_interface,
+					       CORBA_Environment           *ev);
+
+Bonobo_Unknown bonobo_moniker_query_resolve   (BonoboMoniker               *moniker,
+					       const Bonobo_ResolveOptions *options,
+					       const CORBA_char            *requested_interface,
+					       CORBA_Environment           *ev);
+
+Bonobo_Unknown bonobo_moniker_new_resolve     (BonoboMoniker               *moniker,
+					       const Bonobo_ResolveOptions *options,
+					       const CORBA_char            *requested_interface,
+					       CORBA_Environment           *ev);
+
+/* extender functions */
+
+Bonobo_Unknown bonobo_file_extender_resolve   (BonoboMonikerExtender *extender,
+					       const Bonobo_Moniker   m,
+					       const Bonobo_ResolveOptions *options,
+					       const CORBA_char      *display_name,
+					       const CORBA_char      *requested_interface,
+					       CORBA_Environment     *ev);
+
+Bonobo_Unknown bonobo_stream_extender_resolve (BonoboMonikerExtender       *extender,
+					       const Bonobo_Moniker         m,
+					       const Bonobo_ResolveOptions *options,
+					       const CORBA_char            *display_name,
+					       const CORBA_char            *requested_interface,
+					       CORBA_Environment           *ev);
+
+#endif /* _BONOBO_MONIKER_STD_H_ */
diff --git a/po/.cvsignore b/po/.cvsignore
new file mode 100644
index 0000000..7754fbc
--- /dev/null
+++ b/po/.cvsignore
@@ -0,0 +1,11 @@
+*.gmo
+*.mo
+Makefile
+Makefile.in
+Makefile.in.in
+POTFILES
+cat-id-tbl.c
+gnome-libs.pot
+gnome.pot
+stamp-cat-id
+messages
diff --git a/po/ChangeLog b/po/ChangeLog
new file mode 100644
index 0000000..e69de29
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644
index 0000000..e69de29
diff --git a/tests/test-storage.c b/tests/test-storage.c
new file mode 100644
index 0000000..0eb0f73
--- /dev/null
+++ b/tests/test-storage.c
@@ -0,0 +1,544 @@
+#include <config.h>
+#include <gnome.h>
+#include <liboaf/liboaf.h>
+
+#include <gdk/gdkprivate.h>
+#include <gdk/gdkx.h>
+#include <bonobo/bonobo.h>
+
+#define TESTSIZE (1024*1)
+
+#define NO_EXCEPTION(ev)		  G_STMT_START{		        \
+     if (BONOBO_EX (ev))			       		        \
+       g_log (G_LOG_DOMAIN,					        \
+	      G_LOG_LEVEL_ERROR,				        \
+	      "file %s: line %d: unexpected exception: (%s)",	        \
+	      __FILE__,						        \
+	      __LINE__,						        \
+	      (ev)->_repo_id);		  }G_STMT_END
+
+#define CHECK_EXCEPTION(ev, repo_id)	  G_STMT_START{		        \
+     if (!BONOBO_EX (ev) || strcmp ((ev)->_repo_id, repo_id))	        \
+       g_log (G_LOG_DOMAIN,					        \
+	      G_LOG_LEVEL_ERROR,				        \
+	      "file %s: line %d: missing exception %s (got: %s)",	\
+	      __FILE__,						        \
+	      __LINE__,						        \
+	      repo_id,                                                  \
+	      (ev)->_repo_id);		                                \
+     CORBA_exception_free (ev);           }G_STMT_END
+
+
+CORBA_ORB orb;
+
+static void
+basic_io_tests (CORBA_Object storage, CORBA_Environment *ev)
+{
+	CORBA_Object stream;
+	Bonobo_Stream_iobuf *buf, *obuf;
+	gint32 i, j;
+
+	printf ("starting basic tests\n");
+
+	buf = Bonobo_Stream_iobuf__alloc ();
+	buf->_buffer = (gpointer)&i;
+	buf->_length = 4;
+	
+	/* try to open non existent file */
+	stream = Bonobo_Storage_openStream (storage, "test1.txt",
+					    Bonobo_Storage_READ, ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotFound);
+
+	/* create a new file */
+	Bonobo_Storage_openStream (storage, "test5.txt",
+				   Bonobo_Storage_CREATE, ev);
+	NO_EXCEPTION (ev);
+	
+	/* create a new file */
+	stream = Bonobo_Storage_openStream (storage, "test1.txt",
+					    Bonobo_Storage_CREATE, ev);
+	NO_EXCEPTION (ev);
+
+	/* write test data */
+	for (i = 0; i < TESTSIZE; i++) {
+		Bonobo_Stream_write (stream, buf, ev);
+		NO_EXCEPTION (ev);
+	}
+	
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+    	
+	/* open an existing file */
+	stream = Bonobo_Storage_openStream (storage, "test1.txt",
+					    Bonobo_Storage_READ, ev);
+	NO_EXCEPTION (ev);
+	
+	/* write to a read only file */
+	Bonobo_Stream_write (stream, buf, ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Stream_NoPermission);
+
+	/* erase nonexistent file */
+	Bonobo_Storage_erase (storage, "t1.txt", ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotFound);
+
+	/* erase the file */
+	Bonobo_Storage_erase (storage, "test1.txt", ev);
+	NO_EXCEPTION (ev);
+
+	/* compare the content */
+	for (j = 0; j < TESTSIZE; j++) {
+		Bonobo_Stream_read (stream, 4, &obuf, ev);
+		NO_EXCEPTION (ev);
+		g_assert (buf->_length == 4); 
+		g_assert (*((gint32 *)obuf->_buffer) == j); 
+		CORBA_free (obuf);
+	}
+
+	/* close the file */
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+
+	/* try to open a deleted file */
+	stream = Bonobo_Storage_openStream (storage, "test1.txt",
+					    Bonobo_Storage_READ, ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotFound);
+	
+	/* open an existing file */
+	stream = Bonobo_Storage_openStream (storage, "test5.txt",
+					    Bonobo_Storage_READ, ev);
+	NO_EXCEPTION (ev);
+
+	CORBA_exception_free (ev);
+
+	printf ("end basic tests\n");
+}
+
+static void
+compressed_io_tests (CORBA_Object storage, CORBA_Environment *ev)
+{
+	CORBA_Object stream;
+	Bonobo_Stream_iobuf *buf, *obuf;
+	gint32 i, j;
+
+	printf ("starting compressed IO tests\n");
+
+	buf = Bonobo_Stream_iobuf__alloc ();
+	buf->_buffer = (gpointer)&i;
+	buf->_length = 4;
+
+	/* create a compressed file */
+	stream = Bonobo_Storage_openStream (storage, "test2.txt",
+					    Bonobo_Storage_CREATE |
+					    Bonobo_Storage_COMPRESSED, 
+					    ev);
+	NO_EXCEPTION (ev);
+     
+	/* write test data */
+	for (j = 0; j < TESTSIZE; j++) {
+		i = j/8;
+		Bonobo_Stream_write (stream, buf, ev);
+		NO_EXCEPTION (ev);
+	}
+
+	/* maybe we can´t seek writable compressed files */
+	j = Bonobo_Stream_seek (stream, 0, Bonobo_Stream_SEEK_SET, ev);
+	if (BONOBO_EX(ev))
+		CHECK_EXCEPTION (ev, ex_Bonobo_Stream_NotSupported);
+
+	/* close the file */
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+
+	/* open the file again*/
+	stream = Bonobo_Storage_openStream (storage, "test2.txt",
+					    Bonobo_Storage_READ, ev);
+	NO_EXCEPTION (ev);
+
+	/* compare the content */
+	for (j = 0; j < TESTSIZE; j++) {
+		Bonobo_Stream_read (stream, 4, &obuf, ev);
+		NO_EXCEPTION (ev);
+		g_assert (buf->_length == 4);
+		g_assert (*((gint32 *)obuf->_buffer) == (j/8)); 
+		CORBA_free (obuf);
+	}
+
+	/* seek to start */
+	j = Bonobo_Stream_seek (stream, 0, Bonobo_Stream_SEEK_SET, ev);
+	NO_EXCEPTION (ev);
+	g_assert (j == 0);
+
+	/* compare the content again*/
+	for (j = 0; j < TESTSIZE; j++) {
+		Bonobo_Stream_read (stream, 4, &obuf, ev);
+		NO_EXCEPTION (ev);
+		g_assert (buf->_length == 4);
+		g_assert (*((gint32 *)obuf->_buffer) == (j/8)); 
+		CORBA_free (obuf);
+	}
+
+	/* close the file */
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+
+	CORBA_exception_free (ev);
+
+	printf ("end compressed IO tests\n");
+}
+
+static void
+dir_tests (CORBA_Object storage, CORBA_Environment *ev)
+{
+	CORBA_Object dir1, dir2;
+	gchar buf[1024];
+	gint i;
+
+	printf ("starting directory tests\n");
+
+	/* try to open non existent directory */
+	dir2 = Bonobo_Storage_openStorage (storage, "testdir",
+					   Bonobo_Storage_READ, ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotFound);
+	
+	/* create a directory */
+	dir1 = Bonobo_Storage_openStorage (storage, "testdir",
+					   Bonobo_Storage_CREATE, ev);
+	NO_EXCEPTION (ev);
+	
+	/* close the directory */
+	bonobo_object_release_unref (dir1, ev);
+	NO_EXCEPTION (ev);
+	
+	/* try to open non existent directory */
+	dir2 = Bonobo_Storage_openStorage (storage, "testdir/a",
+					   Bonobo_Storage_READ, ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotFound);
+
+	/* create some directories */
+	for (i = 0; i < 200; i++) {
+		sprintf (buf,"testdir/testdir%d", i);
+		dir2 = Bonobo_Storage_openStorage (storage, buf,
+						   Bonobo_Storage_CREATE, ev);
+		NO_EXCEPTION (ev);
+     		bonobo_object_release_unref (dir2, ev);
+		NO_EXCEPTION (ev);
+	}
+
+	/* erase some directories */
+	for (i = 0; i < 100; i++) {
+		sprintf (buf,"testdir/testdir%d", i);
+		Bonobo_Storage_erase (storage, buf, ev);
+		NO_EXCEPTION (ev);
+	}
+	
+	/* try to erase a non empty directory */
+	Bonobo_Storage_erase (storage, "testdir", ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotEmpty);
+
+	/* rename the directory */
+	Bonobo_Storage_rename (storage, "testdir", "testdir2", ev);
+	NO_EXCEPTION (ev);
+	
+	/* try to remove non existent directories */
+	for (i = 0; i < 100; i++) {
+		sprintf (buf,"testdir2/testdir%d", i);
+		Bonobo_Storage_erase (storage, buf, ev);
+		CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotFound);
+	}
+	
+	/* erase more directories */
+	for (i = 100; i < 200; i++) {
+		sprintf (buf,"testdir2/testdir%d", i);
+		Bonobo_Storage_erase (storage, buf, ev);
+		NO_EXCEPTION (ev);
+	}
+	
+	/* try to erase an empty directory */
+	Bonobo_Storage_erase (storage, "testdir2", ev);
+	NO_EXCEPTION (ev);
+
+	CORBA_exception_free (ev);
+
+	printf ("end directorty tests\n");
+}
+
+static void
+mime_tests (CORBA_Object storage, CORBA_Environment *ev)
+{
+	Bonobo_StorageInfo *setinfo, *getinfo;
+	CORBA_Object stream;
+
+	printf ("starting mime-type tests\n");
+
+	setinfo = Bonobo_StorageInfo__alloc ();
+
+	/* read the content type */
+	getinfo = Bonobo_Storage_getInfo (storage, "", 
+					  Bonobo_FIELD_CONTENT_TYPE, ev);
+	NO_EXCEPTION (ev);
+	g_assert (!strcmp(getinfo->content_type, "x-directory/normal"));
+	CORBA_free (getinfo);
+
+	/* set the content type */
+	setinfo->content_type = "text/plain";
+	Bonobo_Storage_setInfo (storage, "", setinfo, 
+				Bonobo_FIELD_CONTENT_TYPE, ev);
+	NO_EXCEPTION (ev);
+
+	/* read the content type */
+	getinfo = Bonobo_Storage_getInfo (storage, "", 
+					  Bonobo_FIELD_CONTENT_TYPE, ev);
+	NO_EXCEPTION (ev);
+	g_assert (!strcmp(getinfo->content_type, "text/plain"));
+	CORBA_free (getinfo);
+
+	/* create a new file */
+	stream = Bonobo_Storage_openStream (storage, "mimetest.txt",
+					    Bonobo_Storage_CREATE, ev);
+	NO_EXCEPTION (ev);
+
+	/* read the content type */
+	getinfo = Bonobo_Storage_getInfo (storage, "mimetest.txt", 
+					  Bonobo_FIELD_CONTENT_TYPE, ev);
+	NO_EXCEPTION (ev);
+	g_assert (!strcmp(getinfo->content_type, "application/octet-stream"));
+	CORBA_free (getinfo);
+
+	/* close the file */
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+
+	/* try to set the content type of a non existent file*/
+	setinfo->content_type = "text/xxx-plain";
+	Bonobo_Storage_setInfo (storage, "mi.txt", setinfo, 
+				Bonobo_FIELD_CONTENT_TYPE, ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotFound);
+
+	/* set the content type */
+	setinfo->content_type = "text/xxx-plain";
+	Bonobo_Storage_setInfo (storage, "mimetest.txt", setinfo, 
+				Bonobo_FIELD_CONTENT_TYPE, ev);
+	NO_EXCEPTION (ev);
+
+	/* try to read the content type of a non existent file */
+	getinfo = Bonobo_Storage_getInfo (storage, "mi.txt", 
+					  Bonobo_FIELD_CONTENT_TYPE, ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Storage_NotFound);
+	
+	/* read the content type */
+	getinfo = Bonobo_Storage_getInfo (storage, "mimetest.txt", 
+					  Bonobo_FIELD_CONTENT_TYPE, ev);
+	NO_EXCEPTION (ev);
+	g_assert (!strcmp(getinfo->content_type, "text/xxx-plain"));
+	CORBA_free (getinfo);
+
+	/* open the file */
+	stream = Bonobo_Storage_openStream (storage, "mimetest.txt",
+					    Bonobo_Storage_WRITE, ev);
+	NO_EXCEPTION (ev);
+
+	/* read the content type */
+	getinfo = Bonobo_Stream_getInfo (stream, Bonobo_FIELD_CONTENT_TYPE, 
+					 ev);
+	NO_EXCEPTION (ev);
+	g_assert (!strcmp(getinfo->content_type, "text/xxx-plain"));
+	CORBA_free (getinfo);
+	
+	/* set the content type */
+	setinfo->content_type = "text/xxx-yyy";
+	Bonobo_Stream_setInfo (stream, setinfo, 
+			       Bonobo_FIELD_CONTENT_TYPE, ev);
+	NO_EXCEPTION (ev);
+
+	/* read the content type */
+	getinfo = Bonobo_Stream_getInfo (stream, Bonobo_FIELD_CONTENT_TYPE, 
+					 ev);
+	NO_EXCEPTION (ev);
+	g_assert (!strcmp(getinfo->content_type, "text/xxx-yyy"));
+	CORBA_free (getinfo);
+	
+	/* close the file */
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+
+	/* open the file read only */
+	stream = Bonobo_Storage_openStream (storage, "mimetest.txt",
+					    Bonobo_Storage_READ, ev);
+	NO_EXCEPTION (ev);
+
+	/* try to set the content type on a read only file  */
+	setinfo->content_type = "text/xxx-yyy";
+	Bonobo_Stream_setInfo (stream, setinfo, 
+			       Bonobo_FIELD_CONTENT_TYPE, ev);
+	CHECK_EXCEPTION (ev, ex_Bonobo_Stream_NoPermission);	
+
+	/* close the file */
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+
+	CORBA_exception_free (ev);
+
+	printf ("end mime-type tests\n");
+}
+
+static void
+stream_copy_tests (CORBA_Object storage, CORBA_Environment *ev)
+{
+	CORBA_Object stream;
+	Bonobo_StorageInfo *setinfo, *getinfo;
+	Bonobo_Stream_iobuf *buf, *obuf;
+	gint32 i, j;
+	CORBA_long bread, bwritten;
+
+	printf ("starting copy tests\n");
+
+	setinfo = Bonobo_StorageInfo__alloc ();
+
+	buf = Bonobo_Stream_iobuf__alloc ();
+	buf->_buffer = (gpointer)&i;
+	buf->_length = 4;
+
+	/* create a new file */
+	stream = Bonobo_Storage_openStream (storage, "copy1.txt",
+					    Bonobo_Storage_CREATE, ev);
+	NO_EXCEPTION (ev);
+
+	/* set the content type */
+	setinfo->content_type = "text/plain";
+	Bonobo_Stream_setInfo (stream, setinfo, 
+			       Bonobo_FIELD_CONTENT_TYPE, ev);
+	NO_EXCEPTION (ev);
+
+	/* check the content type */
+	getinfo = Bonobo_Stream_getInfo (stream, Bonobo_FIELD_CONTENT_TYPE, 
+					 ev);
+	NO_EXCEPTION (ev);
+	g_assert (!strcmp(getinfo->content_type, "text/plain"));
+	CORBA_free (getinfo);
+
+	/* write test data */
+	for (i = 0; i < TESTSIZE; i++) {
+		Bonobo_Stream_write (stream, buf, ev);
+		NO_EXCEPTION (ev);
+	}
+	
+	/* seek to start of file */
+	Bonobo_Stream_seek (stream, 0, Bonobo_Stream_SEEK_SET, ev);
+	NO_EXCEPTION (ev);
+
+	/* copy the whole file */
+	Bonobo_Stream_copyTo (stream, "copy2.txt", -1, &bread, &bwritten, ev);
+	NO_EXCEPTION (ev);
+	
+	g_assert (bread == (TESTSIZE*4));
+	g_assert (bwritten == (TESTSIZE*4));
+
+	/* close the file */
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+
+	/* open the copied file */
+	stream = Bonobo_Storage_openStream (storage, "copy2.txt",
+					    Bonobo_Storage_READ, ev);
+	NO_EXCEPTION (ev);
+
+	/* compare the content */
+	for (j = 0; j < TESTSIZE; j++) {
+		Bonobo_Stream_read (stream, 4, &obuf, ev);
+		NO_EXCEPTION (ev);
+		g_assert (buf->_length == 4); 
+		g_assert (*((gint32 *)obuf->_buffer) == j); 
+		CORBA_free (obuf);
+	}
+
+	/* check the content type */
+	getinfo = Bonobo_Stream_getInfo (stream, Bonobo_FIELD_CONTENT_TYPE, 
+					 ev);
+	NO_EXCEPTION (ev);
+	g_assert (!strcmp(getinfo->content_type, "text/plain"));
+	CORBA_free (getinfo);
+
+	/* close the file */
+	bonobo_object_release_unref (stream, ev);
+	NO_EXCEPTION (ev);
+
+	CORBA_exception_free (ev);
+
+	printf ("end copy tests\n");
+}
+
+int
+main (int argc, char *argv [])
+{
+	BonoboStorage *bonobo_storage1, *bonobo_storage2;
+	CORBA_Environment ev;
+	CORBA_Object storage1, storage2;
+	gchar *driver_list[] = { "efs", "fs", NULL };
+	gchar *driver;
+	gint dn = 0;
+
+	CORBA_exception_init (&ev);
+
+	
+        gnome_init_with_popt_table ("MyShell", "1.0",
+				    argc, argv,
+				    oaf_popt_options, 0, NULL); 
+	orb = oaf_init (argc, argv);
+	
+	if (bonobo_init (orb, NULL, NULL) == FALSE)
+		g_error (_("Can not bonobo_init"));
+
+	while ((driver = driver_list [dn++])) {
+		printf ("TEST DRIVER: %s\n", driver);
+		
+		system ("rm -rf /tmp/storagetest.dir1");
+		system ("rm -rf /tmp/storagetest.dir2");
+		
+		CORBA_exception_free (&ev); 
+		
+		bonobo_storage1 = bonobo_storage_open_full 
+			(driver, "/tmp/storagetest.dir1", 
+			 Bonobo_Storage_WRITE | 
+			 Bonobo_Storage_CREATE, 0664, &ev);
+		NO_EXCEPTION (&ev);
+
+		storage1 = BONOBO_OBJECT(bonobo_storage1)->corba_objref;
+		g_assert (storage1 != NULL);
+  
+		basic_io_tests (storage1, &ev);
+		compressed_io_tests (storage1, &ev);
+		dir_tests (storage1, &ev);
+
+		if (strcmp (driver, "fs")) { /* fs driver does not work */ 
+			mime_tests (storage1, &ev);
+			stream_copy_tests (storage1, &ev);
+
+			Bonobo_Storage_commit (storage1, &ev);
+			NO_EXCEPTION (&ev);
+
+			bonobo_storage2 = bonobo_storage_open_full 
+				(driver, "/tmp/storagetest.dir2", 
+				 Bonobo_Storage_WRITE | 
+				 Bonobo_Storage_CREATE, 0664, &ev);
+			NO_EXCEPTION (&ev);
+
+			storage2 = BONOBO_OBJECT(bonobo_storage2)->corba_objref;
+			g_assert (storage2 != NULL);
+
+			bonobo_storage_copy_to (storage1, storage2, &ev);
+			NO_EXCEPTION (&ev);
+
+			Bonobo_Storage_commit (storage2, &ev);
+			NO_EXCEPTION (&ev);
+		
+			bonobo_object_unref (BONOBO_OBJECT(bonobo_storage2));
+		}
+
+		bonobo_object_unref (BONOBO_OBJECT(bonobo_storage1));
+
+	}
+
+	CORBA_exception_free (&ev);
+   
+	return 0;
+}
diff --git a/tools/.cvsignore b/tools/.cvsignore
new file mode 100644
index 0000000..d37e842
--- /dev/null
+++ b/tools/.cvsignore
@@ -0,0 +1,3 @@
+Makefile.in
+Makefile
+gnome-maketypes.awk
diff --git a/tools/ChangeLog b/tools/ChangeLog
new file mode 100644
index 0000000..18c2bda
--- /dev/null
+++ b/tools/ChangeLog
@@ -0,0 +1,21 @@
+2001-04-11  Martin Baulig  <baulig suse de>
+
+	* gnome-maketypes.awk.in: Do some renaming magic to have types
+	called `GDK_TYPE_*', `GTK_TYPE_*' and `GNOME_TYPES_*'.
+
+	* gnome-makeenums.pl, gnome-maketypes.awk.in: Use gobject here;
+	removed all references to GTK+.
+
+2001-03-24  Martin Baulig  <baulig suse de>
+
+	* gnome-maketypes.awk.in: Allow `#f' for the boxed-init func;
+	use #f or #f for boxed-is-refcounted.
+
+2001-03-21  Martin Baulig  <baulig suse de>
+
+	* gnome-makeenums.pl: New file. This was formerly known
+	as gnome-libs/libgnomeui/makeenums.pl.
+
+	* gnome-maketypes.awk.in: New file. This was formerly
+	known as gnome-libs/libgnomeui/maketypes.awk.
+
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..c66a4ac
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,9 @@
+bin_SCRIPTS = \
+	gnome-maketypes.awk		\
+	gnome-makeenums.pl
+
+EXTRA_DIST = \
+	$(bin_SCRIPTS)
+
+
+
diff --git a/tools/gnome-makeenums.pl b/tools/gnome-makeenums.pl
new file mode 100755
index 0000000..8564550
--- /dev/null
+++ b/tools/gnome-makeenums.pl
@@ -0,0 +1,231 @@
+#!/usr/bin/perl -w
+
+# This script snarfs the enums from header files and writes them out into
+# a .defs file (gnome.defs, for example). From there, the sister script
+# maketypes.awk converts the defs into a *typebuiltins.h, as well as
+# *typebuiltins_vals.c, *typebuiltins_ids.c and *typebuiltins_evals.c.
+
+# Information about the current enumeration
+
+my $flags;			# Is enumeration a bitmask
+my $seenbitshift;			# Have we seen bitshift operators?
+my $prefix;			# Prefix for this enumeration
+my $enumname;			# Name for this enumeration
+my $firstenum = 1;		# Is this the first enumeration in file?
+my @entries;			# [ $name, $val ] for each entry
+
+sub parse_options {
+    my $opts = shift;
+    my @opts;
+
+    for $opt (split /\s*,\s*/, $opts) {
+	my ($key,$val) = $opt =~ /\s*(\w+)(?:=(\S+))?/;
+	defined $val or $val = 1;
+	push @opts, $key, $val;
+    }
+    @opts;
+}
+sub parse_entries {
+    my $file = shift;
+
+    while (<$file>) {
+	# Read lines until we have no open comments
+
+	while (m@/\*
+	       ([^*]|\*(?!/))*$
+	       @x) {
+	    my $new;
+	    defined ($new = <$file>) || die "Unmatched comment";
+	    $_ .= $new;
+	}
+
+	# Now strip comments
+	s@/\*(?!<)
+	    ([^*]+|\*(?!/))*
+	   \*/@@gx;
+	
+	s \n@ @;
+	
+	next if m ^\s*$@;
+
+	# Handle include files
+	if (/^\#include\s*<([^>]*)>/ ) {
+            my $file= "../$1";
+	    open NEWFILE, $file or next;
+#die "Cannot open include file $file: $!\n";
+	    
+	    if (parse_entries (\*NEWFILE)) {
+		return 1;
+	    } else {
+		next;
+	    }
+	}
+	
+	if (/^\s*\}\s*(\w+)/) {
+	    $enumname = $1;
+	    return 1;
+	}
+
+	if (m ^\s*
+              (\w+)\s*		         # name
+              (?:=(                      # value
+                   (?:[^,/]|/(?!\*))*
+                  ))?,?\s*
+              (?:/\*<		         # options 
+                (([^*]|\*(?!/))*)
+               >\*/)?
+              \s*$
+             @x) {
+	    my ($name, $value, $options) = ($1,$2,$3);
+
+	    if (!defined $flags && defined $value && $value =~ /<</) {
+		$seenbitshift = 1;
+	    }
+	    if (defined $options) {
+		my %options = parse_options($options);
+		if (!defined $options{skip}) {
+		    push @entries, [ $name, $options{nick} ];
+		}
+	    } else {
+		push @entries, [ $name ];
+	    }
+	} else {
+#	    print STDERR "Can't understand: $_\n";
+	}
+    }
+    return 0;
+}
+
+
+my $gen_arrays = 0;
+my $gen_defs = 0;
+
+# Parse arguments
+
+if (@ARGV) {
+    if ($ARGV[0] eq "arrays") {
+	shift @ARGV;
+	$gen_arrays = 1;
+    } elsif ($ARGV[0] eq "defs") {
+	shift @ARGV;
+	$gen_defs = 1;
+    } else {
+	$gen_defs = 1;
+    }
+    
+}
+
+if ($gen_defs) {
+    print ";; generated by makeenums.pl  ; -*- scheme -*-\n\n";
+} else {
+    print "/* Generated by makeenums.pl */\n\n";
+}
+
+ENUMERATION:
+for ($filecounter = 0; $filecounter < scalar @ARGV; $filecounter++) {
+  $afile = $ARGV[$filecounter];
+  open(STDIN, $afile);
+  $startsize = scalar @ARGV;
+
+  while ($amainline = <STDIN>) {
+    if (eof || $amainline =~ /\sDEPRECATED/) {
+      $firstenum = 1;		# Flag to print filename at next enum
+      last;
+    }
+    
+    if ($amainline =~ m ^\s*typedef\s+enum\s*({)?\s*(?:/\*<(([^*]|\*(?!/))*)>\*/)? x) {
+      if (defined $2) {
+	my  %options = parse_options($2);
+	$prefix	     = $options{prefix};
+	$flags	     = $options{flags};
+      } else {
+	$prefix	     = undef;
+	$flags	     = undef;
+      }
+      # Didn't have trailing '{' look on next lines
+      if (!defined $1) {
+	while (<STDIN>) {
+	  if (s/^\s*\{//) {
+	    last;
+	  }
+	}
+      }
+      
+      $seenbitshift = 0;
+      @entries = ();
+      $entry = undef;
+      $enumname = undef;
+
+      # Now parse the entries
+      parse_entries (\*STDIN);
+
+      if(! $enumname) { next; }
+      
+      # figure out if this was a flags or enums enumeration
+      
+      if (!defined $flags) {
+	$flags	     = $seenbitshift;
+      }
+      
+      # Autogenerate a prefix
+      
+      if (!defined $prefix) {
+	for	     (@entries) {
+	  my $name = $_->[0];
+	  if (defined $prefix) {
+	    my $tmp = ~ ($name ^ $prefix);
+	    ($tmp) = $tmp =~ /(^\xff*)/;
+	    $prefix = $prefix & $tmp;
+	  } else {
+	    $prefix = $name;
+	  }
+	}
+	#	     Trim so that it ends in an underscore
+	$prefix	     =~ s/_[^_]*$/_/;
+      }
+      
+      for $entry (@entries) {
+	my	     ($name,$nick) = @{$entry};
+	if	     (!defined $nick) {
+	  ($nick = $name) =~ s/^$prefix//;
+	  $nick =~ tr/_/-/;
+	  $nick = lc($nick);
+	  @{$entry} = ($name, $nick);
+	}
+      }
+      
+      # Spit out the output
+      
+      if ($gen_defs) {
+	if	     ($firstenum) {
+	  print qq(\n; enumerations from "$afile"\n);
+	  $firstenum = 0;
+	}
+	
+	print	     "\n(define-".($flags ? "flags" : "enum")." $enumname";
+	
+	for	     (@entries) {
+	  my ($name,$nick) = @{$_};
+	  print "\n   ($nick $name)";
+	}
+	print	     ")\n";
+	
+      } else {
+	($valuename  = $enumname) =~ s/([A-Z][a-z])/_$1/g;
+	$valuename   =~ s/([a-z])([A-Z])/$1_$2/g;
+	$valuename   = lc($valuename);
+	
+	print	     "static const GEnumValue $ {valuename}_values[] = {\n";
+	for	     (@entries) {
+	  my ($name,$nick) = @{$_};
+	  print qq(  { $name, "$name", "$nick" },\n);
+	}
+	print	     "  { 0, NULL, NULL }\n";
+	print	     "};\n";
+      }
+    }
+  }
+  $endsize = scalar @ARGV;
+  $endsize == $startsize || die("$endsize != $startsize");
+  close (STDIN);		# reset line numbering
+}
diff --git a/tools/gnome-maketypes.awk.in b/tools/gnome-maketypes.awk.in
new file mode 100644
index 0000000..b5605a4
--- /dev/null
+++ b/tools/gnome-maketypes.awk.in
@@ -0,0 +1,167 @@
+#! @AWK@ -f
+
+BEGIN {
+  type_name = "";	# GtkEnumType
+  type_macro = "";	# G_TYPE_ENUM
+  type_ident = "";	# _g_enum_type
+  type_counter = 0;
+  gen_macros = 0;
+  gen_entries = 0;
+  gen_vars = 0;
+  boxed_init = "";
+  boxed_copy = "";
+  boxed_free = "";
+  is_refcounted = "";
+  
+  for (i = 2; i < ARGC; i++)
+    {
+      if (ARGV[i] == "macros")
+	gen_macros = 1;
+      else if (ARGV[i] == "entries")
+	gen_entries = 1;
+      else if (ARGV[i] == "variables")
+	gen_vars = 1;
+      ARGV[i] = "";
+    }
+  
+  if (gen_macros)
+    printf ("/* type macros, generated by maketypes.awk */\n");
+  else if (gen_entries)
+    printf ("/* type entries, generated by maketypes.awk */\n\n");
+  else if (gen_vars)
+    printf ("/* type variables, generated by maketypes.awk */\n\n");
+  else
+    {
+      printf ("hm? what do you want me to do?\n") > "/dev/stderr";
+      exit 1;
+    }
+}
+
+function set_type (set_type_1)
+{
+  type_counter += 1;
+  type_name = set_type_1;
+  type_macro = "G_TYPE_";
+  
+  tmp = type_name;
+# OK, the following is ridiculous, and sed s///g would be far easier
+  gsub ("[A-Z]", "@&", tmp);
+  gsub ("[^A-Z]@", "&_", tmp);
+  gsub ("@", "", tmp);
+  gsub ("[A-Z][A-Z][A-Z][0-9a-z]", "@&", tmp);
+  gsub ("@..", "&_", tmp);
+  gsub ("@", "", tmp);
+  type_macro = type_macro toupper (tmp);
+  type_ident = "_" tolower (tmp);
+
+  sub ("^G_TYPE_GTK_", "GTK_TYPE_", type_macro);
+  sub ("^G_TYPE_GDK_", "GDK_TYPE_", type_macro);
+  sub ("^G_TYPE_GNOME_", "GNOME_TYPE_", type_macro);
+}
+
+function generate (generate_what)
+{
+  if (gen_macros)
+    {
+      printf ("extern GType %s;\n", type_macro);
+    }
+  if (gen_entries)
+    {
+      printf ("  { \"%s\", &%s,\n", type_name, type_macro);
+      if (generate_what == "BOXED")
+	printf ("    G_TYPE_%s, %s, %s, %s, %s },\n", generate_what, boxed_init, boxed_copy, boxed_free, is_refcounted);
+      else
+	printf ("    G_TYPE_%s, %s_values },\n", generate_what, type_ident);
+    }
+  if (gen_vars)
+    {
+      printf ("GType %s = 0;\n", type_macro);
+    }
+}
+
+# skip scheme comments
+";" {
+  sub (";.*", "");
+}
+
+# parse keywords
+
+/\(define-enum/ {
+  if ($2 == "")
+    printf ("huh? define-enum keyword without arg?\n") > "/dev/stderr";
+  else
+    {
+      set_type($2);
+      generate("ENUM");
+    }
+}
+
+/\(define-flags/ {
+  if ($2 == "")
+    printf ("huh? define-flags keyword without arg?\n") > "/dev/stderr";
+  else
+    {
+      set_type($2);
+      generate("FLAGS");
+    }
+}
+
+/\(define-boxed/ {
+  if ($2 == "")
+    printf ("huh? define-boxed keyword without arg?\n") > "/dev/stderr";
+  else
+      {
+	  boxed_init = "NULL";
+	  boxed_copy = "NULL";
+	  boxed_free = "NULL";
+	  is_refcounted = "FALSE";
+	  set_type($2);
+	  do {
+	      getline;
+	      sub (";.*", "", $0);
+	  } while ($0 ~ /^[ \t]*$/);
+	  tmp_var1 = $1;
+	  if ($0 ~ /\)/) { generate("BOXED"); next; }
+	  do {
+	      getline;
+	      sub (";.*", "", $0);
+	  } while ($0 ~ /^[ \t]*$/);
+	  tmp_var2 = $1;
+	  if ($0 ~ /\)/) { generate("BOXED"); next; }
+	  do {
+	      getline;
+	      sub (";.*", "", $0);
+	  } while ($0 ~ /^[ \t]*$/);
+	  tmp_var3 = $1;
+	  if ($0 ~ /\)/) { generate("BOXED"); next; }
+	  do {
+	      getline;
+	      sub (";.*", "", $0);
+	  } while ($0 ~ /^[ \t]*$/);
+	  tmp_var4 = $1;
+	  sub ("\).*", "", tmp_var4);
+	  if (tmp_var1 ~ /^(\#[fF])|([_A-Za-z][_A-Za-z0-9]*)$/ &&
+	      tmp_var2 ~ /^[_A-Za-z][_A-Za-z0-9]*$/ &&
+	      tmp_var3 ~ /^[_A-Za-z][_A-Za-z0-9]*$/ &&
+	      tmp_var4 ~ /^(\#[tfTF])$/)
+	      {
+		  if (tmp_var1 ~ /^(\#[fF])$/)
+		     boxed_init = "NULL";
+		  else
+		     boxed_init = tmp_var1;
+		  boxed_copy = tmp_var2;
+		  boxed_free = tmp_var3;
+		  if (tmp_var4 ~ /^(\#[tT])$/)
+		     is_refcounted = "TRUE";
+		  else
+		     is_refcounted = "FALSE";
+		  # printf ("read boxed funcs: %s %s %s\n", boxed_init, boxed_copy, boxed_free) > "/dev/stderr";
+	      }
+	  generate("BOXED");
+      }
+}
+
+END {
+  if (gen_macros)
+    printf("\n#define\tGNOME_TYPE_NUM_BUILTINS\t(%u)\n", type_counter);
+}



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