Incorporate upstream changes to v1.6.8.

Squash upstream commits up to and including the v1.6.8
release (upstream commit 1cad15cc).

This repository's changes from upstream are now limited to:

- addition of Android.mk, CleanSpec.mk, config.h, and NOTICE
  files
- addition of dbus/dbus-arch-deps.h and removal from
  dbus/.gitignore (ebae2d21, f022f55d)
- WANT_PIDFILE #ifdefs added to bus/bus.c to disable writing
  dbus-daemon's PID to a file (3100d06a)
- TRACE_LOCKS set to 0 in dbus/dbus-connection.c (88a0ffe5)
- DBUS_ANDROID_LOG added to dbus/dbus-internals.c to use
  logcat (7de15def)
- ANDROID_MANAGED_SOCKET added to dbus/dbus-sysdeps-unix.c
  to use an SELinux-managed socket rather than a
  dbus-daemon-created Unix domain socket (3100d06a)

Bug: 22328216
Change-Id: I793ebdf963d9b0740f0da28f1de593d088f08406
diff --git a/.gitignore b/.gitignore
index 2936342..db3db97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,12 +9,15 @@
 config.status
 config.sub
 configure
+cscope.out
 depcomp
 *.pc
 install-sh
 libtool
 ltmain.sh
 missing
+/m4/lt*.m4
+/m4/libtool.m4
 stamp-h1
 stamp-h
 stamp-h.in
@@ -30,4 +33,11 @@
 *.bbg
 *.da
 *.gcov
+*.gcda
+*.gcno
 tags
+/dbus-1.*/
+/dbus-1.*.tar.*
+/lcov.html/
+/lcov.info
+/lcov.info.tmp
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000..4f386b9
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,10 @@
+Benjamin Reed <rangerrick@befunk.com> Benjamin Reed <ranger@befunk.com>
+Benjamin Reed <rangerrick@befunk.com> Benjamin Reed <ranger@Sin.local>
+Christian Dywan <christian.dywan@lanedo.com> Christian Dywan <christian@lanedo.com>
+Colin Walters <walters@verbum.org> Colin Walters <walters@lightbox.localdomain>
+Colin Walters <walters@verbum.org> Colin Walters <walters@space-ghost.verbum.private>
+Havoc Pennington <hp@pobox.com> Havoc Pennington <hp@localhost.localdomain>
+Ralf Habacker <ralf.habacker@freenet.de> Ralf Habacker <Ralf.Habacker@freenet.de>
+Ralf Habacker <ralf.habacker@freenet.de> Ralf Habacker <ralf@s15291359.onlinehome-server.info>
+Ralf Habacker <ralf.habacker@freenet.de> unknown <Administrator@.(none)>
+Ralf Habacker <ralf.habacker@freenet.de> unknown <Habacker@.(none)>
diff --git a/AUTHORS b/AUTHORS
index c8fd0cc..ed8afdf 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,18 +1,20 @@
+Alban Crequy <alban.crequy@collabora.co.uk>
 Alexander Larsson <alexl@redhat.com>
 Anders Carlsson <andersca@codefactory.se>
+Andre Heinecke <aheinecke@intevation.de>
 Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
 Aurelien Jarno <aurel32@debian.org>
-Benjamin Reed <ranger@befunk.com>
 Benjamin Reed <rangerrick@befunk.com>
-Benjamin Reed <ranger@Sin.local>
+Brian Cameron <brian.cameron@oracle.com>
 Brian Cameron <brian.cameron@sun.com>
+Chris Mayo <aklhfex gmail com>
 Christian Dywan <christian.dywan@lanedo.com>
 Christian Ehrlicher <Ch.Ehrlicher@gmx.de>
 Christian Persch (GNOME) <chpe@gnome.org>
-Colin Walters <walters@lightbox.localdomain>
-Colin Walters <walters@space-ghost.verbum.private>
 Colin Walters <walters@verbum.org>
 Colin Watson <cjwatson@ubuntu.com>
+Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+Cristian Rodríguez <cristian.rodriguez@opensuse.org>
 Cyril Brulebois <kibi@debian.org>
 Daniel P. Berrange <dan@berrange.com>
 Daniel Reed <djr@redhat.com>
@@ -28,7 +30,6 @@
 Harald Fernengel <harry@kdevelop.org>
 Harri Porten <porten@kde.org>
 Hasso Tepper <hasso@estpak.ee>
-Havoc Pennington <hp@localhost.localdomain>
 Havoc Pennington <hp@pobox.com>
 Havoc Pennington <hp@redhat.com>
 Hendrik Buschmeier <hbuschme@TechFak.Uni-Bielefeld.DE>
@@ -37,6 +38,7 @@
 James Willcox <jwillcox@gnome.org>
 Jens Granseuer <jensgr@gmx.net>
 Jérémie Dimino <jeremie@dimino.org>
+Jiří Klimeš <jklimes@redhat.com>
 Joe Marcus Clarke <marcus@freedesktop.org>
 Joe Shaw <joeshaw@novell.com>
 Johan Gyllenspetz <johangy@axis.com>
@@ -44,6 +46,7 @@
 John (J5) Palmieri <johnp@redhat.com>
 Jon Gosting <yukarionsen@gmail.com>
 Jon Trowbridge <trow@ximian.com>
+Kay Sievers <kay.sievers@vrfy.org>
 Kimmo Hämäläinen <kimmo.hamalainen@nokia.com>
 Kjartan Maraas <kmaraas@gnome.org>
 Kristian Høgsberg <krh@redhat.com>
@@ -57,6 +60,7 @@
 Marc Brockschmidt <he@debian.org>
 Marc Mutz <marc@kdab.net>
 Marcus Brinkmann <marcus.brinkmann@ruhr-uni-bochum.de>
+Mark Brand <mabrand@mabrand.nl>
 Mark McLoughlin <mark@skynet.ie>
 Matthias Clasen <mclasen@redhat.com>
 Matt McCutchen <matt@mattmccutchen.net>
@@ -64,6 +68,7 @@
 Michael Meeks <michael@ximian.com>
 Mikael Hallendal <micke@codefactory.se>
 Mikael Hallendal <micke@imendio.com>
+Mike McQuaid <mike@mikemcquaid.com>
 Miloslav Trmac <mitr@volny.cz>
 Murray Cumming <murrayc@murrayc.com>
 Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
@@ -72,6 +77,7 @@
 Oswald Buddenhagen <ossi@kde.org>
 Owen Fraser-Green <owen@discobabe.net>
 Patrick von Reth <patrick.vonreth@gmail.com>
+Pau Garcia i Quiles <pgquiles@elpauer.org>
 Paul Bolle <pebolle@tiscali.nl>
 Peter Breitenlohner <peb@mppmu.mpg.de>
 Peter Kümmel <syntheticpp@gmx.net>
@@ -79,16 +85,17 @@
 Philip Blundell <philb@gnu.org>
 Plácido Revilla <unknown@unknown.domain>
 Ralf Habacker <ralf.habacker@freenet.de>
-Ralf Habacker <Ralf.Habacker@freenet.de>
-Ralf Habacker <ralf@s15291359.onlinehome-server.info>
 Ray Strode <rstrode@redhat.com>
+Richard A. Hankins <richard.a.hankins@gmail.com>
 Richard Hughes <richard@hughsie.com>
 Richard Hult <rhult@codefactory.se>
 Richard Hult <richard@imendio.com>
 Robert McQueen <robot101@debian.org>
+Roberto Guido <bob4job@gmail.com>
 Romain Pokrzywka <romain@kdab.com>
 Ross Burton <ross@openedhand.com>
 Ryan Lortie <desrt@desrt.ca>
+Sascha Silbe <sascha-pgp@silbe.org>
 Sascha Silbe <sascha-web-bugs.freedesktop.org@silbe.org>
 Scott James Remnant <scott@netsplit.com>
 Scott James Remnant <scott@ubuntu.com>
@@ -96,6 +103,9 @@
 Seth Nickell <seth@gnome.org>
 Simon McVittie <simon.mcvittie@collabora.co.uk>
 Sjoerd Simons <sjoerd@luon.net>
+Sledz <sledz@MOBIL-400-586.intern.dresearch.de>
+Steve Grubb <sgrubb@redhat.com>
+Sven Herzberg <sven@imendio.com>
 Thiago Macieira <thiago@kde.org>
 Tim Dijkstra <tim@famdijkstra.org>
 Tobias Mueller <fdo-bugs@cryptobitch.de>
@@ -103,10 +113,10 @@
 Tomas Pelka <tpelka@redhat.com>
 Tom Hughes <tom.hughes@palm.com>
 Tor Lillqvist <tml@iki.fi>
-unknown <Administrator@.(none)>
-unknown <Habacker@.(none)>
 Waldo Bastian <bastian@kde.org>
 William Lachance <wrlach@gmail.com>
 Will Thompson <will.thompson@collabora.co.uk>
+Wulf C. Krueger <philantrop@exherbo.org>
 Xan Lopez <xan@gnome.org>
+Yaakov Selkowitz <yselkowitz@users.sourceforge.net>
 Zack Rusin <zack@kde.org>
diff --git a/Doxyfile.in b/Doxyfile.in
index 80ee0d0..afac639 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -133,7 +133,7 @@
 #---------------------------------------------------------------------------
 # configuration options related to the XML output
 #---------------------------------------------------------------------------
-GENERATE_XML           = NO
+GENERATE_XML           = YES
 #---------------------------------------------------------------------------
 # Configuration options related to the preprocessor   
 #---------------------------------------------------------------------------
diff --git a/HACKING b/HACKING
index 873e025..805fd2e 100644
--- a/HACKING
+++ b/HACKING
@@ -152,17 +152,17 @@
  - verify that the libtool versioning/library soname is 
    changed if it needs to be, or not changed if not
 
- - update the file NEWS based on the ChangeLog
+ - update the file NEWS based on the git history
 
- - update the AUTHORS file based on the ChangeLog
+ - verify that the version number of dbus-specification.xml is
+   changed if it needs to be; if changes have been made, update the
+   release date in that file
 
- - add a ChangeLog entry containing the version number 
-   you're releasing ("Released 0.3" or something)
-   so people can see which changes were before and after
-   a given release
+ - update the AUTHORS file with "make update-authors" if necessary
 
- - the version number should have major.minor.micro even
-   if micro is 0, i.e. "1.0.0" and "1.2.0" not "1.0"/"1.2"
+ - the version number should have major.minor.micro, even
+   if micro is 0, i.e. "1.0.0" and "1.2.0" not "1.0"/"1.2"; the micro
+   version should be even for releases, and odd for intermediate snapshots
 
  - "make distcheck" (DO NOT just "make dist" - pass the check!)
 
@@ -176,14 +176,15 @@
    then simply created an unsigned annotated tag:
    "git tag -a -m 'Released X.Y.Z' dbus-X.Y.Z".
 
- - bump the version number up in configure.in, and commit
-   it.  Make sure you do this *after* tagging the previous
+ - bump the version number up in configure.ac (so the micro version is odd),
+   and commit it.  Make sure you do this *after* tagging the previous
    release! The idea is that git has a newer version number
-   than anything released.
+   than anything released. Similarly, bump the version number of
+   dbus-specification.xml and set the release date to "(not finalized)".
 
  - merge the branch you've released to the chronologically-later
    branch (usually "master"). You'll probably have to fix a merge
-   conflict in configure.in (the version number).
+   conflict in configure.ac (the version number).
 
  - push your changes and the tag to the central repository with
      git push origin master dbus-X.Y dbus-X.Y.Z
@@ -192,6 +193,8 @@
    dbus.freedesktop.org:/srv/dbus.freedesktop.org/www/releases/dbus/dbus-X.Y.Z.tar.gz.
    This should be possible if you're in group "dbus"
 
+ - Update the online documentation with `make -C doc maintainer-upload-docs`.
+
  - update the wiki page http://www.freedesktop.org/Software/dbus by
    adding the new release under the Download heading. Then, cut the
    link and changelog for the previous that was there.
@@ -205,32 +208,27 @@
  - post to dbus@lists.freedesktop.org announcing the release.
  
 
-After making a ".0" stable release
+Making a ".0" stable release
 ===
 
-After releasing, when you increment the version number in git, also
-move the ChangeLog to ChangeLog.pre-X-Y where X-Y is what you just
-released, e.g. ChangeLog.pre-1-0. Then create and cvs add a new empty
-ChangeLog. The last entry in ChangeLog.pre-1-0 should be the one about
-"Released 1.0". 
+We create a branch for each stable release. The branch name should be
+dbus-X.Y which is a branch that has releases versioned X.Y.Z;
+changes on a stable branch should be limited to significant bug fixes.
 
-Add ChangeLog.pre-X-Y to EXTRA_DIST in Makefile.am.
+Because we won't make minor changes like keeping up with the latest
+deprecations on a stable branch, stable branches should turn off the
+gcc warning for deprecated declarations (e.g. see commit 4ebb275ab7).
 
-We create a branch for each stable release; sometimes the branch is
-not done immediately, instead it's possible to wait until someone has
-a not-suitable-for-stable change they want to make and then branch to
-allow committing that change.
-
-The branch name should be dbus-X.Y-branch which is a branch that has
-releases versioned X.Y.Z
+Be extra-careful not to merge master (or any branch based on master) into a
+stable branch.
 
 To branch:
-  git branch dbus-X.Y-branch
+  git branch dbus-X.Y
 and upload the branch tag to the server:
-  git-push origin dbus-X.Y-branch
+  git push origin dbus-X.Y
 
 To develop in this branch:
-  git-checkout dbus-X.Y-branch
+  git checkout dbus-X.Y
 
 Environment variables
 ===
@@ -287,10 +285,8 @@
 
 "make check" runs all the deterministic test programs (i.e. not break-loader).
 
-"make check-coverage" is available if you configure with --enable-gcov and 
-gives a complete report on test suite coverage. You can also run 
-"test/decode-gcov foo.c" on any source file to get annotated source, 
-after running make check with a gcov-enabled tree.
+"make lcov-check" is available if you configure with --enable-compiler-coverage
+and gives a complete report on test suite coverage.
 
 Patches
 ===
@@ -310,6 +306,20 @@
  - if there's a live unresolved controversy about a change,
    don't commit it while the argument is still raging.
 
+ - at their discretion, members of the reviewer group may also commit
+   branches/patches under these conditions:
+
+   - the branch does not add or change API, ABI or wire-protocol
+
+   - the branch solves a known problem and is covered by the regression tests
+
+   - there are no objections from the rest of the review group within
+     a week of the patches being attached to Bugzilla
+
+   - the committer gets a positive review on Bugzilla from someone they
+     consider qualified to review the change (e.g. a colleague with D-Bus
+     experience; not necessarily a member of the reviewer group)
+
  - regardless of reviews, to commit a patch:
     - make check must pass
     - the test suite must be extended to cover the new code
@@ -338,5 +348,4 @@
 Scott James Remnant <scott@netsplit.com>
 Will Thompson <will.thompson@collabora.co.uk>
 Simon McVittie <simon.mcvittie@collabora.co.uk>
-
-
+David Zeuthen <davidz@redhat.com>
diff --git a/Makefile.am b/Makefile.am
index d937dcf..10b9670 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,5 +1,4 @@
-SUBDIRS=dbus bus doc tools test
-DIST_SUBDIRS=dbus bus doc tools test
+SUBDIRS=dbus bus tools test doc
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = dbus-1.pc
@@ -15,52 +14,20 @@
         NEWS.pre-1-0            \
 	ChangeLog.pre-1-2       \
         NEWS.pre-1-2		\
-	README.windbus
+	README.win		\
+	README.wince		\
+	README.cygwin		\
+	README.launchd		\
+	cmake
 
 all-local: Doxyfile
 
-if DBUS_GCOV_ENABLED
-clean-gcov:
-	find -name "*.da" -o -name "*.gcov" | xargs rm || true
-
-clean-bbg:
-	find -name "*.bbg" -o -name "*.bb" | xargs rm || true
-
-GCOV_DIRS=dbus bus
-
-## .PHONY so it always rebuilds it
-.PHONY: coverage-report.txt
-coverage-report.txt:
-	BBG_FILES=`find $(GCOV_DIRS) -name "*.bbg" -o -name "*.gcno"` ;			\
-	C_FILES= ;									\
-	for F in $$BBG_FILES ; do							\
-		F_nolibs=`echo $$F | sed -e 's/.libs\///g'` ;				\
-		C=`echo $$F_nolibs | sed -e 's/.bbg/.c/g' | sed -e 's/.gcno/.c/g'`  ;	\
-		B=`basename $$F .bbg` ;							\
-		D=`dirname $$F` ;							\
-		DA=`echo $$F | sed -e 's/.bbg/.da/g'` ;					\
-		DA_libs=`echo $$D/.libs/$$B/.da` ;					\
-		if test -e $$DA || test -e $$DA_libs; then				\
-			C_FILES="$$C_FILES $$C" ;					\
-		fi ;									\
-	done ;										\
-	echo $$C_FILES ;								\
-	$(top_builddir)/test/decode-gcov --report $$C_FILES > coverage-report.txt
-
-check-coverage: clean-gcov all check coverage-report.txt
-	cat coverage-report.txt
-
-else
-coverage-report.txt:
-	echo "Need to reconfigure with --enable-gcov"
-
-check-coverage:
-	echo "Need to reconfigure with --enable-gcov"
-
-endif
-
 update-authors:
 	git shortlog -s -e | cut -c 8- | sort > AUTHORS
 
 DISTCHECK_CONFIGURE_FLAGS = \
 	--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
+
+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
+
+include tools/lcov.am
diff --git a/NEWS b/NEWS
index c4b46de..02fa145 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,582 @@
+D-Bus 1.6.8 (2012-09-28)
+==
+
+The "Fix one thing, break another" release.
+
+• Follow up to CVE-2012-3524: The additional hardening
+  work to use __secure_getenv() as a followup to bug #52202
+  broke certain configurations of gnome-keyring.  Given
+  the difficulty of making this work without extensive
+  changes to gnome-keyring, use of __secure_getenv() is
+  deferred.
+
+D-Bus 1.6.6 (2012-09-28)
+==
+
+The "Clear the environment in your setuid binaries, please" release.
+
+• CVE-2012-3524: Don't access environment variables (fd.o #52202)
+  Thanks to work and input from Colin Walters, Simon McVittie,
+  Geoffrey Thomas, and others.
+• Unix-specific:
+  · Fix compilation on Solaris (fd.o #53286, Jonathan Perkin)
+  · Work around interdependent headers on OpenBSD by including sys/types.h
+    before each use of sys/socket.h (fd.o #54418, Brad Smith)
+
+D-Bus 1.6.4 (2012-07-18)
+==
+
+• Detect that users are "at the console" correctly when configured with
+  a non-default path such as --enable-console-auth-dir=/run/console
+  (fd.o #51521, Dave Reisner)
+
+• Remove an incorrect assertion from DBusTransport (fd.o #51657,
+  Simon McVittie)
+
+• Make --enable-developer default to "no" (regression in 1.6.2;
+  fd.o #51657, Simon McVittie)
+
+• Windows-specific:
+  · Launch dbus-daemon correctly if its path contains a space
+    (fd.o #49450, Wolfgang Baron)
+
+D-Bus 1.6.2 (2012-06-27)
+==
+
+The "Ice Cabbage" release.
+
+• Change how we create /var/lib/dbus so it works under Automake >= 1.11.4
+  (fd.o #51406, Simon McVittie)
+
+• Don't return from dbus_pending_call_set_notify with a lock held on OOM
+  (fd.o #51032, Simon McVittie)
+
+• Disconnect "developer mode" (assertions, verbose mode etc.) from
+  Automake maintainer mode. D-Bus developers should now configure with
+  --enable-developer. Automake maintainer mode is now on by default;
+  distributions can disable it with --disable-maintainer-mode.
+  (fd.o #34671, Simon McVittie)
+
+• Automatically define DBUS_STATIC_BUILD in static-only Autotools builds,
+  fixing linking when targeting Windows (fd.o #33973; william, Simon McVittie)
+
+• Unix-specific:
+  · Check for libpthread under CMake on Unix (fd.o #47237, Simon McVittie)
+
+D-Bus 1.6.0 (2012-06-05)
+==
+
+The “soul of this machine has improved” release.
+
+This version starts a new stable branch of D-Bus: only bug fixes will
+be accepted into 1.6.x. Other changes will now go to the 1.7.x branch.
+
+Summary of changes since 1.4.x:
+
+• New requirements
+  · PTHREAD_MUTEX_RECURSIVE on Unix
+  · compiler support for 64-bit integers (int64_t or equivalent)
+
+• D-Bus Specification v0.19
+
+• New dbus-daemon features
+  · <allow own_prefix="com.example.Service"/> rules allow the service to
+    own names like com.example.Service.Instance3
+  · optional systemd integration when checking at_console policies
+  · --nopidfile option, mainly for use by systemd
+  · path_namespace and arg0namespace may appear in match rules
+  · eavesdropping is disabled unless the match rule contains eavesdrop=true
+
+• New public API
+  · functions to validate various string types (dbus_validate_path() etc.)
+  · dbus_type_is_valid()
+  · DBusBasicValue, a union of every basic type
+
+• Bug fixes
+  · removed an unsafe reimplementation of recursive mutexes
+  · dbus-daemon no longer busy-loops if it has far too many file descriptors
+  · dbus-daemon.exe --print-address works on Windows
+  · all the other bug fixes from 1.4.20
+
+• Other major implementation changes
+  · on Linux, dbus-daemon uses epoll if supported, for better scalability
+  · dbus_threads_init() ignores its argument and behaves like
+    dbus_threads_init_default() instead
+  · removed the per-connection link cache, improving dbus-daemon performance
+
+• Developer features
+  · optional Valgrind instrumentation (--with-valgrind)
+  · optional Stats interface on the dbus-daemon (--enable-stats)
+  · optionally abort whenever malloc() fails (--enable-embedded-tests
+    and export DBUS_MALLOC_CANNOT_FAIL=1)
+
+Changes since 1.5.12:
+
+• Be more careful about monotonic time vs. real time, fixing DBUS_COOKIE_SHA1
+  spec-compliance (fd.o #48580, David Zeuthen)
+
+• Don't use install(1) within the source/build trees, fixing the build as
+  non-root when using OpenBSD install(1) (fd.o #48217, Antoine Jacoutot)
+
+• Add missing commas in some tcp and nonce-tcp addresses, and remove
+  an unused duplicate copy of the nonce-tcp transport in Windows builds
+  (fd.o #45896, Simon McVittie)
+
+D-Bus 1.5.12 (2012-03-27)
+==
+
+The “Big Book of Science” release.
+
+• Add public API to validate various string types:
+  dbus_validate_path(), dbus_validate_interface(), dbus_validate_member(),
+  dbus_validate_error_name(), dbus_validate_bus_name(), dbus_validate_utf8()
+  (fd.o #39549, Simon McVittie)
+
+• Turn DBusBasicValue into public API so bindings don't need to invent their
+  own "union of everything" type (fd.o #11191, Simon McVittie)
+
+• Enumerate data files included in the build rather than using find(1)
+  (fd.o #33840, Simon McVittie)
+
+• Add support for policy rules like <allow own_prefix="com.example.Service"/>
+  in dbus-daemon (fd.o #46273, Alban Crequy)
+
+• Windows-specific:
+  · make dbus-daemon.exe --print-address (and --print-pid) work again
+    on Win32, but not on WinCE (fd.o #46049, Simon McVittie)
+  · fix duplicate case value when compiling against mingw-w64
+    (fd.o #47321, Andoni Morales Alastruey)
+
+D-Bus 1.5.10 (2012-02-21)
+==
+
+The "fire in Delerium" release.
+
+On Unix platforms, PTHREAD_MUTEX_RECURSIVE (as specified in POSIX 2008 Base
+and SUSv2) is now required.
+
+• D-Bus Specification 0.19:
+  · Formally define unique connection names and well-known bus names,
+    and document best practices for interface, bus, member and error names,
+    and object paths (fd.o #37095, Simon McVittie)
+  · Document the search path for session and system services on Unix, and
+    where they should be installed by build systems (fd.o #21620, fd.o #35306;
+    Simon McVittie)
+  · Document the systemd transport (fd.o #35232, Lennart Poettering)
+
+• Make dbus_threads_init() use the same built-in threading implementation
+  as dbus_threads_init_default(); the user-specified primitives that it
+  takes as a parameter are now ignored (fd.o #43744, Simon McVittie)
+
+• Allow all configured auth mechanisms, not just one (fd.o #45106,
+  Pavel Strashkin)
+
+• Improve cmake build system (Ralf Habacker):
+  · simplify XML parser dependencies (fd.o #41027)
+  · generate build timestamp (fd.o #41029)
+  · only create batch files on Windows
+  · fix option and cache syntax
+  · add help-options target
+  · share dbus-arch-deps.h.in with autotools rather than having our
+    own version (fd.o #41033)
+
+• Build tests successfully with older GLib, as found in e.g. Debian 6
+  (fd.o #41219, Simon McVittie)
+
+• Avoid use of deprecated GThread API (fd.o #44413, Martin Pitt)
+
+• Build documentation correctly if man2html doesn't support filenames on
+  its command-line (fd.o #43875, Jack Nagel)
+
+• Improve test coverage. To get even more coverage, run the tests with
+  DBUS_TEST_SLOW=1 (fd.o #38285, #42811; Simon McVittie)
+
+• Reduce the size of the shared library by moving functionality only used
+  by dbus-daemon, tests etc. into their internal library and deleting
+  unused code (fd.o #34976, #39759; Simon McVittie)
+
+• Add dbus-daemon --nopidfile option, overriding the configuration, for
+  setups where the default configuration must include <pidfile/> to avoid
+  breaking traditional init, but the pid file is in fact unnecessary; use
+  it under systemd to improve startup time a bit (fd.o #45520,
+  Lennart Poettering)
+
+• Optionally (if configured --with-valgrind) add instrumentation to debug
+  libdbus and associated tools more meaningfully under Valgrind
+  (fd.o #37286, Simon McVittie)
+
+• Improve the dbus-send(1) man page (fd.o #14005, Simon McVittie)
+
+• Make dbus-protocol.h compatible with C++11 (fd.o #46147, Marc Mutz)
+
+• If tests are enabled and DBUS_MALLOC_CANNOT_FAIL is set in the environment,
+  abort on failure to malloc() (like GLib does), to turn runaway memory leaks
+  into a debuggable core-dump if a resource limit is applied (fd.o #41048,
+  Simon McVittie)
+
+• Don't crash if realloc() returns NULL in a debug build (fd.o #41048,
+  Simon McVittie)
+
+• Unix-specific:
+  · Replace our broken reimplementation of recursive mutexes, which has
+    been broken since 2006, with an ordinary pthreads recursive mutex
+    (fd.o #43744; Sigmund Augdal, Simon McVittie)
+  · Use epoll(7) for a more efficient main loop in Linux; equivalent patches
+    welcomed for other OSs' equivalents like kqueue, /dev/poll, or Solaris
+    event ports (fd.o #33337; Simon McVittie, Ralf Habacker)
+  · When running under systemd, use it instead of ConsoleKit to check
+    whether to apply at_console policies (fd.o #39609, Lennart Poettering)
+  · Avoid a highly unlikely fd leak (fd.o #29881, Simon McVittie)
+  · Don't close invalid fd -1 if getaddrinfo fails (fd.o #37258, eXeC001er)
+  · Don't touch ~/.dbus and ~/.dbus-keyrings when running 'make installcheck'
+    (fd.o #41218, Simon McVittie)
+  · Stop pretending we respect XDG_DATA_DIRS for system services: the launch
+    helper doesn't obey environment variables to avoid privilege escalation
+    attacks, so make the system bus follow the same rules
+    (fd.o #21620, Simon McVittie)
+
+• Windows-specific:
+  · Find the dbus-daemon executable next to the shared library (fd.o #41558;
+    Jesper Dam, Ralf Habacker)
+  · Remove the faulty implementation of _dbus_condvar_wake_all (fd.o #44609,
+    Simon McVittie)
+
+D-Bus 1.5.8 (2011-09-21)
+==
+
+The "cross-metering" release.
+
+In addition to dead code removal and refactoring, this release contains all
+of the bugfixes from 1.4.16.
+
+• Clean up dead code, and make more warnings fatal in development builds
+  (fd.o #39231, fd.o #41012; Simon McVittie)
+
+• If full test coverage is requested via --enable-tests, strictly require
+  Python, pygobject and dbus-python, which are required by some tests; if not,
+  and Python is missing, skip those tests rather than failing
+  (fd.o #37847, Simon McVittie)
+
+• When using cmake, provide the same version-info API in the installed headers
+  as for autotools (DBUS_VERSION, etc.) (fd.o #40905, Ralf Habacker)
+
+• Add a regression test for fd.o #38005 (fd.o #39836, Simon McVittie)
+
+• Make "NOCONFIGURE=1 ./autogen.sh" not run configure (Colin Walters)
+
+• Add _DBUS_STATIC_ASSERT and use it to check invariants (fd.o #39636,
+  Simon McVittie)
+
+• Fix duplicates in authors list (Ralf Habacker)
+
+• Fix broken links from dbus-tutorial.html if $(htmldir) != $(docdir)
+  (fd.o #39879, Chris Mayo)
+
+• Fix a small memory leak, and a failure to report errors, when updating
+  a service file entry for activation (fd.o #39230, Simon McVittie)
+
+• Unix-specific:
+  · Clean up (non-abstract) Unix sockets on bus daemon exit (fd.o #38656;
+    Brian Cameron, Simon McVittie)
+  · On systems that use libcap-ng but not systemd, drop supplemental groups
+    when switching to the daemon user (Red Hat #726953, Steve Grubb)
+  · Make the cmake build work again on GNU platforms (fd.o #29228,
+    Simon McVittie)
+  · Fix compilation on non-C99 systems that have inttypes.h but not stdint.h,
+    like Solaris (fd.o #40313, Dagobert Michelsen)
+  · Define CMSG_ALIGN, CMSG_LEN, CMSG_SPACE on Solaris < 10
+    (fd.o #40235, Simon McVittie)
+  · Cope with Unixes that don't have LOG_PERROR, like Solaris 10
+    (fd.o #39987, Simon McVittie)
+  · Cope with platforms whose vsnprintf violates both POSIX and C99, like
+    Tru64, IRIX and HP-UX (fd.o #11668, Simon McVittie)
+
+• Windows-specific:
+  · Fix compilation on MSVC, which doesn't understand "inline" with its
+    C99 meaning (fd.o #40000; Ralf Habacker, Simon McVittie)
+  · Fix misuse of GPid in test/dbus-daemon.c (fd.o #40003, Simon McVittie)
+  · Fix cross-compilation to Windows with Automake (fd.o #40003, Simon McVittie)
+
+D-Bus 1.5.6 (2011-07-29)
+==
+
+The "weird, gravy-like aftertaste" release.
+
+In addition to new features and refactoring, this release contains all of the
+bugfixes from 1.4.14.
+
+Potentially incompatible (Bustle and similar debugging tools will need
+changes to work as intended):
+
+• Do not allow match rules to "eavesdrop" (receive messages intended for a
+  different recipient) by mistake: eavesdroppers must now opt-in to this
+  behaviour by putting "eavesdrop='true'" in the match rule, which will
+  not have any practical effect on buses where eavesdropping is not allowed
+  (fd.o #37890, Cosimo Alfarano)
+
+Other changes:
+
+• D-Bus Specification version 0.18 (fd.o #37890, fd.o #39450, fd.o #38252;
+  Cosimo Alfarano, Simon McVittie)
+  · add the "eavesdrop" keyword to match rules
+  · define eavesdropping, unicast messages and broadcast messages
+  · stop claiming that match rules are needed to match unicast messages to you
+  · promote the type system to be a top-level section
+
+• Use DBUS_ERROR_OBJECT_PATH_IN_USE if dbus_connection_try_register_object_path
+  or dbus_connection_try_register_fallback fails, not ...ADDRESS_IN_USE,
+  and simplify object-path registration (fd.o #38874, Jiří Klimeš)
+
+• Consistently use atomic operations on everything that is ever manipulated
+  via atomic ops, as was done for changes to DBusConnection's refcount in
+  1.4.12 (fd.o #38005, Simon McVittie)
+
+• Fix a file descriptor leak when connecting to a TCP socket (fd.o #37258,
+  Simon McVittie)
+
+• Make "make check" in a clean tree work, by not running tests until
+  test data has been set up (fd.o #34405, Simon McVittie)
+
+• The dbus-daemon no longer busy-loops if it has a very large number of file
+  descriptors (fd.o #23194, Simon McVittie)
+
+• Refactor message flow through dispatching to avoid locking violations if
+  the bus daemon's message limit is hit; remove the per-connection link cache,
+  which was meant to improve performance, but now reduces it (fd.o #34393,
+  Simon McVittie)
+
+• Some cmake fixes (Ralf Habacker)
+
+• Remove dead code, mainly from DBusString (fd.o #38570, fd.o #39610;
+  Simon McVittie, Lennart Poettering)
+
+• Stop storing two extra byte order indicators in each D-Bus message
+  (fd.o #38287, Simon McVittie)
+
+• Add an optional Stats interface which can be used to get statistics from
+  a running dbus-daemon if enabled at configure time with --enable-stats
+  (fd.o #34040, Simon McVittie)
+
+• Fix various typos (fd.o #27227, fd.o #38284; Sascha Silbe, Simon McVittie)
+
+• Documentation (fd.o #36156, Simon McVittie):
+  · let xsltproc be overridden as usual: ./configure XSLTPROC=myxsltproc
+  · install more documentation automatically, including man2html output
+  · put dbus.devhelp in the right place (it must go in ${htmldir})
+
+• Unix-specific:
+  · look for system services in /lib/dbus-1/system-services in addition to all
+    the other well-known locations; note that this should always be /lib,
+    even on platforms where shared libraries on the root FS would go in /lib64,
+    /lib/x86_64-linux-gnu or similar (fd.o #35229, Lennart Poettering)
+  · opt-in to fd passing on Solaris (fd.o #33465, Simon McVittie)
+
+• Windows-specific (Ralf Habacker):
+  · fix use of a mutex for autolaunch server detection
+  · don't crash on malloc failure in _dbus_printf_string_upper_bound
+
+D-Bus 1.5.4 (2011-06-10)
+==
+
+Security (local denial of service):
+
+• Byte-swap foreign-endian messages correctly, preventing a long-standing
+  local DoS if foreign-endian messages are relayed through the dbus-daemon
+  (backporters: this is git commit c3223ba6c401ba81df1305851312a47c485e6cd7)
+  (CVE-2011-2200, fd.o #38120, Debian #629938; Simon McVittie)
+
+New things:
+
+• The constant to use for an infinite timeout now has a name,
+  DBUS_TIMEOUT_INFINITE. It is numerically equivalent to 0x7fffffff (INT32_MAX)
+  which can be used for source compatibility with older versions of libdbus.
+
+• If GLib and DBus-GLib are already installed, more tests will be built,
+  providing better coverage. The new tests can also be installed via
+      ./configure --enable-installed-tests
+  for system integration testing, if required. (fd.o #34570, Simon McVittie)
+
+Changes:
+
+• Consistently use atomic operations for the DBusConnection's refcount,
+  fixing potential threading problems (fd.o #38005, Simon McVittie)
+
+• Don't use -Wl,--gc-sections by default: in practice the size decrease is
+  small (300KiB on x86-64) and it frequently doesn't work in unusual
+  toolchains. To optimize for minimum installed size, you should benchmark
+  various possibilities for CFLAGS and LDFLAGS, and set the best flags for
+  your particular toolchain at configure time. (fd.o #33466, Simon McVittie)
+
+• Use #!/bin/sh for run-with-tmp-session-bus.sh, making it work on *BSD
+  (fd.o #35880, Timothy Redaelli)
+
+• Use ln -fs to set up dbus for systemd, which should fix reinstallation
+  when not using a DESTDIR (fd.o #37870, Simon McVittie)
+
+• Windows-specific changes:
+  · don't try to build dbus-daemon-launch-helper (fd.o #37838, Mark Brand)
+
+D-Bus 1.5.2 (2011-06-01)
+==
+
+The "Boar Hunter" release.
+
+Notes for distributors:
+
+  This version of D-Bus no longer uses -fPIE by default. Distributions wishing
+  to harden the dbus-daemon and dbus-launch-helper can re-enable this if their
+  toolchain supports it reliably, via something like:
+
+    ./configure CFLAGS=-fPIE LDFLAGS="-pie -Wl,-z,relro"
+
+  or by using distribution-specific wrappers such as Debian's hardening-wrapper.
+
+Changes:
+
+  • D-Bus Specification v0.17
+    · Reserve the extra characters used in signatures by GVariant
+      (fd.o #34529, Simon McVittie)
+    · Define the ObjectManager interface (fd.o #34869, David Zeuthen)
+  • Don't force -fPIE: distributions and libtool know better than we do whether
+    it's desirable (fd.o #16621, fd.o #27215; Simon McVittie)
+  • Allow --disable-gc-sections, in case your toolchain offers the
+    -ffunction-sections, -fdata-sections and -Wl,--gc-sections options
+    but they're broken, as seen on Solaris (fd.o #33466, Simon McVittie)
+  • Install dbus-daemon and dbus-daemon-launch-helper in a more normal way
+    (fd.o #14512; Simon McVittie, loosely based on a patch from Luca Barbato)
+  • Ensure that maintainers upload documentation with the right permissions
+    (fd.o #36130, Simon McVittie)
+  • Don't force users of libdbus to be linked against -lpthread, -lrt
+    (fd.o #32827, Simon McVittie)
+  • Log system-bus activation information to syslog (fd.o #35705,
+    Colin Walters)
+  • Log messages dropped due to quotas to syslog (fd.o #35358,
+    Simon McVittie)
+  • Make the nonce-tcp transport work on Unix (fd.o #34569, Simon McVittie)
+  • On Unix, if /var/lib/dbus/machine-id cannot be read, try /etc/machine-id
+    (fd.o #35228, Lennart Poettering)
+  • In the regression tests, don't report fds as "leaked" if they were open
+    on startup (fd.o #35173, Simon McVittie)
+  • Make dbus-monitor bail out if asked to monitor more than one bus,
+    rather than silently using the last one (fd.o #26548, Will Thompson)
+  • Clarify documentation (fd.o #35182, Simon McVittie)
+  • Clean up minor dead code and some incorrect error handling
+    (fd.o #33128, fd.o #29881; Simon McVittie)
+  • Check that compiler options are supported before using them (fd.o #19681,
+    Simon McVittie)
+  • Windows:
+    • Remove obsolete workaround for winioctl.h (fd.o #35083, Ralf Habacker)
+
+D-Bus 1.5.0 (2011-04-11)
+==
+
+The "you never know when you need to tow something from your giant
+flying shark" release.
+
+  • D-Bus Specification v0.16
+    · Add support for path_namespace and arg0namespace in match rules
+      (fd.o #24317, #34870; Will Thompson, David Zeuthen, Simon McVittie)
+    · Make argNpath support object paths, not just object-path-like strings,
+      and document it better (fd.o #31818, Will Thompson)
+  • Let the bus daemon implement more than one interface (fd.o #33757,
+    Simon McVittie)
+  • Optimize _dbus_string_replace_len to reduce waste (fd.o #21261,
+    Roberto Guido)
+  • Require user intervention to compile with missing 64-bit support
+    (fd.o #35114, Simon McVittie)
+  • Add dbus_type_is_valid as public API (fd.o #20496, Simon McVittie)
+  • Raise UnknownObject instead of UnknownMethod for calls to methods on
+    paths that are not part of the object tree, and UnknownInterface for calls
+    to unknown interfaces in the bus daemon (fd.o #34527, Lennart Poettering)
+
+D-Bus 1.4.8 (2011-04-08)
+==
+
+The "It's like the beginning of a lobster" release.
+
+  • Rename configure.in to configure.ac, and update it to modern conventions
+    (fd.o #32245; Javier Jardón, Simon McVittie)
+  • Correctly give XDG_DATA_HOME priority over XDG_DATA_DIRS (fd.o #34496,
+    Anders Kaseorg)
+  • Prevent X11 autolaunching if $DISPLAY is unset or empty, and add
+    --disable-x11-autolaunch configure option to prevent it altogether
+    in embedded environments (fd.o #19997, NB#219964; Simon McVittie)
+  • Install the documentation, and an index for Devhelp (fd.o #13495,
+    Debian #454142; Simon McVittie, Matthias Clasen)
+  • If checks are not disabled, check validity of string-like types and
+    booleans when sending them (fd.o #16338, NB#223152; Simon McVittie)
+  • Add UnknownObject, UnknownInterface, UnknownProperty and PropertyReadOnly
+    errors to dbus-shared.h (fd.o #34527, Lennart Poettering)
+  • Break up a huge conditional in config-parser so gcov can produce coverage
+    data (fd.o #10887, Simon McVittie)
+  • List which parts of the Desktop Entry specification are applicable to
+    .service files (fd.o #19159, Sven Herzberg)
+  • Don't suppress service activation if two services have the same Exec=
+    (fd.o #35750, Colin Walters)
+  • Windows:
+    · Avoid the name ELEMENT_TYPE due to namespace-pollution from winioctl.h
+      (Andre Heinecke)
+    · Include _dbus_path_is_absolute in libdbus on Windows, fixing compilation
+      (fd.o #32805, Mark Brand)
+
+D-Bus 1.4.6 (2010-02-17)
+==
+
+The "1, 2, miss a few, 99, 100" release.
+
+  • Remove unfinished changes intended to support GTest-based tests,
+    which were mistakenly included in 1.4.4
+
+D-Bus 1.4.4 (2010-02-17)
+==
+
+  • Switch back to using even micro versions for stable releases; 1.4.1
+    should have been called 1.4.2, so skip that version number
+  • Don't leave bad file descriptors being watched when spawning processes,
+    which could result in a busy-loop (fd.o #32992, NB#200248; possibly
+    also LP#656134, LP#680444, LP#713157)
+  • Check for MSG_NOSIGNAL correctly
+  • Fix failure to detect abstract socket support (fd.o #29895)
+  • Make _dbus_system_logv actually exit with DBUS_SYSTEM_LOG_FATAL
+    (fd.o #32262, NB#180486)
+  • Improve some error code paths (fd.o #29981, fd.o #32264, fd.o #32262,
+    fd.o #33128, fd.o #33277, fd.o #33126, NB#180486)
+  • Avoid possible symlink attacks in /tmp during compilation (fd.o #32854)
+  • Tidy up dead code (fd.o #25306, fd.o #33128, fd.o #34292, NB#180486)
+  • Improve gcc malloc annotations (fd.o #32710)
+  • If the system bus is launched via systemd, protect it from the OOM killer
+  • Documentation improvements (fd.o #11190)
+  • Avoid readdir_r, which is difficult to use correctly (fd.o #8284,
+    fd.o #15922, LP#241619)
+  • Cope with invalid files in session.d, system.d (fd.o #19186,
+    Debian #230231)
+  • Don't distribute generated files that embed our builddir (fd.o #30285,
+    fd.o #34292)
+  • Raise the system bus's fd limit to be sufficient for its configuration
+    (fd.o #33474, LP#381063)
+  • Fix syslog string processing
+  • Ignore -Waddress
+  • Remove broken gcov parsing code and --enable-gcov, and replace them
+    with lcov HTML reports and --enable-compiler-coverage (fd.o #10887)
+  • Windows:
+    · avoid live-lock in Windows CE due to unfair condition variables
+  • OpenBSD:
+    · support credentials-passing (fd.o #32542)
+  • Solaris:
+    · opt-in to thread safety (fd.o #33464)
+
+D-Bus 1.4.1 (20 December 2010)
+==
+
+ • Fix for CVE-2010-4352: sending messages with excessively-nested variants can
+   crash the bus. The existing restriction to 64-levels of nesting previously
+   only applied to the static type signature; now it also applies to dynamic
+   nesting using variants. Thanks to Rémi Denis-Courmont for discoving this
+   issue.
+ • OS X portability fixes, including launchd support.
+ • Windows autolaunch improvements.
+ • Various bug fixes.
+
 D-Bus 1.4.0 (6 Sep 2010)
 ==
  - systemd hookup
diff --git a/README b/README
index 89bfaf7..fd832ca 100644
--- a/README
+++ b/README
@@ -66,62 +66,19 @@
 dbus could be build by using autotools or cmake. 
 
 When using autotools the configure step is initiated by running ./configure 
-with our without additional configuration flags. 
+with or without additional configuration flags. 
 
 When using cmake the configure step is initiated by running the cmake 
-program with our without additional configuration flags. 
+program with or without additional configuration flags. 
 
 Configuration flags
 ===
 
-When using autools the dbus-specific configuration flags that can be given to
-the ./configure program are these 
+When using autotools, run "./configure --help" to see the possible
+configuration options and environment variables.
 
-  --enable-tests             enable unit test code
-  --enable-verbose-mode      support verbose debug mode
-  --enable-asserts           include assertion checks
-  --enable-checks            include sanity checks on public API
-  --enable-xml-docs          build XML documentation (requires xmlto)
-  --enable-doxygen-docs      build DOXYGEN documentation (requires Doxygen)
-  --enable-gcov              compile with coverage profiling instrumentation (gcc only)
-  --enable-abstract-sockets  use abstract socket namespace (linux only)
-  --enable-selinux           build with SELinux support
-  --enable-dnotify           build with dnotify support (linux only)
-  --enable-kqueue            build with kqueue support (*BSD only)
-  --with-xml=libxml/expat           XML library to use
-  --with-init-scripts=redhat        Style of init scripts to install
-  --with-session-socket-dir=dirname Where to put sockets for the per-login-session message bus
-  --with-test-socket-dir=dirname    Where to put sockets for make check
-  --with-system-pid-file=pidfile    PID file for systemwide daemon
-  --with-system-socket=filename     UNIX domain socket for systemwide daemon
-  --with-console-auth-dir=dirname   directory to check for console ownerhip
-  --with-dbus-user=<user>           User for running the DBUS daemon (messagebus)
-  --with-gnu-ld                     assume the C compiler uses GNU ld [default=no]
-  --with-tags[=TAGS]                include additional configurations [automatic]
-  --with-x                          use the X Window System
-
-When using the cmake build system the dbus-specific configuration flags that can be given 
-to the cmake program are these (use -D<key>=<value> on command line)
-
-    CMAKE_BUILD_TYPE                   set dbus build mode - one of Debug|Release|RelWithDebInfo|MinSizeRel
-    DBUS_BUILD_TESTS                   enable unit test code  default=ON
-    DBUS_BUILD_X11                     Build X11-dependent code default=ON
-    HAVE_CONSOLE_OWNER_FILE            enable console owner file (solaris only) ) default=ON
-    DBUS_DISABLE_ASSERTS               Disable assertion checking default=OFF
-    DBUS_DISABLE_CHECKS                Disable public API sanity checking default=OFF
-    DBUS_ENABLE_ABSTRACT_SOCKETS       enable support for abstract sockets (linux only) default=ON
-    DBUS_ENABLE_ANSI                   enable -ansi -pedantic gcc flags default=OFF
-    DBUS_ENABLE_DNOTIFY                build with dnotify support (linux only) default=ON
-    DBUS_ENABLE_VERBOSE_MODE           support verbose debug mode default=ON
-    DBUS_ENABLE_DOXYGEN_DOCS           build DOXYGEN documentation (requires Doxygen) default=ON
-    DBUS_GCOV_ENABLED                  compile with coverage profiling instrumentation (gcc only) default=OFF
-    DBUS_INSTALL_SYSTEM_LIBS           install required system libraries default (windows only) =OFF
-    DBUS_USE_EXPAT                     Use expat (== ON) or libxml2 (==OFF) default=ON [1]
-    DBUS_USE_NONCE_TCP_DEFAULT_ADDRESS Use nonce tcp default address default=OFF
-    DBUS_USE_OUTPUT_DEBUG_STRING       enable win32 debug port for message output default=OFF
-    
-    [1] requires installed development package of the related dependency 
-
+When using cmake, inspect README.cmake to see the possible
+configuration options and environment variables.
     
 API/ABI Policy
 ===
@@ -183,3 +140,24 @@
 main D-Bus package, and have their own release cycles, levels of
 maturity, and ABI stability policies. Please consult the documentation
 for your binding.
+
+Bootstrapping D-Bus on new platforms
+===
+
+A full build of D-Bus, with all regression tests enabled and run, has some
+dependencies which themselves depend on D-Bus, either for compilation or
+for some of *their* regression tests: GLib, dbus-glib and dbus-python are
+currently affected.
+
+To avoid circular dependencies, when bootstrapping D-Bus for the first time
+on a new OS or CPU architecture, you can either cross-compile some of
+those components, or choose the build order and options carefully:
+
+* build and install D-Bus without tests
+  - do not use the --enable-modular-tests=yes configure option
+  - do not use the --enable-tests=yes configure option
+* build and install GLib, again without tests
+* use those versions of libdbus and GLib to build and install dbus-glib
+* ... and use those to install dbus-python
+* rebuild libdbus; this time you can run all of the tests
+* rebuild GLib; this time you can run all of the tests
diff --git a/README.cmake b/README.cmake
new file mode 100644
index 0000000..5feaf55
--- /dev/null
+++ b/README.cmake
@@ -0,0 +1,171 @@
+This file describes how to compile dbus using the cmake build system
+
+Requirements
+------------
+- cmake version >= 2.4.4 see http://www.cmake.org
+- installed libexpat see http://sourceforge.net/projects/expat/ 
+    unsupported RelWithDebInfo builds could be fetched 
+    from http://sourceforge.net/projects/kde-windows/files/expat/
+
+Building
+--------
+
+Win32 MinGW-w64|32
+1. install mingw-w64 from http://sourceforge.net/projects/mingw-w64/
+2. install cmake and libexpat
+3. get dbus sources
+4. unpack dbus sources into a sub directory (referred as <dbus-src-root> later)
+5. mkdir dbus-build
+6. cd dbus-build
+7. run 
+    cmake -G "MinGW Makefiles" [<options, see below>] <dbus-src-root>/cmake
+    mingw32-make
+    mingw32-make install
+
+Win32 Microsoft nmake
+1. install MSVC 2010 Express Version from http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express
+2. install cmake and libexpat
+3. get dbus sources
+4. unpack dbus sources into a sub directory (referred as <dbus-src-root> later)
+5. mkdir dbus-build
+6. cd dbus-build
+7. run 
+    cmake -G "NMake Makefiles" [<options, see below>] <dbus-src-root>/cmake
+    nmake
+    nmake install
+
+Win32 Visual Studio 2010 Express IDE
+1. install MSVC 2010 Express Version from http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express
+2. install cmake and libexpat
+3. get dbus sources
+4. unpack dbus sources into a sub directory (referred as <dbus-src-root> later)
+5. mkdir dbus-build
+6. cd dbus-build
+7. run
+      cmake -G "Visual Studio 10" [<options, see below>] <dbus-src-root>/cmake
+8a. open IDE with
+      vcexpress dbus.sln
+8b. for immediate build run
+      vcexpress dbus.sln /build
+
+Win32 Visual Studio 2010 Professional IDE
+1. install MSVC 2010 Professional Version
+2. install cmake and libexpat
+3. get dbus sources
+4. unpack dbus sources into a sub directory (referred as <dbus-src-root> later)
+5. mkdir dbus-build
+6. cd dbus-build
+7. run 
+      cmake -G "Visual Studio 10" [<options, see below>] <dbus-src-root>/cmake
+8a. open IDE with
+      devenv dbus.sln
+8b. for immediate build run
+      devenv dbus.sln /build
+
+Linux
+1. install cmake and libexpat
+2. get dbus sources
+3. unpack dbus sources into a sub directory (referred as <dbus-src-root> later)
+4. mkdir dbus-build
+5. cd dbus-build
+6. run 
+    cmake -G "<for available targets, see cmake --help for a list>" [<options, see below>] <dbus-src-root>/cmake
+    make
+    make install
+
+For other compilers see cmake --help in the Generators section
+
+Configuration flags
+-------------------
+
+When using the cmake build system the dbus-specific configuration flags that can be given 
+to the cmake program are these (use -D<key>=<value> on command line). The listed values 
+are the defaults.
+
+// Choose the type of build, options are: None(CMAKE_CXX_FLAGS or
+// CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.
+CMAKE_BUILD_TYPE:STRING=Debug
+
+// Include path for 3rdparty packages
+CMAKE_INCLUDE_PATH:PATH=
+
+// Library path for 3rdparty packages
+CMAKE_LIBRARY_PATH:PATH=
+
+// Install path prefix, prepended onto install directories.
+CMAKE_INSTALL_PREFIX:PATH=C:/Program Files/dbus
+
+
+// enable unit test code
+DBUS_BUILD_TESTS:BOOL=ON
+
+// The name of the dbus daemon executable
+DBUS_DAEMON_NAME:STRING=dbus-daemon
+
+// Disable assertion checking
+DBUS_DISABLE_ASSERTS:BOOL=OFF
+
+// Disable public API sanity checking
+DBUS_DISABLE_CHECKS:BOOL=OFF
+
+// enable -ansi -pedantic gcc flags
+DBUS_ENABLE_ANSI:BOOL=OFF
+
+// build DOXYGEN documentation (requires Doxygen)
+DBUS_ENABLE_DOXYGEN_DOCS:BOOL=OFF
+
+// enable bus daemon usage statistics
+DBUS_ENABLE_STATS:BOOL=OFF
+
+// support verbose debug mode
+DBUS_ENABLE_VERBOSE_MODE:BOOL=ON
+
+// build XML  documentation (requires xmlto or meinproc4)
+DBUS_ENABLE_XML_DOCS:BOOL=ON
+
+// Some atomic integer implementation present
+DBUS_HAVE_ATOMIC_INT:BOOL=OFF
+
+// install required system libraries
+DBUS_INSTALL_SYSTEM_LIBS:BOOL=OFF
+
+// session bus default address
+DBUS_SESSION_BUS_DEFAULT_ADDRESS:STRING=nonce-tcp:
+
+// system bus default address
+DBUS_SYSTEM_BUS_DEFAULT_ADDRESS:STRING=nonce-tcp:
+
+// Use atomic integer implementation for 486
+DBUS_USE_ATOMIC_INT_486:BOOL=OFF
+
+// Use expat (== ON) or libxml2 (==OFF)
+DBUS_USE_EXPAT:BOOL=ON
+
+win32 only:
+// enable win32 debug port for message output
+DBUS_USE_OUTPUT_DEBUG_STRING:BOOL=OFF
+
+gcc only:
+// compile with coverage profiling instrumentation
+DBUS_GCOV_ENABLED:BOOL=OFF
+
+linux only:
+// build with dnotify support 
+DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX:BOOL=ON
+
+solaris only:
+// enable console owner file 
+HAVE_CONSOLE_OWNER_FILE:BOOL=ON
+
+// Directory to check for console ownership
+DBUS_CONSOLE_OWNER_FILE:STRING=/dev/console
+
+x11 only:
+// Build with X11 auto launch support
+DBUS_BUILD_X11:BOOL=ON
+
+
+Note: The above mentioned options could be extracted after 
+configuring from the output of running "<maketool> help-options" 
+in the build directory. The related entries start with 
+CMAKE_ or DBUS_. 
diff --git a/README.cygwin b/README.cygwin
index 754b3e0..904cbb4 100755
--- a/README.cygwin
+++ b/README.cygwin
@@ -1,9 +1,6 @@
 The cygwin dbus port is included in master branch of
 dbus git repository since 1.3.1.
 
-See cygwin/README for more informations about
-the cygwin dbus port.
-
 The cygwin port of dbus is maintained by:
 
 http://sourceware.org/cygwinports/
diff --git a/README.dbus4win b/README.dbus4win
deleted file mode 100644
index 5a26fea..0000000
--- a/README.dbus4win
+++ /dev/null
@@ -1,67 +0,0 @@
-On 2009-10-21 I (Tor Lillqvist <tml@iki.fi>) cherry-picked a bunch of
-commits from the dbus4win-noncetcp branch of the dbus4win repository
-to (my clone of) dbus upstream's master branch.
-
-The dbus4win repository is at least currently at
-git://repo.or.cz/dbus4win.git
-
-I went through the commits done to the dbus4win-noncetcp branch since
-the dbus-1.2.14 tag, i.e. commit f719d454329a1a54ff2d569feaf10ceee7cead50.
-
-The following commits were left out because they either 0) were
-already upstream, 1) seemed broken, or 2) seemed pointless to me,
-especially if the commit message didn't say much. For each commit left
-out, below is three lines: its id, the first log comment line, and an
-explanation why I left it out.
-
-f719d454329a1a54ff2d569feaf10ceee7cead50
-configure.in: not all gccs support -Wno-pointer-sign
-already upstream
-
-6eddb6e1229b617ad44c8d61107983229dc7d589
-configure.in: fail abstract socket test gracefully when cross-compilin
-already upstream
-
-c54dd9eefa5ed0d54be3b09cf30c12f05130fda1
-r783: one ifdef lesser
-probably pointless
-
-93c288ca3e86e7760d3ac3fa6490257c1b6dc544
-r783: compile if ENOMEM or EINTR is undefined.
-huh, ENOMEM and EINTR is defined in the Microsoft C library
-
-4f4ba13357da15c35a9d4ad111bf972a5d0d5db0
-r783: introduced _dbus_daemon_release() function called in _dbus_loop_quit()...
-this can't be right, there can be nested dbus loops afaik
-
-124eb334324472a10de2c7e0a1455d353431f08f
-unix build fixes against windbus-svn
-can't be right to make a char* const when the code below then assigns through it
-
-594bd19a0c45822d8763871e3491d99beb4d22cb
-introduce DBUS_DIR_SEPERATOR and make use of it. On windows, disable some system service tests
-"forward" slashes work fine on Windows, no need to uglify code with DBUS_DIR_SEPARATOR
-
-cd2cdb3457f72cf058d5b19796ee691ceca6b52c
-r783: introduced DBUS_CLEANUP_OLD_SERVICES that does cleanup prev zombie-instances...
-unsure about this. something specific to KDE-on-Windows?
-
-eeedba5b2f5b008819619764943caddd52441adf
-build fixes for OS X, xcode 3.1.2, gcc 4.2.1
-doesn't apply, seems to be upstream?
-
-7dc7f71cf3003e006f6e177b5460d14a7cdbf2de
-configure.in: fix pthread detection
-doesn't apply
-
-05b37fa87b1f6aa670de9007879f53a8198a7a89
-configure.in: suppress -fPIC, -fPIE for W32
-doesn't apply
-
-b0d14fed92d9f539cd3478e72dc2f3ea75f3941a
-configure.in: only check for wspiapi.h on Windows
-nah, no harm checking for it on UNIX too
-
-1724fc10e516e2d570537d522d8608abba90be5e
-prototypes cleanup
-related to cd2cdb3457f72cf058d5b19796ee691ceca6b52c which was skipped above
diff --git a/README.launchd b/README.launchd
new file mode 100644
index 0000000..701e57d
--- /dev/null
+++ b/README.launchd
@@ -0,0 +1,61 @@
+Launchd[1,2] replaces init, inetd and cron on Mac OS X since 10.4 "Tiger".
+dbus uses this service to provide a common session bus address for each user
+and so deprecates the X11 enabled dbus-launcher.
+
+[1] http://developer.apple.com/MacOsX/launchd.html
+[2] http://launchd.macosforge.org/
+
+
+Setup
+===
+
+Configure with --enable-launchd and --without-x (X11 should not harm but it's
+simply not necessary any more)
+After installation, to prevent a reboot, load the dbus session starter into
+launchd by executing:
+$ launchctl load /Library/LaunchAgents/org.freedesktop.dbus-session.plist
+
+You can change the launch agent dir via configure, but it's not recommended.
+Make sure to execute the above line as the actual user for which you want to
+use a session bus since launchd manages its agents on a per user basis.
+
+
+How it works
+===
+
+Launchd allocates a socket and provides the unix path to it via the variable
+DBUS_LAUNCHD_SESSION_BUS_SOCKET in launchd's environment. Every process
+spawned by launchd (or dbus-daemon, if stared by launchd) can access it through
+its own environment. Other processes can query launchd for it by executing:
+$ launchctl getenv DBUS_LAUNCHD_SESSION_BUS_SOCKET
+However, this is normally done by the dbus client lib for you.
+
+If launchd start dbus-daemon with a config file containing a "launchd:env=FOO"
+address, as the default session config does with env=DBUS_LAUNCHD_SESSION_BUS_SOCKET,
+the daemon will get the file descriptor from launchd and start listening on it.
+The environment variable is used to get the actual socket path which is passed
+to every service spawned by dbus-daemon as a result from autolaunch messages.
+Please note that it's not possible to start dbus-daemon manually when using a
+"launchd:" address. Only child processes of launchd can access the above
+mentioned file descriptor!
+
+To create custom buses just set up an other launch agent. As a quick start copy
+/Library/LaunchAgents/org.freedesktop.dbus-session.plist, change the label
+to i.e. "org.freedesktop.dbus-foo" and change the SecureSocketWithKey value,
+i.e. to "DBUS_LAUNCHD_FOO_BUS_SOCKET". This environment variable has to be set
+in the config file for your new bus in the <listen> element (see session.config).
+Then edit your /Library/LaunchAgents/org.freedesktop.dbus-foo.plist to start
+dbus-daemon with "--config-file=/opt/local/etc/dbus-1/foo.conf" instead of
+"--session". Now load the new plist onto launchd as described in the setup
+section of this document.
+Executing "launchctl export" should now give you two sockets, one in
+DBUS_LAUNCHD_SESSION_BUS_SOCKET and the new DBUS_LAUNCHD_FOO_BUS_SOCKET.
+To connect to this new bus use "launchd:env=DBUS_LAUNCHD_FOO_BUS_SOCKET".
+
+Since Mac OS X 10.5 "Leopard" you can also configure launchd to start
+dbus-daemon on demand as soon as some process connects to the socket. Since
+it's broken on 10.4 this feature is disabled per default. Look at
+/Library/LaunchAgents/org.freedesktop.dbus-session.plist to change it.
+
+On the client side, the envvar DBUS_SESSION_BUS_ADDRESS can be normally used
+but if it's not set, launchd is queried for the session bus socket.
diff --git a/README.win b/README.win
new file mode 100644
index 0000000..d18f23d
--- /dev/null
+++ b/README.win
@@ -0,0 +1,111 @@
+-----------------------------------------
+Windows port of the freedesktop.org D-Bus
+-----------------------------------------
+
+Features and completeness
+-------------------------
+The windows port of dbus provides the dbus-1 library and mostly
+applications which are already available on unix. These applications
+are: dbus-daemon, dbus-launch, dbus-monitor and dbus-send.
+DBus comes with a test suite which is used on unix to guarantate
+production quality and this test suite runs mostly. There are some
+test not running yet and there is help needed to get them running.
+
+Supported compilers
+-------------------
+On windows Microsoft Visual Studio 2010 (Express and professional variants) 
+and mingw-w64|32 are known to work.
+
+Building
+--------
+DBus can be built on windows using automake or cmake. See the
+file README for more information.
+Special cmake build instructions can be found in cmake/readme-cmake.txt
+
+
+windbus and dbus4win Ports
+--------------------------
+The Windows ports from the windbus and dbus4win projects has been merged
+into the freedesktop git master branch, as applicable. The spec has been
+updated with windows specific stuff.
+
+
+Tests
+-----
+ - dbus library check
+    bin\dbus-test.exe <build-root>\test\data
+
+ - bus daemon check
+    bin\bus-test.exe <build-root>\test\data
+
+ - check available names
+    bin\test_names.exe
+
+ - check if dbus-daemon is accessable
+    bin\dbus-send.exe --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames method return sender=org.freedesktop.DBus -> dest=:1.4 array [ string "org.freedesktop.DBus"string ":1.4"]
+
+ - start session dbus-daemon
+    either by running
+        bin\dbus-launch
+    or
+        start bin\dbus-daemon --session
+
+    Before running these commands you may execute
+        set DBUS_VERBOSE=1
+    for getting debug infos
+
+
+ - call function registerd in dbus
+    bin\dbus-send.exe  --dest=org.freedesktop.DBus --print-reply --type=method_call / org.freedesktop.DBus.StartServiceByName string:org.freedesktop.DBus.TestSuiteEchoService  uint32:455 method return sender=org.freedesktop.DBus -> dest=:1.8 uint32 2
+
+    note: When building with the Visual C++ IDE the *.exe files are in
+          the bin/Debug and bin/Release folder, not in the bin folder.
+
+
+FAQ
+---
+
+- How far is WinDBus from being usable for production ?
+
+  dbus comes with a test suite which is used on unix to guarantate
+  production quality and this test suite runs mostly. There are some
+  test not running and we need help to get them running.
+  In the pratice I and some other people are using dbus for at least more
+  than four years in conjunction with kde on windows without any problems.
+
+- On UNIX D-Bus uses UNIX sockets to communicate (correct me if I'm wrong).
+  What is used on Windows ?
+
+  tcp sockets, there are some efforts to get named pipe running, but some
+  design problems of the win32 api, we are not able to solve without
+  bigger changes to the dbus code base let us stop this effort.
+
+- Do you have any clue if dbus-win32 can run in a Windows CE environment?
+
+  dbus has been ported to wince, see README.wince for more information
+
+- Do you know if the C++ binding made by OpenWengo will be easily portable to Windows?
+
+  The OpenWengo dbus-c++ binding has been ported to windows see in WinDBus svn
+  (http://sf.net/projects/windbus)
+  The related test applicationa are running well.
+
+
+TODO
+----
+
+Oktober 2010:
+
+- the code wrapped with DBUS_WIN_FIXME should be inspected if it required for windows
+
+- create a dbus setup installer
+
+- implement system bus and system bus service starter
+  see http://windbus.svn.sourceforge.net/viewvc/windbus/trunk/bus/bus-service-win.c
+  for a starting point
+
+- implement a real login session bus
+  The scope parameter of the autolaunch meta protocol could be extended to support user
+  specific session busses (like already done with the amarok bundled dbus which use a
+  shared memory area named "DBusDaemonAddressInfo:<username>".
+  Also the dbus installer should start a session bus on user login.
diff --git a/README.windbus b/README.windbus
deleted file mode 100644
index 1dde5c8..0000000
--- a/README.windbus
+++ /dev/null
@@ -1,169 +0,0 @@
-This README.windbus file below originates from the "windbus" fork. It
-does not reflect reality here. Changes from both windbus and the
-separate "dbus4win" fork have been merged into this code repository,
-as applicable.
-
-----------------------------------------
-Windows port of the freedesktop.org D-Bus
-----------------------------------------
-
-Requirements 
-------------
-- cmake version >= 2.4.4 see http://www.cmake.org 
-- installed libxml2 or libexpat from http://82.149.170.66/kde-windows/win32libs
-
-Build
------
-
-unix
-1. install cmake and libxml or libexpat 
-2. get dbus sources 
-3. mkdir dbus-build 
-4. cd dbus-build 
-5. cmake <dbus-src-root>/cmake or cmake -DDBUS_USE_EXPAT=on <dbus-src-root>/cmake in case libexpat should de used
-5. make 
-6. make install
-
-win32
-1. Install your prefered compiler
-	- Mingw from www.mingw.org 
-	- Visual C++ 2005 Express/Studio
-	
-2. Install libxml2 or libexpat packages from 
-     http://82.149.170.66/kde-windows/win32libs
-   into a subdir win32libs in your program installation eg 
-     - german  => "c:\Programme\win32libs"
-     - english => "c:\Program Files\win32libs" 
-     
-3. download and install the most recent CMake version from http://www.cmake.org/files/
-
-4. apply dbus-win.patch: 'patch -p0 -i dbus-win.patch'
-
-5. open command shell and run in the created build folder which resides side by side 
-   to the D-Bus sources:
-   	- for mingw: 
-		cmake -G "MinGW Makefiles" <options> ..\<dbus-source-root>\cmake
-	- for Visual C++
-		cmake ..\<dbus-source-root>\cmake
-
-7. build
-
-
-Tests
------
-(when build with the Visual C++ IDE the *.exe files are 
-in the bin/Debug and bin/Release folder)
-
- - dbus library check 
-		bin\dbus-test.exe .\test\data
-	
- - bus daemon check 
-		bin\bus-test.exe .\test\data
-
- - check available names 
-		bin\test_names.exe 
-
- - check if dbus-daemon is accessable 
-		bin\dbus-send.exe --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames method return sender=org.freedesktop.DBus -> dest=:1.4 array [ 	      string "org.freedesktop.DBus"string ":1.4"] 
-		
- - start dbus-daemon
-		* set DBUS_VERBOSE=0  (=1 for getting debug infos)
-		* start bin\dbus-daemon --session
-		* bin\dbus-send.exe  --dest=org.freedesktop.DBus --print-reply --type=method_call / org.freedesktop.DBus.StartServiceByName string:org.freedesktop.DBus.TestSuiteEchoService  uint32:455 method return sender=org.freedesktop.DBus -> dest=:1.8 uint32 2
-
-
-
-Some build options
--------------
-    key                        description                            default value
-    ---                        -----------                            -------------
-DBUS_USE_EXPAT              "Use expat (== ON) or libxml2 (==OFF)         OFF
-DBUS_DISABLE_ASSERTS        "Disable assertion checking"                  OFF
-DBUS_BUILD_TESTS            "enable unit test code"                       ON
-DBUS_ENABLE_ANSI            "enable -ansi -pedantic gcc flags"            OFF
-DBUS_ENABLE_GCOV            "compile with coverage profiling 
-                             instrumentation (gcc only)"                  OFF
-DBUS_ENABLE_VERBOSE_MODE    "support verbose debug mode"                  ON
-DBUS_DISABLE_CHECKS         "Disable public API sanity checking"          OFF
-DBUS_INSTALL_SYSTEM_LIBS    "install required system libraries 
-                             (mingw: libxml2, libiconv, mingw10)"         OFF
-CMAKE_BUILD_TYPE            "build type (== debug) or (== release)        release
-
-
-
-Developers
-----------
-
-Running the tests in Visual Studio:
-
- To successfully run the tests by the IDE you must add
- the FULL patch to test\data in your build directory
- (e.g. c:\dbus\build\test\data)  
- in something like 
-  -> Project Settings
-    -> Debugging
-       -> Command line arguments
-    
-    
-       
-FAQ
----
-
-- How much work remains till DBUS win32 can be merged with the main project?
-
-There are some patches outstanding and the most effort is required in
-discussions with the main dbus team how to implement some parts. One of
-the main dbus team estimated the open work to one fulltime week.
-http://lists.freedesktop.org/archives/dbus/2006-November/006264.html
-
-I assume they will answer ALL your questions, and they are very
-interested in fully supporting win32.
-
-- How far is WinDBus from being usable for production ?
-dbus comes with a test suite which is used on unix to guarantate
-production quality and this test suite runs mostly. There are some 
-test not running and we need help to get them running.
-
-In the pratice I and some other people are using dbus for at least more
-than a half year in conjunction with kde on windows without any problems.
-
-
-- On UNIX D-Bus uses UNIX sockets to communicate (correct me if I'm wrong). 
-  What is used on Windows ?
-  
-tcp sockets, there are some efforts to get named pipe running, but some
-design problems of the win32 api, we are not able to solve without
-bigger changes to the dbus code base let us stop this effort.
-
-
-- Do you have any clue if dbus-win32 can run in a Windows CE environment?
-
-I was told that windows ce does not have posix function
-open/close/select/... and dbus code uses such function in some area.
-
-
-- Do you know if the C++ binding made by OpenWengo will be easily portable to Windows?
-
-We have already ported the OpenWengo dbus-c++ binding, see in WinDBus svn  (http://sf.net/projects/windbus)
-The related test applicationa are running well.
-
-
-TODO
-----
-
-February 2007:
-
-- all changes of dbus-win.patch should become part of the official D-Bus code
-  
-- all code currently disabled by DBUS_WIN_FIXME should work
-  
-- clean up:
-    * bus/bus-service-win.c
-    * bus/dir-watch.c
-    * dbus/dbus-spawn-win.c
-    * dbus/dbus-sysdeps-util-win.c
-    * dbus/dbus-sysdeps-win.c
-
-
-see also:
-http://lists.freedesktop.org/archives/dbus/2006-July/005076.html
diff --git a/autogen.sh b/autogen.sh
index bf53b27..1558112 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -27,8 +27,12 @@
 	DIE=1
 }
 
-AUTOMAKE=automake-1.9
-ACLOCAL=aclocal-1.9
+# If the user hasn't explicitly chosen an Automake version, use 1.11. This is
+# the earliest version that gives us silent rules.
+if test -z "$AUTOMAKE"; then
+    AUTOMAKE=automake-1.11
+    ACLOCAL=aclocal-1.11
+fi
 
 ($AUTOMAKE --version) < /dev/null > /dev/null 2>&1 || {
         AUTOMAKE=automake
@@ -43,7 +47,12 @@
 	DIE=1
 }
 
-(libtoolize --version) < /dev/null > /dev/null 2>&1 || {
+LIBTOOLIZE=`which libtoolize`
+if ! test -f $LIBTOOLIZE; then
+	LIBTOOLIZE=`which glibtoolize`
+fi
+
+($LIBTOOLIZE --version) < /dev/null > /dev/null 2>&1 || {
 	echo
 	echo "You must have libtoolize installed to compile $PROJECT."
 	echo "Install the libtool package from ftp.gnu.org or a mirror."
@@ -64,10 +73,9 @@
         echo "to pass any to it, please specify them on the $0 command line."
 fi
 
-libtoolize --copy --force
+$LIBTOOLIZE --copy --force
 
-echo $ACLOCAL $ACLOCAL_FLAGS
-$ACLOCAL $ACLOCAL_FLAGS
+$ACLOCAL -I m4 $ACLOCAL_FLAGS
 
 ## optionally feature autoheader
 (autoheader --version)  < /dev/null > /dev/null 2>&1 && autoheader
@@ -77,8 +85,9 @@
 
 cd $ORIGDIR
 
-run_configure=true
-for arg in $*; do
+if test x"$NOCONFIGURE" = x; then
+  run_configure=true
+  for arg in $*; do
     case $arg in 
         --no-configure)
             run_configure=false
@@ -86,10 +95,13 @@
         *)
             ;;
     esac
-done
+  done
+else
+  run_configure=false
+fi
 
 if $run_configure; then
-    $srcdir/configure --enable-maintainer-mode --config-cache "$@"
+    $srcdir/configure --enable-developer --config-cache "$@"
     echo 
     echo "Now type 'make' to compile $PROJECT."
 else
diff --git a/bus/.gitignore b/bus/.gitignore
index ff8d303..861dc1f 100644
--- a/bus/.gitignore
+++ b/bus/.gitignore
@@ -16,10 +16,11 @@
 bus-test
 rc.messagebus
 messagebus
+messagebus-config
 session.conf
 system.conf
-dbus-daemon.1
 bus-test-launch-helper
 bus-test-system
 dbus.service
 dbus.socket
+org.freedesktop.dbus-session.plist
diff --git a/bus/Android.mk b/bus/Android.mk
index 3da183e..a0a963b 100644
--- a/bus/Android.mk
+++ b/bus/Android.mk
@@ -12,6 +12,7 @@
 	-Wno-address \
 	-Wno-empty-body \
 	-Wno-pointer-sign \
+	-Wno-sign-compare \
 	-Wno-unused-parameter
 
 LOCAL_SRC_FILES:= \
diff --git a/bus/Makefile.am b/bus/Makefile.am
index 5c4fb15..6cbc09a 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -1,20 +1,47 @@
-
 configdir=$(sysconfdir)/dbus-1
+dbus_daemon_execdir = $(DBUS_DAEMONDIR)
 
-INCLUDES=-I$(top_srcdir) $(DBUS_BUS_CFLAGS) @PIE_CFLAGS@		\
-	-DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\"	\
-	-DDBUS_COMPILATION
+DBUS_BUS_LIBS = \
+	$(XML_LIBS) \
+	$(SELINUX_LIBS) \
+	$(THREAD_LIBS) \
+	$(ADT_LIBS) \
+	$(NETWORK_libs) \
+	$(NULL)
+
+DBUS_LAUNCHER_LIBS = \
+	$(XML_LIBS) \
+	$(THREAD_LIBS) \
+	$(NETWORK_libs) \
+	$(NULL)
+
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	$(XML_CFLAGS) \
+	-DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \
+	-DDBUS_COMPILATION \
+	-DDBUS_STATIC_BUILD \
+	$(NULL)
+
+# if assertions are enabled, improve backtraces
+AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
 
 EFENCE=
 
 CONFIG_IN_FILES=				\
 	session.conf.in				\
-	system.conf.in
+	system.conf.in				\
+	org.freedesktop.dbus-session.plist.in
 
 config_DATA=					\
 	session.conf				\
 	system.conf
 
+if DBUS_ENABLE_LAUNCHD
+agentdir=$(LAUNCHD_AGENT_DIR)
+agent_DATA=org.freedesktop.dbus-session.plist
+endif
+
 if DBUS_USE_LIBXML
 XML_SOURCES=config-loader-libxml.c
 endif
@@ -66,6 +93,8 @@
 	services.h				\
 	signals.c				\
 	signals.h				\
+	stats.c					\
+	stats.h					\
 	test.c					\
 	test.h					\
 	utils.c					\
@@ -76,14 +105,11 @@
 	$(BUS_SOURCES)				\
 	main.c
 
-dbus_daemon_CPPFLAGS = -DDBUS_STATIC_BUILD
 dbus_daemon_LDADD=					\
 	$(top_builddir)/dbus/libdbus-internal.la	\
 	$(EFENCE)					\
 	$(DBUS_BUS_LIBS)
 
-dbus_daemon_LDFLAGS=@R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@ @PIE_LDFLAGS@
-
 LAUNCH_HELPER_SOURCES=				\
 	$(XML_SOURCES)				\
 	config-parser-common.c			\
@@ -103,13 +129,10 @@
 	activation-helper-bin.c			\
 	$(LAUNCH_HELPER_SOURCES)
 
-dbus_daemon_launch_helper_CPPFLAGS = -DDBUS_STATIC_BUILD
 dbus_daemon_launch_helper_LDADD=		\
 	$(top_builddir)/dbus/libdbus-internal.la \
 	$(DBUS_LAUNCHER_LIBS)
 
-dbus_daemon_launch_helper_LDFLAGS=@R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@
-
 ## we build another binary so we can do the launch testing without root privs.
 ## DO NOT INSTALL THIS FILE
 dbus_daemon_launch_helper_test_SOURCES=		\
@@ -120,8 +143,8 @@
 	$(top_builddir)/dbus/libdbus-internal.la \
 	$(DBUS_LAUNCHER_LIBS)
 
-dbus_daemon_launch_helper_test_LDFLAGS=@R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@
-dbus_daemon_launch_helper_test_CPPFLAGS= -DDBUS_STATIC_BUILD	\
+dbus_daemon_launch_helper_test_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
 	-DACTIVATION_LAUNCHER_TEST
 
 ## we build yet another binary so we can do the OOM tests
@@ -134,36 +157,37 @@
 	$(top_builddir)/dbus/libdbus-internal.la \
 	$(DBUS_LAUNCHER_LIBS)
 
-bus_test_launch_helper_LDFLAGS=@R_DYNAMIC_LDFLAG@ @SECTION_LDFLAGS@
-bus_test_launch_helper_CPPFLAGS= -DDBUS_STATIC_BUILD	\
+bus_test_launch_helper_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
 	-DACTIVATION_LAUNCHER_TEST	\
 	-DACTIVATION_LAUNCHER_DO_OOM
 
-extra_tests=
-extra_noinst_programs=
-extra_inst_programs=
+noinst_PROGRAMS =
+dbus_daemon_exec_PROGRAMS = dbus-daemon
 if DBUS_UNIX
-extra_tests+=bus-test-launch-helper
-extra_noinst_programs+=dbus-daemon-launch-helper dbus-daemon-launch-helper-test dbus-daemon
-endif
-if DBUS_WIN
-extra_inst_programs+=dbus-daemon
-endif
+libexec_PROGRAMS = dbus-daemon-launch-helper
+endif DBUS_UNIX
 
-## note that TESTS has special meaning (stuff to use in make check)
-## so if adding tests not to be run in make check, don't add them to
-## TESTS
+## Note that TESTS has special meaning (stuff to use in make check).
+## We don't actually want to run any of these tests until test/ has been
+## compiled, so we don't put them in TESTS here; we run them in test/
+## instead.
+
 if DBUS_BUILD_TESTS
-TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus DBUS_FATAL_WARNINGS=1 DBUS_BLOCK_ON_ABORT=1
-TESTS=bus-test bus-test-system $(extra_tests)
-else
-TESTS=
-endif
-
 ## we use noinst_PROGRAMS not check_PROGRAMS so that we build
 ## even when not doing "make check"
-noinst_PROGRAMS=$(TESTS) $(extra_noinst_programs)
-bin_PROGRAMS=$(extra_inst_programs)
+
+# run as a test by test/Makefile.am
+noinst_PROGRAMS += bus-test bus-test-system
+
+if DBUS_UNIX
+# run as a test by test/Makefile.am
+noinst_PROGRAMS += bus-test-launch-helper
+# this is used by the tests but is not,itself, a test
+noinst_PROGRAMS += dbus-daemon-launch-helper-test
+endif DBUS_UNIX
+
+endif DBUS_BUILD_TESTS
 
 bus_test_system_SOURCES=			\
 	$(XML_SOURCES)				\
@@ -175,60 +199,47 @@
 	utils.h					\
 	test-system.c
 
-bus_test_system_CPPFLAGS = -DDBUS_STATIC_BUILD
 bus_test_system_LDADD=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_BUS_LIBS)
-bus_test_system_LDFLAGS=@R_DYNAMIC_LDFLAG@
 
 bus_test_SOURCES=				\
 	$(BUS_SOURCES)				\
 	test-main.c
 
-bus_test_CPPFLAGS = -DDBUS_STATIC_BUILD
 bus_test_LDADD=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_BUS_LIBS)
-bus_test_LDFLAGS=@R_DYNAMIC_LDFLAG@
 
 ## mop up the gcov files
 clean-local:
 	/bin/rm *.bb *.bbg *.da *.gcov || true
 
-uninstall-hook:
-	rm -f $(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon$(EXEEXT)
-	rm -f $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper$(EXEEXT)
-
 install-data-hook:
 	$(mkinstalldirs) $(DESTDIR)$(localstatedir)/run/dbus
 	$(mkinstalldirs) $(DESTDIR)$(configdir)/system.d
 	$(mkinstalldirs) $(DESTDIR)$(configdir)/session.d
 	$(mkinstalldirs) $(DESTDIR)$(datadir)/dbus-1/services
 	$(mkinstalldirs) $(DESTDIR)$(datadir)/dbus-1/system-services
+if HAVE_SYSTEMD
+# Install dbus.socket as default implementation of a D-Bus stack.
+# Deliberately not using $(LN_S) here: ln -fs is not universally portable,
+# but neither is systemd, so it's OK to assume here that ln complies with SUS.
+	$(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/dbus.target.wants
+	ln -fs ../dbus.socket $(DESTDIR)$(systemdsystemunitdir)/dbus.target.wants/dbus.socket
+# Unconditionally enable D-Bus on systemd installations
+	$(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants
+	ln -fs ../dbus.socket $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants/dbus.socket
+	$(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/multi-user.target.wants
+	ln -fs ../dbus.service $(DESTDIR)$(systemdsystemunitdir)/multi-user.target.wants/dbus.service
+endif
+
 if DBUS_UNIX
-	if test '!' -d $(DESTDIR)$(DBUS_DAEMONDIR); then \
-		$(mkinstalldirs) $(DESTDIR)$(DBUS_DAEMONDIR); \
-		chmod 755 $(DESTDIR)$(DBUS_DAEMONDIR); \
-	fi
-	$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) dbus-daemon$(EXEEXT) $(DESTDIR)$(DBUS_DAEMONDIR)
-	$(mkinstalldirs) $(DESTDIR)$(libexecdir)/dbus-1
-	if test -f dbus-daemon-launch-helper$(EXEEXT) ; then \
-	$(LIBTOOL) --mode=install $(INSTALL_PROGRAM) dbus-daemon-launch-helper$(EXEEXT) $(DESTDIR)$(libexecdir); \
+install-exec-hook:
 	if test `id -u` -eq 0; then \
 		chown root:$(DBUS_USER) $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper$(EXEEXT); \
 		chmod 4750 $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper$(EXEEXT); \
 	else \
 		echo "Not installing $(DESTDIR)$(libexecdir)/dbus-daemon-launch-helper binary setuid!"; \
 		echo "You'll need to manually set permissions to root:$(DBUS_USER) and permissions 4750"; \
-	fi \
 	fi
 endif
-if HAVE_SYSTEMD
-# Install dbus.socket as default implementation of a D-Bus stack
-	$(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/dbus.target.wants
-	$(LN_S) ../dbus.socket $(DESTDIR)$(systemdsystemunitdir)/dbus.target.wants/dbus.socket
-# Unconditionally enable D-Bus on systemd installations
-	$(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants
-	$(LN_S) ../dbus.socket $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants/dbus.socket
-	$(mkinstalldirs) $(DESTDIR)$(systemdsystemunitdir)/multi-user.target.wants
-	$(LN_S) ../dbus.service $(DESTDIR)$(systemdsystemunitdir)/multi-user.target.wants/dbus.service
-endif
 
 #### Init scripts fun
 SCRIPT_IN_FILES=messagebus.in \
@@ -276,9 +287,6 @@
 	dbus.socket
 endif
 
-MAN_IN_FILES=dbus-daemon.1.in
-man_MANS = dbus-daemon.1
-
 #### Extra dist
 
-EXTRA_DIST=$(CONFIG_IN_FILES) $(SCRIPT_IN_FILES) $(man_MANS) $(MAN_IN_FILES)
+EXTRA_DIST=$(CONFIG_IN_FILES) $(SCRIPT_IN_FILES)
diff --git a/bus/activation-helper.c b/bus/activation-helper.c
index baba8f0..cbc00d2 100644
--- a/bus/activation-helper.c
+++ b/bus/activation-helper.c
@@ -140,21 +140,12 @@
   return desktop_file;
 }
 
-/* Cleares the environment, except for DBUS_VERBOSE and DBUS_STARTER_x */
+/* Clears the environment, except for DBUS_STARTER_x,
+ * which we hardcode to the system bus.
+ */
 static dbus_bool_t
 clear_environment (DBusError *error)
 {
-  const char *debug_env = NULL;
-  const char *starter_env = NULL;
-
-#ifdef DBUS_ENABLE_VERBOSE_MODE
-  /* are we debugging */
-  debug_env = _dbus_getenv ("DBUS_VERBOSE");
-#endif
-
-  /* we save the starter */
-  starter_env = _dbus_getenv ("DBUS_STARTER_ADDRESS");
-
 #ifndef ACTIVATION_LAUNCHER_TEST
   /* totally clear the environment */
   if (!_dbus_clearenv ())
@@ -165,17 +156,8 @@
     }
 #endif
 
-#ifdef DBUS_ENABLE_VERBOSE_MODE
-  /* restore the debugging environment setting if set */
-  if (debug_env)
-    _dbus_setenv ("DBUS_VERBOSE", debug_env);
-#endif
-
-  /* restore the starter */
-  if (starter_env)
-    _dbus_setenv ("DBUS_STARTER_ADDRESS", starter_env);
-
-  /* set the type, which must be system if we got this far */
+  /* Ensure the bus is set to system */
+  _dbus_setenv ("DBUS_STARTER_ADDRESS", DBUS_SYSTEM_BUS_DEFAULT_ADDRESS);
   _dbus_setenv ("DBUS_STARTER_BUS_TYPE", "system");
 
   return TRUE;
@@ -184,6 +166,7 @@
 static dbus_bool_t
 check_permissions (const char *dbus_user, DBusError *error)
 {
+#ifndef ACTIVATION_LAUNCHER_TEST
   uid_t uid, euid;
   struct passwd *pw;
 
@@ -191,7 +174,6 @@
   uid = 0;
   euid = 0;
 
-#ifndef ACTIVATION_LAUNCHER_TEST
   /* bail out unless the dbus user is invoking the helper */
   pw = getpwnam(dbus_user);
   if (!pw)
@@ -403,12 +385,15 @@
 {
   DBusString config_file;
   dbus_bool_t retval;
+#ifdef ACTIVATION_LAUNCHER_TEST
   const char *test_config_file;
+#endif
 
   retval = FALSE;
-  test_config_file = NULL;
 
 #ifdef ACTIVATION_LAUNCHER_TEST
+  test_config_file = NULL;
+
   /* there is no _way_ we should be setuid if this define is set.
    * but we should be doubly paranoid and check... */
   if (getuid() != geteuid())
diff --git a/bus/activation.c b/bus/activation.c
index ee5efa8..3dfba78 100644
--- a/bus/activation.c
+++ b/bus/activation.c
@@ -143,16 +143,6 @@
   dbus_free (entry);
 }
 
-static void
-handle_timeout_callback (DBusTimeout   *timeout,
-                         void          *data)
-{
-  BusPendingActivation *pending_activation = data;
-
-  while (!dbus_timeout_handle (pending_activation->timeout))
-    _dbus_wait_for_memory ();
-}
-
 static BusPendingActivation *
 bus_pending_activation_ref (BusPendingActivation *pending_activation)
 {
@@ -179,8 +169,7 @@
   if (pending_activation->timeout_added)
     {
       _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context),
-                                 pending_activation->timeout,
-                                 handle_timeout_callback, pending_activation);
+                                 pending_activation->timeout);
       pending_activation->timeout_added = FALSE;
     }
 
@@ -264,9 +253,11 @@
   DBusStat stat_buf;
   DBusString file_path;
   DBusError tmp_error;
+  dbus_bool_t retval;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
+  retval = FALSE;
   name = NULL;
   exec = NULL;
   user = NULL;
@@ -286,14 +277,14 @@
       !_dbus_concat_dir_and_file (&file_path, filename))
     {
       BUS_SET_OOM (error);
-      goto failed;
+      goto out;
     }
 
   if (!_dbus_stat (&file_path, &stat_buf, NULL))
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Can't stat the service file\n");
-      goto failed;
+      goto out;
     }
 
   if (!bus_desktop_file_get_string (desktop_file,
@@ -301,14 +292,18 @@
                                     DBUS_SERVICE_NAME,
                                     &name,
                                     error))
-    goto failed;
+    goto out;
 
   if (!bus_desktop_file_get_string (desktop_file,
                                     DBUS_SERVICE_SECTION,
                                     DBUS_SERVICE_EXEC,
                                     &exec_tmp,
                                     error))
-    goto failed;
+    goto out;
+
+  exec = _dbus_strdup (_dbus_replace_install_prefix (exec_tmp));
+  dbus_free (exec_tmp);
+  exec_tmp = NULL;
 
   /* user is not _required_ unless we are using system activation */
   if (!bus_desktop_file_get_string (desktop_file,
@@ -321,7 +316,7 @@
       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
         {
           dbus_move_error (&tmp_error, error);
-          goto failed;
+          goto out;
         }
       else
         {
@@ -344,7 +339,7 @@
       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
         {
           dbus_move_error (&tmp_error, error);
-          goto failed;
+          goto out;
         }
       else
         {
@@ -360,8 +355,6 @@
   entry = _dbus_hash_table_lookup_string (s_dir->entries,
                                           _dbus_string_get_const_data (filename));
 
-  exec = strdup (_dbus_replace_install_prefix (exec_tmp));
-
   if (entry == NULL) /* New file */
     {
       /* FIXME we need a better-defined algorithm for which service file to
@@ -371,14 +364,14 @@
         {
           dbus_set_error (error, DBUS_ERROR_FAILED,
                           "Service %s already exists in activation entry list\n", name);
-          goto failed;
+          goto out;
         }
 
       entry = dbus_new0 (BusActivationEntry, 1);
       if (entry == NULL)
         {
           BUS_SET_OOM (error);
-          goto failed;
+          goto out;
         }
 
       entry->name = name;
@@ -387,18 +380,24 @@
       entry->systemd_service = systemd_service;
       entry->refcount = 1;
 
+      /* ownership has been transferred to entry, do not free separately */
+      name = NULL;
+      exec = NULL;
+      user = NULL;
+      systemd_service = NULL;
+
       entry->s_dir = s_dir;
       entry->filename = _dbus_strdup (_dbus_string_get_const_data (filename));
       if (!entry->filename)
         {
           BUS_SET_OOM (error);
-          goto failed;
+          goto out;
         }
 
       if (!_dbus_hash_table_insert_string (activation->entries, entry->name, bus_activation_entry_ref (entry)))
         {
           BUS_SET_OOM (error);
-          goto failed;
+          goto out;
         }
 
       if (!_dbus_hash_table_insert_string (s_dir->entries, entry->filename, bus_activation_entry_ref (entry)))
@@ -406,7 +405,7 @@
           /* Revert the insertion in the entries table */
           _dbus_hash_table_remove_string (activation->entries, entry->name);
           BUS_SET_OOM (error);
-          goto failed;
+          goto out;
         }
 
       _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
@@ -418,19 +417,31 @@
 
       if (_dbus_hash_table_lookup_string (activation->entries, name))
         {
-          _dbus_verbose ("The new service name \"%s\" of service file \"%s\" already in cache, ignoring\n",
+          _dbus_verbose ("The new service name \"%s\" of service file \"%s\" is already in cache, ignoring\n",
                          name, _dbus_string_get_const_data (&file_path));
-          goto failed;
+          dbus_set_error (error, DBUS_ERROR_FAILED,
+                          "The new service name \"%s\" of service file \"%s\" is already in cache, ignoring\n",
+                          name, _dbus_string_get_const_data (&file_path));
+          goto out;
         }
 
+      /* ownership has been transferred to entry, do not free separately */
       dbus_free (entry->name);
+      entry->name = name;
+      name = NULL;
+
       dbus_free (entry->exec);
+      entry->exec = exec;
+      exec = NULL;
+
       dbus_free (entry->user);
+      entry->user = user;
+      user = NULL;
+
       dbus_free (entry->systemd_service);
       entry->systemd_service = systemd_service;
-      entry->name = name;
-      entry->exec = exec;
-      entry->user = user;
+      systemd_service = NULL;
+
       if (!_dbus_hash_table_insert_string (activation->entries,
                                            entry->name, bus_activation_entry_ref(entry)))
         {
@@ -439,21 +450,17 @@
            * the entries hash table */
           _dbus_hash_table_remove_string (entry->s_dir->entries,
                                           entry->filename);
-          bus_activation_entry_unref (entry);
-          return FALSE;
+          goto out;
         }
     }
 
   entry->mtime = stat_buf.mtime;
+  retval = TRUE;
 
-  _dbus_string_free (&file_path);
-  bus_activation_entry_unref (entry);
-
-  return TRUE;
-
-failed:
+out:
+  /* if these have been transferred into entry, the variables will be NULL */
   dbus_free (name);
-  dbus_free (exec_tmp);
+  dbus_free (exec);
   dbus_free (user);
   dbus_free (systemd_service);
   _dbus_string_free (&file_path);
@@ -461,7 +468,7 @@
   if (entry)
     bus_activation_entry_unref (entry);
 
-  return FALSE;
+  return retval;
 }
 
 static dbus_bool_t
@@ -877,8 +884,6 @@
                     DBusError         *error)
 {
   BusActivation *activation;
-  DBusList      *link;
-  char          *dir;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -1091,6 +1096,10 @@
   if (!pending_activation)
     return TRUE;
 
+  bus_context_log (activation->context,
+                   DBUS_SYSTEM_LOG_INFO, "Successfully activated service '%s'",
+                   service_name);
+
   link = _dbus_list_get_first_link (&pending_activation->entries);
   while (link != NULL)
     {
@@ -1315,22 +1324,16 @@
     }
 }
 
-static dbus_bool_t
-babysitter_watch_callback (DBusWatch     *watch,
-                           unsigned int   condition,
-                           void          *data)
+static void
+pending_activation_finished_cb (DBusBabysitter *babysitter,
+                                void           *data)
 {
   BusPendingActivation *pending_activation = data;
-  dbus_bool_t retval;
-  DBusBabysitter *babysitter;
   dbus_bool_t uses_servicehelper;
 
-  babysitter = pending_activation->babysitter;
-
+  _dbus_assert (babysitter == pending_activation->babysitter);
   _dbus_babysitter_ref (babysitter);
 
-  retval = dbus_watch_handle (watch, condition);
-
   /* There are two major cases here; are we the system bus or the session?  Here this
    * is distinguished by whether or not we use a setuid helper launcher.  With the launch helper,
    * some process exit codes are meaningful, processed by handle_servicehelper_exit_error.
@@ -1341,15 +1344,7 @@
    */
   uses_servicehelper = bus_context_get_servicehelper (pending_activation->activation->context) != NULL;
 
-  /* FIXME this is broken in the same way that
-   * connection watches used to be; there should be
-   * a separate callback for status change, instead
-   * of doing "if we handled a watch status might
-   * have changed"
-   *
-   * Fixing this lets us move dbus_watch_handle
-   * calls into dbus-mainloop.c
-   */
+  /* strictly speaking this is redundant with the check in dbus-spawn now */
   if (_dbus_babysitter_get_child_exited (babysitter))
     {
       DBusError error;
@@ -1385,6 +1380,11 @@
 
       if (activation_failed)
         {
+          bus_context_log (pending_activation->activation->context,
+                           DBUS_SYSTEM_LOG_INFO, "Activated service '%s' failed: %s",
+                           pending_activation->service_name,
+                           error.message);
+
           /* Destroy all pending activations with the same exec */
           _dbus_hash_iter_init (pending_activation->activation->pending_activations,
                                 &iter);
@@ -1404,8 +1404,6 @@
     }
 
   _dbus_babysitter_unref (babysitter);
-
-  return retval;
 }
 
 static dbus_bool_t
@@ -1414,9 +1412,9 @@
 {
   BusPendingActivation *pending_activation = data;
 
-  return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context),
-                               watch, babysitter_watch_callback, pending_activation,
-                               NULL);
+  return _dbus_loop_add_watch (
+      bus_context_get_loop (pending_activation->activation->context),
+      watch);
 }
 
 static void
@@ -1426,7 +1424,17 @@
   BusPendingActivation *pending_activation = data;
 
   _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context),
-                           watch, babysitter_watch_callback, pending_activation);
+                           watch);
+}
+
+static void
+toggle_babysitter_watch (DBusWatch      *watch,
+                         void           *data)
+{
+  BusPendingActivation *pending_activation = data;
+
+  _dbus_loop_toggle_watch (bus_context_get_loop (pending_activation->activation->context),
+                           watch);
 }
 
 static dbus_bool_t
@@ -1447,6 +1455,10 @@
   dbus_set_error (&error, DBUS_ERROR_TIMED_OUT,
                   "Activation of %s timed out",
                   pending_activation->service_name);
+  bus_context_log (pending_activation->activation->context,
+                   DBUS_SYSTEM_LOG_INFO,
+                   "Failed to activate service '%s': timed out",
+                   pending_activation->service_name);
 
   pending_activation_failed (pending_activation, &error);
 
@@ -1659,6 +1671,7 @@
                                  const char     *service_name,
                                  DBusError      *error)
 {
+  DBusError tmp_error;
   BusActivationEntry *entry;
   BusPendingActivation *pending_activation;
   BusPendingActivationEntry *pending_activation_entry;
@@ -1669,12 +1682,9 @@
   char **envp = NULL;
   int argc;
   dbus_bool_t retval;
-  DBusHashIter iter;
-  dbus_bool_t activated;
+  dbus_bool_t was_pending_activation;
   DBusString command;
 
-  activated = TRUE;
-
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   if (activation->n_pending_activations >=
@@ -1753,7 +1763,8 @@
 
   /* Check if the service is being activated */
   pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
-  if (pending_activation)
+  was_pending_activation = (pending_activation != NULL);
+  if (was_pending_activation)
     {
       if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
         {
@@ -1832,10 +1843,7 @@
         }
 
       if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context),
-                                   pending_activation->timeout,
-                                   handle_timeout_callback,
-                                   pending_activation,
-                                   NULL))
+                                   pending_activation->timeout))
         {
           _dbus_verbose ("Failed to add timeout for pending activation\n");
 
@@ -1860,19 +1868,6 @@
       pending_activation->n_entries += 1;
       pending_activation->activation->n_pending_activations += 1;
 
-      activated = FALSE;
-      _dbus_hash_iter_init (activation->pending_activations, &iter);
-      while (_dbus_hash_iter_next (&iter))
-        {
-          BusPendingActivation *p = _dbus_hash_iter_get_value (&iter);
-
-          if (strcmp (p->exec, entry->exec) == 0)
-            {
-              activated = TRUE;
-              break;
-            }
-        }
-
       if (!_dbus_hash_table_insert_string (activation->pending_activations,
                                            pending_activation->service_name,
                                            pending_activation))
@@ -1895,7 +1890,7 @@
       return FALSE;
     }
 
-  if (activated)
+  if (was_pending_activation)
     return TRUE;
 
   if (bus_context_get_systemd_activation (activation->context))
@@ -1961,18 +1956,34 @@
           service = bus_registry_lookup (registry, &service_string);
 
           if (service != NULL)
-            /* Wonderful, systemd is connected, let's just send the msg */
-            retval = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service),
-                                           message, error);
+            {
+              bus_context_log (activation->context,
+                               DBUS_SYSTEM_LOG_INFO, "Activating via systemd: service name='%s' unit='%s'",
+                               service_name,
+                               entry->systemd_service);
+              /* Wonderful, systemd is connected, let's just send the msg */
+              retval = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service),
+                                             message, error);
+            }
           else
-            /* systemd is not around, let's "activate" it. */
-            retval = bus_activation_activate_service (activation, connection, activation_transaction, TRUE,
-                                                      message, "org.freedesktop.systemd1", error);
+            {
+              bus_context_log (activation->context,
+                               DBUS_SYSTEM_LOG_INFO, "Activating systemd to hand-off: service name='%s' unit='%s'",
+                               service_name,
+                               entry->systemd_service);
+              /* systemd is not around, let's "activate" it. */
+              retval = bus_activation_activate_service (activation, connection, activation_transaction, TRUE,
+                                                        message, "org.freedesktop.systemd1", error);
+            }
 
           dbus_message_unref (message);
 
           if (!retval)
             {
+              bus_context_log (activation->context,
+                               DBUS_SYSTEM_LOG_INFO, "Failed to activate via systemd: service name='%s' unit='%s'",
+                               service_name,
+                               entry->systemd_service);
               _DBUS_ASSERT_ERROR_IS_SET (error);
               _dbus_verbose ("failed to send activation message: %s\n", error->name);
               bus_transaction_cancel_and_free (activation_transaction);
@@ -2068,13 +2079,29 @@
     }
 
   _dbus_verbose ("Spawning %s ...\n", argv[0]);
+  if (servicehelper != NULL)
+    bus_context_log (activation->context,
+                     DBUS_SYSTEM_LOG_INFO, "Activating service name='%s' (using servicehelper)",
+                     service_name);
+  else
+    bus_context_log (activation->context,
+                     DBUS_SYSTEM_LOG_INFO, "Activating service name='%s'",
+                     service_name);
+
+  dbus_error_init (&tmp_error);
+
   if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv,
                                           envp,
                                           NULL, activation,
-                                          error))
+                                          &tmp_error))
     {
       _dbus_verbose ("Failed to spawn child\n");
-      _DBUS_ASSERT_ERROR_IS_SET (error);
+      bus_context_log (activation->context,
+                       DBUS_SYSTEM_LOG_INFO, "Failed to activate service %s: %s",
+                       service_name,
+                       tmp_error.message);
+      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
+      dbus_move_error (&tmp_error, error);
       dbus_free_string_array (argv);
       dbus_free_string_array (envp);
 
@@ -2086,10 +2113,14 @@
 
   _dbus_assert (pending_activation->babysitter != NULL);
 
+  _dbus_babysitter_set_result_function (pending_activation->babysitter,
+                                        pending_activation_finished_cb,
+                                        pending_activation);
+
   if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
                                              add_babysitter_watch,
                                              remove_babysitter_watch,
-                                             NULL,
+                                             toggle_babysitter_watch,
                                              pending_activation,
                                              NULL))
     {
@@ -2165,10 +2196,16 @@
                              DBUS_TYPE_INVALID))
     dbus_set_error(&error, code, str);
 
+
   if (unit)
     {
       DBusHashIter iter;
 
+      bus_context_log (activation->context,
+                       DBUS_SYSTEM_LOG_INFO, "Activation via systemd failed for unit '%s': %s",
+                       unit,
+                       str);
+
       _dbus_hash_iter_init (activation->pending_activations,
                             &iter);
 
@@ -2511,14 +2548,18 @@
     _dbus_assert_not_reached ("could not initiate service reload test");
 
   if (!do_service_reload_test (&directory, FALSE))
-    ; /* Do nothing? */
+    {
+      /* Do nothing? */
+    }
 
   /* Do OOM tests */
   if (!init_service_reload_test (&directory))
     _dbus_assert_not_reached ("could not initiate service reload test");
 
   if (!do_service_reload_test (&directory, TRUE))
-    ; /* Do nothing? */
+    {
+      /* Do nothing? */
+    }
 
   /* Cleanup test directory */
   if (!cleanup_service_reload_test (&directory))
diff --git a/bus/bus.c b/bus/bus.c
index 4c67561..bc27f46 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -23,6 +23,9 @@
 
 #include <config.h>
 #include "bus.h"
+
+#include <stdio.h>
+
 #include "activation.h"
 #include "connection.h"
 #include "services.h"
@@ -36,6 +39,7 @@
 #include <dbus/dbus-hash.h>
 #include <dbus/dbus-credentials.h>
 #include <dbus/dbus-internals.h>
+
 #ifdef DBUS_CYGWIN
 #include <signal.h>
 #endif
@@ -101,19 +105,6 @@
 }
 
 static dbus_bool_t
-server_watch_callback (DBusWatch     *watch,
-                       unsigned int   condition,
-                       void          *data)
-{
-  /* FIXME this can be done in dbus-mainloop.c
-   * if the code in activation.c for the babysitter
-   * watch handler is fixed.
-   */
-
-  return dbus_watch_handle (watch, condition);
-}
-
-static dbus_bool_t
 add_server_watch (DBusWatch  *watch,
                   void       *data)
 {
@@ -122,9 +113,7 @@
 
   context = server_get_context (server);
 
-  return _dbus_loop_add_watch (context->loop,
-                               watch, server_watch_callback, server,
-                               NULL);
+  return _dbus_loop_add_watch (context->loop, watch);
 }
 
 static void
@@ -136,17 +125,19 @@
 
   context = server_get_context (server);
 
-  _dbus_loop_remove_watch (context->loop,
-                           watch, server_watch_callback, server);
+  _dbus_loop_remove_watch (context->loop, watch);
 }
 
-
 static void
-server_timeout_callback (DBusTimeout   *timeout,
-                         void          *data)
+toggle_server_watch (DBusWatch  *watch,
+                     void       *data)
 {
-  /* can return FALSE on OOM but we just let it fire again later */
-  dbus_timeout_handle (timeout);
+  DBusServer *server = data;
+  BusContext *context;
+
+  context = server_get_context (server);
+
+  _dbus_loop_toggle_watch (context->loop, watch);
 }
 
 static dbus_bool_t
@@ -158,8 +149,7 @@
 
   context = server_get_context (server);
 
-  return _dbus_loop_add_timeout (context->loop,
-                                 timeout, server_timeout_callback, server, NULL);
+  return _dbus_loop_add_timeout (context->loop, timeout);
 }
 
 static void
@@ -171,8 +161,7 @@
 
   context = server_get_context (server);
 
-  _dbus_loop_remove_timeout (context->loop,
-                             timeout, server_timeout_callback, server);
+  _dbus_loop_remove_timeout (context->loop, timeout);
 }
 
 static void
@@ -253,7 +242,7 @@
   if (!dbus_server_set_watch_functions (server,
                                         add_server_watch,
                                         remove_server_watch,
-                                        NULL,
+                                        toggle_server_watch,
                                         server,
                                         NULL))
     {
@@ -282,7 +271,7 @@
 process_config_first_time_only (BusContext       *context,
 				BusConfigParser  *parser,
                                 const DBusString *address,
-                                dbus_bool_t      systemd_activation,
+                                BusContextFlags   flags,
 				DBusError        *error)
 {
   DBusString log_prefix;
@@ -298,8 +287,14 @@
 
   retval = FALSE;
   auth_mechanisms = NULL;
+  pidfile = NULL;
 
-  context->systemd_activation = systemd_activation;
+  _dbus_init_system_log ();
+
+  if (flags & BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION)
+    context->systemd_activation = TRUE;
+  else
+    context->systemd_activation = FALSE;
 
 #ifdef WANT_PIDFILE
   /* Check for an existing pid file. Of course this is a race;
@@ -307,7 +302,10 @@
    * avoid that. But we want to check for the pid file
    * before overwriting any existing sockets, etc.
    */
-  pidfile = bus_config_parser_get_pidfile (parser);
+
+  if (flags & BUS_CONTEXT_FLAG_WRITE_PID_FILE)
+    pidfile = bus_config_parser_get_pidfile (parser);
+
   if (pidfile != NULL)
     {
       DBusString u;
@@ -376,11 +374,20 @@
       if (!credentials)
         goto oom;
       if (!_dbus_string_append (&log_prefix, "[session "))
-        goto oom;
+        {
+          _dbus_credentials_unref (credentials);
+          goto oom;
+        }
       if (!_dbus_credentials_to_string_append (credentials, &log_prefix))
-        goto oom;
+        {
+          _dbus_credentials_unref (credentials);
+          goto oom;
+        }
       if (!_dbus_string_append (&log_prefix, "] "))
-        goto oom;
+        {
+          _dbus_credentials_unref (credentials);
+          goto oom;
+        }
       _dbus_credentials_unref (credentials);
     }
   if (!_dbus_string_steal_data (&log_prefix, &context->log_prefix))
@@ -408,6 +415,7 @@
           if (auth_mechanisms[i] == NULL)
             goto oom;
           link = _dbus_list_get_next_link (auth_mechanisms_list, link);
+          i += 1;
         }
     }
   else
@@ -497,7 +505,6 @@
   DBusString full_address;
   DBusList *link;
   DBusList **dirs;
-  BusActivation *new_activation;
   char *addr;
   const char *servicehelper;
   char *s;
@@ -622,7 +629,6 @@
 
   *result = NULL;
 
-  link = _dbus_list_get_first_link (a);
   for (link = _dbus_list_get_first_link (a); link; link = _dbus_list_get_next_link (a, link))
     {
       if (!_dbus_list_append (result, link->data))
@@ -640,6 +646,24 @@
   return FALSE;
 }
 
+static void
+raise_file_descriptor_limit (BusContext      *context)
+{
+
+  /* I just picked this out of thin air; we need some extra
+   * descriptors for things like any internal pipes we create,
+   * inotify, connections to SELinux, etc.
+   */
+  unsigned int arbitrary_extra_fds = 32;
+  unsigned int limit;
+
+  limit = context->limits.max_completed_connections +
+    context->limits.max_incomplete_connections
+    + arbitrary_extra_fds;
+
+  _dbus_request_file_descriptor_limit (limit);
+}
+
 static dbus_bool_t
 process_config_postinit (BusContext      *context,
 			 BusConfigParser *parser,
@@ -648,6 +672,8 @@
   DBusHashTable *service_context_table;
   DBusList *watched_dirs = NULL;
 
+  raise_file_descriptor_limit (context);
+
   service_context_table = bus_config_parser_steal_service_context_table (parser);
   if (!bus_registry_set_service_context_table (context->registry,
 					       service_context_table))
@@ -678,17 +704,18 @@
 
 BusContext*
 bus_context_new (const DBusString *config_file,
-                 ForceForkSetting  force_fork,
+                 BusContextFlags   flags,
                  DBusPipe         *print_addr_pipe,
                  DBusPipe         *print_pid_pipe,
                  const DBusString *address,
-                 dbus_bool_t      systemd_activation,
                  DBusError        *error)
 {
-  DBusString log_prefix;
   BusContext *context;
   BusConfigParser *parser;
 
+  _dbus_assert ((flags & BUS_CONTEXT_FLAG_FORK_NEVER) == 0 ||
+                (flags & BUS_CONTEXT_FLAG_FORK_ALWAYS) == 0);
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   context = NULL;
@@ -737,7 +764,7 @@
       goto failed;
     }
 
-  if (!process_config_first_time_only (context, parser, address, systemd_activation, error))
+  if (!process_config_first_time_only (context, parser, address, flags, error))
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
       goto failed;
@@ -833,7 +860,8 @@
     if (context->pidfile)
       _dbus_string_init_const (&u, context->pidfile);
 
-    if ((force_fork != FORK_NEVER && context->fork) || force_fork == FORK_ALWAYS)
+    if (((flags & BUS_CONTEXT_FLAG_FORK_NEVER) == 0 && context->fork) ||
+        (flags & BUS_CONTEXT_FLAG_FORK_ALWAYS))
       {
         _dbus_verbose ("Forking and becoming daemon\n");
 
@@ -865,7 +893,8 @@
           }
       }
 #else
-    if ((force_fork != FORK_NEVER && context->fork) || force_fork == FORK_ALWAYS)
+    if (((flags & BUS_CONTEXT_FLAG_FORK_NEVER) == 0 && context->fork) ||
+        (flags & BUS_CONTEXT_FLAG_FORK_ALWAYS))
       {
         if (!_dbus_become_daemon (NULL,
                                   0,
@@ -1275,7 +1304,14 @@
   va_list args;
 
   if (!context->syslog)
-    return;
+    {
+      /* we're not syslogging; just output to stderr */
+      va_start (args, msg);
+      vfprintf (stderr, msg, args);
+      fprintf (stderr, "\n");
+      va_end (args);
+      return;
+    }
 
   va_start (args, msg);
 
@@ -1301,6 +1337,77 @@
   va_end (args);
 }
 
+static inline const char *
+nonnull (const char *maybe_null,
+         const char *if_null)
+{
+  return (maybe_null ? maybe_null : if_null);
+}
+
+/*
+ * Log something about a message, usually that it was rejected.
+ */
+static void
+complain_about_message (BusContext     *context,
+                        const char     *error_name,
+                        const char     *complaint,
+                        int             matched_rules,
+                        DBusMessage    *message,
+                        DBusConnection *sender,
+                        DBusConnection *proposed_recipient,
+                        dbus_bool_t     requested_reply,
+                        dbus_bool_t     log,
+                        DBusError      *error)
+{
+  DBusError stack_error = DBUS_ERROR_INIT;
+  const char *sender_name;
+  const char *sender_loginfo;
+  const char *proposed_recipient_loginfo;
+
+  if (error == NULL && !log)
+    return;
+
+  if (sender != NULL)
+    {
+      sender_name = bus_connection_get_name (sender);
+      sender_loginfo = bus_connection_get_loginfo (sender);
+    }
+  else
+    {
+      sender_name = "(unset)";
+      sender_loginfo = "(bus)";
+    }
+
+  if (proposed_recipient != NULL)
+    proposed_recipient_loginfo = bus_connection_get_loginfo (proposed_recipient);
+  else
+    proposed_recipient_loginfo = "bus";
+
+  dbus_set_error (&stack_error, error_name,
+      "%s, %d matched rules; type=\"%s\", sender=\"%s\" (%s) "
+      "interface=\"%s\" member=\"%s\" error name=\"%s\" "
+      "requested_reply=\"%d\" destination=\"%s\" (%s)",
+      complaint,
+      matched_rules,
+      dbus_message_type_to_string (dbus_message_get_type (message)),
+      sender_name,
+      sender_loginfo,
+      nonnull (dbus_message_get_interface (message), "(unset)"),
+      nonnull (dbus_message_get_member (message), "(unset)"),
+      nonnull (dbus_message_get_error_name (message), "(unset)"),
+      requested_reply,
+      nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS),
+      proposed_recipient_loginfo);
+
+  /* If we hit OOM while setting the error, this will syslog "out of memory"
+   * which is itself an indication that something is seriously wrong */
+  if (log)
+    bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY, "%s",
+        stack_error.message);
+
+  dbus_move_error (&stack_error, error);
+}
+
 /*
  * addressed_recipient is the recipient specified in the message.
  *
@@ -1330,9 +1437,6 @@
   dbus_bool_t log;
   int type;
   dbus_bool_t requested_reply;
-  const char *sender_name;
-  const char *sender_loginfo;
-  const char *proposed_recipient_loginfo;
 
   type = dbus_message_get_type (message);
   dest = dbus_message_get_destination (message);
@@ -1345,23 +1449,6 @@
                 addressed_recipient != NULL ||
                 strcmp (dest, DBUS_SERVICE_DBUS) == 0);
 
-  /* Used in logging below */
-  if (sender != NULL)
-    {
-      sender_name = bus_connection_get_name (sender);
-      sender_loginfo = bus_connection_get_loginfo (sender);
-    }
-  else
-    {
-      sender_name = NULL;
-      sender_loginfo = "(bus)";
-    }
-
-  if (proposed_recipient != NULL)
-    proposed_recipient_loginfo = bus_connection_get_loginfo (proposed_recipient);
-  else
-    proposed_recipient_loginfo = "bus";
-
   switch (type)
     {
     case DBUS_MESSAGE_TYPE_METHOD_CALL:
@@ -1396,19 +1483,12 @@
         {
           if (error != NULL && !dbus_error_is_set (error))
             {
-              dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
-                              "An SELinux policy prevents this sender "
-                              "from sending this message to this recipient "
-                              "(rejected message had sender \"%s\" interface \"%s\" "
-                              "member \"%s\" error name \"%s\" destination \"%s\")",
-                              sender_name ? sender_name : "(unset)",
-                              dbus_message_get_interface (message) ?
-                              dbus_message_get_interface (message) : "(unset)",
-                              dbus_message_get_member (message) ?
-                              dbus_message_get_member (message) : "(unset)",
-                              dbus_message_get_error_name (message) ?
-                              dbus_message_get_error_name (message) : "(unset)",
-                              dest ? dest : DBUS_SERVICE_DBUS);
+              /* don't syslog this, just set the error: avc_has_perm should
+               * have already written to either the audit log or syslog */
+              complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+                  "An SELinux policy prevents this sender from sending this "
+                  "message to this recipient",
+                  0, message, sender, proposed_recipient, FALSE, FALSE, error);
               _dbus_verbose ("SELinux security check denying send to service\n");
             }
 
@@ -1522,60 +1602,23 @@
                                          proposed_recipient,
                                          message, &toggles, &log))
     {
-      const char *msg = "Rejected send message, %d matched rules; "
-                        "type=\"%s\", sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" error name=\"%s\" requested_reply=%d destination=\"%s\" (%s))";
-
-      dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, msg,
-                      toggles,
-                      dbus_message_type_to_string (dbus_message_get_type (message)),
-                      sender_name ? sender_name : "(unset)",
-                      sender_loginfo,
-                      dbus_message_get_interface (message) ?
-                      dbus_message_get_interface (message) : "(unset)",
-                      dbus_message_get_member (message) ?
-                      dbus_message_get_member (message) : "(unset)",
-                      dbus_message_get_error_name (message) ?
-                      dbus_message_get_error_name (message) : "(unset)",
-                      requested_reply,
-                      dest ? dest : DBUS_SERVICE_DBUS,
-                      proposed_recipient_loginfo);
-      /* Needs to be duplicated to avoid calling malloc and having to handle OOM */
-      if (addressed_recipient == proposed_recipient)
-        bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY, msg,
-                                  toggles,
-                                  dbus_message_type_to_string (dbus_message_get_type (message)),
-                                  sender_name ? sender_name : "(unset)",
-                                  sender_loginfo,
-                                  dbus_message_get_interface (message) ?
-                                  dbus_message_get_interface (message) : "(unset)",
-                                  dbus_message_get_member (message) ?
-                                  dbus_message_get_member (message) : "(unset)",
-                                  dbus_message_get_error_name (message) ?
-                                  dbus_message_get_error_name (message) : "(unset)",
-                                  requested_reply,
-                                  dest ? dest : DBUS_SERVICE_DBUS,
-                                  proposed_recipient_loginfo);
+      complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+          "Rejected send message", toggles,
+          message, sender, proposed_recipient, requested_reply,
+          (addressed_recipient == proposed_recipient), error);
       _dbus_verbose ("security policy disallowing message due to sender policy\n");
       return FALSE;
     }
 
   if (log)
-    bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY,
-                              "Would reject message, %d matched rules; "
-                              "type=\"%s\", sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" error name=\"%s\" requested_reply=%d destination=\"%s\" (%s))",
-                              toggles,
-                              dbus_message_type_to_string (dbus_message_get_type (message)),
-                              sender_name ? sender_name : "(unset)",
-                              sender_loginfo,
-                              dbus_message_get_interface (message) ?
-                              dbus_message_get_interface (message) : "(unset)",
-                              dbus_message_get_member (message) ?
-                              dbus_message_get_member (message) : "(unset)",
-                              dbus_message_get_error_name (message) ?
-                              dbus_message_get_error_name (message) : "(unset)",
-                              requested_reply,
-                              dest ? dest : DBUS_SERVICE_DBUS,
-                              proposed_recipient_loginfo);
+    {
+      /* We want to drop this message, and are only not doing so for backwards
+       * compatibility. */
+      complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+          "Would reject message", toggles,
+          message, sender, proposed_recipient, requested_reply,
+          TRUE, NULL);
+    }
 
   if (recipient_policy &&
       !bus_client_policy_check_can_receive (recipient_policy,
@@ -1585,41 +1628,10 @@
                                             addressed_recipient, proposed_recipient,
                                             message, &toggles))
     {
-      const char *msg = "Rejected receive message, %d matched rules; "
-                        "type=\"%s\" sender=\"%s\" (%s) interface=\"%s\" member=\"%s\" error name=\"%s\" reply serial=%u requested_reply=%d destination=\"%s\" (%s))";
-
-      dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, msg,
-                      toggles,
-                      dbus_message_type_to_string (dbus_message_get_type (message)),
-                      sender_name ? sender_name : "(unset)",
-                      sender_loginfo,
-                      dbus_message_get_interface (message) ?
-                      dbus_message_get_interface (message) : "(unset)",
-                      dbus_message_get_member (message) ?
-                      dbus_message_get_member (message) : "(unset)",
-                      dbus_message_get_error_name (message) ?
-                      dbus_message_get_error_name (message) : "(unset)",
-                      dbus_message_get_reply_serial (message),
-                      requested_reply,
-                      dest ? dest : DBUS_SERVICE_DBUS,
-                      proposed_recipient_loginfo);
-      /* Needs to be duplicated to avoid calling malloc and having to handle OOM */
-      if (addressed_recipient == proposed_recipient)
-        bus_context_log (context, DBUS_SYSTEM_LOG_SECURITY, msg,
-                                  toggles,
-                                  dbus_message_type_to_string (dbus_message_get_type (message)),
-                                  sender_name ? sender_name : "(unset)",
-                                  sender_loginfo,
-                                  dbus_message_get_interface (message) ?
-                                  dbus_message_get_interface (message) : "(unset)",
-                                  dbus_message_get_member (message) ?
-                                  dbus_message_get_member (message) : "(unset)",
-                                  dbus_message_get_error_name (message) ?
-                                  dbus_message_get_error_name (message) : "(unset)",
-                                  dbus_message_get_reply_serial (message),
-                                  requested_reply,
-                                  dest ? dest : DBUS_SERVICE_DBUS,
-                                  proposed_recipient_loginfo);
+      complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+          "Rejected receive message", toggles,
+          message, sender, proposed_recipient, requested_reply,
+          (addressed_recipient == proposed_recipient), NULL);
       _dbus_verbose ("security policy disallowing message due to recipient policy\n");
       return FALSE;
     }
@@ -1629,11 +1641,10 @@
       ((dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
        (dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
     {
-      dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
-                      "The destination service \"%s\" has a full message queue",
-                      dest ? dest : (proposed_recipient ?
-                                     bus_connection_get_name (proposed_recipient) :
-                                     DBUS_SERVICE_DBUS));
+      complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
+          "Rejected: destination has a full message queue",
+          0, message, sender, proposed_recipient, requested_reply, TRUE,
+          error);
       _dbus_verbose ("security policy disallowing message due to full message queue\n");
       return FALSE;
     }
diff --git a/bus/bus.h b/bus/bus.h
index ebef17c..3597884 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -66,17 +66,18 @@
 
 typedef enum
 {
-  FORK_FOLLOW_CONFIG_FILE,
-  FORK_ALWAYS,
-  FORK_NEVER
-} ForceForkSetting;
+  BUS_CONTEXT_FLAG_NONE = 0,
+  BUS_CONTEXT_FLAG_FORK_ALWAYS = (1 << 1),
+  BUS_CONTEXT_FLAG_FORK_NEVER = (1 << 2),
+  BUS_CONTEXT_FLAG_WRITE_PID_FILE = (1 << 3),
+  BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION = (1 << 4)
+} BusContextFlags;
 
 BusContext*       bus_context_new                                (const DBusString *config_file,
-                                                                  ForceForkSetting  force_fork,
+                                                                  BusContextFlags   flags,
                                                                   DBusPipe         *print_addr_pipe,
                                                                   DBusPipe         *print_pid_pipe,
                                                                   const DBusString *address,
-                                                                  dbus_bool_t      systemd_activation,
                                                                   DBusError        *error);
 dbus_bool_t       bus_context_reload_config                      (BusContext       *context,
 								  DBusError        *error);
diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
index f8d75be..c522ff4 100644
--- a/bus/config-parser-common.c
+++ b/bus/config-parser-common.c
@@ -49,7 +49,7 @@
     }
   else if (strcmp (name, "type") == 0)
     {
-      return ELEMENT_TYPE;
+      return ELEMENT_CONFIGTYPE;
     }
   else if (strcmp (name, "fork") == 0)
     {
@@ -169,7 +169,7 @@
       return "servicehelper";
     case ELEMENT_INCLUDEDIR:
       return "includedir";
-    case ELEMENT_TYPE:
+    case ELEMENT_CONFIGTYPE:
       return "type";
     case ELEMENT_SELINUX:
       return "selinux";
diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
index da74560..186bf4c 100644
--- a/bus/config-parser-common.h
+++ b/bus/config-parser-common.h
@@ -41,7 +41,8 @@
   ELEMENT_SERVICEDIR,
   ELEMENT_SERVICEHELPER,
   ELEMENT_INCLUDEDIR,
-  ELEMENT_TYPE,
+  /* this is really <type>, but winioctl.h defines ELEMENT_TYPE */
+  ELEMENT_CONFIGTYPE,
   ELEMENT_SELINUX,
   ELEMENT_ASSOCIATE,
   ELEMENT_STANDARD_SESSION_SERVICEDIRS,
diff --git a/bus/config-parser-trivial.c b/bus/config-parser-trivial.c
index 59ec2ba..6ef50f8 100644
--- a/bus/config-parser-trivial.c
+++ b/bus/config-parser-trivial.c
@@ -164,7 +164,7 @@
     {
     case ELEMENT_SERVICEHELPER:
     case ELEMENT_USER:
-    case ELEMENT_TYPE:
+    case ELEMENT_CONFIGTYPE:
       /* content about to be handled */
       break;
 
@@ -188,7 +188,7 @@
     default:
       {
         /* we really don't care about the others... */
-        _dbus_verbose (" START We dont care about '%s' type '%i'\n", element_name, parser->type);
+        _dbus_verbose (" START We don't care about '%s' type '%i'\n", element_name, parser->type);
         break;
       }
     }
@@ -277,7 +277,7 @@
       }
       break;
 
-    case ELEMENT_TYPE:
+    case ELEMENT_CONFIGTYPE:
       {
         if (!_dbus_string_copy (&content_sane, 0, &parser->bus_type, 0))
           {
@@ -289,7 +289,7 @@
     default:
       {
         /* we don't care about the others... really */
-        _dbus_verbose (" CONTENTS We dont care '%s' type '%i'\n", _dbus_string_get_const_data (&content_sane), parser->type);
+        _dbus_verbose (" CONTENTS We don't care about '%s' type '%i'\n", _dbus_string_get_const_data (&content_sane), parser->type);
         break;
       }
     }
diff --git a/bus/config-parser.c b/bus/config-parser.c
index 26f732a..07e8fbb 100644
--- a/bus/config-parser.c
+++ b/bus/config-parser.c
@@ -30,6 +30,7 @@
 #include "selinux.h"
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-internals.h>
+#include <dbus/dbus-sysdeps.h>
 #include <string.h>
 
 typedef enum
@@ -689,12 +690,12 @@
 
       return TRUE;
     }
-  else if (element_type == ELEMENT_TYPE)
+  else if (element_type == ELEMENT_CONFIGTYPE)
     {
       if (!check_no_attributes (parser, "type", attribute_names, attribute_values, error))
         return FALSE;
 
-      if (push_element (parser, ELEMENT_TYPE) == NULL)
+      if (push_element (parser, ELEMENT_CONFIGTYPE) == NULL)
         {
           BUS_SET_OOM (error);
           return FALSE;
@@ -1153,6 +1154,7 @@
   const char *send_requested_reply;
   const char *receive_requested_reply;
   const char *own;
+  const char *own_prefix;
   const char *user;
   const char *group;
 
@@ -1178,6 +1180,7 @@
                           "send_requested_reply", &send_requested_reply,
                           "receive_requested_reply", &receive_requested_reply,
                           "own", &own,
+                          "own_prefix", &own_prefix,
                           "user", &user,
                           "group", &group,
                           "log", &log,
@@ -1189,7 +1192,7 @@
         receive_interface || receive_member || receive_error || receive_sender ||
         receive_type || receive_path || eavesdrop ||
         send_requested_reply || receive_requested_reply ||
-        own || user || group))
+        own || own_prefix || user || group))
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Element <%s> must have one or more attributes",
@@ -1217,102 +1220,103 @@
    *   base send_ can combine with send_destination, send_path, send_type, send_requested_reply
    *   base receive_ with receive_sender, receive_path, receive_type, receive_requested_reply, eavesdrop
    *
-   *   user, group, own must occur alone
+   *   user, group, own, own_prefix must occur alone
    *
    * Pretty sure the below stuff is broken, FIXME think about it more.
    */
 
-  if (((send_interface && send_error) ||
-       (send_interface && receive_interface) ||
-       (send_interface && receive_member) ||
-       (send_interface && receive_error) ||
-       (send_interface && receive_sender) ||
-       (send_interface && receive_requested_reply) ||
-       (send_interface && own) ||
-       (send_interface && user) ||
-       (send_interface && group)) ||
+  if ((send_interface && (send_error ||
+                          receive_interface ||
+                          receive_member ||
+                          receive_error ||
+                          receive_sender ||
+                          receive_requested_reply ||
+                          own || own_prefix ||
+                          user ||
+                          group)) ||
 
-      ((send_member && send_error) ||
-       (send_member && receive_interface) ||
-       (send_member && receive_member) ||
-       (send_member && receive_error) ||
-       (send_member && receive_sender) ||
-       (send_member && receive_requested_reply) ||
-       (send_member && own) ||
-       (send_member && user) ||
-       (send_member && group)) ||
-      
-      ((send_error && receive_interface) ||
-       (send_error && receive_member) ||
-       (send_error && receive_error) ||
-       (send_error && receive_sender) ||
-       (send_error && receive_requested_reply) ||
-       (send_error && own) ||
-       (send_error && user) ||
-       (send_error && group)) ||
+      (send_member && (send_error ||
+                       receive_interface ||
+                       receive_member ||
+                       receive_error ||
+                       receive_sender ||
+                       receive_requested_reply ||
+                       own || own_prefix ||
+                       user ||
+                       group)) ||
 
-      ((send_destination && receive_interface) ||
-       (send_destination && receive_member) ||
-       (send_destination && receive_error) ||
-       (send_destination && receive_sender) ||
-       (send_destination && receive_requested_reply) ||
-       (send_destination && own) ||
-       (send_destination && user) ||
-       (send_destination && group)) ||
+      (send_error && (receive_interface ||
+                      receive_member ||
+                      receive_error ||
+                      receive_sender ||
+                      receive_requested_reply ||
+                      own || own_prefix ||
+                      user ||
+                      group)) ||
 
-      ((send_type && receive_interface) ||
-       (send_type && receive_member) ||
-       (send_type && receive_error) ||
-       (send_type && receive_sender) ||
-       (send_type && receive_requested_reply) ||
-       (send_type && own) ||
-       (send_type && user) ||
-       (send_type && group)) ||
+      (send_destination && (receive_interface ||
+                            receive_member ||
+                            receive_error ||
+                            receive_sender ||
+                            receive_requested_reply ||
+                            own || own_prefix ||
+                            user ||
+                            group)) ||
 
-      ((send_path && receive_interface) ||
-       (send_path && receive_member) ||
-       (send_path && receive_error) ||
-       (send_path && receive_sender) ||
-       (send_path && receive_requested_reply) ||
-       (send_path && own) ||
-       (send_path && user) ||
-       (send_path && group)) ||
+      (send_type && (receive_interface ||
+                     receive_member ||
+                     receive_error ||
+                     receive_sender ||
+                     receive_requested_reply ||
+                     own || own_prefix ||
+                     user ||
+                     group)) ||
 
-      ((send_requested_reply && receive_interface) ||
-       (send_requested_reply && receive_member) ||
-       (send_requested_reply && receive_error) ||
-       (send_requested_reply && receive_sender) ||
-       (send_requested_reply && receive_requested_reply) ||
-       (send_requested_reply && own) ||
-       (send_requested_reply && user) ||
-       (send_requested_reply && group)) ||
-      
-      ((receive_interface && receive_error) ||
-       (receive_interface && own) ||
-       (receive_interface && user) ||
-       (receive_interface && group)) ||
+      (send_path && (receive_interface ||
+                     receive_member ||
+                     receive_error ||
+                     receive_sender ||
+                     receive_requested_reply ||
+                     own || own_prefix ||
+                     user ||
+                     group)) ||
 
-      ((receive_member && receive_error) ||
-       (receive_member && own) ||
-       (receive_member && user) ||
-       (receive_member && group)) ||
-      
-      ((receive_error && own) ||
-       (receive_error && user) ||
-       (receive_error && group)) ||
+      (send_requested_reply && (receive_interface ||
+                                receive_member ||
+                                receive_error ||
+                                receive_sender ||
+                                receive_requested_reply ||
+                                own || own_prefix ||
+                                user ||
+                                group)) ||
 
-      ((eavesdrop && own) ||
-       (eavesdrop && user) ||
-       (eavesdrop && group)) ||
+      (receive_interface && (receive_error ||
+                             own || own_prefix ||
+                             user ||
+                             group)) ||
 
-      ((receive_requested_reply && own) ||
-       (receive_requested_reply && user) ||
-       (receive_requested_reply && group)) ||
-      
-      ((own && user) ||
-       (own && group)) ||
+      (receive_member && (receive_error ||
+                          own || own_prefix ||
+                          user ||
+                          group)) ||
 
-      ((user && group)))
+      (receive_error && (own || own_prefix ||
+                         user ||
+                         group)) ||
+
+      (eavesdrop && (own || own_prefix ||
+                     user ||
+                     group)) ||
+
+      (receive_requested_reply && (own || own_prefix ||
+                                   user ||
+                                   group)) ||
+
+      (own && (own_prefix || user || group)) ||
+
+      (own_prefix && (own || user || group)) ||
+
+      (user && group))
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Invalid combination of attributes on element <%s>",
@@ -1488,18 +1492,29 @@
       if (receive_sender && rule->d.receive.origin == NULL)
         goto nomem;
     }
-  else if (own)
+  else if (own || own_prefix)
     {
       rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow); 
       if (rule == NULL)
         goto nomem;
 
-      if (IS_WILDCARD (own))
-        own = NULL;
+      if (own)
+        {
+          if (IS_WILDCARD (own))
+            own = NULL;
       
-      rule->d.own.service_name = _dbus_strdup (own);
-      if (own && rule->d.own.service_name == NULL)
-        goto nomem;
+          rule->d.own.prefix = 0;
+          rule->d.own.service_name = _dbus_strdup (own);
+          if (own && rule->d.own.service_name == NULL)
+            goto nomem;
+        }
+      else
+        {
+          rule->d.own.prefix = 1;
+          rule->d.own.service_name = _dbus_strdup (own_prefix);
+          if (rule->d.own.service_name == NULL)
+            goto nomem;
+        }
     }
   else if (user)
     {      
@@ -2001,7 +2016,7 @@
 
     case ELEMENT_INCLUDE:
     case ELEMENT_USER:
-    case ELEMENT_TYPE:
+    case ELEMENT_CONFIGTYPE:
     case ELEMENT_LISTEN:
     case ELEMENT_PIDFILE:
     case ELEMENT_AUTH:
@@ -2117,7 +2132,7 @@
 
   if (included == NULL)
     {
-      _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&tmp_error);
+      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
 
       if (dbus_error_has_name (&tmp_error, DBUS_ERROR_FILE_NOT_FOUND) &&
           ignore_missing)
@@ -2133,7 +2148,7 @@
     }
   else
     {
-      _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&tmp_error);
+      _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
 
       if (!merge_included (parser, included, error))
         {
@@ -2236,8 +2251,19 @@
         {
           if (!include_file (parser, &full_path, TRUE, error))
             {
-              _dbus_string_free (&full_path);
-              goto failed;
+              if (dbus_error_is_set (error))
+                {
+                  /* We log to syslog unconditionally here, because this is
+                   * the configuration parser, so we don't yet know whether
+                   * this bus is going to want to write to syslog! (There's
+                   * also some layer inversion going on, if we want to use
+                   * the bus context.) */
+                  _dbus_system_log (DBUS_SYSTEM_LOG_INFO,
+                                    "Encountered error '%s' while parsing '%s'\n",
+                                    error->message,
+                                    _dbus_string_get_const_data (&full_path));
+                  dbus_error_free (error);
+                }
             }
         }
 
@@ -2460,7 +2486,7 @@
       }
       break;
 
-    case ELEMENT_TYPE:
+    case ELEMENT_CONFIGTYPE:
       {
         char *s;
 
@@ -2720,9 +2746,60 @@
 } Validity;
 
 static dbus_bool_t
+do_check_own_rules (BusPolicy  *policy)
+{
+  const struct {
+    char *name;
+    dbus_bool_t allowed;
+  } checks[] = {
+    {"org.freedesktop", FALSE},
+    {"org.freedesktop.ManySystem", FALSE},
+    {"org.freedesktop.ManySystems", TRUE},
+    {"org.freedesktop.ManySystems.foo", TRUE},
+    {"org.freedesktop.ManySystems.foo.bar", TRUE},
+    {"org.freedesktop.ManySystems2", FALSE},
+    {"org.freedesktop.ManySystems2.foo", FALSE},
+    {"org.freedesktop.ManySystems2.foo.bar", FALSE},
+    {NULL, FALSE}
+  };
+  int i = 0;
+
+  while (checks[i].name)
+    {
+      DBusString service_name;
+      dbus_bool_t ret;
+
+      if (!_dbus_string_init (&service_name))
+        _dbus_assert_not_reached ("couldn't init string");
+      if (!_dbus_string_append (&service_name, checks[i].name))
+        _dbus_assert_not_reached ("couldn't append string");
+
+      ret = bus_policy_check_can_own (policy, &service_name);
+      printf ("        Check name %s: %s\n", checks[i].name,
+              ret ? "allowed" : "not allowed");
+      if (checks[i].allowed && !ret)
+        {
+          _dbus_warn ("Cannot own %s\n", checks[i].name);
+          return FALSE;
+        }
+      if (!checks[i].allowed && ret)
+        {
+          _dbus_warn ("Can own %s\n", checks[i].name);
+          return FALSE;
+        }
+      _dbus_string_free (&service_name);
+
+      i++;
+    }
+
+  return TRUE;
+}
+
+static dbus_bool_t
 do_load (const DBusString *full_path,
          Validity          validity,
-         dbus_bool_t       oom_possible)
+         dbus_bool_t       oom_possible,
+         dbus_bool_t       check_own_rules)
 {
   BusConfigParser *parser;
   DBusError error;
@@ -2759,6 +2836,11 @@
     {
       _DBUS_ASSERT_ERROR_IS_CLEAR (&error);
 
+      if (check_own_rules && do_check_own_rules (parser->policy) == FALSE)
+        {
+          return FALSE;
+        }
+
       bus_config_parser_unref (parser);
 
       if (validity == INVALID)
@@ -2775,6 +2857,7 @@
 {
   const DBusString *full_path;
   Validity          validity;
+  dbus_bool_t       check_own_rules;
 } LoaderOomData;
 
 static dbus_bool_t
@@ -2782,7 +2865,7 @@
 {
   LoaderOomData *d = data;
 
-  return do_load (d->full_path, d->validity, TRUE);
+  return do_load (d->full_path, d->validity, TRUE, d->check_own_rules);
 }
 
 static dbus_bool_t
@@ -2865,6 +2948,8 @@
 
       d.full_path = &full_path;
       d.validity = validity;
+      d.check_own_rules = _dbus_string_ends_with_c_str (&full_path,
+          "check-own-rules.conf");
 
       /* FIXME hackaround for an expat problem, see
        * https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=124747
@@ -3241,15 +3326,15 @@
 static const char *test_session_service_dir_matches[] = 
         {
 #ifdef DBUS_UNIX
+         "/testhome/foo/.testlocal/testshare/dbus-1/services",
          "/testusr/testlocal/testshare/dbus-1/services",
          "/testusr/testshare/dbus-1/services",
-#endif
          DBUS_DATADIR"/dbus-1/services",
-#ifdef DBUS_UNIX
-         "/testhome/foo/.testlocal/testshare/dbus-1/services",
 #endif
+/* will be filled in test_default_session_servicedirs() */
 #ifdef DBUS_WIN
          NULL,
+         NULL,
 #endif
          NULL
         };
@@ -3260,16 +3345,28 @@
   DBusList *dirs;
   DBusList *link;
   DBusString progs;
-  const char *common_progs;
   int i;
 
+#ifdef DBUS_WIN
+  const char *common_progs;
+  char buffer[1024];
+
+  if (_dbus_get_install_root(buffer, sizeof(buffer)))
+    {
+      strcat(buffer,DBUS_DATADIR);
+      strcat(buffer,"/dbus-1/services");
+      test_session_service_dir_matches[0] = buffer;
+    }
+#endif
+
   /* On Unix we don't actually use this variable, but it's easier to handle the
    * deallocation if we always allocate it, whether needed or not */
   if (!_dbus_string_init (&progs))
     _dbus_assert_not_reached ("OOM allocating progs");
 
-  common_progs = _dbus_getenv ("CommonProgramFiles");
 #ifndef DBUS_UNIX
+  common_progs = _dbus_getenv ("CommonProgramFiles");
+
   if (common_progs) 
     {
       if (!_dbus_string_append (&progs, common_progs)) 
@@ -3370,10 +3467,14 @@
 static const char *test_system_service_dir_matches[] = 
         {
 #ifdef DBUS_UNIX
-         "/testusr/testlocal/testshare/dbus-1/system-services",
-         "/testusr/testshare/dbus-1/system-services",
+         "/usr/local/share/dbus-1/system-services",
+         "/usr/share/dbus-1/system-services",
 #endif
          DBUS_DATADIR"/dbus-1/system-services",
+#ifdef DBUS_UNIX
+         "/lib/dbus-1/system-services",
+#endif
+
 #ifdef DBUS_WIN
          NULL,
 #endif
@@ -3386,7 +3487,9 @@
   DBusList *dirs;
   DBusList *link;
   DBusString progs;
+#ifndef DBUS_UNIX
   const char *common_progs;
+#endif
   int i;
 
   /* On Unix we don't actually use this variable, but it's easier to handle the
@@ -3394,8 +3497,9 @@
   if (!_dbus_string_init (&progs))
     _dbus_assert_not_reached ("OOM allocating progs");
 
-  common_progs = _dbus_getenv ("CommonProgramFiles");
 #ifndef DBUS_UNIX
+  common_progs = _dbus_getenv ("CommonProgramFiles");
+
   if (common_progs) 
     {
       if (!_dbus_string_append (&progs, common_progs)) 
@@ -3526,3 +3630,4 @@
 }
 
 #endif /* DBUS_BUILD_TESTS */
+
diff --git a/bus/connection.c b/bus/connection.c
index 1e65ef3..d69758c 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -62,6 +62,16 @@
   DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */
   int stamp;                   /**< Incrementing number */
   BusExpireList *pending_replies; /**< List of pending replies */
+
+#ifdef DBUS_ENABLE_STATS
+  int total_match_rules;
+  int peak_match_rules;
+  int peak_match_rules_per_conn;
+
+  int total_bus_names;
+  int peak_bus_names;
+  int peak_bus_names_per_conn;
+#endif
 };
 
 static dbus_int32_t connection_data_slot = -1;
@@ -87,6 +97,11 @@
   long connection_tv_sec;  /**< Time when we connected (seconds component) */
   long connection_tv_usec; /**< Time when we connected (microsec component) */
   int stamp;               /**< connections->stamp last time we were traversed */
+
+#ifdef DBUS_ENABLE_STATS
+  int peak_match_rules;
+  int peak_bus_names;
+#endif
 } BusConnectionData;
 
 static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
@@ -211,7 +226,7 @@
       if (!bus_service_remove_owner (service, connection,
                                      transaction, &error))
         {
-          _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&error);
+          _DBUS_ASSERT_ERROR_IS_SET (&error);
           
           if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
             {
@@ -295,30 +310,12 @@
 }
 
 static dbus_bool_t
-connection_watch_callback (DBusWatch     *watch,
-                           unsigned int   condition,
-                           void          *data)
-{
- /* FIXME this can be done in dbus-mainloop.c
-  * if the code in activation.c for the babysitter
-  * watch handler is fixed.
-  */
-  
-#if 0
-  _dbus_verbose ("Calling handle_watch\n");
-#endif
-  return dbus_watch_handle (watch, condition);
-}
-
-static dbus_bool_t
 add_connection_watch (DBusWatch      *watch,
                       void           *data)
 {
   DBusConnection *connection = data;
 
-  return _dbus_loop_add_watch (connection_get_loop (connection),
-                               watch, connection_watch_callback, connection,
-                               NULL);
+  return _dbus_loop_add_watch (connection_get_loop (connection), watch);
 }
 
 static void
@@ -327,18 +324,16 @@
 {
   DBusConnection *connection = data;
   
-  _dbus_loop_remove_watch (connection_get_loop (connection),
-                           watch, connection_watch_callback, connection);
+  _dbus_loop_remove_watch (connection_get_loop (connection), watch);
 }
 
 static void
-connection_timeout_callback (DBusTimeout   *timeout,
-                             void          *data)
+toggle_connection_watch (DBusWatch      *watch,
+                         void           *data)
 {
-  /* DBusConnection *connection = data; */
+  DBusConnection *connection = data;
 
-  /* can return FALSE on OOM but we just let it fire again later */
-  dbus_timeout_handle (timeout);
+  _dbus_loop_toggle_watch (connection_get_loop (connection), watch);
 }
 
 static dbus_bool_t
@@ -347,8 +342,7 @@
 {
   DBusConnection *connection = data;
   
-  return _dbus_loop_add_timeout (connection_get_loop (connection),
-                                 timeout, connection_timeout_callback, connection, NULL);
+  return _dbus_loop_add_timeout (connection_get_loop (connection), timeout);
 }
 
 static void
@@ -357,8 +351,7 @@
 {
   DBusConnection *connection = data;
   
-  _dbus_loop_remove_timeout (connection_get_loop (connection),
-                             timeout, connection_timeout_callback, connection);
+  _dbus_loop_remove_timeout (connection_get_loop (connection), timeout);
 }
 
 static void
@@ -419,14 +412,6 @@
   dbus_free (d);
 }
 
-static void
-call_timeout_callback (DBusTimeout   *timeout,
-                       void          *data)
-{
-  /* can return FALSE on OOM but we just let it fire again later */
-  dbus_timeout_handle (timeout);
-}
-
 BusConnections*
 bus_connections_new (BusContext *context)
 {
@@ -460,8 +445,7 @@
     goto failed_4;
   
   if (!_dbus_loop_add_timeout (bus_context_get_loop (context),
-                               connections->expire_timeout,
-                               call_timeout_callback, NULL, NULL))
+                               connections->expire_timeout))
     goto failed_5;
   
   connections->refcount = 1;
@@ -532,8 +516,7 @@
       bus_expire_list_free (connections->pending_replies);
       
       _dbus_loop_remove_timeout (bus_context_get_loop (connections->context),
-                                 connections->expire_timeout,
-                                 call_timeout_callback, NULL);
+                                 connections->expire_timeout);
       
       _dbus_timeout_unref (connections->expire_timeout);
       
@@ -586,9 +569,12 @@
 
   if (dbus_connection_get_windows_user (connection, &windows_sid))
     {
-      if (!_dbus_string_append_printf (&loginfo_buf, "sid=\"%s\" ", windows_sid))
-        goto oom;
+      dbus_bool_t did_append;
+      did_append = _dbus_string_append_printf (&loginfo_buf,
+                                               "sid=\"%s\" ", windows_sid);
       dbus_free (windows_sid);
+      if (!did_append)
+        goto oom;
     }
 
   if (!_dbus_string_steal_data (&loginfo_buf, &(d->cached_loginfo_string)))
@@ -620,8 +606,8 @@
   d->connections = connections;
   d->connection = connection;
   
-  _dbus_get_current_time (&d->connection_tv_sec,
-                          &d->connection_tv_usec);
+  _dbus_get_monotonic_time (&d->connection_tv_sec,
+                            &d->connection_tv_usec);
   
   _dbus_assert (connection_data_slot >= 0);
   
@@ -654,7 +640,7 @@
   if (!dbus_connection_set_watch_functions (connection,
                                             add_connection_watch,
                                             remove_connection_watch,
-                                            NULL,
+                                            toggle_connection_watch,
                                             connection,
                                             NULL))
     goto out;
@@ -790,7 +776,7 @@
       DBusList *link;
       int auth_timeout;
       
-      _dbus_get_current_time (&tv_sec, &tv_usec);
+      _dbus_get_monotonic_time (&tv_sec, &tv_usec);
       auth_timeout = bus_context_get_auth_timeout (connections->context);
   
       link = _dbus_list_get_first_link (&connections->incomplete);
@@ -853,12 +839,7 @@
                                  int              *n_groups,
                                  DBusError        *error)
 {
-  BusConnectionData *d;
   unsigned long uid;
-  
-  d = BUS_CONNECTION_DATA (connection);
-
-  _dbus_assert (d != NULL);
 
   *groups = NULL;
   *n_groups = 0;
@@ -1221,6 +1202,16 @@
   d->oom_preallocated = NULL;
 }
 
+#ifdef DBUS_ENABLE_STATS
+static void
+update_peak (int *peak,
+             int n)
+{
+  if (*peak < n)
+    *peak = n;
+}
+#endif
+
 void
 bus_connection_add_match_rule_link (DBusConnection *connection,
                                     DBusList       *link)
@@ -1233,6 +1224,15 @@
   _dbus_list_append_link (&d->match_rules, link);
 
   d->n_match_rules += 1;
+
+#ifdef DBUS_ENABLE_STATS
+  update_peak (&d->peak_match_rules, d->n_match_rules);
+  update_peak (&d->connections->peak_match_rules_per_conn, d->n_match_rules);
+
+  d->connections->total_match_rules += 1;
+  update_peak (&d->connections->peak_match_rules,
+               d->connections->total_match_rules);
+#endif
 }
 
 dbus_bool_t
@@ -1264,6 +1264,10 @@
 
   d->n_match_rules -= 1;
   _dbus_assert (d->n_match_rules >= 0);
+
+#ifdef DBUS_ENABLE_STATS
+  d->connections->total_match_rules -= 1;
+#endif
 }
 
 int
@@ -1289,6 +1293,16 @@
   _dbus_list_append_link (&d->services_owned, link);
 
   d->n_services_owned += 1;
+
+#ifdef DBUS_ENABLE_STATS
+  update_peak (&d->peak_bus_names, d->n_services_owned);
+  update_peak (&d->connections->peak_bus_names_per_conn,
+               d->n_services_owned);
+
+  d->connections->total_bus_names += 1;
+  update_peak (&d->connections->peak_bus_names,
+               d->connections->total_bus_names);
+#endif
 }
 
 dbus_bool_t
@@ -1320,6 +1334,10 @@
 
   d->n_services_owned -= 1;
   _dbus_assert (d->n_services_owned >= 0);
+
+#ifdef DBUS_ENABLE_STATS
+  d->connections->total_bus_names -= 1;
+#endif
 }
 
 int
@@ -1437,13 +1455,7 @@
                               DBusConnection  *requesting_completion,
                               DBusError       *error)
 {
-  BusConnectionData *d;
   unsigned long uid;
-  
-  d = BUS_CONNECTION_DATA (requesting_completion);
-  _dbus_assert (d != NULL);
-
-  _dbus_assert (d->name == NULL);
 
   if (connections->n_completed >=
       bus_context_get_max_completed_connections (connections->context))
@@ -1760,8 +1772,8 @@
   cprd->pending = pending;
   cprd->connections = connections;
   
-  _dbus_get_current_time (&pending->expire_item.added_tv_sec,
-                          &pending->expire_item.added_tv_usec);
+  _dbus_get_monotonic_time (&pending->expire_item.added_tv_sec,
+                            &pending->expire_item.added_tv_usec);
 
   _dbus_verbose ("Added pending reply %p, replier %p receiver %p serial %u\n",
                  pending,
@@ -2303,3 +2315,71 @@
 
   return TRUE;
 }
+
+#ifdef DBUS_ENABLE_STATS
+int
+bus_connections_get_n_active (BusConnections *connections)
+{
+  return connections->n_completed;
+}
+
+int
+bus_connections_get_n_incomplete (BusConnections *connections)
+{
+  return connections->n_incomplete;
+}
+
+int
+bus_connections_get_total_match_rules (BusConnections *connections)
+{
+  return connections->total_match_rules;
+}
+
+int
+bus_connections_get_peak_match_rules (BusConnections *connections)
+{
+  return connections->peak_match_rules;
+}
+
+int
+bus_connections_get_peak_match_rules_per_conn (BusConnections *connections)
+{
+  return connections->peak_match_rules_per_conn;
+}
+
+int
+bus_connections_get_total_bus_names (BusConnections *connections)
+{
+  return connections->total_bus_names;
+}
+
+int
+bus_connections_get_peak_bus_names (BusConnections *connections)
+{
+  return connections->peak_bus_names;
+}
+
+int
+bus_connections_get_peak_bus_names_per_conn (BusConnections *connections)
+{
+  return connections->peak_bus_names_per_conn;
+}
+
+int
+bus_connection_get_peak_match_rules (DBusConnection *connection)
+{
+  BusConnectionData *d;
+
+  d = BUS_CONNECTION_DATA (connection);
+  return d->peak_match_rules;
+}
+
+int
+bus_connection_get_peak_bus_names (DBusConnection *connection)
+{
+  BusConnectionData *d;
+
+  d = BUS_CONNECTION_DATA (connection);
+  return d->peak_bus_names;
+}
+#endif /* DBUS_ENABLE_STATS */
diff --git a/bus/connection.h b/bus/connection.h
index 4b9a754..c936021 100644
--- a/bus/connection.h
+++ b/bus/connection.h
@@ -138,4 +138,17 @@
                                                   void                         *data,
                                                   DBusFreeFunction              free_data_function);
 
+/* called by stats.c, only present if DBUS_ENABLE_STATS */
+int bus_connections_get_n_active                  (BusConnections *connections);
+int bus_connections_get_n_incomplete              (BusConnections *connections);
+int bus_connections_get_total_match_rules         (BusConnections *connections);
+int bus_connections_get_peak_match_rules          (BusConnections *connections);
+int bus_connections_get_peak_match_rules_per_conn (BusConnections *connections);
+int bus_connections_get_total_bus_names           (BusConnections *connections);
+int bus_connections_get_peak_bus_names            (BusConnections *connections);
+int bus_connections_get_peak_bus_names_per_conn   (BusConnections *connections);
+
+int bus_connection_get_peak_match_rules           (DBusConnection *connection);
+int bus_connection_get_peak_bus_names             (DBusConnection *connection);
+
 #endif /* BUS_CONNECTION_H */
diff --git a/bus/dbus.service.in b/bus/dbus.service.in
index 399306f..160947c 100644
--- a/bus/dbus.service.in
+++ b/bus/dbus.service.in
@@ -4,7 +4,6 @@
 After=syslog.target
 
 [Service]
-ExecStartPre=@EXPANDED_BINDIR@/dbus-uuidgen --ensure
-ExecStartPre=-/bin/rm -f @DBUS_SYSTEM_PID_FILE@
-ExecStart=@EXPANDED_BINDIR@/dbus-daemon --system --address=systemd: --nofork --systemd-activation
+ExecStart=@EXPANDED_BINDIR@/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
 ExecReload=@EXPANDED_BINDIR@/dbus-send --print-reply --system --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ReloadConfig
+OOMScoreAdjust=-900
diff --git a/bus/dir-watch-inotify.c b/bus/dir-watch-inotify.c
index 39eff97..2e9be98 100644
--- a/bus/dir-watch-inotify.c
+++ b/bus/dir-watch-inotify.c
@@ -50,12 +50,6 @@
 static DBusLoop *loop = NULL;
 
 static dbus_bool_t
-_inotify_watch_callback (DBusWatch *watch, unsigned int condition, void *data)
-{
-  return dbus_watch_handle (watch, condition);
-}
-
-static dbus_bool_t
 _handle_inotify_watch (DBusWatch *passed_watch, unsigned int flags, void *data)
 {
   char buffer[INOTIFY_BUF_LEN];
@@ -204,16 +198,18 @@
 
   _set_watched_dirs_internal (&empty);
 
-  close (inotify_fd);
-  inotify_fd = -1;
   if (watch != NULL)
     {
-      _dbus_loop_remove_watch (loop, watch, _inotify_watch_callback, NULL);
+      _dbus_loop_remove_watch (loop, watch);
+      _dbus_watch_invalidate (watch);
       _dbus_watch_unref (watch);
       _dbus_loop_unref (loop);
     }
   watch = NULL;
   loop = NULL;
+
+  close (inotify_fd);
+  inotify_fd = -1;
 }
 
 static int
@@ -250,8 +246,7 @@
           goto out;
         }
 
-      if (!_dbus_loop_add_watch (loop, watch, _inotify_watch_callback,
-                                 NULL, NULL))
+      if (!_dbus_loop_add_watch (loop, watch))
         {
           _dbus_warn ("Unable to add reload watch to main loop");
           _dbus_watch_unref (watch);
@@ -259,7 +254,13 @@
           goto out;
         }
 
-      _dbus_register_shutdown_func (_shutdown_inotify, NULL);
+      if (!_dbus_register_shutdown_func (_shutdown_inotify, NULL))
+      {
+          _dbus_warn ("Unable to register shutdown func");
+          _dbus_watch_unref (watch);
+          watch = NULL;
+          goto out;
+      }
     }
 
   ret = 1;
diff --git a/bus/dir-watch-kqueue.c b/bus/dir-watch-kqueue.c
index 4e436eb..ac6290c 100644
--- a/bus/dir-watch-kqueue.c
+++ b/bus/dir-watch-kqueue.c
@@ -50,12 +50,6 @@
 static DBusLoop *loop = NULL;
 
 static dbus_bool_t
-_kqueue_watch_callback (DBusWatch *watch, unsigned int condition, void *data)
-{
-  return dbus_watch_handle (watch, condition);
-}
-
-static dbus_bool_t
 _handle_kqueue_watch (DBusWatch *watch, unsigned int flags, void *data)
 {
   struct kevent ev;
@@ -80,7 +74,8 @@
       kq = -1;
       if (watch != NULL)
 	{
-	  _dbus_loop_remove_watch (loop, watch, _kqueue_watch_callback, NULL);
+	  _dbus_loop_remove_watch (loop, watch);
+          _dbus_watch_invalidate (watch);
           _dbus_watch_unref (watch);
 	  watch = NULL;
 	}
@@ -120,14 +115,14 @@
 	    goto out;
 	  }
 
-	if (!_dbus_loop_add_watch (loop, watch, _kqueue_watch_callback,
-                                   NULL, NULL))
+	if (!_dbus_loop_add_watch (loop, watch))
           {
             _dbus_warn ("Unable to add reload watch to main loop");
-	    close (kq);
-	    kq = -1;
+	    _dbus_watch_invalidate (watch);
 	    _dbus_watch_unref (watch);
 	    watch = NULL;
+	    close (kq);
+	    kq = -1;
             goto out;
 	  }
     }
diff --git a/bus/dispatch.c b/bus/dispatch.c
index df152c2..7a96f9d 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -41,17 +41,10 @@
 #include <unistd.h>
 #endif
 
-#ifndef TEST_CONNECTION
-/*
- TODO autotools:
-  move to build system as already done for cmake
-*/
-#ifdef DBUS_UNIX
-#define TEST_CONNECTION "debug-pipe:name=test-server"
-#else
-#define TEST_CONNECTION "tcp:host=localhost,port=1234"
-#endif
-#endif
+/* This is hard-coded in the files in valid-config-files-*. We have to use
+ * the debug-pipe transport because the tests in this file require that
+ * dbus_connection_open_private() does not block. */
+#define TEST_DEBUG_PIPE "debug-pipe:name=test-server"
 
 static dbus_bool_t
 send_one_message (DBusConnection *connection,
@@ -321,7 +314,7 @@
           if (!bus_activation_activate_service (activation, connection, transaction, TRUE,
                                                 message, service_name, &error))
             {
-              _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&error);
+              _DBUS_ASSERT_ERROR_IS_SET (&error);
               _dbus_verbose ("bus_activation_activate_service() failed: %s\n", error.name);
               goto out;
             }
@@ -1532,7 +1525,7 @@
 
   dbus_error_init (&error);
 
-  connection = dbus_connection_open_private (TEST_CONNECTION, &error);
+  connection = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (connection == NULL)
     {
       _DBUS_ASSERT_ERROR_IS_SET (&error);
@@ -4501,7 +4494,7 @@
   if (context == NULL)
     return FALSE;
 
-  foo = dbus_connection_open_private (TEST_CONNECTION, &error);
+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (foo == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4519,7 +4512,7 @@
   if (!check_add_match_all (context, foo))
     _dbus_assert_not_reached ("AddMatch message failed");
 
-  bar = dbus_connection_open_private (TEST_CONNECTION, &error);
+  bar = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (bar == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4534,7 +4527,7 @@
   if (!check_add_match_all (context, bar))
     _dbus_assert_not_reached ("AddMatch message failed");
 
-  baz = dbus_connection_open_private (TEST_CONNECTION, &error);
+  baz = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (baz == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4650,7 +4643,7 @@
   if (context == NULL)
     return FALSE;
 
-  foo = dbus_connection_open_private (TEST_CONNECTION, &error);
+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (foo == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4733,7 +4726,7 @@
   if (context == NULL)
     return FALSE;
 
-  foo = dbus_connection_open_private (TEST_CONNECTION, &error);
+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (foo == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4773,7 +4766,6 @@
   DBusConnection *foo, *bar;
   DBusError error;
   DBusMessage *m;
-  dbus_bool_t b;
   int one[2], two[2], x, y, z;
   char r;
 
@@ -4783,7 +4775,7 @@
   if (context == NULL)
     _dbus_assert_not_reached ("could not alloc context");
 
-  foo = dbus_connection_open_private (TEST_CONNECTION, &error);
+  foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (foo == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
@@ -4798,7 +4790,7 @@
   if (!check_add_match_all (context, foo))
     _dbus_assert_not_reached ("AddMatch message failed");
 
-  bar = dbus_connection_open_private (TEST_CONNECTION, &error);
+  bar = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
   if (bar == NULL)
     _dbus_assert_not_reached ("could not alloc connection");
 
diff --git a/bus/driver.c b/bus/driver.c
index cc8d1f2..574e0f3 100644
--- a/bus/driver.c
+++ b/bus/driver.c
@@ -30,6 +30,7 @@
 #include "services.h"
 #include "selinux.h"
 #include "signals.h"
+#include "stats.h"
 #include "utils.h"
 #include <dbus/dbus-string.h>
 #include <dbus/dbus-internals.h>
@@ -826,7 +827,6 @@
   DBusMessageIter iter;
   DBusMessageIter dict_iter;
   DBusMessageIter dict_entry_iter;
-  int msg_type;
   int array_type;
   int key_type;
   DBusList *keys, *key_link;
@@ -841,9 +841,13 @@
   /* The message signature has already been checked for us,
    * so let's just assert it's right.
    */
-  msg_type = dbus_message_iter_get_arg_type (&iter);
+#ifndef DBUS_DISABLE_ASSERT
+    {
+      int msg_type = dbus_message_iter_get_arg_type (&iter);
 
-  _dbus_assert (msg_type == DBUS_TYPE_ARRAY);
+      _dbus_assert (msg_type == DBUS_TYPE_ARRAY);
+    }
+#endif
 
   dbus_message_iter_recurse (&iter, &dict_iter);
 
@@ -1644,11 +1648,7 @@
   return FALSE;
 }
 
-/* For speed it might be useful to sort this in order of
- * frequency of use (but doesn't matter with only a few items
- * anyhow)
- */
-static struct
+typedef struct
 {
   const char *name;
   const char *in_args;
@@ -1657,7 +1657,13 @@
                            BusTransaction *transaction,
                            DBusMessage    *message,
                            DBusError      *error);
-} message_handlers[] = {
+} MessageHandler;
+
+/* For speed it might be useful to sort this in order of
+ * frequency of use (but doesn't matter with only a few items
+ * anyhow)
+ */
+static const MessageHandler dbus_message_handlers[] = {
   { "Hello",
     "",
     DBUS_TYPE_STRING_AS_STRING,
@@ -1729,7 +1735,52 @@
   { "GetId",
     "",
     DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_get_id }
+    bus_driver_handle_get_id },
+  { NULL, NULL, NULL, NULL }
+};
+
+static dbus_bool_t bus_driver_handle_introspect (DBusConnection *,
+    BusTransaction *, DBusMessage *, DBusError *);
+
+static const MessageHandler introspectable_message_handlers[] = {
+  { "Introspect", "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_introspect },
+  { NULL, NULL, NULL, NULL }
+};
+
+#ifdef DBUS_ENABLE_STATS
+static const MessageHandler stats_message_handlers[] = {
+  { "GetStats", "", "a{sv}", bus_stats_handle_get_stats },
+  { "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats },
+  { NULL, NULL, NULL, NULL }
+};
+#endif
+
+typedef struct {
+  const char *name;
+  const MessageHandler *message_handlers;
+  const char *extra_introspection;
+} InterfaceHandler;
+
+/* These should ideally be sorted by frequency of use, although it
+ * probably doesn't matter with this few items */
+static InterfaceHandler interface_handlers[] = {
+  { DBUS_INTERFACE_DBUS, dbus_message_handlers,
+    "    <signal name=\"NameOwnerChanged\">\n"
+    "      <arg type=\"s\"/>\n"
+    "      <arg type=\"s\"/>\n"
+    "      <arg type=\"s\"/>\n"
+    "    </signal>\n"
+    "    <signal name=\"NameLost\">\n"
+    "      <arg type=\"s\"/>\n"
+    "    </signal>\n"
+    "    <signal name=\"NameAcquired\">\n"
+    "      <arg type=\"s\"/>\n"
+    "    </signal>\n" },
+  { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL },
+#ifdef DBUS_ENABLE_STATS
+  { BUS_INTERFACE_STATS, stats_message_handlers, NULL },
+#endif
+  { NULL, NULL, NULL }
 };
 
 static dbus_bool_t
@@ -1770,87 +1821,44 @@
 dbus_bool_t
 bus_driver_generate_introspect_string (DBusString *xml)
 {
-  int i;
+  const InterfaceHandler *ih;
+  const MessageHandler *mh;
 
   if (!_dbus_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
     return FALSE;
   if (!_dbus_string_append (xml, "<node>\n"))
     return FALSE;
-  if (!_dbus_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE))
-    return FALSE;
-  if (!_dbus_string_append (xml, "    <method name=\"Introspect\">\n"))
-    return FALSE;
-  if (!_dbus_string_append_printf (xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING))
-    return FALSE;
-  if (!_dbus_string_append (xml, "    </method>\n"))
-    return FALSE;
-  if (!_dbus_string_append (xml, "  </interface>\n"))
-    return FALSE;
 
-  if (!_dbus_string_append_printf (xml, "  <interface name=\"%s\">\n",
-                                   DBUS_INTERFACE_DBUS))
-    return FALSE;
-
-  i = 0;
-  while (i < _DBUS_N_ELEMENTS (message_handlers))
+  for (ih = interface_handlers; ih->name != NULL; ih++)
     {
-
-      if (!_dbus_string_append_printf (xml, "    <method name=\"%s\">\n",
-                                       message_handlers[i].name))
+      if (!_dbus_string_append_printf (xml, "  <interface name=\"%s\">\n",
+                                       ih->name))
         return FALSE;
 
-      if (!write_args_for_direction (xml, message_handlers[i].in_args, TRUE))
-	return FALSE;
+      for (mh = ih->message_handlers; mh->name != NULL; mh++)
+        {
+          if (!_dbus_string_append_printf (xml, "    <method name=\"%s\">\n",
+                                           mh->name))
+            return FALSE;
 
-      if (!write_args_for_direction (xml, message_handlers[i].out_args, FALSE))
-	return FALSE;
+          if (!write_args_for_direction (xml, mh->in_args, TRUE))
+            return FALSE;
 
-      if (!_dbus_string_append (xml, "    </method>\n"))
-	return FALSE;
+          if (!write_args_for_direction (xml, mh->out_args, FALSE))
+            return FALSE;
 
-      ++i;
+          if (!_dbus_string_append (xml, "    </method>\n"))
+            return FALSE;
+        }
+
+      if (ih->extra_introspection != NULL &&
+          !_dbus_string_append (xml, ih->extra_introspection))
+        return FALSE;
+
+      if (!_dbus_string_append (xml, "  </interface>\n"))
+        return FALSE;
     }
 
-  if (!_dbus_string_append_printf (xml, "    <signal name=\"NameOwnerChanged\">\n"))
-    return FALSE;
-
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-
-  if (!_dbus_string_append_printf (xml, "    </signal>\n"))
-    return FALSE;
-
-
-
-  if (!_dbus_string_append_printf (xml, "    <signal name=\"NameLost\">\n"))
-    return FALSE;
-
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-
-  if (!_dbus_string_append_printf (xml, "    </signal>\n"))
-    return FALSE;
-
-
-
-  if (!_dbus_string_append_printf (xml, "    <signal name=\"NameAcquired\">\n"))
-    return FALSE;
-
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-
-  if (!_dbus_string_append_printf (xml, "    </signal>\n"))
-    return FALSE;
-
-  if (!_dbus_string_append (xml, "  </interface>\n"))
-    return FALSE;
-
   if (!_dbus_string_append (xml, "</node>\n"))
     return FALSE;
 
@@ -1925,8 +1933,10 @@
 			   DBusMessage    *message,
                            DBusError      *error)
 {
-  const char *name, *sender, *interface;
-  int i;
+  const char *name, *interface;
+  const InterfaceHandler *ih;
+  const MessageHandler *mh;
+  dbus_bool_t found_interface = FALSE;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -1944,57 +1954,54 @@
       return TRUE; /* we just ignore this */
     }
 
-  if (dbus_message_is_method_call (message,
-                                   DBUS_INTERFACE_INTROSPECTABLE,
-                                   "Introspect"))
-    return bus_driver_handle_introspect (connection, transaction, message, error);
-
+  /* may be NULL, which means "any interface will do" */
   interface = dbus_message_get_interface (message);
-  if (interface == NULL)
-    interface = DBUS_INTERFACE_DBUS;
 
   _dbus_assert (dbus_message_get_member (message) != NULL);
 
   name = dbus_message_get_member (message);
-  sender = dbus_message_get_sender (message);
 
-  if (strcmp (interface,
-              DBUS_INTERFACE_DBUS) != 0)
-    {
-      _dbus_verbose ("Driver got message to unknown interface \"%s\"\n",
-                     interface);
-      goto unknown;
-    }
-
-  _dbus_verbose ("Driver got a method call: %s\n",
-		 dbus_message_get_member (message));
+  _dbus_verbose ("Driver got a method call: %s\n", name);
 
   /* security checks should have kept this from getting here */
-  _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
-
-  i = 0;
-  while (i < _DBUS_N_ELEMENTS (message_handlers))
+#ifndef DBUS_DISABLE_ASSERT
     {
-      if (strcmp (message_handlers[i].name, name) == 0)
+      const char *sender = dbus_message_get_sender (message);
+
+      _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
+    }
+#endif
+
+  for (ih = interface_handlers; ih->name != NULL; ih++)
+    {
+      if (interface != NULL && strcmp (interface, ih->name) != 0)
+        continue;
+
+      found_interface = TRUE;
+
+      for (mh = ih->message_handlers; mh->name != NULL; mh++)
         {
+          if (strcmp (mh->name, name) != 0)
+            continue;
+
           _dbus_verbose ("Found driver handler for %s\n", name);
 
-          if (!dbus_message_has_signature (message, message_handlers[i].in_args))
+          if (!dbus_message_has_signature (message, mh->in_args))
             {
               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
               _dbus_verbose ("Call to %s has wrong args (%s, expected %s)\n",
                              name, dbus_message_get_signature (message),
-                             message_handlers[i].in_args);
+                             mh->in_args);
 
               dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
                               "Call to %s has wrong args (%s, expected %s)\n",
                               name, dbus_message_get_signature (message),
-                              message_handlers[i].in_args);
+                              mh->in_args);
               _DBUS_ASSERT_ERROR_IS_SET (error);
               return FALSE;
             }
 
-          if ((* message_handlers[i].handler) (connection, transaction, message, error))
+          if ((* mh->handler) (connection, transaction, message, error))
             {
               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
               _dbus_verbose ("Driver handler succeeded\n");
@@ -2007,15 +2014,12 @@
               return FALSE;
             }
         }
-
-      ++i;
     }
 
- unknown:
   _dbus_verbose ("No driver handler for message \"%s\"\n",
                  name);
 
-  dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD,
+  dbus_set_error (error, found_interface ? DBUS_ERROR_UNKNOWN_METHOD : DBUS_ERROR_UNKNOWN_INTERFACE,
                   "%s does not understand message %s",
                   DBUS_SERVICE_DBUS, name);
 
diff --git a/bus/expirelist.c b/bus/expirelist.c
index 946a615..1a12ea4 100644
--- a/bus/expirelist.c
+++ b/bus/expirelist.c
@@ -40,14 +40,6 @@
 
 static dbus_bool_t expire_timeout_handler (void *data);
 
-static void
-call_timeout_callback (DBusTimeout   *timeout,
-                       void          *data)
-{
-  /* can return FALSE on OOM but we just let it fire again later */
-  dbus_timeout_handle (timeout);
-}
-
 BusExpireList*
 bus_expire_list_new (DBusLoop      *loop,
                      int            expire_after,
@@ -73,9 +65,7 @@
 
   _dbus_timeout_set_enabled (list->timeout, FALSE);
 
-  if (!_dbus_loop_add_timeout (list->loop,
-                               list->timeout,
-                               call_timeout_callback, NULL, NULL))
+  if (!_dbus_loop_add_timeout (list->loop, list->timeout))
     goto failed;
 
   return list;
@@ -94,8 +84,7 @@
 {
   _dbus_assert (list->items == NULL);
 
-  _dbus_loop_remove_timeout (list->loop, list->timeout,
-                             call_timeout_callback, NULL);
+  _dbus_loop_remove_timeout (list->loop, list->timeout);
 
   _dbus_timeout_unref (list->timeout);
 
@@ -134,9 +123,9 @@
 }
 
 static int
-do_expiration_with_current_time (BusExpireList *list,
-                                 long           tv_sec,
-                                 long           tv_usec)
+do_expiration_with_monotonic_time (BusExpireList *list,
+                                   long           tv_sec,
+                                   long           tv_usec)
 {
   DBusList *link;
   int next_interval, min_wait_time, items_to_expire;
@@ -205,9 +194,9 @@
     {
       long tv_sec, tv_usec;
 
-      _dbus_get_current_time (&tv_sec, &tv_usec);
+      _dbus_get_monotonic_time (&tv_sec, &tv_usec);
 
-      next_interval = do_expiration_with_current_time (list, tv_sec, tv_usec);
+      next_interval = do_expiration_with_monotonic_time (list, tv_sec, tv_usec);
     }
 
   bus_expire_timeout_set_interval (list->timeout, next_interval);
@@ -351,7 +340,7 @@
                               test_expire_func, NULL);
   _dbus_assert (list != NULL);
 
-  _dbus_get_current_time (&tv_sec, &tv_usec);
+  _dbus_get_monotonic_time (&tv_sec, &tv_usec);
 
   tv_sec_not_expired = tv_sec;
   tv_usec_not_expired = tv_usec;
@@ -378,22 +367,22 @@
     _dbus_assert_not_reached ("out of memory");
 
   next_interval =
-    do_expiration_with_current_time (list, tv_sec_not_expired,
-                                     tv_usec_not_expired);
+    do_expiration_with_monotonic_time (list, tv_sec_not_expired,
+                                       tv_usec_not_expired);
   _dbus_assert (item->expire_count == 0);
   _dbus_verbose ("next_interval = %d\n", next_interval);
   _dbus_assert (next_interval == 1);
   
   next_interval =
-    do_expiration_with_current_time (list, tv_sec_expired,
-                                     tv_usec_expired);
+    do_expiration_with_monotonic_time (list, tv_sec_expired,
+                                       tv_usec_expired);
   _dbus_assert (item->expire_count == 1);
   _dbus_verbose ("next_interval = %d\n", next_interval);
   _dbus_assert (next_interval == -1);
 
   next_interval =
-    do_expiration_with_current_time (list, tv_sec_past,
-                                     tv_usec_past);
+    do_expiration_with_monotonic_time (list, tv_sec_past,
+                                       tv_usec_past);
   _dbus_assert (item->expire_count == 1);
   _dbus_verbose ("next_interval = %d\n", next_interval);
   _dbus_assert (next_interval == 1000 + EXPIRE_AFTER);
diff --git a/bus/main.c b/bus/main.c
index b25c945..ca0be3c 100644
--- a/bus/main.c
+++ b/bus/main.c
@@ -35,20 +35,30 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for write() and STDERR_FILENO */
+#endif
 #include "selinux.h"
 
 static BusContext *context;
 
+#ifdef DBUS_UNIX
+
 static int reload_pipe[2];
 #define RELOAD_READ_END 0
 #define RELOAD_WRITE_END 1
 
-static void close_reload_pipe (void);
+static void close_reload_pipe (DBusWatch **);
+
+typedef enum
+ {
+   ACTION_RELOAD = 'r',
+   ACTION_QUIT = 'q'
+ } SignalAction;
 
 static void
 signal_handler (int sig)
 {
-
   switch (sig)
     {
 #ifdef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX
@@ -59,23 +69,63 @@
     case SIGHUP:
       {
         DBusString str;
-        _dbus_string_init_const (&str, "foo");
+        char action[2] = { ACTION_RELOAD, '\0' };
+
+        _dbus_string_init_const (&str, action);
         if ((reload_pipe[RELOAD_WRITE_END] > 0) &&
             !_dbus_write_socket (reload_pipe[RELOAD_WRITE_END], &str, 0, 1))
           {
-            _dbus_warn ("Unable to write to reload pipe.\n");
-            close_reload_pipe ();
+            /* If we receive SIGHUP often enough to fill the pipe buffer (4096
+             * times on old Linux, 65536 on modern Linux) before it can be
+             * drained, let's just warn and ignore. The configuration will be
+             * reloaded while draining the pipe buffer, which is what we
+             * wanted. It's harmless that it will be reloaded fewer times than
+             * we asked for, since the reload is delayed anyway, so new changes
+             * will be picked up.
+             *
+             * We use write() because _dbus_warn uses vfprintf, which isn't
+             * async-signal-safe.
+             *
+             * This is necessarily Unix-specific, but so are POSIX signals,
+             * so... */
+            static const char message[] =
+              "Unable to write to reload pipe - buffer full?\n";
+
+            write (STDERR_FILENO, message, strlen (message));
           }
       }
       break;
 #endif
+
+    case SIGTERM:
+      {
+        DBusString str;
+        char action[2] = { ACTION_QUIT, '\0' };
+        _dbus_string_init_const (&str, action);
+        if ((reload_pipe[RELOAD_WRITE_END] < 0) ||
+            !_dbus_write_socket (reload_pipe[RELOAD_WRITE_END], &str, 0, 1))
+          {
+            /* If we can't write to the socket, dying seems a more
+             * important response to SIGTERM than cleaning up sockets,
+             * so we exit. We'd use exit(), but that's not async-signal-safe,
+             * so we'll have to resort to _exit(). */
+            static const char message[] =
+              "Unable to write termination signal to pipe - buffer full?\n"
+              "Will exit instead.\n";
+
+            write (STDERR_FILENO, message, strlen (message));
+            _exit (1);
+          }
+      }
+      break;
     }
 }
+#endif /* DBUS_UNIX */
 
 static void
 usage (void)
 {
-  fprintf (stderr, DBUS_DAEMON_NAME " [--version] [--session] [--system] [--config-file=FILE] [--print-address[=DESCRIPTOR]] [--print-pid[=DESCRIPTOR]] [--fork] [--nofork] [--introspect] [--address=ADDRESS] [--systemd-activation]\n");
+  fprintf (stderr, DBUS_DAEMON_NAME " [--version] [--session] [--system] [--config-file=FILE] [--print-address[=DESCRIPTOR]] [--print-pid[=DESCRIPTOR]] [--fork] [--nofork] [--introspect] [--address=ADDRESS] [--systemd-activation] [--nopidfile]\n");
   exit (1);
 }
 
@@ -163,6 +213,7 @@
     }
 }
 
+#ifdef DBUS_UNIX
 static dbus_bool_t
 handle_reload_watch (DBusWatch    *watch,
 		     unsigned int  flags,
@@ -170,6 +221,8 @@
 {
   DBusError error;
   DBusString str;
+  char *action_str;
+  char action = '\0';
 
   while (!_dbus_string_init (&str))
     _dbus_wait_for_memory ();
@@ -178,9 +231,15 @@
       _dbus_read_socket (reload_pipe[RELOAD_READ_END], &str, 1) != 1)
     {
       _dbus_warn ("Couldn't read from reload pipe.\n");
-      close_reload_pipe ();
+      close_reload_pipe (&watch);
       return TRUE;
     }
+
+  action_str = _dbus_string_get_data (&str);
+  if (action_str != NULL)
+    {
+      action = action_str[0];
+    }
   _dbus_string_free (&str);
 
   /* this can only fail if we don't understand the config file
@@ -188,24 +247,43 @@
    * loaded config.
    */
   dbus_error_init (&error);
-  if (! bus_context_reload_config (context, &error))
-    {
-      _DBUS_ASSERT_ERROR_IS_SET (&error);
-      _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) ||
-		    dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY));
-      _dbus_warn ("Unable to reload configuration: %s\n",
-		  error.message);
-      dbus_error_free (&error);
-    }
-  return TRUE;
-}
 
-static dbus_bool_t
-reload_watch_callback (DBusWatch    *watch,
-		       unsigned int  condition,
-		       void         *data)
-{
-  return dbus_watch_handle (watch, condition);
+  switch (action)
+    {
+    case ACTION_RELOAD:
+      if (! bus_context_reload_config (context, &error))
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (&error);
+          _dbus_assert (dbus_error_has_name (&error, DBUS_ERROR_FAILED) ||
+                        dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY));
+          _dbus_warn ("Unable to reload configuration: %s\n",
+                      error.message);
+          dbus_error_free (&error);
+        }
+      break;
+
+    case ACTION_QUIT:
+      {
+        DBusLoop *loop;
+        /*
+         * On OSs without abstract sockets, we want to quit
+         * gracefully rather than being killed by SIGTERM,
+         * so that DBusServer gets a chance to clean up the
+         * sockets from the filesystem. fd.o #38656
+         */
+        loop = bus_context_get_loop (context);
+        if (loop != NULL)
+          {
+            _dbus_loop_quit (loop);
+          }
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  return TRUE;
 }
 
 static void
@@ -237,8 +315,7 @@
       exit (1);
     }
 
-  if (!_dbus_loop_add_watch (loop, watch, reload_watch_callback,
-			     NULL, NULL))
+  if (!_dbus_loop_add_watch (loop, watch))
     {
       _dbus_warn ("Unable to add reload watch to main loop: %s\n",
 		  error.message);
@@ -249,14 +326,20 @@
 }
 
 static void
-close_reload_pipe (void)
+close_reload_pipe (DBusWatch **watch)
 {
+    _dbus_loop_remove_watch (bus_context_get_loop (context), *watch);
+    _dbus_watch_invalidate (*watch);
+    _dbus_watch_unref (*watch);
+    *watch = NULL;
+
     _dbus_close_socket (reload_pipe[RELOAD_READ_END], NULL);
     reload_pipe[RELOAD_READ_END] = -1;
 
     _dbus_close_socket (reload_pipe[RELOAD_WRITE_END], NULL);
     reload_pipe[RELOAD_WRITE_END] = -1;
 }
+#endif /* DBUS_UNIX */
 
 int
 main (int argc, char **argv)
@@ -272,9 +355,7 @@
   int i;
   dbus_bool_t print_address;
   dbus_bool_t print_pid;
-  dbus_bool_t is_session_bus;
-  int force_fork;
-  dbus_bool_t systemd_activation;
+  BusContextFlags flags;
 
   if (!_dbus_string_init (&config_file))
     return 1;
@@ -290,9 +371,8 @@
 
   print_address = FALSE;
   print_pid = FALSE;
-  is_session_bus = FALSE;
-  force_fork = FORK_FOLLOW_CONFIG_FILE;
-  systemd_activation = FALSE;
+
+  flags = BUS_CONTEXT_FLAG_WRITE_PID_FILE;
 
   prev_arg = NULL;
   i = 1;
@@ -303,17 +383,35 @@
       if (strcmp (arg, "--help") == 0 ||
           strcmp (arg, "-h") == 0 ||
           strcmp (arg, "-?") == 0)
-        usage ();
+        {
+          usage ();
+        }
       else if (strcmp (arg, "--version") == 0)
-        version ();
+        {
+          version ();
+        }
       else if (strcmp (arg, "--introspect") == 0)
-        introspect ();
+        {
+          introspect ();
+        }
       else if (strcmp (arg, "--nofork") == 0)
-        force_fork = FORK_NEVER;
+        {
+          flags &= ~BUS_CONTEXT_FLAG_FORK_ALWAYS;
+          flags |= BUS_CONTEXT_FLAG_FORK_NEVER;
+        }
       else if (strcmp (arg, "--fork") == 0)
-        force_fork = FORK_ALWAYS;
+        {
+          flags &= ~BUS_CONTEXT_FLAG_FORK_NEVER;
+          flags |= BUS_CONTEXT_FLAG_FORK_ALWAYS;
+        }
+      else if (strcmp (arg, "--nopidfile") == 0)
+        {
+          flags &= ~BUS_CONTEXT_FLAG_WRITE_PID_FILE;
+        }
       else if (strcmp (arg, "--systemd-activation") == 0)
-        systemd_activation = TRUE;
+        {
+          flags |= BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION;
+        }
       else if (strcmp (arg, "--system") == 0)
         {
           check_two_config_files (&config_file, "system");
@@ -349,7 +447,9 @@
             exit (1);
         }
       else if (strcmp (arg, "--config-file") == 0)
-        ; /* wait for next arg */
+        {
+          /* wait for next arg */
+        }
       else if (strstr (arg, "--address=") == arg)
         {
           const char *file;
@@ -371,7 +471,9 @@
             exit (1);
         }
       else if (strcmp (arg, "--address") == 0)
-        ; /* wait for next arg */
+        {
+          /* wait for next arg */
+        }
       else if (strstr (arg, "--print-address=") == arg)
         {
           const char *desc;
@@ -397,7 +499,9 @@
           print_address = TRUE;
         }
       else if (strcmp (arg, "--print-address") == 0)
-        print_address = TRUE; /* and we'll get the next arg if appropriate */
+        {
+          print_address = TRUE; /* and we'll get the next arg if appropriate */
+        }
       else if (strstr (arg, "--print-pid=") == arg)
         {
           const char *desc;
@@ -423,9 +527,13 @@
           print_pid = TRUE;
         }
       else if (strcmp (arg, "--print-pid") == 0)
-        print_pid = TRUE; /* and we'll get the next arg if appropriate */
+        {
+          print_pid = TRUE; /* and we'll get the next arg if appropriate */
+        }
       else
-        usage ();
+        {
+          usage ();
+        }
 
       prev_arg = arg;
 
@@ -489,10 +597,9 @@
     }
 
   dbus_error_init (&error);
-  context = bus_context_new (&config_file, force_fork,
+  context = bus_context_new (&config_file, flags,
                              &print_addr_pipe, &print_pid_pipe,
                              _dbus_string_get_length(&address) > 0 ? &address : NULL,
-                             systemd_activation,
                              &error);
   _dbus_string_free (&config_file);
   if (context == NULL)
@@ -503,24 +610,25 @@
       exit (1);
     }
 
-  is_session_bus = bus_context_get_type(context) != NULL
-      && strcmp(bus_context_get_type(context),"session") == 0;
-
-  if (is_session_bus)
-    _dbus_daemon_publish_session_bus_address (bus_context_get_address (context));
-
   /* bus_context_new() closes the print_addr_pipe and
    * print_pid_pipe
    */
 
+#ifdef DBUS_UNIX
   setup_reload_pipe (bus_context_get_loop (context));
 
+  /* POSIX signals are Unix-specific, and _dbus_set_signal_handler is
+   * unimplemented (and probably unimplementable) on Windows, so there's
+   * no point in trying to make the handler portable to non-Unix. */
+
+  _dbus_set_signal_handler (SIGTERM, signal_handler);
 #ifdef SIGHUP
   _dbus_set_signal_handler (SIGHUP, signal_handler);
 #endif
 #ifdef DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX
   _dbus_set_signal_handler (SIGIO, signal_handler);
 #endif /* DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX */
+#endif /* DBUS_UNIX */
 
   _dbus_verbose ("We are on D-Bus...\n");
   _dbus_loop_run (bus_context_get_loop (context));
@@ -529,8 +637,5 @@
   bus_context_unref (context);
   bus_selinux_shutdown ();
 
-  if (is_session_bus)
-    _dbus_daemon_unpublish_session_bus_address ();
-
   return 0;
 }
diff --git a/bus/org.freedesktop.dbus-session.plist.in b/bus/org.freedesktop.dbus-session.plist.in
new file mode 100644
index 0000000..40ff370
--- /dev/null
+++ b/bus/org.freedesktop.dbus-session.plist.in
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>Label</key>
+	<string>org.freedesktop.dbus-session</string>
+
+	<key>ServiceIPC</key>
+	<true/>
+
+	<!-- Please uncomment on 10.4; OnDemand doesn't work properly there. -->
+	<!--
+	<key>OnDemand</key>
+	<false />
+	-->
+
+	<key>ProgramArguments</key>
+	<array>
+		<string>@DBUS_DAEMONDIR@/dbus-daemon</string>
+		<string>--nofork</string>
+		<string>--session</string>
+	</array>
+
+	<key>Sockets</key>
+	<dict>
+		<key>unix_domain_listener</key>
+		<dict>
+			<key>SecureSocketWithKey</key>
+			<string>DBUS_LAUNCHD_SESSION_BUS_SOCKET</string>
+		</dict>
+	</dict>
+</dict>
+</plist>
diff --git a/bus/policy.c b/bus/policy.c
index a1fff86..379cea9 100644
--- a/bus/policy.c
+++ b/bus/policy.c
@@ -403,8 +403,8 @@
         }
       else if (rule->type == BUS_POLICY_RULE_GROUP)
         {
-          _dbus_verbose ("List %p group rule uid="DBUS_UID_FORMAT"\n",
-                         list, rule->d.user.uid);
+          _dbus_verbose ("List %p group rule gid="DBUS_GID_FORMAT"\n",
+                         list, rule->d.group.gid);
           
           if (rule->d.group.gid == DBUS_GID_UNSET)
             ;  /* '*' wildcard */
@@ -1240,25 +1240,26 @@
   return allowed;
 }
 
-dbus_bool_t
-bus_client_policy_check_can_own (BusClientPolicy  *policy,
-                                 DBusConnection   *connection,
-                                 const DBusString *service_name)
+
+
+static dbus_bool_t
+bus_rules_check_can_own (DBusList *rules,
+                         const DBusString *service_name)
 {
   DBusList *link;
   dbus_bool_t allowed;
   
-  /* policy->rules is in the order the rules appeared
+  /* rules is in the order the rules appeared
    * in the config file, i.e. last rule that applies wins
    */
 
   allowed = FALSE;
-  link = _dbus_list_get_first_link (&policy->rules);
+  link = _dbus_list_get_first_link (&rules);
   while (link != NULL)
     {
       BusPolicyRule *rule = link->data;
 
-      link = _dbus_list_get_next_link (&policy->rules, link);
+      link = _dbus_list_get_next_link (&rules, link);
       
       /* Rule is skipped if it specifies a different service name from
        * the desired one.
@@ -1267,12 +1268,25 @@
       if (rule->type != BUS_POLICY_RULE_OWN)
         continue;
 
-      if (rule->d.own.service_name != NULL)
+      if (!rule->d.own.prefix && rule->d.own.service_name != NULL)
         {
           if (!_dbus_string_equal_c_str (service_name,
                                          rule->d.own.service_name))
             continue;
         }
+      else if (rule->d.own.prefix)
+        {
+          const char *data;
+          char next_char;
+          if (!_dbus_string_starts_with_c_str (service_name,
+                                               rule->d.own.service_name))
+            continue;
+
+          data = _dbus_string_get_const_data (service_name);
+          next_char = data[strlen (rule->d.own.service_name)];
+          if (next_char != '\0' && next_char != '.')
+            continue;
+        }
 
       /* Use this rule */
       allowed = rule->allow;
@@ -1281,17 +1295,19 @@
   return allowed;
 }
 
-#ifdef DBUS_BUILD_TESTS
-
 dbus_bool_t
-bus_policy_test (const DBusString *test_data_dir)
+bus_client_policy_check_can_own (BusClientPolicy  *policy,
+                                 const DBusString *service_name)
 {
-  /* This doesn't do anything for now because I decided to do it in
-   * dispatch.c instead by having some of the clients in dispatch.c
-   * have particular policies applied to them.
-   */
-  
-  return TRUE;
+  return bus_rules_check_can_own (policy->rules, service_name);
 }
 
+#ifdef DBUS_BUILD_TESTS
+dbus_bool_t
+bus_policy_check_can_own (BusPolicy  *policy,
+                          const DBusString *service_name)
+{
+  return bus_rules_check_can_own (policy->default_rules, service_name);
+}
 #endif /* DBUS_BUILD_TESTS */
+
diff --git a/bus/policy.h b/bus/policy.h
index 1782dbf..3ff6f48 100644
--- a/bus/policy.h
+++ b/bus/policy.h
@@ -86,6 +86,8 @@
     {
       /* can be NULL meaning "any" */
       char *service_name;
+      /* if prefix is set, any name starting with service_name can be owned */
+      unsigned int prefix : 1;
     } own;
 
     struct
@@ -154,11 +156,14 @@
                                                       DBusMessage      *message,
                                                       dbus_int32_t     *toggles);
 dbus_bool_t      bus_client_policy_check_can_own     (BusClientPolicy  *policy,
-                                                      DBusConnection   *connection,
                                                       const DBusString *service_name);
 dbus_bool_t      bus_client_policy_append_rule       (BusClientPolicy  *policy,
                                                       BusPolicyRule    *rule);
 void             bus_client_policy_optimize          (BusClientPolicy  *policy);
 
+#ifdef DBUS_BUILD_TESTS
+dbus_bool_t      bus_policy_check_can_own     (BusPolicy  *policy,
+                                               const DBusString *service_name);
+#endif
 
 #endif /* BUS_POLICY_H */
diff --git a/bus/selinux.c b/bus/selinux.c
index fe04063..36287e9 100644
--- a/bus/selinux.c
+++ b/bus/selinux.c
@@ -164,7 +164,7 @@
   }
 #endif /* HAVE_LIBAUDIT */
   
-  vsyslog (LOG_INFO, fmt, ap);
+  vsyslog (LOG_USER | LOG_INFO, fmt, ap);
   va_end(ap);
 }
 
@@ -342,7 +342,6 @@
     }
   else
     {
-      openlog ("dbus", LOG_PERROR, LOG_USER);
       _dbus_verbose ("Access Vector Cache (AVC) started.\n");
     }
 
@@ -1056,7 +1055,7 @@
       capng_clear (CAPNG_SELECT_BOTH);
       capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,
                     CAP_AUDIT_WRITE);
-      rc = capng_change_id (uid, gid, 0);
+      rc = capng_change_id (uid, gid, CAPNG_DROP_SUPP_GRP);
       if (rc)
         {
           switch (rc) {
diff --git a/bus/services.c b/bus/services.c
index 0a04925..6f380fa 100644
--- a/bus/services.c
+++ b/bus/services.c
@@ -385,7 +385,6 @@
 {
   dbus_bool_t retval;
   DBusConnection *old_owner_conn;
-  DBusConnection *current_owner_conn;
   BusClientPolicy *policy;
   BusService *service;
   BusActivation  *activation;
@@ -460,8 +459,7 @@
       goto out;
     }
   
-  if (!bus_client_policy_check_can_own (policy, connection,
-                                        service_name))
+  if (!bus_client_policy_check_can_own (policy, service_name))
     {
       dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
                       "Connection \"%s\" is not allowed to own the service \"%s\" due "
@@ -510,12 +508,10 @@
   primary_owner = bus_service_get_primary_owner (service);
   if (primary_owner == NULL)
     goto out;
-    
-  current_owner_conn = primary_owner->conn;
-     
+
   if (old_owner_conn == NULL)
     {
-      _dbus_assert (current_owner_conn == connection);
+      _dbus_assert (primary_owner->conn == connection);
 
       *result = DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;      
     }
diff --git a/bus/signals.c b/bus/signals.c
index 6f97b2b..28506d3 100644
--- a/bus/signals.c
+++ b/bus/signals.c
@@ -47,8 +47,11 @@
   int args_len;
 };
 
+#define BUS_MATCH_ARG_NAMESPACE   0x4000000u
 #define BUS_MATCH_ARG_IS_PATH  0x8000000u
 
+#define BUS_MATCH_ARG_FLAGS (BUS_MATCH_ARG_NAMESPACE | BUS_MATCH_ARG_IS_PATH)
+
 BusMatchRule*
 bus_match_rule_new (DBusConnection *matches_go_to)
 {
@@ -135,8 +138,8 @@
   
   if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
     {
-      /* FIXME make type readable */
-      if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
+      if (!_dbus_string_append_printf (&str, "type='%s'",
+            dbus_message_type_to_string (rule->message_type)))
         goto nomem;
     }
 
@@ -176,6 +179,18 @@
         goto nomem;
     }
 
+  if (rule->flags & BUS_MATCH_PATH_NAMESPACE)
+    {
+      if (_dbus_string_get_length (&str) > 0)
+        {
+          if (!_dbus_string_append (&str, ","))
+            goto nomem;
+        }
+
+      if (!_dbus_string_append_printf (&str, "path_namespace='%s'", rule->path))
+        goto nomem;
+    }
+
   if (rule->flags & BUS_MATCH_SENDER)
     {
       if (_dbus_string_get_length (&str) > 0)
@@ -200,6 +215,20 @@
         goto nomem;
     }
 
+  if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
+    {
+      if (_dbus_string_get_length (&str) > 0)
+        {
+          if (!_dbus_string_append (&str, ","))
+            goto nomem;
+        }
+
+      if (!_dbus_string_append_printf (&str, "eavesdrop='%s'",
+            (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) ?
+            "true" : "false"))
+        goto nomem;
+    }
+
   if (rule->flags & BUS_MATCH_ARGS)
     {
       int i;
@@ -211,7 +240,7 @@
         {
           if (rule->args[i] != NULL)
             {
-              dbus_bool_t is_path;
+              dbus_bool_t is_path, is_namespace;
 
               if (_dbus_string_get_length (&str) > 0)
                 {
@@ -220,10 +249,13 @@
                 }
 
               is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
+              is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
               
               if (!_dbus_string_append_printf (&str,
                                                "arg%d%s='%s'",
-                                               i, is_path ? "path" : "",
+                                               i,
+                                               is_path ? "path" :
+                                               is_namespace ? "namespace" : "",
                                                rule->args[i]))
                 goto nomem;
             }
@@ -336,9 +368,20 @@
   return TRUE;
 }
 
+void
+bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
+                                            dbus_bool_t is_eavesdropping)
+{
+  if (is_eavesdropping)
+    rule->flags |= BUS_MATCH_CLIENT_IS_EAVESDROPPING;
+  else
+    rule->flags &= ~(BUS_MATCH_CLIENT_IS_EAVESDROPPING);
+}
+
 dbus_bool_t
 bus_match_rule_set_path (BusMatchRule *rule,
-                         const char   *path)
+                         const char   *path,
+                         dbus_bool_t   is_namespace)
 {
   char *new;
 
@@ -348,7 +391,13 @@
   if (new == NULL)
     return FALSE;
 
-  rule->flags |= BUS_MATCH_PATH;
+  rule->flags &= ~(BUS_MATCH_PATH|BUS_MATCH_PATH_NAMESPACE);
+
+  if (is_namespace)
+    rule->flags |= BUS_MATCH_PATH_NAMESPACE;
+  else
+    rule->flags |= BUS_MATCH_PATH;
+
   dbus_free (rule->path);
   rule->path = new;
 
@@ -359,7 +408,8 @@
 bus_match_rule_set_arg (BusMatchRule     *rule,
                         int                arg,
                         const DBusString *value,
-                        dbus_bool_t       is_path)
+                        dbus_bool_t       is_path,
+                        dbus_bool_t       is_namespace)
 {
   int length;
   char *new;
@@ -426,6 +476,9 @@
   if (is_path)
     rule->arg_lens[arg] |= BUS_MATCH_ARG_IS_PATH;
 
+  if (is_namespace)
+    rule->arg_lens[arg] |= BUS_MATCH_ARG_NAMESPACE;
+
   /* NULL termination didn't get busted */
   _dbus_assert (rule->args[rule->args_len] == NULL);
   _dbus_assert (rule->arg_lens[rule->args_len] == 0);
@@ -720,7 +773,8 @@
                                 const DBusString *value,
                                 DBusError        *error)
 {
-  dbus_bool_t is_path;
+  dbus_bool_t is_path = FALSE;
+  dbus_bool_t is_namespace = FALSE;
   DBusString key_str;
   unsigned long arg;
   int length;
@@ -751,16 +805,34 @@
       goto failed;
     }
 
-  if (end != length &&
-      ((end + 4) != length ||
-       !_dbus_string_ends_with_c_str (&key_str, "path")))
+  if (end != length)
     {
-      dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
-                      "Key '%s' in match rule contains junk after argument number. Only 'path' is optionally valid ('arg0path' for example).\n", key);
-      goto failed;
-    }
+      if ((end + strlen ("path")) == length &&
+          _dbus_string_ends_with_c_str (&key_str, "path"))
+        {
+          is_path = TRUE;
+        }
+      else if (_dbus_string_equal_c_str (&key_str, "arg0namespace"))
+        {
+          int value_len = _dbus_string_get_length (value);
 
-  is_path = end != length;
+          is_namespace = TRUE;
+
+          if (!_dbus_validate_bus_namespace (value, 0, value_len))
+            {
+              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                  "arg0namespace='%s' is not a valid prefix of a bus name",
+                  _dbus_string_get_const_data (value));
+              goto failed;
+            }
+        }
+      else
+        {
+          dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+              "Key '%s' in match rule contains junk after argument number (%u). Only 'arg%upath' (for example) or 'arg0namespace' are valid", key, arg, arg);
+          goto failed;
+        }
+    }
 
   /* If we didn't check this we could allocate a huge amount of RAM */
   if (arg > DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER)
@@ -779,7 +851,7 @@
       goto failed;
     }
   
-  if (!bus_match_rule_set_arg (rule, arg, value, is_path))
+  if (!bus_match_rule_set_arg (rule, arg, value, is_path, is_namespace))
     {
       BUS_SET_OOM (error);
       goto failed;
@@ -935,12 +1007,15 @@
               goto failed;
             }
         }
-      else if (strcmp (key, "path") == 0)
+      else if (strcmp (key, "path") == 0 ||
+          strcmp (key, "path_namespace") == 0)
         {
-          if (rule->flags & BUS_MATCH_PATH)
+          dbus_bool_t is_namespace = (strcmp (key, "path_namespace") == 0);
+
+          if (rule->flags & (BUS_MATCH_PATH | BUS_MATCH_PATH_NAMESPACE))
             {
               dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
-                              "Key %s specified twice in match rule\n", key);
+                              "path or path_namespace specified twice in match rule\n");
               goto failed;
             }
 
@@ -951,7 +1026,7 @@
               goto failed;
             }
 
-          if (!bus_match_rule_set_path (rule, value))
+          if (!bus_match_rule_set_path (rule, value, is_namespace))
             {
               BUS_SET_OOM (error);
               goto failed;
@@ -979,6 +1054,31 @@
               goto failed;
             }
         }
+      else if (strcmp (key, "eavesdrop") == 0)
+        {
+          /* do not detect "eavesdrop" being used more than once in rule:
+           * 1) it's not possible, it's only in the flags
+           * 2) it might be used twice to disable eavesdropping when it's
+           * automatically added (eg dbus-monitor/bustle) */
+
+          /* we accept only "true|false" as possible values */
+          if ((strcmp (value, "true") == 0))
+            {
+              bus_match_rule_set_client_is_eavesdropping (rule, TRUE);
+            }
+          else if (strcmp (value, "false") == 0)
+            {
+              bus_match_rule_set_client_is_eavesdropping (rule, FALSE);
+            }
+          else
+            {
+              dbus_set_error (error, DBUS_ERROR_MATCH_RULE_INVALID,
+                              "eavesdrop='%s' is invalid, "
+                              "it should be 'true' or 'false'\n",
+                              value);
+              goto failed;
+            }
+        }
       else if (strncmp (key, "arg", 3) == 0)
         {
           if (!bus_match_rule_parse_arg_match (rule, key, &tmp_str, error))
@@ -1102,6 +1202,7 @@
       else
         _dbus_hash_table_unref (p->rules_by_iface);
     }
+  dbus_free (matchmaker);
 
   return NULL;
 }
@@ -1287,7 +1388,7 @@
   if ((a->flags & BUS_MATCH_PATH) &&
       strcmp (a->path, b->path) != 0)
     return FALSE;
-  
+
   if ((a->flags & BUS_MATCH_INTERFACE) &&
       strcmp (a->interface, b->interface) != 0)
     return FALSE;
@@ -1300,6 +1401,9 @@
       strcmp (a->destination, b->destination) != 0)
     return FALSE;
 
+  /* we already compared the value of flags, and
+   * BUS_MATCH_CLIENT_IS_EAVESDROPPING does not have another struct member */
+
   if (a->flags & BUS_MATCH_ARGS)
     {
       int i;
@@ -1318,7 +1422,7 @@
           if (a->arg_lens[i] != b->arg_lens[i])
             return FALSE;
 
-          length = a->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
+          length = a->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
 
           if (a->args[i] != NULL)
             {
@@ -1550,12 +1654,24 @@
 }
 
 static dbus_bool_t
+str_has_prefix (const char *str, const char *prefix)
+{
+  size_t prefix_len;
+  prefix_len = strlen (prefix);
+  if (strncmp (str, prefix, prefix_len) == 0)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+static dbus_bool_t
 match_rule_matches (BusMatchRule    *rule,
                     DBusConnection  *sender,
                     DBusConnection  *addressed_recipient,
                     DBusMessage     *message,
                     BusMatchFlags    already_matched)
 {
+  dbus_bool_t wants_to_eavesdrop = FALSE;
   int flags;
 
   /* All features of the match rule are AND'd together,
@@ -1570,6 +1686,9 @@
   /* Don't bother re-matching features we've already checked implicitly. */
   flags = rule->flags & (~already_matched);
 
+  if (flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
+    wants_to_eavesdrop = TRUE;
+
   if (flags & BUS_MATCH_MESSAGE_TYPE)
     {
       _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
@@ -1623,6 +1742,24 @@
         }
     }
 
+  /* Note: this part is relevant for eavesdropper rules:
+   * Two cases:
+   * 1) rule has a destination to be matched
+   *   (flag BUS_MATCH_DESTINATION present). Rule will match if:
+   *   - rule->destination matches the addressed_recipient
+   *   AND
+   *   - wants_to_eavesdrop=TRUE
+   *
+   *   Note: (the case in which addressed_recipient is the actual rule owner
+   *   is handled elsewere in dispatch.c:bus_dispatch_matches().
+   *
+   * 2) rule has no destination. Rule will match if:
+   *    - message has no specified destination (ie broadcasts)
+   *      (Note: this will rule out unicast method calls and unicast signals,
+   *      fixing FDO#269748)
+   *    OR
+   *    - wants_to_eavesdrop=TRUE (destination-catch-all situation)
+   */
   if (flags & BUS_MATCH_DESTINATION)
     {
       const char *destination;
@@ -1631,6 +1768,12 @@
 
       destination = dbus_message_get_destination (message);
       if (destination == NULL)
+        /* broadcast, but this rule specified a destination: no match */
+        return FALSE;
+
+      /* rule owner does not intend to eavesdrop: we'll deliver only msgs
+       * directed to it, NOT MATCHING */
+      if (!wants_to_eavesdrop)
         return FALSE;
 
       if (addressed_recipient == NULL)
@@ -1644,6 +1787,19 @@
           if (!connection_is_primary_owner (addressed_recipient, rule->destination))
             return FALSE;
         }
+    } else { /* no destination in rule */
+        dbus_bool_t msg_is_broadcast;
+
+        _dbus_assert (rule->destination == NULL);
+
+        msg_is_broadcast = (dbus_message_get_destination (message) == NULL);
+
+        if (!wants_to_eavesdrop && !msg_is_broadcast)
+          return FALSE;
+
+        /* if we are here rule owner intends to eavesdrop
+         * OR
+         * message is being broadcasted */
     }
 
   if (flags & BUS_MATCH_PATH)
@@ -1660,6 +1816,31 @@
         return FALSE;
     }
 
+  if (flags & BUS_MATCH_PATH_NAMESPACE)
+    {
+      const char *path;
+      int len;
+
+      _dbus_assert (rule->path != NULL);
+
+      path = dbus_message_get_path (message);
+      if (path == NULL)
+        return FALSE;
+
+      if (!str_has_prefix (path, rule->path))
+        return FALSE;
+
+      len = strlen (rule->path);
+
+      /* Check that the actual argument is within the expected
+       * namespace, rather than just starting with that string,
+       * by checking that the matched prefix is followed by a '/'
+       * or the end of the path.
+       */
+      if (path[len] != '\0' && path[len] != '/')
+        return FALSE;
+    }
+
   if (flags & BUS_MATCH_ARGS)
     {
       int i;
@@ -1675,11 +1856,12 @@
           int current_type;
           const char *expected_arg;
           int expected_length;
-          dbus_bool_t is_path;
+          dbus_bool_t is_path, is_namespace;
 
           expected_arg = rule->args[i];
-          expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_IS_PATH;
+          expected_length = rule->arg_lens[i] & ~BUS_MATCH_ARG_FLAGS;
           is_path = (rule->arg_lens[i] & BUS_MATCH_ARG_IS_PATH) != 0;
+          is_namespace = (rule->arg_lens[i] & BUS_MATCH_ARG_NAMESPACE) != 0;
           
           current_type = dbus_message_iter_get_arg_type (&iter);
 
@@ -1687,8 +1869,9 @@
             {
               const char *actual_arg;
               int actual_length;
-              
-              if (current_type != DBUS_TYPE_STRING)
+
+              if (current_type != DBUS_TYPE_STRING &&
+                  (!is_path || current_type != DBUS_TYPE_OBJECT_PATH))
                 return FALSE;
 
               actual_arg = NULL;
@@ -1711,6 +1894,32 @@
                               MIN (actual_length, expected_length)) != 0)
                     return FALSE;
                 }
+              else if (is_namespace)
+                {
+                  if (expected_length > actual_length)
+                    return FALSE;
+
+                  /* If the actual argument doesn't start with the expected
+                   * namespace, then we don't match.
+                   */
+                  if (memcmp (expected_arg, actual_arg, expected_length) != 0)
+                    return FALSE;
+
+                  if (expected_length < actual_length)
+                    {
+                      /* Check that the actual argument is within the expected
+                       * namespace, rather than just starting with that string,
+                       * by checking that the matched prefix ends in a '.'.
+                       *
+                       * This doesn't stop "foo.bar." matching "foo.bar..baz"
+                       * which is an invalid namespace, but at some point the
+                       * daemon can't cover up for broken services.
+                       */
+                      if (actual_arg[expected_length] != '.')
+                        return FALSE;
+                    }
+                  /* otherwise we had an exact match. */
+                }
               else
                 {
                   if (expected_length != actual_length ||
@@ -2025,7 +2234,73 @@
 
       bus_match_rule_unref (rule);
     }
-  
+
+  rule = check_parse (TRUE, "arg7path='/foo'");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags = BUS_MATCH_ARGS);
+      _dbus_assert (rule->args != NULL);
+      _dbus_assert (rule->args_len == 8);
+      _dbus_assert (rule->args[7] != NULL);
+      _dbus_assert (rule->args[8] == NULL);
+      _dbus_assert (strcmp (rule->args[7], "/foo") == 0);
+      _dbus_assert ((rule->arg_lens[7] & BUS_MATCH_ARG_IS_PATH)
+          == BUS_MATCH_ARG_IS_PATH);
+
+      bus_match_rule_unref (rule);
+    }
+
+  /* Arg 0 namespace matches */
+  rule = check_parse (TRUE, "arg0namespace='foo'");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == BUS_MATCH_ARGS);
+      _dbus_assert (rule->args != NULL);
+      _dbus_assert (rule->args_len == 1);
+      _dbus_assert (strcmp (rule->args[0], "foo") == 0);
+      _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
+          == BUS_MATCH_ARG_NAMESPACE);
+
+      bus_match_rule_unref (rule);
+    }
+
+  rule = check_parse (TRUE, "arg0namespace='foo.bar'");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == BUS_MATCH_ARGS);
+      _dbus_assert (rule->args != NULL);
+      _dbus_assert (rule->args_len == 1);
+      _dbus_assert (strcmp (rule->args[0], "foo.bar") == 0);
+      _dbus_assert ((rule->arg_lens[0] & BUS_MATCH_ARG_NAMESPACE)
+          == BUS_MATCH_ARG_NAMESPACE);
+
+      bus_match_rule_unref (rule);
+    }
+
+  /* Only arg0namespace is supported. */
+  rule = check_parse (FALSE, "arg1namespace='foo'");
+  _dbus_assert (rule == NULL);
+
+  /* An empty string isn't a valid namespace prefix (you should just not
+   * specify this key at all).
+   */
+  rule = check_parse (FALSE, "arg0namespace=''");
+  _dbus_assert (rule == NULL);
+
+  /* Trailing periods aren't allowed (earlier versions of the arg0namespace
+   * spec allowed a single trailing period, which altered the semantics) */
+  rule = check_parse (FALSE, "arg0namespace='foo.'");
+  _dbus_assert (rule == NULL);
+
+  rule = check_parse (FALSE, "arg0namespace='foo.bar.'");
+  _dbus_assert (rule == NULL);
+
+  rule = check_parse (FALSE, "arg0namespace='foo..'");
+  _dbus_assert (rule == NULL);
+
+  rule = check_parse (FALSE, "arg0namespace='foo.bar..'");
+  _dbus_assert (rule == NULL);
+
   /* Too-large argN */
   rule = check_parse (FALSE, "arg300='foo'");
   _dbus_assert (rule == NULL);
@@ -2046,6 +2321,24 @@
   rule = check_parse (FALSE, "type='signal',type='method_call'");
   _dbus_assert (rule == NULL);
 
+  rule = check_parse (TRUE, "path_namespace='/foo/bar'");
+  if (rule != NULL)
+    {
+      _dbus_assert (rule->flags == BUS_MATCH_PATH_NAMESPACE);
+      _dbus_assert (rule->path != NULL);
+      _dbus_assert (strcmp (rule->path, "/foo/bar") == 0);
+
+      bus_match_rule_unref (rule);
+    }
+
+  /* Almost a duplicate */
+  rule = check_parse (FALSE, "path='/foo',path_namespace='/foo'");
+  _dbus_assert (rule == NULL);
+
+  /* Trailing / was supported in the initial proposal, but now isn't */
+  rule = check_parse (FALSE, "path_namespace='/foo/'");
+  _dbus_assert (rule == NULL);
+
   /* Duplicates with the argN code */
   rule = check_parse (FALSE, "arg0='foo',arg0='bar'");
   _dbus_assert (rule == NULL);
@@ -2106,6 +2399,7 @@
   { "type='method_call',arg0='blah',arg1='baz'", "arg0='blah',arg1='baz',type='method_call'" },
   { "type='method_call',arg3='foosh'", "arg3='foosh',type='method_call'" },
   { "arg3='fool'", "arg3='fool'" },
+  { "arg0namespace='fool'", "arg0namespace='fool'" },
   { "member='food'", "member='food'" }
 };
 
@@ -2175,6 +2469,13 @@
   "type='signal',member='Frobated',arg0='foobar'",
   "member='Frobated',arg0='foobar'",
   "type='signal',arg0='foobar'",
+  /* The definition of argXpath matches says: "As with normal argument matches,
+   * if the argument is exactly equal to the string given in the match rule
+   * then the rule is satisfied." So this should match (even though the
+   * argument is not a valid path)!
+   */
+  "arg0path='foobar'",
+  "arg0namespace='foobar'",
   NULL
 };
 
@@ -2193,6 +2494,44 @@
   "arg0='foobar',arg1='abcdef'",
   "arg0='foobar',arg1='abcdef',arg2='abcdefghi',arg3='abcdefghi',arg4='abcdefghi'",
   "arg0='foobar',arg1='abcdef',arg4='abcdefghi',arg3='abcdefghi',arg2='abcdefghi'",
+  "arg0path='foo'",
+  "arg0path='foobar/'",
+  "arg1path='3'",
+  "arg0namespace='foo'",
+  "arg0namespace='foo',arg1='abcdef'",
+  "arg0namespace='moo'",
+  NULL
+};
+
+#define EXAMPLE_NAME "com.example.backend.foo"
+
+static const char *
+should_match_message_2[] = {
+  /* EXAMPLE_NAME is in all of these namespaces */
+  "arg0namespace='com.example.backend'",
+  "arg0namespace='com.example'",
+  "arg0namespace='com'",
+
+  /* If the client specifies the name exactly, with no trailing period, then
+   * it should match.
+   */
+  "arg0namespace='com.example.backend.foo'",
+
+  NULL
+};
+
+static const char *
+should_not_match_message_2[] = {
+  /* These are not even prefixes */
+  "arg0namespace='com.example.backend.foo.bar'",
+  "arg0namespace='com.example.backend.foobar'",
+
+  /* These are prefixes, but they're not parent namespaces. */
+  "arg0namespace='com.example.backend.fo'",
+  "arg0namespace='com.example.backen'",
+  "arg0namespace='com.exampl'",
+  "arg0namespace='co'",
+
   NULL
 };
 
@@ -2248,7 +2587,7 @@
 static void
 test_matching (void)
 {
-  DBusMessage *message1;
+  DBusMessage *message1, *message2;
   const char *v_STRING;
   dbus_int32_t v_INT32;
 
@@ -2270,6 +2609,185 @@
                   should_not_match_message_1);
   
   dbus_message_unref (message1);
+
+  message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
+  _dbus_assert (message2 != NULL);
+  if (!dbus_message_set_member (message2, "NameOwnerChanged"))
+    _dbus_assert_not_reached ("oom");
+
+  /* Obviously this isn't really a NameOwnerChanged signal. */
+  v_STRING = EXAMPLE_NAME;
+  if (!dbus_message_append_args (message2,
+                                 DBUS_TYPE_STRING, &v_STRING,
+                                 NULL))
+    _dbus_assert_not_reached ("oom");
+
+  check_matching (message2, 2,
+                  should_match_message_2,
+                  should_not_match_message_2);
+
+  dbus_message_unref (message2);
+}
+
+#define PATH_MATCH_RULE "arg0path='/aa/bb/'"
+
+/* This is a list of paths that should be matched by PATH_MATCH_RULE, taken
+ * from the specification. Notice that not all of them are actually legal D-Bus
+ * paths.
+ *
+ * The author of this test takes no responsibility for the semantics of
+ * this match rule key.
+ */
+static const char *paths_that_should_be_matched[] = {
+    "/aa/",
+    "/aa/bb/",
+    "/aa/bb/cc/",
+#define FIRST_VALID_PATH_WHICH_SHOULD_MATCH 3
+    "/",
+    "/aa/bb/cc",
+    NULL
+};
+
+/* These paths should not be matched by PATH_MATCH_RULE. */
+static const char *paths_that_should_not_be_matched[] = {
+    "/aa/b",
+    "/aa",
+    /* or even... */
+    "/aa/bb",
+    NULL
+};
+
+static void
+test_path_match (int type,
+                 const char   *path,
+                 const char   *rule_text,
+                 BusMatchRule *rule,
+                 dbus_bool_t   should_match)
+{
+  DBusMessage *message = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
+  dbus_bool_t matched;
+
+  _dbus_assert (message != NULL);
+  if (!dbus_message_set_member (message, "Foo"))
+    _dbus_assert_not_reached ("oom");
+
+  if (!dbus_message_append_args (message,
+                                 type, &path,
+                                 NULL))
+    _dbus_assert_not_reached ("oom");
+
+  matched = match_rule_matches (rule, NULL, NULL, message, 0);
+
+  if (matched != should_match)
+    {
+      _dbus_warn ("Expected rule %s to %s message "
+                  "with first arg %s of type '%c', failed\n",
+                  rule_text,
+                  should_match ? "match" : "not match",
+                  path,
+                  (char) type);
+      exit (1);
+    }
+
+  dbus_message_unref (message);
+}
+
+static void
+test_path_matching (void)
+{
+  BusMatchRule *rule;
+  const char **s;
+
+  rule = check_parse (TRUE, PATH_MATCH_RULE);
+  _dbus_assert (rule != NULL);
+
+  for (s = paths_that_should_be_matched; *s != NULL; s++)
+    test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, TRUE);
+
+  for (s = paths_that_should_be_matched + FIRST_VALID_PATH_WHICH_SHOULD_MATCH;
+       *s != NULL; s++)
+    test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, TRUE);
+
+  for (s = paths_that_should_not_be_matched; *s != NULL; s++)
+    {
+      test_path_match (DBUS_TYPE_STRING, *s, PATH_MATCH_RULE, rule, FALSE);
+      test_path_match (DBUS_TYPE_OBJECT_PATH, *s, PATH_MATCH_RULE, rule, FALSE);
+    }
+
+  bus_match_rule_unref (rule);
+}
+
+static const char*
+path_namespace_should_match_message_1[] = {
+  "type='signal',path_namespace='/foo'",
+  "type='signal',path_namespace='/foo/TheObjectManager'",
+  NULL
+};
+
+static const char*
+path_namespace_should_not_match_message_1[] = {
+  "type='signal',path_namespace='/bar'",
+  "type='signal',path_namespace='/bar/TheObjectManager'",
+  NULL
+};
+
+static const char*
+path_namespace_should_match_message_2[] = {
+  "type='signal',path_namespace='/foo/TheObjectManager'",
+  NULL
+};
+
+static const char*
+path_namespace_should_not_match_message_2[] = {
+  NULL
+};
+
+static const char*
+path_namespace_should_match_message_3[] = {
+  NULL
+};
+
+static const char*
+path_namespace_should_not_match_message_3[] = {
+  "type='signal',path_namespace='/foo/TheObjectManager'",
+  NULL
+};
+
+static void
+test_matching_path_namespace (void)
+{
+  DBusMessage *message1;
+  DBusMessage *message2;
+  DBusMessage *message3;
+
+  message1 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
+  _dbus_assert (message1 != NULL);
+  if (!dbus_message_set_path (message1, "/foo/TheObjectManager"))
+    _dbus_assert_not_reached ("oom");
+
+  message2 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
+  _dbus_assert (message2 != NULL);
+  if (!dbus_message_set_path (message2, "/foo/TheObjectManager/child_object"))
+    _dbus_assert_not_reached ("oom");
+
+  message3 = dbus_message_new (DBUS_MESSAGE_TYPE_SIGNAL);
+  _dbus_assert (message3 != NULL);
+  if (!dbus_message_set_path (message3, "/foo/TheObjectManagerOther"))
+    _dbus_assert_not_reached ("oom");
+
+  check_matching (message1, 1,
+                  path_namespace_should_match_message_1,
+                  path_namespace_should_not_match_message_1);
+  check_matching (message2, 2,
+                  path_namespace_should_match_message_2,
+                  path_namespace_should_not_match_message_2);
+  check_matching (message3, 3,
+                  path_namespace_should_match_message_3,
+                  path_namespace_should_not_match_message_3);
+
+  dbus_message_unref (message3);
+  dbus_message_unref (message2);
+  dbus_message_unref (message1);
 }
 
 dbus_bool_t
@@ -2286,9 +2804,10 @@
     _dbus_assert_not_reached ("Parsing match rules test failed");
 
   test_equality ();
-
   test_matching ();
-  
+  test_path_matching ();
+  test_matching_path_namespace ();
+
   return TRUE;
 }
 
diff --git a/bus/signals.h b/bus/signals.h
index eeb1d2d..a71d2e4 100644
--- a/bus/signals.h
+++ b/bus/signals.h
@@ -31,13 +31,15 @@
 
 typedef enum
 {
-  BUS_MATCH_MESSAGE_TYPE = 1 << 0,
-  BUS_MATCH_INTERFACE    = 1 << 1,
-  BUS_MATCH_MEMBER       = 1 << 2,
-  BUS_MATCH_SENDER       = 1 << 3,
-  BUS_MATCH_DESTINATION  = 1 << 4,
-  BUS_MATCH_PATH         = 1 << 5,
-  BUS_MATCH_ARGS         = 1 << 6
+  BUS_MATCH_MESSAGE_TYPE            = 1 << 0,
+  BUS_MATCH_INTERFACE               = 1 << 1,
+  BUS_MATCH_MEMBER                  = 1 << 2,
+  BUS_MATCH_SENDER                  = 1 << 3,
+  BUS_MATCH_DESTINATION             = 1 << 4,
+  BUS_MATCH_PATH                    = 1 << 5,
+  BUS_MATCH_ARGS                    = 1 << 6,
+  BUS_MATCH_PATH_NAMESPACE          = 1 << 7,
+  BUS_MATCH_CLIENT_IS_EAVESDROPPING = 1 << 8
 } BusMatchFlags;
 
 BusMatchRule* bus_match_rule_new   (DBusConnection *matches_go_to);
@@ -55,11 +57,21 @@
 dbus_bool_t bus_match_rule_set_destination  (BusMatchRule     *rule,
                                              const char       *destination);
 dbus_bool_t bus_match_rule_set_path         (BusMatchRule     *rule,
-                                             const char       *path);
+                                             const char       *path,
+                                             dbus_bool_t       is_namespace);
 dbus_bool_t bus_match_rule_set_arg          (BusMatchRule     *rule,
                                              int               arg,
                                              const DBusString *value,
-                                             dbus_bool_t       is_path);
+                                             dbus_bool_t       is_path,
+                                             dbus_bool_t       is_namespace);
+
+/* Calling this methods a client declares that it is creating a rule which
+ * needs to eavesdrop (e.g., dbus-monitor), any other created rules not
+ * setting themselves as eavesdropping won't receive any message not addressed
+ * to them, when eavedrop is enabled in the policy.  On the other hand, when
+ * eavedrop is not enabled in policy, this method won't have any effect */
+void bus_match_rule_set_client_is_eavesdropping (BusMatchRule     *rule,
+                                                 dbus_bool_t is_eavesdropping);
 
 BusMatchRule* bus_match_rule_parse (DBusConnection   *matches_go_to,
                                     const DBusString *rule_text,
diff --git a/bus/stats.c b/bus/stats.c
new file mode 100644
index 0000000..28fd49b
--- /dev/null
+++ b/bus/stats.c
@@ -0,0 +1,352 @@
+/* stats.c - statistics from the bus driver
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <config.h>
+#include "stats.h"
+
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-connection-internal.h>
+
+#include "connection.h"
+#include "services.h"
+#include "utils.h"
+
+#ifdef DBUS_ENABLE_STATS
+
+static DBusMessage *
+new_asv_reply (DBusMessage      *message,
+               DBusMessageIter  *iter,
+               DBusMessageIter  *arr_iter)
+{
+  DBusMessage *reply = dbus_message_new_method_return (message);
+
+  if (reply == NULL)
+    return NULL;
+
+  dbus_message_iter_init_append (reply, iter);
+
+  if (!dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, "{sv}",
+                                         arr_iter))
+    {
+      dbus_message_unref (reply);
+      return NULL;
+    }
+
+  return reply;
+}
+
+static dbus_bool_t
+open_asv_entry (DBusMessageIter *arr_iter,
+                DBusMessageIter *entry_iter,
+                const char      *key,
+                const char      *type,
+                DBusMessageIter *var_iter)
+{
+  if (!dbus_message_iter_open_container (arr_iter, DBUS_TYPE_DICT_ENTRY,
+                                         NULL, entry_iter))
+    return FALSE;
+
+  if (!dbus_message_iter_append_basic (entry_iter, DBUS_TYPE_STRING, &key))
+    {
+      dbus_message_iter_abandon_container (arr_iter, entry_iter);
+      return FALSE;
+    }
+
+  if (!dbus_message_iter_open_container (entry_iter, DBUS_TYPE_VARIANT,
+                                         type, var_iter))
+    {
+      dbus_message_iter_abandon_container (arr_iter, entry_iter);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static dbus_bool_t
+close_asv_entry (DBusMessageIter *arr_iter,
+                 DBusMessageIter *entry_iter,
+                 DBusMessageIter *var_iter)
+{
+  if (!dbus_message_iter_close_container (entry_iter, var_iter))
+    {
+      dbus_message_iter_abandon_container (arr_iter, entry_iter);
+      return FALSE;
+    }
+
+  if (!dbus_message_iter_close_container (arr_iter, entry_iter))
+    return FALSE;
+
+  return TRUE;
+}
+
+static dbus_bool_t
+close_asv_reply (DBusMessageIter *iter,
+                 DBusMessageIter *arr_iter)
+{
+  return dbus_message_iter_close_container (iter, arr_iter);
+}
+
+static void
+abandon_asv_entry (DBusMessageIter *arr_iter,
+                   DBusMessageIter *entry_iter,
+                   DBusMessageIter *var_iter)
+{
+  dbus_message_iter_abandon_container (entry_iter, var_iter);
+  dbus_message_iter_abandon_container (arr_iter, entry_iter);
+}
+
+static void
+abandon_asv_reply (DBusMessageIter *iter,
+                 DBusMessageIter *arr_iter)
+{
+  dbus_message_iter_abandon_container (iter, arr_iter);
+}
+
+static dbus_bool_t
+asv_add_uint32 (DBusMessageIter *iter,
+                DBusMessageIter *arr_iter,
+                const char *key,
+                dbus_uint32_t value)
+{
+  DBusMessageIter entry_iter, var_iter;
+
+  if (!open_asv_entry (arr_iter, &entry_iter, key, DBUS_TYPE_UINT32_AS_STRING,
+                       &var_iter))
+    goto oom;
+
+  if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_UINT32,
+                                       &value))
+    {
+      abandon_asv_entry (arr_iter, &entry_iter, &var_iter);
+      goto oom;
+    }
+
+  if (!close_asv_entry (arr_iter, &entry_iter, &var_iter))
+    goto oom;
+
+  return TRUE;
+
+oom:
+  abandon_asv_reply (iter, arr_iter);
+  return FALSE;
+}
+
+static dbus_bool_t
+asv_add_string (DBusMessageIter *iter,
+                DBusMessageIter *arr_iter,
+                const char *key,
+                const char *value)
+{
+  DBusMessageIter entry_iter, var_iter;
+
+  if (!open_asv_entry (arr_iter, &entry_iter, key, DBUS_TYPE_STRING_AS_STRING,
+                       &var_iter))
+    goto oom;
+
+  if (!dbus_message_iter_append_basic (&var_iter, DBUS_TYPE_STRING,
+                                       &value))
+    {
+      abandon_asv_entry (arr_iter, &entry_iter, &var_iter);
+      goto oom;
+    }
+
+  if (!close_asv_entry (arr_iter, &entry_iter, &var_iter))
+    goto oom;
+
+  return TRUE;
+
+oom:
+  abandon_asv_reply (iter, arr_iter);
+  return FALSE;
+}
+
+dbus_bool_t
+bus_stats_handle_get_stats (DBusConnection *connection,
+                            BusTransaction *transaction,
+                            DBusMessage    *message,
+                            DBusError      *error)
+{
+  BusConnections *connections;
+  DBusMessage *reply = NULL;
+  DBusMessageIter iter, arr_iter;
+  static dbus_uint32_t stats_serial = 0;
+  dbus_uint32_t in_use, in_free_list, allocated;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  connections = bus_transaction_get_connections (transaction);
+
+  reply = new_asv_reply (message, &iter, &arr_iter);
+
+  if (reply == NULL)
+    goto oom;
+
+  /* Globals */
+
+  if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++))
+    goto oom;
+
+  _dbus_list_get_stats (&in_use, &in_free_list, &allocated);
+  if (!asv_add_uint32 (&iter, &arr_iter, "ListMemPoolUsedBytes", in_use) ||
+      !asv_add_uint32 (&iter, &arr_iter, "ListMemPoolCachedBytes",
+                       in_free_list) ||
+      !asv_add_uint32 (&iter, &arr_iter, "ListMemPoolAllocatedBytes",
+                       allocated))
+    goto oom;
+
+  /* Connections */
+
+  if (!asv_add_uint32 (&iter, &arr_iter, "ActiveConnections",
+        bus_connections_get_n_active (connections)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "IncompleteConnections",
+        bus_connections_get_n_incomplete (connections)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "MatchRules",
+        bus_connections_get_total_match_rules (connections)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakMatchRules",
+        bus_connections_get_peak_match_rules (connections)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakMatchRulesPerConnection",
+        bus_connections_get_peak_match_rules_per_conn (connections)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "BusNames",
+        bus_connections_get_total_bus_names (connections)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakBusNames",
+        bus_connections_get_peak_bus_names (connections)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakBusNamesPerConnection",
+        bus_connections_get_peak_bus_names_per_conn (connections)))
+    goto oom;
+
+  /* end */
+
+  if (!close_asv_reply (&iter, &arr_iter))
+    goto oom;
+
+  if (!bus_transaction_send_from_driver (transaction, connection, reply))
+    goto oom;
+
+  dbus_message_unref (reply);
+  return TRUE;
+
+oom:
+  if (reply != NULL)
+    dbus_message_unref (reply);
+
+  BUS_SET_OOM (error);
+  return FALSE;
+}
+
+dbus_bool_t
+bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
+                                       BusTransaction *transaction,
+                                       DBusMessage    *message,
+                                       DBusError      *error)
+{
+  const char *bus_name = NULL;
+  DBusString bus_name_str;
+  DBusMessage *reply = NULL;
+  DBusMessageIter iter, arr_iter;
+  static dbus_uint32_t stats_serial = 0;
+  dbus_uint32_t in_messages, in_bytes, in_fds, in_peak_bytes, in_peak_fds;
+  dbus_uint32_t out_messages, out_bytes, out_fds, out_peak_bytes, out_peak_fds;
+  BusRegistry *registry;
+  BusService *service;
+  DBusConnection *stats_connection;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  registry = bus_connection_get_registry (caller_connection);
+
+  if (! dbus_message_get_args (message, error,
+                               DBUS_TYPE_STRING, &bus_name,
+                               DBUS_TYPE_INVALID))
+      return FALSE;
+
+  _dbus_string_init_const (&bus_name_str, bus_name);
+  service = bus_registry_lookup (registry, &bus_name_str);
+
+  if (service == NULL)
+    {
+      dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
+                      "Bus name '%s' has no owner", bus_name);
+      return FALSE;
+    }
+
+  stats_connection = bus_service_get_primary_owners_connection (service);
+  _dbus_assert (stats_connection != NULL);
+
+  reply = new_asv_reply (message, &iter, &arr_iter);
+
+  if (reply == NULL)
+    goto oom;
+
+  /* Bus daemon per-connection stats */
+
+  if (!asv_add_uint32 (&iter, &arr_iter, "Serial", stats_serial++) ||
+      !asv_add_uint32 (&iter, &arr_iter, "MatchRules",
+        bus_connection_get_n_match_rules (stats_connection)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakMatchRules",
+        bus_connection_get_peak_match_rules (stats_connection)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "BusNames",
+        bus_connection_get_n_services_owned (stats_connection)) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakBusNames",
+        bus_connection_get_peak_bus_names (stats_connection)) ||
+      !asv_add_string (&iter, &arr_iter, "UniqueName",
+        bus_connection_get_name (stats_connection)))
+    goto oom;
+
+  /* DBusConnection per-connection stats */
+
+  _dbus_connection_get_stats (stats_connection,
+                              &in_messages, &in_bytes, &in_fds,
+                              &in_peak_bytes, &in_peak_fds,
+                              &out_messages, &out_bytes, &out_fds,
+                              &out_peak_bytes, &out_peak_fds);
+
+  if (!asv_add_uint32 (&iter, &arr_iter, "IncomingMessages", in_messages) ||
+      !asv_add_uint32 (&iter, &arr_iter, "IncomingBytes", in_bytes) ||
+      !asv_add_uint32 (&iter, &arr_iter, "IncomingFDs", in_fds) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakIncomingBytes", in_peak_bytes) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakIncomingFDs", in_peak_fds) ||
+      !asv_add_uint32 (&iter, &arr_iter, "OutgoingMessages", out_messages) ||
+      !asv_add_uint32 (&iter, &arr_iter, "OutgoingBytes", out_bytes) ||
+      !asv_add_uint32 (&iter, &arr_iter, "OutgoingFDs", out_fds) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakOutgoingBytes", out_peak_bytes) ||
+      !asv_add_uint32 (&iter, &arr_iter, "PeakOutgoingFDs", out_peak_fds))
+    goto oom;
+
+  /* end */
+
+  if (!close_asv_reply (&iter, &arr_iter))
+    goto oom;
+
+  if (!bus_transaction_send_from_driver (transaction, caller_connection,
+                                         reply))
+    goto oom;
+
+  dbus_message_unref (reply);
+  return TRUE;
+
+oom:
+  if (reply != NULL)
+    dbus_message_unref (reply);
+
+  BUS_SET_OOM (error);
+  return FALSE;
+}
+
+#endif
diff --git a/bus/stats.h b/bus/stats.h
new file mode 100644
index 0000000..0f843db
--- /dev/null
+++ b/bus/stats.h
@@ -0,0 +1,38 @@
+/* stats.h - statistics from the bus driver
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef BUS_STATS_H
+#define BUS_STATS_H
+
+#include "bus.h"
+
+#define BUS_INTERFACE_STATS "org.freedesktop.DBus.Debug.Stats"
+
+dbus_bool_t bus_stats_handle_get_stats (DBusConnection *connection,
+                                        BusTransaction *transaction,
+                                        DBusMessage    *message,
+                                        DBusError      *error);
+
+dbus_bool_t bus_stats_handle_get_connection_stats (DBusConnection *connection,
+                                                   BusTransaction *transaction,
+                                                   DBusMessage    *message,
+                                                   DBusError      *error);
+
+#endif /* multiple-inclusion guard */
diff --git a/bus/test-main.c b/bus/test-main.c
index cb0ed00..0f736c7 100644
--- a/bus/test-main.c
+++ b/bus/test-main.c
@@ -28,7 +28,7 @@
 #include <dbus/dbus-string.h>
 #include <dbus/dbus-sysdeps.h>
 #include <dbus/dbus-internals.h>
-#include <dbus/dbus-message-private.h>
+#include <dbus/dbus-message-internal.h>
 #include "selinux.h"
 
 #ifdef DBUS_BUILD_TESTS
@@ -54,6 +54,8 @@
 }
 #endif /* DBUS_BUILD_TESTS */
 
+static DBusInitialFDs *initial_fds = NULL;
+
 static void
 test_pre_hook (void)
 {
@@ -62,16 +64,21 @@
       && (!bus_selinux_pre_init ()
 	  || !bus_selinux_full_init ()))
     die ("could not init selinux support");
+
+  initial_fds = _dbus_check_fdleaks_enter ();
 }
 
 static char *progname = "";
+
 static void
 test_post_hook (void)
 {
   if (_dbus_getenv ("DBUS_TEST_SELINUX"))
     bus_selinux_shutdown ();
   check_memleaks (progname);
-  _dbus_check_fdleaks();
+
+  _dbus_check_fdleaks_leave (initial_fds);
+  initial_fds = NULL;
 }
 
 int
@@ -79,6 +86,7 @@
 {
 #ifdef DBUS_BUILD_TESTS
   const char *dir;
+  const char *only;
   DBusString test_data_dir;
 
   progname = argv[0];
@@ -88,6 +96,11 @@
   else
     dir = _dbus_getenv ("DBUS_TEST_DATA");
 
+  if (argc > 2)
+    only = argv[2];
+  else
+    only = NULL;
+
   if (dir == NULL)
     {
       fprintf (stderr, "Must specify test data directory as argv[1] or in DBUS_TEST_DATA env variable\n");
@@ -98,55 +111,70 @@
 
   if (!_dbus_threads_init_debug ())
     die ("initializing debug threads");
- 
-  test_pre_hook ();
-  printf ("%s: Running expire list test\n", argv[0]);
-  if (!bus_expire_list_test (&test_data_dir))
-    die ("expire list");
-  test_post_hook ();
- 
-  test_pre_hook ();
-  printf ("%s: Running config file parser test\n", argv[0]);
-  if (!bus_config_parser_test (&test_data_dir))
-    die ("parser");
-  test_post_hook ();
 
-  test_pre_hook ();
-  printf ("%s: Running policy test\n", argv[0]);
-  if (!bus_policy_test (&test_data_dir))
-    die ("policy");
-  test_post_hook ();
+  if (only == NULL || strcmp (only, "expire-list") == 0)
+    {
+      test_pre_hook ();
+      printf ("%s: Running expire list test\n", argv[0]);
+      if (!bus_expire_list_test (&test_data_dir))
+        die ("expire list");
+      test_post_hook ();
+    }
 
-  test_pre_hook ();
-  printf ("%s: Running signals test\n", argv[0]);
-  if (!bus_signals_test (&test_data_dir))
-    die ("signals");
-  test_post_hook ();
+  if (only == NULL || strcmp (only, "config-parser") == 0)
+    {
+      test_pre_hook ();
+      printf ("%s: Running config file parser test\n", argv[0]);
+      if (!bus_config_parser_test (&test_data_dir))
+        die ("parser");
+      test_post_hook ();
+    }
 
-  test_pre_hook ();
-  printf ("%s: Running SHA1 connection test\n", argv[0]);
-  if (!bus_dispatch_sha1_test (&test_data_dir))
-    die ("sha1");
-  test_post_hook ();
+  if (only == NULL || strcmp (only, "signals") == 0)
+    {
+      test_pre_hook ();
+      printf ("%s: Running signals test\n", argv[0]);
+      if (!bus_signals_test (&test_data_dir))
+        die ("signals");
+      test_post_hook ();
+    }
 
-  test_pre_hook ();
-  printf ("%s: Running message dispatch test\n", argv[0]);
-  if (!bus_dispatch_test (&test_data_dir)) 
-    die ("dispatch");
-  test_post_hook ();
+  if (only == NULL || strcmp (only, "dispatch-sha1") == 0)
+    {
+      test_pre_hook ();
+      printf ("%s: Running SHA1 connection test\n", argv[0]);
+      if (!bus_dispatch_sha1_test (&test_data_dir))
+        die ("sha1");
+      test_post_hook ();
+    }
 
-  test_pre_hook ();
-  printf ("%s: Running service files reloading test\n", argv[0]);
-  if (!bus_activation_service_reload_test (&test_data_dir))
-    die ("service reload");
-  test_post_hook ();
+  if (only == NULL || strcmp (only, "dispatch") == 0)
+    {
+      test_pre_hook ();
+      printf ("%s: Running message dispatch test\n", argv[0]);
+      if (!bus_dispatch_test (&test_data_dir)) 
+        die ("dispatch");
+      test_post_hook ();
+    }
+
+  if (only == NULL || strcmp (only, "activation-service-reload") == 0)
+    {
+      test_pre_hook ();
+      printf ("%s: Running service files reloading test\n", argv[0]);
+      if (!bus_activation_service_reload_test (&test_data_dir))
+        die ("service reload");
+      test_post_hook ();
+    }
 
 #ifdef HAVE_UNIX_FD_PASSING
-  test_pre_hook ();
-  printf ("%s: Running unix fd passing test\n", argv[0]);
-  if (!bus_unix_fds_passing_test (&test_data_dir))
-    die ("unix fd passing");
-  test_post_hook ();
+  if (only == NULL || strcmp (only, "unix-fds-passing") == 0)
+    {
+      test_pre_hook ();
+      printf ("%s: Running unix fd passing test\n", argv[0]);
+      if (!bus_unix_fds_passing_test (&test_data_dir))
+        die ("unix fd passing");
+      test_post_hook ();
+    }
 #endif
 
   printf ("%s: Success\n", argv[0]);
diff --git a/bus/test.c b/bus/test.c
index 6efad6e..1ca9607 100644
--- a/bus/test.c
+++ b/bus/test.c
@@ -37,69 +37,38 @@
 static DBusLoop *client_loop = NULL;
 
 static dbus_bool_t
-client_watch_callback (DBusWatch     *watch,
-                       unsigned int   condition,
-                       void          *data)
-{
-  /* FIXME this can be done in dbus-mainloop.c
-   * if the code in activation.c for the babysitter
-   * watch handler is fixed.
-   */
-
-  return dbus_watch_handle (watch, condition);
-}
-
-static dbus_bool_t
 add_client_watch (DBusWatch      *watch,
                   void           *data)
 {
-  DBusConnection *connection = data;
-
-  return _dbus_loop_add_watch (client_loop,
-                               watch, client_watch_callback, connection,
-                               NULL);
+  return _dbus_loop_add_watch (client_loop, watch);
 }
 
 static void
 remove_client_watch (DBusWatch      *watch,
                      void           *data)
 {
-  DBusConnection *connection = data;
-
-  _dbus_loop_remove_watch (client_loop,
-                           watch, client_watch_callback, connection);
+  _dbus_loop_remove_watch (client_loop, watch);
 }
 
 static void
-client_timeout_callback (DBusTimeout   *timeout,
-                         void          *data)
+toggle_client_watch (DBusWatch      *watch,
+                     void           *data)
 {
-  DBusConnection *connection = data;
-
-  dbus_connection_ref (connection);
-
-  /* can return FALSE on OOM but we just let it fire again later */
-  dbus_timeout_handle (timeout);
-
-  dbus_connection_unref (connection);
+  _dbus_loop_toggle_watch (client_loop, watch);
 }
 
 static dbus_bool_t
 add_client_timeout (DBusTimeout    *timeout,
                     void           *data)
 {
-  DBusConnection *connection = data;
-
-  return _dbus_loop_add_timeout (client_loop, timeout, client_timeout_callback, connection, NULL);
+  return _dbus_loop_add_timeout (client_loop, timeout);
 }
 
 static void
 remove_client_timeout (DBusTimeout    *timeout,
                        void           *data)
 {
-  DBusConnection *connection = data;
-
-  _dbus_loop_remove_timeout (client_loop, timeout, client_timeout_callback, connection);
+  _dbus_loop_remove_timeout (client_loop, timeout);
 }
 
 static DBusHandlerResult
@@ -150,7 +119,7 @@
   if (!dbus_connection_set_watch_functions (connection,
                                             add_client_watch,
                                             remove_client_watch,
-                                            NULL,
+                                            toggle_client_watch,
                                             connection,
                                             NULL))
     goto out;
@@ -323,7 +292,7 @@
     }
 
   dbus_error_init (&error);
-  context = bus_context_new (&config_file, FALSE, NULL, NULL, NULL, FALSE, &error);
+  context = bus_context_new (&config_file, BUS_CONTEXT_FLAG_NONE, NULL, NULL, NULL, &error);
   if (context == NULL)
     {
       _DBUS_ASSERT_ERROR_IS_SET (&error);
diff --git a/bus/test.h b/bus/test.h
index 45024e6..98a2c6b 100644
--- a/bus/test.h
+++ b/bus/test.h
@@ -32,7 +32,6 @@
 
 dbus_bool_t bus_dispatch_test         (const DBusString             *test_data_dir);
 dbus_bool_t bus_dispatch_sha1_test    (const DBusString             *test_data_dir);
-dbus_bool_t bus_policy_test           (const DBusString             *test_data_dir);
 dbus_bool_t bus_config_parser_test    (const DBusString             *test_data_dir);
 dbus_bool_t bus_config_parser_trivial_test (const DBusString        *test_data_dir);
 dbus_bool_t bus_signals_test          (const DBusString             *test_data_dir);
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index a9aa40e..000acda 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -1,20 +1,5 @@
 project(dbus)
 
-set (DBUS_MAJOR_VERSION "1")
-set (DBUS_MINOR_VERSION "3")
-set (DBUS_MICRO_VERSION "1")
-# used by file version info
-set (DBUS_PATCH_VERSION "1")
-set (DBUS_VERSION ${DBUS_MAJOR_VERSION}.${DBUS_MINOR_VERSION}.${DBUS_MICRO_VERSION})
-endif (DBUS_PATCH_VERSION)
-
-set (DBUS_VERSION_STRING "${DBUS_VERSION}")
-
-if (NOT DBUS_BUILD_TIMESTAMP)
-    message(STATUS "FIXME set DBUS_BUILD_TIMESTAMP to current date or fix current time stamp generation for having actual build date in version file info")
-    set (DBUS_BUILD_TIMESTAMP 20091231)
-endif (NOT DBUS_BUILD_TIMESTAMP)
-
 # we need to be up to date
 CMAKE_MINIMUM_REQUIRED(VERSION 2.4.4 FATAL_ERROR)
 if(COMMAND cmake_policy)
@@ -24,6 +9,60 @@
 # where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
 set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/modules")
 
+# detect version
+include(MacrosAutotools)
+autoversion(../configure.ac dbus)
+# used by file version info
+set (DBUS_PATCH_VERSION "0")
+
+include(Macros)
+TIMESTAMP(DBUS_BUILD_TIMESTAMP)
+
+########### basic vars ###############
+
+
+if (DBUSDIR)
+	set(DBUS_INSTALL_DIR "${DBUSDIR}")
+endif (DBUSDIR)
+if ($ENV{DBUSDIR})
+	set(DBUS_INSTALL_DIR "$ENV{DBUSDIR}")
+endif ($ENV{DBUSDIR})
+
+if (DBUS_INSTALL_DIR)
+	set(CMAKE_INSTALL_PREFIX "${DBUS_INSTALL_DIR}" CACHE PATH "install prefix" FORCE)
+else (DBUS_INSTALL_DIR)
+	set(DBUS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}")
+endif (DBUS_INSTALL_DIR)
+
+# autotools style
+if (NOT DATAROOTDIR)
+    set (DATAROOTDIR share)
+endif()
+
+if (NOT DATADIR)
+    set (DATADIR ${DATAROOTDIR})
+endif()
+
+if (NOT DOCDIR)
+    SET(DOCDIR ${DATAROOTDIR}/doc/dbus)
+endif()
+
+if (NOT DBUS_DATADIR)
+    SET(DBUS_DATADIR ${DATADIR})
+endif()
+
+set(prefix                   ${DBUS_INSTALL_DIR})
+set(exec_prefix              ${prefix})
+set(EXPANDED_LIBDIR          ${DBUS_INSTALL_DIR}/lib)
+set(EXPANDED_INCLUDEDIR      ${DBUS_INSTALL_DIR}/include)
+set(EXPANDED_BINDIR          ${DBUS_INSTALL_DIR}/bin)
+set(EXPANDED_SYSCONFDIR      ${DBUS_INSTALL_DIR}/etc)
+set(EXPANDED_DATADIR         ${DBUS_INSTALL_DIR}/${DBUS_DATADIR})
+set(DBUS_MACHINE_UUID_FILE   ${DBUS_INSTALL_DIR}/lib/dbus/machine-id)
+set(DBUS_BINDIR              ${EXPANDED_BINDIR})
+set(DBUS_DAEMONDIR 			 ${EXPANDED_BINDIR})
+
+
 #enable building of shared library
 SET(BUILD_SHARED_LIBS ON)
 
@@ -39,16 +78,31 @@
     include(Win32Macros)
     addExplorerWrapper(${CMAKE_PROJECT_NAME})
 endif (WIN32)
-find_package(LibXml2)
-find_package(LibExpat)
-find_package(X11)
+
+option (DBUS_USE_EXPAT "Use expat (== ON) or libxml2 (==OFF)" ON)
 
 if(NOT WIN32)
-	OPTION(DBUS_ENABLE_ABSTRACT_SOCKETS "enable support for abstract sockets" ON)
+	option (DBUS_ENABLE_ABSTRACT_SOCKETS "enable support for abstract sockets" ON)
+	set (CMAKE_THREAD_PREFER_PTHREAD ON)
+	include (FindThreads)
 endif(NOT WIN32)
 
 #AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion checks]),enable_asserts=$enableval,enable_asserts=$USE_MAINTAINER_MODE)
-OPTION(DBUS_DISABLE_ASSERTS "Disable assertion checking" OFF)
+option (DBUS_DISABLE_ASSERTS "Disable assertion checking" OFF)
+
+option (DBUS_ENABLE_STATS "enable bus daemon usage statistics" OFF)
+
+option (DBUS_ENABLE_STATS "enable bus daemon usage statistics" OFF)
+
+if (DBUS_USE_EXPAT)
+    find_package(LibExpat)
+else ()
+    find_package(LibXml2)
+endif ()
+find_package(X11)
+
+# analogous to AC_USE_SYSTEM_EXTENSIONS in configure.ac
+add_definitions(-D_POSIX_C_SOURCE=199309L -D_GNU_SOURCE)
 
 # do config checks
 INCLUDE(ConfigureChecks.cmake)
@@ -60,8 +114,7 @@
 include (MacroLibrary)
 
 if(VCS)
-	set(DBUS_VERBOSE_C_S 1 CACHE TYPE STRING FORCE)
-	set(DBUS_VERBOSE_C_S 1)
+	set(DBUS_VERBOSE_C_S 1 CACHE STRING "verbose mode" FORCE)
 endif(VCS)
 
 if(WIN32)
@@ -78,8 +131,8 @@
 
 		# Use the highest warning level
 		if (WALL)
-			set(WALL 1 CACHE TYPE STRING FORCE)
-			set(CMAKE_CXX_WARNING_LEVEL 4 CACHE TYPE STRING FORCE)
+			set(WALL 1 CACHE STRING "all warnings"  FORCE)
+			set(CMAKE_CXX_WARNING_LEVEL 4 CACHE STRING "warning level" FORCE)
 
 			if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
 				STRING(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
@@ -93,7 +146,7 @@
 				SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
 			endif(CMAKE_C_FLAGS MATCHES "/W[0-4]")
 		else (WALL)
-			set(CMAKE_CXX_WARNING_LEVEL 3 CACHE TYPE STRING FORCE)
+			set(CMAKE_CXX_WARNING_LEVEL 3 CACHE STRING "warning level" FORCE)
 		endif (WALL)
 
 		SET(MSVC_W_ERROR   " /we4028 /we4013 /we4133 /we4047 /we4031 /we4002 /we4003 /we4114")
@@ -171,55 +224,28 @@
 
 ENABLE_TESTING()
 
-
-########### basic vars ###############
-
-if (DBUSDIR)
-	set(DBUS_INSTALL_DIR "${DBUSDIR}")
-endif (DBUSDIR)
-if ($ENV{DBUSDIR})
-	set(DBUS_INSTALL_DIR "$ENV{DBUSDIR}")
-endif ($ENV{DBUSDIR})
-
-if (DBUS_INSTALL_DIR)
-	set(CMAKE_INSTALL_PREFIX "${DBUS_INSTALL_DIR}" CACHE TYPE PATH FORCE)
-else (DBUS_INSTALL_DIR)
-	set(DBUS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}")
-endif (DBUS_INSTALL_DIR)
-
-set(prefix                   ${DBUS_INSTALL_DIR})
-set(exec_prefix              ${prefix})
-set(EXPANDED_LIBDIR          ${DBUS_INSTALL_DIR}/lib)
-set(EXPANDED_INCLUDEDIR      ${DBUS_INSTALL_DIR}/include)
-set(EXPANDED_BINDIR          ${DBUS_INSTALL_DIR}/bin)
-set(EXPANDED_SYSCONFDIR      ${DBUS_INSTALL_DIR}/etc)
-set(EXPANDED_DATADIR         ${DBUS_INSTALL_DIR}/data)
-set(DBUS_MACHINE_UUID_FILE   ${DBUS_INSTALL_DIR}/lib/dbus/machine-id)
-set(DBUS_BINDIR              ${EXPANDED_BINDIR})
-set(DBUS_DAEMONDIR 			 ${EXPANDED_BINDIR})
-
 ########### command line options ###############
 # TODO: take check from configure.in
 
 #AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[enable unit test code]),enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE)
-OPTION(DBUS_BUILD_TESTS "enable unit test code" ON)
+option (DBUS_BUILD_TESTS "enable unit test code" ON)
  
 if(DBUS_BUILD_TESTS)
-    add_definitions(-DDBUS_BUILD_TESTS)
+    add_definitions(-DDBUS_BUILD_TESTS -DDBUS_ENABLE_EMBEDDED_TESTS)
 endif(DBUS_BUILD_TESTS)
 
-OPTION(DBUS_USE_OUTPUT_DEBUG_STRING "enable win32 debug port for message output" OFF)
+option (DBUS_USE_OUTPUT_DEBUG_STRING "enable win32 debug port for message output" OFF)
 if(DBUS_USE_OUTPUT_DEBUG_STRING)
     add_definitions(-DDBUS_USE_OUTPUT_DEBUG_STRING)
 endif(DBUS_USE_OUTPUT_DEBUG_STRING)
 
 if(WIN32)
 	# win32 dbus service support - this support is not complete
-	OPTION(DBUS_SERVICE "enable dbus service installer" OFF)
+	option (DBUS_SERVICE "enable dbus service installer" OFF)
 endif(WIN32)
 
 #AC_ARG_ENABLE(ansi, AS_HELP_STRING([--enable-ansi],[enable -ansi -pedantic gcc flags]),enable_ansi=$enableval,enable_ansi=no)
-OPTION(DBUS_ENABLE_ANSI "enable -ansi -pedantic gcc flags" OFF)
+option (DBUS_ENABLE_ANSI "enable -ansi -pedantic gcc flags" OFF)
 if(DBUS_ENABLE_ANSI)
    if(NOT MSVC)
         add_definitions(-ansi -D_POSIX_C_SOURCE=199309L -D_BSD_SOURCE -pedantic)
@@ -229,14 +255,14 @@
 endif(DBUS_ENABLE_ANSI)
 
 #AC_ARG_ENABLE(verbose-mode, AS_HELP_STRING([--enable-verbose-mode],[support verbose debug mode]),enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
-OPTION(DBUS_ENABLE_VERBOSE_MODE "support verbose debug mode" ON)
+option (DBUS_ENABLE_VERBOSE_MODE "support verbose debug mode" ON)
 
 #AC_ARG_ENABLE(checks, AS_HELP_STRING([--enable-checks],[include sanity checks on public API]),enable_checks=$enableval,enable_checks=yes)
-OPTION(DBUS_DISABLE_CHECKS "Disable public API sanity checking" OFF)
+option (DBUS_DISABLE_CHECKS "Disable public API sanity checking" OFF)
 
 if(NOT MSVC)
     #AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],[compile with coverage profiling instrumentation (gcc only)]),enable_gcov=$enableval,enable_gcov=no)
-    OPTION(DBUS_GCOV_ENABLED "compile with coverage profiling instrumentation (gcc only)" OFF)
+    option (DBUS_GCOV_ENABLED "compile with coverage profiling instrumentation (gcc only)" OFF)
     if(DBUS_GCOV_ENABLED)
             add_definitions(-fprofile-arcs -ftest-coverage)
             # FIXME!!!!
@@ -253,7 +279,7 @@
 
 #AC_ARG_ENABLE(dnotify, AS_HELP_STRING([--enable-dnotify],[build with dnotify support (linux only)]),enable_dnotify=$enableval,enable_dnotify=auto)
 if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
-    OPTION(DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX "build with dnotify support (linux only)" ON) # add a check !
+    option (DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX "build with dnotify support (linux only)" ON) # add a check !
 endif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux")
 
 #AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue support (FreeBSD only)]),enable_kqueue=$enableval,enable_kqueue=auto)
@@ -262,9 +288,9 @@
 #AC_ARG_ENABLE(console-owner-file, AS_HELP_STRING([--enable-console-owner-file],[enable console owner file]),enable_console_owner_file=$enableval,enable_console_owner_file=auto)
 STRING(TOUPPER ${CMAKE_SYSTEM_NAME} sysname)
 if("${sysname}" MATCHES ".*SOLARIS.*")
-    OPTION(HAVE_CONSOLE_OWNER_FILE "enable console owner file (solaris only)" ON)
+    option (HAVE_CONSOLE_OWNER_FILE "enable console owner file (solaris only)" ON)
     if(HAVE_CONSOLE_OWNER_FILE)
-        SET(DBUS_CONSOLE_OWNER_FILE "/dev/console" CACHE STRING "Directory to check for console ownerhip")
+        set (DBUS_CONSOLE_OWNER_FILE "/dev/console" CACHE STRING "Directory to check for console ownerhip")
     endif(HAVE_CONSOLE_OWNER_FILE)
 endif("${sysname}" MATCHES ".*SOLARIS.*")
 
@@ -273,12 +299,6 @@
     message(FATAL "Neither expat nor libxml2 found!")
 endif(NOT LIBXML2_FOUND AND NOT LIBEXPAT_FOUND)
 
-if(LIBEXPAT_FOUND)
-    OPTION(DBUS_USE_EXPAT "Use expat (== ON) or libxml2 (==OFF)" ON)
-else(LIBEXPAT_FOUND)
-    OPTION(DBUS_USE_EXPAT "Use expat (== ON) or libxml2 (==OFF)" OFF)
-endif(LIBEXPAT_FOUND)
-
 if(DBUS_USE_EXPAT)
     SET(XML_LIB "Expat")
     SET(XML_LIBRARY     ${LIBEXPAT_LIBRARIES})
@@ -324,28 +344,30 @@
     endif(UNAME_EXECUTABLE)
 endif(CMAKE_COMPILER_IS_GNUCC AND NOT DBUS_ENABLE_ANSI)
 
-OPTION(DBUS_HAVE_ATOMIC_INT    "Some atomic integer implementation present" ${atomic_int})
-OPTION(DBUS_USE_ATOMIC_INT_486 "Use atomic integer implementation for 486" ${atomic_int_486})
+set (DBUS_HAVE_ATOMIC_INT ${atomic_int} CACHE STRING "Some atomic integer implementation present")
+set (DBUS_USE_ATOMIC_INT_486 ${atomic_int_486} CACHE STRING "Use atomic integer implementation for 486")
 
 if(X11_FOUND)
-  OPTION(DBUS_BUILD_X11 "Build X11-dependent code " ON)
+  option (DBUS_BUILD_X11 "Build with X11 autolaunch support " ON)
 endif(X11_FOUND)
 
 # test binary names
 if (WIN32)
-	set (EXT ".exe")
+	# Automake calls this EXEEXT, and CMake doesn't have a standard name
+	# for it; follow Automake's naming convention so we can share .in files
+	set (EXEEXT ".exe")
 endif(WIN32)
 
 if (MSVC_IDE)
     if(CMAKE_BUILD_TYPE MATCHES Debug)
-		set(IDE_BIN Debug/ )
+		set(IDE_BIN /Debug )
 		message(STATUS)
 		message(STATUS "Visual Studio: test programs will only work with 'Debug' configuration!")
 		message(STATUS "To run tests with 'Release' configuration use -DCMAKE_BUILD_TYPE=Release")
 		message(STATUS "Add '..\\..\\test\\data' to the command line option of the test programs")
 		message(STATUS)
     else(CMAKE_BUILD_TYPE MATCHES Debug)
-		set(IDE_BIN Release/)
+		set(IDE_BIN /Release)
 		message(STATUS)
 		message(STATUS "Visual Studio: test programs will only work with 'Release' configuration!")
 		message(STATUS "To run tests with 'Debug' configuration use -DCMAKE_BUILD_TYPE=Debug")
@@ -356,13 +378,6 @@
 	FILE(REMOVE ${CMAKE_BINARY_DIR}/data/dbus-1/services)
 endif (MSVC_IDE)
 
-set(TEST_SERVICE_DIR          ${CMAKE_BINARY_DIR}/test/data/valid-service-files     CACHE STRING "Full path to test file test/data/valid-service-files in builddir" )
-set(TEST_SERVICE_BINARY       ${CMAKE_BINARY_DIR}/bin/${IDE_BIN}test-service${EXT}       CACHE STRING "Full path to test file test/test-service in builddir" ${TEST_PATH_FORCE})
-set(TEST_SHELL_SERVICE_BINARY ${CMAKE_BINARY_DIR}/bin/${IDE_BIN}test-shell-service${EXT} CACHE STRING "Full path to test file test/test-shell-service in builddir" ${TEST_PATH_FORCE})
-set(TEST_EXIT_BINARY          ${CMAKE_BINARY_DIR}/bin/${IDE_BIN}test-exit${EXT}          CACHE STRING "Full path to test file test/test-exit in builddir" ${TEST_PATH_FORCE})
-set(TEST_SEGFAULT_BINARY      ${CMAKE_BINARY_DIR}/bin/${IDE_BIN}test-segfault${EXT}      CACHE STRING "Full path to test file test/test-segfault in builddir" ${TEST_PATH_FORCE})
-set(TEST_SLEEP_FOREVER_BINARY ${CMAKE_BINARY_DIR}/bin/${IDE_BIN}test-sleep-forever${EXT} CACHE STRING "Full path to test file test/test-sleep-forever in builddir" ${TEST_PATH_FORCE})
-
 #### Find socket directories
  if (NOT $ENV{TMPDIR} STREQUAL "")
      set (DBUS_SESSION_SOCKET_DIR $ENV{TMPDIR})
@@ -418,26 +433,24 @@
 
 
 if (WIN32)
-  set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "nonce-tcp:" CACHE STRING "system bus default address" )
-  set (DBUS_SESSION_BUS_DEFAULT_ADDRESS "nonce-tcp:" CACHE STRING "session bus default address" )
+  set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "nonce-tcp:" CACHE STRING "system bus default address")
+  set (DBUS_SESSION_BUS_DEFAULT_ADDRESS "nonce-tcp:" CACHE STRING "session bus default address")
 
   set (DBUS_SYSTEM_CONFIG_FILE "etc/dbus-1/system.conf")
   set (DBUS_SESSION_CONFIG_FILE "etc/dbus-1/session.conf")
   # bus-test expects a non empty string
   set (DBUS_USER "Administrator")
-  set (DBUS_DATADIR "data")
 else (WIN32)
-  set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:tmpdir=" CACHE STRING "system bus default address" )
-  set (DBUS_SESSION_BUS_DEFAULT_ADDRESS "unix:path=${DBUS_SESSION_SOCKET_DIR}" CACHE STRING "session bus default address" )
+  set (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:tmpdir=" CACHE STRING "system bus default address")
+  set (DBUS_SESSION_BUS_DEFAULT_ADDRESS "unix:path=${DBUS_SESSION_SOCKET_DIR}" CACHE STRING "session bus default address")
   set (sysconfdir "")
   set (configdir ${sysconfdir}/dbus-1 )
   set (DBUS_SYSTEM_CONFIG_FILE  ${configdir}/system.conf)
   set (DBUS_SESSION_CONFIG_FILE ${configdir}/session.conf)
   set (DBUS_USER "root")
-  set (DBUS_DATADIR ${EXPANDED_DATADIR})
 endif (WIN32)
 
-set(DBUS_DAEMON_NAME dbus-daemon CACHE STRING "The name of the dbus daemon executable")
+set (DBUS_DAEMON_NAME "dbus-daemon" CACHE STRING "The name of the dbus daemon executable")
 
 ########### create config.h ###############
 
@@ -450,24 +463,20 @@
 
 # compiler definitions
 add_definitions(-DHAVE_CONFIG_H=1)
-add_definitions(${DBUS_BUS_CFLAGS} -DDBUS_API_SUBJECT_TO_CHANGE)
+add_definitions(${DBUS_BUS_CFLAGS})
 
 
 if (DBUS_BUILD_TESTS)
     # set variables used for the .in files (substituted by configure_file) in test/data:
-    set(TEST_VALID_SERVICE_DIR ${CMAKE_BINARY_DIR}/test/data/valid-service-files)
-    set(TEST_VALID_SERVICE_SYSTEM_DIR ${CMAKE_BINARY_DIR}/test/data/valid-service-files-system)
-    set(TEST_INVALID_SERVICE_SYSTEM_DIR ${CMAKE_BINARY_DIR}/test/data/invalid-service-files-system)
+    set(DBUS_TEST_EXEC ${EXECUTABLE_OUTPUT_PATH}${IDE_BIN})
+    set(DBUS_TEST_DATA ${CMAKE_BINARY_DIR}/test/data)
     set(TEST_SOCKET_DIR ${DBUS_SESSION_SOCKET_DIR} )
     set(TEST_LAUNCH_HELPER_BINARY ${EXECUTABLE_OUTPUT_PATH}/dbus-daemon-launch-helper-test)
-    set(TEST_PRIVSERVER_BINARY ${EXECUTABLE_OUTPUT_PATH}/test-privserver)
     if (UNIX)
-        set (TEST_LISTEN "debug-pipe:name=test-server")
-        set (TEST_CONNECTION "${TEST_LISTEN}")
+        set (TEST_LISTEN "unix:tmpdir=${TEST_SOCKET_DIR}")
     endif (UNIX)
     if (WIN32)
-        set (TEST_LISTEN "tcp:host=localhost,port=12436")
-        set (TEST_CONNECTION "${TEST_LISTEN}")
+        set (TEST_LISTEN "tcp:host=localhost")
     endif (WIN32)
 endif  (DBUS_BUILD_TESTS)
 
@@ -481,8 +490,12 @@
 set (DBUS_INTERNAL_CLIENT_DEFINITIONS "-DDBUS_STATIC_BUILD")
 
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h )
+
+if (WIN32)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dbus-env.bat.cmake ${CMAKE_BINARY_DIR}/bin/dbus-env.bat )
 install_files(/bin FILES ${CMAKE_BINARY_DIR}/bin/dbus-env.bat)
+endif()
+
 add_definitions(-DHAVE_CONFIG_H=1)
 
 ########### subdirs ###############
@@ -538,6 +551,7 @@
 message("        Building verbose mode:    ${DBUS_ENABLE_VERBOSE_MODE}         ")
 message("        Building w/o assertions:  ${DBUS_DISABLE_ASSERTS}             ")
 message("        Building w/o checks:      ${DBUS_DISABLE_CHECKS}              ")
+message("        Building bus stats API:   ${DBUS_ENABLE_STATS}                ")
 message("        installing system libs:   ${DBUS_INSTALL_SYSTEM_LIBS}         ")
 #message("        Building SELinux support: ${have_selinux}                     ")
 #message("        Building dnotify support: ${have_dnotify}                     ")
@@ -592,3 +606,8 @@
 MESSAGE(" ")
 
 INCLUDE(modules/CPackInstallConfig.cmake)
+
+add_custom_target(help-options
+    cmake -LH 
+    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+)
diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake
index e48b60d..33a9cee 100644
--- a/cmake/ConfigureChecks.cmake
+++ b/cmake/ConfigureChecks.cmake
@@ -54,43 +54,39 @@
 if(SIZEOF_INT EQUAL 8)
     set (DBUS_HAVE_INT64 1)
     set (DBUS_INT64_TYPE "int")
-else(SIZEOF_INT EQUAL 8)
-    if(SIZEOF_LONG EQUAL 8)
-        set (DBUS_HAVE_INT64 1)
-        set (DBUS_INT64_TYPE "long")
-    else(SIZEOF_LONG EQUAL 8)
-        if(SIZEOF_LONG_LONG EQUAL 8)
-            set (DBUS_HAVE_INT64 1)
-            set (DBUS_INT64_TYPE "long long")
-        else(SIZEOF_LONG_LONG EQUAL 8)
-            if(SIZEOF___INT64 EQUAL 8)
-                set (DBUS_HAVE_INT64 1)
-                set (DBUS_INT64_TYPE "__int64")
-            endif(SIZEOF___INT64 EQUAL 8)
-        endif(SIZEOF_LONG_LONG EQUAL 8)
-    endif(SIZEOF_LONG EQUAL 8)
+    set (DBUS_INT64_CONSTANT  "(val)")
+    set (DBUS_UINT64_CONSTANT "(val##U)")
+elseif(SIZEOF_LONG EQUAL 8)
+    set (DBUS_HAVE_INT64 1)
+    set (DBUS_INT64_TYPE "long")
+    set (DBUS_INT64_CONSTANT  "(val##L)")
+    set (DBUS_UINT64_CONSTANT "(val##UL)")
+elseif(SIZEOF_LONG_LONG EQUAL 8)
+    set (DBUS_HAVE_INT64 1)
+    set (DBUS_INT64_TYPE "long long")
+    set (DBUS_INT64_CONSTANT  "(val##LL)")
+    set (DBUS_UINT64_CONSTANT "(val##ULL)")
+elseif(SIZEOF___INT64 EQUAL 8)
+    set (DBUS_HAVE_INT64 1)
+    set (DBUS_INT64_TYPE "__int64")
+    set (DBUS_INT64_CONSTANT  "(val##i64)")
+    set (DBUS_UINT64_CONSTANT "(val##ui64)")
 endif(SIZEOF_INT EQUAL 8)
 
 # DBUS_INT32_TYPE
 if(SIZEOF_INT EQUAL 4)
     set (DBUS_INT32_TYPE "int")
-else(SIZEOF_INT EQUAL 4)
-    if(SIZEOF_LONG EQUAL 4)
-        set (DBUS_INT32_TYPE "long")
-    else(SIZEOF_LONG EQUAL 4)
-        if(SIZEOF_LONG_LONG EQUAL 4)
-            set (DBUS_INT32_TYPE "long long")
-        endif(SIZEOF_LONG_LONG EQUAL 4)
-    endif(SIZEOF_LONG EQUAL 4)
+elseif(SIZEOF_LONG EQUAL 4)
+    set (DBUS_INT32_TYPE "long")
+elseif(SIZEOF_LONG_LONG EQUAL 4)
+    set (DBUS_INT32_TYPE "long long")
 endif(SIZEOF_INT EQUAL 4)
 
 # DBUS_INT16_TYPE
 if(SIZEOF_INT EQUAL 2)
     set (DBUS_INT16_TYPE "int")
-else(SIZEOF_INT EQUAL 2)
-    if(SIZEOF_SHORT EQUAL 2)
-        set (DBUS_INT16_TYPE "short")
-    endif(SIZEOF_SHORT EQUAL 2)
+elseif(SIZEOF_SHORT EQUAL 2)
+    set (DBUS_INT16_TYPE "short")
 endif(SIZEOF_INT EQUAL 2)
 
 find_program(DOXYGEN doxygen)
diff --git a/cmake/bus/CMakeLists.txt b/cmake/bus/CMakeLists.txt
index 876be81..faf9a8e 100644
--- a/cmake/bus/CMakeLists.txt
+++ b/cmake/bus/CMakeLists.txt
@@ -11,9 +11,8 @@
 )
 
 # config files for installation 
-FOREACH(file ${config_DATA})
-	CONFIGURE_FILE( "${CMAKE_CURRENT_SOURCE_DIR}/${file}.cmake" "${CMAKE_CURRENT_BINARY_DIR}/${file}" IMMEDIATE @ONLY)
-ENDFOREACH(file)
+CONFIGURE_FILE( "${BUS_DIR}/session.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/session.conf" IMMEDIATE @ONLY)
+CONFIGURE_FILE( "system.conf.cmake" "${CMAKE_CURRENT_BINARY_DIR}/system.conf" IMMEDIATE @ONLY)
 
 # copy services for local daemon start to local service dir data/dbus-1/services
 SET (SERVICE_FILES test/data/valid-service-files)
@@ -74,6 +73,12 @@
 	${XML_SOURCES}
 	${DIR_WATCH_SOURCE}
 )
+if(DBUS_ENABLE_STATS)
+	list(APPEND BUS_SOURCES
+		${BUS_DIR}/stats.c
+		${BUS_DIR}/stats.h
+	)
+endif()
 
 include_directories(${XML_INCLUDE_DIR})
 
@@ -84,6 +89,7 @@
 
 install_targets(/bin dbus-daemon)
 install_files(/etc/dbus-1 FILES ${config_DATA})
+install(DIRECTORY .  DESTINATION etc/dbus-1/session.d  FILES_MATCHING PATTERN "*.conf")
 
 if (DBUS_SERVICE)
 	set (dbus_service_SOURCES 
diff --git a/cmake/bus/dbus-daemon.xml b/cmake/bus/dbus-daemon.xml
index c6f4db0..f331699 100644
--- a/cmake/bus/dbus-daemon.xml
+++ b/cmake/bus/dbus-daemon.xml
@@ -512,6 +512,7 @@
    eavesdrop="true" | "false"
 
    own="name"
+   own_prefix="name"
    user="username"
    group="groupname"
 </literallayout> <!-- .fi -->
@@ -590,6 +591,13 @@
 like "foo.bar.*" aren't allowed for now because they'd be work to
 implement and maybe encourage sloppy security anyway.</para>
 
+<para>&lt;allow own_prefix="a.b"/&gt; allows you to own the name "a.b" or any
+name whose first dot-separated elements are "a.b": in particular,
+you can own "a.b.c" or "a.b.c.d", but not "a.bc" or "a.c".
+This is useful when services like Telepathy and ReserveDevice
+define a meaning for subtrees of well-known names, such as
+org.freedesktop.Telepathy.ConnectionManager.(anything)
+and org.freedesktop.ReserveDevice1.(anything).</para>
 
 <para>It does not make sense to deny a user or group inside a &lt;policy&gt;
 for a user or group; user/group denials can only be inside
diff --git a/cmake/bus/session.conf.cmake b/cmake/bus/session.conf.cmake
deleted file mode 100644
index 6bba91e..0000000
--- a/cmake/bus/session.conf.cmake
+++ /dev/null
@@ -1,30 +0,0 @@
-<!-- This configuration file controls the per-user-login-session message bus.
-     Add a session-local.conf and edit that rather than changing this 
-     file directly. -->
-
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-  <!-- Our well-known bus type, don't change this -->
-  <type>session</type>
-
-  <listen>@DBUS_SESSION_BUS_DEFAULT_ADDRESS@</listen>
-
-  <standard_session_servicedirs />
-
-  <policy context="default">
-    <!-- Allow everything to be sent -->
-    <allow send_destination="*"/>
-    <!-- Allow everything to be received -->
-    <allow eavesdrop="true"/>
-    <!-- Allow anyone to own anything -->
-    <allow own="*"/>
-  </policy>
-
-  <!-- This is included last so local configuration can override what's 
-       in this standard file -->
-  <include ignore_missing="yes">session-local.conf</include>
-
-  <include if_selinux_enabled="yes" selinux_root_relative="yes">contexts/dbus_contexts</include>
-
-</busconfig>
diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake
index 956c6d2..6221c19 100644
--- a/cmake/config.h.cmake
+++ b/cmake/config.h.cmake
@@ -16,7 +16,7 @@
 #cmakedefine DBUS_DAEMON_NAME "@DBUS_DAEMON_NAME@"
 #cmakedefine DBUS_SYSTEM_BUS_DEFAULT_ADDRESS  "@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@"
 #cmakedefine DBUS_MACHINE_UUID_FILE "@DBUS_MACHINE_UUID_FILE@"
-//#cmakedefine DBUS_SESSION_BUS_DEFAULT_ADDRESS "@DBUS_SESSION_BUS_DEFAULT_ADDRESS@"
+#cmakedefine DBUS_SESSION_BUS_DEFAULT_ADDRESS "@DBUS_SESSION_BUS_DEFAULT_ADDRESS@"
 #cmakedefine DBUS_DAEMONDIR "@DBUS_DAEMONDIR@"
 #cmakedefine PACKAGE "@PACKAGE@"
 /* Version number of package */
@@ -25,25 +25,18 @@
 #cmakedefine DBUS_MICRO_VERSION @DBUS_MICRO_VERSION@
 #cmakedefine DBUS_VERSION ((@DBUS_MAJOR_VERSION@ << 16) | (@DBUS_MINOR_VERSION@ << 8) | (@DBUS_MICRO_VERSION@))
 #cmakedefine DBUS_VERSION_STRING "@DBUS_VERSION_STRING@"
+#cmakedefine DBUS_ENABLE_STATS
 
 #define VERSION DBUS_VERSION_STRING
 
 #define TEST_LISTEN       "@TEST_LISTEN@"
-#define TEST_CONNECTION   "@TEST_CONNECTION@"
 
 // test binaries
+#define DBUS_TEST_EXEC "@DBUS_TEST_EXEC@"
+#define DBUS_EXEEXT "@EXEEXT@"
+
 /* Full path to test file test/test-exit in builddir */
 #define TEST_BUS_BINARY          "@TEST_BUS_BINARY@"
-/* Full path to test file test/test-exit in builddir */
-#define TEST_EXIT_BINARY          "@TEST_EXIT_BINARY@"
-/* Full path to test file test/test-segfault in builddir */
-#define TEST_SEGFAULT_BINARY      "@TEST_SEGFAULT_BINARY@"
-/* Full path to test file test/test-service in builddir */
-#define TEST_SERVICE_BINARY       "@TEST_SERVICE_BINARY@"
-/* Full path to test file test/test-shell-service in builddir */
-#define TEST_SHELL_SERVICE_BINARY "@TEST_SHELL_SERVICE_BINARY@"
-/* Full path to test file test/test-sleep-forever in builddir */
-#define TEST_SLEEP_FOREVER_BINARY "@TEST_SLEEP_FOREVER_BINARY@"
 
 /* Some dbus features */
 #cmakedefine DBUS_BUILD_TESTS 1
@@ -83,6 +76,11 @@
 #endif
 
 #cmakedefine DBUS_BUILD_X11 1
+/* For the moment, the cmake build system doesn't have an equivalent of
+ * the autoconf build system's --disable-x11-autolaunch */
+#ifdef DBUS_BUILD_X11
+# define DBUS_ENABLE_X11_AUTOLAUNCH 1
+#endif
 
 #define _DBUS_VA_COPY_ASSIGN(a1,a2) { a1 = a2; }
 
@@ -247,4 +245,8 @@
 #define _dbus_verbose_C_S _dbus_verbose
 #endif 
 
+# if defined(_MSC_VER) && !defined(inline)
+#define inline __inline
+#endif
+
 #endif  // _DBUS_CONFIG_H
diff --git a/cmake/cross-compile.sh b/cmake/cross-compile.sh
index c1821bd..49e66e5 100755
--- a/cmake/cross-compile.sh
+++ b/cmake/cross-compile.sh
@@ -28,8 +28,13 @@
     exit 1
 fi
 
+if ! TEMP=`mktemp --tmpdir -d dbus-cross-compile.XXXXXX`; then
+    echo "mktemp failed, try with coreutils 6.10 or later?" >&2
+    exit 1
+fi
+
 # make cmake happy 
-export TEMP=/tmp
+export TEMP
 
 HOST_CC=gcc; export HOST_CC;
 
@@ -67,10 +72,10 @@
 unset x i ;
 
 if ! test -f "$cross_root/lib/libexpat.dll.a"; then
-    (cd /tmp; wget http://www.winkde.org/pub/kde/ports/win32/repository/win32libs/expat-2.0.1-bin.zip)
-    (cd /tmp; wget http://www.winkde.org/pub/kde/ports/win32/repository/win32libs/expat-2.0.1-lib.zip)
-    (cd $cross_root; unzip -x /tmp/expat-2.0.1-bin.zip)
-    (cd $cross_root; unzip -x /tmp/expat-2.0.1-lib.zip)
+    (cd $TEMP && wget http://www.winkde.org/pub/kde/ports/win32/repository/win32libs/expat-2.0.1-bin.zip)
+    (cd $TEMP && wget http://www.winkde.org/pub/kde/ports/win32/repository/win32libs/expat-2.0.1-lib.zip)
+    (cd $cross_root && unzip -x $TMP/expat-2.0.1-bin.zip)
+    (cd $cross_root && unzip -x $TMP/expat-2.0.1-lib.zip)
 fi 
 
 if test -f "$cross_root/lib/libexpat.dll.a"; then
diff --git a/cmake/dbus/CMakeLists.txt b/cmake/dbus/CMakeLists.txt
index 52cbf90..d09e63d 100644
--- a/cmake/dbus/CMakeLists.txt
+++ b/cmake/dbus/CMakeLists.txt
@@ -2,7 +2,7 @@
 
 SET(DBUS_DIR ${CMAKE_SOURCE_DIR}/../dbus)
 
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dbus-arch-deps.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/dbus-arch-deps.h )
+configure_file(${DBUS_DIR}/dbus-arch-deps.h.in ${CMAKE_CURRENT_BINARY_DIR}/dbus-arch-deps.h )
 
 add_definitions(-DDBUS_COMPILATION)
 
@@ -21,6 +21,7 @@
 	${DBUS_DIR}/dbus-server.h
 	${DBUS_DIR}/dbus-shared.h
 	${DBUS_DIR}/dbus-signature.h
+	${DBUS_DIR}/dbus-syntax.h
 	${DBUS_DIR}/dbus-threads.h
 	${DBUS_DIR}/dbus-types.h
 	dbus-arch-deps.h
@@ -31,7 +32,6 @@
 set (DBUS_LIB_SOURCES
 	${DBUS_DIR}/dbus-address.c
 	${DBUS_DIR}/dbus-auth.c
-	${DBUS_DIR}/dbus-auth-script.c
 	${DBUS_DIR}/dbus-bus.c
 	${DBUS_DIR}/dbus-connection.c
 	${DBUS_DIR}/dbus-credentials.c
@@ -52,15 +52,12 @@
 	${DBUS_DIR}/dbus-server-debug-pipe.c
 	${DBUS_DIR}/dbus-sha.c
 	${DBUS_DIR}/dbus-signature.c
+	${DBUS_DIR}/dbus-syntax.c
 	${DBUS_DIR}/dbus-timeout.c
 	${DBUS_DIR}/dbus-threads.c
 	${DBUS_DIR}/dbus-transport.c
 	${DBUS_DIR}/dbus-transport-socket.c
 	${DBUS_DIR}/dbus-watch.c
-#dbus-md5.c
-#
-#  find a clean Windows implementation
-#  and move code to a *-win.c file
 )
 
 
@@ -78,7 +75,6 @@
 
 set (DBUS_LIB_HEADERS
 	${DBUS_DIR}/dbus-auth.h
-	${DBUS_DIR}/dbus-auth-script.h
 	${DBUS_DIR}/dbus-connection-internal.h
 	${DBUS_DIR}/dbus-credentials.h
 	${DBUS_DIR}/dbus-keyring.h
@@ -103,7 +99,6 @@
 	${DBUS_DIR}/dbus-transport-protected.h
 	${DBUS_DIR}/dbus-watch.h
 	${CMAKE_BINARY_DIR}/config.h
-##dbus-md5.h
 )
 if(UNIX)
 	set (DBUS_LIB_HEADERS ${DBUS_LIB_HEADERS} 
@@ -154,6 +149,7 @@
 ### should be underscore-prefixed but don't really need 
 ### to be unless they move to DBUS_SHARED_SOURCES later)
 set (DBUS_UTIL_SOURCES
+	${DBUS_DIR}/dbus-auth-script.c
 	${DBUS_DIR}/dbus-auth-util.c
 	${DBUS_DIR}/dbus-credentials-util.c
 	${DBUS_DIR}/dbus-mainloop.c
@@ -163,6 +159,8 @@
 	${DBUS_DIR}/dbus-message-factory.c
 	${DBUS_DIR}/dbus-message-util.c
 	${DBUS_DIR}/dbus-shell.c
+	${DBUS_DIR}/dbus-socket-set.c
+	${DBUS_DIR}/dbus-socket-set-poll.c
 	${DBUS_DIR}/dbus-string-util.c
 	${DBUS_DIR}/dbus-sysdeps-util.c
 )
@@ -175,9 +173,11 @@
 endif (DBUS_BUILD_TESTS)
 
 set (DBUS_UTIL_HEADERS
+	${DBUS_DIR}/dbus-auth-script.h
 	${DBUS_DIR}/dbus-mainloop.h
 	${DBUS_DIR}/dbus-message-factory.h
 	${DBUS_DIR}/dbus-shell.h
+	${DBUS_DIR}/dbus-socket-set.h
 	${DBUS_DIR}/dbus-spawn.h
 	${DBUS_DIR}/dbus-test.h
 )
@@ -213,12 +213,14 @@
 		${DBUS_DIR}/dbus-sysdeps-unix.c
 		${DBUS_DIR}/dbus-sysdeps-pthread.c
 		${DBUS_DIR}/dbus-userdb.c
+        ${DBUS_DIR}/sd-daemon.c
 	)
 	set (DBUS_SHARED_HEADERS ${DBUS_SHARED_HEADERS} 
 		${DBUS_DIR}/dbus-server-unix.h
 		${DBUS_DIR}/dbus-transport-unix.h
 		${DBUS_DIR}/dbus-sysdeps-unix.h
 		${DBUS_DIR}/dbus-userdb.h
+        ${DBUS_DIR}/sd-daemon.h
 	)
 	set (DBUS_UTIL_SOURCES ${DBUS_UTIL_SOURCES}
 		${DBUS_DIR}/dbus-spawn.c
@@ -230,15 +232,11 @@
 set(libdbus_SOURCES
 	${DBUS_LIB_SOURCES}
 	${DBUS_SHARED_SOURCES}
-	# for debugging
-	${DBUS_UTIL_SOURCES}
 )
 
 set(libdbus_HEADERS 
 	${DBUS_LIB_HEADERS}
 	${DBUS_SHARED_HEADERS}
-	# for debugging
-	${DBUS_UTIL_HEADERS}
 )
 if (MSVC)
     set (BUILD_FILEVERSION ${DBUS_MAJOR_VERSION},${DBUS_MINOR_VERSION},${DBUS_MICRO_VERSION},${DBUS_PATCH_VERSION})
@@ -259,16 +257,17 @@
 ### Client library
 
 add_library(dbus-1 SHARED
-			${DBUS_LIB_SOURCES}
-			${DBUS_SHARED_SOURCES}
-			${DBUS_LIB_HEADERS}
-			${DBUS_SHARED_HEADERS})
+			${libdbus_SOURCES}
+			${libdbus_HEADERS}
+)
 if(WIN32)
     if(WINCE)
         target_link_libraries(dbus-1 ws2)
     else(WINCE)
         target_link_libraries(dbus-1 ws2_32 advapi32 netapi32)
     endif(WINCE)
+else(WIN32)
+    target_link_libraries(dbus-1 ${CMAKE_THREAD_LIBS_INIT})
 endif(WIN32)
 
 install_targets(/lib dbus-1 )
@@ -292,6 +291,8 @@
     else(WINCE)
         target_link_libraries(dbus-internal ws2_32 advapi32 netapi32)
     endif(WINCE)
+else(WIN32)
+    target_link_libraries(dbus-internal ${CMAKE_THREAD_LIBS_INIT})
 endif(WIN32)
 
 if (DBUS_BUILD_TESTS)
diff --git a/cmake/dbus/dbus-arch-deps.h.cmake b/cmake/dbus/dbus-arch-deps.h.cmake
deleted file mode 100644
index 7d566e9..0000000
--- a/cmake/dbus/dbus-arch-deps.h.cmake
+++ /dev/null
@@ -1,56 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
-/* dbus-arch-deps.h Header with architecture/compiler specific information, installed to libdir
- *
- * Copyright (C) 2003 Red Hat, Inc.
- *
- * Licensed under the Academic Free License version 2.0
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION)
-#error "Only <dbus/dbus.h> can be included directly, this file may disappear or change contents."
-#endif
-
-#ifndef DBUS_ARCH_DEPS_H
-#define DBUS_ARCH_DEPS_H
-
-#include <dbus/dbus-macros.h>
-
-DBUS_BEGIN_DECLS;
-
-#cmakedefine DBUS_HAVE_INT64 1
-#if DBUS_HAVE_INT64
-typedef @DBUS_INT64_TYPE@ dbus_int64_t;
-typedef unsigned @DBUS_INT64_TYPE@ dbus_uint64_t;
-
-#define DBUS_INT64_CONSTANT(val)  (val##LL)
-#define DBUS_UINT64_CONSTANT(val) (val##ULL)
-
-#else
-#undef DBUS_HAVE_INT64
-#undef DBUS_INT64_CONSTANT
-#undef DBUS_UINT64_CONSTANT
-#endif
-
-typedef @DBUS_INT32_TYPE@ dbus_int32_t;
-typedef unsigned @DBUS_INT32_TYPE@ dbus_uint32_t;
-
-typedef @DBUS_INT16_TYPE@ dbus_int16_t;
-typedef unsigned @DBUS_INT16_TYPE@ dbus_uint16_t;
-
-DBUS_END_DECLS;
-
-#endif /* DBUS_ARCH_DEPS_H */
diff --git a/cmake/modules/Macros.cmake b/cmake/modules/Macros.cmake
new file mode 100644
index 0000000..b637156
--- /dev/null
+++ b/cmake/modules/Macros.cmake
@@ -0,0 +1,15 @@
+
+MACRO(TIMESTAMP RESULT)
+    IF(WIN32)
+        EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE DATE)
+        string(REGEX REPLACE "(..)[/.](..)[/.](....).*" "\\3\\2\\1" DATE ${DATE})
+        EXECUTE_PROCESS(COMMAND "cmd" " /C time /T" OUTPUT_VARIABLE TIME)
+        string(REGEX REPLACE "(..):(..)" "\\1\\2" TIME ${TIME})
+        set (${RESULT} "${DATE}${TIME}")
+    ELSEIF(UNIX)
+        EXECUTE_PROCESS(COMMAND "date" "+%Y%m%d%H%M" OUTPUT_VARIABLE ${RESULT})
+    ELSE()
+        MESSAGE(SEND_ERROR "date not implemented")
+        SET(${RESULT} 000000000000)
+    ENDIF()
+ENDMACRO()
diff --git a/cmake/modules/MacrosAutotools.cmake b/cmake/modules/MacrosAutotools.cmake
new file mode 100644
index 0000000..ff30eaf
--- /dev/null
+++ b/cmake/modules/MacrosAutotools.cmake
@@ -0,0 +1,40 @@
+#
+# @Author Ralf Habacker
+# 
+# extracts version information from autoconf config file
+# and set related cmake variables
+# 
+# returns  
+#   ${prefix}_VERSION
+#   ${prefix}_VERSION_STRING
+#   ${prefix}_MAJOR_VERSION
+#   ${prefix}_MINOR_VERSION
+#   ${prefix}_MICRO_VERSION
+# 
+macro(autoversion config prefix)
+	file (READ ${config} _configure_ac)
+	string(TOUPPER ${prefix} prefix_upper)
+	string (REGEX REPLACE ".*${prefix}_major_version], .([0-9]+).*" "\\1" ${prefix_upper}_MAJOR_VERSION ${_configure_ac})
+	string (REGEX REPLACE ".*${prefix}_minor_version], .([0-9]+).*" "\\1" ${prefix_upper}_MINOR_VERSION ${_configure_ac})
+	string (REGEX REPLACE ".*${prefix}_micro_version], .([0-9]+).*" "\\1" ${prefix_upper}_MICRO_VERSION ${_configure_ac})
+	set (${prefix_upper}_VERSION ${${prefix_upper}_MAJOR_VERSION}.${${prefix_upper}_MINOR_VERSION}.${${prefix_upper}_MICRO_VERSION})
+	set (${prefix_upper}_VERSION_STRING "${${prefix_upper}_VERSION}")
+
+endmacro()
+
+#
+# parses config.h template and create cmake equivalent 
+# not implemented yet
+# 
+macro(autoconfig template output)
+	file(READ ${template} contents)
+	# Convert file contents into a CMake list (where each element in the list
+	# is one line of the file)
+	STRING(REGEX REPLACE ";" "\\\\;" contents "${contents}")
+	STRING(REGEX REPLACE "\n" ";" contents "${contents}")
+	foreach(line contents)
+		message(STATUS ${line})
+		# find #undef lines
+		# append to config.h #define <variable-name> <variable-content>
+	endforeach()
+endmacro()
diff --git a/cmake/readme-cmake.txt b/cmake/readme-cmake.txt
deleted file mode 100644
index 9350073..0000000
--- a/cmake/readme-cmake.txt
+++ /dev/null
@@ -1,54 +0,0 @@
-This directory contains configuration files for the cmake build system 
-
-Requirements 
-------------
-- cmake version >= 2.4.4 see http://www.cmake.org 
-- installed libxml2 or libexpat 
-
-Building 
---------
-
-unix
-1. install cmake and libxml or libexpat 
-2. get dbus sources 
-3. mkdir dbus-build 
-4. cd dbus-build 
-5. cmake <dbus-src-root>/cmake or cmake -DDBUS_USE_EXPAT=on <dbus-src-root>/cmake in case libexpat should de used
-5. make 
-6. make install
-
-win32-mingw
-1. install cmake and libxml or libexpat in <ProgramDir>\gnuwin32
-2. get dbus sources 
-3. mkdir dbus-build 
-4. cd dbus-build 
-5. cmake -G "MinGW Makefiles" <dbus-src-root>/cmake
-6. make 
-7. make install
-
-win32-msvc
-1. install cmake and libxml or libexpat in <ProgramDir>\gnuwin32
-2. get dbus sources 
-3. mkdir dbus-build 
-4. cd dbus-build 
-5. cmake -G <msvc available target, see cmake --help for a list" <dbus-src-root>/cmake
-6. make 
-7. make install
-
-
-Some build options (use -D<key>=<value> on command line)
-------------------
-    key                        description                            default value
-    ---                        -----------                            -------------
-DBUS_USE_EXPAT              "Use expat (== ON) or libxml2 (==OFF)         OFF
-DBUS_DISABLE_ASSERTS        "Disable assertion checking"                  OFF
-DBUS_BUILD_TESTS            "enable unit test code"                       ON
-DBUS_ENABLE_ANSI            "enable -ansi -pedantic gcc flags"            OFF
-DBUS_ENABLE_GCOV            "compile with coverage profiling 
-                             instrumentation (gcc only)"                  OFF
-DBUS_ENABLE_VERBOSE_MODE    "support verbose debug mode"                  ON
-DBUS_DISABLE_CHECKS         "Disable public API sanity checking"          OFF
-DBUS_INSTALL_SYSTEM_LIBS    "install required system libraries 
-                             (mingw: libxml2, libiconv, mingw10)"         OFF
-CMAKE_BUILD_TYPE            "build type (== debug) or (== release)        release
-
diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index 7bb80ab..8657e4c 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -2,24 +2,20 @@
 
 add_definitions(${DBUS_INTERNAL_CLIENT_DEFINITIONS})
 
-add_library(dbus_testutils STATIC
+add_library(dbus-testutils STATIC
     ${CMAKE_SOURCE_DIR}/../test/test-utils.h
     ${CMAKE_SOURCE_DIR}/../test/test-utils.c
 )
-target_link_libraries(dbus_testutils ${DBUS_INTERNAL_LIBRARIES})
+target_link_libraries(dbus-testutils ${DBUS_INTERNAL_LIBRARIES})
 
 add_subdirectory( name-test )
 
 set (test-service_SOURCES
     ${CMAKE_SOURCE_DIR}/../test/test-service.c
-    ${CMAKE_SOURCE_DIR}/../test/test-utils.c
-    ${CMAKE_SOURCE_DIR}/../test/test-utils.h
 )
 
 set (test-names_SOURCES
     ${CMAKE_SOURCE_DIR}/../test/test-names.c
-    ${CMAKE_SOURCE_DIR}/../test/test-utils.c
-    ${CMAKE_SOURCE_DIR}/../test/test-utils.h
 )
 
 set (break_loader_SOURCES
@@ -28,8 +24,6 @@
 
 set (test-shell-service_SOURCES
     ${CMAKE_SOURCE_DIR}/../test/test-shell-service.c
-    ${CMAKE_SOURCE_DIR}/../test/test-utils.c
-    ${CMAKE_SOURCE_DIR}/../test/test-utils.h
 )
 
 set (shell-test_SOURCES
@@ -52,22 +46,18 @@
     ${CMAKE_SOURCE_DIR}/../test/test-sleep-forever.c
 )
 
-set (decode_gcov_SOURCES
-    ${CMAKE_SOURCE_DIR}/../test/decode-gcov.c
-)
-
 add_executable(test-service ${test-service_SOURCES})
-target_link_libraries(test-service ${DBUS_INTERNAL_LIBRARIES})
+target_link_libraries(test-service dbus-testutils)
 
 add_executable(test-names ${test-names_SOURCES})
-target_link_libraries(test-names ${DBUS_INTERNAL_LIBRARIES})
+target_link_libraries(test-names dbus-testutils)
 
 add_executable(shell-test ${shell-test_SOURCES})
 target_link_libraries(shell-test ${DBUS_INTERNAL_LIBRARIES})
-ADD_TEST(shell-test ${EXECUTABLE_OUTPUT_PATH}/shell-test${EXT})
+ADD_TEST(shell-test ${EXECUTABLE_OUTPUT_PATH}/shell-test${EXEEXT})
 
 add_executable(test-shell-service ${test-shell-service_SOURCES})
-target_link_libraries(test-shell-service ${DBUS_INTERNAL_LIBRARIES})
+target_link_libraries(test-shell-service dbus-testutils)
 
 add_executable(spawn-test ${spawn-test_SOURCES})
 target_link_libraries(spawn-test ${DBUS_INTERNAL_LIBRARIES})
@@ -81,9 +71,6 @@
 add_executable(test-sleep-forever ${test-sleep-forever_SOURCES})
 target_link_libraries(test-sleep-forever ${DBUS_INTERNAL_LIBRARIES})
 
-#add_executable(decode-gcov ${decode_gcov_SOURCES})
-#target_link_libraries(decode-gcov ${DBUS_INTERNAL_LIBRARIES})
-
 ### keep these in creation order, i.e. uppermost dirs first 
 set (TESTDIRS
     test/data
@@ -141,10 +128,6 @@
       GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME)
       STRING(REGEX REPLACE "\\.in$" "" FILENAME ${FILENAME})
       SET (TARGET ${CMAKE_BINARY_DIR}/${DIR}/${FILENAME})
-      STRING(REGEX REPLACE "\\.in$" ".cmake" _file ${FILE})
-      IF (EXISTS ${_file})
-        SET (FILE ${_file})
-      ENDIF (EXISTS ${_file})
       configure_file(${FILE} ${TARGET} @ONLY IMMEDIATE)
       IF (CONFIG_VERBOSE)
         MESSAGE("${FILE}")
diff --git a/cmake/test/name-test/CMakeLists.txt b/cmake/test/name-test/CMakeLists.txt
index 6982722..80b9908 100644
--- a/cmake/test/name-test/CMakeLists.txt
+++ b/cmake/test/name-test/CMakeLists.txt
@@ -21,15 +21,19 @@
 ADD_TEST(test-ids ${EXECUTABLE_OUTPUT_PATH}/test-ids)
 
 add_executable(test-shutdown ${NAMEtest-DIR}/test-shutdown.c)
-target_link_libraries(test-shutdown ${DBUS_INTERNAL_LIBRARIES} dbus_testutils)
+target_link_libraries(test-shutdown dbus-testutils)
 ADD_TEST(test-shutdown ${EXECUTABLE_OUTPUT_PATH}/test-shutdown)
 
 add_executable(test-privserver ${NAMEtest-DIR}/test-privserver.c)
-target_link_libraries(test-privserver ${DBUS_INTERNAL_LIBRARIES} dbus_testutils)
+target_link_libraries(test-privserver dbus-testutils)
 ADD_TEST(test-privserver ${EXECUTABLE_OUTPUT_PATH}/test-privserver)
 
 add_executable(test-privserver-client ${NAMEtest-DIR}/test-privserver-client.c)
-target_link_libraries(test-privserver-client ${DBUS_INTERNAL_LIBRARIES} dbus_testutils)
+target_link_libraries(test-privserver-client dbus-testutils)
 ADD_TEST(test-privserver-client ${EXECUTABLE_OUTPUT_PATH}/test-privserver-client)
 
+add_executable(test-autolaunch ${NAMEtest-DIR}/test-autolaunch.c)
+target_link_libraries(test-autolaunch dbus-testutils)
+ADD_TEST(test-autolaunch ${EXECUTABLE_OUTPUT_PATH}/test-autolaunch)
+
 endif (DBUS_BUILD_TESTS)
diff --git a/cmake/tools/CMakeLists.txt b/cmake/tools/CMakeLists.txt
index e91a509..101c7e6 100644
--- a/cmake/tools/CMakeLists.txt
+++ b/cmake/tools/CMakeLists.txt
@@ -33,14 +33,6 @@
 	../../tools/dbus-cleanup-sockets.c
 )
 
-set (dbus_viewer_SOURCES
-	../../tools/dbus-names-model.c			
-	../../tools/dbus-names-model.h			
-	../../tools/dbus-tree-view.c			
-	../../tools/dbus-tree-view.h			
-	../../tools/dbus-viewer.c
-)
-
 add_executable(dbus-send ${dbus_send_SOURCES})
 target_link_libraries(dbus-send ${DBUS_LIBRARIES})
 install_targets(/bin dbus-send )
diff --git a/configure.in b/configure.ac
similarity index 68%
rename from configure.in
rename to configure.ac
index 1d5741e..24fcc9e 100644
--- a/configure.in
+++ b/configure.ac
@@ -1,29 +1,27 @@
 dnl -*- mode: m4 -*-
-AC_PREREQ(2.52)
+AC_PREREQ([2.63])
 
 m4_define([dbus_major_version], [1])
-m4_define([dbus_minor_version], [4])
-m4_define([dbus_micro_version], [0])
+m4_define([dbus_minor_version], [6])
+m4_define([dbus_micro_version], [8])
 m4_define([dbus_version],
           [dbus_major_version.dbus_minor_version.dbus_micro_version])
-AC_INIT(dbus, [dbus_version])
+AC_INIT([dbus],[dbus_version],[https://bugs.freedesktop.org/enter_bug.cgi?product=dbus],[dbus])
 
 AC_CANONICAL_HOST
-AC_LIBTOOL_WIN32_DLL
-AC_LIBTOOL_RC
 
-AM_INIT_AUTOMAKE([1.9 tar-ustar])
-AM_CONFIG_HEADER(config.h)
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_MACRO_DIR([m4])
 
-# Honor aclocal flags
-ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS"
+AM_INIT_AUTOMAKE([1.10 tar-ustar -Wno-portability])
 
 GETTEXT_PACKAGE=dbus-1
 AC_SUBST(GETTEXT_PACKAGE)
 AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[The name of the gettext domain])
 
- ## must come before we use the $USE_MAINTAINER_MODE variable later
-AM_MAINTAINER_MODE
+# By default, rebuild autotools files on demand; only use ./missing if the
+# user says --disable-maintainer-mode (some distributions like to do this)
+AM_MAINTAINER_MODE([enable])
 
 m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
 
@@ -35,7 +33,7 @@
 #
 
 ## increment if the interface has additions, changes, removals.
-LT_CURRENT=8
+LT_CURRENT=10
 
 ## increment any time the source changes; set to
 ##  0 if you increment CURRENT
@@ -44,7 +42,7 @@
 ## increment if any interfaces have been added; set to 0
 ## if any interfaces have been changed or removed. removal has
 ## precedence over adding, so set to 0 if both happened.
-LT_AGE=5
+LT_AGE=7
 
 AC_SUBST(LT_CURRENT)
 AC_SUBST(LT_REVISION)
@@ -69,6 +67,13 @@
 AC_C_INLINE
 AM_PROG_LIBTOOL
 AC_PROG_MKDIR_P
+COMPILER_COVERAGE
+COMPILER_OPTIMISATIONS
+PKG_PROG_PKG_CONFIG
+
+# Initialize libtool
+LT_INIT([win32-dll])
+LT_LANG([Windows Resource])
 
 # Set some internal variables depending on the platform for later use.
 dbus_win=no
@@ -119,14 +124,29 @@
 AM_CONDITIONAL(DBUS_UNIX, test "$dbus_unix" = yes)
 AM_CONDITIONAL(DBUS_CYGWIN, test "$dbus_cygwin" = yes)
 
-AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[enable unit test code]),enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE)
+# this must come first: other options use this to set their defaults
+AC_ARG_ENABLE([developer],
+  [AS_HELP_STRING([--enable-developer],
+    [set defaults to be appropriate for a D-Bus developer instead of a distribution/end-user])],
+  [],
+  [enable_developer=no])
+
+DBUS_STATIC_BUILD_CPPFLAGS=
+if test "x$enable_shared" = xno; then
+    # On Windows, linking against the static library requires special effort
+    # to turn off DLL import/export processing. We normally link some things
+    # against the dynamic library, but if we're not building that, we'll
+    # have to link everything statically.
+    DBUS_STATIC_BUILD_CPPFLAGS=-DDBUS_STATIC_BUILD
+fi
+AC_SUBST([DBUS_STATIC_BUILD_CPPFLAGS])
+
 AC_ARG_ENABLE(ansi, AS_HELP_STRING([--enable-ansi],[enable -ansi -pedantic gcc flags]),enable_ansi=$enableval,enable_ansi=no)
-AC_ARG_ENABLE(verbose-mode, AS_HELP_STRING([--enable-verbose-mode],[support verbose debug mode]),enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
-AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion checks]),enable_asserts=$enableval,enable_asserts=$USE_MAINTAINER_MODE)
+AC_ARG_ENABLE(verbose-mode, AS_HELP_STRING([--enable-verbose-mode],[support verbose debug mode]),enable_verbose_mode=$enableval,enable_verbose_mode=$enable_developer)
+AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion checks]),enable_asserts=$enableval,enable_asserts=$enable_developer)
 AC_ARG_ENABLE(checks, AS_HELP_STRING([--enable-checks],[include sanity checks on public API]),enable_checks=$enableval,enable_checks=yes)
 AC_ARG_ENABLE(xml-docs, AS_HELP_STRING([--enable-xml-docs],[build XML documentation (requires xmlto)]),enable_xml_docs=$enableval,enable_xml_docs=auto)
 AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGEN documentation (requires Doxygen)]),enable_doxygen_docs=$enableval,enable_doxygen_docs=auto)
-AC_ARG_ENABLE(gcov, AS_HELP_STRING([--enable-gcov],[compile with coverage profiling instrumentation (gcc only)]),enable_gcov=$enableval,enable_gcov=no)
 AC_ARG_ENABLE(abstract-sockets, AS_HELP_STRING([--enable-abstract-sockets],[use abstract socket namespace (linux only)]),enable_abstract_sockets=$enableval,enable_abstract_sockets=auto)
 AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto)
 AC_ARG_ENABLE(libaudit,AS_HELP_STRING([--enable-libaudit],[build audit daemon support for SELinux]),enable_libaudit=$enableval,enable_libaudit=auto)
@@ -135,8 +155,10 @@
 AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue support]),enable_kqueue=$enableval,enable_kqueue=auto)
 AC_ARG_ENABLE(console-owner-file, AS_HELP_STRING([--enable-console-owner-file],[enable console owner file]),enable_console_owner_file=$enableval,enable_console_owner_file=auto)
 AC_ARG_ENABLE(userdb-cache, AS_HELP_STRING([--enable-userdb-cache],[build with userdb-cache support]),enable_userdb_cache=$enableval,enable_userdb_cache=yes)
+AC_ARG_ENABLE(launchd, AS_HELP_STRING([--enable-launchd],[build with launchd auto-launch support]),enable_launchd=$enableval,enable_launchd=auto)
+AC_ARG_ENABLE(systemd, AS_HELP_STRING([--enable-systemd],[build with systemd at_console support]),enable_systemd=$enableval,enable_systemd=auto)
 
-AC_ARG_WITH(xml, AS_HELP_STRING([--with-xml=[libxml/expat]],[XML library to use]))
+AC_ARG_WITH(xml, AS_HELP_STRING([--with-xml=[libxml/expat]],[XML library to use (libxml may be named libxml2 on some systems)]))
 AC_ARG_WITH(init-scripts, AS_HELP_STRING([--with-init-scripts=[redhat]],[Style of init scripts to install]))
 AC_ARG_WITH(session-socket-dir, AS_HELP_STRING([--with-session-socket-dir=[dirname]],[Where to put sockets for the per-login-session message bus]))
 AC_ARG_WITH(test-socket-dir, AS_HELP_STRING([--with-test-socket-dir=[dirname]],[Where to put sockets for make check]))
@@ -144,14 +166,107 @@
 AC_ARG_WITH(system-socket, AS_HELP_STRING([--with-system-socket=[filename]],[UNIX domain socket for systemwide daemon]))
 AC_ARG_WITH(console-auth-dir, AS_HELP_STRING([--with-console-auth-dir=[dirname]],[directory to check for console ownerhip]))
 AC_ARG_WITH(console-owner-file, AS_HELP_STRING([--with-console-owner-file=[filename]],[file whose owner determines current console owner]))
+AC_ARG_WITH(launchd-agent-dir, AS_HELP_STRING([--with-launchd-agent-dir=[dirname]],[directory to put the launchd agent (default: /Library/LaunchAgents)]))
 AC_ARG_WITH(dbus_user, AS_HELP_STRING([--with-dbus-user=<user>],[User for running the DBUS daemon (messagebus)]))
 AC_ARG_WITH(dbus_daemondir, AS_HELP_STRING([--with-dbus-daemondir=[dirname]],[Directory for installing the DBUS daemon]))
+AC_ARG_WITH(dbus_session_bus_default_address, AS_HELP_STRING([--with-dbus-session-bus-default-address=[nonce-tcp:/autolaunch:/tcp:host:port]],[Transport Type to be used (default: nonce-tcp:)]),with_dbus_session_bus_default_address=$withval,with_dbus_session_bus_default_address=nonce-tcp:)
 
-dnl DBUS_BUILD_TESTS controls unit tests built in to .c files
-dnl and also some stuff in the test/ subdir
-AM_CONDITIONAL(DBUS_BUILD_TESTS, test x$enable_tests = xyes)
-if test x$enable_tests = xyes; then
-    AC_DEFINE(DBUS_BUILD_TESTS,1,[Build test code])
+AC_ARG_ENABLE([embedded-tests],
+  AS_HELP_STRING([--enable-embedded-tests],
+    [enable unit test code in the library and binaries]),
+  [], [enable_embedded_tests=$enable_developer])
+AC_ARG_ENABLE([modular-tests],
+  AS_HELP_STRING([--enable-modular-tests],
+    [enable modular regression tests (requires GLib)]),
+  [], [enable_modular_tests=auto])
+# --enable-tests overrides both --enable-embedded-tests and
+# --enable-modular-tests
+AC_ARG_ENABLE([tests],
+  AS_HELP_STRING([--enable-tests],
+    [enable/disable all tests, overriding embedded-tests/modular-tests]),
+  [
+  if test "x$enableval" = xyes; then
+    AC_MSG_NOTICE([Full test coverage was requested with --enable-tests=yes])
+    AC_MSG_NOTICE([This has many dependencies (GLib, dbus-glib, Python)])
+  fi
+  enable_embedded_tests=$enableval
+  enable_modular_tests=$enableval
+  ],
+  [])
+
+# DBUS_ENABLE_EMBEDDED_TESTS controls unit tests built in to .c files
+# and also some stuff in the test/ subdir. DBUS_BUILD_TESTS was an older
+# name for this.
+AM_CONDITIONAL([DBUS_BUILD_TESTS], [test "x$enable_embedded_tests" = xyes])
+AM_CONDITIONAL([DBUS_ENABLE_EMBEDDED_TESTS],
+  [test "x$enable_embedded_tests" = xyes])
+if test "x$enable_embedded_tests" = xyes; then
+    AC_DEFINE([DBUS_ENABLE_EMBEDDED_TESTS], [1],
+      [Define to build test code into the library and binaries])
+    AC_DEFINE([DBUS_BUILD_TESTS], [1],
+      [Define to build test code into the library and binaries])
+fi
+
+# DBUS_ENABLE_MODULAR_TESTS controls tests that work based on public API.
+# These use GTest, from GLib, because life's too short. They're enabled by
+# default (unless you don't have GLib), because they don't bloat the library
+# or binaries.
+
+with_glib=yes
+
+if test "x$enable_modular_tests" != xno; then
+  PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.24, gio-2.0 >= 2.24],
+    [],
+    [if test "x$enable_modular_tests" = xyes; then
+      AC_MSG_NOTICE([Full test coverage (--enable-modular-tests=yes or --enable-tests=yes) requires GLib])
+      AC_MSG_ERROR([$GLIB_ERRORS])
+    else # assumed to be "auto"
+      with_glib=no
+    fi])
+  # If dbus-gmain.[ch] returned to libdbus then we wouldn't need this
+  PKG_CHECK_MODULES([DBUS_GLIB], [dbus-glib-1],
+    [],
+    [if test "x$enable_modular_tests" = xyes; then
+      AC_MSG_NOTICE([Full test coverage (--enable-modular-tests=yes or --enable-tests=yes) requires dbus-glib])
+      AC_MSG_ERROR([$DBUS_GLIB_ERRORS])
+    else # assumed to be "auto"
+      with_glib=no
+    fi])
+fi
+if test "x$enable_modular_tests" != xno; then
+  AC_DEFINE([DBUS_ENABLE_MODULAR_TESTS], [1],
+    [Define to build independent test binaries])
+fi
+AM_CONDITIONAL([DBUS_ENABLE_MODULAR_TESTS],
+  [test "x$enable_modular_tests" != xno])
+
+if test "x$with_glib" != xno; then
+  AC_DEFINE([DBUS_WITH_GLIB], [1],
+    [Define if GLib, GObject, GIO are available])
+fi
+AM_CONDITIONAL([DBUS_WITH_GLIB], [test "x$with_glib" != xno])
+
+AC_ARG_ENABLE([installed-tests],
+  AS_HELP_STRING([--enable-installed-tests],
+    [enable unit test code in the library and binaries]),
+  [], [enable_installed_tests=no])
+AM_CONDITIONAL([DBUS_ENABLE_INSTALLED_TESTS],
+  [test "x$enable_installed_tests" = xyes])
+
+if test "x$enable_tests" = xyes; then
+  # full test coverage is required, Python is a hard dependency
+  AC_MSG_NOTICE([Full test coverage (--enable-tests=yes) requires Python, dbus-python, pygobject])
+  AM_PATH_PYTHON([2.6])
+  AC_MSG_CHECKING([for Python modules for full test coverage])
+  if "$PYTHON" -c "import dbus, gobject, dbus.mainloop.glib"; then
+    AC_MSG_RESULT([yes])
+  else
+    AC_MSG_RESULT([no])
+    AC_MSG_ERROR([cannot import dbus, gobject, dbus.mainloop.glib Python modules])
+  fi
+else
+  # --enable-tests not given: do not abort if Python is missing
+  AM_PATH_PYTHON([2.6], [], [:])
 fi
 
 if test x$enable_verbose_mode = xyes; then
@@ -160,7 +275,7 @@
 
 if test x$enable_asserts = xno; then
     AC_DEFINE(DBUS_DISABLE_ASSERT,1,[Disable assertion checking])
-    AC_DEFINE(G_DISABLE_ASSERT,1,[Disable GLib assertion macros])
+    DISABLE_UNUSED_WARNINGS="unused-label"
     R_DYNAMIC_LDFLAG=""
 else
     # -rdynamic is needed for glibc's backtrace_symbols to work.
@@ -178,26 +293,17 @@
 if test x$enable_checks = xno; then
     AC_DEFINE(DBUS_DISABLE_CHECKS,1,[Disable public API sanity checking])
     AC_DEFINE(G_DISABLE_CHECKS,1,[Disable GLib public API sanity checking])
+    DISABLE_UNUSED_WARNINGS="unused-label"
 fi
 
 if test x$enable_userdb_cache = xyes; then
     AC_DEFINE(DBUS_ENABLE_USERDB_CACHE,1,[Build with caching of user data])
 fi
 
-if test x$enable_gcov = xyes; then
+if test x$enable_compiler_coverage = xyes; then
      ## so that config.h changes when you toggle gcov support
      AC_DEFINE_UNQUOTED(DBUS_GCOV_ENABLED, 1, [Defined if gcov is enabled to force a rebuild due to config.h changing])
-
-     AC_MSG_CHECKING([for gcc 3.3 version of gcov file format])
-     have_gcc33_gcov=no
-     AC_RUN_IFELSE( [AC_LANG_PROGRAM( , [[ if (__GNUC__ >=3 && __GNUC_MINOR__ >= 3) exit (0); else exit (1); ]])],
-                   have_gcc33_gcov=yes)
-     if test x$have_gcc33_gcov = xyes ; then
-         AC_DEFINE_UNQUOTED(DBUS_HAVE_GCC33_GCOV, 1, [Defined if we have gcc 3.3 and thus the new gcov format])
-     fi
-     AC_MSG_RESULT($have_gcc33_gcov)
 fi
-AM_CONDITIONAL(DBUS_GCOV_ENABLED, test x$enable_gcov = xyes)
 
 # glibc21.m4 serial 3
 dnl Copyright (C) 2000-2002, 2004 Free Software Foundation, Inc.
@@ -234,6 +340,12 @@
 AC_CHECK_SIZEOF(long long)
 AC_CHECK_SIZEOF(__int64)
 
+AC_ARG_WITH([64-bit],
+  [AS_HELP_STRING([--without-64-bit],
+    [If you have to use this option, please report it as a bug])],
+  [],
+  [with_64_bit=yes])
+
 ### See what our 64 bit type is called
 AC_MSG_CHECKING([64-bit integer type])
 
@@ -271,13 +383,32 @@
   ;;
 esac
 
-if test -z "$dbusint64" ; then
+AS_IF(
+  [test "x$with_64_bit" = xno],
+  [
         DBUS_INT64_TYPE="no_int64_type_detected"
         DBUS_HAVE_INT64=0
         DBUS_INT64_CONSTANT=
         DBUS_UINT64_CONSTANT=
-        AC_MSG_RESULT([none found])
-else
+        AC_MSG_RESULT([disabled via --without-64-bit])
+  ],
+  dnl else if
+  [test -z "$dbusint64"],
+  [AC_MSG_RESULT([not found])
+  AC_MSG_ERROR([Could not find a 64-bit integer type.
+
+Please report a bug here with details of your platform and compiler:
+
+    http://bugs.freedesktop.org/enter_bug.cgi?product=DBus&component=core
+
+To compile D-Bus with all 64-bit integer types removed (not recommended), use
+the option "--without-64-bit".
+
+This option is likely to be removed in future, unless you report that your
+platform needs it.])
+  ],
+  dnl else
+  [
         DBUS_INT64_TYPE="$dbusint64"
         DBUS_HAVE_INT64=1
         DBUS_INT64_CONSTANT="$dbusint64_constant"
@@ -286,7 +417,7 @@
 		AC_DEFINE_UNQUOTED(DBUS_INT64_PRINTF_MODIFIER, [$dbusint64_printf_modifier], [Define to printf modifier for 64 bit integer type])
 	fi
         AC_MSG_RESULT($DBUS_INT64_TYPE)
-fi
+  ])
 
 AC_SUBST(DBUS_INT64_TYPE)
 AC_SUBST(DBUS_INT64_CONSTANT)
@@ -298,7 +429,7 @@
 
 case 4 in
 $ac_cv_sizeof_short)
-  dbusint32=int
+  dbusint32=short
   ;;
 $ac_cv_sizeof_int)
   dbusint32=int
@@ -363,7 +494,7 @@
 dnl we currently check for all three va_copy possibilities, so we get
 dnl all results in config.log for bug reports.
 AC_CACHE_CHECK([for an implementation of va_copy()],dbus_cv_va_copy,[
-	AC_LINK_IFELSE([#include <stdarg.h>
+	AC_LINK_IFELSE([AC_LANG_SOURCE([#include <stdarg.h>
 #include <stdlib.h>
 	static void f (int i, ...) {
 	va_list args1, args2;
@@ -376,12 +507,12 @@
 	int main() {
 	  f (0, 42);
 	  return 0;
-	}],
+	}])],
 	[dbus_cv_va_copy=yes],
 	[dbus_cv_va_copy=no])
 ])
 AC_CACHE_CHECK([for an implementation of __va_copy()],dbus_cv___va_copy,[
-	AC_LINK_IFELSE([#include <stdarg.h>
+	AC_LINK_IFELSE([AC_LANG_SOURCE([#include <stdarg.h>
 #include <stdlib.h>
 	static void f (int i, ...) {
 	va_list args1, args2;
@@ -394,7 +525,7 @@
 	int main() {
 	  f (0, 42);
 	  return 0;
-	}],
+	}])],
 	[dbus_cv___va_copy=yes],
 	[dbus_cv___va_copy=no])
 ])
@@ -447,8 +578,8 @@
 
 AC_CACHE_CHECK([whether $CC knows __sync_sub_and_fetch()],
   dbus_cv_sync_sub_and_fetch,
-  [AC_LINK_IFELSE(
-     AC_LANG_PROGRAM([], [[int a = 4; int b = __sync_sub_and_fetch(&a, 4); exit(b); ]]),
+  [AC_LINK_IFELSE([
+     AC_LANG_PROGRAM([[]], [[int a = 4; int b = __sync_sub_and_fetch(&a, 4); exit(b); ]])],
      [dbus_cv_sync_sub_and_fetch=yes],
      [dbus_cv_sync_sub_and_fetch=no])
   ])
@@ -465,7 +596,12 @@
 AC_SEARCH_LIBS(socket,[socket network])
 AC_CHECK_FUNC(gethostbyname,,[AC_CHECK_LIB(nsl,gethostbyname)])
 
-AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll setlocale localeconv strtoll strtoull)
+AC_CHECK_FUNCS(vsnprintf vasprintf nanosleep usleep setenv clearenv unsetenv socketpair getgrouplist fpathconf setrlimit poll setlocale localeconv strtoll strtoull issetugid getresuid)
+
+AC_CHECK_HEADERS([syslog.h])
+if test "x$ac_cv_header_syslog_h" = "xyes"; then
+  AC_CHECK_DECLS([LOG_PERROR], [], [], [[#include <syslog.h>]])
+fi
 
 #### Check for broken poll; taken from Glib's configure
 
@@ -496,38 +632,42 @@
 AC_MSG_RESULT($broken_poll)
 
 AC_MSG_CHECKING(for dirfd)
-AC_TRY_LINK([
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 #include <sys/types.h>
 #include <dirent.h>
-],[
+]], [[
 DIR *dirp;
 dirp = opendir(".");
 dirfd(dirp);
 closedir(dirp);
-],
-dbus_have_dirfd=yes, dbus_have_dirfd=no)
+]])],
+[dbus_have_dirfd=yes],
+[dbus_have_dirfd=no])
 AC_MSG_RESULT($dbus_have_dirfd)
 if test "$dbus_have_dirfd" = yes; then
 	AC_DEFINE(HAVE_DIRFD,1,[Have dirfd function])
 else
 	AC_MSG_CHECKING(for DIR *dirp->dd_fd)
-	AC_TRY_LINK([
+	AC_LINK_IFELSE([AC_LANG_PROGRAM([[
 #include <sys/types.h>
 #include <dirent.h>
-	],[
+	]], [[
 DIR *dirp;
 int fd;
 dirp = opendir(".");
 fd = dirp->dd_fd;
 closedir(dirp);
-	],
-	dbus_have_ddfd=yes, dbus_have_ddfd=no)
+        ]])],
+        [dbus_have_ddfd=yes],
+        [dbus_have_ddfd=no])
 	AC_MSG_RESULT($dbus_have_ddfd)
 	if test "$dbus_have_ddfd" = yes; then
 		AC_DEFINE(HAVE_DDFD,1,[Have the ddfd member of DIR])
 	fi
 fi
 
+AC_CHECK_HEADERS(sys/resource.h)
+
 AC_CHECK_HEADERS(dirent.h)
 
 AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)])
@@ -588,11 +728,10 @@
 else
         AC_CACHE_CHECK([for nonposix getpwnam_r],
                 ac_cv_func_nonposix_getpwnam_r,
-                [AC_TRY_LINK([#include <pwd.h>],
-                        [char buffer[10000];
+                [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pwd.h>]], [[char buffer[10000];
                         struct passwd pwd;
                         getpwnam_r ("", &pwd, buffer,
-                                        sizeof (buffer));],
+                                        sizeof (buffer));]])],
                         [ac_cv_func_nonposix_getpwnam_r=yes],
                         [ac_cv_func_nonposix_getpwnam_r=no])])
                 if test "$ac_cv_func_nonposix_getpwnam_r" = yes; then
@@ -603,14 +742,16 @@
 
 dnl check for socklen_t
 AC_MSG_CHECKING(whether socklen_t is defined)
-AC_TRY_COMPILE([
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netdb.h>
-],[
+]], [[
 socklen_t foo;
 foo = 1;
-],dbus_have_socklen_t=yes,dbus_have_socklen_t=no)
+]])],
+[dbus_have_socklen_t=yes],
+[dbus_have_socklen_t=no])
 AC_MSG_RESULT($dbus_have_socklen_t)
 
 if test "x$dbus_have_socklen_t" = "xyes"; then
@@ -625,23 +766,28 @@
 AC_CHECK_HEADERS(sys/syslimits.h)
 
 dnl Make it easy to check if we have MSG_NOSIGNAL without actually having to include sys/socket.h
-AC_CHECK_DECLS([MSG_NOSIGNAL], [], [], [[ #include <sys/socket.h> ]])
+AC_CHECK_DECLS([MSG_NOSIGNAL], [], [], [[ #include <sys/types.h>
+#include <sys/socket.h> ]])
 
 dnl check for flavours of varargs macros (test from GLib)
 AC_MSG_CHECKING(for ISO C99 varargs macros in C)
-AC_TRY_COMPILE([],[
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
 int a(int p1, int p2, int p3);
 #define call_a(...) a(1,__VA_ARGS__)
 call_a(2,3);
-],dbus_have_iso_c_varargs=yes,dbus_have_iso_c_varargs=no)
+]])],
+[dbus_have_iso_c_varargs=yes],
+[dbus_have_iso_c_varargs=no])
 AC_MSG_RESULT($dbus_have_iso_c_varargs)
 
 AC_MSG_CHECKING(for GNUC varargs macros)
-AC_TRY_COMPILE([],[
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
 int a(int p1, int p2, int p3);
 #define call_a(params...) a(1,params)
 call_a(2,3);
-],dbus_have_gnuc_varargs=yes,dbus_have_gnuc_varargs=no)
+]])],
+[dbus_have_gnuc_varargs=yes],
+[dbus_have_gnuc_varargs=no])
 AC_MSG_RESULT($dbus_have_gnuc_varargs)
 
 dnl Output varargs tests
@@ -654,14 +800,16 @@
 
 dnl Check for various credentials.
 AC_MSG_CHECKING(for struct cmsgcred)
-AC_TRY_COMPILE([
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
 #include <sys/types.h>
 #include <sys/socket.h>
-],[
+]], [[
 struct cmsgcred cred;
 
 cred.cmcred_pid = 0;
-],dbus_have_struct_cmsgcred=yes,dbus_have_struct_cmsgcred=no)
+]])],
+[dbus_have_struct_cmsgcred=yes],
+[dbus_have_struct_cmsgcred=no])
 AC_MSG_RESULT($dbus_have_struct_cmsgcred)
 
 if test x$dbus_have_struct_cmsgcred = xyes; then
@@ -690,6 +838,7 @@
 #include <errno.h>
 ]],
 [[
+  size_t slen;
   int listen_fd;
   struct sockaddr_un addr;
 
@@ -704,9 +853,13 @@
   memset (&addr, '\0', sizeof (addr));
   addr.sun_family = AF_UNIX;
   strcpy (addr.sun_path, "X/tmp/dbus-fake-socket-path-used-in-configure-test");
+  /* SUN_LEN uses strlen() so need to calculate it before adding \0 at the
+   * beginning.
+   */
+  slen = SUN_LEN(&addr);
   addr.sun_path[0] = '\0'; /* this is what makes it abstract */
 
-  if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)
+  if (bind (listen_fd, (struct sockaddr*) &addr, slen) < 0)
     {
        fprintf (stderr, "Abstract socket namespace bind() failed: %s\n",
                 strerror (errno));
@@ -796,6 +949,8 @@
    XML_LIBS=$LIBXML_LIBS
    XML_CFLAGS=$LIBXML_CFLAGS
 fi
+AC_SUBST([XML_CFLAGS])
+AC_SUBST([XML_LIBS])
 
 # Thread lib detection
 AC_CHECK_FUNC(pthread_cond_timedwait,[AC_CHECK_LIB(pthread,pthread_cond_timedwait,
@@ -806,15 +961,17 @@
 if test x$have_pthread_condattr_setclock = xtrue; then
     AC_SEARCH_LIBS([clock_getres],[rt],[THREAD_LIBS="$THREAD_LIBS -lrt"])
     AC_MSG_CHECKING([for CLOCK_MONOTONIC])
-    AC_TRY_COMPILE([#include <time.h>
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <time.h>
 #include <pthread.h>
-], [
+]], [[
 struct timespec monotonic_timer;
 pthread_condattr_t attr;
 pthread_condattr_init (&attr);
 pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
 clock_getres (CLOCK_MONOTONIC,&monotonic_timer);
-], have_clock_monotonic=true, have_clock_monotonic=false)
+]])],
+[have_clock_monotonic=true],
+[have_clock_monotonic=false])
 if test x$have_clock_monotonic = xtrue; then
     AC_MSG_RESULT([found])
     AC_DEFINE(HAVE_MONOTONIC_CLOCK, 1, [Define if we have CLOCK_MONOTONIC])
@@ -824,6 +981,8 @@
 fi
 LIBS="$save_libs"
 
+AC_SUBST([THREAD_LIBS])
+
 # SELinux detection
 if test x$enable_selinux = xno ; then
     have_selinux=no;
@@ -835,12 +994,13 @@
     # see if we have the SELinux header with the new D-Bus stuff in it
     if test x$have_selinux = xyes ; then
         AC_MSG_CHECKING([for DBUS Flask permissions in selinux/av_permissions.h])
-	AC_TRY_COMPILE([#include <selinux/av_permissions.h>],
-			[#ifdef DBUS__ACQUIRE_SVC return 0;
-			 #else
-			 #error DBUS__ACQUIRE_SVC not defined
-			 #endif],
-                        have_selinux=yes, have_selinux=no)
+        AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <selinux/av_permissions.h>]],
+                          [[#ifdef DBUS__ACQUIRE_SVC return 0;
+			    #else
+			    #error DBUS__ACQUIRE_SVC not defined
+			    #endif]])],
+                          [have_selinux=yes],
+                          [have_selinux=no])
 	AC_MSG_RESULT($have_selinux)
     fi
 
@@ -902,6 +1062,36 @@
 
 AM_CONDITIONAL(DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX, test x$have_dnotify = xyes)
 
+# For simplicity, we require the userland API for epoll_create1 at
+# compile-time (glibc 2.9), but we'll run on kernels that turn out
+# not to have it at runtime.
+AC_ARG_ENABLE([epoll],
+              [AS_HELP_STRING([--enable-epoll],[use epoll(4) on Linux])],
+              [enable_epoll=$enableval], [enable_epoll=auto])
+if test x$enable_epoll = xno; then
+    have_linux_epoll=no
+else
+    AC_MSG_CHECKING([for Linux epoll(4)])
+    AC_LINK_IFELSE([AC_LANG_PROGRAM(
+        [
+        #ifndef __linux__
+        #error This is not Linux
+        #endif
+        #include <sys/epoll.h>
+        ],
+        [epoll_create1 (EPOLL_CLOEXEC);])],
+        [have_linux_epoll=yes],
+        [have_linux_epoll=no])
+    AC_MSG_RESULT([$have_linux_epoll])
+fi
+if test x$enable_epoll,$have_linux_epoll = xyes,no; then
+    AC_MSG_ERROR([epoll support explicitly enabled but not available])
+fi
+if test x$have_linux_epoll = xyes; then
+  AC_DEFINE([DBUS_HAVE_LINUX_EPOLL], 1, [Define to use epoll(4) on Linux])
+fi
+AM_CONDITIONAL([HAVE_LINUX_EPOLL], [test x$have_linux_epoll = xyes])
+
 # kqueue checks
 if test x$enable_kqueue = xno ; then
     have_kqueue=no
@@ -922,6 +1112,38 @@
 
 AM_CONDITIONAL(DBUS_BUS_ENABLE_KQUEUE, test x$have_kqueue = xyes)
 
+# launchd checks
+if test x$enable_launchd = xno ; then
+    have_launchd=no
+else
+    have_launchd=yes
+    AC_CHECK_HEADER([launch.h], , have_launchd=no)
+    AC_PATH_PROG([LAUNCHCTL], [launchctl])
+    if test "x$LAUNCHCTL" = "x"; then
+        have_launchd=no
+    fi
+
+    if test x$enable_launchd = xyes && test x$have_launchd = xno ; then
+        AC_MSG_ERROR([launchd support explicitly enabled but not available])
+    fi
+fi
+
+dnl check if launchd is enabled
+if test x$have_launchd = xyes; then
+    AC_DEFINE(DBUS_ENABLE_LAUNCHD,1,[Use launchd autolaunch])
+fi
+
+AM_CONDITIONAL(DBUS_ENABLE_LAUNCHD, test x$have_launchd = xyes)
+
+#### Directory to place launchd agent file
+if test "x$with_launchd_agent_dir" = "x"; then
+   LAUNCHD_AGENT_DIR="/Library/LaunchAgents"
+else
+   LAUNCHD_AGENT_DIR="$with_launchd_agent_dir"
+fi
+
+AC_SUBST(LAUNCHD_AGENT_DIR)
+
 dnl console owner file
 if test x$enable_console_owner_file = xno ; then
     have_console_owner_file=no;
@@ -938,6 +1160,24 @@
 
 AM_CONDITIONAL(HAVE_CONSOLE_OWNER_FILE, test x$have_console_owner_file = xyes)
 
+dnl systemd detection
+if test x$enable_systemd = xno ; then
+    have_systemd=no;
+else
+    PKG_CHECK_MODULES(SYSTEMD,
+        [libsystemd-login >= 32, libsystemd-daemon >= 32],
+        have_systemd=yes,
+        have_systemd=no)
+fi
+
+if test x$have_systemd = xyes; then
+    AC_DEFINE(HAVE_SYSTEMD,1,[Have systemd])
+fi
+
+if test x$enable_systemd = xyes -a x$have_systemd != xyes ; then
+    AC_MSG_ERROR([Explicitly requested systemd support, but systemd not found])
+fi
+
 # libaudit detection
 if test x$enable_libaudit = xno ; then
     have_libaudit=no;
@@ -958,7 +1198,9 @@
     AC_DEFINE(HAVE_LIBAUDIT,1,[audit daemon SELinux support])
 fi
 
-# Check for ADT API
+AC_SUBST([SELINUX_LIBS])
+
+# Check for ADT API (Solaris Basic Security Mode auditing)
 AC_MSG_CHECKING(for ADT API)
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
 #include <bsm/adt.h>
@@ -974,10 +1216,12 @@
 else
    AC_MSG_RESULT(no)
 fi
+AC_SUBST([ADT_LIBS])
 
 # Check for SCM_RIGHTS
 AC_MSG_CHECKING([for SCM_RIGHTS])
 AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 static int x = SCM_RIGHTS;
@@ -995,295 +1239,155 @@
   fi
 fi
 
+AC_SUBST([NETWORK_libs])
+
+AC_ARG_WITH([valgrind],
+  [AS_HELP_STRING([--with-valgrind],
+     [Add instrumentation to help valgrind to understand our allocator])],
+  [],
+  [with_valgrind=no])
+
+if test x$with_valgrind != xno; then
+  PKG_CHECK_MODULES([VALGRIND], [valgrind >= 3.6])
+  AC_DEFINE([WITH_VALGRIND], [1], [Define to add Valgrind instrumentation])
+fi
+
 #### Set up final flags
-DBUS_CLIENT_CFLAGS=
-DBUS_CLIENT_LIBS="$THREAD_LIBS $NETWORK_libs"
-AC_SUBST(DBUS_CLIENT_CFLAGS)
-AC_SUBST(DBUS_CLIENT_LIBS)
-
-DBUS_BUS_CFLAGS="$XML_CFLAGS"
-DBUS_BUS_LIBS="$XML_LIBS $SELINUX_LIBS $INTLLIBS $THREAD_LIBS $ADT_LIBS $NETWORK_libs"
-AC_SUBST(DBUS_BUS_CFLAGS)
-AC_SUBST(DBUS_BUS_LIBS)
-
-DBUS_LAUNCHER_CFLAGS="$XML_CFLAGS"
-DBUS_LAUNCHER_LIBS="$XML_LIBS $THREAD_LIBS $NETWORK_libs"
-AC_SUBST(DBUS_LAUNCHER_CFLAGS)
-AC_SUBST(DBUS_LAUNCHER_LIBS)
-
-DBUS_TEST_CFLAGS=
-DBUS_TEST_LIBS="$THREAD_LIBS $NETWORK_libs"
-AC_SUBST(DBUS_TEST_CFLAGS)
-AC_SUBST(DBUS_TEST_LIBS)
+LIBDBUS_LIBS="$THREAD_LIBS $NETWORK_libs"
+AC_SUBST([LIBDBUS_LIBS])
 
 ### X11 detection
-if test x$dbus_win = xyes ; then
-   enable_x11=no
-else
-AC_PATH_XTRA
+DBUS_X_LIBS=
+DBUS_X_CFLAGS=
 
-## for now enable_x11 just tracks have_x11,
-## there's no --enable-x11
-if test x$no_x = xyes ; then
-   have_x11=no
-   enable_x11=no
+AC_ARG_ENABLE([x11-autolaunch],
+  AS_HELP_STRING([--enable-x11-autolaunch], [build with X11 auto-launch support]),
+  [], [enable_x11_autolaunch=auto])
+
+if test "x$dbus_win" = xyes; then
+    if test "x$enable_x11_autolaunch" = xyes; then
+        AC_MSG_ERROR([X11 auto-launch is not supported on Windows])
+    fi
+
+    enable_x11_autolaunch=no
+    have_x11=no
 else
-   have_x11=yes
-   enable_x11=yes
+    AC_PATH_XTRA
+
+    if test "x$no_x" = xyes; then
+        have_x11=no
+    else
+        have_x11=yes
+        DBUS_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
+        DBUS_X_CFLAGS="$X_CFLAGS"
+    fi
 fi
 
-if test x$enable_x11 = xyes ; then
-   AC_DEFINE(DBUS_BUILD_X11,1,[Build X11-dependent code])
-   DBUS_X_LIBS="$X_LIBS $X_PRE_LIBS -lX11 $X_EXTRA_LIBS"
-   DBUS_X_CFLAGS="$X_CFLAGS"
+if test "x$enable_x11_autolaunch,$have_x11" = xyes,no; then
+    AC_MSG_ERROR([X11 auto-launch requires X headers/libraries])
 else
-   DBUS_X_LIBS=
-   DBUS_X_CFLAGS=
+    # move from "auto" to "yes" or "no" if necessary
+    if test "x$enable_x11_autolaunch" != xno; then
+        enable_x11_autolaunch="$have_x11"
+    fi
 fi
 
-AC_SUBST(DBUS_X_CFLAGS)
-AC_SUBST(DBUS_X_LIBS)
+if test "x$have_x11" = xyes ; then
+   AC_DEFINE([DBUS_BUILD_X11], [1], [Define to build X11 functionality])
 fi
 
+if test "x$enable_x11_autolaunch" = xyes ; then
+   AC_DEFINE([DBUS_ENABLE_X11_AUTOLAUNCH], [1], [Define to enable X11 auto-launch])
+fi
+
+AC_SUBST([DBUS_X_CFLAGS])
+AC_SUBST([DBUS_X_LIBS])
 
 #### gcc warning flags
 
 cc_supports_flag() {
-  AC_MSG_CHECKING(whether $CC supports "$@")
-  Cfile=/tmp/foo${$}
-  touch ${Cfile}.c
-  $CC -c "$@" ${Cfile}.c -o ${Cfile}.o >/dev/null 2>&1
-  rc=$?
-  rm -f ${Cfile}.c ${Cfile}.o
-  case $rc in
-    0) AC_MSG_RESULT(yes);;
-    *) AC_MSG_RESULT(no);;
-  esac
-  return $rc
+  AC_MSG_CHECKING(whether $CC supports "$*")
+  save_CFLAGS="$CFLAGS"
+  CFLAGS="$*"
+  AC_TRY_COMPILE([], [], [rc=yes], [rc=no])
+  CFLAGS="$save_CFLAGS"
+  AC_MSG_RESULT([$rc])
+  test "x$rc" = xyes
 }
 
-ld_supports_flag() {
-  AC_MSG_CHECKING([whether $LD supports "$@"])
-  AC_TRY_LINK([
-    int one(void) { return 1; }
-    int two(void) { return 2; }
-  ], [ two(); ] , [_ac_ld_flag_supported=yes], [_ac_ld_flag_supported=no])
+TP_COMPILER_WARNINGS([WARNING_CFLAGS],
+  dnl Use -Werror by default if:
+  dnl - we're not on Windows (too many warnings), and
+  dnl - we're in developer mode (a D-Bus developer, not a distro or end-user)
+  dnl Override with --enable-Werror or --disable-Werror
+  [test x$dbus_win != xyes -a x$dbus_cygwin != xyes -a x$enable_developer = xyes],
 
-  if test "$_ac_ld_flag_supported" = "yes"; then
-    rm -f conftest.c
-    touch conftest.c
-    if $CC -c conftest.c; then
-      ld_out=`$LD $@ -o conftest conftest.o 2>&1`
-      ld_ret=$?
-      if test $ld_ret -ne 0 ; then
-        _ac_ld_flag_supported=no
-      elif echo "$ld_out" | egrep 'option ignored|^usage:|unrecognized option|illegal option' >/dev/null ; then
-        _ac_ld_flag_supported=no
-      fi
-    fi
-    rm -f conftest.c conftest.o conftest
-  fi
+  dnl Enable these warnings if possible:
+  [all \
+   extra \
+   char-subscripts \
+   missing-declarations \
+   missing-prototypes \
+   nested-externs \
+   pointer-arith \
+   cast-align \
+   no-address \
+   float-equal \
+   declaration-after-statement \
+  ],
 
-  AC_MSG_RESULT($_ac_ld_flag_supported)
-  if test "$_ac_ld_flag_supported" = "yes" ; then
-    return 0
-  else
-    return 1
-  fi
-}
-
-# Don't bother with -Werror on Windows for now, too many warnings
-if test x$dbus_win != xyes -a x$dbus_cygwin != xyes -a x$USE_MAINTAINER_MODE = xyes; then
-  if cc_supports_flag "-Werror"; then
-    CFLAGS="$CFLAGS -Werror"
-  fi
-fi
+  dnl Disable these warnings if possible, make them non-fatal if possible,
+  dnl and don't enable -Werror unless we succeeded.
+  dnl
+  dnl Intentional:
+  dnl - $DISABLE_UNUSED_WARNINGS disables unused-label warnings if not
+  dnl   checking or not asserting
+  dnl - missing field initializers being 0 is a C feature, not a bug
+  dnl - unused-parameter is to make writing callbacks less annoying
+  dnl
+  dnl To be fixed one day:
+  dnl - sign-compare and pointer-sign are workarounds for fd.o #17433
+  dnl - type-limits is probably a bug too, but having the rest of -Wextra
+  dnl   is better than nothing
+  [$DISABLE_UNUSED_WARNINGS \
+   missing-field-initializers \
+   unused-parameter \
+   sign-compare \
+   pointer-sign \
+   type-limits \
+  ])
 
 if test "x$GCC" = "xyes"; then
-  changequote(,)dnl
-  case " $CFLAGS " in
-  *[\ \	]-Wall[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wall" ;;
-  esac
+  # We're treating -fno-common like a warning: it makes the linker more
+  # strict, because on some systems the linker is *always* this strict
+  TP_ADD_COMPILER_FLAG([WARNING_CFLAGS], [-fno-common])
 
-  case " $CFLAGS " in
-  *[\ \	]-Wchar-subscripts[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wchar-subscripts" ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-Wmissing-declarations[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wmissing-declarations" ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-Wmissing-prototypes[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-Wnested-externs[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wnested-externs" ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-Wpointer-arith[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wpointer-arith" ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-Wcast-align[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wcast-align" ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-Wfloat-equal[\ \	]*) ;;
-  *) if cc_supports_flag -Wfloat-equals; then
-        CFLAGS="$CFLAGS -Wfloat-equal"
-     fi
-     ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-Wdeclaration-after-statement[\ \	]*) ;;
-  *) if cc_supports_flag -Wdeclaration-after-statement; then
-        CFLAGS="$CFLAGS -Wdeclaration-after-statement"
-     fi
-     ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-fno-common[\ \	]*) ;;
-  *) if cc_supports_flag -fno-common; then
-        CFLAGS="$CFLAGS -fno-common"
-     fi
-     ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-fPIC[\ \	]*) ;;
-  *) if test x$dbus_win = xno && cc_supports_flag -fPIC; then
-        PIC_CFLAGS="-fPIC"
-        if ld_supports_flag -z,relro; then
-           PIC_LDFLAGS="-Wl,-z,relro"
-        fi
-     fi
-     ;;
-  esac
-
-  case " $CFLAGS " in
-  *[\ \	]-fPIE[\ \	]*) ;;
-  *) if test x$dbus_win = xno && cc_supports_flag -fPIE; then
-        PIE_CFLAGS="-fPIE"
-        if ld_supports_flag -z,relro; then
-           PIE_LDFLAGS="-pie -Wl,-z,relro"
-        else
-           PIE_LDFLAGS="-pie"
-        fi
-     fi
-     ;;
-  esac
-
-  ### Disabled warnings, and compiler flag overrides
-
-  # Let's just ignore unused for now
-  case " $CFLAGS " in
-  *[\ \	]-Wno-unused[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wno-unused" ;;
-  esac
-
-  # This group is for warnings we currently don't pass.
-  # We would like to, however.  Please fix.
-
-  # http://bugs.freedesktop.org/show_bug.cgi?id=17433
-  case " $CFLAGS " in
-  *[\ \	]-Wno-sign-compare[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -Wno-sign-compare" ;;
-  esac
-  case " $CFLAGS " in
-  *[\ \	]-Wno-pointer-sign[\ \	]*) ;;
-  *) if cc_supports_flag -Wno-pointer-sign; then
-        CFLAGS="$CFLAGS -Wno-pointer-sign"
-     fi
-     ;;
-  esac
-
-  # This one is special - it's not a warning override.
   # http://bugs.freedesktop.org/show_bug.cgi?id=10599
-  case " $CFLAGS " in
-  *[\ \	]-fno-strict-aliasing[\ \	]*) ;;
-  *) CFLAGS="$CFLAGS -fno-strict-aliasing" ;;
-  esac
-  ### End disabled warnings
+  TP_ADD_COMPILER_FLAG([WARNING_CFLAGS], [-fno-strict-aliasing])
 
   if test "x$enable_ansi" = "xyes"; then
-    case " $CFLAGS " in
-    *[\ \	]-ansi[\ \	]*) ;;
-    *) CFLAGS="$CFLAGS -ansi" ;;
-    esac
-
-    case " $CFLAGS " in
-    *[\ \	]-D_POSIX_C_SOURCE*) ;;
-    *) CFLAGS="$CFLAGS -D_POSIX_C_SOURCE=199309L" ;;
-    esac
-
-    case " $CFLAGS " in
-    *[\ \	]-D_BSD_SOURCE[\ \	]*) ;;
-    *) CFLAGS="$CFLAGS -D_BSD_SOURCE" ;;
-    esac
-
-    case " $CFLAGS " in
-    *[\ \	]-pedantic[\ \	]*) ;;
-    *) CFLAGS="$CFLAGS -pedantic" ;;
-    esac
-  fi
-  if test x$enable_gcov = xyes; then
-    case " $CFLAGS " in
-    *[\ \	]-fprofile-arcs[\ \	]*) ;;
-    *) CFLAGS="$CFLAGS -fprofile-arcs" ;;
-    esac
-    case " $CFLAGS " in
-    *[\ \	]-ftest-coverage[\ \	]*) ;;
-    *) CFLAGS="$CFLAGS -ftest-coverage" ;;
-    esac
-
-    ## remove optimization
-    CFLAGS=`echo "$CFLAGS" | sed -e 's/-O[0-9]*//g'`
-  fi
-  changequote([,])dnl
-else
-  if test x$enable_gcov = xyes; then
-    AC_MSG_ERROR([--enable-gcov can only be used with gcc])
+    TP_ADD_COMPILER_FLAG([WARNING_CFLAGS],
+      [-ansi -D_POSIX_C_SOURCE=199309L -D_BSD_SOURCE -pedantic])
   fi
 fi
 
-AC_SUBST(PIC_CFLAGS)
-AC_SUBST(PIC_LDFLAGS)
-AC_SUBST(PIE_CFLAGS)
-AC_SUBST(PIE_LDFLAGS)
+dnl In principle we should put WARNING_CFLAGS in each Makefile.am like
+dnl telepathy-glib does, since CFLAGS is meant to be reserved for the user...
+dnl but prepending to CFLAGS (so the user can override it with later CFLAGS)
+dnl is the next best thing
+CFLAGS="$WARNING_CFLAGS $CFLAGS"
 
-if ld_supports_flag --gc-sections; then
-  SECTION_LDFLAGS="-Wl,--gc-sections $SECTION_LDFLAGS"
-  CFLAGS="-ffunction-sections -fdata-sections $CFLAGS"
-fi
-AC_SUBST(SECTION_FLAGS)
-AC_SUBST(SECTION_LDFLAGS)
-AC_MSG_RESULT($ac_gcsections)
-
-# Add -D_POSIX_PTHREAD_SEMANTICS if on Solaris
-#
 case $host_os in
     solaris*)
-       CFLAGS="$CFLAGS -D_POSIX_PTHREAD_SEMANTICS" ;;
+        # Solaris' C library apparently needs these runes to be threadsafe...
+        CFLAGS="$CFLAGS -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT"
+        # ... this opt-in to get sockaddr_in6 and sockaddr_storage...
+        CFLAGS="$CFLAGS -D__EXTENSIONS__"
+        # ... and this opt-in to get file descriptor passing support
+        CFLAGS="$CFLAGS -D_XOPEN_SOURCE=500"
+        ;;
 esac
 
-changequote(,)dnl
-# compress spaces in flags
-CFLAGS=`echo "$CFLAGS" | sed -e 's/ +/ /g'`
-CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/ +/ /g'`
-CPPFLAGS=`echo "$CPPFLAGS" | sed -e 's/ +/ /g'`
-changequote([,])dnl
-
 ### Doxygen Documentation
 
 AC_PATH_PROG(DOXYGEN, doxygen, no)
@@ -1311,7 +1415,10 @@
 fi
 
 AM_CONDITIONAL(DBUS_DOXYGEN_DOCS_ENABLED, test x$enable_doxygen_docs = xyes)
-AC_MSG_RESULT(yes)
+AC_MSG_RESULT($enable_doxygen_docs)
+
+AC_CHECK_PROGS([XSLTPROC], [xsltproc])
+AM_CONDITIONAL([DBUS_HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"])
 
 ### XML Documentation
 
@@ -1340,7 +1447,15 @@
 fi
 
 AM_CONDITIONAL(DBUS_XML_DOCS_ENABLED, test x$enable_xml_docs = xyes)
-AC_MSG_RESULT(yes)
+AC_MSG_RESULT($enable_xml_docs)
+
+AC_PATH_PROG([MAN2HTML], [man2html])
+AC_ARG_VAR([MAN2HTML], [Path to man2html (optional)])
+AM_CONDITIONAL(DBUS_HAVE_MAN2HTML, test x$MAN2HTML != x)
+
+AM_CONDITIONAL(DBUS_CAN_UPLOAD_DOCS,
+    test x$enable_doxygen_docs = xyes -a x$enable_xml_docs = xyes -a \
+         x$MAN2HTML != x)
 
 #### Have to go $localstatedir->$prefix/var->/usr/local/var
 
@@ -1387,7 +1502,12 @@
 ##### systemd unit files
 AC_ARG_WITH([systemdsystemunitdir],
 AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
-        [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
+    [],
+    [
+    PKG_CHECK_EXISTS([systemd],
+      [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)],
+      [with_systemdsystemunitdir=no])
+    ])
 if test "x$with_systemdsystemunitdir" != xno; then
    AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
 fi
@@ -1488,31 +1608,19 @@
 # Useful in a cross-compilation environment, where the tests are run on the host system.
 AC_ARG_WITH(dbus-test-dir, AS_HELP_STRING([--with-dbus-test-dir=[dirname]],[path where the tests tools are available]),
 			   DBUS_PWD=$withval)
-AC_DEFUN([TEST_PATH], [
-TEST_$1=${DBUS_PWD}/test/$2
-AC_DEFINE_UNQUOTED(TEST_$1, "$TEST_$1",
-                   [Full path to test file test/$2 in builddir])
-AC_SUBST(TEST_$1)
-])
-AC_DEFUN([TEST_PROG], [
-TEST_$1=${DBUS_PWD}/test/$2
-AC_DEFINE_UNQUOTED(TEST_$1, "$TEST_$1$EXEEXT",
-                   [Full path to test file test/$2 in builddir])
-AC_SUBST(TEST_$1)
-])
 
-TEST_PATH(VALID_SERVICE_DIR, data/valid-service-files)
-TEST_PATH(INVALID_SERVICE_DIR, data/invalid-service-files)
-TEST_PATH(VALID_SERVICE_SYSTEM_DIR, data/valid-service-files-system)
-TEST_PATH(INVALID_SERVICE_SYSTEM_DIR, data/invalid-service-files-system)
-TEST_PROG(SERVICE_BINARY, test-service)
-TEST_PROG(SHELL_SERVICE_BINARY, test-shell-service)
-TEST_PROG(EXIT_BINARY, test-exit)
-TEST_PROG(SEGFAULT_BINARY, test-segfault)
-TEST_PROG(SLEEP_FOREVER_BINARY, test-sleep-forever)
-TEST_PROG(PRIVSERVER_BINARY, name-test/test-privserver)
+DBUS_TEST_EXEC="$DBUS_PWD/test"
+DBUS_TEST_DATA="$DBUS_PWD/test/data"
 
-AC_DEFINE_UNQUOTED(TEST_BUS_BINARY, "$DBUS_PWD/bus/dbus-daemon$EXEEXT",
+AC_SUBST([DBUS_TEST_DATA])
+AC_SUBST([DBUS_TEST_EXEC])
+
+AC_DEFINE_UNQUOTED([DBUS_TEST_EXEC], ["$DBUS_TEST_EXEC"],
+                   [Full path to the daemon in the builddir])
+AC_DEFINE_UNQUOTED([DBUS_EXEEXT], ["$EXEEXT"],
+                   [Extension for executables, typically empty or .exe])
+
+AC_DEFINE_UNQUOTED(TEST_BUS_BINARY, ["$DBUS_PWD/bus/dbus-daemon$EXEEXT"],
                    [Full path to the daemon in the builddir])
 AC_SUBST(TEST_BUS_BINARY)
 
@@ -1533,6 +1641,8 @@
    DEFAULT_SOCKET_DIR=/tmp
 fi
 
+DEFAULT_SOCKET_DIR=`echo $DEFAULT_SOCKET_DIR | sed 's/+/%2B/g'`
+
 if ! test -z "$with_test_socket_dir" ; then
    TEST_SOCKET_DIR="$with_test_socket_dir"
 else
@@ -1541,6 +1651,15 @@
 AC_SUBST(TEST_SOCKET_DIR)
 AC_DEFINE_UNQUOTED(DBUS_TEST_SOCKET_DIR, "$TEST_SOCKET_DIR", [Where to put test sockets])
 
+if test "x$dbus_unix" = xyes; then
+  TEST_LISTEN="unix:tmpdir=$TEST_SOCKET_DIR"
+else
+  TEST_LISTEN="tcp:host=localhost"
+fi
+AC_SUBST([TEST_LISTEN])
+AC_DEFINE_UNQUOTED([TEST_LISTEN], ["$TEST_LISTEN"],
+  [Listening address for regression tests])
+
 if ! test -z "$with_session_socket_dir" ; then
    DBUS_SESSION_SOCKET_DIR="$with_session_socket_dir"
 else
@@ -1550,7 +1669,9 @@
 AC_SUBST(DBUS_SESSION_SOCKET_DIR)
 
 if test x$dbus_win = xyes; then
-        DBUS_SESSION_BUS_DEFAULT_ADDRESS="nonce-tcp:"
+        DBUS_SESSION_BUS_DEFAULT_ADDRESS="$with_dbus_session_bus_default_address"
+elif test x$have_launchd = xyes; then
+        DBUS_SESSION_BUS_DEFAULT_ADDRESS="launchd:env=DBUS_LAUNCHD_SESSION_BUS_SOCKET"
 else
         DBUS_SESSION_BUS_DEFAULT_ADDRESS="unix:tmpdir=$DBUS_SESSION_SOCKET_DIR"
 fi
@@ -1568,7 +1689,16 @@
 #endif
 ])
 
-AC_OUTPUT([
+AC_ARG_ENABLE([stats],
+  [AS_HELP_STRING([--enable-stats],
+    [enable bus daemon usage statistics])],
+  [], [enable_stats=no])
+if test "x$enable_stats" = xyes; then
+  AC_DEFINE([DBUS_ENABLE_STATS], [1],
+    [Define to enable bus daemon usage statistics])
+fi
+
+AC_CONFIG_FILES([
 Doxyfile
 dbus/versioninfo.rc
 dbus/dbus-arch-deps.h
@@ -1576,8 +1706,8 @@
 bus/session.conf
 bus/messagebus
 bus/messagebus-config
+bus/org.freedesktop.dbus-session.plist
 bus/rc.messagebus
-bus/dbus-daemon.1
 bus/dbus.service
 bus/dbus.socket
 Makefile
@@ -1587,7 +1717,9 @@
 test/Makefile
 test/name-test/Makefile
 doc/Makefile
+doc/dbus-daemon.1
 dbus-1.pc
+dbus-1-uninstalled.pc
 test/data/valid-config-files/debug-allow-all.conf
 test/data/valid-config-files/debug-allow-all-sha1.conf
 test/data/valid-config-files-system/debug-allow-all-pass.conf
@@ -1606,6 +1738,7 @@
 test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service
 test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service
 ])
+AC_OUTPUT
 
 dnl ==========================================================================
 echo "
@@ -1628,25 +1761,30 @@
 	64-bit int:		  ${DBUS_INT64_TYPE}
 	32-bit int:		  ${DBUS_INT32_TYPE}
 	16-bit int:		  ${DBUS_INT16_TYPE}
-        Doxygen:                  ${DOXYGEN}
-        xmlto:                    ${XMLTO}"
+        Doxygen:                  ${DOXYGEN:-not found}
+        xmlto:                    ${XMLTO:-not found}
+        man2html:                 ${MAN2HTML:-not found}"
 
 echo "
-        Maintainer mode:          ${USE_MAINTAINER_MODE}
-        gcc coverage profiling:   ${enable_gcov}
-        Building unit tests:      ${enable_tests}
+        Rebuilding generated files: ${USE_MAINTAINER_MODE}
+        gcc coverage profiling:   ${enable_compiler_coverage}
+        Building embedded tests:  ${enable_embedded_tests}
+        Building modular tests:   ${enable_modular_tests}
+            - with GLib:          ${with_glib}
         Building verbose mode:    ${enable_verbose_mode}
         Building assertions:      ${enable_asserts}
         Building checks:          ${enable_checks}
+        Building bus stats API:   ${enable_stats}
         Building SELinux support: ${have_selinux}
         Building inotify support: ${have_inotify}
         Building dnotify support: ${have_dnotify}
         Building kqueue support:  ${have_kqueue}
+        Building systemd support: ${have_systemd}
         Building X11 code:        ${enable_x11}
         Building Doxygen docs:    ${enable_doxygen_docs}
         Building XML docs:        ${enable_xml_docs}
         Building cache support:   ${enable_userdb_cache}
-        Gettext libs (empty OK):  ${INTLLIBS}
+        Building launchd support: ${have_launchd}
         Using XML parser:         ${with_xml}
         Init scripts style:       ${with_init_scripts}
         Abstract socket names:    ${ac_cv_have_abstract_sockets}
@@ -1661,14 +1799,18 @@
 	Session bus services dir: ${EXPANDED_DATADIR}/dbus-1/services
         'make check' socket dir:  ${TEST_SOCKET_DIR}
 "
+if test x$have_launchd = xyes; then
+        echo "        launchd agent dir:        ${LAUNCHD_AGENT_DIR}"
+fi
+echo
 
-if test x$enable_tests = xyes; then
+if test x$enable_embedded_tests = xyes; then
         echo "NOTE: building with unit tests increases the size of the installed library and renders it insecure."
 fi
-if test x$enable_tests = xyes -a x$enable_asserts = xno; then
-        echo "NOTE: building with unit tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)"
+if test x$enable_embedded_tests = xyes -a x$enable_asserts = xno; then
+        echo "NOTE: building with embedded tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)"
 fi
-if test x$enable_gcov = xyes; then
+if test x$enable_compiler_coverage = xyes; then
         echo "NOTE: building with coverage profiling is definitely for developers only."
 fi
 if test x$enable_verbose_mode = xyes; then
@@ -1684,3 +1826,16 @@
         echo
 	echo "WARNING: You have chosen to use libxml as your xml parser however this code path is not maintained by the D-Bus developers and if it breaks you get to keep the pieces.  If you have selected this option in err please reconfigure with expat (e.g. --with-xml=expat)."
 fi
+
+if test "x$DBUS_HAVE_INT64" = x0; then
+  AC_MSG_WARN([You have disabled 64-bit integers via --without-64-bit.
+
+  This removes parts of the standard D-Bus API and ABI (the 't' and 'x'
+  typecodes, the dbus_int64_t and dbus_uint64_t types, etc.) and should only be
+  used if your compiler lacks support for 64-bit integers. Please report a bug
+  with details of your platform and compiler.
+
+  This option is likely to be removed in future, unless the D-Bus developers
+  receive reports that it is still needed.
+  ])
+fi
diff --git a/dbus-1-uninstalled.pc.in b/dbus-1-uninstalled.pc.in
new file mode 100644
index 0000000..038c83e
--- /dev/null
+++ b/dbus-1-uninstalled.pc.in
@@ -0,0 +1,17 @@
+abs_top_builddir=@abs_top_builddir@
+abs_top_srcdir=@abs_top_srcdir@
+prefix=
+exec_prefix=
+system_bus_default_address=@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@
+sysconfdir=@EXPANDED_SYSCONFDIR@
+session_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/services
+system_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/system-services
+interfaces_dir=@EXPANDED_DATADIR@/dbus-1/interfaces
+daemondir=@DBUS_DAEMONDIR@
+
+Name: dbus
+Description: Free desktop message bus (uninstalled copy)
+Version: @VERSION@
+Libs: ${abs_top_builddir}/dbus/libdbus-1.la
+Libs.private: @LIBDBUS_LIBS@
+Cflags: -I${abs_top_srcdir} @DBUS_STATIC_BUILD_CPPFLAGS@
diff --git a/dbus-1.pc.in b/dbus-1.pc.in
index e3e63c4..25f8bce 100644
--- a/dbus-1.pc.in
+++ b/dbus-1.pc.in
@@ -12,5 +12,6 @@
 Name: dbus
 Description: Free desktop message bus
 Version: @VERSION@
-Libs: -L${libdir} -ldbus-1 @DBUS_CLIENT_LIBS@
-Cflags: -I${includedir}/dbus-1.0 -I${libdir}/dbus-1.0/include
+Libs: -L${libdir} -ldbus-1
+Libs.private: @LIBDBUS_LIBS@
+Cflags: -I${includedir}/dbus-1.0 -I${libdir}/dbus-1.0/include @DBUS_STATIC_BUILD_CPPFLAGS@
diff --git a/dbus/.gitignore b/dbus/.gitignore
index 115b62e..e495cb3 100644
--- a/dbus/.gitignore
+++ b/dbus/.gitignore
@@ -13,3 +13,4 @@
 dbus-glib-error-enum.h
 *.gcno
 *.gcda
+versioninfo.rc
diff --git a/dbus/Android.mk b/dbus/Android.mk
index 0d38aea..5811292 100644
--- a/dbus/Android.mk
+++ b/dbus/Android.mk
@@ -39,12 +39,15 @@
 	dbus-sha.c \
 	dbus-shell.c \
 	dbus-signature.c \
+	dbus-socket-set.c \
+	dbus-socket-set-poll.c \
 	dbus-spawn.c \
 	dbus-string.c \
 	dbus-string-util.c \
 	dbus-sysdeps.c \
 	dbus-sysdeps-pthread.c \
 	dbus-sysdeps-unix.c \
+	dbus-sysdeps-util.c \
 	dbus-sysdeps-util-unix.c \
 	dbus-timeout.c \
 	dbus-threads.c \
@@ -66,7 +69,6 @@
 LOCAL_CFLAGS+= \
 	-DDBUS_COMPILATION \
 	-DANDROID_MANAGED_SOCKET \
-	-DANDROID_ATOMIC \
 	-DDBUS_MACHINE_UUID_FILE=\"/etc/machine-id\" \
 	-DDBUS_SYSTEM_CONFIG_FILE=\"/system/etc/dbus.conf\" \
 	-DDBUS_SESSION_CONFIG_FILE=\"/system/etc/session.conf\" \
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
index f88c7b7..bb5ccca 100644
--- a/dbus/Makefile.am
+++ b/dbus/Makefile.am
@@ -1,10 +1,19 @@
 
 configdir=$(sysconfdir)/dbus-1
 
-INCLUDES=-I$(top_builddir) -I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) @PIC_CFLAGS@ -DDBUS_COMPILATION	\
-	-DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\"		\
-	-DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\"			\
-	-DDBUS_SESSION_CONFIG_FILE=\""$(configdir)/session.conf"\"
+AM_CPPFLAGS = \
+	-I$(top_builddir) \
+	-I$(top_srcdir) \
+	$(SYSTEMD_CFLAGS) \
+	$(VALGRIND_CFLAGS) \
+	-DDBUS_COMPILATION \
+	-DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" \
+	-DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \
+	-DDBUS_SESSION_CONFIG_FILE=\""$(configdir)/session.conf"\" \
+	$(NULL)
+
+# if assertions are enabled, improve backtraces
+AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
 
 dbusincludedir=$(includedir)/dbus-1.0/dbus
 dbusarchincludedir=$(libdir)/dbus-1.0/include/dbus
@@ -25,7 +34,6 @@
 dbus_res_ldflag = -Wl,$(dbus_res)
 no_undefined = -no-undefined
 export_symbols =
-export_symvols_internal =
 
 libdbus_1_la_DEPENDENCIES = $(dbus_res)
 intllibs =
@@ -37,7 +45,6 @@
 ## don't export symbols that start with "_" (we use this
 ## convention for internal symbols)
 export_symbols = -export-symbols-regex "^[^_].*"
-export_symbols_internal =
 
 intllibs = @LTLIBINTL@
 
@@ -73,6 +80,13 @@
 	dbus-sysdeps-util-win.c			\
 	dbus-spawn-win.c
 else
+
+if DBUS_ENABLE_LAUNCHD
+launchd_source = dbus-server-launchd.h dbus-server-launchd.c
+else
+launchd_source =
+endif
+
 DBUS_LIB_arch_sources = 			\
 	dbus-uuidgen.c				\
 	dbus-uuidgen.h				\
@@ -80,6 +94,7 @@
 	dbus-server-unix.h
 
 DBUS_SHARED_arch_sources = 			\
+	$(launchd_source)			\
 	dbus-file-unix.c 			\
 	dbus-pipe-unix.c 			\
 	dbus-sysdeps-unix.c 			\
@@ -98,6 +113,10 @@
 	dbus-spawn.c
 endif
 
+if HAVE_LINUX_EPOLL
+DBUS_UTIL_arch_sources += dbus-socket-set-epoll.c
+endif
+
 dbusinclude_HEADERS=				\
 	dbus.h					\
 	dbus-address.h				\
@@ -113,11 +132,12 @@
 	dbus-server.h				\
 	dbus-shared.h				\
 	dbus-signature.h			\
+	dbus-syntax.h				\
 	dbus-threads.h				\
 	dbus-types.h
 
 
-dbusarchinclude_HEADERS=			\
+nodist_dbusarchinclude_HEADERS=			\
 	dbus-arch-deps.h
 
 ### source code that goes in the installed client library
@@ -126,8 +146,6 @@
 	dbus-address.c				\
 	dbus-auth.c				\
 	dbus-auth.h				\
-	dbus-auth-script.c			\
-	dbus-auth-script.h			\
 	dbus-bus.c				\
 	dbus-connection.c			\
 	dbus-connection-internal.h		\
@@ -166,6 +184,7 @@
 	dbus-sha.c				\
 	dbus-sha.h				\
 	dbus-signature.c			\
+	dbus-syntax.c				\
 	dbus-timeout.c				\
 	dbus-timeout.h				\
 	dbus-threads-internal.h			\
@@ -178,9 +197,6 @@
 	dbus-watch.c				\
 	dbus-watch.h
 
-##	dbus-md5.c				\
-##	dbus-md5.h				\
-
 ### source code that goes in the installed client library
 ### AND is generic utility functionality used by the
 ### daemon or test programs (all symbols in here should
@@ -208,7 +224,8 @@
 	dbus-string-private.h			\
 	$(DBUS_SHARED_arch_sources)		\
 	dbus-sysdeps.c				\
-	dbus-sysdeps.h
+	dbus-sysdeps.h				\
+	dbus-valgrind-internal.h
 
 ### source code that is generic utility functionality used
 ### by the bus daemon or test apps, but is NOT included
@@ -216,6 +233,8 @@
 ### should be underscore-prefixed but don't really need
 ### to be unless they move to DBUS_SHARED_SOURCES later)
 DBUS_UTIL_SOURCES=				\
+	dbus-auth-script.c			\
+	dbus-auth-script.h			\
 	dbus-auth-util.c			\
 	dbus-credentials-util.c			\
 	dbus-mainloop.c				\
@@ -229,6 +248,9 @@
 	dbus-shell.c				\
 	dbus-shell.h				\
 	$(DBUS_UTIL_arch_sources)		\
+	dbus-socket-set.h			\
+	dbus-socket-set.c			\
+	dbus-socket-set-poll.c			\
 	dbus-spawn.h				\
 	dbus-string-util.c			\
 	dbus-sysdeps-util.c			\
@@ -244,41 +266,42 @@
 	$(DBUS_SHARED_SOURCES)			\
 	$(DBUS_UTIL_SOURCES)
 
-BUILT_SOURCES=$(dbusarchinclude_HEADERS)
+BUILT_SOURCES=$(nodist_dbusarchinclude_HEADERS)
 EXTRA_DIST=dbus-arch-deps.h.in
 
-
 ## this library is the same as libdbus, but exports all the symbols
 ## and is only used for static linking within the dbus package.
 noinst_LTLIBRARIES=libdbus-internal.la
 
-libdbus_1_la_CPPFLAGS= -Ddbus_1_EXPORTS
-libdbus_1_la_LIBADD= $(DBUS_CLIENT_LIBS)
-libdbus_1_la_LDFLAGS= $(export_symbols) -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -no-undefined @R_DYNAMIC_LDFLAG@ @PIC_LDFLAGS@
+libdbus_1_la_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
+	-Ddbus_1_EXPORTS \
+	$(NULL)
+libdbus_1_la_LIBADD= $(LIBDBUS_LIBS)
+libdbus_1_la_LDFLAGS = \
+	$(AM_LDFLAGS) \
+	$(export_symbols) \
+	-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+	-no-undefined \
+	$(NULL)
 
-libdbus_internal_la_CPPFLAGS = -DDBUS_STATIC_BUILD
-libdbus_internal_la_LIBADD=$(DBUS_CLIENT_LIBS)
-libdbus_internal_la_LDFLAGS=$(export_symbols_internal) @R_DYNAMIC_LDFLAG@
+libdbus_internal_la_CPPFLAGS = \
+	$(AM_CPPFLAGS) \
+	-DDBUS_STATIC_BUILD \
+	$(NULL)
+libdbus_internal_la_LIBADD=$(LIBDBUS_LIBS) $(SYSTEMD_LIBS)
 
-## note that TESTS has special meaning (stuff to use in make check)
-## so if adding tests not to be run in make check, don't add them to
-## TESTS
+noinst_PROGRAMS =
+
 if DBUS_BUILD_TESTS
-TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus
-TESTS=dbus-test
-else
-TESTS=
+# We can't actually run this til we've reached test/
+noinst_PROGRAMS += dbus-test
 endif
 
-## we use noinst_PROGRAMS not check_PROGRAMS so that we build
-## even when not doing "make check"
-noinst_PROGRAMS=$(TESTS)
-
 dbus_test_SOURCES=				\
 	dbus-test-main.c
 
-dbus_test_LDADD=libdbus-internal.la $(DBUS_TEST_LIBS)
-dbus_test_LDFLAGS=@R_DYNAMIC_LDFLAG@
+dbus_test_LDADD = libdbus-internal.la
 
 ## mop up the gcov files
 clean-local:
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index 4c9c1b5..d2c37a7 100644
--- a/dbus/dbus-auth.c
+++ b/dbus/dbus-auth.c
@@ -593,7 +593,7 @@
             }
           else
             {
-              _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&error);
+              _DBUS_ASSERT_ERROR_IS_SET (&error);
               _dbus_verbose ("%s: Error loading keyring: %s\n",
                              DBUS_AUTH_NAME (auth), error.message);
               if (send_rejected (auth))
@@ -614,7 +614,7 @@
   auth->cookie_id = _dbus_keyring_get_best_key (auth->keyring, &error);
   if (auth->cookie_id < 0)
     {
-      _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&error);
+      _DBUS_ASSERT_ERROR_IS_SET (&error);
       _dbus_verbose ("%s: Could not get a cookie ID to send to client: %s\n",
                      DBUS_AUTH_NAME (auth), error.message);
       if (send_rejected (auth))
@@ -920,7 +920,7 @@
             }
           else
             {
-              _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&error);
+              _DBUS_ASSERT_ERROR_IS_SET (&error);
 
               _dbus_verbose ("%s: Error loading keyring: %s\n",
                              DBUS_AUTH_NAME (auth), error.message);
@@ -1202,18 +1202,6 @@
         {
           _dbus_verbose ("%s: Received invalid UTF-8 trace data from ANONYMOUS client\n",
                          DBUS_AUTH_NAME (auth));
-
-          {
-            DBusString plaintext;
-            DBusString encoded;
-            _dbus_string_init_const (&plaintext, "D-Bus " DBUS_VERSION_STRING);
-            _dbus_string_init (&encoded);
-            _dbus_string_hex_encode (&plaintext, 0,
-                                     &encoded,
-                                     0);
-              _dbus_verbose ("%s: try '%s'\n",
-                             DBUS_AUTH_NAME (auth), _dbus_string_get_const_data (&encoded));
-          }
           return send_rejected (auth);
         }
       
@@ -2079,7 +2067,7 @@
     case DBUS_AUTH_COMMAND_AGREE_UNIX_FD:
       _dbus_assert(auth->unix_fd_possible);
       auth->unix_fd_negotiated = TRUE;
-      _dbus_verbose("Sucessfully negotiated UNIX FD passing\n");
+      _dbus_verbose("Successfully negotiated UNIX FD passing\n");
       return send_begin (auth);
 
     case DBUS_AUTH_COMMAND_ERROR:
@@ -2806,7 +2794,7 @@
 }
 
 /**
- * Queries whether unix fd passing was sucessfully negotiated.
+ * Queries whether unix fd passing was successfully negotiated.
  *
  * @param auth the auth conversion
  * @returns #TRUE when unix fd passing was negotiated.
diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c
index 92ec20e..fadc3a8 100644
--- a/dbus/dbus-bus.c
+++ b/dbus/dbus-bus.c
@@ -434,13 +434,14 @@
   _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL);
   _dbus_return_val_if_error_is_set (error, NULL);
 
+  connection = NULL;
+
   _DBUS_LOCK (bus);
 
   if (!init_connections_unlocked ())
     {
-      _DBUS_UNLOCK (bus);
       _DBUS_SET_OOM (error);
-      return NULL;
+      goto out;
     }
 
   /* We want to use the activation address even if the
@@ -462,9 +463,7 @@
     {
       connection = bus_connections[type];
       dbus_connection_ref (connection);
-      
-      _DBUS_UNLOCK (bus);
-      return connection;
+      goto out;
     }
 
   address = bus_connection_addresses[address_type];
@@ -472,8 +471,7 @@
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
                       "Unable to determine the address of the message bus (try 'man dbus-launch' and 'man dbus-daemon' for help)");
-      _DBUS_UNLOCK (bus);
-      return NULL;
+      goto out;
     }
 
   if (private)
@@ -483,19 +481,15 @@
   
   if (!connection)
     {
-      _DBUS_ASSERT_ERROR_IS_SET (error);
-      _DBUS_UNLOCK (bus);
-      return NULL;
+      goto out;
     }
 
   if (!dbus_bus_register (connection, error))
     {
-      _DBUS_ASSERT_ERROR_IS_SET (error);
       _dbus_connection_close_possibly_shared (connection);
       dbus_connection_unref (connection);
-
-      _DBUS_UNLOCK (bus);
-      return NULL;
+      connection = NULL;
+      goto out;
     }
 
   if (!private)
@@ -520,10 +514,12 @@
   bd->is_well_known = TRUE;
   _DBUS_UNLOCK (bus_datas);
 
-  
-  _DBUS_UNLOCK (bus);
+out:
+  /* Return a reference to the caller, or NULL with error set. */
+  if (connection == NULL)
+    _DBUS_ASSERT_ERROR_IS_SET (error);
 
-  /* Return a reference to the caller */
+  _DBUS_UNLOCK (bus);
   return connection;
 }
 
@@ -661,6 +657,8 @@
   _dbus_return_val_if_error_is_set (error, FALSE);
 
   retval = FALSE;
+  message = NULL;
+  reply = NULL;
 
   _DBUS_LOCK (bus_datas);
 
@@ -668,18 +666,16 @@
   if (bd == NULL)
     {
       _DBUS_SET_OOM (error);
-      _DBUS_UNLOCK (bus_datas);
-      return FALSE;
+      goto out;
     }
 
   if (bd->unique_name != NULL)
     {
       _dbus_verbose ("Ignoring attempt to register the same DBusConnection %s with the message bus a second time.\n",
                      bd->unique_name);
-      _DBUS_UNLOCK (bus_datas);
-
       /* Success! */
-      return TRUE;
+      retval = TRUE;
+      goto out;
     }
   
   message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
@@ -690,15 +686,11 @@
   if (!message)
     {
       _DBUS_SET_OOM (error);
-
-      _DBUS_UNLOCK (bus_datas);
-      return FALSE;
+      goto out;
     }
   
   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
 
-  dbus_message_unref (message);
-  
   if (reply == NULL)
     goto out;
   else if (dbus_set_error_from_message (error, reply))
@@ -718,14 +710,17 @@
   retval = TRUE;
   
  out:
+  _DBUS_UNLOCK (bus_datas);
+
+  if (message)
+    dbus_message_unref (message);
+
   if (reply)
     dbus_message_unref (reply);
 
   if (!retval)
     _DBUS_ASSERT_ERROR_IS_SET (error);
 
-  _DBUS_UNLOCK (bus_datas);
-  
   return retval;
 }
 
@@ -769,7 +764,7 @@
                           const char     *unique_name)
 {
   BusData *bd;
-  dbus_bool_t success;
+  dbus_bool_t success = FALSE;
 
   _dbus_return_val_if_fail (connection != NULL, FALSE);
   _dbus_return_val_if_fail (unique_name != NULL, FALSE);
@@ -778,13 +773,14 @@
   
   bd = ensure_bus_data (connection);
   if (bd == NULL)
-    return FALSE;
+    goto out;
 
   _dbus_assert (bd->unique_name == NULL);
   
   bd->unique_name = _dbus_strdup (unique_name);
   success = bd->unique_name != NULL;
-  
+
+out:
   _DBUS_UNLOCK (bus_datas);
   
   return success;
@@ -812,7 +808,7 @@
 dbus_bus_get_unique_name (DBusConnection *connection)
 {
   BusData *bd;
-  const char *unique_name;
+  const char *unique_name = NULL;
 
   _dbus_return_val_if_fail (connection != NULL, NULL);
 
@@ -820,12 +816,13 @@
   
   bd = ensure_bus_data (connection);
   if (bd == NULL)
-    return NULL;
+    goto out;
 
   unique_name = bd->unique_name;
 
+out:
   _DBUS_UNLOCK (bus_datas);
-  
+
   return unique_name;
 }
 
@@ -1432,11 +1429,17 @@
  * If you pass #NULL for the error, this function will not
  * block; the match thus won't be added until you flush the
  * connection, and if there's an error adding the match
- * (only possible error is lack of resources in the bus),
- * you won't find out about it.
+ * you won't find out about it. This is generally acceptable, since the
+ * possible errors (including a lack of resources in the bus, the connection
+ * having exceeded its quota of active match rules, or the match rule being
+ * unparseable) are generally unrecoverable.
  *
  * If you pass non-#NULL for the error this function will
- * block until it gets a reply.
+ * block until it gets a reply. This may be useful when using match rule keys
+ * introduced in recent versions of D-Bus, like 'arg0namespace', to allow the
+ * application to fall back to less efficient match rules supported by older
+ * versions of the daemon if the running version is not new enough; or when
+ * using user-supplied rules rather than rules hard-coded at compile time.
  *
  * Normal API conventions would have the function return
  * a boolean value indicating whether the error was set,
diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h
index cdf3f59..3d37f18 100644
--- a/dbus/dbus-connection-internal.h
+++ b/dbus/dbus-connection-internal.h
@@ -48,13 +48,11 @@
 void              _dbus_connection_unlock                      (DBusConnection     *connection);
 DBusConnection *  _dbus_connection_ref_unlocked                (DBusConnection     *connection);
 void              _dbus_connection_unref_unlocked              (DBusConnection     *connection);
-dbus_bool_t       _dbus_connection_queue_received_message      (DBusConnection     *connection,
-                                                                DBusMessage        *message);
 void              _dbus_connection_queue_received_message_link (DBusConnection     *connection,
                                                                 DBusList           *link);
 dbus_bool_t       _dbus_connection_has_messages_to_send_unlocked (DBusConnection     *connection);
 DBusMessage*      _dbus_connection_get_message_to_send         (DBusConnection     *connection);
-void              _dbus_connection_message_sent                (DBusConnection     *connection,
+void              _dbus_connection_message_sent_unlocked       (DBusConnection     *connection,
                                                                 DBusMessage        *message);
 dbus_bool_t       _dbus_connection_add_watch_unlocked          (DBusConnection     *connection,
                                                                 DBusWatch          *watch);
@@ -103,6 +101,23 @@
                                                                    DBusCondVar **dispatch_cond_loc,
                                                                    DBusCondVar **io_path_cond_loc);
 
+/* if DBUS_ENABLE_STATS */
+void _dbus_connection_get_stats (DBusConnection *connection,
+                                 dbus_uint32_t  *in_messages,
+                                 dbus_uint32_t  *in_bytes,
+                                 dbus_uint32_t  *in_fds,
+                                 dbus_uint32_t  *in_peak_bytes,
+                                 dbus_uint32_t  *in_peak_fds,
+                                 dbus_uint32_t  *out_messages,
+                                 dbus_uint32_t  *out_bytes,
+                                 dbus_uint32_t  *out_fds,
+                                 dbus_uint32_t  *out_peak_bytes,
+                                 dbus_uint32_t  *out_peak_fds);
+
+
+/* if DBUS_BUILD_TESTS */
+const char* _dbus_connection_get_address (DBusConnection *connection);
+
 /* This _dbus_bus_* stuff doesn't really belong here, but dbus-bus-internal.h seems
  * silly for one function
  */
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index b65d5dd..fb52955 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -38,6 +38,7 @@
 #include "dbus-protocol.h"
 #include "dbus-dataslot.h"
 #include "dbus-string.h"
+#include "dbus-signature.h"
 #include "dbus-pending-call.h"
 #include "dbus-object-tree.h"
 #include "dbus-threads-internal.h"
@@ -65,22 +66,18 @@
 
 #define CONNECTION_LOCK(connection)   do {                                      \
     if (TRACE_LOCKS) { _dbus_verbose ("LOCK\n"); }   \
-    _dbus_mutex_lock ((connection)->mutex);                                      \
+    _dbus_rmutex_lock ((connection)->mutex);                                    \
     TOOK_LOCK_CHECK (connection);                                               \
   } while (0)
 
-#define CONNECTION_UNLOCK(connection) do {                                              \
-    if (TRACE_LOCKS) { _dbus_verbose ("UNLOCK\n");  }        \
-    RELEASING_LOCK_CHECK (connection);                                                  \
-    _dbus_mutex_unlock ((connection)->mutex);                                            \
-  } while (0)
+#define CONNECTION_UNLOCK(connection) _dbus_connection_unlock (connection)
 
 #define SLOTS_LOCK(connection) do {                     \
-    _dbus_mutex_lock ((connection)->slot_mutex);        \
+    _dbus_rmutex_lock ((connection)->slot_mutex);       \
   } while (0)
 
 #define SLOTS_UNLOCK(connection) do {                   \
-    _dbus_mutex_unlock ((connection)->slot_mutex);      \
+    _dbus_rmutex_unlock ((connection)->slot_mutex);     \
   } while (0)
 
 #define DISPATCH_STATUS_NAME(s)                                            \
@@ -206,6 +203,27 @@
  * @{
  */
 
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+static void
+_dbus_connection_trace_ref (DBusConnection *connection,
+    int old_refcount,
+    int new_refcount,
+    const char *why)
+{
+  static int enabled = -1;
+
+  _dbus_trace_ref ("DBusConnection", connection, old_refcount, new_refcount,
+      why, "DBUS_CONNECTION_TRACE", &enabled);
+}
+#else
+#define _dbus_connection_trace_ref(c,o,n,w) \
+  do \
+  {\
+    (void) (o); \
+    (void) (n); \
+  } while (0)
+#endif
+
 /**
  * Internal struct representing a message filter function 
  */
@@ -233,7 +251,7 @@
   DBusList *counter_link;     /**< Preallocated link in the resource counter */
 };
 
-#ifdef HAVE_DECL_MSG_NOSIGNAL
+#if HAVE_DECL_MSG_NOSIGNAL
 static dbus_bool_t _dbus_modify_sigpipe = FALSE;
 #else
 static dbus_bool_t _dbus_modify_sigpipe = TRUE;
@@ -246,15 +264,16 @@
 {
   DBusAtomic refcount; /**< Reference count. */
 
-  DBusMutex *mutex; /**< Lock on the entire DBusConnection */
+  DBusRMutex *mutex; /**< Lock on the entire DBusConnection */
 
-  DBusMutex *dispatch_mutex;     /**< Protects dispatch_acquired */
+  DBusCMutex *dispatch_mutex;     /**< Protects dispatch_acquired */
   DBusCondVar *dispatch_cond;    /**< Notify when dispatch_acquired is available */
-  DBusMutex *io_path_mutex;      /**< Protects io_path_acquired */
+  DBusCMutex *io_path_mutex;      /**< Protects io_path_acquired */
   DBusCondVar *io_path_cond;     /**< Notify when io_path_acquired is available */
   
   DBusList *outgoing_messages; /**< Queue of messages we need to send, send the end of the list first. */
   DBusList *incoming_messages; /**< Queue of messages we have received, end of the list received most recently. */
+  DBusList *expired_messages;  /**< Messages that will be released when we next unlock. */
 
   DBusMessage *message_borrowed; /**< Filled in if the first incoming message has been borrowed;
                                   *   dispatch_acquired will be set by the borrower
@@ -271,7 +290,7 @@
   
   DBusList *filter_list;        /**< List of filters. */
 
-  DBusMutex *slot_mutex;        /**< Lock on slot_list so overall connection lock need not be taken */
+  DBusRMutex *slot_mutex;        /**< Lock on slot_list so overall connection lock need not be taken */
   DBusDataSlotList slot_list;   /**< Data stored by allocated integer ID */
 
   DBusHashTable *pending_replies;  /**< Hash of message serials to #DBusPendingCall. */  
@@ -289,9 +308,6 @@
 
   DBusDispatchStatus last_dispatch_status; /**< The last dispatch status we reported to the application. */
 
-  DBusList *link_cache; /**< A cache of linked list links to prevent contention
-                         *   for the global linked list mempool lock
-                         */
   DBusObjectTree *objects; /**< Object path handlers registered with this connection */
 
   char *server_guid; /**< GUID of server if we are in shared_connections, #NULL if server GUID is unknown or connection is private */
@@ -341,8 +357,14 @@
 static DBusMessageFilter *
 _dbus_message_filter_ref (DBusMessageFilter *filter)
 {
-  _dbus_assert (filter->refcount.value > 0);
+#ifdef DBUS_DISABLE_ASSERT
   _dbus_atomic_inc (&filter->refcount);
+#else
+  dbus_int32_t old_value;
+
+  old_value = _dbus_atomic_inc (&filter->refcount);
+  _dbus_assert (old_value > 0);
+#endif
 
   return filter;
 }
@@ -350,9 +372,12 @@
 static void
 _dbus_message_filter_unref (DBusMessageFilter *filter)
 {
-  _dbus_assert (filter->refcount.value > 0);
+  dbus_int32_t old_value;
 
-  if (_dbus_atomic_dec (&filter->refcount) == 1)
+  old_value = _dbus_atomic_dec (&filter->refcount);
+  _dbus_assert (old_value > 0);
+
+  if (old_value == 1)
     {
       if (filter->free_user_data_function)
         (* filter->free_user_data_function) (filter->user_data);
@@ -380,7 +405,31 @@
 void
 _dbus_connection_unlock (DBusConnection *connection)
 {
-  CONNECTION_UNLOCK (connection);
+  DBusList *expired_messages;
+  DBusList *iter;
+
+  if (TRACE_LOCKS)
+    {
+      _dbus_verbose ("UNLOCK\n");
+    }
+
+  /* If we had messages that expired (fell off the incoming or outgoing
+   * queues) while we were locked, actually release them now */
+  expired_messages = connection->expired_messages;
+  connection->expired_messages = NULL;
+
+  RELEASING_LOCK_CHECK (connection);
+  _dbus_rmutex_unlock (connection->mutex);
+
+  for (iter = _dbus_list_pop_first_link (&expired_messages);
+      iter != NULL;
+      iter = _dbus_list_pop_first_link (&expired_messages))
+    {
+      DBusMessage *message = iter->data;
+
+      dbus_message_unref (message);
+      _dbus_list_free_link (iter);
+    }
 }
 
 /**
@@ -398,32 +447,6 @@
 }
 
 #ifdef DBUS_BUILD_TESTS
-/* For now this function isn't used */
-/**
- * Adds a message to the incoming message queue, returning #FALSE
- * if there's insufficient memory to queue the message.
- * Does not take over refcount of the message.
- *
- * @param connection the connection.
- * @param message the message to queue.
- * @returns #TRUE on success.
- */
-dbus_bool_t
-_dbus_connection_queue_received_message (DBusConnection *connection,
-                                         DBusMessage    *message)
-{
-  DBusList *link;
-
-  link = _dbus_list_alloc_link (message);
-  if (link == NULL)
-    return FALSE;
-
-  dbus_message_ref (message);
-  _dbus_connection_queue_received_message_link (connection, link);
-
-  return TRUE;
-}
-
 /**
  * Gets the locks so we can examine them
  *
@@ -444,9 +467,9 @@
                                  DBusCondVar   **dispatch_cond_loc,
                                  DBusCondVar   **io_path_cond_loc)
 {
-  *mutex_loc = connection->mutex;
-  *dispatch_mutex_loc = connection->dispatch_mutex;
-  *io_path_mutex_loc = connection->io_path_mutex; 
+  *mutex_loc = (DBusMutex *) connection->mutex;
+  *dispatch_mutex_loc = (DBusMutex *) connection->dispatch_mutex;
+  *io_path_mutex_loc = (DBusMutex *) connection->io_path_mutex;
   *dispatch_cond_loc = connection->dispatch_cond;
   *io_path_cond_loc = connection->io_path_cond;
 }
@@ -511,7 +534,11 @@
                  dbus_message_get_signature (message),
                  dbus_message_get_reply_serial (message),
                  connection,
-                 connection->n_incoming);}
+                 connection->n_incoming);
+
+  _dbus_message_trace_ref (message, -1, -1,
+      "_dbus_conection_queue_received_message_link");
+}
 
 /**
  * Adds a link + message to the incoming message queue.
@@ -532,7 +559,10 @@
   connection->n_incoming += 1;
 
   _dbus_connection_wakeup_mainloop (connection);
-  
+
+  _dbus_message_trace_ref (link->data, -1, -1,
+      "_dbus_connection_queue_synthesized_message_link");
+
   _dbus_verbose ("Synthesized message %p added to incoming queue %p, %d incoming\n",
                  link->data, connection, connection->n_incoming);
 }
@@ -599,8 +629,8 @@
  * @param message the message that was sent.
  */
 void
-_dbus_connection_message_sent (DBusConnection *connection,
-                               DBusMessage    *message)
+_dbus_connection_message_sent_unlocked (DBusConnection *connection,
+                                        DBusMessage    *message)
 {
   DBusList *link;
 
@@ -615,11 +645,10 @@
   _dbus_assert (link != NULL);
   _dbus_assert (link->data == message);
 
-  /* Save this link in the link cache */
   _dbus_list_unlink (&connection->outgoing_messages,
                      link);
-  _dbus_list_prepend_link (&connection->link_cache, link);
-  
+  _dbus_list_prepend_link (&connection->expired_messages, link);
+
   connection->n_outgoing -= 1;
 
   _dbus_verbose ("Message %p (%s %s %s %s '%s') removed from outgoing queue %p, %d left to send\n",
@@ -637,12 +666,11 @@
                  dbus_message_get_signature (message),
                  connection, connection->n_outgoing);
 
-  /* Save this link in the link cache also */
-  _dbus_message_remove_counter (message, connection->outgoing_counter,
-                                &link);
-  _dbus_list_prepend_link (&connection->link_cache, link);
-  
-  dbus_message_unref (message);
+  /* It's OK that in principle we call the notify function, because for the
+   * outgoing limit, there isn't one */
+  _dbus_message_remove_counter (message, connection->outgoing_counter);
+
+  /* The message will actually be unreffed when we unlock */
 }
 
 /** Function to be called in protected_change_watch() with refcount held */
@@ -1051,7 +1079,7 @@
   CONNECTION_UNLOCK (connection);
   
   _dbus_verbose ("locking io_path_mutex\n");
-  _dbus_mutex_lock (connection->io_path_mutex);
+  _dbus_cmutex_lock (connection->io_path_mutex);
 
   _dbus_verbose ("start connection->io_path_acquired = %d timeout = %d\n",
                  connection->io_path_acquired, timeout_milliseconds);
@@ -1100,7 +1128,7 @@
                  connection->io_path_acquired, we_acquired);
 
   _dbus_verbose ("unlocking io_path_mutex\n");
-  _dbus_mutex_unlock (connection->io_path_mutex);
+  _dbus_cmutex_unlock (connection->io_path_mutex);
 
   CONNECTION_LOCK (connection);
   
@@ -1124,7 +1152,7 @@
   HAVE_LOCK_CHECK (connection);
   
   _dbus_verbose ("locking io_path_mutex\n");
-  _dbus_mutex_lock (connection->io_path_mutex);
+  _dbus_cmutex_lock (connection->io_path_mutex);
   
   _dbus_assert (connection->io_path_acquired);
 
@@ -1135,7 +1163,7 @@
   _dbus_condvar_wake_one (connection->io_path_cond);
 
   _dbus_verbose ("unlocking io_path_mutex\n");
-  _dbus_mutex_unlock (connection->io_path_mutex);
+  _dbus_cmutex_unlock (connection->io_path_mutex);
 }
 
 /**
@@ -1264,15 +1292,15 @@
   if (connection == NULL)
     goto error;
 
-  _dbus_mutex_new_at_location (&connection->mutex);
+  _dbus_rmutex_new_at_location (&connection->mutex);
   if (connection->mutex == NULL)
     goto error;
 
-  _dbus_mutex_new_at_location (&connection->io_path_mutex);
+  _dbus_cmutex_new_at_location (&connection->io_path_mutex);
   if (connection->io_path_mutex == NULL)
     goto error;
 
-  _dbus_mutex_new_at_location (&connection->dispatch_mutex);
+  _dbus_cmutex_new_at_location (&connection->dispatch_mutex);
   if (connection->dispatch_mutex == NULL)
     goto error;
   
@@ -1284,7 +1312,7 @@
   if (connection->io_path_cond == NULL)
     goto error;
 
-  _dbus_mutex_new_at_location (&connection->slot_mutex);
+  _dbus_rmutex_new_at_location (&connection->slot_mutex);
   if (connection->slot_mutex == NULL)
     goto error;
 
@@ -1309,8 +1337,9 @@
   
   if (_dbus_modify_sigpipe)
     _dbus_disable_sigpipe ();
-  
-  connection->refcount.value = 1;
+
+  /* initialized to 0: use atomic op to avoid mixing atomic and non-atomic */
+  _dbus_atomic_inc (&connection->refcount);
   connection->transport = transport;
   connection->watches = watch_list;
   connection->timeouts = timeout_list;
@@ -1347,7 +1376,8 @@
   _dbus_transport_ref (transport);
 
   CONNECTION_UNLOCK (connection);
-  
+
+  _dbus_connection_trace_ref (connection, 0, 1, "new_for_transport");
   return connection;
   
  error:
@@ -1361,10 +1391,10 @@
     {
       _dbus_condvar_free_at_location (&connection->io_path_cond);
       _dbus_condvar_free_at_location (&connection->dispatch_cond);
-      _dbus_mutex_free_at_location (&connection->mutex);
-      _dbus_mutex_free_at_location (&connection->io_path_mutex);
-      _dbus_mutex_free_at_location (&connection->dispatch_mutex);
-      _dbus_mutex_free_at_location (&connection->slot_mutex);
+      _dbus_rmutex_free_at_location (&connection->mutex);
+      _dbus_cmutex_free_at_location (&connection->io_path_mutex);
+      _dbus_cmutex_free_at_location (&connection->dispatch_mutex);
+      _dbus_rmutex_free_at_location (&connection->slot_mutex);
       dbus_free (connection);
     }
   if (pending_replies)
@@ -1394,13 +1424,17 @@
  */
 DBusConnection *
 _dbus_connection_ref_unlocked (DBusConnection *connection)
-{  
+{
+  dbus_int32_t old_refcount;
+
   _dbus_assert (connection != NULL);
   _dbus_assert (connection->generation == _dbus_current_generation);
 
   HAVE_LOCK_CHECK (connection);
 
-  _dbus_atomic_inc (&connection->refcount);
+  old_refcount = _dbus_atomic_inc (&connection->refcount);
+  _dbus_connection_trace_ref (connection, old_refcount, old_refcount + 1,
+      "ref_unlocked");
 
   return connection;
 }
@@ -1414,15 +1448,18 @@
 void
 _dbus_connection_unref_unlocked (DBusConnection *connection)
 {
-  dbus_bool_t last_unref;
+  dbus_int32_t old_refcount;
 
   HAVE_LOCK_CHECK (connection);
-  
+
   _dbus_assert (connection != NULL);
 
-  last_unref = (_dbus_atomic_dec (&connection->refcount) == 1);
+  old_refcount = _dbus_atomic_dec (&connection->refcount);
 
-  if (last_unref)
+  _dbus_connection_trace_ref (connection, old_refcount, old_refcount - 1,
+      "unref_unlocked");
+
+  if (old_refcount == 1)
     _dbus_connection_last_unref (connection);
 }
 
@@ -1859,7 +1896,7 @@
       if (connection)
         break;
 
-      _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&tmp_error);
+      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
       
       if (i == 0)
         dbus_move_error (&tmp_error, &first_error);
@@ -1868,11 +1905,11 @@
     }
   
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&tmp_error);
+  _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
   
   if (connection == NULL)
     {
-      _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&first_error);
+      _DBUS_ASSERT_ERROR_IS_SET (&first_error);
       dbus_move_error (&first_error, error);
     }
   else
@@ -1913,31 +1950,13 @@
   if (preallocated == NULL)
     return NULL;
 
-  if (connection->link_cache != NULL)
-    {
-      preallocated->queue_link =
-        _dbus_list_pop_first_link (&connection->link_cache);
-      preallocated->queue_link->data = NULL;
-    }
-  else
-    {
-      preallocated->queue_link = _dbus_list_alloc_link (NULL);
-      if (preallocated->queue_link == NULL)
-        goto failed_0;
-    }
-  
-  if (connection->link_cache != NULL)
-    {
-      preallocated->counter_link =
-        _dbus_list_pop_first_link (&connection->link_cache);
-      preallocated->counter_link->data = connection->outgoing_counter;
-    }
-  else
-    {
-      preallocated->counter_link = _dbus_list_alloc_link (connection->outgoing_counter);
-      if (preallocated->counter_link == NULL)
-        goto failed_1;
-    }
+  preallocated->queue_link = _dbus_list_alloc_link (NULL);
+  if (preallocated->queue_link == NULL)
+    goto failed_0;
+
+  preallocated->counter_link = _dbus_list_alloc_link (connection->outgoing_counter);
+  if (preallocated->counter_link == NULL)
+    goto failed_1;
 
   _dbus_counter_ref (preallocated->counter_link->data);
 
@@ -1961,12 +1980,13 @@
                                                        dbus_uint32_t        *client_serial)
 {
   dbus_uint32_t serial;
-  const char *sig;
 
   preallocated->queue_link->data = message;
   _dbus_list_prepend_link (&connection->outgoing_messages,
                            preallocated->queue_link);
 
+  /* It's OK that we'll never call the notify function, because for the
+   * outgoing limit, there isn't one */
   _dbus_message_add_counter_link (message,
                                   preallocated->counter_link);
 
@@ -1977,8 +1997,6 @@
   
   connection->n_outgoing += 1;
 
-  sig = dbus_message_get_signature (message);
-  
   _dbus_verbose ("Message %p (%s %s %s %s '%s') for %s added to outgoing queue %p, %d pending to send\n",
                  message,
                  dbus_message_type_to_string (dbus_message_get_type (message)),
@@ -1991,7 +2009,7 @@
                  dbus_message_get_member (message) ?
                  dbus_message_get_member (message) :
                  "no member",
-                 sig,
+                 dbus_message_get_signature (message),
                  dbus_message_get_destination (message) ?
                  dbus_message_get_destination (message) :
                  "null",
@@ -2110,23 +2128,15 @@
 void
 _dbus_connection_close_if_only_one_ref (DBusConnection *connection)
 {
-  dbus_int32_t tmp_refcount;
+  dbus_int32_t refcount;
 
   CONNECTION_LOCK (connection);
 
-  /* We increment and then decrement the refcount, because there is no
-   * _dbus_atomic_get (mirroring the fact that there's no InterlockedGet
-   * on Windows). */
-  _dbus_atomic_inc (&connection->refcount);
-  tmp_refcount = _dbus_atomic_dec (&connection->refcount);
+  refcount = _dbus_atomic_get (&connection->refcount);
+  /* The caller should have at least one ref */
+  _dbus_assert (refcount >= 1);
 
-  /* The caller should have one ref, and this function temporarily took
-   * one more, which is reflected in this count even though we already
-   * released it (relying on the caller's ref) due to _dbus_atomic_dec
-   * semantics */
-  _dbus_assert (tmp_refcount >= 2);
-
-  if (tmp_refcount == 2)
+  if (refcount == 1)
     _dbus_connection_close_possibly_shared_and_unlock (connection);
   else
     CONNECTION_UNLOCK (connection);
@@ -2378,10 +2388,10 @@
    * below
    */
   timeout = _dbus_pending_call_get_timeout_unlocked (pending);
+  _dbus_get_monotonic_time (&start_tv_sec, &start_tv_usec);
   if (timeout)
     {
       timeout_milliseconds = dbus_timeout_get_interval (timeout);
-      _dbus_get_current_time (&start_tv_sec, &start_tv_usec);
 
       _dbus_verbose ("dbus_connection_send_with_reply_and_block(): will block %d milliseconds for reply serial %u from %ld sec %ld usec\n",
                      timeout_milliseconds,
@@ -2435,7 +2445,7 @@
         return;
     }
   
-  _dbus_get_current_time (&tv_sec, &tv_usec);
+  _dbus_get_monotonic_time (&tv_sec, &tv_usec);
   elapsed_milliseconds = (tv_sec - start_tv_sec) * 1000 +
 	  (tv_usec - start_tv_usec) / 1000;
   
@@ -2626,10 +2636,13 @@
 DBusConnection *
 dbus_connection_ref (DBusConnection *connection)
 {
+  dbus_int32_t old_refcount;
+
   _dbus_return_val_if_fail (connection != NULL, NULL);
   _dbus_return_val_if_fail (connection->generation == _dbus_current_generation, NULL);
-
-  _dbus_atomic_inc (&connection->refcount);
+  old_refcount = _dbus_atomic_inc (&connection->refcount);
+  _dbus_connection_trace_ref (connection, old_refcount, old_refcount + 1,
+      "ref");
 
   return connection;
 }
@@ -2641,9 +2654,7 @@
   DBusMessage *message = element;
   DBusConnection *connection = data;
 
-  _dbus_message_remove_counter (message,
-                                connection->outgoing_counter,
-                                NULL);
+  _dbus_message_remove_counter (message, connection->outgoing_counter);
   dbus_message_unref (message);
 }
 
@@ -2657,9 +2668,9 @@
   DBusList *link;
 
   _dbus_verbose ("Finalizing connection %p\n", connection);
-  
-  _dbus_assert (connection->refcount.value == 0);
-  
+
+  _dbus_assert (_dbus_atomic_get (&connection->refcount) == 0);
+
   /* You have to disconnect the connection before unref:ing it. Otherwise
    * you won't get the disconnected message.
    */
@@ -2725,17 +2736,15 @@
       _dbus_list_free_link (connection->disconnect_message_link);
     }
 
-  _dbus_list_clear (&connection->link_cache);
-  
   _dbus_condvar_free_at_location (&connection->dispatch_cond);
   _dbus_condvar_free_at_location (&connection->io_path_cond);
 
-  _dbus_mutex_free_at_location (&connection->io_path_mutex);
-  _dbus_mutex_free_at_location (&connection->dispatch_mutex);
+  _dbus_cmutex_free_at_location (&connection->io_path_mutex);
+  _dbus_cmutex_free_at_location (&connection->dispatch_mutex);
 
-  _dbus_mutex_free_at_location (&connection->slot_mutex);
+  _dbus_rmutex_free_at_location (&connection->slot_mutex);
 
-  _dbus_mutex_free_at_location (&connection->mutex);
+  _dbus_rmutex_free_at_location (&connection->mutex);
   
   dbus_free (connection);
 }
@@ -2762,14 +2771,17 @@
 void
 dbus_connection_unref (DBusConnection *connection)
 {
-  dbus_bool_t last_unref;
+  dbus_int32_t old_refcount;
 
   _dbus_return_if_fail (connection != NULL);
   _dbus_return_if_fail (connection->generation == _dbus_current_generation);
 
-  last_unref = (_dbus_atomic_dec (&connection->refcount) == 1);
+  old_refcount = _dbus_atomic_dec (&connection->refcount);
 
-  if (last_unref)
+  _dbus_connection_trace_ref (connection, old_refcount, old_refcount - 1,
+      "unref");
+
+  if (old_refcount == 1)
     {
 #ifndef DBUS_DISABLE_CHECKS
       if (_dbus_transport_get_is_connected (connection->transport))
@@ -3038,7 +3050,7 @@
  * This function can be used to do runtime checking for types that
  * might be unknown to the specific D-Bus client implementation
  * version, i.e. it will return FALSE for all types this
- * implementation does not know.
+ * implementation does not know, including invalid or reserved types.
  *
  * @param connection the connection
  * @param type the type to check
@@ -3050,7 +3062,7 @@
 {
   _dbus_return_val_if_fail (connection != NULL, FALSE);
 
-  if (!_dbus_type_is_valid(type))
+  if (!dbus_type_is_valid (type))
     return FALSE;
 
   if (type != DBUS_TYPE_UNIX_FD)
@@ -3278,6 +3290,7 @@
   DBusPendingCall *pending = data;
 
   connection = _dbus_pending_call_get_connection_and_lock (pending);
+  _dbus_connection_ref_unlocked (connection);
 
   _dbus_pending_call_queue_timeout_error_unlocked (pending, 
                                                    connection);
@@ -3290,6 +3303,7 @@
 
   /* Unlocks, and calls out to user code */
   _dbus_connection_update_dispatch_status_and_unlock (connection, status);
+  dbus_connection_unref (connection);
   
   return TRUE;
 }
@@ -3316,8 +3330,9 @@
  *
  * If -1 is passed for the timeout, a sane default timeout is used. -1
  * is typically the best value for the timeout for this reason, unless
- * you want a very short or very long timeout.  If INT_MAX is passed for
- * the timeout, no timeout will be set and the call will block forever.
+ * you want a very short or very long timeout.  If #DBUS_TIMEOUT_INFINITE is
+ * passed for the timeout, no timeout will be set and the call will block
+ * forever.
  *
  * @warning if the connection is disconnected or you try to send Unix
  * file descriptors on a connection that does not support them, the
@@ -3329,7 +3344,9 @@
  * object, or #NULL if connection is disconnected or when you try to
  * send Unix file descriptors on a connection that does not support
  * them.
- * @param timeout_milliseconds timeout in milliseconds, -1 for default or INT_MAX for no timeout
+ * @param timeout_milliseconds timeout in milliseconds, -1 (or
+ *  #DBUS_TIMEOUT_USE_DEFAULT) for default or #DBUS_TIMEOUT_INFINITE for no
+ *  timeout
  * @returns #FALSE if no memory, #TRUE otherwise.
  *
  */
@@ -3462,7 +3479,9 @@
  *
  * @param connection the connection
  * @param message the message to send
- * @param timeout_milliseconds timeout in milliseconds, -1 for default or INT_MAX for no timeout.
+ * @param timeout_milliseconds timeout in milliseconds, -1 (or
+ *  #DBUS_TIMEOUT_USE_DEFAULT) for default or #DBUS_TIMEOUT_INFINITE for no
+ *  timeout
  * @param error return location for error message
  * @returns the message that is the reply or #NULL with an error code if the
  * function fails.
@@ -3710,46 +3729,6 @@
    return _dbus_connection_read_write_dispatch(connection, timeout_milliseconds, TRUE);
 }
 
-
-/**
- * This function is intended for use with applications that want to 
- * dispatch all the events in the incoming/outgoing queue before returning. 
- * The function just calls dbus_connection_read_write_dispatch till
- * the incoming queue is empty.
- * 
- * @param connection the connection
- * @param timeout_milliseconds max time to block or -1 for infinite
- * @returns #TRUE if the disconnect message has not been processed
- */
-dbus_bool_t
-dbus_connection_read_write_dispatch_greedy (DBusConnection *connection,
-                                            int   timeout_milliseconds)
-{
-  dbus_bool_t ret, progress_possible;
-  int pre_incoming, pre_outgoing;
-  do
-    {
-      pre_incoming = connection->n_incoming;
-      pre_outgoing = connection->n_outgoing;
-      ret = dbus_connection_read_write_dispatch(connection, timeout_milliseconds);
-      /* No need to take a lock here. If another 'reader' thread has read the packet,
-       * dbus_connection_read_write_dispatch will just return. If a writer
-       * writes a packet between the call and the check, it will get processed 
-       * in the next call to the function.
-       */
-      if ((pre_incoming != connection->n_incoming ||
-           pre_outgoing != connection->n_outgoing) &&
-          (connection->n_incoming > 0 ||
-           connection->n_outgoing > 0)) {
-        progress_possible = TRUE;
-      } else {
-        progress_possible = FALSE;
-      }
-    } while (ret == TRUE && progress_possible);
-  return ret;
-}
-
-
 /** 
  * This function is intended for use with applications that don't want to
  * write a main loop and deal with #DBusWatch and #DBusTimeout. See also
@@ -3858,6 +3837,8 @@
 
   CONNECTION_UNLOCK (connection);
 
+  _dbus_message_trace_ref (message, -1, -1, "dbus_connection_borrow_message");
+
   /* We don't update dispatch status until it's returned or stolen */
   
   return message;
@@ -3892,6 +3873,8 @@
 
   status = _dbus_connection_get_dispatch_status_unlocked (connection);
   _dbus_connection_update_dispatch_status_and_unlock (connection, status);
+
+  _dbus_message_trace_ref (message, -1, -1, "dbus_connection_return_message");
 }
 
 /**
@@ -3921,7 +3904,8 @@
 
   pop_message = _dbus_list_pop_first (&connection->incoming_messages);
   _dbus_assert (message == pop_message);
-  
+  (void) pop_message; /* unused unless asserting */
+
   connection->n_incoming -= 1;
  
   _dbus_verbose ("Incoming message %p stolen from queue, %d incoming\n",
@@ -3933,6 +3917,8 @@
 
   status = _dbus_connection_get_dispatch_status_unlocked (connection);
   _dbus_connection_update_dispatch_status_and_unlock (connection, status);
+  _dbus_message_trace_ref (message, -1, -1,
+      "dbus_connection_steal_borrowed_message");
 }
 
 /* See dbus_connection_pop_message, but requires the caller to own
@@ -3967,6 +3953,9 @@
                      dbus_message_get_signature (link->data),
                      connection, connection->n_incoming);
 
+      _dbus_message_trace_ref (link->data, -1, -1,
+          "_dbus_connection_pop_message_link_unlocked");
+
       check_disconnected_message_arrived_unlocked (connection, link->data);
       
       return link;
@@ -4028,6 +4017,9 @@
                  "no member",
                  dbus_message_get_signature (message_link->data),
                  connection, connection->n_incoming);
+
+  _dbus_message_trace_ref (message_link->data, -1, -1,
+      "_dbus_connection_putback_message_link_unlocked");
 }
 
 /**
@@ -4096,7 +4088,7 @@
   CONNECTION_UNLOCK (connection);
   
   _dbus_verbose ("locking dispatch_mutex\n");
-  _dbus_mutex_lock (connection->dispatch_mutex);
+  _dbus_cmutex_lock (connection->dispatch_mutex);
 
   while (connection->dispatch_acquired)
     {
@@ -4110,7 +4102,7 @@
   connection->dispatch_acquired = TRUE;
 
   _dbus_verbose ("unlocking dispatch_mutex\n");
-  _dbus_mutex_unlock (connection->dispatch_mutex);
+  _dbus_cmutex_unlock (connection->dispatch_mutex);
   
   CONNECTION_LOCK (connection);
   _dbus_connection_unref_unlocked (connection);
@@ -4129,7 +4121,7 @@
   HAVE_LOCK_CHECK (connection);
   
   _dbus_verbose ("locking dispatch_mutex\n");
-  _dbus_mutex_lock (connection->dispatch_mutex);
+  _dbus_cmutex_lock (connection->dispatch_mutex);
   
   _dbus_assert (connection->dispatch_acquired);
 
@@ -4137,7 +4129,7 @@
   _dbus_condvar_wake_one (connection->dispatch_cond);
 
   _dbus_verbose ("unlocking dispatch_mutex\n");
-  _dbus_mutex_unlock (connection->dispatch_mutex);
+  _dbus_cmutex_unlock (connection->dispatch_mutex);
 }
 
 static void
@@ -4176,7 +4168,7 @@
       
       while ((link = _dbus_list_get_last_link (&connection->outgoing_messages)))
         {
-          _dbus_connection_message_sent (connection, link->data);
+          _dbus_connection_message_sent_unlocked (connection, link->data);
         }
     } 
 }
@@ -4361,44 +4353,48 @@
 _dbus_connection_peer_filter_unlocked_no_update (DBusConnection *connection,
                                                  DBusMessage    *message)
 {
+  dbus_bool_t sent = FALSE;
+  DBusMessage *ret = NULL;
+  DBusList *expire_link;
+
   if (connection->route_peer_messages && dbus_message_get_destination (message) != NULL)
     {
       /* This means we're letting the bus route this message */
       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
     }
-  else if (dbus_message_is_method_call (message,
-                                        DBUS_INTERFACE_PEER,
-                                        "Ping"))
+
+  if (!dbus_message_has_interface (message, DBUS_INTERFACE_PEER))
     {
-      DBusMessage *ret;
-      dbus_bool_t sent;
-      
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  /* Preallocate a linked-list link, so that if we need to dispose of a
+   * message, we can attach it to the expired list */
+  expire_link = _dbus_list_alloc_link (NULL);
+
+  if (!expire_link)
+    return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+  if (dbus_message_is_method_call (message,
+                                   DBUS_INTERFACE_PEER,
+                                   "Ping"))
+    {
       ret = dbus_message_new_method_return (message);
       if (ret == NULL)
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-     
+        goto out;
+
       sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL);
-
-      dbus_message_unref (ret);
-
-      if (!sent)
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-      
-      return DBUS_HANDLER_RESULT_HANDLED;
     }
   else if (dbus_message_is_method_call (message,
                                         DBUS_INTERFACE_PEER,
                                         "GetMachineId"))
     {
-      DBusMessage *ret;
-      dbus_bool_t sent;
       DBusString uuid;
       
       ret = dbus_message_new_method_return (message);
       if (ret == NULL)
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
+        goto out;
 
-      sent = FALSE;
       _dbus_string_init (&uuid);
       if (_dbus_get_local_machine_uuid_encoded (&uuid))
         {
@@ -4411,43 +4407,38 @@
             }
         }
       _dbus_string_free (&uuid);
-      
-      dbus_message_unref (ret);
-
-      if (!sent)
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-      
-      return DBUS_HANDLER_RESULT_HANDLED;
     }
-  else if (dbus_message_has_interface (message, DBUS_INTERFACE_PEER))
+  else
     {
       /* We need to bounce anything else with this interface, otherwise apps
        * could start extending the interface and when we added extensions
        * here to DBusConnection we'd break those apps.
        */
-      
-      DBusMessage *ret;
-      dbus_bool_t sent;
-      
       ret = dbus_message_new_error (message,
                                     DBUS_ERROR_UNKNOWN_METHOD,
                                     "Unknown method invoked on org.freedesktop.DBus.Peer interface");
       if (ret == NULL)
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-      
+        goto out;
+
       sent = _dbus_connection_send_unlocked_no_update (connection, ret, NULL);
-      
-      dbus_message_unref (ret);
-      
-      if (!sent)
-        return DBUS_HANDLER_RESULT_NEED_MEMORY;
-      
-      return DBUS_HANDLER_RESULT_HANDLED;
+    }
+
+out:
+  if (ret == NULL)
+    {
+      _dbus_list_free_link (expire_link);
     }
   else
     {
-      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+      /* It'll be safe to unref the reply when we unlock */
+      expire_link->data = ret;
+      _dbus_list_prepend_link (&connection->expired_messages, expire_link);
     }
+
+  if (!sent)
+    return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+  return DBUS_HANDLER_RESULT_HANDLED;
 }
 
 /**
@@ -4517,6 +4508,7 @@
   DBusPendingCall *pending;
   dbus_int32_t reply_serial;
   DBusDispatchStatus status;
+  dbus_bool_t found_object;
 
   _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE);
 
@@ -4608,9 +4600,6 @@
       /* unlocks and calls user code */
       _dbus_connection_update_dispatch_status_and_unlock (connection,
                                                           DBUS_DISPATCH_NEED_MEMORY);
-
-      if (pending)
-        dbus_pending_call_unref (pending);
       dbus_connection_unref (connection);
       
       return DBUS_DISPATCH_NEED_MEMORY;
@@ -4681,7 +4670,8 @@
 
   HAVE_LOCK_CHECK (connection);
   result = _dbus_object_tree_dispatch_and_unlock (connection->objects,
-                                                  message);
+                                                  message,
+                                                  &found_object);
   
   CONNECTION_LOCK (connection);
 
@@ -4696,10 +4686,11 @@
       DBusMessage *reply;
       DBusString str;
       DBusPreallocatedSend *preallocated;
+      DBusList *expire_link;
 
       _dbus_verbose ("  sending error %s\n",
                      DBUS_ERROR_UNKNOWN_METHOD);
-      
+
       if (!_dbus_string_init (&str))
         {
           result = DBUS_HANDLER_RESULT_NEED_MEMORY;
@@ -4720,7 +4711,7 @@
         }
       
       reply = dbus_message_new_error (message,
-                                      DBUS_ERROR_UNKNOWN_METHOD,
+                                      found_object ? DBUS_ERROR_UNKNOWN_METHOD : DBUS_ERROR_UNKNOWN_OBJECT,
                                       _dbus_string_get_const_data (&str));
       _dbus_string_free (&str);
 
@@ -4730,11 +4721,24 @@
           _dbus_verbose ("no memory for error reply in dispatch\n");
           goto out;
         }
-      
+
+      expire_link = _dbus_list_alloc_link (reply);
+
+      if (expire_link == NULL)
+        {
+          dbus_message_unref (reply);
+          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+          _dbus_verbose ("no memory for error send in dispatch\n");
+          goto out;
+        }
+
       preallocated = _dbus_connection_preallocate_send_unlocked (connection);
 
       if (preallocated == NULL)
         {
+          _dbus_list_free_link (expire_link);
+          /* It's OK that this is finalized, because it hasn't been seen by
+           * anything that could attach user callbacks */
           dbus_message_unref (reply);
           result = DBUS_HANDLER_RESULT_NEED_MEMORY;
           _dbus_verbose ("no memory for error send in dispatch\n");
@@ -4743,9 +4747,9 @@
 
       _dbus_connection_send_preallocated_unlocked_no_update (connection, preallocated,
                                                              reply, NULL);
+      /* reply will be freed when we release the lock */
+      _dbus_list_prepend_link (&connection->expired_messages, expire_link);
 
-      dbus_message_unref (reply);
-      
       result = DBUS_HANDLER_RESULT_HANDLED;
     }
   
@@ -4771,20 +4775,35 @@
        */
       _dbus_connection_putback_message_link_unlocked (connection,
                                                       message_link);
+      /* now we don't want to free them */
+      message_link = NULL;
+      message = NULL;
     }
   else
     {
       _dbus_verbose (" ... done dispatching\n");
-      
-      _dbus_list_free_link (message_link);
-      dbus_message_unref (message); /* don't want the message to count in max message limits
-                                     * in computing dispatch status below
-                                     */
     }
-  
+
   _dbus_connection_release_dispatch (connection);
   HAVE_LOCK_CHECK (connection);
 
+  if (message != NULL)
+    {
+      /* We don't want this message to count in maximum message limits when
+       * computing the dispatch status, below. We have to drop the lock
+       * temporarily, because finalizing a message can trigger callbacks.
+       *
+       * We have a reference to the connection, and we don't use any cached
+       * pointers to the connection's internals below this point, so it should
+       * be safe to drop the lock and take it back. */
+      CONNECTION_UNLOCK (connection);
+      dbus_message_unref (message);
+      CONNECTION_LOCK (connection);
+    }
+
+  if (message_link != NULL)
+    _dbus_list_free_link (message_link);
+
   _dbus_verbose ("before final status update\n");
   status = _dbus_connection_get_dispatch_status_unlocked (connection);
 
@@ -5456,8 +5475,8 @@
   if (filter == NULL)
     return FALSE;
 
-  filter->refcount.value = 1;
-  
+  _dbus_atomic_inc (&filter->refcount);
+
   CONNECTION_LOCK (connection);
 
   if (!_dbus_list_append (&connection->filter_list,
@@ -5548,31 +5567,30 @@
 }
 
 /**
- * Registers a handler for a given path in the object hierarchy.
- * The given vtable handles messages sent to exactly the given path.
+ * Registers a handler for a given path or subsection in the object
+ * hierarchy. The given vtable handles messages sent to exactly the
+ * given path or also for paths bellow that, depending on fallback
+ * parameter.
  *
  * @param connection the connection
+ * @param fallback whether to handle messages also for "subdirectory"
  * @param path a '/' delimited string of path elements
  * @param vtable the virtual table
  * @param user_data data to pass to functions in the vtable
  * @param error address where an error can be returned
  * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or
- *    #DBUS_ERROR_ADDRESS_IN_USE) is reported
+ *    #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported
  */
-dbus_bool_t
-dbus_connection_try_register_object_path (DBusConnection              *connection,
-                                          const char                  *path,
-                                          const DBusObjectPathVTable  *vtable,
-                                          void                        *user_data,
-                                          DBusError                   *error)
+static dbus_bool_t
+_dbus_connection_register_object_path (DBusConnection              *connection,
+                                       dbus_bool_t                  fallback,
+                                       const char                  *path,
+                                       const DBusObjectPathVTable  *vtable,
+                                       void                        *user_data,
+                                       DBusError                   *error)
 {
   char **decomposed_path;
   dbus_bool_t retval;
-  
-  _dbus_return_val_if_fail (connection != NULL, FALSE);
-  _dbus_return_val_if_fail (path != NULL, FALSE);
-  _dbus_return_val_if_fail (path[0] == '/', FALSE);
-  _dbus_return_val_if_fail (vtable != NULL, FALSE);
 
   if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL))
     return FALSE;
@@ -5580,7 +5598,7 @@
   CONNECTION_LOCK (connection);
 
   retval = _dbus_object_tree_register (connection->objects,
-                                       FALSE,
+                                       fallback,
                                        (const char **) decomposed_path, vtable,
                                        user_data, error);
 
@@ -5595,6 +5613,33 @@
  * Registers a handler for a given path in the object hierarchy.
  * The given vtable handles messages sent to exactly the given path.
  *
+ * @param connection the connection
+ * @param path a '/' delimited string of path elements
+ * @param vtable the virtual table
+ * @param user_data data to pass to functions in the vtable
+ * @param error address where an error can be returned
+ * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or
+ *    #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported
+ */
+dbus_bool_t
+dbus_connection_try_register_object_path (DBusConnection              *connection,
+                                          const char                  *path,
+                                          const DBusObjectPathVTable  *vtable,
+                                          void                        *user_data,
+                                          DBusError                   *error)
+{
+  _dbus_return_val_if_fail (connection != NULL, FALSE);
+  _dbus_return_val_if_fail (path != NULL, FALSE);
+  _dbus_return_val_if_fail (path[0] == '/', FALSE);
+  _dbus_return_val_if_fail (vtable != NULL, FALSE);
+
+  return _dbus_connection_register_object_path (connection, FALSE, path, vtable, user_data, error);
+}
+
+/**
+ * Registers a handler for a given path in the object hierarchy.
+ * The given vtable handles messages sent to exactly the given path.
+ *
  * It is a bug to call this function for object paths which already
  * have a handler. Use dbus_connection_try_register_object_path() if this
  * might be the case.
@@ -5603,7 +5648,8 @@
  * @param path a '/' delimited string of path elements
  * @param vtable the virtual table
  * @param user_data data to pass to functions in the vtable
- * @returns #FALSE if not enough memory
+ * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or
+ *    #DBUS_ERROR_OBJECT_PATH_IN_USE) ocurred
  */
 dbus_bool_t
 dbus_connection_register_object_path (DBusConnection              *connection,
@@ -5611,7 +5657,6 @@
                                       const DBusObjectPathVTable  *vtable,
                                       void                        *user_data)
 {
-  char **decomposed_path;
   dbus_bool_t retval;
   DBusError error = DBUS_ERROR_INIT;
 
@@ -5620,21 +5665,9 @@
   _dbus_return_val_if_fail (path[0] == '/', FALSE);
   _dbus_return_val_if_fail (vtable != NULL, FALSE);
 
-  if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL))
-    return FALSE;
+  retval = _dbus_connection_register_object_path (connection, FALSE, path, vtable, user_data, &error);
 
-  CONNECTION_LOCK (connection);
-
-  retval = _dbus_object_tree_register (connection->objects,
-                                       FALSE,
-                                       (const char **) decomposed_path, vtable,
-                                       user_data, &error);
-
-  CONNECTION_UNLOCK (connection);
-
-  dbus_free_string_array (decomposed_path);
-
-  if (dbus_error_has_name (&error, DBUS_ERROR_ADDRESS_IN_USE))
+  if (dbus_error_has_name (&error, DBUS_ERROR_OBJECT_PATH_IN_USE))
     {
       _dbus_warn ("%s\n", error.message);
       dbus_error_free (&error);
@@ -5656,7 +5689,7 @@
  * @param user_data data to pass to functions in the vtable
  * @param error address where an error can be returned
  * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or
- *    #DBUS_ERROR_ADDRESS_IN_USE) is reported
+ *    #DBUS_ERROR_OBJECT_PATH_IN_USE) is reported
  */
 dbus_bool_t
 dbus_connection_try_register_fallback (DBusConnection              *connection,
@@ -5665,29 +5698,12 @@
                                        void                        *user_data,
                                        DBusError                   *error)
 {
-  char **decomposed_path;
-  dbus_bool_t retval;
-
   _dbus_return_val_if_fail (connection != NULL, FALSE);
   _dbus_return_val_if_fail (path != NULL, FALSE);
   _dbus_return_val_if_fail (path[0] == '/', FALSE);
   _dbus_return_val_if_fail (vtable != NULL, FALSE);
 
-  if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL))
-    return FALSE;
-
-  CONNECTION_LOCK (connection);
-
-  retval = _dbus_object_tree_register (connection->objects,
-                                       TRUE,
-                                       (const char **) decomposed_path, vtable,
-                                       user_data, error);
-
-  CONNECTION_UNLOCK (connection);
-
-  dbus_free_string_array (decomposed_path);
-
-  return retval;
+  return _dbus_connection_register_object_path (connection, TRUE, path, vtable, user_data, error);
 }
 
 /**
@@ -5704,7 +5720,8 @@
  * @param path a '/' delimited string of path elements
  * @param vtable the virtual table
  * @param user_data data to pass to functions in the vtable
- * @returns #FALSE if not enough memory
+ * @returns #FALSE if an error (#DBUS_ERROR_NO_MEMORY or
+ *    #DBUS_ERROR_OBJECT_PATH_IN_USE) occured
  */
 dbus_bool_t
 dbus_connection_register_fallback (DBusConnection              *connection,
@@ -5712,7 +5729,6 @@
                                    const DBusObjectPathVTable  *vtable,
                                    void                        *user_data)
 {
-  char **decomposed_path;
   dbus_bool_t retval;
   DBusError error = DBUS_ERROR_INIT;
 
@@ -5721,21 +5737,9 @@
   _dbus_return_val_if_fail (path[0] == '/', FALSE);
   _dbus_return_val_if_fail (vtable != NULL, FALSE);
 
-  if (!_dbus_decompose_path (path, strlen (path), &decomposed_path, NULL))
-    return FALSE;
+  retval = _dbus_connection_register_object_path (connection, TRUE, path, vtable, user_data, &error);
 
-  CONNECTION_LOCK (connection);
-
-  retval = _dbus_object_tree_register (connection->objects,
-                                       TRUE,
-				       (const char **) decomposed_path, vtable,
-                                       user_data, &error);
-
-  CONNECTION_UNLOCK (connection);
-
-  dbus_free_string_array (decomposed_path);
-
-  if (dbus_error_has_name (&error, DBUS_ERROR_ADDRESS_IN_USE))
+  if (dbus_error_has_name (&error, DBUS_ERROR_OBJECT_PATH_IN_USE))
     {
       _dbus_warn ("%s\n", error.message);
       dbus_error_free (&error);
@@ -6193,6 +6197,47 @@
   return res;
 }
 
+#ifdef DBUS_ENABLE_STATS
+void
+_dbus_connection_get_stats (DBusConnection *connection,
+                            dbus_uint32_t  *in_messages,
+                            dbus_uint32_t  *in_bytes,
+                            dbus_uint32_t  *in_fds,
+                            dbus_uint32_t  *in_peak_bytes,
+                            dbus_uint32_t  *in_peak_fds,
+                            dbus_uint32_t  *out_messages,
+                            dbus_uint32_t  *out_bytes,
+                            dbus_uint32_t  *out_fds,
+                            dbus_uint32_t  *out_peak_bytes,
+                            dbus_uint32_t  *out_peak_fds)
+{
+  CONNECTION_LOCK (connection);
+
+  if (in_messages != NULL)
+    *in_messages = connection->n_incoming;
+
+  _dbus_transport_get_stats (connection->transport,
+                             in_bytes, in_fds, in_peak_bytes, in_peak_fds);
+
+  if (out_messages != NULL)
+    *out_messages = connection->n_outgoing;
+
+  if (out_bytes != NULL)
+    *out_bytes = _dbus_counter_get_size_value (connection->outgoing_counter);
+
+  if (out_fds != NULL)
+    *out_fds = _dbus_counter_get_unix_fd_value (connection->outgoing_counter);
+
+  if (out_peak_bytes != NULL)
+    *out_peak_bytes = _dbus_counter_get_peak_size_value (connection->outgoing_counter);
+
+  if (out_peak_fds != NULL)
+    *out_peak_fds = _dbus_counter_get_peak_unix_fd_value (connection->outgoing_counter);
+
+  CONNECTION_UNLOCK (connection);
+}
+#endif /* DBUS_ENABLE_STATS */
+
 /**
  * Gets the approximate number of uni fds of all messages in the
  * outgoing message queue.
@@ -6213,4 +6258,18 @@
   return res;
 }
 
+#ifdef DBUS_BUILD_TESTS
+/**
+ * Returns the address of the transport object of this connection
+ *
+ * @param connection the connection
+ * @returns the address string
+ */
+const char*
+_dbus_connection_get_address (DBusConnection *connection)
+{
+  return _dbus_transport_get_address (connection->transport);
+}
+#endif
+
 /** @} */
diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h
index bd19832..fe4d04e 100644
--- a/dbus/dbus-connection.h
+++ b/dbus/dbus-connection.h
@@ -69,6 +69,7 @@
                                  *   state passed to
                                  *   dbus_watch_handle()).
                                  */
+  /* Internal to libdbus, there is also _DBUS_WATCH_NVAL in dbus-watch.h */
 } DBusWatchFlags;
 
 /**
@@ -201,9 +202,6 @@
 dbus_bool_t        dbus_connection_read_write_dispatch          (DBusConnection             *connection,
                                                                  int                         timeout_milliseconds);
 DBUS_EXPORT
-dbus_bool_t        dbus_connection_read_write_dispatch_greedy   (DBusConnection             *connection,
-                                                                 int                         timeout_milliseconds);
-DBUS_EXPORT
 dbus_bool_t        dbus_connection_read_write                   (DBusConnection             *connection,
                                                                  int                         timeout_milliseconds);
 DBUS_EXPORT
diff --git a/dbus/dbus-dataslot.c b/dbus/dbus-dataslot.c
index fd25c41..0369612 100644
--- a/dbus/dbus-dataslot.c
+++ b/dbus/dbus-dataslot.c
@@ -67,12 +67,12 @@
  */
 dbus_bool_t
 _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator *allocator,
-                                 DBusMutex             **mutex_loc,
+                                 DBusRMutex            **mutex_loc,
                                  dbus_int32_t          *slot_id_p)
 {
   dbus_int32_t slot;
 
-  _dbus_mutex_lock (*mutex_loc);
+  _dbus_rmutex_lock (*mutex_loc);
 
   if (allocator->n_allocated_slots == 0)
     {
@@ -146,7 +146,7 @@
                  slot, allocator, allocator->n_allocated_slots, allocator->n_used_slots);
   
  out:
-  _dbus_mutex_unlock (*(allocator->lock_loc));
+  _dbus_rmutex_unlock (*(allocator->lock_loc));
   return slot >= 0;
 }
 
@@ -165,7 +165,7 @@
 _dbus_data_slot_allocator_free (DBusDataSlotAllocator *allocator,
                                 dbus_int32_t          *slot_id_p)
 {
-  _dbus_mutex_lock (*(allocator->lock_loc));
+  _dbus_rmutex_lock (*(allocator->lock_loc));
   
   _dbus_assert (*slot_id_p < allocator->n_allocated_slots);
   _dbus_assert (allocator->allocated_slots[*slot_id_p].slot_id == *slot_id_p);
@@ -175,7 +175,7 @@
 
   if (allocator->allocated_slots[*slot_id_p].refcount > 0)
     {
-      _dbus_mutex_unlock (*(allocator->lock_loc));
+      _dbus_rmutex_unlock (*(allocator->lock_loc));
       return;
     }
 
@@ -190,18 +190,18 @@
   
   if (allocator->n_used_slots == 0)
     {
-      DBusMutex **mutex_loc = allocator->lock_loc;
+      DBusRMutex **mutex_loc = allocator->lock_loc;
       
       dbus_free (allocator->allocated_slots);
       allocator->allocated_slots = NULL;
       allocator->n_allocated_slots = 0;
       allocator->lock_loc = NULL;
 
-      _dbus_mutex_unlock (*mutex_loc);
+      _dbus_rmutex_unlock (*mutex_loc);
     }
   else
     {
-      _dbus_mutex_unlock (*(allocator->lock_loc));
+      _dbus_rmutex_unlock (*(allocator->lock_loc));
     }
 }
 
@@ -247,10 +247,10 @@
    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
    * are disabled, since then the asserts are empty.
    */
-  _dbus_mutex_lock (*(allocator->lock_loc));
+  _dbus_rmutex_lock (*(allocator->lock_loc));
   _dbus_assert (slot < allocator->n_allocated_slots);
   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
-  _dbus_mutex_unlock (*(allocator->lock_loc));
+  _dbus_rmutex_unlock (*(allocator->lock_loc));
 #endif
   
   if (slot >= list->n_slots)
@@ -304,11 +304,11 @@
    * be e.g. realloc()ing allocated_slots. We avoid doing this if asserts
    * are disabled, since then the asserts are empty.
    */
-  _dbus_mutex_lock (*(allocator->lock_loc));
+  _dbus_rmutex_lock (*(allocator->lock_loc));
   _dbus_assert (slot >= 0);
   _dbus_assert (slot < allocator->n_allocated_slots);
   _dbus_assert (allocator->allocated_slots[slot].slot_id == slot);
-  _dbus_mutex_unlock (*(allocator->lock_loc));
+  _dbus_rmutex_unlock (*(allocator->lock_loc));
 #endif
 
   if (slot >= list->n_slots)
@@ -384,14 +384,14 @@
   int i;
   DBusFreeFunction old_free_func;
   void *old_data;
-  DBusMutex *mutex;
+  DBusRMutex *mutex;
   
   if (!_dbus_data_slot_allocator_init (&allocator))
     _dbus_assert_not_reached ("no memory for allocator");
 
   _dbus_data_slot_list_init (&list);
 
-  _dbus_mutex_new_at_location (&mutex);
+  _dbus_rmutex_new_at_location (&mutex);
   if (mutex == NULL)
     _dbus_assert_not_reached ("failed to alloc mutex");
   
@@ -471,7 +471,7 @@
       ++i;
     }
 
-  _dbus_mutex_free_at_location (&mutex);
+  _dbus_rmutex_free_at_location (&mutex);
   
   return TRUE;
 }
diff --git a/dbus/dbus-dataslot.h b/dbus/dbus-dataslot.h
index 2e706f7..3d9d5ed 100644
--- a/dbus/dbus-dataslot.h
+++ b/dbus/dbus-dataslot.h
@@ -57,7 +57,7 @@
   DBusAllocatedSlot *allocated_slots; /**< Allocated slots */
   int  n_allocated_slots; /**< number of slots malloc'd */
   int  n_used_slots;      /**< number of slots used */
-  DBusMutex **lock_loc;   /**< location of thread lock */
+  DBusRMutex **lock_loc;  /**< location of thread lock */
 };
 
 /**
@@ -72,7 +72,7 @@
 
 dbus_bool_t _dbus_data_slot_allocator_init  (DBusDataSlotAllocator  *allocator);
 dbus_bool_t _dbus_data_slot_allocator_alloc (DBusDataSlotAllocator  *allocator,
-                                             DBusMutex              **mutex_loc,
+                                             DBusRMutex             **mutex_loc,
                                              int                    *slot_id_p);
 void        _dbus_data_slot_allocator_free  (DBusDataSlotAllocator  *allocator,
                                              int                    *slot_id_p);
diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c
index 5f27501..db3305b 100644
--- a/dbus/dbus-errors.c
+++ b/dbus/dbus-errors.c
@@ -78,6 +78,8 @@
   
 } DBusRealError;
 
+_DBUS_STATIC_ASSERT (sizeof (DBusRealError) == sizeof (DBusError));
+
 /**
  * Returns a longer message describing an error name.
  * If the error name is unknown, returns the name
diff --git a/dbus/dbus-file-win.c b/dbus/dbus-file-win.c
index 53a3fc5..06a8ea1 100644
--- a/dbus/dbus-file-win.c
+++ b/dbus/dbus-file-win.c
@@ -275,7 +275,10 @@
       goto out;
     }
   if (world_readable)
-    _dbus_make_file_world_readable (tmp_filename_c);
+    {
+      if (! _dbus_make_file_world_readable (&tmp_filename, error))
+        goto out;
+    }
 
   _dbus_verbose ("tmp file %s hnd %p opened\n", tmp_filename_c, hnd);
 
diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c
index 67ef4ce..c4c6f93 100644
--- a/dbus/dbus-hash.c
+++ b/dbus/dbus-hash.c
@@ -222,6 +222,8 @@
   int n_entries_on_init;     /**< used to detect table resize since initialization */
 } DBusRealHashIter;
 
+_DBUS_STATIC_ASSERT (sizeof (DBusRealHashIter) == sizeof (DBusHashIter));
+
 static DBusHashEntry* find_direct_function      (DBusHashTable          *table,
                                                  void                   *key,
                                                  dbus_bool_t             create_if_not_found,
@@ -232,17 +234,7 @@
                                                  dbus_bool_t             create_if_not_found,
                                                  DBusHashEntry        ***bucket,
                                                  DBusPreallocatedHash   *preallocated);
-#ifdef DBUS_BUILD_TESTS
-static DBusHashEntry* find_two_strings_function (DBusHashTable          *table,
-                                                 void                   *key,
-                                                 dbus_bool_t             create_if_not_found,
-                                                 DBusHashEntry        ***bucket,
-                                                 DBusPreallocatedHash   *preallocated);
-#endif
 static unsigned int   string_hash               (const char             *str);
-#ifdef DBUS_BUILD_TESTS
-static unsigned int   two_strings_hash          (const char             *str);
-#endif
 static void           rebuild_table             (DBusHashTable          *table);
 static DBusHashEntry* alloc_entry               (DBusHashTable          *table);
 static void           remove_entry              (DBusHashTable          *table,
@@ -327,18 +319,12 @@
   switch (table->key_type)
     {
     case DBUS_HASH_INT:
-    case DBUS_HASH_POINTER:
     case DBUS_HASH_UINTPTR:
       table->find_function = find_direct_function;
       break;
     case DBUS_HASH_STRING:
       table->find_function = find_string_function;
       break;
-    case DBUS_HASH_TWO_STRINGS:
-#ifdef DBUS_BUILD_TESTS
-      table->find_function = find_two_strings_function;
-#endif
-      break;
     default:
       _dbus_assert_not_reached ("Unknown hash table type");
       break;
@@ -719,26 +705,6 @@
   return real->entry->key;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Gets the key for the current entry.
- * Only works for hash tables of type #DBUS_HASH_TWO_STRINGS
- * @param iter the hash table iterator.
- */
-const char*
-_dbus_hash_iter_get_two_strings_key (DBusHashIter *iter)
-{
-  DBusRealHashIter *real;
-
-  real = (DBusRealHashIter*) iter;
-
-  _dbus_assert (real->table != NULL);
-  _dbus_assert (real->entry != NULL);
-
-  return real->entry->key;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * A low-level but efficient interface for manipulating the hash
  * table.  It's efficient because you can get, set, and optionally
@@ -874,27 +840,6 @@
   return h;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/* This hashes a memory block with two nul-terminated strings
- * in it, used in dbus-object-registry.c at the moment.
- */
-static unsigned int
-two_strings_hash (const char *str)
-{
-  const char *p = str;
-  unsigned int h = *p;
-
-  if (h)
-    for (p += 1; *p != '\0'; p++)
-      h = (h << 5) - h + *p;
-
-  for (p += 1; *p != '\0'; p++)
-    h = (h << 5) - h + *p;
-  
-  return h;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /** Key comparison function */
 typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b);
 
@@ -955,44 +900,6 @@
                                 preallocated);
 }
 
-#ifdef DBUS_BUILD_TESTS
-static int
-two_strings_cmp (const char *a,
-                 const char *b)
-{
-  size_t len_a;
-  size_t len_b;
-  int res;
-  
-  res = strcmp (a, b);
-  if (res != 0)
-    return res;
-
-  len_a = strlen (a);
-  len_b = strlen (b);
-
-  return strcmp (a + len_a + 1, b + len_b + 1);
-}
-#endif
-
-#ifdef DBUS_BUILD_TESTS
-static DBusHashEntry*
-find_two_strings_function (DBusHashTable        *table,
-                           void                 *key,
-                           dbus_bool_t           create_if_not_found,
-                           DBusHashEntry      ***bucket,
-                           DBusPreallocatedHash *preallocated)
-{
-  unsigned int idx;
-  
-  idx = two_strings_hash (key) & table->mask;
-
-  return find_generic_function (table, key, idx,
-                                (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket,
-                                preallocated);
-}
-#endif /* DBUS_BUILD_TESTS */
-
 static DBusHashEntry*
 find_direct_function (DBusHashTable        *table,
                       void                 *key,
@@ -1107,17 +1014,8 @@
             case DBUS_HASH_STRING:
               idx = string_hash (entry->key) & table->mask;
               break;
-            case DBUS_HASH_TWO_STRINGS:
-#ifdef DBUS_BUILD_TESTS
-              idx = two_strings_hash (entry->key) & table->mask;
-#else
-              idx = 0;
-              _dbus_assert_not_reached ("two-strings is not enabled");
-#endif
-              break;
             case DBUS_HASH_INT:
             case DBUS_HASH_UINTPTR:
-            case DBUS_HASH_POINTER:
               idx = RANDOM_INDEX (table, entry->key);
               break;
             default:
@@ -1163,33 +1061,6 @@
     return NULL;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Looks up the value for a given string in a hash table
- * of type #DBUS_HASH_TWO_STRINGS. Returns %NULL if the value
- * is not present. (A not-present entry is indistinguishable
- * from an entry with a value of %NULL.)
- * @param table the hash table.
- * @param key the string to look up.
- * @returns the value of the hash entry.
- */
-void*
-_dbus_hash_table_lookup_two_strings (DBusHashTable *table,
-                                     const char    *key)
-{
-  DBusHashEntry *entry;
-
-  _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
-  
-  entry = (* table->find_function) (table, (char*) key, FALSE, NULL, NULL);
-
-  if (entry)
-    return entry->value;
-  else
-    return NULL;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Looks up the value for a given integer in a hash table
  * of type #DBUS_HASH_INT. Returns %NULL if the value
@@ -1215,34 +1086,6 @@
     return NULL;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/* disabled since it's only used for testing */
-/**
- * Looks up the value for a given integer in a hash table
- * of type #DBUS_HASH_POINTER. Returns %NULL if the value
- * is not present. (A not-present entry is indistinguishable
- * from an entry with a value of %NULL.)
- * @param table the hash table.
- * @param key the integer to look up.
- * @returns the value of the hash entry.
- */
-void*
-_dbus_hash_table_lookup_pointer (DBusHashTable *table,
-                                 void          *key)
-{
-  DBusHashEntry *entry;
-
-  _dbus_assert (table->key_type == DBUS_HASH_POINTER);
-  
-  entry = (* table->find_function) (table, key, FALSE, NULL, NULL);
-
-  if (entry)
-    return entry->value;
-  else
-    return NULL;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Looks up the value for a given integer in a hash table
  * of type #DBUS_HASH_UINTPTR. Returns %NULL if the value
@@ -1296,36 +1139,6 @@
     return FALSE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Removes the hash entry for the given key. If no hash entry
- * for the key exists, does nothing.
- *
- * @param table the hash table.
- * @param key the hash key.
- * @returns #TRUE if the entry existed
- */
-dbus_bool_t
-_dbus_hash_table_remove_two_strings (DBusHashTable *table,
-                                     const char    *key)
-{
-  DBusHashEntry *entry;
-  DBusHashEntry **bucket;
-  
-  _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
-  
-  entry = (* table->find_function) (table, (char*) key, FALSE, &bucket, NULL);
-
-  if (entry)
-    {
-      remove_entry (table, bucket, entry);
-      return TRUE;
-    }
-  else
-    return FALSE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Removes the hash entry for the given key. If no hash entry
  * for the key exists, does nothing.
@@ -1354,37 +1167,6 @@
     return FALSE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/* disabled since it's only used for testing */
-/**
- * Removes the hash entry for the given key. If no hash entry
- * for the key exists, does nothing.
- *
- * @param table the hash table.
- * @param key the hash key.
- * @returns #TRUE if the entry existed
- */
-dbus_bool_t
-_dbus_hash_table_remove_pointer (DBusHashTable *table,
-                                 void          *key)
-{
-  DBusHashEntry *entry;
-  DBusHashEntry **bucket;
-  
-  _dbus_assert (table->key_type == DBUS_HASH_POINTER);
-  
-  entry = (* table->find_function) (table, key, FALSE, &bucket, NULL);
-  
-  if (entry)
-    {
-      remove_entry (table, bucket, entry);
-      return TRUE;
-    }
-  else
-    return FALSE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Removes the hash entry for the given key. If no hash entry
  * for the key exists, does nothing.
@@ -1447,49 +1229,6 @@
   return TRUE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Creates a hash entry with the given key and value.
- * The key and value are not copied; they are stored
- * in the hash table by reference. If an entry with the
- * given key already exists, the previous key and value
- * are overwritten (and freed if the hash table has
- * a key_free_function and/or value_free_function).
- *
- * Returns #FALSE if memory for the new hash entry
- * can't be allocated.
- * 
- * @param table the hash table.
- * @param key the hash entry key.
- * @param value the hash entry value.
- */
-dbus_bool_t
-_dbus_hash_table_insert_two_strings (DBusHashTable *table,
-                                     char          *key,
-                                     void          *value)
-{
-  DBusHashEntry *entry;
-  
-  _dbus_assert (table->key_type == DBUS_HASH_TWO_STRINGS);
-  
-  entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
-
-  if (entry == NULL)
-    return FALSE; /* no memory */
-
-  if (table->free_key_function && entry->key != key)
-    (* table->free_key_function) (entry->key);
-  
-  if (table->free_value_function && entry->value != value)
-    (* table->free_value_function) (entry->value);
-  
-  entry->key = key;
-  entry->value = value;
-
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Creates a hash entry with the given key and value.
  * The key and value are not copied; they are stored
@@ -1531,50 +1270,6 @@
   return TRUE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/* disabled since it's only used for testing */
-/**
- * Creates a hash entry with the given key and value.
- * The key and value are not copied; they are stored
- * in the hash table by reference. If an entry with the
- * given key already exists, the previous key and value
- * are overwritten (and freed if the hash table has
- * a key_free_function and/or value_free_function).
- *
- * Returns #FALSE if memory for the new hash entry
- * can't be allocated.
- * 
- * @param table the hash table.
- * @param key the hash entry key.
- * @param value the hash entry value.
- */
-dbus_bool_t
-_dbus_hash_table_insert_pointer (DBusHashTable *table,
-                                 void          *key,
-                                 void          *value)
-{
-  DBusHashEntry *entry;
-
-  _dbus_assert (table->key_type == DBUS_HASH_POINTER);
-  
-  entry = (* table->find_function) (table, key, TRUE, NULL, NULL);
-
-  if (entry == NULL)
-    return FALSE; /* no memory */
-
-  if (table->free_key_function && entry->key != key)
-    (* table->free_key_function) (entry->key);
-  
-  if (table->free_value_function && entry->value != value)
-    (* table->free_value_function) (entry->value);
-  
-  entry->key = key;
-  entry->value = value;
-
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Creates a hash entry with the given key and value.
  * The key and value are not copied; they are stored
@@ -1730,28 +1425,6 @@
   return count;
 }
 
-/* Copy the foo\0bar\0 double string thing */
-static char*
-_dbus_strdup2 (const char *str)
-{
-  size_t len;
-  char *copy;
-  
-  if (str == NULL)
-    return NULL;
-  
-  len = strlen (str);
-  len += strlen ((str + len + 1));
-
-  copy = dbus_malloc (len + 2);
-  if (copy == NULL)
-    return NULL;
-
-  memcpy (copy, str, len + 2);
-  
-  return copy;
-}
-
 /**
  * @ingroup DBusHashTableInternals
  * Unit test for DBusHashTable
@@ -1764,7 +1437,6 @@
   DBusHashTable *table1;
   DBusHashTable *table2;
   DBusHashTable *table3;
-  DBusHashTable *table4;
   DBusHashIter iter;
 #define N_HASH_KEYS 5000
   char **keys;
@@ -1788,14 +1460,8 @@
     {
       int len;
 
-      /* all the hash keys are TWO_STRINGS, but
-       * then we can also use those as regular strings.
-       */
-      
       len = sprintf (keys[i], "Hash key %d", i);
-      sprintf (keys[i] + len + 1, "Two string %d", i);
       _dbus_assert (*(keys[i] + len) == '\0');
-      _dbus_assert (*(keys[i] + len + 1) != '\0');
       ++i;
     }
   printf ("... done.\n");
@@ -1815,12 +1481,6 @@
   if (table3 == NULL)
     goto out;
 
-  table4 = _dbus_hash_table_new (DBUS_HASH_TWO_STRINGS,
-                                 dbus_free, dbus_free);
-  if (table4 == NULL)
-    goto out;
-
-  
   /* Insert and remove a bunch of stuff, counting the table in between
    * to be sure it's not broken and that iteration works
    */
@@ -1857,21 +1517,9 @@
                                           i, value))
         goto out;
 
-      key = _dbus_strdup2 (keys[i]);
-      if (key == NULL)
-        goto out;
-      value = _dbus_strdup ("Value!");
-      if (value == NULL)
-        goto out;
-      
-      if (!_dbus_hash_table_insert_two_strings (table4,
-                                                key, value))
-        goto out;
-      
       _dbus_assert (count_entries (table1) == i + 1);
       _dbus_assert (count_entries (table2) == i + 1);
       _dbus_assert (count_entries (table3) == i + 1);
-      _dbus_assert (count_entries (table4) == i + 1);
 
       value = _dbus_hash_table_lookup_string (table1, keys[i]);
       _dbus_assert (value != NULL);
@@ -1885,10 +1533,6 @@
       _dbus_assert (value != NULL);
       _dbus_assert (strcmp (value, keys[i]) == 0);
 
-      value = _dbus_hash_table_lookup_two_strings (table4, keys[i]);
-      _dbus_assert (value != NULL);
-      _dbus_assert (strcmp (value, "Value!") == 0);
-      
       ++i;
     }
 
@@ -1902,13 +1546,9 @@
 
       _dbus_hash_table_remove_uintptr (table3, i);
 
-      _dbus_hash_table_remove_two_strings (table4,
-                                           keys[i]);
-      
       _dbus_assert (count_entries (table1) == i);
       _dbus_assert (count_entries (table2) == i);
       _dbus_assert (count_entries (table3) == i);
-      _dbus_assert (count_entries (table4) == i);
 
       --i;
     }
@@ -1916,15 +1556,12 @@
   _dbus_hash_table_ref (table1);
   _dbus_hash_table_ref (table2);
   _dbus_hash_table_ref (table3);
-  _dbus_hash_table_ref (table4);
   _dbus_hash_table_unref (table1);
   _dbus_hash_table_unref (table2);
   _dbus_hash_table_unref (table3);
-  _dbus_hash_table_unref (table4);
   _dbus_hash_table_unref (table1);
   _dbus_hash_table_unref (table2);
   _dbus_hash_table_unref (table3);
-  _dbus_hash_table_unref (table4);
   table3 = NULL;
 
   /* Insert a bunch of stuff then check
diff --git a/dbus/dbus-hash.h b/dbus/dbus-hash.h
index d1ca246..5aa183c 100644
--- a/dbus/dbus-hash.h
+++ b/dbus/dbus-hash.h
@@ -67,9 +67,7 @@
 typedef enum
 {
   DBUS_HASH_STRING,        /**< Hash keys are strings. */
-  DBUS_HASH_TWO_STRINGS,   /**< Hash key is two strings in one memory block, i.e. foo\\0bar\\0 */
   DBUS_HASH_INT,           /**< Hash keys are integers. */
-  DBUS_HASH_POINTER,       /**< Hash keys are pointers. */
   DBUS_HASH_UINTPTR        /**< Hash keys are integer capable to hold a pointer. */
 } DBusHashType;
 
@@ -88,7 +86,6 @@
                                                     void             *value);
 int            _dbus_hash_iter_get_int_key         (DBusHashIter     *iter);
 const char*    _dbus_hash_iter_get_string_key      (DBusHashIter     *iter);
-const char*    _dbus_hash_iter_get_two_strings_key (DBusHashIter     *iter);
 uintptr_t      _dbus_hash_iter_get_uintptr_key     (DBusHashIter     *iter);
 dbus_bool_t    _dbus_hash_iter_lookup              (DBusHashTable    *table,
                                                     void             *key,
@@ -96,36 +93,22 @@
                                                     DBusHashIter     *iter);
 void*          _dbus_hash_table_lookup_string      (DBusHashTable    *table,
                                                     const char       *key);
-void*          _dbus_hash_table_lookup_two_strings (DBusHashTable    *table,
-                                                    const char       *key);
 void*          _dbus_hash_table_lookup_int         (DBusHashTable    *table,
                                                     int               key);
-void*          _dbus_hash_table_lookup_pointer     (DBusHashTable    *table,
-                                                    void             *key);
 void*          _dbus_hash_table_lookup_uintptr     (DBusHashTable    *table,
                                                     uintptr_t         key);
 dbus_bool_t    _dbus_hash_table_remove_string      (DBusHashTable    *table,
                                                     const char       *key);
-dbus_bool_t    _dbus_hash_table_remove_two_strings (DBusHashTable    *table,
-                                                    const char       *key);
 dbus_bool_t    _dbus_hash_table_remove_int         (DBusHashTable    *table,
                                                     int               key);
-dbus_bool_t    _dbus_hash_table_remove_pointer     (DBusHashTable    *table,
-                                                    void             *key);
 dbus_bool_t    _dbus_hash_table_remove_uintptr     (DBusHashTable    *table,
                                                     uintptr_t         key);
 dbus_bool_t    _dbus_hash_table_insert_string      (DBusHashTable    *table,
                                                     char             *key,
                                                     void             *value);
-dbus_bool_t    _dbus_hash_table_insert_two_strings (DBusHashTable    *table,
-                                                    char             *key,
-                                                    void             *value);
 dbus_bool_t    _dbus_hash_table_insert_int         (DBusHashTable    *table,
                                                     int               key,
                                                     void             *value);
-dbus_bool_t    _dbus_hash_table_insert_pointer     (DBusHashTable    *table,
-                                                    void             *key,
-                                                    void             *value);
 dbus_bool_t    _dbus_hash_table_insert_uintptr     (DBusHashTable    *table,
                                                     uintptr_t         key,
                                                     void             *value);
diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
index e87c55c..1ec4980 100644
--- a/dbus/dbus-internals.c
+++ b/dbus/dbus-internals.c
@@ -26,6 +26,7 @@
 #include "dbus-protocol.h"
 #include "dbus-marshal-basic.h"
 #include "dbus-test.h"
+#include "dbus-valgrind-internal.h"
 #include <stdio.h>
 #include <stdarg.h>
 #include <string.h>
@@ -314,9 +315,6 @@
 #include <pthread.h>
 #endif
 
-#ifdef _MSC_VER
-#define inline
-#endif
 #ifdef DBUS_USE_OUTPUT_DEBUG_STRING
 static char module_name[1024];
 #endif
@@ -369,7 +367,6 @@
 static char *_dbus_file_path_extract_elements_from_tail(const char *file,int level)
 {
   static int prefix = -1;
-  char *p;
 
   if (prefix == -1) 
     {
@@ -412,20 +409,19 @@
  * @param format printf-style format string.
  */
 void
+_dbus_verbose_real (
 #ifdef DBUS_CPP_SUPPORTS_VARIABLE_MACRO_ARGUMENTS
-_dbus_verbose_real (const char *file, 
+                    const char *file,
                     const int line, 
                     const char *function, 
-                    const char *format,
-#else
-_dbus_verbose_real (const char *format,
 #endif
+                    const char *format,
                     ...)
 {
   va_list args;
   static dbus_bool_t need_pid = TRUE;
   int len;
-
+  
   /* things are written a bit oddly here so that
    * in the non-verbose case we just have the one
    * conditional and return immediately.
@@ -492,6 +488,72 @@
   verbose_initted = FALSE;
 }
 
+void
+_dbus_trace_ref (const char *obj_name,
+                 void       *obj,
+                 int         old_refcount,
+                 int         new_refcount,
+                 const char *why,
+                 const char *env_var,
+                 int        *enabled)
+{
+  _dbus_assert (obj_name != NULL);
+  _dbus_assert (obj != NULL);
+  _dbus_assert (old_refcount >= -1);
+  _dbus_assert (new_refcount >= -1);
+
+  if (old_refcount == -1)
+    {
+      _dbus_assert (new_refcount == -1);
+    }
+  else
+    {
+      _dbus_assert (new_refcount >= 0);
+      _dbus_assert (old_refcount >= 0);
+      _dbus_assert (old_refcount > 0 || new_refcount > 0);
+    }
+
+  _dbus_assert (why != NULL);
+  _dbus_assert (env_var != NULL);
+  _dbus_assert (enabled != NULL);
+
+  if (*enabled < 0)
+    {
+      const char *s = _dbus_getenv (env_var);
+
+      *enabled = FALSE;
+
+      if (s && *s)
+        {
+          if (*s == '0')
+            *enabled = FALSE;
+          else if (*s == '1')
+            *enabled = TRUE;
+          else
+            _dbus_warn ("%s should be 0 or 1 if set, not '%s'", env_var, s);
+        }
+    }
+
+  if (*enabled)
+    {
+      if (old_refcount == -1)
+        {
+          VALGRIND_PRINTF_BACKTRACE ("%s %p ref stolen (%s)",
+                                     obj_name, obj, why);
+          _dbus_verbose ("%s %p ref stolen (%s)",
+                         obj_name, obj, why);
+        }
+      else
+        {
+          VALGRIND_PRINTF_BACKTRACE ("%s %p %d -> %d refs (%s)",
+                                     obj_name, obj,
+                                     old_refcount, new_refcount, why);
+          _dbus_verbose ("%s %p %d -> %d refs (%s)",
+                         obj_name, obj, old_refcount, new_refcount, why);
+        }
+    }
+}
+
 #endif /* DBUS_ENABLE_VERBOSE_MODE */
 
 /**
@@ -621,7 +683,10 @@
 {
   long now;
 
-  _dbus_get_current_time (&now, NULL);
+  /* don't use monotonic time because the UUID may be saved to disk, e.g.
+   * it may persist across reboots
+   */
+  _dbus_get_real_time (&now, NULL);
 
   uuid->as_uint32s[DBUS_UUID_LENGTH_WORDS - 1] = DBUS_UINT32_TO_BE (now);
   
@@ -855,42 +920,6 @@
   return ok;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Returns a string describing the given name.
- *
- * @param header_field the field to describe
- * @returns a constant string describing the field
- */
-const char *
-_dbus_header_field_to_string (int header_field)
-{
-  switch (header_field)
-    {
-    case DBUS_HEADER_FIELD_INVALID:
-      return "invalid";
-    case DBUS_HEADER_FIELD_PATH:
-      return "path";
-    case DBUS_HEADER_FIELD_INTERFACE:
-      return "interface";
-    case DBUS_HEADER_FIELD_MEMBER:
-      return "member";
-    case DBUS_HEADER_FIELD_ERROR_NAME:
-      return "error-name";
-    case DBUS_HEADER_FIELD_REPLY_SERIAL:
-      return "reply-serial";
-    case DBUS_HEADER_FIELD_DESTINATION:
-      return "destination";
-    case DBUS_HEADER_FIELD_SENDER:
-      return "sender";
-    case DBUS_HEADER_FIELD_SIGNATURE:
-      return "signature";
-    default:
-      return "unknown";
-    }
-}
-#endif /* DBUS_BUILD_TESTS */
-
 #ifndef DBUS_DISABLE_CHECKS
 /** String used in _dbus_return_if_fail macro */
 const char *_dbus_return_if_fail_warning_format =
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index 4286972..8036a2b 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -108,20 +108,28 @@
 #  define _dbus_is_verbose _dbus_is_verbose_real
 #else
 #  ifdef HAVE_ISO_VARARGS
-#    define _dbus_verbose(...)
+#    define _dbus_verbose(...) do { } while (0)
 #  elif defined (HAVE_GNUC_VARARGS)
-#    define _dbus_verbose(format...)
+#    define _dbus_verbose(format...) do { } while (0)
 #  else
 static void _dbus_verbose(const char * x,...) {;}
 #  endif
-#  define _dbus_verbose_reset()
+#  define _dbus_verbose_reset() do { } while (0)
 #  define _dbus_is_verbose() FALSE 
 #endif /* !DBUS_ENABLE_VERBOSE_MODE */
 
+void _dbus_trace_ref (const char *obj_name,
+                      void       *obj,
+                      int         old_refcount,
+                      int         new_refcount,
+                      const char *why,
+                      const char *env_var,
+                      int        *enabled);
+
 const char* _dbus_strerror (int error_number);
 
 #ifdef DBUS_DISABLE_ASSERT
-#define _dbus_assert(condition)
+#define _dbus_assert(condition) do { } while (0)
 #else
 void _dbus_real_assert (dbus_bool_t  condition,
                         const char  *condition_text,
@@ -133,7 +141,7 @@
 #endif /* !DBUS_DISABLE_ASSERT */
 
 #ifdef DBUS_DISABLE_ASSERT
-#define _dbus_assert_not_reached(explanation)
+#define _dbus_assert_not_reached(explanation) do { } while (0)
 #else
 void _dbus_real_assert_not_reached (const char *explanation,
                                     const char *file,
@@ -181,15 +189,11 @@
 /* this is an assert and not an error, but in the typical --disable-checks case (you're trying
  * to really minimize code size), disabling these assertions makes sense.
  */
-#define _DBUS_ASSERT_ERROR_IS_SET(error)
-#define _DBUS_ASSERT_ERROR_IS_CLEAR(error)
-#define _DBUS_ASSERT_ERROR_CONTENT_IS_SET(error)
-#define _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR(error)
+#define _DBUS_ASSERT_ERROR_IS_SET(error) do { } while (0)
+#define _DBUS_ASSERT_ERROR_IS_CLEAR(error) do { } while (0)
 #else
 #define _DBUS_ASSERT_ERROR_IS_SET(error)   _dbus_assert ((error) == NULL || dbus_error_is_set ((error)))
 #define _DBUS_ASSERT_ERROR_IS_CLEAR(error) _dbus_assert ((error) == NULL || !dbus_error_is_set ((error)))
-#define _DBUS_ASSERT_ERROR_CONTENT_IS_SET(error)   _dbus_assert (dbus_error_is_set ((error)))
-#define _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR(error) _dbus_assert (!dbus_error_is_set ((error)))
 #endif
 
 #define _dbus_return_if_error_is_set(error) _dbus_return_if_fail ((error) == NULL || !dbus_error_is_set ((error)))
@@ -263,8 +267,6 @@
                                     int                  start,
                                     int                  len);
 
-const char* _dbus_header_field_to_string (int header_field);
-
 extern const char *_dbus_no_memory_message;
 #define _DBUS_SET_OOM(error) dbus_set_error_const ((error), DBUS_ERROR_NO_MEMORY, _dbus_no_memory_message)
 
@@ -302,10 +304,10 @@
 
 /* Thread initializers */
 #define _DBUS_LOCK_NAME(name)           _dbus_lock_##name
-#define _DBUS_DECLARE_GLOBAL_LOCK(name) extern DBusMutex  *_dbus_lock_##name
-#define _DBUS_DEFINE_GLOBAL_LOCK(name)  DBusMutex         *_dbus_lock_##name  
-#define _DBUS_LOCK(name)                _dbus_mutex_lock   (_dbus_lock_##name)
-#define _DBUS_UNLOCK(name)              _dbus_mutex_unlock (_dbus_lock_##name)
+#define _DBUS_DECLARE_GLOBAL_LOCK(name) extern DBusRMutex *_dbus_lock_##name
+#define _DBUS_DEFINE_GLOBAL_LOCK(name)  DBusRMutex        *_dbus_lock_##name
+#define _DBUS_LOCK(name)                _dbus_rmutex_lock   (_dbus_lock_##name)
+#define _DBUS_UNLOCK(name)              _dbus_rmutex_unlock (_dbus_lock_##name)
 
 /* 1-5 */
 _DBUS_DECLARE_GLOBAL_LOCK (list);
@@ -366,6 +368,12 @@
 
 dbus_bool_t _dbus_get_local_machine_uuid_encoded (DBusString *uuid_str);
 
+#define _DBUS_PASTE2(a, b) a ## b
+#define _DBUS_PASTE(a, b) _DBUS_PASTE2 (a, b)
+#define _DBUS_STATIC_ASSERT(expr) \
+  typedef struct { char _assertion[(expr) ? 1 : -1]; } \
+  _DBUS_PASTE (_DBUS_STATIC_ASSERT_, __LINE__)
+
 DBUS_END_DECLS
 
 #endif /* DBUS_INTERNALS_H */
diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c
index bef6452..3b9ce31 100644
--- a/dbus/dbus-keyring.c
+++ b/dbus/dbus-keyring.c
@@ -143,8 +143,6 @@
 
   return keyring;
 
-  /*  out_4: */
-  _dbus_string_free (&keyring->filename_lock);
  out_3:
   _dbus_string_free (&keyring->filename);
  out_2:
@@ -355,7 +353,7 @@
       goto out;
     }
 
-  _dbus_get_current_time (&timestamp, NULL);
+  _dbus_get_real_time (&timestamp, NULL);
       
   keys[n_keys-1].id = id;
   keys[n_keys-1].creation_time = timestamp;
@@ -430,7 +428,7 @@
   retval = FALSE;
   have_lock = FALSE;
 
-  _dbus_get_current_time (&now, NULL);
+  _dbus_get_real_time (&now, NULL);
   
   if (add_new)
     {
@@ -719,6 +717,13 @@
   DBusCredentials *our_credentials;
   
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  if (_dbus_check_setuid ())
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to create DBus keyring when setuid");
+      return NULL;
+    }
   
   keyring = NULL;
   error_set = FALSE;
@@ -910,7 +915,7 @@
   int i;
   long tv_sec, tv_usec;
 
-  _dbus_get_current_time (&tv_sec, &tv_usec);
+  _dbus_get_real_time (&tv_sec, &tv_usec);
   
   i = 0;
   while (i < keyring->n_keys)
diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c
index 6a16ed6..7e11cc8 100644
--- a/dbus/dbus-list.c
+++ b/dbus/dbus-list.c
@@ -146,6 +146,18 @@
     }
 }
 
+#ifdef DBUS_ENABLE_STATS
+void
+_dbus_list_get_stats     (dbus_uint32_t *in_use_p,
+                          dbus_uint32_t *in_free_list_p,
+                          dbus_uint32_t *allocated_p)
+{
+  _DBUS_LOCK (list);
+  _dbus_mem_pool_get_stats (list_pool, in_use_p, in_free_list_p, allocated_p);
+  _DBUS_UNLOCK (list);
+}
+#endif
+
 /** @} */
 
 /**
@@ -313,37 +325,6 @@
   link_before (list, *list, link);
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Inserts data into the list before the given existing link.
- * 
- * @param list the list to modify
- * @param before_this_link existing link to insert before, or #NULL to append
- * @param data the value to insert
- * @returns #TRUE on success, #FALSE if memory allocation fails
- */
-dbus_bool_t
-_dbus_list_insert_before (DBusList **list,
-                          DBusList  *before_this_link,
-                          void      *data)
-{
-  DBusList *link;
-  
-  if (before_this_link == NULL)
-    return _dbus_list_append (list, data);
-  else
-    {
-      link = alloc_link (data);
-      if (link == NULL)
-        return FALSE;
-  
-      link_before (list, before_this_link, link);
-    }
-  
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Inserts data into the list after the given existing link.
  * 
@@ -692,29 +673,6 @@
   return data;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Removes the last link in the list and returns it.  This is a
- * constant-time operation.
- *
- * @param list address of the list head.
- * @returns the last link in the list, or #NULL for an empty list.
- */
-DBusList*
-_dbus_list_pop_last_link (DBusList **list)
-{
-  DBusList *link;
-  
-  link = _dbus_list_get_last_link (list);
-  if (link == NULL)
-    return NULL;
-
-  _dbus_list_unlink (list, link);
-
-  return link;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Copies a list. This is a linear-time operation.  If there isn't
  * enough memory to copy the entire list, the destination list will be
@@ -1076,25 +1034,25 @@
       DBusList *got_link1;
       DBusList *got_link2;
 
-      DBusList *link1;
       DBusList *link2;
       
+      void *data1_indirect;
       void *data1;
       void *data2;
       
       got_link1 = _dbus_list_get_last_link (&list1);
       got_link2 = _dbus_list_get_first_link (&list2);
-      
-      link1 = _dbus_list_pop_last_link (&list1);
+
       link2 = _dbus_list_pop_first_link (&list2);
 
-      _dbus_assert (got_link1 == link1);
       _dbus_assert (got_link2 == link2);
 
-      data1 = link1->data;
+      data1_indirect = got_link1->data;
+      /* this call makes got_link1 invalid */
+      data1 = _dbus_list_pop_last (&list1);
+      _dbus_assert (data1 == data1_indirect);
       data2 = link2->data;
 
-      _dbus_list_free_link (link1);
       _dbus_list_free_link (link2);
       
       _dbus_assert (_DBUS_POINTER_TO_INT (data1) == i);
@@ -1337,31 +1295,6 @@
 
   _dbus_list_clear (&list1);
   _dbus_list_clear (&list2);
-  
-  /* insert_before on empty list */
-  _dbus_list_insert_before (&list1, NULL,
-                            _DBUS_INT_TO_POINTER (0));
-  verify_list (&list1);
-
-  /* inserting before first element */
-  _dbus_list_insert_before (&list1, list1,
-                            _DBUS_INT_TO_POINTER (2));
-  verify_list (&list1);
-  _dbus_assert (is_descending_sequence (&list1));
-
-  /* inserting in the middle */
-  _dbus_list_insert_before (&list1, list1->next,
-                            _DBUS_INT_TO_POINTER (1));
-  verify_list (&list1);
-  _dbus_assert (is_descending_sequence (&list1));  
-
-  /* using insert_before to append */
-  _dbus_list_insert_before (&list1, NULL,
-                            _DBUS_INT_TO_POINTER (-1));
-  verify_list (&list1);
-  _dbus_assert (is_descending_sequence (&list1));
-  
-  _dbus_list_clear (&list1);
 
   /* insert_after on empty list */
   _dbus_list_insert_after (&list1, NULL,
diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h
index 663ad25..910d738 100644
--- a/dbus/dbus-list.h
+++ b/dbus/dbus-list.h
@@ -69,7 +69,6 @@
 void*       _dbus_list_pop_first          (DBusList **list);
 void*       _dbus_list_pop_last           (DBusList **list);
 DBusList*   _dbus_list_pop_first_link     (DBusList **list);
-DBusList*   _dbus_list_pop_last_link      (DBusList **list);
 dbus_bool_t _dbus_list_copy               (DBusList **list,
                                            DBusList **dest);
 int         _dbus_list_get_length         (DBusList **list);
@@ -84,8 +83,6 @@
 dbus_bool_t _dbus_list_length_is_one      (DBusList **list);
 
 
-
-
 void _dbus_list_foreach (DBusList            **list,
                          DBusForeachFunction   function,
                          void                 *data);
@@ -93,6 +90,11 @@
 #define _dbus_list_get_next_link(list, link) ((link)->next == *(list) ? NULL : (link)->next)
 #define _dbus_list_get_prev_link(list, link) ((link) == *(list) ? NULL : (link)->prev)
 
+/* if DBUS_ENABLE_STATS */
+void        _dbus_list_get_stats          (dbus_uint32_t *in_use_p,
+                                           dbus_uint32_t *in_free_list_p,
+                                           dbus_uint32_t *allocated_p);
+
 DBUS_END_DECLS
 
 #endif /* DBUS_LIST_H */
diff --git a/dbus/dbus-macros.h b/dbus/dbus-macros.h
index d1e40ec..dcd3eeb 100644
--- a/dbus/dbus-macros.h
+++ b/dbus/dbus-macros.h
@@ -74,6 +74,20 @@
 #define _DBUS_GNUC_NORETURN
 #endif  /* !__GNUC__ */
 
+#if    __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#define DBUS_MALLOC     __attribute__((__malloc__))
+#else
+#define DBUS_MALLOC
+#endif
+
+#if     (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+#define DBUS_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+#define DBUS_ALLOC_SIZE2(x,y) __attribute__((__alloc_size__(x,y)))
+#else
+#define DBUS_ALLOC_SIZE(x)
+#define DBUS_ALLOC_SIZE2(x,y)
+#endif
+
 /** @def _DBUS_GNUC_PRINTF
  * used to tell gcc about printf format strings
  */
diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c
index 96ba599..cef676a 100644
--- a/dbus/dbus-mainloop.c
+++ b/dbus/dbus-mainloop.c
@@ -1,7 +1,8 @@
 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-mainloop.c  Main loop utility
  *
- * Copyright (C) 2003, 2004  Red Hat, Inc.
+ * Copyright © 2003, 2004  Red Hat, Inc.
+ * Copyright © 2011 Nokia Corporation
  *
  * Licensed under the Academic Free License version 2.1
  * 
@@ -26,8 +27,10 @@
 
 #ifndef DOXYGEN_SHOULD_SKIP_THIS
 
+#include <dbus/dbus-hash.h>
 #include <dbus/dbus-list.h>
-#include <dbus/dbus-sysdeps.h>
+#include <dbus/dbus-socket-set.h>
+#include <dbus/dbus-watch.h>
 
 #define MAINLOOP_SPEW 0
 
@@ -55,77 +58,31 @@
 struct DBusLoop
 {
   int refcount;
-  DBusList *callbacks;
+  /** fd => dbus_malloc'd DBusList ** of references to DBusWatch */
+  DBusHashTable *watches;
+  DBusSocketSet *socket_set;
+  DBusList *timeouts;
   int callback_list_serial;
   int watch_count;
   int timeout_count;
   int depth; /**< number of recursive runs */
   DBusList *need_dispatch;
+  /** TRUE if we will skip a watch next time because it was OOM; becomes
+   * FALSE between polling, and dealing with the results of the poll */
+  unsigned oom_watch_pending : 1;
 };
 
-typedef enum
-{
-  CALLBACK_WATCH,
-  CALLBACK_TIMEOUT
-} CallbackType;
-
 typedef struct
 {
-  int refcount;
-  CallbackType type;
-  void *data;
-  DBusFreeFunction free_data_func;
-} Callback;
-
-typedef struct
-{
-  Callback callback;
-  DBusWatchFunction function;
-  DBusWatch *watch;
-  /* last watch handle failed due to OOM */
-  unsigned int last_iteration_oom : 1;
-} WatchCallback;
-
-typedef struct
-{
-  Callback callback;
   DBusTimeout *timeout;
-  DBusTimeoutFunction function;
   unsigned long last_tv_sec;
   unsigned long last_tv_usec;
 } TimeoutCallback;
 
-#define WATCH_CALLBACK(callback)   ((WatchCallback*)callback)
 #define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback)
 
-static WatchCallback*
-watch_callback_new (DBusWatch         *watch,
-                    DBusWatchFunction  function,
-                    void              *data,
-                    DBusFreeFunction   free_data_func)
-{
-  WatchCallback *cb;
-
-  cb = dbus_new (WatchCallback, 1);
-  if (cb == NULL)
-    return NULL;
-
-  cb->watch = watch;
-  cb->function = function;
-  cb->last_iteration_oom = FALSE;
-  cb->callback.refcount = 1;
-  cb->callback.type = CALLBACK_WATCH;
-  cb->callback.data = data;
-  cb->callback.free_data_func = free_data_func;
-  
-  return cb;
-}
-
 static TimeoutCallback*
-timeout_callback_new (DBusTimeout         *timeout,
-                      DBusTimeoutFunction  function,
-                      void                *data,
-                      DBusFreeFunction     free_data_func)
+timeout_callback_new (DBusTimeout         *timeout)
 {
   TimeoutCallback *cb;
 
@@ -134,84 +91,37 @@
     return NULL;
 
   cb->timeout = timeout;
-  cb->function = function;
-  _dbus_get_current_time (&cb->last_tv_sec,
-                          &cb->last_tv_usec);
-  cb->callback.refcount = 1;    
-  cb->callback.type = CALLBACK_TIMEOUT;
-  cb->callback.data = data;
-  cb->callback.free_data_func = free_data_func;
-  
-  return cb;
-}
-
-static Callback * 
-callback_ref (Callback *cb)
-{
-  _dbus_assert (cb->refcount > 0);
-  
-  cb->refcount += 1;
-
+  _dbus_get_monotonic_time (&cb->last_tv_sec,
+                            &cb->last_tv_usec);
   return cb;
 }
 
 static void
-callback_unref (Callback *cb)
+timeout_callback_free (TimeoutCallback *cb)
 {
-  _dbus_assert (cb->refcount > 0);
-
-  cb->refcount -= 1;
-
-  if (cb->refcount == 0)
-    {
-      if (cb->free_data_func)
-        (* cb->free_data_func) (cb->data);
-      
-      dbus_free (cb);
-    }
-}
-
-static dbus_bool_t
-add_callback (DBusLoop  *loop,
-              Callback *cb)
-{
-  if (!_dbus_list_append (&loop->callbacks, cb))
-    return FALSE;
-
-  loop->callback_list_serial += 1;
-
-  switch (cb->type)
-    {
-    case CALLBACK_WATCH:
-      loop->watch_count += 1;
-      break;
-    case CALLBACK_TIMEOUT:
-      loop->timeout_count += 1;
-      break;
-    }
-  
-  return TRUE;
+  dbus_free (cb);
 }
 
 static void
-remove_callback (DBusLoop  *loop,
-                 DBusList *link)
+free_watch_table_entry (void *data)
 {
-  Callback *cb = link->data;
-  
-  switch (cb->type)
+  DBusList **watches = data;
+  DBusWatch *watch;
+
+  /* DBusHashTable sometimes calls free_function(NULL) even if you never
+   * have NULL as a value */
+  if (watches == NULL)
+    return;
+
+  for (watch = _dbus_list_pop_first (watches);
+      watch != NULL;
+      watch = _dbus_list_pop_first (watches))
     {
-    case CALLBACK_WATCH:
-      loop->watch_count -= 1;
-      break;
-    case CALLBACK_TIMEOUT:
-      loop->timeout_count -= 1;
-      break;
+      _dbus_watch_unref (watch);
     }
-  
-  callback_unref (cb);
-  _dbus_list_remove_link (&loop->callbacks, link);
-  loop->callback_list_serial += 1;
+
+  _dbus_assert (*watches == NULL);
+  dbus_free (watches);
 }
 
 DBusLoop*
@@ -223,8 +133,25 @@
   if (loop == NULL)
     return NULL;
 
+  loop->watches = _dbus_hash_table_new (DBUS_HASH_INT, NULL,
+                                        free_watch_table_entry);
+
+  loop->socket_set = _dbus_socket_set_new (0);
+
+  if (loop->watches == NULL || loop->socket_set == NULL)
+    {
+      if (loop->watches != NULL)
+        _dbus_hash_table_unref (loop->watches);
+
+      if (loop->socket_set != NULL)
+        _dbus_socket_set_free (loop->socket_set);
+
+      dbus_free (loop);
+      return NULL;
+    }
+
   loop->refcount = 1;
-  
+
   return loop;
 }
 
@@ -254,82 +181,229 @@
 
           dbus_connection_unref (connection);
         }
-      
+
+      _dbus_hash_table_unref (loop->watches);
+      _dbus_socket_set_free (loop->socket_set);
       dbus_free (loop);
     }
 }
 
-dbus_bool_t
-_dbus_loop_add_watch (DBusLoop          *loop,
-                      DBusWatch        *watch,
-                      DBusWatchFunction  function,
-                      void             *data,
-                      DBusFreeFunction  free_data_func)
+static DBusList **
+ensure_watch_table_entry (DBusLoop *loop,
+                          int       fd)
 {
-  WatchCallback *wcb;
+  DBusList **watches;
 
-  wcb = watch_callback_new (watch, function, data, free_data_func);
-  if (wcb == NULL)
+  watches = _dbus_hash_table_lookup_int (loop->watches, fd);
+
+  if (watches == NULL)
+    {
+      watches = dbus_new0 (DBusList *, 1);
+
+      if (watches == NULL)
+        return watches;
+
+      if (!_dbus_hash_table_insert_int (loop->watches, fd, watches))
+        {
+          dbus_free (watches);
+          watches = NULL;
+        }
+    }
+
+  return watches;
+}
+
+static void
+cull_watches_for_invalid_fd (DBusLoop  *loop,
+                             int        fd)
+{
+  DBusList *link;
+  DBusList **watches;
+
+  _dbus_warn ("invalid request, socket fd %d not open\n", fd);
+  watches = _dbus_hash_table_lookup_int (loop->watches, fd);
+
+  if (watches != NULL)
+    {
+      for (link = _dbus_list_get_first_link (watches);
+          link != NULL;
+          link = _dbus_list_get_next_link (watches, link))
+        _dbus_watch_invalidate (link->data);
+    }
+
+  _dbus_hash_table_remove_int (loop->watches, fd);
+}
+
+static dbus_bool_t
+gc_watch_table_entry (DBusLoop  *loop,
+                      DBusList **watches,
+                      int        fd)
+{
+  /* If watches is already NULL we have nothing to do */
+  if (watches == NULL)
     return FALSE;
 
-  if (!add_callback (loop, (Callback*) wcb))
+  /* We can't GC hash table entries if they're non-empty lists */
+  if (*watches != NULL)
+    return FALSE;
+
+  _dbus_hash_table_remove_int (loop->watches, fd);
+  return TRUE;
+}
+
+static void
+refresh_watches_for_fd (DBusLoop  *loop,
+                        DBusList **watches,
+                        int        fd)
+{
+  DBusList *link;
+  unsigned int flags = 0;
+  dbus_bool_t interested = FALSE;
+
+  _dbus_assert (fd != -1);
+
+  if (watches == NULL)
+    watches = _dbus_hash_table_lookup_int (loop->watches, fd);
+
+  /* we allocated this in the first _dbus_loop_add_watch for the fd, and keep
+   * it until there are none left */
+  _dbus_assert (watches != NULL);
+
+  for (link = _dbus_list_get_first_link (watches);
+      link != NULL;
+      link = _dbus_list_get_next_link (watches, link))
     {
-      wcb->callback.free_data_func = NULL; /* don't want to have this side effect */
-      callback_unref ((Callback*) wcb);
+      if (dbus_watch_get_enabled (link->data) &&
+          !_dbus_watch_get_oom_last_time (link->data))
+        {
+          flags |= dbus_watch_get_flags (link->data);
+          interested = TRUE;
+        }
+    }
+
+  if (interested)
+    _dbus_socket_set_enable (loop->socket_set, fd, flags);
+  else
+    _dbus_socket_set_disable (loop->socket_set, fd);
+}
+
+dbus_bool_t
+_dbus_loop_add_watch (DBusLoop  *loop,
+                      DBusWatch *watch)
+{
+  int fd;
+  DBusList **watches;
+
+  fd = dbus_watch_get_socket (watch);
+  _dbus_assert (fd != -1);
+
+  watches = ensure_watch_table_entry (loop, fd);
+
+  if (watches == NULL)
+    return FALSE;
+
+  if (!_dbus_list_append (watches, _dbus_watch_ref (watch)))
+    {
+      _dbus_watch_unref (watch);
+      gc_watch_table_entry (loop, watches, fd);
+
       return FALSE;
     }
-  
+
+  if (_dbus_list_length_is_one (watches))
+    {
+      if (!_dbus_socket_set_add (loop->socket_set, fd,
+                                 dbus_watch_get_flags (watch),
+                                 dbus_watch_get_enabled (watch)))
+        {
+          _dbus_hash_table_remove_int (loop->watches, fd);
+          return FALSE;
+        }
+    }
+  else
+    {
+      /* we're modifying, not adding, which can't fail with OOM */
+      refresh_watches_for_fd (loop, watches, fd);
+    }
+
+  loop->callback_list_serial += 1;
+  loop->watch_count += 1;
   return TRUE;
 }
 
 void
-_dbus_loop_remove_watch (DBusLoop          *loop,
-                         DBusWatch        *watch,
-                         DBusWatchFunction  function,
-                         void             *data)
+_dbus_loop_toggle_watch (DBusLoop          *loop,
+                         DBusWatch         *watch)
 {
+  refresh_watches_for_fd (loop, NULL, dbus_watch_get_socket (watch));
+}
+
+void
+_dbus_loop_remove_watch (DBusLoop         *loop,
+                         DBusWatch        *watch)
+{
+  DBusList **watches;
   DBusList *link;
-  
-  link = _dbus_list_get_first_link (&loop->callbacks);
-  while (link != NULL)
+  int fd;
+
+  /* This relies on people removing watches before they invalidate them,
+   * which has been safe since fd.o #33336 was fixed. Assert about it
+   * so we don't regress. */
+  fd = dbus_watch_get_socket (watch);
+  _dbus_assert (fd != -1);
+
+  watches = _dbus_hash_table_lookup_int (loop->watches, fd);
+
+  if (watches != NULL)
     {
-      DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
-      Callback *this = link->data;
-
-      if (this->type == CALLBACK_WATCH &&
-          WATCH_CALLBACK (this)->watch == watch &&
-          this->data == data &&
-          WATCH_CALLBACK (this)->function == function)
+      link = _dbus_list_get_first_link (watches);
+      while (link != NULL)
         {
-          remove_callback (loop, link);
-          
-          return;
-        }
-      
-      link = next;
-    }
+          DBusList *next = _dbus_list_get_next_link (watches, link);
+          DBusWatch *this = link->data;
 
-  _dbus_warn ("could not find watch %p function %p data %p to remove\n",
-              watch, (void *)function, data);
+          if (this == watch)
+            {
+              _dbus_list_remove_link (watches, link);
+              loop->callback_list_serial += 1;
+              loop->watch_count -= 1;
+              _dbus_watch_unref (this);
+
+              /* if that was the last watch for that fd, drop the hash table
+               * entry, and stop reserving space for it in the socket set */
+              if (gc_watch_table_entry (loop, watches, fd))
+                {
+                  _dbus_socket_set_remove (loop->socket_set, fd);
+                }
+
+              return;
+            }
+
+          link = next;
+         }
+     }
+
+  _dbus_warn ("could not find watch %p to remove\n", watch);
 }
 
 dbus_bool_t
-_dbus_loop_add_timeout (DBusLoop            *loop,
-                        DBusTimeout        *timeout,
-                        DBusTimeoutFunction  function,
-                        void               *data,
-                        DBusFreeFunction    free_data_func)
+_dbus_loop_add_timeout (DBusLoop           *loop,
+                        DBusTimeout        *timeout)
 {
   TimeoutCallback *tcb;
 
-  tcb = timeout_callback_new (timeout, function, data, free_data_func);
+  tcb = timeout_callback_new (timeout);
   if (tcb == NULL)
     return FALSE;
 
-  if (!add_callback (loop, (Callback*) tcb))
+  if (_dbus_list_append (&loop->timeouts, tcb))
     {
-      tcb->callback.free_data_func = NULL; /* don't want to have this side effect */
-      callback_unref ((Callback*) tcb);
+      loop->callback_list_serial += 1;
+      loop->timeout_count += 1;
+    }
+  else
+    {
+      timeout_callback_free (tcb);
       return FALSE;
     }
   
@@ -337,34 +411,31 @@
 }
 
 void
-_dbus_loop_remove_timeout (DBusLoop            *loop,
-                           DBusTimeout        *timeout,
-                           DBusTimeoutFunction  function,
-                           void               *data)
+_dbus_loop_remove_timeout (DBusLoop           *loop,
+                           DBusTimeout        *timeout)
 {
   DBusList *link;
   
-  link = _dbus_list_get_first_link (&loop->callbacks);
+  link = _dbus_list_get_first_link (&loop->timeouts);
   while (link != NULL)
     {
-      DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
-      Callback *this = link->data;
+      DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
+      TimeoutCallback *this = link->data;
 
-      if (this->type == CALLBACK_TIMEOUT &&
-          TIMEOUT_CALLBACK (this)->timeout == timeout &&
-          this->data == data &&
-          TIMEOUT_CALLBACK (this)->function == function)
+      if (this->timeout == timeout)
         {
-          remove_callback (loop, link);
-          
+          _dbus_list_remove_link (&loop->timeouts, link);
+          loop->callback_list_serial += 1;
+          loop->timeout_count -= 1;
+          timeout_callback_free (this);
+
           return;
         }
       
       link = next;
     }
 
-  _dbus_warn ("could not find timeout %p function %p data %p to remove\n",
-              timeout, (void *)function, data);
+  _dbus_warn ("could not find timeout %p to remove\n", timeout);
 }
 
 /* Convolutions from GLib, there really must be a better way
@@ -521,141 +592,43 @@
 {  
 #define N_STACK_DESCRIPTORS 64
   dbus_bool_t retval;
-  DBusPollFD *fds;
-  DBusPollFD stack_fds[N_STACK_DESCRIPTORS];
-  int n_fds;
-  WatchCallback **watches_for_fds;
-  WatchCallback *stack_watches_for_fds[N_STACK_DESCRIPTORS];
+  DBusSocketEvent ready_fds[N_STACK_DESCRIPTORS];
   int i;
   DBusList *link;
   int n_ready;
   int initial_serial;
   long timeout;
-  dbus_bool_t oom_watch_pending;
   int orig_depth;
-  
+
   retval = FALSE;      
 
-  fds = NULL;
-  watches_for_fds = NULL;
-  n_fds = 0;
-  oom_watch_pending = FALSE;
   orig_depth = loop->depth;
   
 #if MAINLOOP_SPEW
   _dbus_verbose ("Iteration block=%d depth=%d timeout_count=%d watch_count=%d\n",
                  block, loop->depth, loop->timeout_count, loop->watch_count);
 #endif
-  
-  if (loop->callbacks == NULL)
+
+  if (_dbus_hash_table_get_n_entries (loop->watches) == 0 &&
+      loop->timeouts == NULL)
     goto next_iteration;
 
-  if (loop->watch_count > N_STACK_DESCRIPTORS)
-    {
-      fds = dbus_new0 (DBusPollFD, loop->watch_count);
-      
-      while (fds == NULL)
-        {
-          _dbus_wait_for_memory ();
-          fds = dbus_new0 (DBusPollFD, loop->watch_count);
-        }
-      
-      watches_for_fds = dbus_new (WatchCallback*, loop->watch_count);
-      while (watches_for_fds == NULL)
-        {
-          _dbus_wait_for_memory ();
-          watches_for_fds = dbus_new (WatchCallback*, loop->watch_count);
-        }
-    }
-  else
-    {      
-      fds = stack_fds;
-      watches_for_fds = stack_watches_for_fds;
-    }
-
-  /* fill our array of fds and watches */
-  n_fds = 0;
-  link = _dbus_list_get_first_link (&loop->callbacks);
-  while (link != NULL)
-    {
-      DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
-      Callback *cb = link->data;
-      if (cb->type == CALLBACK_WATCH)
-        {
-          unsigned int flags;
-          WatchCallback *wcb = WATCH_CALLBACK (cb);
-
-          if (wcb->last_iteration_oom)
-            {
-              /* we skip this one this time, but reenable it next time,
-               * and have a timeout on this iteration
-               */
-              wcb->last_iteration_oom = FALSE;
-              oom_watch_pending = TRUE;
-              
-              retval = TRUE; /* return TRUE here to keep the loop going,
-                              * since we don't know the watch is inactive
-                              */
-
-#if MAINLOOP_SPEW
-              _dbus_verbose ("  skipping watch on fd %d as it was out of memory last time\n",
-                             dbus_watch_get_socket (wcb->watch));
-#endif
-            }
-          else if (dbus_watch_get_enabled (wcb->watch))
-            {
-              watches_for_fds[n_fds] = wcb;
-
-              callback_ref (cb);
-                  
-              flags = dbus_watch_get_flags (wcb->watch);
-                  
-              fds[n_fds].fd = dbus_watch_get_socket (wcb->watch);
-              fds[n_fds].revents = 0;
-              fds[n_fds].events = 0;
-              if (flags & DBUS_WATCH_READABLE)
-                fds[n_fds].events |= _DBUS_POLLIN;
-              if (flags & DBUS_WATCH_WRITABLE)
-                fds[n_fds].events |= _DBUS_POLLOUT;
-
-#if MAINLOOP_SPEW
-              _dbus_verbose ("  polling watch on fd %d  %s\n",
-                             fds[n_fds].fd, watch_flags_to_string (flags));
-#endif
-
-              n_fds += 1;
-            }
-          else
-            {
-#if MAINLOOP_SPEW
-              _dbus_verbose ("  skipping disabled watch on fd %d  %s\n",
-                             dbus_watch_get_socket (wcb->watch),
-                             watch_flags_to_string (dbus_watch_get_flags (wcb->watch)));
-#endif
-            }
-        }
-              
-      link = next;
-    }
-  
   timeout = -1;
   if (loop->timeout_count > 0)
     {
       unsigned long tv_sec;
       unsigned long tv_usec;
       
-      _dbus_get_current_time (&tv_sec, &tv_usec);
-          
-      link = _dbus_list_get_first_link (&loop->callbacks);
+      _dbus_get_monotonic_time (&tv_sec, &tv_usec);
+
+      link = _dbus_list_get_first_link (&loop->timeouts);
       while (link != NULL)
         {
-          DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
-          Callback *cb = link->data;
+          DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
+          TimeoutCallback *tcb = link->data;
 
-          if (cb->type == CALLBACK_TIMEOUT &&
-              dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout))
+          if (dbus_timeout_get_enabled (tcb->timeout))
             {
-              TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb);
               int msecs_remaining;
 
               check_timeout (tv_sec, tv_usec, tcb, &msecs_remaining);
@@ -676,7 +649,7 @@
                 break; /* it's not going to get shorter... */
             }
 #if MAINLOOP_SPEW
-          else if (cb->type == CALLBACK_TIMEOUT)
+          else
             {
               _dbus_verbose ("  skipping disabled timeout\n");
             }
@@ -695,17 +668,58 @@
 #endif
     }
 
-  /* if a watch is OOM, don't wait longer than the OOM
+  /* if a watch was OOM last time, don't wait longer than the OOM
    * wait to re-enable it
    */
-  if (oom_watch_pending)
+  if (loop->oom_watch_pending)
     timeout = MIN (timeout, _dbus_get_oom_wait ());
 
 #if MAINLOOP_SPEW
   _dbus_verbose ("  polling on %d descriptors timeout %ld\n", n_fds, timeout);
 #endif
-  
-  n_ready = _dbus_poll (fds, n_fds, timeout);
+
+  n_ready = _dbus_socket_set_poll (loop->socket_set, ready_fds,
+                                   _DBUS_N_ELEMENTS (ready_fds), timeout);
+
+  /* re-enable any watches we skipped this time */
+  if (loop->oom_watch_pending)
+    {
+      DBusHashIter hash_iter;
+
+      loop->oom_watch_pending = FALSE;
+
+      _dbus_hash_iter_init (loop->watches, &hash_iter);
+
+      while (_dbus_hash_iter_next (&hash_iter))
+        {
+          DBusList **watches;
+          int fd;
+          dbus_bool_t changed;
+
+          changed = FALSE;
+          fd = _dbus_hash_iter_get_int_key (&hash_iter);
+          watches = _dbus_hash_iter_get_value (&hash_iter);
+
+          for (link = _dbus_list_get_first_link (watches);
+              link != NULL;
+              link = _dbus_list_get_next_link (watches, link))
+            {
+              DBusWatch *watch = link->data;
+
+              if (_dbus_watch_get_oom_last_time (watch))
+                {
+                  _dbus_watch_set_oom_last_time (watch, FALSE);
+                  changed = TRUE;
+                }
+            }
+
+          if (changed)
+            refresh_watches_for_fd (loop, watches, fd);
+        }
+
+      retval = TRUE; /* return TRUE here to keep the loop going,
+                      * since we don't know the watch was inactive */
+    }
 
   initial_serial = loop->callback_list_serial;
 
@@ -714,25 +728,23 @@
       unsigned long tv_sec;
       unsigned long tv_usec;
 
-      _dbus_get_current_time (&tv_sec, &tv_usec);
+      _dbus_get_monotonic_time (&tv_sec, &tv_usec);
 
       /* It'd be nice to avoid this O(n) thingy here */
-      link = _dbus_list_get_first_link (&loop->callbacks);
+      link = _dbus_list_get_first_link (&loop->timeouts);
       while (link != NULL)
         {
-          DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link);
-          Callback *cb = link->data;
+          DBusList *next = _dbus_list_get_next_link (&loop->timeouts, link);
+          TimeoutCallback *tcb = link->data;
 
           if (initial_serial != loop->callback_list_serial)
             goto next_iteration;
 
           if (loop->depth != orig_depth)
             goto next_iteration;
-              
-          if (cb->type == CALLBACK_TIMEOUT &&
-              dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout))
+
+          if (dbus_timeout_get_enabled (tcb->timeout))
             {
-              TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb);
               int msecs_remaining;
               
               if (check_timeout (tv_sec, tv_usec,
@@ -745,9 +757,11 @@
 #if MAINLOOP_SPEW
                   _dbus_verbose ("  invoking timeout\n");
 #endif
-                  
-                  (* tcb->function) (tcb->timeout,
-                                     cb->data);
+
+                  /* can theoretically return FALSE on OOM, but we just
+                   * let it fire again later - in practice that's what
+                   * every wrapper callback in dbus-daemon used to do */
+                  dbus_timeout_handle (tcb->timeout);
 
                   retval = TRUE;
                 }
@@ -759,7 +773,7 @@
                 }
             }
 #if MAINLOOP_SPEW
-          else if (cb->type == CALLBACK_TIMEOUT)
+          else
             {
               _dbus_verbose ("  skipping invocation of disabled timeout\n");
             }
@@ -768,12 +782,16 @@
           link = next;
         }
     }
-      
+
   if (n_ready > 0)
     {
-      i = 0;
-      while (i < n_fds)
+      for (i = 0; i < n_ready; i++)
         {
+          DBusList **watches;
+          DBusList *next;
+          unsigned int condition;
+          dbus_bool_t any_oom;
+
           /* FIXME I think this "restart if we change the watches"
            * approach could result in starving watches
            * toward the end of the list.
@@ -784,45 +802,73 @@
           if (loop->depth != orig_depth)
             goto next_iteration;
 
-          if (fds[i].revents != 0)
-            {
-              WatchCallback *wcb;
-              unsigned int condition;
-                  
-              wcb = watches_for_fds[i];
-              
-              condition = 0;
-              if (fds[i].revents & _DBUS_POLLIN)
-                condition |= DBUS_WATCH_READABLE;
-              if (fds[i].revents & _DBUS_POLLOUT)
-                condition |= DBUS_WATCH_WRITABLE;
-              if (fds[i].revents & _DBUS_POLLHUP)
-                condition |= DBUS_WATCH_HANGUP;
-              if (fds[i].revents & _DBUS_POLLERR)
-                condition |= DBUS_WATCH_ERROR;
+          _dbus_assert (ready_fds[i].flags != 0);
 
-              /* condition may still be 0 if we got some
-               * weird POLLFOO thing like POLLWRBAND
-               */
-                  
-              if (condition != 0 &&
-                  dbus_watch_get_enabled (wcb->watch))
+          if (_DBUS_UNLIKELY (ready_fds[i].flags & _DBUS_WATCH_NVAL))
+            {
+              cull_watches_for_invalid_fd (loop, ready_fds[i].fd);
+              goto next_iteration;
+            }
+
+          condition = ready_fds[i].flags;
+          _dbus_assert ((condition & _DBUS_WATCH_NVAL) == 0);
+
+          /* condition may still be 0 if we got some
+           * weird POLLFOO thing like POLLWRBAND
+           */
+          if (condition == 0)
+            continue;
+
+          watches = _dbus_hash_table_lookup_int (loop->watches,
+                                                 ready_fds[i].fd);
+
+          if (watches == NULL)
+            continue;
+
+          any_oom = FALSE;
+
+          for (link = _dbus_list_get_first_link (watches);
+              link != NULL;
+              link = next)
+            {
+              DBusWatch *watch = link->data;
+
+              next = _dbus_list_get_next_link (watches, link);
+
+              if (dbus_watch_get_enabled (watch))
                 {
-                  if (!(* wcb->function) (wcb->watch,
-                                          condition,
-                                          ((Callback*)wcb)->data))
-                    wcb->last_iteration_oom = TRUE;
+                  dbus_bool_t oom;
+
+                  oom = !dbus_watch_handle (watch, condition);
+
+                  if (oom)
+                    {
+                      _dbus_watch_set_oom_last_time (watch, TRUE);
+                      loop->oom_watch_pending = TRUE;
+                      any_oom = TRUE;
+                    }
 
 #if MAINLOOP_SPEW
-                  _dbus_verbose ("  Invoked watch, oom = %d\n",
-                                 wcb->last_iteration_oom);
+                  _dbus_verbose ("  Invoked watch, oom = %d\n", oom);
 #endif
-                  
                   retval = TRUE;
+
+                  /* We re-check this every time, in case the callback
+                   * added/removed watches, which might make our position in
+                   * the linked list invalid. See the FIXME above. */
+                  if (initial_serial != loop->callback_list_serial ||
+                      loop->depth != orig_depth)
+                    {
+                      if (any_oom)
+                        refresh_watches_for_fd (loop, NULL, ready_fds[i].fd);
+
+                      goto next_iteration;
+                    }
                 }
             }
-              
-          ++i;
+
+          if (any_oom)
+            refresh_watches_for_fd (loop, watches, ready_fds[i].fd);
         }
     }
       
@@ -830,22 +876,7 @@
 #if MAINLOOP_SPEW
   _dbus_verbose ("  moving to next iteration\n");
 #endif
-  
-  if (fds && fds != stack_fds)
-    dbus_free (fds);
-  if (watches_for_fds)
-    {
-      i = 0;
-      while (i < n_fds)
-        {
-          callback_unref (&watches_for_fds[i]->callback);
-          ++i;
-        }
-      
-      if (watches_for_fds != stack_watches_for_fds)
-        dbus_free (watches_for_fds);
-    }
-  
+
   if (_dbus_loop_dispatch (loop))
     retval = TRUE;
   
diff --git a/dbus/dbus-mainloop.h b/dbus/dbus-mainloop.h
index 656f823..a76cb6f 100644
--- a/dbus/dbus-mainloop.h
+++ b/dbus/dbus-mainloop.h
@@ -33,30 +33,20 @@
 typedef dbus_bool_t (* DBusWatchFunction)   (DBusWatch     *watch,
                                              unsigned int   condition,
                                              void          *data);
-typedef void        (* DBusTimeoutFunction) (DBusTimeout   *timeout,
-                                             void          *data);
 
 DBusLoop*   _dbus_loop_new            (void);
 DBusLoop*   _dbus_loop_ref            (DBusLoop            *loop);
 void        _dbus_loop_unref          (DBusLoop            *loop);
 dbus_bool_t _dbus_loop_add_watch      (DBusLoop            *loop,
-                                       DBusWatch           *watch,
-                                       DBusWatchFunction    function,
-                                       void                *data,
-                                       DBusFreeFunction     free_data_func);
+                                       DBusWatch           *watch);
 void        _dbus_loop_remove_watch   (DBusLoop            *loop,
-                                       DBusWatch           *watch,
-                                       DBusWatchFunction    function,
-                                       void                *data);
+                                       DBusWatch           *watch);
+void        _dbus_loop_toggle_watch   (DBusLoop            *loop,
+                                       DBusWatch           *watch);
 dbus_bool_t _dbus_loop_add_timeout    (DBusLoop            *loop,
-                                       DBusTimeout         *timeout,
-                                       DBusTimeoutFunction  function,
-                                       void                *data,
-                                       DBusFreeFunction     free_data_func);
+                                       DBusTimeout         *timeout);
 void        _dbus_loop_remove_timeout (DBusLoop            *loop,
-                                       DBusTimeout         *timeout,
-                                       DBusTimeoutFunction  function,
-                                       void                *data);
+                                       DBusTimeout         *timeout);
 
 dbus_bool_t _dbus_loop_queue_dispatch (DBusLoop            *loop,
                                        DBusConnection      *connection);
diff --git a/dbus/dbus-marshal-basic.c b/dbus/dbus-marshal-basic.c
index ea18dbf..88b19f3 100644
--- a/dbus/dbus-marshal-basic.c
+++ b/dbus/dbus-marshal-basic.c
@@ -29,6 +29,49 @@
 
 #include <string.h>
 
+#if defined(__GNUC__) && (__GNUC__ >= 4)
+# define _DBUS_ASSERT_ALIGNMENT(type, op, val) \
+  _DBUS_STATIC_ASSERT (__extension__ __alignof__ (type) op val)
+#else
+  /* not gcc, so probably no alignof operator: just use a no-op statement
+   * that's valid in the same contexts */
+# define _DBUS_ASSERT_ALIGNMENT(type, op, val) \
+  _DBUS_STATIC_ASSERT (TRUE)
+#endif
+
+/* True by definition, but just for completeness... */
+_DBUS_STATIC_ASSERT (sizeof (char) == 1);
+_DBUS_ASSERT_ALIGNMENT (char, ==, 1);
+
+_DBUS_STATIC_ASSERT (sizeof (dbus_int16_t) == 2);
+_DBUS_ASSERT_ALIGNMENT (dbus_int16_t, <=, 2);
+_DBUS_STATIC_ASSERT (sizeof (dbus_uint16_t) == 2);
+_DBUS_ASSERT_ALIGNMENT (dbus_uint16_t, <=, 2);
+
+_DBUS_STATIC_ASSERT (sizeof (dbus_int32_t) == 4);
+_DBUS_ASSERT_ALIGNMENT (dbus_int32_t, <=, 4);
+_DBUS_STATIC_ASSERT (sizeof (dbus_uint32_t) == 4);
+_DBUS_ASSERT_ALIGNMENT (dbus_uint32_t, <=, 4);
+_DBUS_STATIC_ASSERT (sizeof (dbus_bool_t) == 4);
+_DBUS_ASSERT_ALIGNMENT (dbus_bool_t, <=, 4);
+
+_DBUS_STATIC_ASSERT (sizeof (double) == 8);
+_DBUS_ASSERT_ALIGNMENT (double, <=, 8);
+
+#ifdef DBUS_HAVE_INT64
+_DBUS_STATIC_ASSERT (sizeof (dbus_int64_t) == 8);
+_DBUS_ASSERT_ALIGNMENT (dbus_int64_t, <=, 8);
+_DBUS_STATIC_ASSERT (sizeof (dbus_uint64_t) == 8);
+_DBUS_ASSERT_ALIGNMENT (dbus_uint64_t, <=, 8);
+#endif
+
+_DBUS_STATIC_ASSERT (sizeof (DBusBasicValue) >= 8);
+/* The alignment of a DBusBasicValue might conceivably be > 8 because of the
+ * pointer, so we don't assert about it */
+
+_DBUS_STATIC_ASSERT (sizeof (DBus8ByteStruct) == 8);
+_DBUS_ASSERT_ALIGNMENT (DBus8ByteStruct, <=, 8);
+
 /**
  * @defgroup DBusMarshal marshaling and unmarshaling
  * @ingroup  DBusInternals
@@ -83,7 +126,7 @@
   else
     *((dbus_uint64_t*)(data)) = DBUS_UINT64_TO_BE (value.u64);
 #else
-  *(DBus8ByteStruct*)data = value.u64;
+  *(DBus8ByteStruct*)data = value.eight;
   swap_8_octets ((DBusBasicValue*)data, byte_order);
 #endif
 }
@@ -133,7 +176,7 @@
 #ifdef DBUS_HAVE_INT64
       value->u64 = DBUS_UINT64_SWAP_LE_BE (value->u64);
 #else
-      swap_bytes ((unsigned char *)value, 8);
+      swap_bytes (&value->bytes, 8);
 #endif
     }
 }
@@ -154,7 +197,7 @@
   else
     r.u64 = DBUS_UINT64_FROM_BE (*(dbus_uint64_t*)data);
 #else
-  r.u64 = *(DBus8ByteStruct*)data;
+  r.eight = *(DBus8ByteStruct*)data;
   swap_8_octets (&r, byte_order);
 #endif
 
@@ -1065,8 +1108,6 @@
     case DBUS_TYPE_INT16:
     case DBUS_TYPE_UINT16:
       return marshal_fixed_multi (str, insert_at, vp, n_elements, byte_order, 2, pos_after);
-      /* FIXME: we canonicalize to 0 or 1 for the single boolean case
-       * should we here too ? */
     case DBUS_TYPE_BOOLEAN:
     case DBUS_TYPE_INT32:
     case DBUS_TYPE_UINT32:
@@ -1233,44 +1274,6 @@
     }
 }
 
-
-/**
- * Return #TRUE if the typecode is a valid typecode.
- * #DBUS_TYPE_INVALID surprisingly enough is not considered valid, and
- * random unknown bytes aren't either. This function is safe with
- * untrusted data.
- *
- * @returns #TRUE if valid
- */
-dbus_bool_t
-_dbus_type_is_valid (int typecode)
-{
-  switch (typecode)
-    {
-    case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_BOOLEAN:
-    case DBUS_TYPE_INT16:
-    case DBUS_TYPE_UINT16:
-    case DBUS_TYPE_INT32:
-    case DBUS_TYPE_UINT32:
-    case DBUS_TYPE_INT64:
-    case DBUS_TYPE_UINT64:
-    case DBUS_TYPE_DOUBLE:
-    case DBUS_TYPE_STRING:
-    case DBUS_TYPE_OBJECT_PATH:
-    case DBUS_TYPE_SIGNATURE:
-    case DBUS_TYPE_ARRAY:
-    case DBUS_TYPE_STRUCT:
-    case DBUS_TYPE_DICT_ENTRY:
-    case DBUS_TYPE_VARIANT:
-    case DBUS_TYPE_UNIX_FD:
-      return TRUE;
-
-    default:
-      return FALSE;
-    }
-}
-
 /**
  * Returns a string describing the given type.
  *
diff --git a/dbus/dbus-marshal-basic.h b/dbus/dbus-marshal-basic.h
index 0c27fc9..034fdab 100644
--- a/dbus/dbus-marshal-basic.h
+++ b/dbus/dbus-marshal-basic.h
@@ -146,40 +146,6 @@
 #  define DBUS_UINT64_FROM_BE(val) (DBUS_UINT64_TO_BE (val))
 #endif /* DBUS_HAVE_INT64 */
 
-#ifndef DBUS_HAVE_INT64
-/**
- * An 8-byte struct you could use to access int64 without having
- * int64 support
- */
-typedef struct
-{
-  dbus_uint32_t first32;  /**< first 32 bits in the 8 bytes (beware endian issues) */
-  dbus_uint32_t second32; /**< second 32 bits in the 8 bytes (beware endian issues) */
-} DBus8ByteStruct;
-#endif /* DBUS_HAVE_INT64 */
-
-/**
- * A simple 8-byte value union that lets you access 8 bytes as if they
- * were various types; useful when dealing with basic types via
- * void pointers and varargs.
- */
-typedef union
-{
-  dbus_int16_t  i16;   /**< as int16 */
-  dbus_uint16_t u16;   /**< as int16 */
-  dbus_int32_t  i32;   /**< as int32 */
-  dbus_uint32_t u32;   /**< as int32 */
-#ifdef DBUS_HAVE_INT64
-  dbus_int64_t  i64;   /**< as int64 */
-  dbus_uint64_t u64;   /**< as int64 */
-#else
-  DBus8ByteStruct u64; /**< as 8-byte-struct */
-#endif
-  double dbl;          /**< as double */
-  unsigned char byt;   /**< as byte */
-  char *str;           /**< as char* */
-} DBusBasicValue;
-
 #ifdef DBUS_DISABLE_ASSERT
 #define _dbus_unpack_uint16(byte_order, data)           \
    (((byte_order) == DBUS_LITTLE_ENDIAN) ?              \
@@ -254,9 +220,7 @@
                                                int               pos,
                                                int               byte_order,
                                                int              *new_pos);
-dbus_bool_t   _dbus_type_is_valid             (int               typecode);
 int           _dbus_type_get_alignment        (int               typecode);
-dbus_bool_t   _dbus_type_is_fixed             (int               typecode);
 int           _dbus_type_get_alignment        (int               typecode);
 const char*   _dbus_type_to_string            (int               typecode);
 
diff --git a/dbus/dbus-marshal-header.c b/dbus/dbus-marshal-header.c
index 3f31d7a..88887a8 100644
--- a/dbus/dbus-marshal-header.c
+++ b/dbus/dbus-marshal-header.c
@@ -165,6 +165,20 @@
 }
 
 /**
+ * Returns the header's byte order.
+ *
+ * @param header the header
+ * @returns the byte order
+ */
+char
+_dbus_header_get_byte_order (const DBusHeader *header)
+{
+  _dbus_assert (_dbus_string_get_length (&header->data) > BYTE_ORDER_OFFSET);
+
+  return (char) _dbus_string_get_byte (&header->data, BYTE_ORDER_OFFSET);
+}
+
+/**
  * Revalidates the fields cache
  *
  * @param header the header
@@ -184,7 +198,7 @@
     }
 
   _dbus_type_reader_init (&reader,
-                          header->byte_order,
+                          _dbus_header_get_byte_order (header),
                           &_dbus_header_signature_str,
                           FIELDS_ARRAY_SIGNATURE_OFFSET,
                           &header->data,
@@ -398,7 +412,7 @@
   _dbus_marshal_set_uint32 (&header->data,
                             SERIAL_OFFSET,
 			    serial,
-                            header->byte_order);
+                            _dbus_header_get_byte_order (header));
 }
 
 /**
@@ -412,7 +426,7 @@
 {
   return _dbus_marshal_read_uint32 (&header->data,
                                     SERIAL_OFFSET,
-                                    header->byte_order,
+                                    _dbus_header_get_byte_order (header),
                                     NULL);
 }
 
@@ -422,15 +436,12 @@
  * _dbus_header_create().
  *
  * @param header header to re-initialize
- * @param byte_order byte order of the header
  */
 void
-_dbus_header_reinit (DBusHeader *header,
-                     int         byte_order)
+_dbus_header_reinit (DBusHeader *header)
 {
   _dbus_string_set_length (&header->data, 0);
 
-  header->byte_order = byte_order;
   header->padding = 0;
 
   _dbus_header_cache_invalidate_all (header);
@@ -445,13 +456,12 @@
  * @returns #FALSE if not enough memory
  */
 dbus_bool_t
-_dbus_header_init (DBusHeader *header,
-                   int         byte_order)
+_dbus_header_init (DBusHeader *header)
 {
   if (!_dbus_string_init_preallocated (&header->data, 32))
     return FALSE;
 
-  _dbus_header_reinit (header, byte_order);
+  _dbus_header_reinit (header);
 
   return TRUE;
 }
@@ -514,6 +524,7 @@
  */
 dbus_bool_t
 _dbus_header_create (DBusHeader  *header,
+                     int          byte_order,
                      int          message_type,
                      const char  *destination,
                      const char  *path,
@@ -526,6 +537,8 @@
   DBusTypeWriter writer;
   DBusTypeWriter array;
 
+  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
+                byte_order == DBUS_BIG_ENDIAN);
   _dbus_assert (((interface || message_type != DBUS_MESSAGE_TYPE_SIGNAL) && member) ||
                 (error_name) ||
                 !(interface || member || error_name));
@@ -534,12 +547,12 @@
   if (!reserve_header_padding (header))
     return FALSE;
 
-  _dbus_type_writer_init_values_only (&writer, header->byte_order,
+  _dbus_type_writer_init_values_only (&writer, byte_order,
                                       &_dbus_header_signature_str, 0,
                                       &header->data,
                                       HEADER_END_BEFORE_PADDING (header));
 
-  v_BYTE = header->byte_order;
+  v_BYTE = byte_order;
   if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE,
                                       &v_BYTE))
     goto oom;
@@ -911,7 +924,8 @@
       _dbus_assert (bad_string_code != DBUS_VALID);
 
       len = _dbus_marshal_read_uint32 (value_str, value_pos,
-                                       header->byte_order, NULL);
+                                       _dbus_header_get_byte_order (header),
+                                       NULL);
 
 #if 0
       _dbus_verbose ("Validating string header field; code %d if fails\n",
@@ -1042,7 +1056,6 @@
   _dbus_type_reader_next (&reader);
 
   _dbus_assert (v_byte == byte_order);
-  header->byte_order = byte_order;
 
   /* MESSAGE TYPE */
   _dbus_assert (_dbus_type_reader_get_current_type (&reader) == DBUS_TYPE_BYTE);
@@ -1184,9 +1197,22 @@
   _dbus_marshal_set_uint32 (&header->data,
                             BODY_LENGTH_OFFSET,
                             body_len,
-                            header->byte_order);
+                            _dbus_header_get_byte_order (header));
 }
 
+/**
+ * Try to find the given field.
+ *
+ * @param header the header
+ * @param field the field code
+ * @param reader a type reader; on success this is left pointing at the struct
+ *  (uv) for the field, while on failure it is left pointing into empty space
+ *  at the end of the header fields
+ * @param realign_root another type reader; on success or failure it is left
+ *  pointing to the beginning of the array of fields (i.e. the thing that might
+ *  need realigning)
+ * @returns #TRUE on success
+ */
 static dbus_bool_t
 find_field_for_modification (DBusHeader     *header,
                              int             field,
@@ -1198,7 +1224,7 @@
   retval = FALSE;
 
   _dbus_type_reader_init (realign_root,
-                          header->byte_order,
+                          _dbus_header_get_byte_order (header),
                           &_dbus_header_signature_str,
                           FIELDS_ARRAY_SIGNATURE_OFFSET,
                           &header->data,
@@ -1271,7 +1297,7 @@
       DBusTypeWriter array;
 
       _dbus_type_writer_init_values_only (&writer,
-                                          header->byte_order,
+                                          _dbus_header_get_byte_order (header),
                                           &_dbus_header_signature_str,
                                           FIELDS_ARRAY_SIGNATURE_OFFSET,
                                           &header->data,
@@ -1341,7 +1367,7 @@
 
   _dbus_marshal_read_basic (&header->data,
                             header->fields[field].value_pos,
-                            type, value, header->byte_order,
+                            type, value, _dbus_header_get_byte_order (header),
                             NULL);
 
   return TRUE;
@@ -1468,28 +1494,19 @@
 _dbus_header_byteswap (DBusHeader *header,
                        int         new_order)
 {
-  if (header->byte_order == new_order)
+  char byte_order;
+
+  byte_order = _dbus_header_get_byte_order (header);
+
+  if (byte_order == new_order)
     return;
 
   _dbus_marshal_byteswap (&_dbus_header_signature_str,
-                          0, header->byte_order,
+                          0, byte_order,
                           new_order,
                           &header->data, 0);
 
-  header->byte_order = new_order;
+  _dbus_string_set_byte (&header->data, BYTE_ORDER_OFFSET, new_order);
 }
 
 /** @} */
-
-#ifdef DBUS_BUILD_TESTS
-#include "dbus-test.h"
-#include <stdio.h>
-
-dbus_bool_t
-_dbus_marshal_header_test (void)
-{
-
-  return TRUE;
-}
-
-#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-marshal-header.h b/dbus/dbus-marshal-header.h
index fd16c5f..350fe5c 100644
--- a/dbus/dbus-marshal-header.h
+++ b/dbus/dbus-marshal-header.h
@@ -59,12 +59,11 @@
   dbus_uint32_t byte_order : 8;     /**< byte order of header */
 };
 
-dbus_bool_t   _dbus_header_init                   (DBusHeader        *header,
-                                                   int                byte_order);
+dbus_bool_t   _dbus_header_init                   (DBusHeader        *header);
 void          _dbus_header_free                   (DBusHeader        *header);
-void          _dbus_header_reinit                 (DBusHeader        *header,
-                                                   int                byte_order);
+void          _dbus_header_reinit                 (DBusHeader        *header);
 dbus_bool_t   _dbus_header_create                 (DBusHeader        *header,
+                                                   int                byte_order,
                                                    int                type,
                                                    const char        *destination,
                                                    const char        *path,
@@ -122,6 +121,7 @@
                                                    int                len);
 void          _dbus_header_byteswap               (DBusHeader        *header,
                                                    int                new_order);
+char          _dbus_header_get_byte_order         (const DBusHeader  *header);
 
 
 
diff --git a/dbus/dbus-marshal-recursive-util.c b/dbus/dbus-marshal-recursive-util.c
index 3508bb0..9512414 100644
--- a/dbus/dbus-marshal-recursive-util.c
+++ b/dbus/dbus-marshal-recursive-util.c
@@ -38,8 +38,8 @@
 #ifdef DBUS_HAVE_INT64
   value->u64 = 0;
 #else
-  value->u64.first32 = 0;
-  value->u64.second32 = 0;
+  value->eight.first32 = 0;
+  value->eight.second32 = 0;
 #endif
 }
 
@@ -59,8 +59,8 @@
 #ifdef DBUS_HAVE_INT64
       return lhs->u64 == rhs->u64;
 #else
-      return lhs->u64.first32 == rhs->u64.first32 &&
-        lhs->u64.second32 == rhs->u64.second32;
+      return lhs->eight.first32 == rhs->eight.first32 &&
+        lhs->eight.second32 == rhs->eight.second32;
 #endif
     }
 }
@@ -1924,6 +1924,14 @@
     node_destroy (node);
   }
 
+  if (_dbus_getenv ("DBUS_TEST_SLOW") == NULL ||
+      atoi (_dbus_getenv ("DBUS_TEST_SLOW")) < 1)
+    {
+      fprintf (stderr, "skipping remaining marshal-recursive tests, "
+          "run with DBUS_TEST_SLOW=1 (or more) to enable\n");
+      goto out;
+    }
+
   start_next_test ("Each container of each container of each value %d iterations\n",
                    N_CONTAINERS * N_CONTAINERS * N_VALUES);
   for (i = 0; i < N_CONTAINERS; i++)
@@ -1996,8 +2004,15 @@
       node_destroy (outer_container);
     }
 
-#if 0
-  /* This one takes a really long time, so comment it out for now */
+  /* This one takes a really long time (10 minutes on a Core2), so only enable
+   * it if you're really sure */
+  if (atoi (_dbus_getenv ("DBUS_TEST_SLOW")) < 2)
+    {
+      fprintf (stderr, "skipping really slow marshal-recursive test, "
+          "run with DBUS_TEST_SLOW=2 (or more) to enable\n");
+      goto out;
+    }
+
   start_next_test ("Each value,value,value triplet combination as toplevel, in all orders %d iterations\n",
                    N_VALUES * N_VALUES * N_VALUES);
   {
@@ -2021,8 +2036,8 @@
         node_destroy (nodes[0]);
       }
   }
-#endif /* #if 0 expensive test */
 
+out:
   fprintf (stderr, "%d total iterations of recursive marshaling tests\n",
            n_iterations_completed_total);
   fprintf (stderr, "each iteration ran at initial offsets 0 through %d in both big and little endian\n",
@@ -3326,7 +3341,6 @@
   DBusString dict_entry_signature;
   int i;
   int n_entries;
-  int entry_value_type;
   TestTypeNode *child;
 
   n_entries = node->klass->subclass_detail;
@@ -3363,9 +3377,7 @@
   if (!_dbus_string_append_byte (&dict_entry_signature,
                                  DBUS_DICT_ENTRY_END_CHAR))
     goto oom;
-  
-  entry_value_type = _dbus_first_type_in_signature (&entry_value_signature, 0);
-  
+
   if (!_dbus_type_writer_recurse (writer, DBUS_TYPE_ARRAY,
                                   &dict_entry_signature, 0,
                                   &sub))
diff --git a/dbus/dbus-marshal-recursive.c b/dbus/dbus-marshal-recursive.c
index cb10854..4adfd2e 100644
--- a/dbus/dbus-marshal-recursive.c
+++ b/dbus/dbus-marshal-recursive.c
@@ -32,6 +32,18 @@
  * @{
  */
 
+static dbus_bool_t _dbus_type_reader_greater_than              (const DBusTypeReader  *lhs,
+                                                                const DBusTypeReader  *rhs);
+
+static void       _dbus_type_writer_set_enabled           (DBusTypeWriter        *writer,
+                                                           dbus_bool_t            enabled);
+static dbus_bool_t _dbus_type_writer_write_reader_partial (DBusTypeWriter        *writer,
+                                                           DBusTypeReader        *reader,
+                                                           const DBusTypeReader  *start_after,
+                                                           int                    start_after_new_pos,
+                                                           int                    start_after_new_len,
+                                                           DBusList             **fixups);
+
 /** turn this on to get deluged in TypeReader verbose spam */
 #define RECURSIVE_MARSHAL_READ_TRACE  0
 
@@ -1428,7 +1440,7 @@
   return retval;
 }
 
-/**
+/*
  * Compares two readers, which must be iterating over the same value data.
  * Returns #TRUE if the first parameter is further along than the second parameter.
  *
@@ -1436,7 +1448,7 @@
  * @param rhs left-hand-side (first) parameter
  * @returns whether lhs is greater than rhs
  */
-dbus_bool_t
+static dbus_bool_t
 _dbus_type_reader_greater_than (const DBusTypeReader  *lhs,
                                 const DBusTypeReader  *rhs)
 {
@@ -2627,7 +2639,7 @@
   return FALSE;
 }
 
-/**
+/*
  * Iterate through all values in the given reader, writing a copy of
  * each value to the writer.  The reader will be moved forward to its
  * end position.
@@ -2658,7 +2670,7 @@
  * @param fixups list to append #DBusArrayLenFixup if the write was partial
  * @returns #FALSE if no memory
  */
-dbus_bool_t
+static dbus_bool_t
 _dbus_type_writer_write_reader_partial (DBusTypeWriter       *writer,
                                         DBusTypeReader       *reader,
                                         const DBusTypeReader *start_after,
@@ -2719,7 +2731,7 @@
   return _dbus_type_writer_write_reader_partial (writer, reader, NULL, 0, 0, NULL);
 }
 
-/**
+/*
  * If disabled, a writer can still be iterated forward and recursed/unrecursed
  * but won't write any values. Types will still be written unless the
  * writer is a "values only" writer, because the writer needs access to
@@ -2728,7 +2740,7 @@
  * @param writer the type writer
  * @param enabled #TRUE if values should be written
  */
-void
+static void
 _dbus_type_writer_set_enabled (DBusTypeWriter   *writer,
                                dbus_bool_t       enabled)
 {
diff --git a/dbus/dbus-marshal-recursive.h b/dbus/dbus-marshal-recursive.h
index 97e5466..acbfd73 100644
--- a/dbus/dbus-marshal-recursive.h
+++ b/dbus/dbus-marshal-recursive.h
@@ -129,8 +129,6 @@
                                                          const DBusTypeReader  *realign_root);
 dbus_bool_t _dbus_type_reader_delete                    (DBusTypeReader        *reader,
                                                          const DBusTypeReader  *realign_root);
-dbus_bool_t _dbus_type_reader_greater_than              (const DBusTypeReader  *lhs,
-                                                         const DBusTypeReader  *rhs);
 
 dbus_bool_t _dbus_type_reader_equal_values              (const DBusTypeReader *lhs,
                                                          const DBusTypeReader *rhs);
@@ -178,14 +176,6 @@
                                                     DBusTypeWriter        *sub);
 dbus_bool_t _dbus_type_writer_write_reader         (DBusTypeWriter        *writer,
                                                     DBusTypeReader        *reader);
-dbus_bool_t _dbus_type_writer_write_reader_partial (DBusTypeWriter        *writer,
-                                                    DBusTypeReader        *reader,
-                                                    const DBusTypeReader  *start_after,
-                                                    int                    start_after_new_pos,
-                                                    int                    start_after_new_len,
-                                                    DBusList             **fixups);
-void        _dbus_type_writer_set_enabled          (DBusTypeWriter        *writer,
-                                                    dbus_bool_t            enabled);
 
 
 #endif /* DBUS_MARSHAL_RECURSIVE_H */
diff --git a/dbus/dbus-marshal-validate.c b/dbus/dbus-marshal-validate.c
index b457997..9187a3e 100644
--- a/dbus/dbus-marshal-validate.c
+++ b/dbus/dbus-marshal-validate.c
@@ -250,7 +250,7 @@
 
       if (last == DBUS_DICT_ENTRY_BEGIN_CHAR)
         {
-          if (!(_dbus_type_is_valid (*p) && dbus_type_is_basic (*p)))
+          if (!(dbus_type_is_valid (*p) && dbus_type_is_basic (*p)))
             {
               result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE;
               goto out;
@@ -393,7 +393,7 @@
               {
                 int array_elem_type = _dbus_type_reader_get_element_type (reader);
 
-                if (!_dbus_type_is_valid (array_elem_type))
+                if (!dbus_type_is_valid (array_elem_type))
                   {
                     return DBUS_INVALID_UNKNOWN_TYPECODE;
                   }
@@ -1082,23 +1082,11 @@
     ((c) >= 'a' && (c) <= 'z') ||               \
     ((c) == '_') || ((c) == '-'))
 
-/**
- * Checks that the given range of the string is a valid bus name in
- * the D-Bus protocol. This includes a length restriction, etc., see
- * the specification.
- *
- * @todo this is inconsistent with most of DBusString in that
- * it allows a start,len range that extends past the string end.
- *
- * @param str the string
- * @param start first byte index to check
- * @param len number of bytes to check
- * @returns #TRUE if the byte range exists and is a valid name
- */
-dbus_bool_t
-_dbus_validate_bus_name (const DBusString  *str,
-                         int                start,
-                         int                len)
+static dbus_bool_t
+_dbus_validate_bus_name_full (const DBusString  *str,
+                              int                start,
+                              int                len,
+                              dbus_bool_t        is_namespace)
 {
   const unsigned char *s;
   const unsigned char *end;
@@ -1176,13 +1164,55 @@
       ++s;
     }
 
-  if (_DBUS_UNLIKELY (last_dot == NULL))
+  if (!is_namespace && _DBUS_UNLIKELY (last_dot == NULL))
     return FALSE;
 
   return TRUE;
 }
 
 /**
+ * Checks that the given range of the string is a valid bus name in
+ * the D-Bus protocol. This includes a length restriction, etc., see
+ * the specification.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that extends past the string end.
+ *
+ * @param str the string
+ * @param start first byte index to check
+ * @param len number of bytes to check
+ * @returns #TRUE if the byte range exists and is a valid name
+ */
+dbus_bool_t
+_dbus_validate_bus_name (const DBusString  *str,
+                         int                start,
+                         int                len)
+{
+  return _dbus_validate_bus_name_full (str, start, len, FALSE);
+}
+
+/**
+ * Checks that the given range of the string is a prefix of a valid bus name in
+ * the D-Bus protocol. Unlike _dbus_validate_bus_name(), this accepts strings
+ * with only one period-separated component.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that extends past the string end.
+ *
+ * @param str the string
+ * @param start first byte index to check
+ * @param len number of bytes to check
+ * @returns #TRUE if the byte range exists and is a valid name
+ */
+dbus_bool_t
+_dbus_validate_bus_namespace (const DBusString  *str,
+                              int                start,
+                              int                len)
+{
+  return _dbus_validate_bus_name_full (str, start, len, TRUE);
+}
+
+/**
  * Checks that the given range of the string is a valid message type
  * signature in the D-Bus protocol.
  *
@@ -1221,6 +1251,8 @@
 DEFINE_DBUS_NAME_CHECK(bus_name)
 /** define _dbus_check_is_valid_signature() */
 DEFINE_DBUS_NAME_CHECK(signature)
+/** define _dbus_check_is_valid_utf8() */
+DEFINE_DBUS_NAME_CHECK(utf8)
 
 /** @} */
 
diff --git a/dbus/dbus-marshal-validate.h b/dbus/dbus-marshal-validate.h
index 8947a2a..0643420 100644
--- a/dbus/dbus-marshal-validate.h
+++ b/dbus/dbus-marshal-validate.h
@@ -144,9 +144,14 @@
 dbus_bool_t _dbus_validate_bus_name   (const DBusString *str,
                                        int               start,
                                        int               len);
+dbus_bool_t _dbus_validate_bus_namespace (const DBusString  *str,
+                                          int                start,
+                                          int                len);
 dbus_bool_t _dbus_validate_signature  (const DBusString *str,
                                        int               start,
                                        int               len);
+/* just to have a name consistent with the above: */
+#define _dbus_validate_utf8(s,b,e) _dbus_string_validate_utf8 (s, b, e)
 
 #ifdef DBUS_DISABLE_CHECKS
 
@@ -193,6 +198,8 @@
 DECLARE_DBUS_NAME_CHECK(bus_name);
 /** defines _dbus_check_is_valid_signature() */
 DECLARE_DBUS_NAME_CHECK(signature);
+/** defines _dbus_check_is_valid_utf8() */
+DECLARE_DBUS_NAME_CHECK(utf8);
 
 /** @} */
 
diff --git a/dbus/dbus-md5.c b/dbus/dbus-md5.c
deleted file mode 100644
index af71d5c..0000000
--- a/dbus/dbus-md5.c
+++ /dev/null
@@ -1,581 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/* dbus-md5.c md5 implementation (based on L Peter Deutsch implementation)
- *
- * Copyright (C) 2003 Red Hat Inc.
- * Copyright (C) 1999, 2000 Aladdin Enterprises.  All rights reserved.
- *
- * This software is provided 'as-is', without any express or implied
- * warranty.  In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- *    claim that you wrote the original software. If you use this software
- *    in a product, an acknowledgment in the product documentation would be
- *    appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- *    misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- *
- * L. Peter Deutsch
- * ghost@aladdin.com
- */
-/*
- * Independent implementation of MD5 (RFC 1321).
- *
- * This code implements the MD5 Algorithm defined in RFC 1321.
- * It is derived directly from the text of the RFC and not from the
- * reference implementation.
- *
- * The original and principal author of md5.c is L. Peter Deutsch
- * <ghost@aladdin.com>.
- */
-
-#include <config.h>
-#include "dbus-internals.h"
-#include "dbus-md5.h"
-#include <string.h>
-
-/**
- * @defgroup DBusMD5 MD5 implementation
- * @ingroup  DBusInternals
- * @brief MD5 hash
- *
- * Types and functions related to computing MD5 sums.
- */
-
-/**
- * @defgroup DBusMD5Internals MD5 implementation details
- * @ingroup  DBusInternals
- * @brief Internals of MD5 implementation.
- *
- * The implementation of MD5 (see http://www.ietf.org/rfc/rfc1321.txt).
- * This MD5 implementation was written by L. Peter Deutsch and
- * is not derived from the RSA reference implementation in the
- * RFC. The version included in D-Bus comes from the Ghostscript
- * 7.05 distribution.
- *
- * @{
- */
-#ifndef DOXYGEN_SHOULD_SKIP_THIS
-/*
- * For reference, here is the program that computed the T values.
- */
-#ifdef COMPUTE_T_VALUES
-#include <math.h>
-int
-main(int argc, char **argv)
-{
-  int i;
-  for (i = 1; i <= 64; ++i)
-    {
-      unsigned long v = (unsigned long)(4294967296.0 * fabs(sin((double)i)));
-
-      /*
-       * The following nonsense is only to avoid compiler warnings about
-       * "integer constant is unsigned in ANSI C, signed with -traditional".
-       */
-      if (v >> 31)
-        {
-          printf("#define T%d /* 0x%08lx */ (T_MASK ^ 0x%08lx)\n", i,
-                 v, (unsigned long)(unsigned int)(~v));
-        } else {
-        printf("#define T%d    0x%08lx\n", i, v);
-      }
-    }
-  return 0;
-}
-#endif /* COMPUTE_T_VALUES */
-/*
- * End of T computation program.
- */
-
-#define T_MASK ((dbus_uint32_t)~0)
-#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
-#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
-#define T3    0x242070db
-#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
-#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
-#define T6    0x4787c62a
-#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
-#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
-#define T9    0x698098d8
-#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
-#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
-#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
-#define T13    0x6b901122
-#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
-#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
-#define T16    0x49b40821
-#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
-#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
-#define T19    0x265e5a51
-#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
-#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
-#define T22    0x02441453
-#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
-#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
-#define T25    0x21e1cde6
-#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
-#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
-#define T28    0x455a14ed
-#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
-#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
-#define T31    0x676f02d9
-#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
-#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
-#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
-#define T35    0x6d9d6122
-#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
-#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
-#define T38    0x4bdecfa9
-#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
-#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
-#define T41    0x289b7ec6
-#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
-#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
-#define T44    0x04881d05
-#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
-#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
-#define T47    0x1fa27cf8
-#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
-#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
-#define T50    0x432aff97
-#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
-#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
-#define T53    0x655b59c3
-#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
-#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
-#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
-#define T57    0x6fa87e4f
-#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
-#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
-#define T60    0x4e0811a1
-#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
-#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
-#define T63    0x2ad7d2bb
-#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
-#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
-
-static void
-md5_process(DBusMD5Context *context, const unsigned char *data /*[64]*/)
-{
-  dbus_uint32_t
-    a = context->abcd[0], b = context->abcd[1],
-    c = context->abcd[2], d = context->abcd[3];
-  dbus_uint32_t t;
-
-#ifdef WORDS_BIGENDIAN
-  /*
-   * On big-endian machines, we must arrange the bytes in the right
-   * order.  (This also works on machines of unknown byte order.)
-   */
-  dbus_uint32_t X[16];
-  const unsigned char *xp = data;
-  int i;
-
-  for (i = 0; i < 16; ++i, xp += 4)
-    X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
-
-#else  /* !WORDS_BIGENDIAN */
-  /*
-   * On little-endian machines, we can process properly aligned data
-   * without copying it.
-   */
-  dbus_uint32_t xbuf[16];
-  const dbus_uint32_t *X;
-
-  if (!((data - (const unsigned char *)0) & 3))
-    {
-      /* data are properly aligned */
-      X = (const dbus_uint32_t *)data;
-    }
-  else
-    {
-      /* not aligned */
-      memcpy(xbuf, data, 64);
-      X = xbuf;
-    }
-#endif
-
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-
-  /* Round 1. */
-  /* Let [abcd k s i] denote the operation
-     a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
-#define SET(a, b, c, d, k, s, Ti)               \
-  t = a + F(b,c,d) + X[k] + Ti;                 \
-  a = ROTATE_LEFT(t, s) + b
-  /* Do the following 16 operations. */
-  SET(a, b, c, d,  0,  7,  T1);
-  SET(d, a, b, c,  1, 12,  T2);
-  SET(c, d, a, b,  2, 17,  T3);
-  SET(b, c, d, a,  3, 22,  T4);
-  SET(a, b, c, d,  4,  7,  T5);
-  SET(d, a, b, c,  5, 12,  T6);
-  SET(c, d, a, b,  6, 17,  T7);
-  SET(b, c, d, a,  7, 22,  T8);
-  SET(a, b, c, d,  8,  7,  T9);
-  SET(d, a, b, c,  9, 12, T10);
-  SET(c, d, a, b, 10, 17, T11);
-  SET(b, c, d, a, 11, 22, T12);
-  SET(a, b, c, d, 12,  7, T13);
-  SET(d, a, b, c, 13, 12, T14);
-  SET(c, d, a, b, 14, 17, T15);
-  SET(b, c, d, a, 15, 22, T16);
-#undef SET
-
-  /* Round 2. */
-  /* Let [abcd k s i] denote the operation
-     a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
-#define SET(a, b, c, d, k, s, Ti)               \
-  t = a + G(b,c,d) + X[k] + Ti;                 \
-  a = ROTATE_LEFT(t, s) + b
-  /* Do the following 16 operations. */
-  SET(a, b, c, d,  1,  5, T17);
-  SET(d, a, b, c,  6,  9, T18);
-  SET(c, d, a, b, 11, 14, T19);
-  SET(b, c, d, a,  0, 20, T20);
-  SET(a, b, c, d,  5,  5, T21);
-  SET(d, a, b, c, 10,  9, T22);
-  SET(c, d, a, b, 15, 14, T23);
-  SET(b, c, d, a,  4, 20, T24);
-  SET(a, b, c, d,  9,  5, T25);
-  SET(d, a, b, c, 14,  9, T26);
-  SET(c, d, a, b,  3, 14, T27);
-  SET(b, c, d, a,  8, 20, T28);
-  SET(a, b, c, d, 13,  5, T29);
-  SET(d, a, b, c,  2,  9, T30);
-  SET(c, d, a, b,  7, 14, T31);
-  SET(b, c, d, a, 12, 20, T32);
-#undef SET
-
-  /* Round 3. */
-  /* Let [abcd k s t] denote the operation
-     a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define SET(a, b, c, d, k, s, Ti)               \
-  t = a + H(b,c,d) + X[k] + Ti;                 \
-  a = ROTATE_LEFT(t, s) + b
-  /* Do the following 16 operations. */
-  SET(a, b, c, d,  5,  4, T33);
-  SET(d, a, b, c,  8, 11, T34);
-  SET(c, d, a, b, 11, 16, T35);
-  SET(b, c, d, a, 14, 23, T36);
-  SET(a, b, c, d,  1,  4, T37);
-  SET(d, a, b, c,  4, 11, T38);
-  SET(c, d, a, b,  7, 16, T39);
-  SET(b, c, d, a, 10, 23, T40);
-  SET(a, b, c, d, 13,  4, T41);
-  SET(d, a, b, c,  0, 11, T42);
-  SET(c, d, a, b,  3, 16, T43);
-  SET(b, c, d, a,  6, 23, T44);
-  SET(a, b, c, d,  9,  4, T45);
-  SET(d, a, b, c, 12, 11, T46);
-  SET(c, d, a, b, 15, 16, T47);
-  SET(b, c, d, a,  2, 23, T48);
-#undef SET
-
-  /* Round 4. */
-  /* Let [abcd k s t] denote the operation
-     a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))
-#define SET(a, b, c, d, k, s, Ti)               \
-  t = a + I(b,c,d) + X[k] + Ti;                 \
-  a = ROTATE_LEFT(t, s) + b
-  /* Do the following 16 operations. */
-  SET(a, b, c, d,  0,  6, T49);
-  SET(d, a, b, c,  7, 10, T50);
-  SET(c, d, a, b, 14, 15, T51);
-  SET(b, c, d, a,  5, 21, T52);
-  SET(a, b, c, d, 12,  6, T53);
-  SET(d, a, b, c,  3, 10, T54);
-  SET(c, d, a, b, 10, 15, T55);
-  SET(b, c, d, a,  1, 21, T56);
-  SET(a, b, c, d,  8,  6, T57);
-  SET(d, a, b, c, 15, 10, T58);
-  SET(c, d, a, b,  6, 15, T59);
-  SET(b, c, d, a, 13, 21, T60);
-  SET(a, b, c, d,  4,  6, T61);
-  SET(d, a, b, c, 11, 10, T62);
-  SET(c, d, a, b,  2, 15, T63);
-  SET(b, c, d, a,  9, 21, T64);
-#undef SET
-
-  /* Then perform the following additions. (That is increment each
-     of the four registers by the value it had before this block
-     was started.) */
-  context->abcd[0] += a;
-  context->abcd[1] += b;
-  context->abcd[2] += c;
-  context->abcd[3] += d;
-}
-
-static void
-md5_init (DBusMD5Context *context)
-{
-  context->count[0] = context->count[1] = 0;
-  context->abcd[0] = 0x67452301;
-  context->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
-  context->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
-  context->abcd[3] = 0x10325476;
-}
-
-static void
-md5_append (DBusMD5Context *context, const unsigned char *data, int nbytes)
-{
-  const unsigned char *p = data;
-  int left = nbytes;
-  int offset = (context->count[0] >> 3) & 63;
-  dbus_uint32_t nbits = (dbus_uint32_t)(nbytes << 3);
-
-  if (nbytes <= 0)
-    return;
-
-  /* Update the message length. */
-  context->count[1] += nbytes >> 29;
-  context->count[0] += nbits;
-  if (context->count[0] < nbits)
-    context->count[1]++;
-
-  /* Process an initial partial block. */
-  if (offset)
-    {
-      int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
-
-      memcpy(context->buf + offset, p, copy);
-      if (offset + copy < 64)
-        return;
-      p += copy;
-      left -= copy;
-      md5_process(context, context->buf);
-    }
-
-  /* Process full blocks. */
-  for (; left >= 64; p += 64, left -= 64)
-    md5_process(context, p);
-
-  /* Process a final partial block. */
-  if (left)
-    memcpy(context->buf, p, left);
-}
-
-static void
-md5_finish (DBusMD5Context *context, unsigned char digest[16])
-{
-  static const unsigned char pad[64] = {
-    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-  };
-  unsigned char data[8];
-  int i;
-
-  /* Save the length before padding. */
-  for (i = 0; i < 8; ++i)
-    data[i] = (unsigned char)(context->count[i >> 2] >> ((i & 3) << 3));
-  /* Pad to 56 bytes mod 64. */
-  md5_append(context, pad, ((55 - (context->count[0] >> 3)) & 63) + 1);
-  /* Append the length. */
-  md5_append(context, data, 8);
-  for (i = 0; i < 16; ++i)
-    digest[i] = (unsigned char)(context->abcd[i >> 2] >> ((i & 3) << 3));
-}
-
-/** @} */ /* End of internals */
-
-/**
- * @addtogroup DBusMD5
- *
- * @{
- */
-
-/**
- * Initializes the MD5 context.
- *
- * @param context an uninitialized context, typically on the stack.
- */
-void
-_dbus_md5_init (DBusMD5Context *context)
-{
-  md5_init (context);
-}
-
-
-/**
- * Feeds more data into an existing md5sum computation.
- *
- * @param context the MD5 context
- * @param data the additional data to hash
- */
-void
-_dbus_md5_update (DBusMD5Context   *context,
-                  const DBusString *data)
-{
-  unsigned int inputLen;
-  unsigned char *input;
-
-  _dbus_string_get_const_data (data, (const char**) &input);
-  inputLen = _dbus_string_get_length (data);
-
-  md5_append (context, input, inputLen);
-}
-
-/**
- * MD5 finalization. Ends an MD5 message-digest operation, writing the
- * the message digest and zeroing the context.  The results are
- * returned as a raw 16-byte digest, not as the ascii-hex-digits
- * string form of the digest.
- *
- * @param context the MD5 context
- * @param results string to append the 16-byte MD5 digest to
- * @returns #FALSE if not enough memory to append the digest
- *
- */
-dbus_bool_t
-_dbus_md5_final (DBusMD5Context   *context,
-                 DBusString       *results)
-{
-  unsigned char digest[16];
-
-  md5_finish (context, digest);
-
-  if (!_dbus_string_append_len (results, digest, 16))
-    return FALSE;
-
-  /* some kind of security paranoia, though it seems pointless
-   * to me given the nonzeroed stuff flying around
-   */
-  _DBUS_ZERO(*context);
-
-  return TRUE;
-}
-
-/**
- * Computes the ASCII hex-encoded md5sum of the given data and
- * appends it to the output string.
- *
- * @param data input data to be hashed
- * @param ascii_output string to append ASCII md5sum to
- * @returns #FALSE if not enough memory
- */
-dbus_bool_t
-_dbus_md5_compute (const DBusString *data,
-                   DBusString       *ascii_output)
-{
-  DBusMD5Context context;
-  DBusString digest;
-
-  _dbus_md5_init (&context);
-
-  _dbus_md5_update (&context, data);
-
-  if (!_dbus_string_init (&digest))
-    return FALSE;
-
-  if (!_dbus_md5_final (&context, &digest))
-    goto error;
-
-  if (!_dbus_string_hex_encode (&digest, 0, ascii_output,
-                                _dbus_string_get_length (ascii_output)))
-    goto error;
-
-  _dbus_string_free (&digest);
-  
-  return TRUE;
-
- error:
-  _dbus_string_free (&digest);
-  return FALSE;
-}
-
-/** @} */ /* end of exported functions */
-
-#ifdef DBUS_BUILD_TESTS
-#include "dbus-test.h"
-#include <stdio.h>
-
-static dbus_bool_t
-check_md5_binary (const unsigned char *input,
-                  int                  input_len,
-                  const char          *expected)
-{
-  DBusString input_str;
-  DBusString expected_str;
-  DBusString results;
-
-  _dbus_string_init_const_len (&input_str, input, input_len);
-  _dbus_string_init_const (&expected_str, expected);
-
-  if (!_dbus_string_init (&results))
-    _dbus_assert_not_reached ("no memory for md5 results");
-
-  if (!_dbus_md5_compute (&input_str, &results))
-    _dbus_assert_not_reached ("no memory for md5 results");
-
-  if (!_dbus_string_equal (&expected_str, &results))
-    {
-      const char *s;
-      _dbus_string_get_const_data (&results, &s);
-      _dbus_warn ("Expected hash %s got %s for md5 sum\n",
-                  expected, s);
-      _dbus_string_free (&results);
-      return FALSE;
-    }
-
-  _dbus_string_free (&results);
-  return TRUE;
-}
-
-static dbus_bool_t
-check_md5_str (const char *input,
-               const char *expected)
-{
-  return check_md5_binary (input, strlen (input), expected);
-}
-
-/**
- * @ingroup DBusMD5Internals
- * Unit test for MD5 computation.
- *
- * @returns #TRUE on success.
- */
-dbus_bool_t
-_dbus_md5_test (void)
-{
-  unsigned char all_bytes[256];
-  int i;
-
-  i = 0;
-  while (i < 256)
-    {
-      all_bytes[i] = i;
-      ++i;
-    }
-
-  if (!check_md5_binary (all_bytes, 256,
-                         "e2c865db4162bed963bfaa9ef6ac18f0"))
-    return FALSE;
-
-#define CHECK(input,expected) if (!check_md5_str (input, expected)) return FALSE
-
-  CHECK ("", "d41d8cd98f00b204e9800998ecf8427e");
-  CHECK ("a", "0cc175b9c0f1b6a831c399e269772661");
-  CHECK ("abc", "900150983cd24fb0d6963f7d28e17f72");
-  CHECK ("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
-  CHECK ("abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
-  CHECK ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
-         "d174ab98d277d9f5a5611c2c9f419d9f");
-  CHECK ("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
-         "57edf4a22be3c955ac49da2e2107b67a");
-
-  return TRUE;
-}
-
-#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-md5.h b/dbus/dbus-md5.h
deleted file mode 100644
index fdc74b3..0000000
--- a/dbus/dbus-md5.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/* dbus-md5.h md5 implementation (based on L Peter Deutsch implementation)
- *
- * Copyright (C) 2003 Red Hat Inc.
- *
- * Licensed under the Academic Free License version 2.1
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-#ifndef DBUS_MD5_H
-#define DBUS_MD5_H
-
-#include <dbus/dbus-macros.h>
-#include <dbus/dbus-errors.h>
-#include <dbus/dbus-string.h>
-
-DBUS_BEGIN_DECLS
-
-typedef struct DBusMD5Context DBusMD5Context;
-
-/**
- * A context used to store the state of the MD5 algorithm
- */
-struct DBusMD5Context
-{
-  dbus_uint32_t count[2];       /**< message length in bits, lsw first */
-  dbus_uint32_t abcd[4];        /**< digest buffer */
-  unsigned char buf[64];        /**< accumulate block */
-};
-
-void        _dbus_md5_init    (DBusMD5Context   *context);
-void        _dbus_md5_update  (DBusMD5Context   *context,
-                               const DBusString *data);
-dbus_bool_t _dbus_md5_final   (DBusMD5Context   *context,
-                               DBusString       *results);
-dbus_bool_t _dbus_md5_compute (const DBusString *data,
-                               DBusString       *ascii_output);
-
-DBUS_END_DECLS
-
-#endif /* DBUS_MD5_H */
diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c
index a37759c..a033b54 100644
--- a/dbus/dbus-memory.c
+++ b/dbus/dbus-memory.c
@@ -106,6 +106,7 @@
 static dbus_bool_t guards = FALSE;
 static dbus_bool_t disable_mem_pools = FALSE;
 static dbus_bool_t backtrace_on_fail_alloc = FALSE;
+static dbus_bool_t malloc_cannot_fail = FALSE;
 static DBusAtomic n_blocks_outstanding = {0};
 
 /** value stored in guard padding for debugging buffer overrun */
@@ -132,7 +133,7 @@
 	{
 	  fail_nth = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_NTH"));
           fail_alloc_counter = fail_nth;
-          _dbus_verbose ("Will fail malloc every %d times\n", fail_nth);
+          _dbus_verbose ("Will fail dbus_malloc every %d times\n", fail_nth);
 	}
       
       if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
@@ -145,7 +146,7 @@
       if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
         {
           guards = TRUE;
-          _dbus_verbose ("Will use malloc guards\n");
+          _dbus_verbose ("Will use dbus_malloc guards\n");
         }
 
       if (_dbus_getenv ("DBUS_DISABLE_MEM_POOLS") != NULL)
@@ -157,7 +158,13 @@
       if (_dbus_getenv ("DBUS_MALLOC_BACKTRACES") != NULL)
         {
           backtrace_on_fail_alloc = TRUE;
-          _dbus_verbose ("Will backtrace on failing a malloc\n");
+          _dbus_verbose ("Will backtrace on failing a dbus_malloc\n");
+        }
+
+      if (_dbus_getenv ("DBUS_MALLOC_CANNOT_FAIL") != NULL)
+        {
+          malloc_cannot_fail = TRUE;
+          _dbus_verbose ("Will abort if system malloc() and friends fail\n");
         }
     }
 }
@@ -233,7 +240,6 @@
 }
 
 #ifdef DBUS_BUILD_TESTS
-static dbus_bool_t called = 0;
 /**
  * Called when about to alloc some memory; if
  * it returns #TRUE, then the allocation should
@@ -248,6 +254,8 @@
   _dbus_initialize_malloc_debug ();
 #ifdef DBUS_WIN_FIXME
   {
+    static dbus_bool_t called = 0;
+
     if (!called)
       {
         _dbus_verbose("TODO: memory allocation testing errors disabled for now\n");
@@ -295,7 +303,7 @@
 int
 _dbus_get_malloc_blocks_outstanding (void)
 {
-  return n_blocks_outstanding.value;
+  return _dbus_atomic_get (&n_blocks_outstanding);
 }
 
 /**
@@ -472,7 +480,15 @@
 
       block = malloc (bytes + GUARD_EXTRA_SIZE);
       if (block)
-	_dbus_atomic_inc (&n_blocks_outstanding);
+        {
+          _dbus_atomic_inc (&n_blocks_outstanding);
+        }
+      else if (malloc_cannot_fail)
+        {
+          _dbus_warn ("out of memory: malloc (%ld + %ld)\n",
+              (long) bytes, (long) GUARD_EXTRA_SIZE);
+          _dbus_abort ();
+        }
       
       return set_guards (block, bytes, SOURCE_MALLOC);
     }
@@ -481,10 +497,19 @@
     {
       void *mem;
       mem = malloc (bytes);
+
 #ifdef DBUS_BUILD_TESTS
       if (mem)
-	_dbus_atomic_inc (&n_blocks_outstanding);
+        {
+          _dbus_atomic_inc (&n_blocks_outstanding);
+        }
+      else if (malloc_cannot_fail)
+        {
+          _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes);
+          _dbus_abort ();
+        }
 #endif
+
       return mem;
     }
 }
@@ -525,8 +550,18 @@
       void *block;
 
       block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
+
       if (block)
-	_dbus_atomic_inc (&n_blocks_outstanding);
+        {
+          _dbus_atomic_inc (&n_blocks_outstanding);
+        }
+      else if (malloc_cannot_fail)
+        {
+          _dbus_warn ("out of memory: calloc (%ld + %ld, 1)\n",
+              (long) bytes, (long) GUARD_EXTRA_SIZE);
+          _dbus_abort ();
+        }
+
       return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
     }
 #endif
@@ -534,10 +569,19 @@
     {
       void *mem;
       mem = calloc (bytes, 1);
+
 #ifdef DBUS_BUILD_TESTS
       if (mem)
-	_dbus_atomic_inc (&n_blocks_outstanding);
+        {
+          _dbus_atomic_inc (&n_blocks_outstanding);
+        }
+      else if (malloc_cannot_fail)
+        {
+          _dbus_warn ("out of memory: calloc (%ld)\n", (long) bytes);
+          _dbus_abort ();
+        }
 #endif
+
       return mem;
     }
 }
@@ -587,8 +631,20 @@
           block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
                            bytes + GUARD_EXTRA_SIZE);
 
-	  old_bytes = *(dbus_uint32_t*)block;
-          if (block && bytes >= old_bytes)
+          if (block == NULL)
+            {
+              if (malloc_cannot_fail)
+                {
+                  _dbus_warn ("out of memory: realloc (%p, %ld + %ld)\n",
+                      memory, (long) bytes, (long) GUARD_EXTRA_SIZE);
+                  _dbus_abort ();
+                }
+
+              return NULL;
+            }
+
+          old_bytes = *(dbus_uint32_t*)block;
+          if (bytes >= old_bytes)
             /* old guards shouldn't have moved */
             check_guards (((unsigned char*)block) + GUARD_START_OFFSET, FALSE);
           
@@ -601,8 +657,16 @@
           block = malloc (bytes + GUARD_EXTRA_SIZE);
 
           if (block)
-	    _dbus_atomic_inc (&n_blocks_outstanding);
-          
+            {
+              _dbus_atomic_inc (&n_blocks_outstanding);
+            }
+          else if (malloc_cannot_fail)
+            {
+              _dbus_warn ("out of memory: malloc (%ld + %ld)\n",
+                  (long) bytes, (long) GUARD_EXTRA_SIZE);
+              _dbus_abort ();
+            }
+
           return set_guards (block, bytes, SOURCE_REALLOC_NULL);   
         }
     }
@@ -611,7 +675,14 @@
     {
       void *mem;
       mem = realloc (memory, bytes);
+
 #ifdef DBUS_BUILD_TESTS
+      if (mem == NULL && malloc_cannot_fail)
+        {
+          _dbus_warn ("out of memory: malloc (%ld)\n", (long) bytes);
+          _dbus_abort ();
+        }
+
       if (memory == NULL && mem != NULL)
 	    _dbus_atomic_inc (&n_blocks_outstanding);
 #endif
@@ -634,10 +705,15 @@
       check_guards (memory, TRUE);
       if (memory)
         {
-	  _dbus_atomic_dec (&n_blocks_outstanding);
-          
-	  _dbus_assert (n_blocks_outstanding.value >= 0);
-          
+#ifdef DBUS_DISABLE_ASSERT
+          _dbus_atomic_dec (&n_blocks_outstanding);
+#else
+          dbus_int32_t old_value;
+
+          old_value = _dbus_atomic_dec (&n_blocks_outstanding);
+          _dbus_assert (old_value >= 1);
+#endif
+
           free (((unsigned char*)memory) - GUARD_START_OFFSET);
         }
       
@@ -648,9 +724,14 @@
   if (memory) /* we guarantee it's safe to free (NULL) */
     {
 #ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_DISABLE_ASSERT
       _dbus_atomic_dec (&n_blocks_outstanding);
-      
-      _dbus_assert (n_blocks_outstanding.value >= 0);
+#else
+      dbus_int32_t old_value;
+
+      old_value = _dbus_atomic_dec (&n_blocks_outstanding);
+      _dbus_assert (old_value >= 1);
+#endif
 #endif
 
       free (memory);
diff --git a/dbus/dbus-memory.h b/dbus/dbus-memory.h
index ea28423..4fd56bd 100644
--- a/dbus/dbus-memory.h
+++ b/dbus/dbus-memory.h
@@ -38,10 +38,18 @@
  */
 
 DBUS_EXPORT
+DBUS_MALLOC
+DBUS_ALLOC_SIZE(1)
 void* dbus_malloc        (size_t bytes);
+
 DBUS_EXPORT
+DBUS_MALLOC
+DBUS_ALLOC_SIZE(1)
 void* dbus_malloc0       (size_t bytes);
+
 DBUS_EXPORT
+DBUS_MALLOC
+DBUS_ALLOC_SIZE(2)
 void* dbus_realloc       (void  *memory,
                           size_t bytes);
 DBUS_EXPORT
diff --git a/dbus/dbus-mempool.c b/dbus/dbus-mempool.c
index 680586b..33aabf9 100644
--- a/dbus/dbus-mempool.c
+++ b/dbus/dbus-mempool.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #include "dbus-mempool.h"
 #include "dbus-internals.h"
+#include "dbus-valgrind-internal.h"
 
 /**
  * @defgroup DBusMemPool memory pools
@@ -171,7 +172,9 @@
 
   _dbus_assert ((pool->block_size %
                  pool->element_size) == 0);
-  
+
+  VALGRIND_CREATE_MEMPOOL (pool, 0, zero_elements)
+
   return pool;
 }
 
@@ -185,6 +188,8 @@
 {
   DBusMemBlock *block;
 
+  VALGRIND_DESTROY_MEMPOOL (pool)
+
   block = pool->blocks;
   while (block != NULL)
     {
@@ -235,6 +240,8 @@
           pool->blocks = block;
           pool->allocated_elements += 1;
 
+          VALGRIND_MEMPOOL_ALLOC (pool, (void *) &block->elements[0],
+              pool->element_size)
           return (void*) &block->elements[0];
         }
       else
@@ -254,11 +261,13 @@
 
           pool->free_elements = pool->free_elements->next;
 
+          VALGRIND_MEMPOOL_ALLOC (pool, element, pool->element_size)
+
           if (pool->zero_elements)
             memset (element, '\0', pool->element_size);
 
           pool->allocated_elements += 1;
-          
+
           return element;
         }
       else
@@ -319,7 +328,8 @@
           pool->blocks->used_so_far += pool->element_size;
 
           pool->allocated_elements += 1;
-          
+
+          VALGRIND_MEMPOOL_ALLOC (pool, element, pool->element_size)
           return element;
         }
     }
@@ -337,6 +347,8 @@
 _dbus_mem_pool_dealloc (DBusMemPool *pool,
                         void        *element)
 {
+  VALGRIND_MEMPOOL_FREE (pool, element)
+
 #ifdef DBUS_BUILD_TESTS
   if (_dbus_disable_mem_pools ())
     {
@@ -380,6 +392,9 @@
       DBusFreedElement *freed;
       
       freed = element;
+      /* used for internal mempool administration */
+      VALGRIND_MAKE_MEM_UNDEFINED (freed, sizeof (freed));
+
       freed->next = pool->free_elements;
       pool->free_elements = freed;
       
@@ -390,6 +405,48 @@
     }
 }
 
+#ifdef DBUS_ENABLE_STATS
+void
+_dbus_mem_pool_get_stats (DBusMemPool   *pool,
+                          dbus_uint32_t *in_use_p,
+                          dbus_uint32_t *in_free_list_p,
+                          dbus_uint32_t *allocated_p)
+{
+  DBusMemBlock *block;
+  DBusFreedElement *freed;
+  dbus_uint32_t in_use = 0;
+  dbus_uint32_t in_free_list = 0;
+  dbus_uint32_t allocated = 0;
+
+  if (pool != NULL)
+    {
+      in_use = pool->element_size * pool->allocated_elements;
+
+      for (freed = pool->free_elements; freed != NULL; freed = freed->next)
+        {
+          in_free_list += pool->element_size;
+        }
+
+      for (block = pool->blocks; block != NULL; block = block->next)
+        {
+          if (block == pool->blocks)
+            allocated += pool->block_size;
+          else
+            allocated += block->used_so_far;
+        }
+    }
+
+  if (in_use_p != NULL)
+    *in_use_p = in_use;
+
+  if (in_free_list_p != NULL)
+    *in_free_list_p = in_free_list;
+
+  if (allocated_p != NULL)
+    *allocated_p = allocated;
+}
+#endif /* DBUS_ENABLE_STATS */
+
 /** @} */
 
 #ifdef DBUS_BUILD_TESTS
diff --git a/dbus/dbus-mempool.h b/dbus/dbus-mempool.h
index afe5247..6693eeb 100644
--- a/dbus/dbus-mempool.h
+++ b/dbus/dbus-mempool.h
@@ -39,6 +39,12 @@
 dbus_bool_t  _dbus_mem_pool_dealloc (DBusMemPool *pool,
                                      void        *element);
 
+/* if DBUS_ENABLE_STATS */
+void         _dbus_mem_pool_get_stats (DBusMemPool   *pool,
+                                       dbus_uint32_t *in_use_p,
+                                       dbus_uint32_t *in_free_list_p,
+                                       dbus_uint32_t *allocated_p);
+
 DBUS_END_DECLS
 
 #endif /* DBUS_MEMPOOL_H */
diff --git a/dbus/dbus-message-factory.c b/dbus/dbus-message-factory.c
index 7ecf827..efa4e02 100644
--- a/dbus/dbus-message-factory.c
+++ b/dbus/dbus-message-factory.c
@@ -27,6 +27,7 @@
 #ifdef DBUS_BUILD_TESTS
 #include "dbus-message-factory.h"
 #include "dbus-message-private.h"
+#include "dbus-signature.h"
 #include "dbus-test.h"
 #include <stdio.h>
 
@@ -169,6 +170,7 @@
   DBusMessage *message;
   DBusString signature;
   DBusString body;
+  char byte_order;
 
   /* Keeping this small makes things go faster */
   message = dbus_message_new_method_call ("o.z.F",
@@ -178,13 +180,15 @@
   if (message == NULL)
     _dbus_assert_not_reached ("oom");
 
+  byte_order = _dbus_header_get_byte_order (&message->header);
+
   set_reply_serial (message);
 
   if (!_dbus_string_init (&signature) || !_dbus_string_init (&body))
     _dbus_assert_not_reached ("oom");
   
   if (dbus_internal_do_not_use_generate_bodies (iter_get_sequence (iter),
-                                                message->byte_order,
+                                                byte_order,
                                                 &signature, &body))
     {
       const char *v_SIGNATURE;
@@ -201,7 +205,7 @@
 
       _dbus_marshal_set_uint32 (&message->header.data, BODY_LENGTH_OFFSET,
                                 _dbus_string_get_length (&message->body),
-                                message->byte_order);
+                                byte_order);
       
       *message_p = message;
     }
@@ -577,15 +581,18 @@
     }
   else if (item_seq == 8)
     {
+      char byte_order;
+
       message = simple_method_call ();
+      byte_order = _dbus_header_get_byte_order (&message->header);
       generate_from_message (data, expected_validity, message);
       
       _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
                                 DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
-                                message->byte_order);
+                                byte_order);
       _dbus_marshal_set_uint32 (data, FIELDS_ARRAY_LENGTH_OFFSET,
                                 DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4,
-                                message->byte_order);
+                                byte_order);
       *expected_validity = DBUS_INVALID_MESSAGE_TOO_LONG;
     }
   else if (item_seq == 9)
@@ -935,6 +942,9 @@
   return TRUE;
 }
 
+#if 0
+/* This is really expensive and doesn't add too much coverage */
+
 static dbus_bool_t
 find_next_typecode (DBusMessageDataIter *iter,
                     DBusString          *data,
@@ -978,7 +988,7 @@
 
       _dbus_assert (byte_seq < _dbus_string_get_length (data));
 
-      if (_dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq)))
+      if (dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq)))
         break;
       else
         iter_next (iter);
@@ -1017,7 +1027,7 @@
   DBUS_TYPE_UNIX_FD,
   255 /* random invalid typecode */
 };
-  
+
 static dbus_bool_t
 generate_typecode_changed (DBusMessageDataIter *iter,
                            DBusString          *data,
@@ -1074,6 +1084,7 @@
   *expected_validity = DBUS_VALIDITY_UNKNOWN;
   return TRUE;
 }
+#endif
 
 typedef struct
 {
diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h
index 870934b..c194873 100644
--- a/dbus/dbus-message-internal.h
+++ b/dbus/dbus-message-internal.h
@@ -30,6 +30,21 @@
 
 DBUS_BEGIN_DECLS
 
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+void _dbus_message_trace_ref (DBusMessage *message,
+                              int          old_refcount,
+                              int          new_refcount,
+                              const char  *why);
+#else
+/* this bypasses any "unused" warnings for the old and new refcount */
+#define _dbus_message_trace_ref(m, o, n, w) \
+  do \
+  {\
+    (void) (o); \
+    (void) (n); \
+  } while (0)
+#endif
+
 typedef struct DBusMessageLoader DBusMessageLoader;
 
 void _dbus_message_get_network_data  (DBusMessage       *message,
@@ -46,8 +61,7 @@
 void        _dbus_message_add_counter_link      (DBusMessage  *message,
                                                  DBusList     *link);
 void        _dbus_message_remove_counter        (DBusMessage  *message,
-                                                 DBusCounter  *counter,
-                                                 DBusList    **link_return);
+                                                 DBusCounter  *counter);
 
 DBusMessageLoader* _dbus_message_loader_new                   (void);
 DBusMessageLoader* _dbus_message_loader_ref                   (DBusMessageLoader  *loader);
@@ -84,6 +98,10 @@
                                                                  long                n);
 long               _dbus_message_loader_get_max_message_unix_fds(DBusMessageLoader  *loader);
 
+typedef struct DBusInitialFDs DBusInitialFDs;
+DBusInitialFDs *_dbus_check_fdleaks_enter (void);
+void            _dbus_check_fdleaks_leave (DBusInitialFDs *fds);
+
 DBUS_END_DECLS
 
 #endif /* DBUS_MESSAGE_INTERNAL_H */
diff --git a/dbus/dbus-message-private.h b/dbus/dbus-message-private.h
index 57888fa..e1578ab 100644
--- a/dbus/dbus-message-private.h
+++ b/dbus/dbus-message-private.h
@@ -102,8 +102,6 @@
 
   DBusString body;   /**< Body network data. */
 
-  char byte_order; /**< Message byte order. */
-
   unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
 
 #ifndef DBUS_DISABLE_CHECKS
@@ -138,9 +136,6 @@
                                                 int              first_arg_type,
                                                 va_list          var_args);
 
-
-void _dbus_check_fdleaks(void);
-
 /** @} */
 
 DBUS_END_DECLS
diff --git a/dbus/dbus-message-util.c b/dbus/dbus-message-util.c
index f972c8a..f785952 100644
--- a/dbus/dbus-message-util.c
+++ b/dbus/dbus-message-util.c
@@ -138,17 +138,26 @@
     }
 }
 
-void
-_dbus_check_fdleaks(void)
-{
-
 #ifdef __linux__
+struct DBusInitialFDs {
+    fd_set set;
+};
+#endif
 
+DBusInitialFDs *
+_dbus_check_fdleaks_enter (void)
+{
+#ifdef __linux__
   DIR *d;
+  DBusInitialFDs *fds;
+
+  /* this is plain malloc so it won't interfere with leak checking */
+  fds = malloc (sizeof (DBusInitialFDs));
+  _dbus_assert (fds != NULL);
 
   /* This works on Linux only */
 
-  if ((d = opendir("/proc/self/fd")))
+  if ((d = opendir ("/proc/self/fd")))
     {
       struct dirent *de;
 
@@ -162,23 +171,75 @@
             continue;
 
           errno = 0;
-          l = strtol(de->d_name, &e, 10);
-          _dbus_assert(errno == 0 && e && !*e);
+          l = strtol (de->d_name, &e, 10);
+          _dbus_assert (errno == 0 && e && !*e);
 
           fd = (int) l;
 
           if (fd < 3)
             continue;
 
-          if (fd == dirfd(d))
+          if (fd == dirfd (d))
             continue;
 
-          _dbus_warn("file descriptor %i leaked in %s.\n", fd, __FILE__);
-          _dbus_assert_not_reached("fdleaks");
+          FD_SET (fd, &fds->set);
         }
 
-      closedir(d);
+      closedir (d);
     }
+
+  return fds;
+#else
+  return NULL;
+#endif
+}
+
+void
+_dbus_check_fdleaks_leave (DBusInitialFDs *fds)
+{
+#ifdef __linux__
+  DIR *d;
+
+  /* This works on Linux only */
+
+  if ((d = opendir ("/proc/self/fd")))
+    {
+      struct dirent *de;
+
+      while ((de = readdir(d)))
+        {
+          long l;
+          char *e = NULL;
+          int fd;
+
+          if (de->d_name[0] == '.')
+            continue;
+
+          errno = 0;
+          l = strtol (de->d_name, &e, 10);
+          _dbus_assert (errno == 0 && e && !*e);
+
+          fd = (int) l;
+
+          if (fd < 3)
+            continue;
+
+          if (fd == dirfd (d))
+            continue;
+
+          if (FD_ISSET (fd, &fds->set))
+            continue;
+
+          _dbus_warn ("file descriptor %i leaked in %s.\n", fd, __FILE__);
+          _dbus_assert_not_reached ("fdleaks");
+        }
+
+      closedir (d);
+    }
+
+  free (fds);
+#else
+  _dbus_assert (fds == NULL);
 #endif
 }
 
@@ -558,8 +619,8 @@
         {
           if (_dbus_string_ends_with_c_str (&filename, ".message"))
             {
-              _dbus_warn ("Could not load %s, message builder language no longer supported\n",
-                          _dbus_string_get_const_data (&filename));
+              printf ("SKIP: Could not load %s, message builder language no longer supported\n",
+                      _dbus_string_get_const_data (&filename));
             }
           
           _dbus_verbose ("Skipping non-.message file %s\n",
@@ -1000,6 +1061,9 @@
   int v_UNIX_FD;
 #endif
   char **decomposed;
+  DBusInitialFDs *initial_fds;
+
+  initial_fds = _dbus_check_fdleaks_enter ();
 
   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
                                           "/org/freedesktop/TestPath",
@@ -1394,7 +1458,8 @@
   _dbus_message_loader_unref (loader);
 
   check_memleaks ();
-  _dbus_check_fdleaks();
+  _dbus_check_fdleaks_leave (initial_fds);
+  initial_fds = _dbus_check_fdleaks_enter ();
 
   /* Check that we can abandon a container */
   message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
@@ -1458,16 +1523,23 @@
   }
 
   check_memleaks ();
-  _dbus_check_fdleaks();
+  _dbus_check_fdleaks_leave (initial_fds);
 
   /* Now load every message in test_data_dir if we have one */
   if (test_data_dir == NULL)
     return TRUE;
 
-  return dbus_internal_do_not_use_foreach_message_file (test_data_dir,
+  initial_fds = _dbus_check_fdleaks_enter ();
+
+  if (!dbus_internal_do_not_use_foreach_message_file (test_data_dir,
                                                         (DBusForeachMessageFileFunc)
                                                         dbus_internal_do_not_use_try_message_file,
-                                                        NULL);  
+                                                        NULL))
+    _dbus_assert_not_reached ("foreach_message_file test failed");
+
+  _dbus_check_fdleaks_leave (initial_fds);
+
+  return TRUE;
 }
 
 #endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index b19697e..71bcee6 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -40,6 +40,10 @@
 
 #include <string.h>
 
+#define _DBUS_TYPE_IS_STRINGLIKE(type) \
+  (type == DBUS_TYPE_STRING || type == DBUS_TYPE_SIGNATURE || \
+   type == DBUS_TYPE_OBJECT_PATH)
+
 static void dbus_message_finalize (DBusMessage *message);
 
 /**
@@ -52,6 +56,51 @@
  * @{
  */
 
+#ifdef DBUS_BUILD_TESTS
+static dbus_bool_t
+_dbus_enable_message_cache (void)
+{
+  static int enabled = -1;
+
+  if (enabled < 0)
+    {
+      const char *s = _dbus_getenv ("DBUS_MESSAGE_CACHE");
+
+      enabled = TRUE;
+
+      if (s && *s)
+        {
+          if (*s == '0')
+            enabled = FALSE;
+          else if (*s == '1')
+            enabled = TRUE;
+          else
+            _dbus_warn ("DBUS_MESSAGE_CACHE should be 0 or 1 if set, not '%s'",
+                s);
+        }
+    }
+
+  return enabled;
+}
+#else
+    /* constant expression, should be optimized away */
+#   define _dbus_enable_message_cache() (TRUE)
+#endif
+
+#ifndef _dbus_message_trace_ref
+void
+_dbus_message_trace_ref (DBusMessage *message,
+                         int          old_refcount,
+                         int          new_refcount,
+                         const char  *why)
+{
+  static int enabled = -1;
+
+  _dbus_trace_ref ("DBusMessage", message, old_refcount, new_refcount, why,
+      "DBUS_MESSAGE_TRACE", &enabled);
+}
+#endif
+
 /* Not thread locked, but strictly const/read-only so should be OK
  */
 /** An static string representing an empty signature */
@@ -115,8 +164,11 @@
 {
   const DBusString *type_str;
   int type_pos;
-  
-  if (message->byte_order == DBUS_COMPILER_BYTE_ORDER)
+  char byte_order;
+
+  byte_order = _dbus_header_get_byte_order (&message->header);
+
+  if (byte_order == DBUS_COMPILER_BYTE_ORDER)
     return;
 
   _dbus_verbose ("Swapping message into compiler byte order\n");
@@ -124,13 +176,13 @@
   get_const_signature (&message->header, &type_str, &type_pos);
   
   _dbus_marshal_byteswap (type_str, type_pos,
-                          message->byte_order,
+                          byte_order,
                           DBUS_COMPILER_BYTE_ORDER,
                           &message->body, 0);
 
-  message->byte_order = DBUS_COMPILER_BYTE_ORDER;
-  
   _dbus_header_byteswap (&message->header, DBUS_COMPILER_BYTE_ORDER);
+  _dbus_assert (_dbus_header_get_byte_order (&message->header) ==
+                DBUS_COMPILER_BYTE_ORDER);
 }
 
 /** byte-swap the message if it doesn't match our byte order.
@@ -139,9 +191,7 @@
  *  Otherwise should not be called since it would do needless
  *  work.
  */
-#define ensure_byte_order(message)                      \
- if (message->byte_order != DBUS_COMPILER_BYTE_ORDER)   \
-   _dbus_message_byteswap (message)
+#define ensure_byte_order(message) _dbus_message_byteswap (message)
 
 /**
  * Gets the data to be sent over the network for this message.
@@ -217,6 +267,11 @@
  * itself not incremented.  Ownership of link and counter refcount is
  * passed to the message.
  *
+ * This function may be called with locks held. As a result, the counter's
+ * notify function is not called; the caller is expected to either call
+ * _dbus_counter_notify() on the counter when they are no longer holding
+ * locks, or take the same action that would be taken by the notify function.
+ *
  * @param message the message
  * @param link link with counter as data
  */
@@ -260,6 +315,11 @@
  * of this message, and decremented by the size/unix fds of this
  * message when this message if finalized.
  *
+ * This function may be called with locks held. As a result, the counter's
+ * notify function is not called; the caller is expected to either call
+ * _dbus_counter_notify() on the counter when they are no longer holding
+ * locks, or take the same action that would be taken by the notify function.
+ *
  * @param message the message
  * @param counter the counter
  * @returns #FALSE if no memory
@@ -285,13 +345,11 @@
  * decrements the counter by the size/unix fds of this message.
  *
  * @param message the message
- * @param link_return return the link used
  * @param counter the counter
  */
 void
 _dbus_message_remove_counter (DBusMessage  *message,
-                              DBusCounter  *counter,
-                              DBusList    **link_return)
+                              DBusCounter  *counter)
 {
   DBusList *link;
 
@@ -299,12 +357,7 @@
                                counter);
   _dbus_assert (link != NULL);
 
-  _dbus_list_unlink (&message->counters,
-                     link);
-  if (link_return)
-    *link_return = link;
-  else
-    _dbus_list_free_link (link);
+  _dbus_list_remove_link (&message->counters, link);
 
   _dbus_counter_adjust_size (counter, - message->size_counter_delta);
 
@@ -312,6 +365,7 @@
   _dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta);
 #endif
 
+  _dbus_counter_notify (counter);
   _dbus_counter_unref (counter);
 }
 
@@ -526,7 +580,8 @@
   _dbus_assert (i < MAX_MESSAGE_CACHE_SIZE);
   _dbus_assert (message != NULL);
 
-  _dbus_assert (message->refcount.value == 0);
+  _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
   _dbus_assert (message->counters == NULL);
   
   _DBUS_UNLOCK (message_cache);
@@ -573,6 +628,7 @@
   _dbus_counter_adjust_unix_fd (counter, - message->unix_fd_counter_delta);
 #endif
 
+  _dbus_counter_notify (counter);
   _dbus_counter_unref (counter);
 }
 
@@ -586,8 +642,8 @@
 {
   dbus_bool_t was_cached;
   int i;
-  
-  _dbus_assert (message->refcount.value == 0);
+
+  _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
 
   /* This calls application code and has to be done first thing
    * without holding the lock
@@ -625,6 +681,9 @@
 
   _dbus_assert (message_cache_count >= 0);
 
+  if (!_dbus_enable_message_cache ())
+    goto out;
+
   if ((_dbus_string_get_length (&message->header.data) +
        _dbus_string_get_length (&message->body)) >
       MAX_MESSAGE_SIZE_TO_CACHE)
@@ -649,8 +708,8 @@
 #endif
 
  out:
-  _dbus_assert (message->refcount.value == 0);
-  
+  _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
   _DBUS_UNLOCK (message_cache);
   
   if (!was_cached)
@@ -661,15 +720,19 @@
 static dbus_bool_t
 _dbus_message_iter_check (DBusMessageRealIter *iter)
 {
+  char byte_order;
+
   if (iter == NULL)
     {
       _dbus_warn_check_failed ("dbus message iterator is NULL\n");
       return FALSE;
     }
 
+  byte_order = _dbus_header_get_byte_order (&iter->message->header);
+
   if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_READER)
     {
-      if (iter->u.reader.byte_order != iter->message->byte_order)
+      if (iter->u.reader.byte_order != byte_order)
         {
           _dbus_warn_check_failed ("dbus message changed byte order since iterator was created\n");
           return FALSE;
@@ -679,7 +742,7 @@
     }
   else if (iter->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER)
     {
-      if (iter->u.writer.byte_order != iter->message->byte_order)
+      if (iter->u.writer.byte_order != byte_order)
         {
           _dbus_warn_check_failed ("dbus message changed byte order since append iterator was created\n");
           return FALSE;
@@ -828,9 +891,7 @@
               _dbus_type_reader_read_fixed_multi (&array,
                                                   (void *) ptr, n_elements_p);
             }
-          else if (spec_element_type == DBUS_TYPE_STRING ||
-                   spec_element_type == DBUS_TYPE_SIGNATURE ||
-                   spec_element_type == DBUS_TYPE_OBJECT_PATH)
+          else if (_DBUS_TYPE_IS_STRINGLIKE (spec_element_type))
             {
               char ***str_array_p;
               int n_elements;
@@ -1039,7 +1100,7 @@
 static void
 dbus_message_finalize (DBusMessage *message)
 {
-  _dbus_assert (message->refcount.value == 0);
+  _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
 
   /* This calls application callbacks! */
   _dbus_data_slot_list_free (&message->slot_list);
@@ -1056,8 +1117,8 @@
   dbus_free(message->unix_fds);
 #endif
 
-  _dbus_assert (message->refcount.value == 0);
-  
+  _dbus_assert (_dbus_atomic_get (&message->refcount) == 0);
+
   dbus_free (message);
 }
 
@@ -1076,7 +1137,7 @@
   else
     {
       from_cache = FALSE;
-      message = dbus_new (DBusMessage, 1);
+      message = dbus_new0 (DBusMessage, 1);
       if (message == NULL)
         return NULL;
 #ifndef DBUS_DISABLE_CHECKS
@@ -1088,9 +1149,11 @@
       message->n_unix_fds_allocated = 0;
 #endif
     }
-  
-  message->refcount.value = 1;
-  message->byte_order = DBUS_COMPILER_BYTE_ORDER;
+
+  _dbus_atomic_inc (&message->refcount);
+
+  _dbus_message_trace_ref (message, 0, 1, "new_empty_header");
+
   message->locked = FALSE;
 #ifndef DBUS_DISABLE_CHECKS
   message->in_cache = FALSE;
@@ -1110,12 +1173,12 @@
 
   if (from_cache)
     {
-      _dbus_header_reinit (&message->header, message->byte_order);
+      _dbus_header_reinit (&message->header);
       _dbus_string_set_length (&message->body, 0);
     }
   else
     {
-      if (!_dbus_header_init (&message->header, message->byte_order))
+      if (!_dbus_header_init (&message->header))
         {
           dbus_free (message);
           return NULL;
@@ -1156,6 +1219,7 @@
     return NULL;
 
   if (!_dbus_header_create (&message->header,
+                            DBUS_COMPILER_BYTE_ORDER,
                             message_type,
                             NULL, NULL, NULL, NULL, NULL))
     {
@@ -1209,6 +1273,7 @@
     return NULL;
 
   if (!_dbus_header_create (&message->header,
+                            DBUS_COMPILER_BYTE_ORDER,
                             DBUS_MESSAGE_TYPE_METHOD_CALL,
                             destination, path, interface, method, NULL))
     {
@@ -1243,6 +1308,7 @@
     return NULL;
 
   if (!_dbus_header_create (&message->header,
+                            DBUS_COMPILER_BYTE_ORDER,
                             DBUS_MESSAGE_TYPE_METHOD_RETURN,
                             sender, NULL, NULL, NULL, NULL))
     {
@@ -1295,6 +1361,7 @@
     return NULL;
 
   if (!_dbus_header_create (&message->header,
+                            DBUS_COMPILER_BYTE_ORDER,
                             DBUS_MESSAGE_TYPE_SIGNAL,
                             NULL, path, interface, name, NULL))
     {
@@ -1345,6 +1412,7 @@
     return NULL;
 
   if (!_dbus_header_create (&message->header,
+                            DBUS_COMPILER_BYTE_ORDER,
                             DBUS_MESSAGE_TYPE_ERROR,
                             sender, NULL, NULL, NULL, error_name))
     {
@@ -1448,8 +1516,8 @@
   if (retval == NULL)
     return NULL;
 
-  retval->refcount.value = 1;
-  retval->byte_order = message->byte_order;
+  _dbus_atomic_inc (&retval->refcount);
+
   retval->locked = FALSE;
 #ifndef DBUS_DISABLE_CHECKS
   retval->generation = message->generation;
@@ -1492,6 +1560,7 @@
 
 #endif
 
+  _dbus_message_trace_ref (retval, 0, 1, "copy");
   return retval;
 
  failed_copy:
@@ -1524,9 +1593,10 @@
   _dbus_return_val_if_fail (message != NULL, NULL);
   _dbus_return_val_if_fail (message->generation == _dbus_current_generation, NULL);
   _dbus_return_val_if_fail (!message->in_cache, NULL);
-  
+
   old_refcount = _dbus_atomic_inc (&message->refcount);
   _dbus_assert (old_refcount >= 1);
+  _dbus_message_trace_ref (message, old_refcount, old_refcount + 1, "ref");
 
   return message;
 }
@@ -1549,7 +1619,9 @@
 
   old_refcount = _dbus_atomic_dec (&message->refcount);
 
-  _dbus_assert (old_refcount >= 0);
+  _dbus_assert (old_refcount >= 1);
+
+  _dbus_message_trace_ref (message, old_refcount, old_refcount - 1, "unref");
 
   if (old_refcount == 1)
     {
@@ -1729,9 +1801,7 @@
                 goto failed;
               }
             }
-          else if (element_type == DBUS_TYPE_STRING ||
-                   element_type == DBUS_TYPE_SIGNATURE ||
-                   element_type == DBUS_TYPE_OBJECT_PATH)
+          else if (_DBUS_TYPE_IS_STRINGLIKE (element_type))
             {
               const char ***value_p;
               const char **value;
@@ -1929,7 +1999,7 @@
                                   DBUS_MESSAGE_ITER_TYPE_READER);
 
   _dbus_type_reader_init (&real->u.reader,
-                          message->byte_order,
+                          _dbus_header_get_byte_order (&message->header),
                           type_str, type_pos,
                           &message->body,
                           0);
@@ -1979,7 +2049,7 @@
  * #DBUS_TYPE_INVALID. You can thus write a loop as follows:
  *
  * @code
- * dbus_message_iter_init (&iter);
+ * dbus_message_iter_init (message, &iter);
  * while ((current_type = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
  *   dbus_message_iter_next (&iter);
  * @endcode
@@ -2121,22 +2191,22 @@
  * descriptors), you can get all the array elements at once with
  * dbus_message_iter_get_fixed_array(). Otherwise, you have to iterate
  * over the container's contents one value at a time.
- * 
- * All basic-typed values are guaranteed to fit in 8 bytes. So you can
- * write code like this:
+ *
+ * All basic-typed values are guaranteed to fit in a #DBusBasicValue,
+ * so in versions of libdbus that have that type, you can write code like this:
  *
  * @code
- * dbus_uint64_t value;
+ * DBusBasicValue value;
  * int type;
  * dbus_message_iter_get_basic (&read_iter, &value);
  * type = dbus_message_iter_get_arg_type (&read_iter);
  * dbus_message_iter_append_basic (&write_iter, type, &value);
  * @endcode
  *
- * On some really obscure platforms dbus_uint64_t might not exist, if
- * you need to worry about this you will know.  dbus_uint64_t is just
- * one example of a type that's large enough to hold any possible
- * value, you could use a struct or char[8] instead if you like.
+ * (All D-Bus basic types are either numeric and 8 bytes or smaller, or
+ * behave like a string; so in older versions of libdbus, DBusBasicValue
+ * can be replaced with union { char *string; unsigned char bytes[8]; },
+ * for instance.)
  *
  * @param iter the iterator
  * @param value location to store the value
@@ -2245,12 +2315,14 @@
                                    int              *n_elements)
 {
   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+#ifndef DBUS_DISABLE_CHECKS
   int subtype = _dbus_type_reader_get_current_type(&real->u.reader);
 
   _dbus_return_if_fail (_dbus_message_iter_check (real));
   _dbus_return_if_fail (value != NULL);
   _dbus_return_if_fail ((subtype == DBUS_TYPE_INVALID) ||
                         (dbus_type_is_fixed (subtype) && subtype != DBUS_TYPE_UNIX_FD));
+#endif
 
   _dbus_type_reader_read_fixed_multi (&real->u.reader,
                                       value, n_elements);
@@ -2284,7 +2356,7 @@
    * due to OOM.
    */
   _dbus_type_writer_init_types_delayed (&real->u.writer,
-                                        message->byte_order,
+                                        _dbus_header_get_byte_order (&message->header),
                                         &message->body,
                                         _dbus_string_get_length (&message->body));
 }
@@ -2515,6 +2587,39 @@
   _dbus_return_val_if_fail (dbus_type_is_basic (type), FALSE);
   _dbus_return_val_if_fail (value != NULL, FALSE);
 
+#ifndef DBUS_DISABLE_CHECKS
+  switch (type)
+    {
+      const char * const *string_p;
+      const dbus_bool_t *bool_p;
+
+      case DBUS_TYPE_STRING:
+        string_p = value;
+        _dbus_return_val_if_fail (_dbus_check_is_valid_utf8 (*string_p), FALSE);
+        break;
+
+      case DBUS_TYPE_OBJECT_PATH:
+        string_p = value;
+        _dbus_return_val_if_fail (_dbus_check_is_valid_path (*string_p), FALSE);
+        break;
+
+      case DBUS_TYPE_SIGNATURE:
+        string_p = value;
+        _dbus_return_val_if_fail (_dbus_check_is_valid_signature (*string_p), FALSE);
+        break;
+
+      case DBUS_TYPE_BOOLEAN:
+        bool_p = value;
+        _dbus_return_val_if_fail (*bool_p == 0 || *bool_p == 1, FALSE);
+        break;
+
+      default:
+          {
+            /* nothing to check, all possible values are allowed */
+          }
+    }
+#endif
+
   if (!_dbus_message_iter_open_signature (real))
     return FALSE;
 
@@ -2598,10 +2703,6 @@
  * @todo If this fails due to lack of memory, the message is hosed and
  * you have to start over building the whole message.
  *
- * For Unix file descriptors this function will internally duplicate
- * the descriptor you passed in. Hence you may close the descriptor
- * immediately after this call.
- *
  * @param iter the append iterator
  * @param element_type the type of the array elements
  * @param value the address of the array
@@ -2627,6 +2728,19 @@
                             DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type),
                             FALSE);
 
+#ifndef DBUS_DISABLE_CHECKS
+  if (element_type == DBUS_TYPE_BOOLEAN)
+    {
+      const dbus_bool_t * const *bools = value;
+      int i;
+
+      for (i = 0; i < n_elements; i++)
+        {
+          _dbus_return_val_if_fail ((*bools)[i] == 0 || (*bools)[i] == 1, FALSE);
+        }
+    }
+#endif
+
   ret = _dbus_type_writer_write_fixed_multi (&real->u.writer, element_type, value, n_elements);
 
   return ret;
@@ -2760,12 +2874,14 @@
                                      DBusMessageIter *sub)
 {
   DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+#ifndef DBUS_DISABLE_CHECKS
   DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub;
 
   _dbus_return_if_fail (_dbus_message_iter_append_check (real));
   _dbus_return_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
   _dbus_return_if_fail (_dbus_message_iter_append_check (real_sub));
   _dbus_return_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
+#endif
 
   _dbus_message_iter_abandon_signature (real);
 }
@@ -3953,8 +4069,6 @@
 
   _dbus_assert (validity == DBUS_VALID);
 
-  message->byte_order = byte_order;
-
   /* 2. VALIDATE BODY */
   if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
     {
@@ -4638,7 +4752,8 @@
 
   if (validity == DBUS_VALID)
     {
-      _dbus_assert(have_message);
+      _dbus_assert (have_message || (header_len + body_len) > len);
+      (void) have_message; /* unused unless asserting */
       return header_len + body_len;
     }
   else
diff --git a/dbus/dbus-nonce.c b/dbus/dbus-nonce.c
index a7a82f1..e74c2dd 100644
--- a/dbus/dbus-nonce.c
+++ b/dbus/dbus-nonce.c
@@ -137,7 +137,8 @@
   DBusString nonce;
 
   _dbus_assert (noncefile != NULL);
-  _dbus_string_init (&nonce);
+  if (!_dbus_string_init (&nonce))
+    return -1;
   //PENDING(kdab): set better errors
   if (_dbus_read_nonce (_dbus_noncefile_get_path(noncefile), &nonce, NULL) != TRUE)
     return -1;
@@ -161,7 +162,11 @@
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
-  _dbus_string_init (&nonce);
+  if (!_dbus_string_init (&nonce))
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+      return FALSE;
+    }
 
   if (!_dbus_generate_random_bytes (&nonce, 16))
     {
@@ -191,7 +196,6 @@
 {
   dbus_bool_t read_result;
   int send_result;
-  size_t sendLen;
   DBusString nonce;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -235,7 +239,6 @@
                      DBusError *error,
                      dbus_bool_t use_subdir)
 {
-    dbus_bool_t ret;
     DBusString randomStr;
 
     _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -270,7 +273,7 @@
           }
         if (!_dbus_string_init (&noncefile->path)
             || !_dbus_string_copy (&noncefile->dir, 0, &noncefile->path, 0)
-            || !_dbus_string_append (&noncefile->dir, "/nonce"))
+            || !_dbus_string_append (&noncefile->path, "/nonce"))
           {
             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
             goto on_error;
diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c
index 28cfc8b..172c9d9 100644
--- a/dbus/dbus-object-tree.c
+++ b/dbus/dbus-object-tree.c
@@ -745,7 +745,8 @@
  */
 DBusHandlerResult
 _dbus_object_tree_dispatch_and_unlock (DBusObjectTree          *tree,
-                                       DBusMessage             *message)
+                                       DBusMessage             *message,
+                                       dbus_bool_t             *found_object)
 {
   char **path;
   dbus_bool_t exact_match;
@@ -791,6 +792,9 @@
   /* Find the deepest path that covers the path in the message */
   subtree = find_handler (tree, (const char**) path, &exact_match);
   
+  if (found_object)
+    *found_object = !!subtree;
+
   /* Build a list of all paths that cover the path in the message */
 
   list = NULL;
@@ -950,7 +954,7 @@
 
   len = strlen (name);
 
-  subtree = dbus_malloc (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
+  subtree = dbus_malloc0 (MAX (front_padding + (len + 1), sizeof (DBusObjectSubtree)));
 
   if (subtree == NULL)
     return NULL;
@@ -987,7 +991,7 @@
     }
 
   subtree->user_data = user_data;
-  subtree->refcount.value = 1;
+  _dbus_atomic_inc (&subtree->refcount);
   subtree->subtrees = NULL;
   subtree->n_subtrees = 0;
   subtree->max_subtrees = 0;
@@ -1002,8 +1006,14 @@
 static DBusObjectSubtree *
 _dbus_object_subtree_ref (DBusObjectSubtree *subtree)
 {
-  _dbus_assert (subtree->refcount.value > 0);
+#ifdef DBUS_DISABLE_ASSERT
   _dbus_atomic_inc (&subtree->refcount);
+#else
+  dbus_int32_t old_value;
+
+  old_value = _dbus_atomic_inc (&subtree->refcount);
+  _dbus_assert (old_value > 0);
+#endif
 
   return subtree;
 }
@@ -1011,9 +1021,12 @@
 static void
 _dbus_object_subtree_unref (DBusObjectSubtree *subtree)
 {
-  _dbus_assert (subtree->refcount.value > 0);
+  dbus_int32_t old_value;
 
-  if (_dbus_atomic_dec (&subtree->refcount) == 1)
+  old_value = _dbus_atomic_dec (&subtree->refcount);
+  _dbus_assert (old_value > 0);
+
+  if (old_value == 1)
     {
       _dbus_assert (subtree->unregister_function == NULL);
       _dbus_assert (subtree->message_function == NULL);
@@ -1382,7 +1395,7 @@
       ++j;
     }
 
-  result = _dbus_object_tree_dispatch_and_unlock (tree, message);
+  result = _dbus_object_tree_dispatch_and_unlock (tree, message, NULL);
   if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
     goto oom;
 
diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h
index 022dd93..5576c25 100644
--- a/dbus/dbus-object-tree.h
+++ b/dbus/dbus-object-tree.h
@@ -42,7 +42,8 @@
 void              _dbus_object_tree_unregister_and_unlock  (DBusObjectTree              *tree,
                                                             const char                 **path);
 DBusHandlerResult _dbus_object_tree_dispatch_and_unlock    (DBusObjectTree              *tree,
-                                                            DBusMessage                 *message);
+                                                            DBusMessage                 *message,
+                                                            dbus_bool_t                 *found_object);
 void*             _dbus_object_tree_get_user_data_unlocked (DBusObjectTree              *tree,
                                                             const char                 **path);
 void              _dbus_object_tree_free_all_unlocked      (DBusObjectTree              *tree);
diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c
index 303e8d8..62c6c74 100644
--- a/dbus/dbus-pending-call.c
+++ b/dbus/dbus-pending-call.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #include "dbus-internals.h"
 #include "dbus-connection-internal.h"
+#include "dbus-message-internal.h"
 #include "dbus-pending-call-internal.h"
 #include "dbus-pending-call.h"
 #include "dbus-list.h"
@@ -78,13 +79,36 @@
   unsigned int timeout_added : 1;                 /**< Have added the timeout */
 };
 
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+static void
+_dbus_pending_call_trace_ref (DBusPendingCall *pending_call,
+    int old_refcount,
+    int new_refcount,
+    const char *why)
+{
+  static int enabled = -1;
+
+  _dbus_trace_ref ("DBusPendingCall", pending_call, old_refcount,
+      new_refcount, why, "DBUS_PENDING_CALL_TRACE", &enabled);
+}
+#else
+#define _dbus_pending_call_trace_ref(p, o, n, w) \
+  do \
+  {\
+    (void) (o); \
+    (void) (n); \
+  } while (0)
+#endif
+
 static dbus_int32_t notify_user_data_slot = -1;
 
 /**
  * Creates a new pending reply object.
  *
  * @param connection connection where reply will arrive
- * @param timeout_milliseconds length of timeout, -1 for default, INT_MAX for no timeout
+ * @param timeout_milliseconds length of timeout, -1 (or
+ *  #DBUS_TIMEOUT_USE_DEFAULT) for default,
+ *  #DBUS_TIMEOUT_INFINITE for no timeout
  * @param timeout_handler timeout handler, takes pending call as data
  * @returns a new #DBusPendingCall or #NULL if no memory.
  */
@@ -112,7 +136,7 @@
       return NULL;
     }
 
-  if (timeout_milliseconds != _DBUS_INT_MAX)
+  if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE)
     {
       timeout = _dbus_timeout_new (timeout_milliseconds,
                                    timeout_handler,
@@ -137,7 +161,9 @@
   _dbus_connection_ref_unlocked (pending->connection);
 
   _dbus_data_slot_list_init (&pending->slot_list);
-  
+
+  _dbus_pending_call_trace_ref (pending, 0, 1, "new_unlocked");
+
   return pending;
 }
 
@@ -351,6 +377,8 @@
   reply_link = _dbus_list_alloc_link (reply);
   if (reply_link == NULL)
     {
+      /* it's OK to unref this, nothing that could have attached a callback
+       * has ever seen it */
       dbus_message_unref (reply);
       return FALSE;
     }
@@ -372,7 +400,11 @@
 DBusPendingCall *
 _dbus_pending_call_ref_unlocked (DBusPendingCall *pending)
 {
-  _dbus_atomic_inc (&pending->refcount);
+  dbus_int32_t old_refcount;
+
+  old_refcount = _dbus_atomic_inc (&pending->refcount);
+  _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
+      "ref_unlocked");
 
   return pending;
 }
@@ -435,6 +467,8 @@
 
   old_refcount = _dbus_atomic_dec (&pending->refcount);
   _dbus_assert (old_refcount > 0);
+  _dbus_pending_call_trace_ref (pending, old_refcount,
+      old_refcount - 1, "unref_and_unlock");
 
   CONNECTION_UNLOCK (pending->connection);
 
@@ -515,6 +549,26 @@
  */
 
 /**
+ * @def DBUS_TIMEOUT_INFINITE
+ *
+ * An integer constant representing an infinite timeout. This has the
+ * numeric value 0x7fffffff (the largest 32-bit signed integer).
+ *
+ * For source compatibility with D-Bus versions earlier than 1.4.12, use
+ * 0x7fffffff, or INT32_MAX (assuming your platform has it).
+ */
+
+/**
+ * @def DBUS_TIMEOUT_USE_DEFAULT
+ *
+ * An integer constant representing a request to use the default timeout.
+ * This has numeric value -1.
+ *
+ * For source compatibility with D-Bus versions earlier than 1.4.12, use a
+ * literal -1.
+ */
+
+/**
  * @typedef DBusPendingCall
  *
  * Opaque data type representing a message pending.
@@ -529,9 +583,13 @@
 DBusPendingCall *
 dbus_pending_call_ref (DBusPendingCall *pending)
 {
+  dbus_int32_t old_refcount;
+
   _dbus_return_val_if_fail (pending != NULL, NULL);
 
-  _dbus_atomic_inc (&pending->refcount);
+  old_refcount = _dbus_atomic_inc (&pending->refcount);
+  _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1,
+      "ref");
 
   return pending;
 }
@@ -545,13 +603,15 @@
 void
 dbus_pending_call_unref (DBusPendingCall *pending)
 {
-  dbus_bool_t last_unref;
+  dbus_int32_t old_refcount;
 
   _dbus_return_if_fail (pending != NULL);
 
-  last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
+  old_refcount = _dbus_atomic_dec (&pending->refcount);
+  _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1,
+      "unref");
 
-  if (last_unref)
+  if (old_refcount == 1)
     _dbus_pending_call_last_unref(pending);
 }
 
@@ -571,6 +631,8 @@
                               void                         *user_data,
                               DBusFreeFunction              free_user_data)
 {
+  dbus_bool_t ret = FALSE;
+
   _dbus_return_val_if_fail (pending != NULL, FALSE);
 
   CONNECTION_LOCK (pending->connection);
@@ -578,13 +640,15 @@
   /* could invoke application code! */
   if (!_dbus_pending_call_set_data_unlocked (pending, notify_user_data_slot,
                                              user_data, free_user_data))
-    return FALSE;
+    goto out;
   
   pending->function = function;
+  ret = TRUE;
 
+out:
   CONNECTION_UNLOCK (pending->connection);
   
-  return TRUE;
+  return ret;
 }
 
 /**
@@ -656,7 +720,8 @@
   pending->reply = NULL;
 
   CONNECTION_UNLOCK (pending->connection);
-  
+
+  _dbus_message_trace_ref (message, -1, -1, "dbus_pending_call_steal_reply");
   return message;
 }
 
@@ -784,19 +849,3 @@
 }
 
 /** @} */
-
-#ifdef DBUS_BUILD_TESTS
-
-/**
- * @ingroup DBusPendingCallInternals
- * Unit test for DBusPendingCall.
- *
- * @returns #TRUE on success.
- */
-dbus_bool_t
-_dbus_pending_call_test (const char *test_data_dir)
-{  
-
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h
index 8f64b8b..8a37ec0 100644
--- a/dbus/dbus-pending-call.h
+++ b/dbus/dbus-pending-call.h
@@ -38,6 +38,9 @@
  * @{
  */
 
+#define DBUS_TIMEOUT_INFINITE ((int) 0x7fffffff)
+#define DBUS_TIMEOUT_USE_DEFAULT (-1)
+
 DBUS_EXPORT
 DBusPendingCall* dbus_pending_call_ref       (DBusPendingCall               *pending);
 DBUS_EXPORT
diff --git a/dbus/dbus-pipe-unix.c b/dbus/dbus-pipe-unix.c
index f35024b..cfc5704 100644
--- a/dbus/dbus-pipe-unix.c
+++ b/dbus/dbus-pipe-unix.c
@@ -50,7 +50,7 @@
 {
   int written;
   
-  written = _dbus_write (pipe->fd_or_handle, buffer, start, len);
+  written = _dbus_write (pipe->fd, buffer, start, len);
   if (written < 0)
     {
       dbus_set_error (error, DBUS_ERROR_FAILED,
@@ -65,13 +65,13 @@
  *
  * @param pipe the pipe instance
  * @param error return location for an error
- * @returns #FALSE if error is set
+ * @returns -1 if error is set
  */
 int
 _dbus_pipe_close  (DBusPipe         *pipe,
                    DBusError        *error)
 {
-  if (_dbus_close (pipe->fd_or_handle, error) < 0)
+  if (!_dbus_close (pipe->fd, error))
     {
       return -1;
     }
diff --git a/dbus/dbus-pipe-win.c b/dbus/dbus-pipe-win.c
index f734518..9c7c257 100644
--- a/dbus/dbus-pipe-win.c
+++ b/dbus/dbus-pipe-win.c
@@ -29,6 +29,7 @@
 #include "dbus-pipe.h"
 
 #include <windows.h>
+#include <io.h>
 
 /**
  * write data to a pipe.
@@ -47,19 +48,18 @@
                   int               len,
                   DBusError        *error)
 {
-  DWORD written;
-  BOOL res;
-
   const char *buffer_c = _dbus_string_get_const_data (buffer);
+  int written;
 
-  res = WriteFile ((HANDLE) pipe->fd_or_handle, buffer_c + start, len, &written, NULL);
-  if (res == 0 || written < 0)
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "Writing to pipe: %s\n",
-                      _dbus_strerror_from_errno ());
-    }
-  return written;
+  written = _write (pipe->fd, buffer_c + start, len);
+
+  if (written >= 0)
+    return written;
+
+  dbus_set_error (error, _dbus_error_from_system_errno (),
+                  "Writing to pipe: %s",
+                  _dbus_strerror_from_errno ());
+  return -1;
 }
 
 /**
@@ -75,10 +75,10 @@
 {
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
-  if (CloseHandle ((HANDLE) pipe->fd_or_handle) == 0)
+  if (_close (pipe->fd) != 0)
     {
       dbus_set_error (error, _dbus_error_from_system_errno (),
-                      "Could not close pipe %d: %s", pipe->fd_or_handle,
+                      "Could not close pipe fd %d: %s", pipe->fd,
                       _dbus_strerror_from_errno ());
       return -1;
     }
diff --git a/dbus/dbus-pipe.c b/dbus/dbus-pipe.c
index 06560f1..7b5fe6d 100644
--- a/dbus/dbus-pipe.c
+++ b/dbus/dbus-pipe.c
@@ -33,9 +33,9 @@
  */
 void
 _dbus_pipe_init (DBusPipe *pipe,
-                 intptr_t  fd)
+                 int       fd)
 {
-  pipe->fd_or_handle = fd;
+  pipe->fd = fd;
 }
 
 /**
@@ -59,7 +59,7 @@
 dbus_bool_t
 _dbus_pipe_is_valid(DBusPipe *pipe)
 {
-  return pipe->fd_or_handle >= 0;
+  return pipe->fd >= 0;
 }
 
 /**
@@ -71,7 +71,7 @@
 dbus_bool_t
 _dbus_pipe_is_stdout_or_stderr (DBusPipe *pipe)
 {
-  return pipe->fd_or_handle == 1 || pipe->fd_or_handle == 2;
+  return pipe->fd == 1 || pipe->fd == 2;
 }
 
 /**
@@ -81,5 +81,5 @@
 void
 _dbus_pipe_invalidate (DBusPipe *pipe)
 {
-  pipe->fd_or_handle = -1;
+  pipe->fd = -1;
 }
diff --git a/dbus/dbus-pipe.h b/dbus/dbus-pipe.h
index f6eac5f..c2063b5 100644
--- a/dbus/dbus-pipe.h
+++ b/dbus/dbus-pipe.h
@@ -39,11 +39,11 @@
 #include <dbus/dbus-sysdeps.h>
 
 struct DBusPipe {
-  intptr_t fd_or_handle;
+  int fd;
 };
 
 void        _dbus_pipe_init                (DBusPipe         *pipe,
-                                            intptr_t          fd);
+                                            int               fd);
 void        _dbus_pipe_init_stdout         (DBusPipe         *pipe);
 int         _dbus_pipe_write               (DBusPipe         *pipe,
                                             const DBusString *buffer,
diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
index 17798e9..60605ab 100644
--- a/dbus/dbus-protocol.h
+++ b/dbus/dbus-protocol.h
@@ -189,7 +189,7 @@
  * arg0='hello' is OK, arg3489720987='hello' is not
  */
 #define DBUS_MAXIMUM_MATCH_RULE_ARG_NUMBER 63
-  
+
 /** Max length of a marshaled array in bytes (64M, 2^26) We use signed
  * int for lengths so must be INT_MAX or less.  We need something a
  * bit smaller than INT_MAX because the array is inside a message with
@@ -390,6 +390,14 @@
 #define DBUS_ERROR_FILE_EXISTS                "org.freedesktop.DBus.Error.FileExists"
 /** Method name you invoked isn't known by the object you invoked it on. */
 #define DBUS_ERROR_UNKNOWN_METHOD             "org.freedesktop.DBus.Error.UnknownMethod"
+/** Object you invoked a method on isn't known. */
+#define DBUS_ERROR_UNKNOWN_OBJECT             "org.freedesktop.DBus.Error.UnknownObject"
+/** Interface you invoked a method on isn't known by the object. */
+#define DBUS_ERROR_UNKNOWN_INTERFACE          "org.freedesktop.DBus.Error.UnknownInterface"
+/** Property you tried to access isn't known by the object. */
+#define DBUS_ERROR_UNKNOWN_PROPERTY           "org.freedesktop.DBus.Error.UnknownProperty"
+/** Property you tried to set is read-only. */
+#define DBUS_ERROR_PROPERTY_READ_ONLY         "org.freedesktop.DBus.Error.PropertyReadOnly"
 /** Certain timeout errors, e.g. while starting a service.
  * @warning this is confusingly-named given that #DBUS_ERROR_TIMEOUT also exists. We can't fix
  * it for compatibility reasons so just be careful.
@@ -448,7 +456,7 @@
 /** XML system identifier of the introspection format version 1.0 */
 #define DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"
 /** XML document type declaration of the introspection format version 1.0 */
-#define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<!DOCTYPE node PUBLIC \""DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER"\"\n\""DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n"
+#define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER "\">\n"
 
 /** @} */
 
diff --git a/dbus/dbus-resources.c b/dbus/dbus-resources.c
index 5f7001c..80fb55b 100644
--- a/dbus/dbus-resources.c
+++ b/dbus/dbus-resources.c
@@ -58,11 +58,17 @@
   long size_value;       /**< current size counter value */
   long unix_fd_value;    /**< current unix fd counter value */
 
+#ifdef DBUS_ENABLE_STATS
+  long peak_size_value;     /**< largest ever size counter value */
+  long peak_unix_fd_value;  /**< largest ever unix fd counter value */
+#endif
+
   long notify_size_guard_value;    /**< call notify function when crossing this size value */
   long notify_unix_fd_guard_value; /**< call notify function when crossing this unix fd value */
 
   DBusCounterNotifyFunction notify_function; /**< notify function */
   void *notify_data; /**< data for notify function */
+  dbus_bool_t notify_pending : 1; /**< TRUE if the guard value has been crossed */
 };
 
 /** @} */  /* end of resource limits internals docs */
@@ -83,19 +89,12 @@
 {
   DBusCounter *counter;
 
-  counter = dbus_new (DBusCounter, 1);
+  counter = dbus_new0 (DBusCounter, 1);
   if (counter == NULL)
     return NULL;
-  
-  counter->refcount = 1;
-  counter->size_value = 0;
-  counter->unix_fd_value = 0;
 
-  counter->notify_size_guard_value = 0;
-  counter->notify_unix_fd_guard_value = 0;
-  counter->notify_function = NULL;
-  counter->notify_data = NULL;
-  
+  counter->refcount = 1;
+
   return counter;
 }
 
@@ -138,8 +137,9 @@
 /**
  * Adjusts the value of the size counter by the given
  * delta which may be positive or negative.
- * Calls the notify function from _dbus_counter_set_notify()
- * if that function has been specified.
+ *
+ * This function may be called with locks held. After calling it, when
+ * any relevant locks are no longer held you must call _dbus_counter_notify().
  *
  * @param counter the counter
  * @param delta value to add to the size counter's current value
@@ -152,6 +152,11 @@
 
   counter->size_value += delta;
 
+#ifdef DBUS_ENABLE_STATS
+  if (counter->peak_size_value < counter->size_value)
+    counter->peak_size_value = counter->size_value;
+#endif
+
 #if 0
   _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n",
                  old, delta, counter->size_value);
@@ -162,14 +167,33 @@
         counter->size_value >= counter->notify_size_guard_value) ||
        (old >= counter->notify_size_guard_value &&
         counter->size_value < counter->notify_size_guard_value)))
-    (* counter->notify_function) (counter, counter->notify_data);
+    counter->notify_pending = TRUE;
+}
+
+/**
+ * Calls the notify function from _dbus_counter_set_notify(),
+ * if that function has been specified and the counter has crossed the
+ * guard value (in either direction) since the last call to this function.
+ *
+ * This function must not be called with locks held, since it can call out
+ * to user code.
+ */
+void
+_dbus_counter_notify (DBusCounter *counter)
+{
+  if (counter->notify_pending)
+    {
+      counter->notify_pending = FALSE;
+      (* counter->notify_function) (counter, counter->notify_data);
+    }
 }
 
 /**
  * Adjusts the value of the unix fd counter by the given
  * delta which may be positive or negative.
- * Calls the notify function from _dbus_counter_set_notify()
- * if that function has been specified.
+ *
+ * This function may be called with locks held. After calling it, when
+ * any relevant locks are no longer held you must call _dbus_counter_notify().
  *
  * @param counter the counter
  * @param delta value to add to the unix fds counter's current value
@@ -182,6 +206,11 @@
   
   counter->unix_fd_value += delta;
 
+#ifdef DBUS_ENABLE_STATS
+  if (counter->peak_unix_fd_value < counter->unix_fd_value)
+    counter->peak_unix_fd_value = counter->unix_fd_value;
+#endif
+
 #if 0
   _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n",
                  old, delta, counter->unix_fd_value);
@@ -192,7 +221,7 @@
         counter->unix_fd_value >= counter->notify_unix_fd_guard_value) ||
        (old >= counter->notify_unix_fd_guard_value &&
         counter->unix_fd_value < counter->notify_unix_fd_guard_value)))
-    (* counter->notify_function) (counter, counter->notify_data);
+    counter->notify_pending = TRUE;
 }
 
 /**
@@ -241,6 +270,21 @@
   counter->notify_unix_fd_guard_value = unix_fd_guard_value;
   counter->notify_function = function;
   counter->notify_data = user_data;
+  counter->notify_pending = FALSE;
 }
 
+#ifdef DBUS_ENABLE_STATS
+long
+_dbus_counter_get_peak_size_value (DBusCounter *counter)
+{
+  return counter->peak_size_value;
+}
+
+long
+_dbus_counter_get_peak_unix_fd_value (DBusCounter *counter)
+{
+  return counter->peak_unix_fd_value;
+}
+#endif
+
 /** @} */  /* end of resource limits exported API */
diff --git a/dbus/dbus-resources.h b/dbus/dbus-resources.h
index 4763a97..781a575 100644
--- a/dbus/dbus-resources.h
+++ b/dbus/dbus-resources.h
@@ -42,6 +42,7 @@
                                               long         delta);
 void         _dbus_counter_adjust_unix_fd    (DBusCounter *counter,
                                               long         delta);
+void         _dbus_counter_notify            (DBusCounter *counter);
 long         _dbus_counter_get_size_value    (DBusCounter *counter);
 long         _dbus_counter_get_unix_fd_value (DBusCounter *counter);
 
@@ -51,6 +52,9 @@
                                   DBusCounterNotifyFunction  function,
                                   void                      *user_data);
 
+/* if DBUS_ENABLE_STATS */
+long _dbus_counter_get_peak_size_value    (DBusCounter *counter);
+long _dbus_counter_get_peak_unix_fd_value (DBusCounter *counter);
 
 DBUS_END_DECLS
 
diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c
index e18cad7..419db5c 100644
--- a/dbus/dbus-server-debug-pipe.c
+++ b/dbus/dbus-server-debug-pipe.c
@@ -177,7 +177,8 @@
   _dbus_string_free (&address);
 
   /* server keeps the pipe hash ref */
-  
+
+  _dbus_server_trace_ref (&debug_server->base, 0, 1, "debug_pipe_new");
   return (DBusServer *)debug_server;
 
  nomem_4:
diff --git a/dbus/dbus-server-launchd.c b/dbus/dbus-server-launchd.c
new file mode 100644
index 0000000..db4673c
--- /dev/null
+++ b/dbus/dbus-server-launchd.c
@@ -0,0 +1,209 @@
+/* dbus-server-launchd.c Server methods for interacting with launchd.
+ * Copyright (C) 2007, Tanner Lovelace <lovelace@wayfarer.org>
+ * Copyright (C) 2008, Colin Walters <walters@verbum.org>
+ * Copyright (C) 2008-2009, Benjamin Reed <rangerrick@befunk.com>
+ * Copyright (C) 2009, Jonas Bähr <jonas.baehr@web.de>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <config.h>
+#include "dbus-server-launchd.h"
+
+/**
+ * @defgroup DBusServerLaunchd DBusServer implementations for Launchd
+ * @ingroup  DBusInternals
+ * @brief Implementation details of DBusServer with Launchd support
+ *
+ * @{
+ */
+
+#ifdef DBUS_ENABLE_LAUNCHD
+#include <launch.h>
+#include <errno.h>
+
+#include "dbus-server-socket.h"
+
+/* put other private launchd functions here */
+
+#endif /* DBUS_ENABLE_LAUNCHD */
+
+/**
+ * @brief Creates a new server from launchd.
+ *
+ * launchd has allocaed a socket for us. We now query launchd for the
+ * file descriptor of this socket and create a server on it.
+ * In addition we inherit launchd's environment which holds a variable
+ * containing the path to the socket. This is used to init the server's
+ * address which is passed to autolaunched services.
+ *
+ * @param launchd_env_var the environment variable which holds the unix path to the socket
+ * @param error location to store reason for failure.
+ * @returns the new server, or #NULL on failure.
+ */
+
+DBusServer *
+_dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error)
+  {
+#ifdef DBUS_ENABLE_LAUNCHD
+    DBusServer *server;
+    DBusString address;
+    int launchd_fd;
+    launch_data_t sockets_dict, checkin_response;
+    launch_data_t checkin_request;
+    launch_data_t listening_fd_array, listening_fd;
+    launch_data_t environment_dict, environment_param;
+    const char *launchd_socket_path, *display;
+
+    launchd_socket_path = _dbus_getenv (launchd_env_var);
+    display = _dbus_getenv ("DISPLAY");
+
+    _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+    if (launchd_socket_path == NULL || *launchd_socket_path == '\0')
+      {
+        dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                        "launchd's environment variable %s is empty, but should contain a socket path.\n", launchd_env_var);
+        return NULL;
+      }
+
+    if (!_dbus_string_init (&address))
+      {
+        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+        return NULL;
+      }
+    if (!_dbus_string_append (&address, "unix:path="))
+      {
+        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+        goto l_failed_0;
+      }
+    if (!_dbus_string_append (&address, launchd_socket_path))
+      {
+        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+        goto l_failed_0;
+      }
+
+    if ((checkin_request = launch_data_new_string (LAUNCH_KEY_CHECKIN)) == NULL)
+      {
+        dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
+                        "launch_data_new_string(\"%s\") Unable to create string.\n",
+                        LAUNCH_KEY_CHECKIN);
+        goto l_failed_0;
+      }
+
+    if ((checkin_response = launch_msg (checkin_request)) == NULL)
+      {
+        dbus_set_error (error, DBUS_ERROR_IO_ERROR,
+                        "launch_msg(\"%s\") IPC failure: %s\n",
+                        LAUNCH_KEY_CHECKIN, strerror (errno));
+        goto l_failed_0;
+      }
+
+    if (LAUNCH_DATA_ERRNO == launch_data_get_type (checkin_response))
+      {
+        dbus_set_error (error, DBUS_ERROR_FAILED, "Check-in failed: %s\n",
+                        strerror (launch_data_get_errno (checkin_response)));
+        goto l_failed_0;
+      }
+
+    sockets_dict =
+      launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_SOCKETS);
+    if (NULL == sockets_dict)
+      {
+        dbus_set_error (error, DBUS_ERROR_IO_ERROR,
+                        "No sockets found to answer requests on!\n");
+        goto l_failed_0;
+      }
+
+    listening_fd_array =
+      launch_data_dict_lookup (sockets_dict, "unix_domain_listener");
+    if (NULL == listening_fd_array)
+      {
+        dbus_set_error (error, DBUS_ERROR_IO_ERROR,
+                        "No known sockets found to answer requests on!\n");
+        goto l_failed_0;
+      }
+
+    if (launch_data_array_get_count (listening_fd_array) != 1)
+      {
+        dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
+                        "Expected 1 socket from launchd, got %d.\n",
+                        launch_data_array_get_count (listening_fd_array));
+        goto l_failed_0;
+      }
+
+    listening_fd = launch_data_array_get_index (listening_fd_array, 0);
+    launchd_fd = launch_data_get_fd (listening_fd);
+
+    _dbus_fd_set_close_on_exec (launchd_fd);
+
+    if (launchd_fd < 0)
+      {
+        _DBUS_ASSERT_ERROR_IS_SET (error);
+        goto l_failed_0;
+  if (display == NULL || *display == '\0')
+    {
+      environment_dict = launch_data_dict_lookup (checkin_response, LAUNCH_JOBKEY_USERENVIRONMENTVARIABLES);
+      if (NULL == environment_dict)
+        {
+          _dbus_warn ("Unable to retrieve user environment from launchd.");
+        }
+      else
+        {
+          environment_param = launch_data_dict_lookup (environment_dict, "DISPLAY");
+          if (NULL == environment_param)
+            {
+              _dbus_warn ("Unable to retrieve DISPLAY from launchd.");
+            }
+          else
+            {
+              display = launch_data_get_string(environment_param);
+              _dbus_setenv ("DISPLAY", display);
+            }
+        }
+    }
+
+      }
+
+    server = _dbus_server_new_for_socket (&launchd_fd, 1, &address, 0);
+    if (server == NULL)
+      {
+        dbus_set_error (error, DBUS_ERROR_NO_SERVER,
+                        "Unable to listen on launchd fd %d.", launchd_fd);
+        goto l_failed_0;
+      }
+
+    _dbus_string_free (&address);
+
+    return server;
+
+  l_failed_0:
+    _dbus_string_free (&address);
+
+    return NULL;
+#else /* DBUS_ENABLE_LAUNCHD */
+    dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS,
+                    "address type 'launchd' requested, but launchd support not compiled in");
+    return NULL;
+#endif
+  }
+
+/** @} */
diff --git a/dbus/dbus-server-launchd.h b/dbus/dbus-server-launchd.h
new file mode 100644
index 0000000..269b914
--- /dev/null
+++ b/dbus/dbus-server-launchd.h
@@ -0,0 +1,36 @@
+/* dbus-server-launchd.h Server methods for interacting with launchd.
+* Copyright (C) 2008, Benjamin Reed <rangerrick@befunk.com>
+*
+* Permission is hereby granted, free of charge, to any person
+* obtaining a copy of this software and associated documentation
+* files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy,
+* modify, merge, publish, distribute, sublicense, and/or sell copies
+* of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be
+* included in all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+* DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef DBUS_SERVER_LAUNCHD_H
+#define DBUS_SERVER_LAUNCHD_H
+
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-server-protected.h>
+
+DBUS_BEGIN_DECLS
+
+DBusServer * _dbus_server_new_for_launchd (const char *launchd_env_var, DBusError * error);
+
+DBUS_END_DECLS
+#endif /* DBUS_SERVER_LAUNCHD_H */
diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h
index cc2de8d..dd5234b 100644
--- a/dbus/dbus-server-protected.h
+++ b/dbus/dbus-server-protected.h
@@ -50,13 +50,14 @@
 };
 
 /**
+ * @ingroup DBusServerInternals
  * Internals of DBusServer object
  */
 struct DBusServer
 {
   DBusAtomic refcount;                        /**< Reference count. */
   const DBusServerVTable *vtable;             /**< Virtual methods for this instance. */
-  DBusMutex *mutex;                           /**< Lock on the server object */
+  DBusRMutex *mutex;                          /**< Lock on the server object */
 
   DBusGUID guid;                              /**< Globally unique ID of server */
 
@@ -66,7 +67,8 @@
   DBusTimeoutList *timeouts;                  /**< Our timeouts */  
 
   char *address;                              /**< Address this server is listening on. */
-  
+  dbus_bool_t published_address;              /**< flag which indicates that server has published its bus address. */
+
   int max_connections;                        /**< Max number of connections allowed at once. */
 
   DBusDataSlotList slot_list;   /**< Data stored by allocated integer ID */
@@ -116,13 +118,28 @@
   DBUS_SERVER_LISTEN_NOT_HANDLED, /**< we aren't in charge of this address type */
   DBUS_SERVER_LISTEN_OK,          /**< we set up the listen */
   DBUS_SERVER_LISTEN_BAD_ADDRESS, /**< malformed address */
-  DBUS_SERVER_LISTEN_DID_NOT_CONNECT /**< well-formed address but failed to set it up */
+  DBUS_SERVER_LISTEN_DID_NOT_CONNECT, /**< well-formed address but failed to set it up */
+  DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED /**< address is already used */
 } DBusServerListenResult;
 
 DBusServerListenResult _dbus_server_listen_platform_specific (DBusAddressEntry  *entry,
                                                               DBusServer       **server_p,
                                                               DBusError         *error);
 
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+void _dbus_server_trace_ref (DBusServer *server,
+    int old_refcount,
+    int new_refcount,
+    const char *why);
+#else
+#define _dbus_server_trace_ref(s,o,n,w) \
+  do \
+  {\
+    (void) (o); \
+    (void) (n); \
+  } while (0)
+#endif
+
 #ifdef DBUS_DISABLE_CHECKS
 #define TOOK_LOCK_CHECK(server)
 #define RELEASING_LOCK_CHECK(server)
@@ -144,14 +161,14 @@
 
 #define SERVER_LOCK(server)   do {                                              \
     if (TRACE_LOCKS) { _dbus_verbose ("LOCK\n"); }   \
-    _dbus_mutex_lock ((server)->mutex);                                          \
+    _dbus_rmutex_lock ((server)->mutex);                                        \
     TOOK_LOCK_CHECK (server);                                                   \
   } while (0)
 
 #define SERVER_UNLOCK(server) do {                                                      \
     if (TRACE_LOCKS) { _dbus_verbose ("UNLOCK\n");  }        \
     RELEASING_LOCK_CHECK (server);                                                      \
-    _dbus_mutex_unlock ((server)->mutex);                                                \
+    _dbus_rmutex_unlock ((server)->mutex);                                              \
   } while (0)
 
 DBUS_END_DECLS
diff --git a/dbus/dbus-server-socket.c b/dbus/dbus-server-socket.c
index dbd7213..ae4b602 100644
--- a/dbus/dbus-server-socket.c
+++ b/dbus/dbus-server-socket.c
@@ -89,10 +89,8 @@
   DBusConnection *connection;
   DBusTransport *transport;
   DBusNewConnectionFunction new_connection_function;
-  DBusServerSocket* socket_server;
   void *new_connection_data;
 
-  socket_server = (DBusServerSocket*)server;
   _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
 
   HAVE_LOCK_CHECK (server);
@@ -236,6 +234,7 @@
         {
           _dbus_server_remove_watch (server,
                                      socket_server->watch[i]);
+          _dbus_watch_invalidate (socket_server->watch[i]);
           _dbus_watch_unref (socket_server->watch[i]);
           socket_server->watch[i] = NULL;
         }
@@ -251,6 +250,9 @@
       _dbus_delete_file (&tmp, NULL);
     }
 
+  if (server->published_address)
+      _dbus_daemon_unpublish_session_bus_address();
+
   HAVE_LOCK_CHECK (server);
 }
 
@@ -270,7 +272,7 @@
  * @param fds list of file descriptors.
  * @param n_fds number of file descriptors
  * @param address the server's address
- * @param use_nonce whether to create and use a nonce for authentication
+ * @param noncefile to be used for authentication (NULL if not needed)
  * @returns the new server, or #NULL if no memory.
  *
  */
@@ -341,14 +343,9 @@
 
   SERVER_UNLOCK (server);
 
+  _dbus_server_trace_ref (&socket_server->base, 0, 1, "new_for_socket");
   return (DBusServer*) socket_server;
 
- failed_3:
-  if (socket_server->noncefile)
-    {
-      _dbus_noncefile_delete (socket_server->noncefile, NULL);
-      dbus_free (socket_server->noncefile );
-    }
  failed_2:
   for (i = 0 ; i < n_fds ; i++)
     {
@@ -461,16 +458,18 @@
       noncefile = dbus_new0 (DBusNonceFile, 1);
       if (noncefile == NULL)
         {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
           goto failed_2;
         }
 
-      if (!_dbus_noncefile_create (noncefile, NULL))
-          goto failed_2;
+      if (!_dbus_noncefile_create (noncefile, error))
+          goto failed_3;
 
       if (!_dbus_string_append (&address, ",noncefile=") ||
           !_dbus_address_append_escaped (&address, _dbus_noncefile_get_path (noncefile)))
         {
-          goto failed_2;
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          goto failed_4;
         }
 
     }
@@ -479,7 +478,7 @@
   if (server == NULL)
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      goto failed_2;
+      goto failed_4;
     }
 
   _dbus_string_free (&port_str);
@@ -488,6 +487,12 @@
 
   return server;
 
+ failed_4:
+  _dbus_noncefile_delete (noncefile, NULL);
+
+ failed_3:
+  dbus_free (noncefile);
+
  failed_2:
   for (i = 0 ; i < nlisten_fds ; i++)
     _dbus_close_socket (listen_fds[i], NULL);
diff --git a/dbus/dbus-server-socket.h b/dbus/dbus-server-socket.h
index 0a7c789..3aec712 100644
--- a/dbus/dbus-server-socket.h
+++ b/dbus/dbus-server-socket.h
@@ -33,6 +33,8 @@
                                                    int               n_fds,
                                                    const DBusString *address,
                                                    DBusNonceFile    *noncefile);
+DBusServer* _dbus_server_new_for_autolaunch       (const DBusString *address,
+                                                   DBusError        *error);
 DBusServer* _dbus_server_new_for_tcp_socket       (const char       *host,
                                                    const char       *bind,
                                                    const char       *port,
diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c
index 3e5ad6c..130f66e 100644
--- a/dbus/dbus-server-unix.c
+++ b/dbus/dbus-server-unix.c
@@ -25,6 +25,7 @@
 #include "dbus-internals.h"
 #include "dbus-server-unix.h"
 #include "dbus-server-socket.h"
+#include "dbus-server-launchd.h"
 #include "dbus-transport-unix.h"
 #include "dbus-connection-internal.h"
 #include "dbus-sysdeps-unix.h"
@@ -178,7 +179,30 @@
       dbus_free (fds);
 
       return DBUS_SERVER_LISTEN_OK;
+	}
+#ifdef DBUS_ENABLE_LAUNCHD
+  else if (strcmp (method, "launchd") == 0)
+    {
+      const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
+      if (launchd_env_var == NULL)
+        {
+          _dbus_set_bad_address (error, "launchd", "env", NULL);
+          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+        }
+      *server_p = _dbus_server_new_for_launchd (launchd_env_var, error);
+
+      if (*server_p != NULL)
+        {
+          _DBUS_ASSERT_ERROR_IS_CLEAR(error);
+          return DBUS_SERVER_LISTEN_OK;
+        }
+      else
+        {
+          _DBUS_ASSERT_ERROR_IS_SET(error);
+          return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
+        }
     }
+#endif
   else
     {
       /* If we don't handle the method, we return NULL with the
@@ -227,11 +251,18 @@
       goto failed_0;
     }
 
-  path_copy = _dbus_strdup (path);
-  if (path_copy == NULL)
+  if (abstract)
     {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
-      goto failed_0;
+      path_copy = NULL;
+    }
+  else
+    {
+      path_copy = _dbus_strdup (path);
+      if (path_copy == NULL)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          goto failed_0;
+        }
     }
 
   listen_fd = _dbus_listen_unix_socket (path, abstract, error);
@@ -249,7 +280,8 @@
       goto failed_2;
     }
 
-  _dbus_server_socket_own_filename(server, path_copy);
+  if (path_copy != NULL)
+    _dbus_server_socket_own_filename(server, path_copy);
 
   _dbus_string_free (&address);
 
diff --git a/dbus/dbus-server-win.c b/dbus/dbus-server-win.c
index 5cfb73e..bb6da48 100644
--- a/dbus/dbus-server-win.c
+++ b/dbus/dbus-server-win.c
@@ -57,37 +57,39 @@
 
   method = dbus_address_entry_get_method (entry);
 
-  if (strcmp (method, "nonce-tcp") == 0)
+  if (strcmp (method, "autolaunch") == 0)
     {
-      const char *host;
-      const char *port;
-      const char *bind;
-      const char *family;
+      const char *host = "localhost";
+      const char *bind = "localhost";
+      const char *port = "0";
+      const char *family = "ipv4";
+      const char *scope = dbus_address_entry_get_value (entry, "scope");
 
-      host = dbus_address_entry_get_value (entry, "host");
-      bind = dbus_address_entry_get_value (entry, "bind");
-      port = dbus_address_entry_get_value (entry, "port");
-      family = dbus_address_entry_get_value (entry, "family");
+      if (_dbus_daemon_is_session_bus_address_published (scope))
+          return DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED;
 
       *server_p = _dbus_server_new_for_tcp_socket (host, bind, port,
-                                                   family, error, TRUE);
-
+                                                   family, error, FALSE);
       if (*server_p)
         {
           _DBUS_ASSERT_ERROR_IS_CLEAR(error);
+          (*server_p)->published_address =
+              _dbus_daemon_publish_session_bus_address ((*server_p)->address, scope);
           return DBUS_SERVER_LISTEN_OK;
         }
       else
         {
+          // make sure no handle is open
+          _dbus_daemon_unpublish_session_bus_address ();
           _DBUS_ASSERT_ERROR_IS_SET(error);
           return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
         }
     }
   else
     {
-  _DBUS_ASSERT_ERROR_IS_CLEAR(error);
-  return DBUS_SERVER_LISTEN_NOT_HANDLED;
-}
+       _DBUS_ASSERT_ERROR_IS_CLEAR(error);
+       return DBUS_SERVER_LISTEN_NOT_HANDLED;
+    }
 }
 
 /** @} */
diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c
index d9e9cc4..b62c2b4 100644
--- a/dbus/dbus-server.c
+++ b/dbus/dbus-server.c
@@ -53,6 +53,20 @@
  * @{
  */
 
+#ifndef _dbus_server_trace_ref
+void
+_dbus_server_trace_ref (DBusServer *server,
+    int old_refcount,
+    int new_refcount,
+    const char *why)
+{
+  static int enabled = -1;
+
+  _dbus_trace_ref ("DBusServer", server, old_refcount, new_refcount, why,
+      "DBUS_SERVER_TRACE", &enabled);
+}
+#endif
+
 /* this is a little fragile since it assumes the address doesn't
  * already have a guid, but it shouldn't
  */
@@ -99,11 +113,21 @@
                         const DBusString       *address)
 {
   server->vtable = vtable;
-  server->refcount.value = 1;
+
+#ifdef DBUS_DISABLE_ASSERT
+  _dbus_atomic_inc (&server->refcount);
+#else
+    {
+      dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount);
+
+      _dbus_assert (old_refcount == 0);
+    }
+#endif
 
   server->address = NULL;
   server->watches = NULL;
   server->timeouts = NULL;
+  server->published_address = FALSE;
 
   if (!_dbus_string_init (&server->guid_hex))
     return FALSE;
@@ -118,7 +142,7 @@
   if (server->address == NULL)
     goto failed;
   
-  _dbus_mutex_new_at_location (&server->mutex);
+  _dbus_rmutex_new_at_location (&server->mutex);
   if (server->mutex == NULL)
     goto failed;
   
@@ -137,7 +161,7 @@
   return TRUE;
 
  failed:
-  _dbus_mutex_free_at_location (&server->mutex);
+  _dbus_rmutex_free_at_location (&server->mutex);
   server->mutex = NULL;
   if (server->watches)
     {
@@ -184,7 +208,7 @@
   _dbus_watch_list_free (server->watches);
   _dbus_timeout_list_free (server->timeouts);
 
-  _dbus_mutex_free_at_location (&server->mutex);
+  _dbus_rmutex_free_at_location (&server->mutex);
   
   dbus_free (server->address);
 
@@ -432,18 +456,15 @@
 void
 _dbus_server_ref_unlocked (DBusServer *server)
 {
+  dbus_int32_t old_refcount;
+
   _dbus_assert (server != NULL);
-  _dbus_assert (server->refcount.value > 0);
-  
   HAVE_LOCK_CHECK (server);
 
-#ifdef DBUS_HAVE_ATOMIC_INT
-  _dbus_atomic_inc (&server->refcount);
-#else
-  _dbus_assert (server->refcount.value > 0);
-
-  server->refcount.value += 1;
-#endif
+  old_refcount = _dbus_atomic_inc (&server->refcount);
+  _dbus_assert (old_refcount > 0);
+  _dbus_server_trace_ref (server, old_refcount, old_refcount + 1,
+      "ref_unlocked");
 }
 
 /**
@@ -454,25 +475,21 @@
 void
 _dbus_server_unref_unlocked (DBusServer *server)
 {
-  dbus_bool_t last_unref;
+  dbus_int32_t old_refcount;
 
   /* Keep this in sync with dbus_server_unref */
-  
+
   _dbus_assert (server != NULL);
-  _dbus_assert (server->refcount.value > 0);
 
   HAVE_LOCK_CHECK (server);
-  
-#ifdef DBUS_HAVE_ATOMIC_INT
-  last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
-#else
-  _dbus_assert (server->refcount.value > 0);
 
-  server->refcount.value -= 1;
-  last_unref = (server->refcount.value == 0);
-#endif
-  
-  if (last_unref)
+  old_refcount = _dbus_atomic_dec (&server->refcount);
+  _dbus_assert (old_refcount > 0);
+
+  _dbus_server_trace_ref (server, old_refcount, old_refcount - 1,
+      "unref_unlocked");
+
+  if (old_refcount == 1)
     {
       _dbus_assert (server->disconnected);
       
@@ -572,14 +589,24 @@
           if (result == DBUS_SERVER_LISTEN_OK)
             {
               _dbus_assert (server != NULL);
-              _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&tmp_error);
+              _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
+              handled_once = TRUE;
+              goto out;
+            }
+          else if (result == DBUS_SERVER_LISTEN_ADDRESS_ALREADY_USED)
+            {
+              _dbus_assert (server == NULL);
+              dbus_set_error (error,
+                       DBUS_ERROR_ADDRESS_IN_USE,
+                       "Address '%s' already used",
+                       dbus_address_entry_get_method (entries[0]));
               handled_once = TRUE;
               goto out;
             }
           else if (result == DBUS_SERVER_LISTEN_BAD_ADDRESS)
             {
               _dbus_assert (server == NULL);
-              _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&tmp_error);
+              _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
               dbus_move_error (&tmp_error, error);
               handled_once = TRUE;
               goto out;
@@ -587,14 +614,14 @@
           else if (result == DBUS_SERVER_LISTEN_NOT_HANDLED)
             {
               _dbus_assert (server == NULL);
-              _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&tmp_error);
+              _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
 
               /* keep trying addresses */
             }
           else if (result == DBUS_SERVER_LISTEN_DID_NOT_CONNECT)
             {
               _dbus_assert (server == NULL);
-              _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&tmp_error);
+              _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
               if (!dbus_error_is_set (&first_connect_error))
                 dbus_move_error (&tmp_error, &first_connect_error);
               else
@@ -647,7 +674,7 @@
           dbus_move_error (&first_connect_error, error);
         }
 
-      _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&first_connect_error); /* be sure we freed it */
+      _DBUS_ASSERT_ERROR_IS_CLEAR (&first_connect_error); /* be sure we freed it */
       _DBUS_ASSERT_ERROR_IS_SET (error);
 
       return NULL;
@@ -668,19 +695,27 @@
 DBusServer *
 dbus_server_ref (DBusServer *server)
 {
+  dbus_int32_t old_refcount;
+
   _dbus_return_val_if_fail (server != NULL, NULL);
-  _dbus_return_val_if_fail (server->refcount.value > 0, NULL);
 
-#ifdef DBUS_HAVE_ATOMIC_INT
-  _dbus_atomic_inc (&server->refcount);
-#else
-  SERVER_LOCK (server);
-  _dbus_assert (server->refcount.value > 0);
+  /* can't get the refcount without a side-effect */
+  old_refcount = _dbus_atomic_inc (&server->refcount);
 
-  server->refcount.value += 1;
-  SERVER_UNLOCK (server);
+#ifndef DBUS_DISABLE_CHECKS
+  if (_DBUS_UNLIKELY (old_refcount <= 0))
+    {
+      /* undo side-effect first */
+      _dbus_atomic_dec (&server->refcount);
+      _dbus_warn_check_failed (_dbus_return_if_fail_warning_format,
+                               _DBUS_FUNCTION_NAME, "old_refcount > 0",
+                               __FILE__, __LINE__);
+      return NULL;
+    }
 #endif
 
+  _dbus_server_trace_ref (server, old_refcount, old_refcount + 1, "ref");
+
   return server;
 }
 
@@ -695,27 +730,30 @@
 void
 dbus_server_unref (DBusServer *server)
 {
-  dbus_bool_t last_unref;
+  dbus_int32_t old_refcount;
 
   /* keep this in sync with unref_unlocked */
-  
+
   _dbus_return_if_fail (server != NULL);
-  _dbus_return_if_fail (server->refcount.value > 0);
 
-#ifdef DBUS_HAVE_ATOMIC_INT
-  last_unref = (_dbus_atomic_dec (&server->refcount) == 1);
-#else
-  SERVER_LOCK (server);
-  
-  _dbus_assert (server->refcount.value > 0);
+  /* can't get the refcount without a side-effect */
+  old_refcount = _dbus_atomic_dec (&server->refcount);
 
-  server->refcount.value -= 1;
-  last_unref = (server->refcount.value == 0);
-  
-  SERVER_UNLOCK (server);
+#ifndef DBUS_DISABLE_CHECKS
+  if (_DBUS_UNLIKELY (old_refcount <= 0))
+    {
+      /* undo side-effect first */
+      _dbus_atomic_inc (&server->refcount);
+      _dbus_warn_check_failed (_dbus_return_if_fail_warning_format,
+                               _DBUS_FUNCTION_NAME, "old_refcount > 0",
+                               __FILE__, __LINE__);
+      return;
+    }
 #endif
-  
-  if (last_unref)
+
+  _dbus_server_trace_ref (server, old_refcount, old_refcount - 1, "unref");
+
+  if (old_refcount == 1)
     {
       /* lock not held! */
       _dbus_assert (server->disconnected);
@@ -738,11 +776,19 @@
 dbus_server_disconnect (DBusServer *server)
 {
   _dbus_return_if_fail (server != NULL);
-  _dbus_return_if_fail (server->refcount.value > 0);
+
+#ifdef DBUS_DISABLE_CHECKS
+  _dbus_atomic_inc (&server->refcount);
+#else
+    {
+      dbus_int32_t old_refcount = _dbus_atomic_inc (&server->refcount);
+
+      _dbus_return_if_fail (old_refcount > 0);
+    }
+#endif
 
   SERVER_LOCK (server);
-  _dbus_server_ref_unlocked (server);
-  
+
   _dbus_assert (server->vtable->disconnect != NULL);
 
   if (!server->disconnected)
@@ -1047,7 +1093,7 @@
 dbus_server_allocate_data_slot (dbus_int32_t *slot_p)
 {
   return _dbus_data_slot_allocator_alloc (&slot_allocator,
-                                          (DBusMutex **)&_DBUS_LOCK_NAME (server_slots),
+                                          (DBusRMutex **)&_DBUS_LOCK_NAME (server_slots),
                                           slot_p);
 }
 
diff --git a/dbus/dbus-signature.c b/dbus/dbus-signature.c
index ddc0bcc..c130de5 100644
--- a/dbus/dbus-signature.c
+++ b/dbus/dbus-signature.c
@@ -283,16 +283,18 @@
  * A "container type" can contain basic types, or nested
  * container types. #DBUS_TYPE_INVALID is not a container type.
  *
- * This function will crash if passed a typecode that isn't
- * in dbus-protocol.h
+ * It is an error to pass an invalid type-code, other than DBUS_TYPE_INVALID,
+ * to this function. The valid type-codes are defined by dbus-protocol.h
+ * and can be checked with dbus_type_is_valid().
  *
+ * @param typecode either a valid type-code or DBUS_TYPE_INVALID
  * @returns #TRUE if type is a container
  */
 dbus_bool_t
 dbus_type_is_container (int typecode)
 {
   /* only reasonable (non-line-noise) typecodes are allowed */
-  _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
+  _dbus_return_val_if_fail (dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
 			    FALSE);
   return TYPE_IS_CONTAINER (typecode);
 }
@@ -305,16 +307,18 @@
  * variants are not basic types.  #DBUS_TYPE_INVALID is not a basic
  * type.
  *
- * This function will crash if passed a typecode that isn't
- * in dbus-protocol.h 
+ * It is an error to pass an invalid type-code, other than DBUS_TYPE_INVALID,
+ * to this function. The valid type-codes are defined by dbus-protocol.h
+ * and can be checked with dbus_type_is_valid().
  *
+ * @param typecode either a valid type-code or DBUS_TYPE_INVALID
  * @returns #TRUE if type is basic
  */
 dbus_bool_t
 dbus_type_is_basic (int typecode)
 {
   /* only reasonable (non-line-noise) typecodes are allowed */
-  _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
+  _dbus_return_val_if_fail (dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
 			    FALSE);
 
   /* everything that isn't invalid or a container */
@@ -334,16 +338,18 @@
  * but struct is not considered a fixed type for purposes of this
  * function.
  *
- * This function will crash if passed a typecode that isn't
- * in dbus-protocol.h
- * 
+ * It is an error to pass an invalid type-code, other than DBUS_TYPE_INVALID,
+ * to this function. The valid type-codes are defined by dbus-protocol.h
+ * and can be checked with dbus_type_is_valid().
+ *
+ * @param typecode either a valid type-code or DBUS_TYPE_INVALID
  * @returns #FALSE if the type can occupy different lengths
  */
 dbus_bool_t
 dbus_type_is_fixed (int typecode)
 {
   /* only reasonable (non-line-noise) typecodes are allowed */
-  _dbus_return_val_if_fail (_dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
+  _dbus_return_val_if_fail (dbus_type_is_valid (typecode) || typecode == DBUS_TYPE_INVALID,
 			    FALSE);
   
   switch (typecode)
@@ -364,6 +370,44 @@
     }
 }
 
+/**
+ * Return #TRUE if the argument is a valid typecode.
+ * #DBUS_TYPE_INVALID surprisingly enough is not considered valid, and
+ * random unknown bytes aren't either. This function is safe with
+ * untrusted data.
+ *
+ * @param typecode a potential type-code
+ * @returns #TRUE if valid
+ */
+dbus_bool_t
+dbus_type_is_valid (int typecode)
+{
+  switch (typecode)
+    {
+    case DBUS_TYPE_BYTE:
+    case DBUS_TYPE_BOOLEAN:
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_UINT64:
+    case DBUS_TYPE_DOUBLE:
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
+    case DBUS_TYPE_SIGNATURE:
+    case DBUS_TYPE_ARRAY:
+    case DBUS_TYPE_STRUCT:
+    case DBUS_TYPE_DICT_ENTRY:
+    case DBUS_TYPE_VARIANT:
+    case DBUS_TYPE_UNIX_FD:
+      return TRUE;
+
+    default:
+      return FALSE;
+    }
+}
+
 /** @} */ /* end of DBusSignature group */
 
 #ifdef DBUS_BUILD_TESTS
diff --git a/dbus/dbus-signature.h b/dbus/dbus-signature.h
index ebf00c1..443941c 100644
--- a/dbus/dbus-signature.h
+++ b/dbus/dbus-signature.h
@@ -79,6 +79,9 @@
 						      DBusError        *error);
 
 DBUS_EXPORT
+dbus_bool_t     dbus_type_is_valid                   (int            typecode);
+
+DBUS_EXPORT
 dbus_bool_t     dbus_type_is_basic                   (int            typecode);
 DBUS_EXPORT
 dbus_bool_t     dbus_type_is_container               (int            typecode);
diff --git a/dbus/dbus-socket-set-epoll.c b/dbus/dbus-socket-set-epoll.c
new file mode 100644
index 0000000..4cd9a56
--- /dev/null
+++ b/dbus/dbus-socket-set-epoll.c
@@ -0,0 +1,371 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-socket-set-epoll.c - a socket set implemented via Linux epoll(4)
+ *
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ *
+ */
+
+#include <config.h>
+#include "dbus-socket-set.h"
+
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-sysdeps.h>
+
+#ifndef __linux__
+# error This file is for Linux epoll(4)
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+typedef struct {
+    DBusSocketSet parent;
+    int epfd;
+} DBusSocketSetEpoll;
+
+static inline DBusSocketSetEpoll *
+socket_set_epoll_cast (DBusSocketSet *set)
+{
+  _dbus_assert (set->cls == &_dbus_socket_set_epoll_class);
+  return (DBusSocketSetEpoll *) set;
+}
+
+/* this is safe to call on a partially-allocated socket set */
+static void
+socket_set_epoll_free (DBusSocketSet *set)
+{
+  DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
+
+  if (self == NULL)
+    return;
+
+  if (self->epfd != -1)
+    close (self->epfd);
+
+  dbus_free (self);
+}
+
+DBusSocketSet *
+_dbus_socket_set_epoll_new (void)
+{
+  DBusSocketSetEpoll *self;
+
+  self = dbus_new0 (DBusSocketSetEpoll, 1);
+
+  if (self == NULL)
+    return NULL;
+
+  self->parent.cls = &_dbus_socket_set_epoll_class;
+
+  self->epfd = epoll_create1 (EPOLL_CLOEXEC);
+
+  if (self->epfd == -1)
+    {
+      int flags;
+
+      /* the size hint is ignored unless you have a rather old kernel,
+       * but must be positive on some versions, so just pick something
+       * arbitrary; it's a hint, not a limit */
+      self->epfd = epoll_create (42);
+
+      flags = fcntl (self->epfd, F_GETFD, 0);
+
+      if (flags != -1)
+        fcntl (self->epfd, F_SETFD, flags | FD_CLOEXEC);
+    }
+
+  if (self->epfd == -1)
+    {
+      socket_set_epoll_free ((DBusSocketSet *) self);
+      return NULL;
+    }
+
+  return (DBusSocketSet *) self;
+}
+
+static uint32_t
+watch_flags_to_epoll_events (unsigned int flags)
+{
+  uint32_t events = 0;
+
+  if (flags & DBUS_WATCH_READABLE)
+    events |= EPOLLIN;
+  if (flags & DBUS_WATCH_WRITABLE)
+    events |= EPOLLOUT;
+
+  return events;
+}
+
+static unsigned int
+epoll_events_to_watch_flags (uint32_t events)
+{
+  short flags = 0;
+
+  if (events & EPOLLIN)
+    flags |= DBUS_WATCH_READABLE;
+  if (events & EPOLLOUT)
+    flags |= DBUS_WATCH_WRITABLE;
+  if (events & EPOLLHUP)
+    flags |= DBUS_WATCH_HANGUP;
+  if (events & EPOLLERR)
+    flags |= DBUS_WATCH_ERROR;
+
+  return flags;
+}
+
+static dbus_bool_t
+socket_set_epoll_add (DBusSocketSet  *set,
+                      int             fd,
+                      unsigned int    flags,
+                      dbus_bool_t     enabled)
+{
+  DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
+  struct epoll_event event;
+  int err;
+
+  event.data.fd = fd;
+
+  if (enabled)
+    {
+      event.events = watch_flags_to_epoll_events (flags);
+    }
+  else
+    {
+      /* We need to add *something* to reserve space in the kernel's data
+       * structures: see socket_set_epoll_disable for more details */
+      event.events = EPOLLET;
+    }
+
+  if (epoll_ctl (self->epfd, EPOLL_CTL_ADD, fd, &event) == 0)
+    return TRUE;
+
+  /* Anything except ENOMEM, ENOSPC means we have an internal error. */
+  err = errno;
+  switch (err)
+    {
+      case ENOMEM:
+      case ENOSPC:
+        /* be silent: this is basically OOM, which our callers are expected
+         * to cope with */
+        break;
+
+      case EBADF:
+        _dbus_warn ("Bad fd %d\n", fd);
+        break;
+
+      case EEXIST:
+        _dbus_warn ("fd %d added and then added again\n", fd);
+        break;
+
+      default:
+        _dbus_warn ("Misc error when trying to watch fd %d: %s\n", fd,
+                    strerror (err));
+        break;
+    }
+
+  return FALSE;
+}
+
+static void
+socket_set_epoll_enable (DBusSocketSet  *set,
+                         int             fd,
+                         unsigned int    flags)
+{
+  DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
+  struct epoll_event event;
+  int err;
+
+  event.data.fd = fd;
+  event.events = watch_flags_to_epoll_events (flags);
+
+  if (epoll_ctl (self->epfd, EPOLL_CTL_MOD, fd, &event) == 0)
+    return;
+
+  err = errno;
+
+  /* Enabling a file descriptor isn't allowed to fail, even for OOM, so we
+   * do our best to avoid all of these. */
+  switch (err)
+    {
+      case EBADF:
+        _dbus_warn ("Bad fd %d\n", fd);
+        break;
+
+      case ENOENT:
+        _dbus_warn ("fd %d enabled before it was added\n", fd);
+        break;
+
+      case ENOMEM:
+        _dbus_warn ("Insufficient memory to change watch for fd %d\n", fd);
+        break;
+
+      default:
+        _dbus_warn ("Misc error when trying to watch fd %d: %s\n", fd,
+                    strerror (err));
+        break;
+    }
+}
+
+static void
+socket_set_epoll_disable (DBusSocketSet  *set,
+                          int             fd)
+{
+  DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
+  struct epoll_event event;
+  int err;
+
+  /* The naive thing to do would be EPOLL_CTL_DEL, but that'll probably
+   * free resources in the kernel. When we come to do socket_set_epoll_enable,
+   * there might not be enough resources to bring it back!
+   *
+   * The next idea you might have is to set the flags to 0. However, events
+   * always trigger on EPOLLERR and EPOLLHUP, even if libdbus isn't actually
+   * delivering them to a DBusWatch. Because epoll is level-triggered by
+   * default, we'll busy-loop on an unhandled error or hangup; not good.
+   *
+   * So, let's set it to be edge-triggered: then the worst case is that
+   * we return from poll immediately on one iteration, ignore it because no
+   * watch is enabled, then go back to normal. When we re-enable a watch
+   * we'll switch back to level-triggered and be notified again (verified to
+   * work on 2.6.32). Compile this file with -DTEST_BEHAVIOUR_OF_EPOLLET for
+   * test code.
+   */
+  event.data.fd = fd;
+  event.events = EPOLLET;
+
+  if (epoll_ctl (self->epfd, EPOLL_CTL_MOD, fd, &event) == 0)
+    return;
+
+  err = errno;
+  _dbus_warn ("Error when trying to watch fd %d: %s\n", fd,
+              strerror (err));
+}
+
+static void
+socket_set_epoll_remove (DBusSocketSet  *set,
+                         int             fd)
+{
+  DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
+  int err;
+  /* Kernels < 2.6.9 require a non-NULL struct pointer, even though its
+   * contents are ignored */
+  struct epoll_event dummy = { 0 };
+
+  if (epoll_ctl (self->epfd, EPOLL_CTL_DEL, fd, &dummy) == 0)
+    return;
+
+  err = errno;
+  _dbus_warn ("Error when trying to remove fd %d: %s\n", fd, strerror (err));
+}
+
+/* Optimally, this should be the same as in DBusLoop: we use it to translate
+ * between struct epoll_event and DBusSocketEvent without allocating heap
+ * memory. */
+#define N_STACK_DESCRIPTORS 64
+
+static int
+socket_set_epoll_poll (DBusSocketSet   *set,
+                       DBusSocketEvent *revents,
+                       int              max_events,
+                       int              timeout_ms)
+{
+  DBusSocketSetEpoll *self = socket_set_epoll_cast (set);
+  struct epoll_event events[N_STACK_DESCRIPTORS];
+  int n_ready;
+  int i;
+
+  _dbus_assert (max_events > 0);
+
+  n_ready = epoll_wait (self->epfd, events,
+                        MIN (_DBUS_N_ELEMENTS (events), max_events),
+                        timeout_ms);
+
+  if (n_ready <= 0)
+    return n_ready;
+
+  for (i = 0; i < n_ready; i++)
+    {
+      revents[i].fd = events[i].data.fd;
+      revents[i].flags = epoll_events_to_watch_flags (events[i].events);
+    }
+
+  return n_ready;
+}
+
+DBusSocketSetClass _dbus_socket_set_epoll_class = {
+    socket_set_epoll_free,
+    socket_set_epoll_add,
+    socket_set_epoll_remove,
+    socket_set_epoll_enable,
+    socket_set_epoll_disable,
+    socket_set_epoll_poll
+};
+
+#ifdef TEST_BEHAVIOUR_OF_EPOLLET
+/* usage: cat /dev/null | ./epoll
+ *
+ * desired output:
+ * ctl ADD: 0
+ * wait for HUP, edge-triggered: 1
+ * wait for HUP again: 0
+ * ctl MOD: 0
+ * wait for HUP: 1
+ */
+
+#include <sys/epoll.h>
+
+#include <stdio.h>
+
+int
+main (void)
+{
+  struct epoll_event input;
+  struct epoll_event output;
+  int epfd = epoll_create1 (EPOLL_CLOEXEC);
+  int fd = 0; /* stdin */
+  int ret;
+
+  input.events = EPOLLHUP | EPOLLET;
+  ret = epoll_ctl (epfd, EPOLL_CTL_ADD, fd, &input);
+  printf ("ctl ADD: %d\n", ret);
+
+  ret = epoll_wait (epfd, &output, 1, -1);
+  printf ("wait for HUP, edge-triggered: %d\n", ret);
+
+  ret = epoll_wait (epfd, &output, 1, 1);
+  printf ("wait for HUP again: %d\n", ret);
+
+  input.events = EPOLLHUP;
+  ret = epoll_ctl (epfd, EPOLL_CTL_MOD, fd, &input);
+  printf ("ctl MOD: %d\n", ret);
+
+  ret = epoll_wait (epfd, &output, 1, -1);
+  printf ("wait for HUP: %d\n", ret);
+
+  return 0;
+}
+
+#endif /* TEST_BEHAVIOUR_OF_EPOLLET */
+
+#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/dbus/dbus-socket-set-poll.c b/dbus/dbus-socket-set-poll.c
new file mode 100644
index 0000000..65a1fd2
--- /dev/null
+++ b/dbus/dbus-socket-set-poll.c
@@ -0,0 +1,320 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-socket-set-poll.c - a socket set implemented via _dbus_poll
+ *
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ *
+ */
+
+#include <config.h>
+#include "dbus-socket-set.h"
+
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-list.h>
+#include <dbus/dbus-sysdeps.h>
+#include <dbus/dbus-watch.h>
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+typedef struct {
+    DBusSocketSet      parent;
+    DBusPollFD        *fds;
+    int                n_fds;
+    int                n_reserved;
+    int                n_allocated;
+} DBusSocketSetPoll;
+
+#define REALLOC_INCREMENT 8
+#define MINIMUM_SIZE 8
+
+/* If we're in the regression tests, force reallocation to happen sooner */
+#ifdef DBUS_BUILD_TESTS
+#define DEFAULT_SIZE_HINT 1
+#else
+#define DEFAULT_SIZE_HINT MINIMUM_SIZE
+#endif
+
+static inline DBusSocketSetPoll *
+socket_set_poll_cast (DBusSocketSet *set)
+{
+  _dbus_assert (set->cls == &_dbus_socket_set_poll_class);
+  return (DBusSocketSetPoll *) set;
+}
+
+/* this is safe to call on a partially-allocated socket set */
+static void
+socket_set_poll_free (DBusSocketSet *set)
+{
+  DBusSocketSetPoll *self = socket_set_poll_cast (set);
+
+  dbus_free (self->fds);
+  dbus_free (self);
+  _dbus_verbose ("freed socket set %p\n", self);
+}
+
+DBusSocketSet *
+_dbus_socket_set_poll_new (int size_hint)
+{
+  DBusSocketSetPoll *ret;
+
+  if (size_hint <= 0)
+    size_hint = DEFAULT_SIZE_HINT;
+
+  ret = dbus_new0 (DBusSocketSetPoll, 1);
+
+  if (ret == NULL)
+    return NULL;
+
+  ret->parent.cls = &_dbus_socket_set_poll_class;
+  ret->n_fds = 0;
+  ret->n_allocated = size_hint;
+
+  ret->fds = dbus_new0 (DBusPollFD, size_hint);
+
+  if (ret->fds == NULL)
+    {
+      /* socket_set_poll_free specifically supports half-constructed
+       * socket sets */
+      socket_set_poll_free ((DBusSocketSet *) ret);
+      return NULL;
+    }
+
+  _dbus_verbose ("new socket set at %p\n", ret);
+  return (DBusSocketSet *) ret;
+}
+
+static short
+watch_flags_to_poll_events (unsigned int flags)
+{
+  short events = 0;
+
+  if (flags & DBUS_WATCH_READABLE)
+    events |= _DBUS_POLLIN;
+  if (flags & DBUS_WATCH_WRITABLE)
+    events |= _DBUS_POLLOUT;
+
+  return events;
+}
+
+static dbus_bool_t
+socket_set_poll_add (DBusSocketSet  *set,
+                     int             fd,
+                     unsigned int    flags,
+                     dbus_bool_t     enabled)
+{
+  DBusSocketSetPoll *self = socket_set_poll_cast (set);
+#ifndef DBUS_DISABLE_ASSERT
+  int i;
+
+  for (i = 0; i < self->n_fds; i++)
+    _dbus_assert (self->fds[i].fd != fd);
+#endif
+
+  if (self->n_reserved >= self->n_allocated)
+    {
+      DBusPollFD *new_fds = dbus_realloc (self->fds,
+          sizeof (DBusPollFD) * (self->n_allocated + REALLOC_INCREMENT));
+
+      _dbus_verbose ("inflating set %p from %d en/%d res/%d alloc to %d\n",
+                     self, self->n_fds, self->n_reserved, self->n_allocated,
+                     self->n_allocated + REALLOC_INCREMENT);
+
+      if (new_fds == NULL)
+        return FALSE;
+
+      self->fds = new_fds;
+      self->n_allocated += REALLOC_INCREMENT;
+    }
+
+  _dbus_verbose ("before adding fd %d to %p, %d en/%d res/%d alloc\n",
+                 fd, self, self->n_fds, self->n_reserved, self->n_allocated);
+  _dbus_assert (self->n_reserved >= self->n_fds);
+  _dbus_assert (self->n_allocated > self->n_reserved);
+
+  self->n_reserved++;
+
+  if (enabled)
+    {
+      self->fds[self->n_fds].fd = fd;
+      self->fds[self->n_fds].events = watch_flags_to_poll_events (flags);
+      self->n_fds++;
+    }
+
+  return TRUE;
+}
+
+static void
+socket_set_poll_enable (DBusSocketSet *set,
+                        int            fd,
+                        unsigned int   flags)
+{
+  DBusSocketSetPoll *self = socket_set_poll_cast (set);
+  int i;
+
+  for (i = 0; i < self->n_fds; i++)
+    {
+      if (self->fds[i].fd == fd)
+        {
+          self->fds[i].events = watch_flags_to_poll_events (flags);
+          return;
+        }
+    }
+
+  /* we allocated space when the socket was added */
+  _dbus_assert (self->n_fds < self->n_reserved);
+  _dbus_assert (self->n_reserved <= self->n_allocated);
+
+  self->fds[self->n_fds].fd = fd;
+  self->fds[self->n_fds].events = watch_flags_to_poll_events (flags);
+  self->n_fds++;
+}
+
+static void
+socket_set_poll_disable (DBusSocketSet *set,
+                         int            fd)
+{
+  DBusSocketSetPoll *self = socket_set_poll_cast (set);
+  int i;
+
+  for (i = 0; i < self->n_fds; i++)
+    {
+      if (self->fds[i].fd == fd)
+        {
+          if (i != self->n_fds - 1)
+            {
+              self->fds[i].fd = self->fds[self->n_fds - 1].fd;
+              self->fds[i].events = self->fds[self->n_fds - 1].events;
+            }
+
+          self->n_fds--;
+          return;
+        }
+    }
+}
+
+static void
+socket_set_poll_remove (DBusSocketSet *set,
+                        int            fd)
+{
+  DBusSocketSetPoll *self = socket_set_poll_cast (set);
+
+  socket_set_poll_disable (set, fd);
+  self->n_reserved--;
+
+  _dbus_verbose ("after removing fd %d from %p, %d en/%d res/%d alloc\n",
+                 fd, self, self->n_fds, self->n_reserved, self->n_allocated);
+  _dbus_assert (self->n_fds <= self->n_reserved);
+  _dbus_assert (self->n_reserved <= self->n_allocated);
+
+  if (self->n_reserved + MINIMUM_SIZE < self->n_allocated / 2)
+    {
+      /* Our array is twice as big as it needs to be - deflate it until it's
+       * only slightly larger than the number reserved. */
+      DBusPollFD *new_fds = dbus_realloc (self->fds,
+          sizeof (DBusPollFD) * (self->n_reserved + MINIMUM_SIZE));
+
+      _dbus_verbose ("before deflating %p, %d en/%d res/%d alloc\n",
+                     self, self->n_fds, self->n_reserved, self->n_allocated);
+
+      if (_DBUS_UNLIKELY (new_fds == NULL))
+        {
+          /* Weird. Oh well, never mind, the too-big array is untouched */
+          return;
+        }
+
+      self->fds = new_fds;
+      self->n_allocated = self->n_reserved;
+    }
+}
+
+static unsigned int
+watch_flags_from_poll_revents (short revents)
+{
+  unsigned int condition = 0;
+
+  if (revents & _DBUS_POLLIN)
+    condition |= DBUS_WATCH_READABLE;
+  if (revents & _DBUS_POLLOUT)
+    condition |= DBUS_WATCH_WRITABLE;
+  if (revents & _DBUS_POLLHUP)
+    condition |= DBUS_WATCH_HANGUP;
+  if (revents & _DBUS_POLLERR)
+    condition |= DBUS_WATCH_ERROR;
+
+  if (_DBUS_UNLIKELY (revents & _DBUS_POLLNVAL))
+    condition |= _DBUS_WATCH_NVAL;
+
+  return condition;
+}
+
+/** This is basically Linux's epoll_wait(2) implemented in terms of poll(2);
+ * it returns results into a caller-supplied buffer so we can be reentrant. */
+static int
+socket_set_poll_poll (DBusSocketSet   *set,
+                      DBusSocketEvent *revents,
+                      int              max_events,
+                      int              timeout_ms)
+{
+  DBusSocketSetPoll *self = socket_set_poll_cast (set);
+  int i;
+  int n_events;
+  int n_ready;
+
+  _dbus_assert (max_events > 0);
+
+  for (i = 0; i < self->n_fds; i++)
+    self->fds[i].revents = 0;
+
+  n_ready = _dbus_poll (self->fds, self->n_fds, timeout_ms);
+
+  if (n_ready <= 0)
+    return n_ready;
+
+  n_events = 0;
+
+  for (i = 0; i < self->n_fds; i++)
+    {
+      if (self->fds[i].revents != 0)
+        {
+          revents[n_events].fd = self->fds[i].fd;
+          revents[n_events].flags = watch_flags_from_poll_revents (self->fds[i].revents);
+
+          n_events += 1;
+
+          /* We ignore events beyond max_events because we have nowhere to
+           * put them. _dbus_poll is level-triggered, so we'll just be told
+           * about them next time round the main loop anyway. */
+          if (n_events == max_events)
+            return n_events;
+        }
+    }
+
+  return n_events;
+}
+
+DBusSocketSetClass _dbus_socket_set_poll_class = {
+    socket_set_poll_free,
+    socket_set_poll_add,
+    socket_set_poll_remove,
+    socket_set_poll_enable,
+    socket_set_poll_disable,
+    socket_set_poll_poll
+};
+
+#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/dbus/dbus-socket-set.c b/dbus/dbus-socket-set.c
new file mode 100644
index 0000000..210d600
--- /dev/null
+++ b/dbus/dbus-socket-set.c
@@ -0,0 +1,47 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * dbus-socket-set.c - used to bolt file descriptors onto a bus
+ *
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ *
+ */
+
+#include <config.h>
+#include <dbus/dbus-socket-set.h>
+
+DBusSocketSet *
+_dbus_socket_set_new (int size_hint)
+{
+  DBusSocketSet *ret;
+
+#ifdef DBUS_HAVE_LINUX_EPOLL
+  ret = _dbus_socket_set_epoll_new ();
+
+  if (ret != NULL)
+    return ret;
+#endif
+
+  ret = _dbus_socket_set_poll_new (size_hint);
+
+  if (ret != NULL)
+    return ret;
+
+  return NULL;
+}
diff --git a/dbus/dbus-socket-set.h b/dbus/dbus-socket-set.h
new file mode 100644
index 0000000..3b71a92
--- /dev/null
+++ b/dbus/dbus-socket-set.h
@@ -0,0 +1,122 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * dbus-socket-set.h - used to bolt file descriptors onto a bus
+ *
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA
+ *
+ */
+
+#ifndef DBUS_SOCKET_SET_H
+#define DBUS_SOCKET_SET_H
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+#include <dbus/dbus.h>
+
+typedef struct {
+    int fd;
+    unsigned int flags;
+} DBusSocketEvent;
+
+typedef struct DBusSocketSet DBusSocketSet;
+
+typedef struct DBusSocketSetClass DBusSocketSetClass;
+struct DBusSocketSetClass {
+    void            (*free)     (DBusSocketSet   *self);
+    dbus_bool_t     (*add)      (DBusSocketSet   *self,
+                                 int              fd,
+                                 unsigned int     flags,
+                                 dbus_bool_t      enabled);
+    void            (*remove)   (DBusSocketSet   *self,
+                                 int              fd);
+    void            (*enable)   (DBusSocketSet   *self,
+                                 int              fd,
+                                 unsigned int     flags);
+    void            (*disable)  (DBusSocketSet   *self,
+                                 int              fd);
+    int             (*poll)     (DBusSocketSet   *self,
+                                 DBusSocketEvent *revents,
+                                 int              max_events,
+                                 int              timeout_ms);
+};
+
+struct DBusSocketSet {
+    DBusSocketSetClass *cls;
+};
+
+DBusSocketSet *_dbus_socket_set_new           (int               size_hint);
+
+static inline void
+_dbus_socket_set_free (DBusSocketSet *self)
+{
+  (self->cls->free) (self);
+}
+
+static inline dbus_bool_t
+_dbus_socket_set_add (DBusSocketSet *self,
+                      int            fd,
+                      unsigned int   flags,
+                      dbus_bool_t    enabled)
+{
+  return (self->cls->add) (self, fd, flags, enabled);
+}
+
+static inline void
+_dbus_socket_set_remove (DBusSocketSet *self,
+                         int            fd)
+{
+  (self->cls->remove) (self, fd);
+}
+
+static inline void
+_dbus_socket_set_enable (DBusSocketSet *self,
+                         int            fd,
+                         unsigned int   flags)
+{
+  (self->cls->enable) (self, fd, flags);
+}
+
+static inline void
+_dbus_socket_set_disable (DBusSocketSet *self,
+                          int            fd)
+{
+  (self->cls->disable) (self, fd);
+}
+
+
+static inline int
+_dbus_socket_set_poll (DBusSocketSet    *self,
+                       DBusSocketEvent  *revents,
+                       int               max_events,
+                       int               timeout_ms)
+{
+  return (self->cls->poll) (self, revents, max_events, timeout_ms);
+}
+
+/* concrete implementations, not necessarily built on all platforms */
+
+extern DBusSocketSetClass _dbus_socket_set_poll_class;
+extern DBusSocketSetClass _dbus_socket_set_epoll_class;
+
+DBusSocketSet *_dbus_socket_set_poll_new  (int  size_hint);
+DBusSocketSet *_dbus_socket_set_epoll_new (void);
+
+#endif /* !DOXYGEN_SHOULD_SKIP_THIS */
+#endif /* multiple-inclusion guard */
diff --git a/dbus/dbus-sockets-win.h b/dbus/dbus-sockets-win.h
index 5dead05..4e1ab8c 100644
--- a/dbus/dbus-sockets-win.h
+++ b/dbus/dbus-sockets-win.h
@@ -41,16 +41,6 @@
 #include <errno.h>
 #endif
 
-/* Make use of the fact that the WSAE* error codes don't
- * overlap with errno E* codes. Wrapper functions store
- * the return value from WSAGetLastError() in errno.
- */
-#if defined(EPROTONOSUPPORT) || \
-    defined(EAFNOSUPPORT) || \
-    defined(EWOULDBLOCK)
-#error This does not look like Win32 and the Microsoft C library
-#endif
-
 #define DBUS_SOCKET_IS_INVALID(s) ((SOCKET)(s) == INVALID_SOCKET)
 #define DBUS_SOCKET_API_RETURNS_ERROR(n) ((n) == SOCKET_ERROR)
 #define DBUS_SOCKET_SET_ERRNO() (_dbus_win_set_errno (WSAGetLastError()))
diff --git a/dbus/dbus-spawn-win.c b/dbus/dbus-spawn-win.c
index 8ac837e..3dae4f3 100644
--- a/dbus/dbus-spawn-win.c
+++ b/dbus/dbus-spawn-win.c
@@ -42,6 +42,7 @@
 #include "dbus-protocol.h"
 
 #define WIN32_LEAN_AND_MEAN
+#include <windows.h>
 //#define STRICT
 //#include <windows.h>
 //#undef STRICT
@@ -81,6 +82,8 @@
 
     DBusWatchList *watches;
     DBusWatch *sitter_watch;
+    DBusBabysitterFinishedFunc finished_cb;
+    void *finished_data;
 
     dbus_bool_t have_spawn_errno;
     int spawn_errno;
@@ -154,6 +157,27 @@
   return sitter;
 }
 
+static void
+close_socket_to_babysitter (DBusBabysitter *sitter)
+{
+  _dbus_verbose ("Closing babysitter\n");
+
+  if (sitter->sitter_watch != NULL)
+    {
+      _dbus_assert (sitter->watches != NULL);
+      _dbus_watch_list_remove_watch (sitter->watches,  sitter->sitter_watch);
+      _dbus_watch_invalidate (sitter->sitter_watch);
+      _dbus_watch_unref (sitter->sitter_watch);
+      sitter->sitter_watch = NULL;
+    }
+
+  if (sitter->socket_to_babysitter != -1)
+    {
+      _dbus_close_socket (sitter->socket_to_babysitter, NULL);
+      sitter->socket_to_babysitter = -1;
+    }
+}
+
 /**
  * Decrement the reference count on the babysitter object.
  *
@@ -172,11 +196,7 @@
 
   if (sitter->refcount == 0)
     {
-      if (sitter->socket_to_babysitter != -1)
-        {
-          _dbus_close_socket (sitter->socket_to_babysitter, NULL);
-          sitter->socket_to_babysitter = -1;
-        }
+      close_socket_to_babysitter (sitter);
 
       if (sitter->socket_to_main != -1)
         {
@@ -372,9 +392,15 @@
    */
 
   PING();
-  _dbus_close_socket (sitter->socket_to_babysitter, NULL);
+  close_socket_to_babysitter (sitter);
   PING();
-  sitter->socket_to_babysitter = -1;
+
+  if (_dbus_babysitter_get_child_exited (sitter) &&
+      sitter->finished_cb != NULL)
+    {
+      sitter->finished_cb (sitter, sitter->finished_data);
+      sitter->finished_cb = NULL;
+    }
 
   return TRUE;
 }
@@ -477,8 +503,7 @@
   int n = 0;
   char *buf;
   char *p;
-  const char *ptr;
-  
+
   if (!strings || !strings[0])
     return 0;
   for (i = 0; strings[i]; i++)
@@ -558,7 +583,7 @@
 babysitter (void *parameter)
 {
   DBusBabysitter *sitter = (DBusBabysitter *) parameter;
-  int fd;
+
   PING();
   _dbus_babysitter_ref (sitter);
 
@@ -668,6 +693,12 @@
   PING();
   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
     {
+      /* we need to free it early so the destructor won't try to remove it
+       * without it having been added, which DBusLoop doesn't allow */
+      _dbus_watch_invalidate (sitter->sitter_watch);
+      _dbus_watch_unref (sitter->sitter_watch);
+      sitter->sitter_watch = NULL;
+
       _DBUS_SET_OOM (error);
       goto out0;
     }
@@ -713,8 +744,41 @@
   return FALSE;
 }
 
+void
+_dbus_babysitter_set_result_function  (DBusBabysitter             *sitter,
+                                       DBusBabysitterFinishedFunc  finished,
+                                       void                       *user_data)
+{
+  sitter->finished_cb = finished;
+  sitter->finished_data = user_data;
+}
+
 #ifdef DBUS_BUILD_TESTS
 
+static char *
+get_test_exec (const char *exe,
+               DBusString *scratch_space)
+{
+  const char *dbus_test_exec;
+
+  dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC");
+
+  if (dbus_test_exec == NULL)
+    dbus_test_exec = DBUS_TEST_EXEC;
+
+  if (!_dbus_string_init (scratch_space))
+    return NULL;
+
+  if (!_dbus_string_append_printf (scratch_space, "%s/%s%s",
+                                   dbus_test_exec, exe, DBUS_EXEEXT))
+    {
+      _dbus_string_free (scratch_space);
+      return NULL;
+    }
+
+  return _dbus_string_get_data (scratch_space);
+}
+
 #define LIVE_CHILDREN(sitter) ((sitter)->child_handle != NULL)
 
 static void
@@ -777,6 +841,7 @@
   char *argv[4] = { NULL, NULL, NULL, NULL };
   DBusBabysitter *sitter;
   DBusError error;
+  DBusString argv0;
 
   sitter = NULL;
 
@@ -784,7 +849,14 @@
 
   /*** Test launching segfault binary */
 
-  argv[0] = TEST_SEGFAULT_BINARY;
+  argv[0] = get_test_exec ("test-segfault", &argv0);
+
+  if (argv[0] == NULL)
+    {
+      /* OOM was simulated, never mind */
+      return TRUE;
+    }
+
   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
                                          NULL, NULL,
                                          &error))
@@ -793,6 +865,8 @@
       _dbus_babysitter_set_child_exit_error (sitter, &error);
     }
 
+  _dbus_string_free (&argv0);
+
   if (sitter)
     _dbus_babysitter_unref (sitter);
 
@@ -822,6 +896,7 @@
   char *argv[4] = { NULL, NULL, NULL, NULL };
   DBusBabysitter *sitter;
   DBusError error;
+  DBusString argv0;
 
   sitter = NULL;
 
@@ -829,7 +904,14 @@
 
   /*** Test launching exit failure binary */
 
-  argv[0] = TEST_EXIT_BINARY;
+  argv[0] = get_test_exec ("test-exit", &argv0);
+
+  if (argv[0] == NULL)
+    {
+      /* OOM was simulated, never mind */
+      return TRUE;
+    }
+
   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
                                          NULL, NULL,
                                          &error))
@@ -838,6 +920,8 @@
       _dbus_babysitter_set_child_exit_error (sitter, &error);
     }
 
+  _dbus_string_free (&argv0);
+
   if (sitter)
     _dbus_babysitter_unref (sitter);
 
@@ -867,6 +951,7 @@
   char *argv[4] = { NULL, NULL, NULL, NULL };
   DBusBabysitter *sitter;
   DBusError error;
+  DBusString argv0;
 
   sitter = NULL;
 
@@ -874,7 +959,14 @@
 
   /*** Test launching sleeping binary then killing it */
 
-  argv[0] = TEST_SLEEP_FOREVER_BINARY;
+  argv[0] = get_test_exec ("test-sleep-forever", &argv0);
+
+  if (argv[0] == NULL)
+    {
+      /* OOM was simulated, never mind */
+      return TRUE;
+    }
+
   if (_dbus_spawn_async_with_babysitter (&sitter, argv, NULL,
                                          NULL, NULL,
                                          &error))
@@ -886,6 +978,8 @@
       _dbus_babysitter_set_child_exit_error (sitter, &error);
     }
 
+  _dbus_string_free (&argv0);
+
   if (sitter)
     _dbus_babysitter_unref (sitter);
 
diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c
index dcd111d..ef00801 100644
--- a/dbus/dbus-spawn.c
+++ b/dbus/dbus-spawn.c
@@ -205,6 +205,9 @@
   DBusWatch *error_watch; /**< Error pipe watch */
   DBusWatch *sitter_watch; /**< Sitter pipe watch */
 
+  DBusBabysitterFinishedFunc finished_cb;
+  void *finished_data;
+
   int errnum; /**< Error number */
   int status; /**< Exit status code */
   unsigned int have_child_status : 1; /**< True if child status has been reaped */
@@ -257,6 +260,9 @@
   return sitter;
 }
 
+static void close_socket_to_babysitter  (DBusBabysitter *sitter);
+static void close_error_pipe_from_child (DBusBabysitter *sitter);
+
 /**
  * Decrement the reference count on the babysitter object.
  * When the reference count of the babysitter object reaches
@@ -273,25 +279,17 @@
   
   sitter->refcount -= 1;
   if (sitter->refcount == 0)
-    {      
-      if (sitter->socket_to_babysitter >= 0)
-        {
-          /* If we haven't forked other babysitters
-           * since this babysitter and socket were
-           * created then this close will cause the
-           * babysitter to wake up from poll with
-           * a hangup and then the babysitter will
-           * quit itself.
-           */
-          _dbus_close_socket (sitter->socket_to_babysitter, NULL);
-          sitter->socket_to_babysitter = -1;
-        }
+    {
+      /* If we haven't forked other babysitters
+       * since this babysitter and socket were
+       * created then this close will cause the
+       * babysitter to wake up from poll with
+       * a hangup and then the babysitter will
+       * quit itself.
+       */
+      close_socket_to_babysitter (sitter);
 
-      if (sitter->error_pipe_from_child >= 0)
-        {
-          _dbus_close_socket (sitter->error_pipe_from_child, NULL);
-          sitter->error_pipe_from_child = -1;
-        }
+      close_error_pipe_from_child (sitter);
 
       if (sitter->sitter_pid > 0)
         {
@@ -341,21 +339,7 @@
 
           sitter->sitter_pid = -1;
         }
-      
-      if (sitter->error_watch)
-        {
-          _dbus_watch_invalidate (sitter->error_watch);
-          _dbus_watch_unref (sitter->error_watch);
-          sitter->error_watch = NULL;
-        }
 
-      if (sitter->sitter_watch)
-        {
-          _dbus_watch_invalidate (sitter->sitter_watch);
-          _dbus_watch_unref (sitter->sitter_watch);
-          sitter->sitter_watch = NULL;
-        }
-      
       if (sitter->watches)
         _dbus_watch_list_free (sitter->watches);
 
@@ -476,16 +460,42 @@
 close_socket_to_babysitter (DBusBabysitter *sitter)
 {
   _dbus_verbose ("Closing babysitter\n");
-  _dbus_close_socket (sitter->socket_to_babysitter, NULL);
-  sitter->socket_to_babysitter = -1;
+
+  if (sitter->sitter_watch != NULL)
+    {
+      _dbus_assert (sitter->watches != NULL);
+      _dbus_watch_list_remove_watch (sitter->watches,  sitter->sitter_watch);
+      _dbus_watch_invalidate (sitter->sitter_watch);
+      _dbus_watch_unref (sitter->sitter_watch);
+      sitter->sitter_watch = NULL;
+    }
+
+  if (sitter->socket_to_babysitter >= 0)
+    {
+      _dbus_close_socket (sitter->socket_to_babysitter, NULL);
+      sitter->socket_to_babysitter = -1;
+    }
 }
 
 static void
 close_error_pipe_from_child (DBusBabysitter *sitter)
 {
   _dbus_verbose ("Closing child error\n");
-  _dbus_close_socket (sitter->error_pipe_from_child, NULL);
-  sitter->error_pipe_from_child = -1;
+
+  if (sitter->error_watch != NULL)
+    {
+      _dbus_assert (sitter->watches != NULL);
+      _dbus_watch_list_remove_watch (sitter->watches,  sitter->error_watch);
+      _dbus_watch_invalidate (sitter->error_watch);
+      _dbus_watch_unref (sitter->error_watch);
+      sitter->error_watch = NULL;
+    }
+
+  if (sitter->error_pipe_from_child >= 0)
+    {
+      _dbus_close_socket (sitter->error_pipe_from_child, NULL);
+      sitter->error_pipe_from_child = -1;
+    }
 }
 
 static void
@@ -752,7 +762,7 @@
               unsigned int     condition,
               void            *data)
 {
-  DBusBabysitter *sitter = data;
+  DBusBabysitter *sitter = _dbus_babysitter_ref (data);
   int revents;
   int fd;
   
@@ -774,7 +784,20 @@
   while (LIVE_CHILDREN (sitter) &&
          babysitter_iteration (sitter, FALSE))
     ;
-  
+
+  /* fd.o #32992: if the handle_* methods closed their sockets, they previously
+   * didn't always remove the watches. Check that we don't regress. */
+  _dbus_assert (sitter->socket_to_babysitter != -1 || sitter->sitter_watch == NULL);
+  _dbus_assert (sitter->error_pipe_from_child != -1 || sitter->error_watch == NULL);
+
+  if (_dbus_babysitter_get_child_exited (sitter) &&
+      sitter->finished_cb != NULL)
+    {
+      sitter->finished_cb (sitter, sitter->finished_data);
+      sitter->finished_cb = NULL;
+    }
+
+  _dbus_babysitter_unref (sitter);
   return TRUE;
 }
 
@@ -1080,7 +1103,9 @@
         {
           char b;
           if (read (sigchld_pipe[READ_END], &b, 1) == -1)
-            /* ignore */;
+            {
+              /* ignore */
+            }
           /* do waitpid check */
           check_babysit_events (grandchild_pid, parent_pipe, 0);
         }
@@ -1164,6 +1189,12 @@
         
   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->error_watch))
     {
+      /* we need to free it early so the destructor won't try to remove it
+       * without it having been added, which DBusLoop doesn't allow */
+      _dbus_watch_invalidate (sitter->error_watch);
+      _dbus_watch_unref (sitter->error_watch);
+      sitter->error_watch = NULL;
+
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       goto cleanup_and_fail;
     }
@@ -1179,6 +1210,12 @@
       
   if (!_dbus_watch_list_add_watch (sitter->watches,  sitter->sitter_watch))
     {
+      /* we need to free it early so the destructor won't try to remove it
+       * without it having been added, which DBusLoop doesn't allow */
+      _dbus_watch_invalidate (sitter->sitter_watch);
+      _dbus_watch_unref (sitter->sitter_watch);
+      sitter->sitter_watch = NULL;
+
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       goto cleanup_and_fail;
     }
@@ -1273,10 +1310,43 @@
   return FALSE;
 }
 
+void
+_dbus_babysitter_set_result_function  (DBusBabysitter             *sitter,
+                                       DBusBabysitterFinishedFunc  finished,
+                                       void                       *user_data)
+{
+  sitter->finished_cb = finished;
+  sitter->finished_data = user_data;
+}
+
 /** @} */
 
 #ifdef DBUS_BUILD_TESTS
 
+static char *
+get_test_exec (const char *exe,
+               DBusString *scratch_space)
+{
+  const char *dbus_test_exec;
+
+  dbus_test_exec = _dbus_getenv ("DBUS_TEST_EXEC");
+
+  if (dbus_test_exec == NULL)
+    dbus_test_exec = DBUS_TEST_EXEC;
+
+  if (!_dbus_string_init (scratch_space))
+    return NULL;
+
+  if (!_dbus_string_append_printf (scratch_space, "%s/%s%s",
+                                   dbus_test_exec, exe, DBUS_EXEEXT))
+    {
+      _dbus_string_free (scratch_space);
+      return NULL;
+    }
+
+  return _dbus_string_get_data (scratch_space);
+}
+
 static void
 _dbus_babysitter_block_for_child_exit (DBusBabysitter *sitter)
 {
@@ -1331,10 +1401,18 @@
   char *argv[4] = { NULL, NULL, NULL, NULL };
   DBusBabysitter *sitter = NULL;
   DBusError error = DBUS_ERROR_INIT;
+  DBusString argv0;
 
   /*** Test launching segfault binary */
-  
-  argv[0] = TEST_SEGFAULT_BINARY;
+
+  argv[0] = get_test_exec ("test-segfault", &argv0);
+
+  if (argv[0] == NULL)
+    {
+      /* OOM was simulated, never mind */
+      return TRUE;
+    }
+
   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
                                          NULL, NULL, NULL,
                                          &error))
@@ -1343,6 +1421,8 @@
       _dbus_babysitter_set_child_exit_error (sitter, &error);
     }
 
+  _dbus_string_free (&argv0);
+
   if (sitter)
     _dbus_babysitter_unref (sitter);
 
@@ -1372,10 +1452,18 @@
   char *argv[4] = { NULL, NULL, NULL, NULL };
   DBusBabysitter *sitter = NULL;
   DBusError error = DBUS_ERROR_INIT;
+  DBusString argv0;
 
   /*** Test launching exit failure binary */
-  
-  argv[0] = TEST_EXIT_BINARY;
+
+  argv[0] = get_test_exec ("test-exit", &argv0);
+
+  if (argv[0] == NULL)
+    {
+      /* OOM was simulated, never mind */
+      return TRUE;
+    }
+
   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
                                          NULL, NULL, NULL,
                                          &error))
@@ -1384,6 +1472,8 @@
       _dbus_babysitter_set_child_exit_error (sitter, &error);
     }
 
+  _dbus_string_free (&argv0);
+
   if (sitter)
     _dbus_babysitter_unref (sitter);
 
@@ -1413,10 +1503,18 @@
   char *argv[4] = { NULL, NULL, NULL, NULL };
   DBusBabysitter *sitter = NULL;
   DBusError error = DBUS_ERROR_INIT;
+  DBusString argv0;
 
   /*** Test launching sleeping binary then killing it */
 
-  argv[0] = TEST_SLEEP_FOREVER_BINARY;
+  argv[0] = get_test_exec ("test-sleep-forever", &argv0);
+
+  if (argv[0] == NULL)
+    {
+      /* OOM was simulated, never mind */
+      return TRUE;
+    }
+
   if (_dbus_spawn_async_with_babysitter (&sitter, argv,
                                          NULL, NULL, NULL,
                                          &error))
@@ -1428,6 +1526,8 @@
       _dbus_babysitter_set_child_exit_error (sitter, &error);
     }
 
+  _dbus_string_free (&argv0);
+
   if (sitter)
     _dbus_babysitter_unref (sitter);
 
diff --git a/dbus/dbus-spawn.h b/dbus/dbus-spawn.h
index 5af54b7..a8814fb 100644
--- a/dbus/dbus-spawn.h
+++ b/dbus/dbus-spawn.h
@@ -35,12 +35,18 @@
 
 typedef struct DBusBabysitter DBusBabysitter;
 
+typedef void (* DBusBabysitterFinishedFunc) (DBusBabysitter *sitter,
+                                             void           *user_data);
+
 dbus_bool_t _dbus_spawn_async_with_babysitter     (DBusBabysitter           **sitter_p,
                                                    char                     **argv,
                                                    char                     **env,
                                                    DBusSpawnChildSetupFunc    child_setup,
                                                    void                      *user_data,
                                                    DBusError                 *error);
+void        _dbus_babysitter_set_result_function  (DBusBabysitter            *sitter,
+                                                   DBusBabysitterFinishedFunc finished,
+                                                   void                      *user_data);
 DBusBabysitter* _dbus_babysitter_ref              (DBusBabysitter            *sitter);
 void        _dbus_babysitter_unref                (DBusBabysitter            *sitter);
 void        _dbus_babysitter_kill_child           (DBusBabysitter            *sitter);
diff --git a/dbus/dbus-string-private.h b/dbus/dbus-string-private.h
index 365d89a..2e6de90 100644
--- a/dbus/dbus-string-private.h
+++ b/dbus/dbus-string-private.h
@@ -24,6 +24,7 @@
 #ifndef DBUS_STRING_PRIVATE_H
 #define DBUS_STRING_PRIVATE_H
 
+#include <dbus/dbus-internals.h>
 #include <dbus/dbus-memory.h>
 #include <dbus/dbus-types.h>
 
@@ -44,13 +45,13 @@
   unsigned char *str;            /**< String data, plus nul termination */
   int            len;            /**< Length without nul */
   int            allocated;      /**< Allocated size of data */
-  int            max_length;     /**< Max length of this string, without nul byte */
   unsigned int   constant : 1;   /**< String data is not owned by DBusString */
   unsigned int   locked : 1;     /**< DBusString has been locked and can't be changed */
   unsigned int   invalid : 1;    /**< DBusString is invalid (e.g. already freed) */
   unsigned int   align_offset : 3; /**< str - align_offset is the actual malloc block */
 } DBusRealString;
 
+_DBUS_STATIC_ASSERT (sizeof (DBusRealString) == sizeof (DBusString));
 
 /**
  * @defgroup DBusStringInternals DBusString implementation details
@@ -63,17 +64,25 @@
  */
 
 /**
- * This is the maximum max length (and thus also the maximum length)
- * of a DBusString
+ * The maximum length of a DBusString
  */
-#define _DBUS_STRING_MAX_MAX_LENGTH (_DBUS_INT32_MAX - _DBUS_STRING_ALLOCATION_PADDING)
+#define _DBUS_STRING_MAX_LENGTH (_DBUS_INT32_MAX - _DBUS_STRING_ALLOCATION_PADDING)
 
 /**
  * Checks a bunch of assertions about a string object
  *
  * @param real the DBusRealString
  */
-#define DBUS_GENERIC_STRING_PREAMBLE(real) _dbus_assert ((real) != NULL); _dbus_assert (!(real)->invalid); _dbus_assert ((real)->len >= 0); _dbus_assert ((real)->allocated >= 0); _dbus_assert ((real)->max_length >= 0); _dbus_assert ((real)->len <= ((real)->allocated - _DBUS_STRING_ALLOCATION_PADDING)); _dbus_assert ((real)->len <= (real)->max_length)
+#define DBUS_GENERIC_STRING_PREAMBLE(real) \
+  do { \
+      (void) real; /* might be unused unless asserting */ \
+      _dbus_assert ((real) != NULL); \
+      _dbus_assert (!(real)->invalid); \
+      _dbus_assert ((real)->len >= 0); \
+      _dbus_assert ((real)->allocated >= 0); \
+      _dbus_assert ((real)->len <= ((real)->allocated - _DBUS_STRING_ALLOCATION_PADDING)); \
+      _dbus_assert ((real)->len <= _DBUS_STRING_MAX_LENGTH); \
+  } while (0)
 
 /**
  * Checks assertions about a string object that needs to be
diff --git a/dbus/dbus-string-util.c b/dbus/dbus-string-util.c
index 4d42bb0..922580d 100644
--- a/dbus/dbus-string-util.c
+++ b/dbus/dbus-string-util.c
@@ -120,26 +120,6 @@
 #include <stdio.h>
 
 static void
-test_max_len (DBusString *str,
-              int         max_len)
-{
-  if (max_len > 0)
-    {
-      if (!_dbus_string_set_length (str, max_len - 1))
-        _dbus_assert_not_reached ("setting len to one less than max should have worked");
-    }
-
-  if (!_dbus_string_set_length (str, max_len))
-    _dbus_assert_not_reached ("setting len to max len should have worked");
-
-  if (_dbus_string_set_length (str, max_len + 1))
-    _dbus_assert_not_reached ("setting len to one more than max len should not have worked");
-
-  if (!_dbus_string_set_length (str, 0))
-    _dbus_assert_not_reached ("setting len to zero should have worked");
-}
-
-static void
 test_hex_roundtrip (const unsigned char *data,
                     int                  len)
 {
@@ -232,25 +212,6 @@
   }
 }
 
-#ifdef DBUS_BUILD_TESTS
-/* The max length thing is sort of a historical artifact
- * from a feature that turned out to be dumb; perhaps
- * we should purge it entirely. The problem with
- * the feature is that it looks like memory allocation
- * failure, but is not a transient or resolvable failure.
- */
-static void
-set_max_length (DBusString *str,
-                int         max_length)
-{
-  DBusRealString *real;
-  
-  real = (DBusRealString*) str;
-
-  real->max_length = max_length;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * @ingroup DBusStringInternals
  * Unit test for DBusString.
@@ -266,26 +227,10 @@
 {
   DBusString str;
   DBusString other;
-  int i, end;
+  int i, a, end;
   long v;
-  double d;
   int lens[] = { 0, 1, 2, 3, 4, 5, 10, 16, 17, 18, 25, 31, 32, 33, 34, 35, 63, 64, 65, 66, 67, 68, 69, 70, 71, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136 };
   char *s;
-  dbus_unichar_t ch;
-  
-  i = 0;
-  while (i < _DBUS_N_ELEMENTS (lens))
-    {
-      if (!_dbus_string_init (&str))
-        _dbus_assert_not_reached ("failed to init string");
-
-      set_max_length (&str, lens[i]);
-      
-      test_max_len (&str, lens[i]);
-      _dbus_string_free (&str);
-
-      ++i;
-    }
 
   /* Test shortening and setting length */
   i = 0;
@@ -296,8 +241,6 @@
       if (!_dbus_string_init (&str))
         _dbus_assert_not_reached ("failed to init string");
 
-      set_max_length (&str, lens[i]);
-      
       if (!_dbus_string_set_length (&str, lens[i]))
         _dbus_assert_not_reached ("failed to set string length");
 
@@ -513,25 +456,93 @@
   _dbus_assert (_dbus_string_get_length (&other) == i * 2 - 1);
   _dbus_assert (_dbus_string_equal_c_str (&other,
                                           "HelloHello WorldWorle"));
-  
+
   _dbus_string_free (&str);
   _dbus_string_free (&other);
-  
-  /* Check append/get unichar */
-  
+
+  /* Different tests are provided because different behaviours are
+   * implemented in _dbus_string_replace_len() in function of replacing and
+   * replaced lengths
+   */
+
   if (!_dbus_string_init (&str))
     _dbus_assert_not_reached ("failed to init string");
+  
+  if (!_dbus_string_append (&str, "Hello World"))
+    _dbus_assert_not_reached ("could not append to string");
 
-  ch = 0;
-  if (!_dbus_string_append_unichar (&str, 0xfffc))
-    _dbus_assert_not_reached ("failed to append unichar");
+  i = _dbus_string_get_length (&str);
+  
+  if (!_dbus_string_init (&other))
+    _dbus_assert_not_reached ("could not init string");
 
-  _dbus_string_get_unichar (&str, 0, &ch, &i);
+  if (!_dbus_string_append (&other, "Foo String"))
+    _dbus_assert_not_reached ("could not append to string");
 
-  _dbus_assert (ch == 0xfffc);
-  _dbus_assert (i == _dbus_string_get_length (&str));
+  a = _dbus_string_get_length (&other);
+
+  if (!_dbus_string_replace_len (&str, 0, 6,
+                                 &other, 4, 0))
+    _dbus_assert_not_reached ("could not replace 0 length");
+
+  _dbus_assert (_dbus_string_get_length (&str) == i);
+  _dbus_assert (_dbus_string_get_length (&other) == a + 6);
+  _dbus_assert (_dbus_string_equal_c_str (&other,
+                                          "Foo Hello String"));
+
+  if (!_dbus_string_replace_len (&str, 5, 6,
+                                 &other,
+                                 _dbus_string_get_length (&other),
+                                 0))
+    _dbus_assert_not_reached ("could not replace at the end");
+
+  _dbus_assert (_dbus_string_get_length (&str) == i);
+  _dbus_assert (_dbus_string_get_length (&other) == a + 6 + 6);
+  _dbus_assert (_dbus_string_equal_c_str (&other,
+                                          "Foo Hello String World"));
+
+  if (!_dbus_string_replace_len (&str, 0, 5,
+                                 &other,
+                                 _dbus_string_get_length (&other) - 5,
+                                 5))
+    _dbus_assert_not_reached ("could not replace same length");
+
+  _dbus_assert (_dbus_string_get_length (&str) == i);
+  _dbus_assert (_dbus_string_get_length (&other) == a + 6 + 6);
+  _dbus_assert (_dbus_string_equal_c_str (&other,
+                                          "Foo Hello String Hello"));
+
+  if (!_dbus_string_replace_len (&str, 6, 5,
+                                 &other, 4, 12))
+    _dbus_assert_not_reached ("could not replace with shorter string");
+
+  _dbus_assert (_dbus_string_get_length (&str) == i);
+  _dbus_assert (_dbus_string_get_length (&other) == a + 5);
+  _dbus_assert (_dbus_string_equal_c_str (&other,
+                                          "Foo World Hello"));
+
+  if (!_dbus_string_replace_len (&str, 0, 1,
+                                 &other, 0, 3))
+    _dbus_assert_not_reached ("could not replace at the beginning");
+
+  _dbus_assert (_dbus_string_get_length (&str) == i);
+  _dbus_assert (_dbus_string_get_length (&other) == a + 3);
+  _dbus_assert (_dbus_string_equal_c_str (&other,
+                                          "H World Hello"));
+
+  if (!_dbus_string_replace_len (&str, 6, 5,
+                                 &other,
+                                 _dbus_string_get_length (&other) - 5,
+                                 5))
+    _dbus_assert_not_reached ("could not replace same length");
+
+  _dbus_assert (_dbus_string_get_length (&str) == i);
+  _dbus_assert (_dbus_string_get_length (&other) == a + 3);
+  _dbus_assert (_dbus_string_equal_c_str (&other,
+                                          "H World World"));
 
   _dbus_string_free (&str);
+  _dbus_string_free (&other);
 
   /* Check insert/set/get byte */
   
@@ -590,22 +601,6 @@
   _dbus_assert (end == i);
 
   _dbus_string_free (&str);
-  
-  if (!_dbus_string_init (&str))
-    _dbus_assert_not_reached ("failed to init string");
-  
-  if (!_dbus_string_append_double (&str, 50.3))
-    _dbus_assert_not_reached ("failed to append float");
-
-  i = _dbus_string_get_length (&str);
-
-  if (!_dbus_string_parse_double (&str, 0, &d, &end))
-    _dbus_assert_not_reached ("failed to parse float");
-
-  _dbus_assert (d > (50.3 - 1e-6) && d < (50.3 + 1e-6));
-  _dbus_assert (end == i);
-
-  _dbus_string_free (&str);
 
   /* Test find */
   if (!_dbus_string_init (&str))
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
index 1ccf147..9accdb1 100644
--- a/dbus/dbus-string.c
+++ b/dbus/dbus-string.c
@@ -154,7 +154,6 @@
   real->len = 0;
   real->str[real->len] = '\0';
   
-  real->max_length = _DBUS_STRING_MAX_MAX_LENGTH;
   real->constant = FALSE;
   real->locked = FALSE;
   real->invalid = FALSE;
@@ -178,25 +177,6 @@
   return _dbus_string_init_preallocated (str, 0);
 }
 
-#ifdef DBUS_BUILD_TESTS
-/* The max length thing is sort of a historical artifact
- * from a feature that turned out to be dumb; perhaps
- * we should purge it entirely. The problem with
- * the feature is that it looks like memory allocation
- * failure, but is not a transient or resolvable failure.
- */
-static void
-set_max_length (DBusString *str,
-                int         max_length)
-{
-  DBusRealString *real;
-  
-  real = (DBusRealString*) str;
-
-  real->max_length = max_length;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Initializes a constant string. The value parameter is not copied
  * (should be static), and the string may never be modified.
@@ -235,7 +215,7 @@
   
   _dbus_assert (str != NULL);
   _dbus_assert (len == 0 || value != NULL);
-  _dbus_assert (len <= _DBUS_STRING_MAX_MAX_LENGTH);
+  _dbus_assert (len <= _DBUS_STRING_MAX_LENGTH);
   _dbus_assert (len >= 0);
   
   real = (DBusRealString*) str;
@@ -243,7 +223,6 @@
   real->str = (unsigned char*) value;
   real->len = len;
   real->allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING; /* a lie, just to avoid special-case assertions... */
-  real->max_length = real->len + 1;
   real->constant = TRUE;
   real->locked = TRUE;
   real->invalid = FALSE;
@@ -336,8 +315,8 @@
   /* at least double our old allocation to avoid O(n), avoiding
    * overflow
    */
-  if (real->allocated > (_DBUS_STRING_MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING) / 2)
-    new_allocated = _DBUS_STRING_MAX_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING;
+  if (real->allocated > (_DBUS_STRING_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING) / 2)
+    new_allocated = _DBUS_STRING_MAX_LENGTH + _DBUS_STRING_ALLOCATION_PADDING;
   else
     new_allocated = real->allocated * 2;
 
@@ -400,7 +379,7 @@
   /* Note, we are setting the length not including nul termination */
 
   /* exceeding max length is the same as failure to allocate memory */
-  if (_DBUS_UNLIKELY (new_length > real->max_length))
+  if (_DBUS_UNLIKELY (new_length > _DBUS_STRING_MAX_LENGTH))
     return FALSE;
   else if (new_length > (real->allocated - _DBUS_STRING_ALLOCATION_PADDING) &&
            _DBUS_UNLIKELY (!reallocate_for_length (real, new_length)))
@@ -421,7 +400,7 @@
   if (len == 0)
     return TRUE;
 
-  if (len > dest->max_length - dest->len)
+  if (len > _DBUS_STRING_MAX_LENGTH - dest->len)
     return FALSE; /* detected overflow of dest->len + len below */
   
   if (!set_length (dest, dest->len + len))
@@ -640,7 +619,6 @@
 _dbus_string_steal_data (DBusString        *str,
                          char             **data_return)
 {
-  int old_max_length;
   DBUS_STRING_PREAMBLE (str);
   _dbus_assert (data_return != NULL);
 
@@ -648,8 +626,6 @@
   
   *data_return = (char*) real->str;
 
-  old_max_length = real->max_length;
-  
   /* reset the string */
   if (!_dbus_string_init (str))
     {
@@ -660,64 +636,9 @@
       return FALSE;
     }
 
-  real->max_length = old_max_length;
-
   return TRUE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Like _dbus_string_get_data_len(), but removes the gotten data from
- * the original string. The caller must free the data returned. This
- * function may fail due to lack of memory, and return #FALSE.
- * The returned string is nul-terminated and has length len.
- *
- * @todo this function is broken because on failure it
- * may corrupt the source string.
- * 
- * @param str the string
- * @param data_return location to return the buffer
- * @param start the start of segment to steal
- * @param len the length of segment to steal
- * @returns #TRUE on success
- */
-dbus_bool_t
-_dbus_string_steal_data_len (DBusString        *str,
-                             char             **data_return,
-                             int                start,
-                             int                len)
-{
-  DBusString dest;
-  DBUS_STRING_PREAMBLE (str);
-  _dbus_assert (data_return != NULL);
-  _dbus_assert (start >= 0);
-  _dbus_assert (len >= 0);
-  _dbus_assert (start <= real->len);
-  _dbus_assert (len <= real->len - start);
-
-  if (!_dbus_string_init (&dest))
-    return FALSE;
-
-  set_max_length (&dest, real->max_length);
-  
-  if (!_dbus_string_move_len (str, start, len, &dest, 0))
-    {
-      _dbus_string_free (&dest);
-      return FALSE;
-    }
-
-  _dbus_warn ("Broken code in _dbus_string_steal_data_len(), see @todo, FIXME\n");
-  if (!_dbus_string_steal_data (&dest, data_return))
-    {
-      _dbus_string_free (&dest);
-      return FALSE;
-    }
-
-  _dbus_string_free (&dest);
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Copies the data from the string into a char*
  *
@@ -785,53 +706,6 @@
   memcpy (buffer, real->str, real->len+1);
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Copies a segment of the string into a char*
- *
- * @param str the string
- * @param data_return place to return the data
- * @param start start index
- * @param len length to copy
- * @returns #FALSE if no memory
- */
-dbus_bool_t
-_dbus_string_copy_data_len (const DBusString  *str,
-                            char             **data_return,
-                            int                start,
-                            int                len)
-{
-  DBusString dest;
-
-  DBUS_CONST_STRING_PREAMBLE (str);
-  _dbus_assert (data_return != NULL);
-  _dbus_assert (start >= 0);
-  _dbus_assert (len >= 0);
-  _dbus_assert (start <= real->len);
-  _dbus_assert (len <= real->len - start);
-
-  if (!_dbus_string_init (&dest))
-    return FALSE;
-
-  set_max_length (&dest, real->max_length);
-
-  if (!_dbus_string_copy_len (str, start, len, &dest, 0))
-    {
-      _dbus_string_free (&dest);
-      return FALSE;
-    }
-
-  if (!_dbus_string_steal_data (&dest, data_return))
-    {
-      _dbus_string_free (&dest);
-      return FALSE;
-    }
-
-  _dbus_string_free (&dest);
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /* Only have the function if we don't have the macro */
 #ifndef _dbus_string_get_length
 /**
@@ -842,11 +716,7 @@
 int
 _dbus_string_get_length (const DBusString  *str)
 {
-  /* The assertion should not fail for empty strings. */
-  DBusRealString *real = (DBusRealString *)str;
-  if (((DBusRealString *)str)->len || ((DBusRealString *)str)->allocated) {
-      DBUS_CONST_STRING_PREAMBLE (str);
-  }
+  DBUS_CONST_STRING_PREAMBLE (str);
   
   return real->len;
 }
@@ -871,7 +741,7 @@
   DBUS_STRING_PREAMBLE (str);  
   _dbus_assert (additional_length >= 0);
 
-  if (_DBUS_UNLIKELY (additional_length > real->max_length - real->len))
+  if (_DBUS_UNLIKELY (additional_length > _DBUS_STRING_MAX_LENGTH - real->len))
     return FALSE; /* would overflow */
   
   return set_length (real,
@@ -937,7 +807,7 @@
   gap_pos = _DBUS_ALIGN_VALUE (insert_at, alignment);
   new_len = real->len + (gap_pos - insert_at) + gap_size;
   
-  if (_DBUS_UNLIKELY (new_len > (unsigned long) real->max_length))
+  if (_DBUS_UNLIKELY (new_len > (unsigned long) _DBUS_STRING_MAX_LENGTH))
     return FALSE;
   
   delta = new_len - real->len;
@@ -1049,7 +919,7 @@
   _dbus_assert (buffer != NULL);
   
   buffer_len = strlen (buffer);
-  if (buffer_len > (unsigned long) real->max_length)
+  if (buffer_len > (unsigned long) _DBUS_STRING_MAX_LENGTH)
     return FALSE;
   
   return append (real, buffer, buffer_len);
@@ -1087,54 +957,6 @@
 } while (0)
 #endif /* DBUS_HAVE_INT64 */
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Appends 4 bytes aligned on a 4 byte boundary
- * with any alignment padding initialized to 0.
- *
- * @param str the DBusString
- * @param octets 4 bytes to append
- * @returns #FALSE if not enough memory.
- */
-dbus_bool_t
-_dbus_string_append_4_aligned (DBusString         *str,
-                               const unsigned char octets[4])
-{
-  DBUS_STRING_PREAMBLE (str);
-  
-  if (!align_length_then_lengthen (str, 4, 4))
-    return FALSE;
-
-  ASSIGN_4_OCTETS (real->str + (real->len - 4), octets);
-
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
-#ifdef DBUS_BUILD_TESTS
-/**
- * Appends 8 bytes aligned on an 8 byte boundary
- * with any alignment padding initialized to 0.
- *
- * @param str the DBusString
- * @param octets 8 bytes to append
- * @returns #FALSE if not enough memory.
- */
-dbus_bool_t
-_dbus_string_append_8_aligned (DBusString         *str,
-                               const unsigned char octets[8])
-{
-  DBUS_STRING_PREAMBLE (str);
-  
-  if (!align_length_then_lengthen (str, 8, 8))
-    return FALSE;
-
-  ASSIGN_8_OCTETS (real->str + (real->len - 8), octets);
-
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Inserts 2 bytes aligned on a 2 byte boundary
  * with any alignment padding initialized to 0.
@@ -1259,6 +1081,9 @@
   /* Measure the message length without terminating nul */
   len = _dbus_printf_string_upper_bound (format, args);
 
+  if (len < 0)
+    return FALSE;
+
   if (!_dbus_string_lengthen (str, len))
     {
       /* don't leak the copy */
@@ -1339,79 +1164,6 @@
   return TRUE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Appends a single Unicode character, encoding the character
- * in UTF-8 format.
- *
- * @param str the string
- * @param ch the Unicode character
- */
-dbus_bool_t
-_dbus_string_append_unichar (DBusString    *str,
-                             dbus_unichar_t ch)
-{
-  int len;
-  int first;
-  int i;
-  unsigned char *out;
-  
-  DBUS_STRING_PREAMBLE (str);
-
-  /* this code is from GLib but is pretty standard I think */
-  
-  len = 0;
-  
-  if (ch < 0x80)
-    {
-      first = 0;
-      len = 1;
-    }
-  else if (ch < 0x800)
-    {
-      first = 0xc0;
-      len = 2;
-    }
-  else if (ch < 0x10000)
-    {
-      first = 0xe0;
-      len = 3;
-    }
-   else if (ch < 0x200000)
-    {
-      first = 0xf0;
-      len = 4;
-    }
-  else if (ch < 0x4000000)
-    {
-      first = 0xf8;
-      len = 5;
-    }
-  else
-    {
-      first = 0xfc;
-      len = 6;
-    }
-
-  if (len > (real->max_length - real->len))
-    return FALSE; /* real->len + len would overflow */
-  
-  if (!set_length (real, real->len + len))
-    return FALSE;
-
-  out = real->str + (real->len - len);
-  
-  for (i = len - 1; i > 0; --i)
-    {
-      out[i] = (ch & 0x3f) | 0x80;
-      ch >>= 6;
-    }
-  out[0] = ch | first;
-
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 static void
 delete (DBusRealString *real,
         int             start,
@@ -1542,9 +1294,6 @@
  * Like _dbus_string_move(), but can move a segment from
  * the middle of the source string.
  *
- * @todo this doesn't do anything with max_length field.
- * we should probably just kill the max_length field though.
- * 
  * @param source the source string
  * @param start first byte of source string to move
  * @param len length of segment to move
@@ -1639,15 +1388,6 @@
 /**
  * Replaces a segment of dest string with a segment of source string.
  *
- * @todo optimize the case where the two lengths are the same, and
- * avoid memmoving the data in the trailing part of the string twice.
- *
- * @todo avoid inserting the source into dest, then deleting
- * the replaced chunk of dest (which creates a potentially large
- * intermediate string). Instead, extend the replaced chunk
- * of dest with padding to the same size as the source chunk,
- * then copy in the source bytes.
- * 
  * @param source the source string
  * @param start where to start copying the source string
  * @param len length of segment to copy
@@ -1673,11 +1413,37 @@
   _dbus_assert (replace_at <= real_dest->len);
   _dbus_assert (replace_len <= real_dest->len - replace_at);
 
-  if (!copy (real_source, start, len,
-             real_dest, replace_at))
-    return FALSE;
+  if (len == replace_len)
+    {
+      memmove (real_dest->str + replace_at,
+               real_source->str + start, len);
+    }
+  else if (len < replace_len)
+    {
+      memmove (real_dest->str + replace_at,
+               real_source->str + start, len);
+      delete (real_dest, replace_at + len,
+              replace_len - len);
+    }
+  else
+    {
+      int diff;
 
-  delete (real_dest, replace_at + len, replace_len);
+      _dbus_assert (len > replace_len);
+
+      diff = len - replace_len;
+
+      /* First of all we check if destination string can be enlarged as
+       * required, then we overwrite previous bytes
+       */
+
+      if (!copy (real_source, start + replace_len, diff,
+                 real_dest, replace_at + replace_len))
+        return FALSE;
+
+      memmove (real_dest->str + replace_at,
+               real_source->str + start, replace_len);
+    }
 
   return TRUE;
 }
@@ -1825,55 +1591,6 @@
      ((Char) < 0xFDD0 || (Char) > 0xFDEF) &&  \
      ((Char) & 0xFFFE) != 0xFFFE)
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Gets a unicode character from a UTF-8 string. Does no validation;
- * you must verify that the string is valid UTF-8 in advance and must
- * pass in the start of a character.
- *
- * @param str the string
- * @param start the start of the UTF-8 character.
- * @param ch_return location to return the character
- * @param end_return location to return the byte index of next character
- */
-void
-_dbus_string_get_unichar (const DBusString *str,
-                          int               start,
-                          dbus_unichar_t   *ch_return,
-                          int              *end_return)
-{
-  int i, mask, len;
-  dbus_unichar_t result;
-  unsigned char c;
-  unsigned char *p;
-  DBUS_CONST_STRING_PREAMBLE (str);
-  _dbus_assert (start >= 0);
-  _dbus_assert (start <= real->len);
-  
-  if (ch_return)
-    *ch_return = 0;
-  if (end_return)
-    *end_return = real->len;
-  
-  mask = 0;
-  p = real->str + start;
-  c = *p;
-  
-  UTF8_COMPUTE (c, mask, len);
-  if (len == 0)
-    return;
-  UTF8_GET (result, p, i, mask, len);
-
-  if (result == (dbus_unichar_t)-1)
-    return;
-
-  if (ch_return)
-    *ch_return = result;
-  if (end_return)
-    *end_return = start + len;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Finds the given substring in the string,
  * returning #TRUE and filling in the byte index
@@ -2465,7 +2182,6 @@
   return TRUE;
 }
 
-#ifdef DBUS_BUILD_TESTS
 /**
  * Checks whether a string starts with the given C string.
  *
@@ -2501,7 +2217,6 @@
   else
     return FALSE;
 }
-#endif /* DBUS_BUILD_TESTS */
 
 /**
  * Appends a two-character hex digit to a string, where the hex digit
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
index 2f1ed31..4ef59db 100644
--- a/dbus/dbus-string.h
+++ b/dbus/dbus-string.h
@@ -48,11 +48,10 @@
 #endif
   int   dummy2;       /**< placeholder */
   int   dummy3;       /**< placeholder */
-  int   dummy4;       /**< placeholder */
-  unsigned int dummy5 : 1; /**< placeholder */
-  unsigned int dummy6 : 1; /**< placeholder */
-  unsigned int dummy7 : 1; /**< placeholder */
-  unsigned int dummy8 : 3; /**< placeholder */
+  unsigned int dummy_bit1 : 1; /**< placeholder */
+  unsigned int dummy_bit2 : 1; /**< placeholder */
+  unsigned int dummy_bit3 : 1; /**< placeholder */
+  unsigned int dummy_bits : 3; /**< placeholder */
 };
 
 #ifdef DBUS_DISABLE_ASSERT
@@ -151,16 +150,8 @@
                                                   long               value);
 dbus_bool_t   _dbus_string_append_uint           (DBusString        *str,
                                                   unsigned long      value);
-dbus_bool_t   _dbus_string_append_double         (DBusString        *str,
-                                                  double             value);
 dbus_bool_t   _dbus_string_append_byte           (DBusString        *str,
                                                   unsigned char      byte);
-dbus_bool_t   _dbus_string_append_unichar        (DBusString        *str,
-                                                  dbus_unichar_t     ch);
-dbus_bool_t   _dbus_string_append_4_aligned      (DBusString        *str,
-                                                  const unsigned char octets[4]);
-dbus_bool_t   _dbus_string_append_8_aligned      (DBusString        *str,
-                                                  const unsigned char octets[8]);
 dbus_bool_t   _dbus_string_append_printf         (DBusString        *str,
                                                   const char        *format,
                                                   ...) _DBUS_GNUC_PRINTF (2, 3);
@@ -209,10 +200,6 @@
 dbus_bool_t   _dbus_string_split_on_byte         (DBusString        *source,
                                                   unsigned char      byte,
                                                   DBusString        *tail);
-void          _dbus_string_get_unichar           (const DBusString  *str,
-                                                  int                start,
-                                                  dbus_unichar_t    *ch_return,
-                                                  int               *end_return);
 dbus_bool_t   _dbus_string_parse_int             (const DBusString  *str,
                                                   int                start,
                                                   long              *value_return,
@@ -221,10 +208,6 @@
                                                   int                start,
                                                   unsigned long     *value_return,
                                                   int               *end_return);
-dbus_bool_t   _dbus_string_parse_double          (const DBusString  *str,
-                                                  int                start,
-                                                  double            *value,
-                                                  int               *end_return);
 dbus_bool_t   _dbus_string_find                  (const DBusString  *str,
                                                   int                start,
                                                   const char        *substr,
@@ -324,7 +307,6 @@
                                    sizeof(_dbus_static_string_##name),  \
                                    sizeof(_dbus_static_string_##name) + \
                                    _DBUS_STRING_ALLOCATION_PADDING,     \
-                                   sizeof(_dbus_static_string_##name),  \
                                    TRUE, TRUE, FALSE, 0 }
 
 DBUS_END_DECLS
diff --git a/dbus/dbus-syntax.c b/dbus/dbus-syntax.c
new file mode 100644
index 0000000..4792287
--- /dev/null
+++ b/dbus/dbus-syntax.c
@@ -0,0 +1,309 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-syntax.c - utility functions for strings with special syntax
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <config.h>
+#include "dbus-syntax.h"
+
+#include "dbus-internals.h"
+#include "dbus-marshal-validate.h"
+#include "dbus-shared.h"
+
+/**
+ * @defgroup DBusSyntax Utility functions for strings with special syntax
+ * @ingroup  DBus
+ * @brief Parsing D-Bus type signatures
+ * @{
+ */
+
+/**
+ * Check an object path for validity. Remember that #NULL can always
+ * be passed instead of a DBusError *, if you don't care about having
+ * an error name and message.
+ *
+ * This function is suitable for validating C strings, but is not suitable
+ * for validating untrusted data from a network unless the string's length
+ * is also checked, since it assumes that the string ends at the first zero
+ * byte according to normal C conventions.
+ *
+ * @param path a potentially invalid object path, which must not be #NULL
+ * @param error error return
+ * @returns #TRUE if path is valid
+ */
+dbus_bool_t
+dbus_validate_path (const char       *path,
+                    DBusError        *error)
+{
+  DBusString str;
+  int len;
+
+  _dbus_return_val_if_fail (path != NULL, FALSE);
+
+  _dbus_string_init_const (&str, path);
+  len = _dbus_string_get_length (&str);
+
+  /* In general, it ought to be valid... */
+  if (_DBUS_LIKELY (_dbus_validate_path (&str, 0, len)))
+    return TRUE;
+
+  /* slow path: string is invalid, find out why */
+
+  if (!_dbus_string_validate_utf8 (&str, 0, len))
+    {
+      /* don't quote the actual string here, since a DBusError also needs to
+       * be valid UTF-8 */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Object path was not valid UTF-8");
+      return FALSE;
+    }
+
+  /* FIXME: later, diagnose exactly how it was invalid */
+  dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                  "Object path was not valid: '%s'", path);
+  return FALSE;
+}
+
+/**
+ * Check an interface name for validity. Remember that #NULL can always
+ * be passed instead of a DBusError *, if you don't care about having
+ * an error name and message.
+ *
+ * This function is suitable for validating C strings, but is not suitable
+ * for validating untrusted data from a network unless the string's length
+ * is also checked, since it assumes that the string ends at the first zero
+ * byte according to normal C conventions.
+ *
+ * @param path a potentially invalid interface name, which must not be #NULL
+ * @param error error return
+ * @returns #TRUE if name is valid
+ */
+dbus_bool_t
+dbus_validate_interface (const char       *name,
+                         DBusError        *error)
+{
+  DBusString str;
+  int len;
+
+  _dbus_return_val_if_fail (name != NULL, FALSE);
+
+  _dbus_string_init_const (&str, name);
+  len = _dbus_string_get_length (&str);
+
+  /* In general, it ought to be valid... */
+  if (_DBUS_LIKELY (_dbus_validate_interface (&str, 0, len)))
+    return TRUE;
+
+  /* slow path: string is invalid, find out why */
+
+  if (!_dbus_string_validate_utf8 (&str, 0, len))
+    {
+      /* don't quote the actual string here, since a DBusError also needs to
+       * be valid UTF-8 */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Interface name was not valid UTF-8");
+      return FALSE;
+    }
+
+  /* FIXME: later, diagnose exactly how it was invalid */
+  dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                  "Interface name was not valid: '%s'", name);
+  return FALSE;
+}
+
+/**
+ * Check a member (method/signal) name for validity. Remember that #NULL
+ * can always be passed instead of a DBusError *, if you don't care about
+ * having an error name and message.
+ *
+ * This function is suitable for validating C strings, but is not suitable
+ * for validating untrusted data from a network unless the string's length
+ * is also checked, since it assumes that the string ends at the first zero
+ * byte according to normal C conventions.
+ *
+ * @param path a potentially invalid member name, which must not be #NULL
+ * @param error error return
+ * @returns #TRUE if name is valid
+ */
+dbus_bool_t
+dbus_validate_member (const char       *name,
+                      DBusError        *error)
+{
+  DBusString str;
+  int len;
+
+  _dbus_return_val_if_fail (name != NULL, FALSE);
+
+  _dbus_string_init_const (&str, name);
+  len = _dbus_string_get_length (&str);
+
+  /* In general, it ought to be valid... */
+  if (_DBUS_LIKELY (_dbus_validate_member (&str, 0, len)))
+    return TRUE;
+
+  /* slow path: string is invalid, find out why */
+
+  if (!_dbus_string_validate_utf8 (&str, 0, len))
+    {
+      /* don't quote the actual string here, since a DBusError also needs to
+       * be valid UTF-8 */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Member name was not valid UTF-8");
+      return FALSE;
+    }
+
+  /* FIXME: later, diagnose exactly how it was invalid */
+  dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                  "Member name was not valid: '%s'", name);
+  return FALSE;
+}
+
+/**
+ * Check an error name for validity. Remember that #NULL
+ * can always be passed instead of a DBusError *, if you don't care about
+ * having an error name and message.
+ *
+ * This function is suitable for validating C strings, but is not suitable
+ * for validating untrusted data from a network unless the string's length
+ * is also checked, since it assumes that the string ends at the first zero
+ * byte according to normal C conventions.
+ *
+ * @param path a potentially invalid error name, which must not be #NULL
+ * @param error error return
+ * @returns #TRUE if name is valid
+ */
+dbus_bool_t
+dbus_validate_error_name (const char       *name,
+                          DBusError        *error)
+{
+  DBusString str;
+  int len;
+
+  _dbus_return_val_if_fail (name != NULL, FALSE);
+
+  _dbus_string_init_const (&str, name);
+  len = _dbus_string_get_length (&str);
+
+  /* In general, it ought to be valid... */
+  if (_DBUS_LIKELY (_dbus_validate_error_name (&str, 0, len)))
+    return TRUE;
+
+  /* slow path: string is invalid, find out why */
+
+  if (!_dbus_string_validate_utf8 (&str, 0, len))
+    {
+      /* don't quote the actual string here, since a DBusError also needs to
+       * be valid UTF-8 */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Error name was not valid UTF-8");
+      return FALSE;
+    }
+
+  /* FIXME: later, diagnose exactly how it was invalid */
+  dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                  "Error name was not valid: '%s'", name);
+  return FALSE;
+}
+
+/**
+ * Check a bus name for validity. Remember that #NULL
+ * can always be passed instead of a DBusError *, if you don't care about
+ * having an error name and message.
+ *
+ * This function is suitable for validating C strings, but is not suitable
+ * for validating untrusted data from a network unless the string's length
+ * is also checked, since it assumes that the string ends at the first zero
+ * byte according to normal C conventions.
+ *
+ * @param path a potentially invalid bus name, which must not be #NULL
+ * @param error error return
+ * @returns #TRUE if name is valid
+ */
+dbus_bool_t
+dbus_validate_bus_name (const char       *name,
+                        DBusError        *error)
+{
+  DBusString str;
+  int len;
+
+  _dbus_return_val_if_fail (name != NULL, FALSE);
+
+  _dbus_string_init_const (&str, name);
+  len = _dbus_string_get_length (&str);
+
+  /* In general, it ought to be valid... */
+  if (_DBUS_LIKELY (_dbus_validate_bus_name (&str, 0, len)))
+    return TRUE;
+
+  /* slow path: string is invalid, find out why */
+
+  if (!_dbus_string_validate_utf8 (&str, 0, len))
+    {
+      /* don't quote the actual string here, since a DBusError also needs to
+       * be valid UTF-8 */
+      dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                      "Bus name was not valid UTF-8");
+      return FALSE;
+    }
+
+  /* FIXME: later, diagnose exactly how it was invalid */
+  dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                  "Bus name was not valid: '%s'", name);
+  return FALSE;
+}
+
+/**
+ * Check a string for validity. Strings on D-Bus must be valid UTF-8.
+ * Remember that #NULL can always be passed instead of a DBusError *,
+ * if you don't care about having an error name and message.
+ *
+ * This function is suitable for validating C strings, but is not suitable
+ * for validating untrusted data from a network unless the string's length
+ * is also checked, since it assumes that the string ends at the first zero
+ * byte according to normal C conventions.
+ *
+ * @param alleged_utf8 a string to be checked, which must not be #NULL
+ * @param error error return
+ * @returns #TRUE if alleged_utf8 is valid UTF-8
+ */
+dbus_bool_t
+dbus_validate_utf8 (const char       *alleged_utf8,
+                    DBusError        *error)
+{
+  DBusString str;
+
+  _dbus_return_val_if_fail (alleged_utf8 != NULL, FALSE);
+
+  _dbus_string_init_const (&str, alleged_utf8);
+
+  if (_DBUS_LIKELY (_dbus_string_validate_utf8 (&str, 0,
+                                                _dbus_string_get_length (&str))))
+    return TRUE;
+
+  /* don't quote the actual string here, since a DBusError also needs to
+   * be valid UTF-8 */
+  dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+                  "String was not valid UTF-8");
+  return FALSE;
+}
+
+/** @} */ /* end of group */
diff --git a/dbus/dbus-syntax.h b/dbus/dbus-syntax.h
new file mode 100644
index 0000000..daf20f0
--- /dev/null
+++ b/dbus/dbus-syntax.h
@@ -0,0 +1,58 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-syntax.h - utility functions for strings with special syntax
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION)
+#error "Only <dbus/dbus.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef DBUS_SYNTAX_H
+#define DBUS_SYNTAX_H
+
+#include <dbus/dbus-macros.h>
+#include <dbus/dbus-types.h>
+#include <dbus/dbus-errors.h>
+
+DBUS_BEGIN_DECLS
+
+DBUS_EXPORT
+dbus_bool_t     dbus_validate_path                   (const char *path,
+                                                      DBusError  *error);
+DBUS_EXPORT
+dbus_bool_t     dbus_validate_interface              (const char *name,
+                                                      DBusError  *error);
+DBUS_EXPORT
+dbus_bool_t     dbus_validate_member                 (const char *name,
+                                                      DBusError  *error);
+DBUS_EXPORT
+dbus_bool_t     dbus_validate_error_name             (const char *name,
+                                                      DBusError  *error);
+DBUS_EXPORT
+dbus_bool_t     dbus_validate_bus_name               (const char *name,
+                                                      DBusError  *error);
+DBUS_EXPORT
+dbus_bool_t     dbus_validate_utf8                   (const char *alleged_utf8,
+                                                      DBusError  *error);
+
+DBUS_END_DECLS
+
+#endif /* multiple-inclusion guard */
diff --git a/dbus/dbus-sysdeps-pthread.c b/dbus/dbus-sysdeps-pthread.c
index 1483c24..c60457b 100644
--- a/dbus/dbus-sysdeps-pthread.c
+++ b/dbus/dbus-sysdeps-pthread.c
@@ -43,18 +43,17 @@
  */
 static dbus_bool_t have_monotonic_clock = 0;
 
-typedef struct {
-  pthread_mutex_t lock; /**< lock protecting count field */
-  volatile int count;   /**< count of how many times lock holder has recursively locked */
-  volatile pthread_t holder; /**< holder of the lock if count >0,
-                                valid but arbitrary thread if count
-                                has ever been >0, uninitialized memory
-                                if count has never been >0 */
-} DBusMutexPThread;
+struct DBusRMutex {
+  pthread_mutex_t lock; /**< the lock */
+};
 
-typedef struct {
+struct DBusCMutex {
+  pthread_mutex_t lock; /**< the lock */
+};
+
+struct DBusCondVar {
   pthread_cond_t cond; /**< the condition */
-} DBusCondVarPThread;
+};
 
 #define DBUS_MUTEX(m)         ((DBusMutex*) m)
 #define DBUS_MUTEX_PTHREAD(m) ((DBusMutexPThread*) m)
@@ -77,13 +76,13 @@
 } while (0)
 #endif /* !DBUS_DISABLE_ASSERT */
 
-static DBusMutex*
-_dbus_pthread_mutex_new (void)
+DBusCMutex *
+_dbus_platform_cmutex_new (void)
 {
-  DBusMutexPThread *pmutex;
+  DBusCMutex *pmutex;
   int result;
-  
-  pmutex = dbus_new (DBusMutexPThread, 1);
+
+  pmutex = dbus_new (DBusCMutex, 1);
   if (pmutex == NULL)
     return NULL;
 
@@ -99,105 +98,84 @@
       PTHREAD_CHECK ("pthread_mutex_init", result);
     }
 
-  /* Only written */
-  pmutex->count = 0;
-
-  /* There's no portable way to have a "null" pthread afaik so we
-   * can't set pmutex->holder to anything sensible.  We only access it
-   * once the lock is held (which means we've set it).
-   */
-  
-  return DBUS_MUTEX (pmutex);
+  return pmutex;
 }
 
-static void
-_dbus_pthread_mutex_free (DBusMutex *mutex)
+DBusRMutex *
+_dbus_platform_rmutex_new (void)
 {
-  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
+  DBusRMutex *pmutex;
+  pthread_mutexattr_t mutexattr;
+  int result;
 
-  _dbus_assert (pmutex->count == 0);
-  
-  PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&pmutex->lock));
+  pmutex = dbus_new (DBusRMutex, 1);
+  if (pmutex == NULL)
+    return NULL;
 
-  dbus_free (pmutex);
-}
+  pthread_mutexattr_init (&mutexattr);
+  pthread_mutexattr_settype (&mutexattr, PTHREAD_MUTEX_RECURSIVE);
+  result = pthread_mutex_init (&pmutex->lock, &mutexattr);
+  pthread_mutexattr_destroy (&mutexattr);
 
-static void
-_dbus_pthread_mutex_lock (DBusMutex *mutex)
-{
-  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
-  pthread_t self = pthread_self ();
-
-  /* If the count is > 0 then someone had the lock, maybe us. If it is
-   * 0, then it might immediately change right after we read it,
-   * but it will be changed by another thread; i.e. if we read 0,
-   * we assume that this thread doesn't have the lock.
-   *
-   * Not 100% sure this is safe, but ... seems like it should be.
-   */
-  if (pmutex->count == 0)
+  if (result == ENOMEM || result == EAGAIN)
     {
-      /* We know we don't have the lock; someone may have the lock. */
-      
-      PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock));
-
-      /* We now have the lock. Count must be 0 since it must be 0 when
-       * the lock is released by another thread, and we just now got
-       * the lock.
-       */
-      _dbus_assert (pmutex->count == 0);
-      
-      pmutex->holder = self;
-      pmutex->count = 1;
+      dbus_free (pmutex);
+      return NULL;
     }
   else
     {
-      /* We know someone had the lock, possibly us. Thus
-       * pmutex->holder is not pointing to junk, though it may not be
-       * the lock holder anymore if the lock holder is not us.  If the
-       * lock holder is us, then we definitely have the lock.
-       */
-
-      if (pthread_equal (pmutex->holder, self))
-        {
-          /* We already have the lock. */
-          _dbus_assert (pmutex->count > 0);
-        }
-      else
-        {
-          /* Wait for the lock */
-          PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&pmutex->lock));
-	  pmutex->holder = self;
-          _dbus_assert (pmutex->count == 0);
-        }
-
-      pmutex->count += 1;
+      PTHREAD_CHECK ("pthread_mutex_init", result);
     }
+
+  return pmutex;
 }
 
-static void
-_dbus_pthread_mutex_unlock (DBusMutex *mutex)
+void
+_dbus_platform_cmutex_free (DBusCMutex *mutex)
 {
-  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
-
-  _dbus_assert (pmutex->count > 0);
-  
-  pmutex->count -= 1;
-
-  if (pmutex->count == 0)
-    PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&pmutex->lock));
-  
-  /* We leave pmutex->holder set to ourselves, its content is undefined if count is 0 */
+  PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&mutex->lock));
+  dbus_free (mutex);
 }
 
-static DBusCondVar *
-_dbus_pthread_condvar_new (void)
+void
+_dbus_platform_rmutex_free (DBusRMutex *mutex)
 {
-  DBusCondVarPThread *pcond;
+  PTHREAD_CHECK ("pthread_mutex_destroy", pthread_mutex_destroy (&mutex->lock));
+  dbus_free (mutex);
+}
+
+void
+_dbus_platform_cmutex_lock (DBusCMutex *mutex)
+{
+  PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&mutex->lock));
+}
+
+void
+_dbus_platform_rmutex_lock (DBusRMutex *mutex)
+{
+  PTHREAD_CHECK ("pthread_mutex_lock", pthread_mutex_lock (&mutex->lock));
+}
+
+void
+_dbus_platform_cmutex_unlock (DBusCMutex *mutex)
+{
+  PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&mutex->lock));
+}
+
+void
+_dbus_platform_rmutex_unlock (DBusRMutex *mutex)
+{
+  PTHREAD_CHECK ("pthread_mutex_unlock", pthread_mutex_unlock (&mutex->lock));
+}
+
+DBusCondVar *
+_dbus_platform_condvar_new (void)
+{
+  DBusCondVar *pcond;
   pthread_condattr_t attr;
   int result;
   
-  pcond = dbus_new (DBusCondVarPThread, 1);
+  pcond = dbus_new (DBusCondVar, 1);
   if (pcond == NULL)
     return NULL;
 
@@ -220,56 +198,31 @@
       PTHREAD_CHECK ("pthread_cond_init", result);
     }
   
-  return DBUS_COND_VAR (pcond);
+  return pcond;
 }
 
-static void
-_dbus_pthread_condvar_free (DBusCondVar *cond)
-{  
-  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
-  
-  PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&pcond->cond));
-
-  dbus_free (pcond);
-}
-
-static void
-_dbus_pthread_condvar_wait (DBusCondVar *cond,
-                            DBusMutex   *mutex)
+void
+_dbus_platform_condvar_free (DBusCondVar *cond)
 {
-  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
-  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
-  int old_count;
-  
-  _dbus_assert (pmutex->count > 0);
-  _dbus_assert (pthread_equal (pmutex->holder, pthread_self ()));
-
-  old_count = pmutex->count;
-  pmutex->count = 0;		/* allow other threads to lock */
-  PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&pcond->cond, &pmutex->lock));
-  _dbus_assert (pmutex->count == 0);
-  pmutex->holder = pthread_self(); /* other threads may have locked the mutex in the meantime */
-
-  /* The order of this line and the above line is important.
-   * See the comments below at the end of _dbus_pthread_condvar_wait_timeout
-   */
-  pmutex->count = old_count;
+  PTHREAD_CHECK ("pthread_cond_destroy", pthread_cond_destroy (&cond->cond));
+  dbus_free (cond);
 }
 
-static dbus_bool_t
-_dbus_pthread_condvar_wait_timeout (DBusCondVar               *cond,
-                                    DBusMutex                 *mutex,
-                                    int                        timeout_milliseconds)
+void
+_dbus_platform_condvar_wait (DBusCondVar *cond,
+                             DBusCMutex  *mutex)
 {
-  DBusMutexPThread *pmutex = DBUS_MUTEX_PTHREAD (mutex);
-  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
+  PTHREAD_CHECK ("pthread_cond_wait", pthread_cond_wait (&cond->cond, &mutex->lock));
+}
+
+dbus_bool_t
+_dbus_platform_condvar_wait_timeout (DBusCondVar               *cond,
+                                     DBusCMutex                *mutex,
+                                     int                        timeout_milliseconds)
+{
   struct timeval time_now;
   struct timespec end_time;
   int result;
-  int old_count;
-  
-  _dbus_assert (pmutex->count > 0);
-  _dbus_assert (pthread_equal (pmutex->holder, pthread_self ()));  
 
 #ifdef HAVE_MONOTONIC_CLOCK
   if (have_monotonic_clock)
@@ -292,70 +245,24 @@
       end_time.tv_nsec -= 1000*1000*1000;
     }
 
-  old_count = pmutex->count;
-  pmutex->count = 0;
-  result = pthread_cond_timedwait (&pcond->cond, &pmutex->lock, &end_time);
+  result = pthread_cond_timedwait (&cond->cond, &mutex->lock, &end_time);
   
   if (result != ETIMEDOUT)
     {
       PTHREAD_CHECK ("pthread_cond_timedwait", result);
     }
 
-  _dbus_assert (pmutex->count == 0);
-  pmutex->holder = pthread_self(); /* other threads may have locked the mutex in the meantime */
-
-  /* restore to old count after setting the owner back to self,
-   * If reversing this line with above line, the previous owner thread could
-   * get into the mutex without proper locking by passing the lock owner check.
-   */
-  pmutex->count = old_count;
-  
   /* return true if we did not time out */
   return result != ETIMEDOUT;
 }
 
-static void
-_dbus_pthread_condvar_wake_one (DBusCondVar *cond)
+void
+_dbus_platform_condvar_wake_one (DBusCondVar *cond)
 {
-  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
-
-  PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&pcond->cond));
+  PTHREAD_CHECK ("pthread_cond_signal", pthread_cond_signal (&cond->cond));
 }
 
 static void
-_dbus_pthread_condvar_wake_all (DBusCondVar *cond)
-{
-  DBusCondVarPThread *pcond = DBUS_COND_VAR_PTHREAD (cond);
-  
-  PTHREAD_CHECK ("pthread_cond_broadcast", pthread_cond_broadcast (&pcond->cond));
-}
-
-static const DBusThreadFunctions pthread_functions =
-{
-  DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK |
-  DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK |
-  DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK |
-  DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
-  NULL, NULL, NULL, NULL,
-  _dbus_pthread_condvar_new,
-  _dbus_pthread_condvar_free,
-  _dbus_pthread_condvar_wait,
-  _dbus_pthread_condvar_wait_timeout,
-  _dbus_pthread_condvar_wake_one,
-  _dbus_pthread_condvar_wake_all,
-  _dbus_pthread_mutex_new,
-  _dbus_pthread_mutex_free,
-  _dbus_pthread_mutex_lock,
-  _dbus_pthread_mutex_unlock
-};
-
-static void
 check_monotonic_clock (void)
 {
 #ifdef HAVE_MONOTONIC_CLOCK
@@ -368,6 +275,11 @@
 dbus_bool_t
 _dbus_threads_init_platform_specific (void)
 {
+  /* These have static variables, and we need to handle both the case
+   * where dbus_threads_init() has been called and when it hasn't;
+   * so initialize them before any threads are allowed to enter.
+   */
   check_monotonic_clock ();
-  return dbus_threads_init (&pthread_functions);
+  (void) _dbus_check_setuid ();
+  return dbus_threads_init (NULL);
 }
diff --git a/dbus/dbus-sysdeps-thread-win.c b/dbus/dbus-sysdeps-thread-win.c
index ab02950..e30e7b8 100644
--- a/dbus/dbus-sysdeps-thread-win.c
+++ b/dbus/dbus-sysdeps-thread-win.c
@@ -90,34 +90,60 @@
   return TRUE;
 }
 
-static DBusMutex*
-_dbus_windows_mutex_new (void)
+DBusCMutex *
+_dbus_platform_cmutex_new (void)
 {
   HANDLE handle;
   handle = CreateMutex (NULL, FALSE, NULL);
-  return (DBusMutex *) handle;
+  return (DBusCMutex *) handle;
 }
 
-static void
-_dbus_windows_mutex_free (DBusMutex *mutex)
+DBusRMutex *
+_dbus_platform_rmutex_new (void)
+{
+  HANDLE handle;
+  handle = CreateMutex (NULL, FALSE, NULL);
+  return (DBusRMutex *) handle;
+}
+
+void
+_dbus_platform_cmutex_free (DBusCMutex *mutex)
 {
   CloseHandle ((HANDLE *) mutex);
 }
 
-static dbus_bool_t
-_dbus_windows_mutex_lock (DBusMutex *mutex)
+void
+_dbus_platform_rmutex_free (DBusRMutex *mutex)
 {
-  return WaitForSingleObject ((HANDLE *) mutex, INFINITE) != WAIT_FAILED;
+  CloseHandle ((HANDLE *) mutex);
 }
 
-static dbus_bool_t
-_dbus_windows_mutex_unlock (DBusMutex *mutex)
+void
+_dbus_platform_cmutex_lock (DBusCMutex *mutex)
 {
-  return ReleaseMutex ((HANDLE *) mutex) != 0;
+  WaitForSingleObject ((HANDLE *) mutex, INFINITE);
 }
 
-static DBusCondVar *
-_dbus_windows_condvar_new (void)
+void
+_dbus_platform_rmutex_lock (DBusRMutex *mutex)
+{
+  WaitForSingleObject ((HANDLE *) mutex, INFINITE);
+}
+
+void
+_dbus_platform_cmutex_unlock (DBusCMutex *mutex)
+{
+  ReleaseMutex ((HANDLE *) mutex);
+}
+
+void
+_dbus_platform_rmutex_unlock (DBusRMutex *mutex)
+{
+  ReleaseMutex ((HANDLE *) mutex);
+}
+
+DBusCondVar *
+_dbus_platform_condvar_new (void)
 {
   DBusCondVar *cond;
     
@@ -128,11 +154,11 @@
   cond->list = NULL;
   
   InitializeCriticalSection (&cond->lock);
-  return (DBusCondVar *) cond;
+  return cond;
 }
 
-static void
-_dbus_windows_condvar_free (DBusCondVar *cond)
+void
+_dbus_platform_condvar_free (DBusCondVar *cond)
 {
   DeleteCriticalSection (&cond->lock);
   _dbus_list_clear (&cond->list);
@@ -141,7 +167,7 @@
 
 static dbus_bool_t
 _dbus_condvar_wait_win32 (DBusCondVar *cond,
-			  DBusMutex *mutex,
+			  DBusCMutex *mutex,
 			  int milliseconds)
 {
   DWORD retval;
@@ -168,9 +194,9 @@
   if (!ret)
     return FALSE; /* Prepend failed */
 
-  _dbus_mutex_unlock (mutex);
+  _dbus_platform_cmutex_unlock (mutex);
   retval = WaitForSingleObject (event, milliseconds);
-  _dbus_mutex_lock (mutex);
+  _dbus_platform_cmutex_lock (mutex);
   
   if (retval == WAIT_TIMEOUT)
     {
@@ -198,67 +224,38 @@
   return retval != WAIT_TIMEOUT;
 }
 
-static void
-_dbus_windows_condvar_wait (DBusCondVar *cond,
-                            DBusMutex   *mutex)
+void
+_dbus_platform_condvar_wait (DBusCondVar *cond,
+                             DBusCMutex  *mutex)
 {
   _dbus_condvar_wait_win32 (cond, mutex, INFINITE);
 }
 
-static dbus_bool_t
-_dbus_windows_condvar_wait_timeout (DBusCondVar               *cond,
-				     DBusMutex                 *mutex,
+dbus_bool_t
+_dbus_platform_condvar_wait_timeout (DBusCondVar               *cond,
+				     DBusCMutex                *mutex,
 				     int                        timeout_milliseconds)
 {
   return _dbus_condvar_wait_win32 (cond, mutex, timeout_milliseconds);
 }
 
-static void
-_dbus_windows_condvar_wake_one (DBusCondVar *cond)
+void
+_dbus_platform_condvar_wake_one (DBusCondVar *cond)
 {
   EnterCriticalSection (&cond->lock);
   
   if (cond->list != NULL)
-    SetEvent (_dbus_list_pop_first (&cond->list));
-    
+    {
+      SetEvent (_dbus_list_pop_first (&cond->list));
+      /* Avoid live lock by pushing the waiter to the mutex lock
+         instruction, which is fair.  If we don't do this, we could
+         acquire the condition variable again before the waiter has a
+         chance itself, leading to starvation.  */
+      Sleep (0);
+    }
   LeaveCriticalSection (&cond->lock);
 }
 
-static void
-_dbus_windows_condvar_wake_all (DBusCondVar *cond)
-{
-  EnterCriticalSection (&cond->lock);
-
-  while (cond->list != NULL)
-    SetEvent (_dbus_list_pop_first (&cond->list));
-  
-  LeaveCriticalSection (&cond->lock);
-}
-
-static const DBusThreadFunctions windows_functions =
-{
-  DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
-  DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
-  DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
-  DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
-  _dbus_windows_mutex_new,
-  _dbus_windows_mutex_free,
-  _dbus_windows_mutex_lock,
-  _dbus_windows_mutex_unlock,
-  _dbus_windows_condvar_new,
-  _dbus_windows_condvar_free,
-  _dbus_windows_condvar_wait,
-  _dbus_windows_condvar_wait_timeout,
-  _dbus_windows_condvar_wake_one,
-  _dbus_windows_condvar_wake_all
-};
-
 dbus_bool_t
 _dbus_threads_init_platform_specific (void)
 {
@@ -272,6 +269,6 @@
 	return FALSE;
     }
 
-  return dbus_threads_init (&windows_functions);
+  return dbus_threads_init (NULL);
 }
 
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index 60e3d32..3f35d99 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -77,11 +77,6 @@
 #include <bsm/adt.h>
 #endif
 
-// Android specific atomic operation header.
-#ifdef ANDROID_ATOMIC
-#include <cutils/atomic.h>
-#endif
-
 #include "sd-daemon.h"
 
 #ifndef O_BINARY
@@ -96,6 +91,38 @@
 #define socklen_t int
 #endif
 
+#if defined (__sun) || defined (__sun__)
+/*
+ * CMS_SPACE etc. definitions for Solaris < 10, based on
+ *   http://mailman.videolan.org/pipermail/vlc-devel/2006-May/024402.html
+ * via
+ *   http://wiki.opencsw.org/porting-faq#toc10
+ *
+ * These are only redefined for Solaris, for now: if your OS needs these too,
+ * please file a bug. (Or preferably, improve your OS so they're not needed.)
+ */
+
+# ifndef CMSG_ALIGN
+#   ifdef __sun__
+#     define CMSG_ALIGN(len) _CMSG_DATA_ALIGN (len)
+#   else
+      /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */
+#     define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & \
+                              ~(sizeof (long) - 1))
+#   endif
+# endif
+
+# ifndef CMSG_SPACE
+#   define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + \
+                            CMSG_ALIGN (len))
+# endif
+
+# ifndef CMSG_LEN
+#   define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))
+# endif
+
+#endif /* Solaris */
+
 static dbus_bool_t
 _dbus_open_socket (int              *fd_p,
                    int               domain,
@@ -138,13 +165,6 @@
     }
 }
 
-dbus_bool_t
-_dbus_open_tcp_socket (int              *fd,
-                       DBusError        *error)
-{
-  return _dbus_open_socket(fd, AF_INET, SOCK_STREAM, 0, error);
-}
-
 /**
  * Opens a UNIX domain socket (as in the socket() call).
  * Does not bind the socket.
@@ -155,7 +175,7 @@
  * @param error return location for an error
  * @returns #FALSE if error is set
  */
-dbus_bool_t
+static dbus_bool_t
 _dbus_open_unix_socket (int              *fd,
                         DBusError        *error)
 {
@@ -210,7 +230,7 @@
                     int               start,
                     int               len)
 {
-#ifdef MSG_NOSIGNAL
+#if HAVE_DECL_MSG_NOSIGNAL
   const char *data;
   int bytes_written;
 
@@ -448,7 +468,7 @@
  again:
 
   bytes_written = sendmsg (fd, &m, 0
-#ifdef MSG_NOSIGNAL
+#if HAVE_DECL_MSG_NOSIGNAL
                            |MSG_NOSIGNAL
 #endif
                            );
@@ -487,7 +507,7 @@
                         int               start2,
                         int               len2)
 {
-#ifdef MSG_NOSIGNAL
+#if HAVE_DECL_MSG_NOSIGNAL
   struct iovec vectors[2];
   const char *data1;
   const char *data2;
@@ -832,8 +852,6 @@
                       path, _dbus_strerror (errno));
 
       _dbus_close (fd, NULL);
-      fd = -1;
-
       return -1;
     }
 
@@ -842,8 +860,6 @@
       _DBUS_ASSERT_ERROR_IS_SET (error);
 
       _dbus_close (fd, NULL);
-      fd = -1;
-
       return -1;
     }
 
@@ -851,6 +867,96 @@
 }
 
 /**
+ * Creates a UNIX domain socket and connects it to the specified
+ * process to execute.
+ *
+ * This will set FD_CLOEXEC for the socket returned.
+ *
+ * @param path the path to the executable
+ * @param argv the argument list for the process to execute.
+ * argv[0] typically is identical to the path of the executable
+ * @param error return location for error code
+ * @returns connection file descriptor or -1 on error
+ */
+int
+_dbus_connect_exec (const char     *path,
+                    char *const    argv[],
+                    DBusError      *error)
+{
+  int fds[2];
+  pid_t pid;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  _dbus_verbose ("connecting to process %s\n", path);
+
+  if (socketpair (AF_UNIX, SOCK_STREAM
+#ifdef SOCK_CLOEXEC
+                  |SOCK_CLOEXEC
+#endif
+                  , 0, fds) < 0)
+    {
+      dbus_set_error (error,
+                      _dbus_error_from_errno (errno),
+                      "Failed to create socket pair: %s",
+                      _dbus_strerror (errno));
+      return -1;
+    }
+
+  _dbus_fd_set_close_on_exec (fds[0]);
+  _dbus_fd_set_close_on_exec (fds[1]);
+
+  pid = fork ();
+  if (pid < 0)
+    {
+      dbus_set_error (error,
+                      _dbus_error_from_errno (errno),
+                      "Failed to fork() to call %s: %s",
+                      path, _dbus_strerror (errno));
+      close (fds[0]);
+      close (fds[1]);
+      return -1;
+    }
+
+  if (pid == 0)
+    {
+      /* child */
+      close (fds[0]);
+
+      dup2 (fds[1], STDIN_FILENO);
+      dup2 (fds[1], STDOUT_FILENO);
+
+      if (fds[1] != STDIN_FILENO &&
+          fds[1] != STDOUT_FILENO)
+        close (fds[1]);
+
+      /* Inherit STDERR and the controlling terminal from the
+         parent */
+
+      _dbus_close_all ();
+
+      execvp (path, argv);
+
+      fprintf (stderr, "Failed to execute process %s: %s\n", path, _dbus_strerror (errno));
+
+      _exit(1);
+    }
+
+  /* parent */
+  close (fds[1]);
+
+  if (!_dbus_set_fd_nonblocking (fds[0], error))
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (error);
+
+      close (fds[0]);
+      return -1;
+    }
+
+  return fds[0];
+}
+
+/**
  * Enables or disables the reception of credentials on the given socket during
  * the next message transmission.  This is only effective if the #LOCAL_CREDS
  * system feature exists, in which case the other side of the connection does
@@ -1194,14 +1300,6 @@
   struct addrinfo hints;
   struct addrinfo *ai, *tmp;
 
-  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
-  if (!_dbus_open_tcp_socket (&fd, error))
-    {
-      _DBUS_ASSERT_ERROR_IS_SET(error);
-      return -1;
-    }
-
   _DBUS_ASSERT_ERROR_IS_CLEAR(error);
 
   _DBUS_ZERO (hints);
@@ -1229,7 +1327,6 @@
                       _dbus_error_from_errno (errno),
                       "Failed to lookup host/port: \"%s:%s\": %s (%d)",
                       host, port, gai_strerror(res), res);
-      _dbus_close (fd, NULL);
       return -1;
     }
 
@@ -1344,13 +1441,14 @@
   hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
 
  redo_lookup_with_port:
+  ai = NULL;
   if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai)
     {
       dbus_set_error (error,
                       _dbus_error_from_errno (errno),
                       "Failed to lookup host/port: \"%s:%s\": %s (%d)",
                       host ? host : "*", port, gai_strerror(res), res);
-      return -1;
+      goto failed;
     }
 
   tmp = ai;
@@ -1421,16 +1519,18 @@
              to use the same port */
           if (!port || !strcmp(port, "0"))
             {
+              int result;
               struct sockaddr_storage addr;
               socklen_t addrlen;
               char portbuf[50];
 
               addrlen = sizeof(addr);
-              getsockname(fd, (struct sockaddr*) &addr, &addrlen);
+              result = getsockname(fd, (struct sockaddr*) &addr, &addrlen);
 
-              if ((res = getnameinfo((struct sockaddr*)&addr, addrlen, NULL, 0,
-                                     portbuf, sizeof(portbuf),
-                                     NI_NUMERICHOST)) != 0)
+              if (result == -1 ||
+                  (res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0,
+                                      portbuf, sizeof(portbuf),
+                                      NI_NUMERICHOST)) != 0)
                 {
                   dbus_set_error (error, _dbus_error_from_errno (errno),
                                   "Failed to resolve port \"%s:%s\": %s (%s)",
@@ -1469,7 +1569,7 @@
       dbus_set_error (error, _dbus_error_from_errno (errno),
                       "Failed to bind socket \"%s:%s\": %s",
                       host ? host : "*", port, _dbus_strerror (errno));
-      return -1;
+      goto failed;
     }
 
   for (i = 0 ; i < nlisten_fd ; i++)
@@ -1526,9 +1626,17 @@
  again:
 
 #if defined(HAVE_CMSGCRED)
-  bytes_written = sendmsg (server_fd, &msg, 0);
+  bytes_written = sendmsg (server_fd, &msg, 0
+#if HAVE_DECL_MSG_NOSIGNAL
+                           |MSG_NOSIGNAL
+#endif
+                           );
 #else
-  bytes_written = write (server_fd, buf, 1);
+  bytes_written = send (server_fd, buf, 1, 0
+#if HAVE_DECL_MSG_NOSIGNAL
+                        |MSG_NOSIGNAL
+#endif
+                        );
 #endif
 
   if (bytes_written < 0 && errno == EINTR)
@@ -1683,7 +1791,11 @@
 
   {
 #ifdef SO_PEERCRED
+#ifdef __OpenBSD__
+    struct sockpeercred cr;
+#else
     struct ucred cr;
+#endif
     int cr_len = sizeof (cr);
 
     if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
@@ -2354,8 +2466,6 @@
 {
 #if DBUS_USE_SYNC
   return __sync_add_and_fetch(&atomic->value, 1)-1;
-#elif defined(ANDROID_ATOMIC)
-  return android_atomic_inc (&(atomic->value));
 #else
   dbus_int32_t res;
   _DBUS_LOCK (atomic);
@@ -2377,8 +2487,6 @@
 {
 #if DBUS_USE_SYNC
   return __sync_sub_and_fetch(&atomic->value, 1)+1;
-#elif defined(ANDROID_ATOMIC)
-  return android_atomic_dec (&(atomic->value));
 #else
   dbus_int32_t res;
 
@@ -2390,16 +2498,28 @@
 #endif
 }
 
-#ifdef DBUS_BUILD_TESTS
-/** Gets our GID
- * @returns process GID
+/**
+ * Atomically get the value of an integer. It may change at any time
+ * thereafter, so this is mostly only useful for assertions.
+ *
+ * @param atomic pointer to the integer to get
+ * @returns the value at this moment
  */
-dbus_gid_t
-_dbus_getgid (void)
+dbus_int32_t
+_dbus_atomic_get (DBusAtomic *atomic)
 {
-  return getgid ();
-}
+#if DBUS_USE_SYNC
+  __sync_synchronize ();
+  return atomic->value;
+#else
+  dbus_int32_t res;
+
+  _DBUS_LOCK (atomic);
+  res = atomic->value;
+  _DBUS_UNLOCK (atomic);
+  return res;
 #endif
+}
 
 /**
  * Wrapper for poll().
@@ -2506,14 +2626,12 @@
  * available, to avoid problems when the system time changes.
  *
  * @param tv_sec return location for number of seconds
- * @param tv_usec return location for number of microseconds (thousandths)
+ * @param tv_usec return location for number of microseconds
  */
 void
-_dbus_get_current_time (long *tv_sec,
-                        long *tv_usec)
+_dbus_get_monotonic_time (long *tv_sec,
+                          long *tv_usec)
 {
-  struct timeval t;
-
 #ifdef HAVE_MONOTONIC_CLOCK
   struct timespec ts;
   clock_gettime (CLOCK_MONOTONIC, &ts);
@@ -2523,6 +2641,8 @@
   if (tv_usec)
     *tv_usec = ts.tv_nsec / 1000;
 #else
+  struct timeval t;
+
   gettimeofday (&t, NULL);
 
   if (tv_sec)
@@ -2533,6 +2653,27 @@
 }
 
 /**
+ * Get current time, as in gettimeofday(). Never uses the monotonic
+ * clock.
+ *
+ * @param tv_sec return location for number of seconds
+ * @param tv_usec return location for number of microseconds
+ */
+void
+_dbus_get_real_time (long *tv_sec,
+                     long *tv_usec)
+{
+  struct timeval t;
+
+  gettimeofday (&t, NULL);
+
+  if (tv_sec)
+    *tv_sec = t.tv_sec;
+  if (tv_usec)
+    *tv_usec = t.tv_usec;
+}
+
+/**
  * Creates a directory; succeeds if the directory
  * is created or already existed.
  *
@@ -2917,11 +3058,6 @@
  *
  * Marks both file descriptors as close-on-exec
  *
- * @todo libdbus only uses this for the debug-pipe server, so in
- * principle it could be in dbus-sysdeps-util.c, except that
- * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the
- * debug-pipe server is used.
- *
  * @param fd1 return location for one end
  * @param fd2 return location for the other end
  * @param blocking #TRUE if pipe should be blocking
@@ -3001,14 +3137,60 @@
  *
  * @param format a printf-style format string
  * @param args arguments for the format string
- * @returns length of the given format string and args
+ * @returns length of the given format string and args, or -1 if no memory
  */
 int
 _dbus_printf_string_upper_bound (const char *format,
                                  va_list     args)
 {
-  char c;
-  return vsnprintf (&c, 1, format, args);
+  char static_buf[1024];
+  int bufsize = sizeof (static_buf);
+  int len;
+
+  len = vsnprintf (static_buf, bufsize, format, args);
+
+  /* If vsnprintf() returned non-negative, then either the string fits in
+   * static_buf, or this OS has the POSIX and C99 behaviour where vsnprintf
+   * returns the number of characters that were needed, or this OS returns the
+   * truncated length.
+   *
+   * We ignore the possibility that snprintf might just ignore the length and
+   * overrun the buffer (64-bit Solaris 7), because that's pathological.
+   * If your libc is really that bad, come back when you have a better one. */
+  if (len == bufsize)
+    {
+      /* This could be the truncated length (Tru64 and IRIX have this bug),
+       * or the real length could be coincidentally the same. Which is it?
+       * If vsnprintf returns the truncated length, we'll go to the slow
+       * path. */
+      if (vsnprintf (static_buf, 1, format, args) == 1)
+        len = -1;
+    }
+
+  /* If vsnprintf() returned negative, we have to do more work.
+   * HP-UX returns negative. */
+  while (len < 0)
+    {
+      char *buf;
+
+      bufsize *= 2;
+
+      buf = dbus_malloc (bufsize);
+
+      if (buf == NULL)
+        return -1;
+
+      len = vsnprintf (buf, bufsize, format, args);
+      dbus_free (buf);
+
+      /* If the reported length is exactly the buffer size, round up to the
+       * next size, in case vsnprintf has been returning the truncated
+       * length */
+      if (len == bufsize)
+        len = -1;
+    }
+
+  return len;
 }
 
 /**
@@ -3081,7 +3263,6 @@
   int ret;
   int status;
   int orig_len;
-  int i;
 
   dbus_bool_t retval;
   sigset_t new_set, old_set;
@@ -3134,7 +3315,6 @@
   if (pid == 0)
     {
       /* child process */
-      int maxfds;
       int fd;
 
       fd = open ("/dev/null", O_RDWR);
@@ -3158,15 +3338,7 @@
       if (dup2 (errors_pipe[WRITE_END], 2) == -1)
         _exit (1);
 
-      maxfds = sysconf (_SC_OPEN_MAX);
-      /* Pick something reasonable if for some reason sysconf
-       * says unlimited.
-       */
-      if (maxfds < 0)
-        maxfds = 1024;
-      /* close all inherited fds */
-      for (i = 3; i < maxfds; i++)
-        close (i);
+      _dbus_close_all ();
 
       sigprocmask (SIG_SETMASK, &old_set, NULL);
 
@@ -3217,7 +3389,12 @@
     {
       /* The process ended with error */
       DBusString error_message;
-      _dbus_string_init (&error_message);
+      if (!_dbus_string_init (&error_message))
+        {
+          _DBUS_SET_OOM (error);
+          goto out;
+        }
+
       ret = 0;
       do
         {
@@ -3271,17 +3448,42 @@
  * @returns #TRUE on success, #FALSE if an error happened
  */
 dbus_bool_t
-_dbus_get_autolaunch_address (DBusString *address,
+_dbus_get_autolaunch_address (const char *scope,
+                              DBusString *address,
                               DBusError  *error)
 {
+#ifdef DBUS_ENABLE_X11_AUTOLAUNCH
+  /* Perform X11-based autolaunch. (We also support launchd-based autolaunch,
+   * but that's done elsewhere, and if it worked, this function wouldn't
+   * be called.) */
+  const char *display;
   static char *argv[6];
   int i;
   DBusString uuid;
   dbus_bool_t retval;
 
+  if (_dbus_check_setuid ())
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to autolaunch when setuid");
+      return FALSE;
+    }
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
   retval = FALSE;
 
+  /* fd.o #19997: if $DISPLAY isn't set to something useful, then
+   * dbus-launch-x11 is just going to fail. Rather than trying to
+   * run it, we might as well bail out early with a nice error. */
+  display = _dbus_getenv ("DISPLAY");
+
+  if (display == NULL || display[0] == '\0')
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+          "Unable to autolaunch a dbus-daemon without a $DISPLAY for X11");
+      return FALSE;
+    }
+
   if (!_dbus_string_init (&uuid))
     {
       _DBUS_SET_OOM (error);
@@ -3317,6 +3519,12 @@
  out:
   _dbus_string_free (&uuid);
   return retval;
+#else
+  dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+      "Using X11 for dbus-daemon autolaunch was disabled at compile time, "
+      "set your DBUS_SESSION_BUS_ADDRESS instead");
+  return FALSE;
+#endif
 }
 
 /**
@@ -3343,14 +3551,137 @@
                                DBusError  *error)
 {
   DBusString filename;
+  dbus_bool_t b;
+
   _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE);
-  return _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error);
+
+  b = _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error);
+  if (b)
+    return TRUE;
+
+  dbus_error_free (error);
+
+  /* Fallback to the system machine ID */
+  _dbus_string_init_const (&filename, "/etc/machine-id");
+  return _dbus_read_uuid_file (&filename, machine_id, FALSE, error);
 }
 
 #define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services"
 #define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services"
 
 /**
+ * quries launchd for a specific env var which holds the socket path.
+ * @param launchd_env_var the env var to look up
+ * @param error a DBusError to store the error in case of failure
+ * @return the value of the env var
+ */
+dbus_bool_t
+_dbus_lookup_launchd_socket (DBusString *socket_path,
+                             const char *launchd_env_var,
+                             DBusError  *error)
+{
+#ifdef DBUS_ENABLE_LAUNCHD
+  char *argv[4];
+  int i;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  if (_dbus_check_setuid ())
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to find launchd socket when setuid");
+      return FALSE;
+    }
+
+  i = 0;
+  argv[i] = "launchctl";
+  ++i;
+  argv[i] = "getenv";
+  ++i;
+  argv[i] = (char*)launchd_env_var;
+  ++i;
+  argv[i] = NULL;
+  ++i;
+
+  _dbus_assert (i == _DBUS_N_ELEMENTS (argv));
+
+  if (!_read_subprocess_line_argv(argv[0], TRUE, argv, socket_path, error))
+    {
+      return FALSE;
+    }
+
+  /* no error, but no result either */
+  if (_dbus_string_get_length(socket_path) == 0)
+    {
+      return FALSE;
+    }
+
+  /* strip the carriage-return */
+  _dbus_string_shorten(socket_path, 1);
+  return TRUE;
+#else /* DBUS_ENABLE_LAUNCHD */
+  dbus_set_error(error, DBUS_ERROR_NOT_SUPPORTED,
+                "can't lookup socket from launchd; launchd support not compiled in");
+  return FALSE;
+#endif
+}
+
+#ifdef DBUS_ENABLE_LAUNCHD
+static dbus_bool_t
+_dbus_lookup_session_address_launchd (DBusString *address, DBusError  *error)
+{
+  dbus_bool_t valid_socket;
+  DBusString socket_path;
+
+  if (_dbus_check_setuid ())
+    {
+      dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED,
+                            "Unable to find launchd socket when setuid");
+      return FALSE;
+    }
+
+  if (!_dbus_string_init (&socket_path))
+    {
+      _DBUS_SET_OOM (error);
+      return FALSE;
+    }
+
+  valid_socket = _dbus_lookup_launchd_socket (&socket_path, "DBUS_LAUNCHD_SESSION_BUS_SOCKET", error);
+
+  if (dbus_error_is_set(error))
+    {
+      _dbus_string_free(&socket_path);
+      return FALSE;
+    }
+
+  if (!valid_socket)
+    {
+      dbus_set_error(error, "no socket path",
+                "launchd did not provide a socket path, "
+                "verify that org.freedesktop.dbus-session.plist is loaded!");
+      _dbus_string_free(&socket_path);
+      return FALSE;
+    }
+  if (!_dbus_string_append (address, "unix:path="))
+    {
+      _DBUS_SET_OOM (error);
+      _dbus_string_free(&socket_path);
+      return FALSE;
+    }
+  if (!_dbus_string_copy (&socket_path, 0, address,
+                          _dbus_string_get_length (address)))
+    {
+      _DBUS_SET_OOM (error);
+      _dbus_string_free(&socket_path);
+      return FALSE;
+    }
+
+  _dbus_string_free(&socket_path);
+  return TRUE;
+}
+#endif
+
+/**
  * Determines the address of the session bus by querying a
  * platform-specific method.
  *
@@ -3374,12 +3705,17 @@
                               DBusString  *address,
                               DBusError   *error)
 {
+#ifdef DBUS_ENABLE_LAUNCHD
+  *supported = TRUE;
+  return _dbus_lookup_session_address_launchd (address, error);
+#else
   /* On non-Mac Unix platforms, if the session address isn't already
    * set in DBUS_SESSION_BUS_ADDRESS environment variable, we punt and
    * fall back to the autolaunch: global default; see
    * init_session_address in dbus/dbus-bus.c. */
   *supported = FALSE;
   return TRUE;
+#endif
 }
 
 /**
@@ -3412,29 +3748,6 @@
   xdg_data_home = _dbus_getenv ("XDG_DATA_HOME");
   xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS");
 
-  if (xdg_data_dirs != NULL)
-    {
-      if (!_dbus_string_append (&servicedir_path, xdg_data_dirs))
-        goto oom;
-
-      if (!_dbus_string_append (&servicedir_path, ":"))
-        goto oom;
-    }
-  else
-    {
-      if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:"))
-        goto oom;
-    }
-
-  /*
-   * add configured datadir to defaults
-   * this may be the same as an xdg dir
-   * however the config parser should take
-   * care of duplicates
-   */
-  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":"))
-        goto oom;
-
   if (xdg_data_home != NULL)
     {
       if (!_dbus_string_append (&servicedir_path, xdg_data_home))
@@ -3456,6 +3769,32 @@
         goto oom;
     }
 
+  if (!_dbus_string_append (&servicedir_path, ":"))
+    goto oom;
+
+  if (xdg_data_dirs != NULL)
+    {
+      if (!_dbus_string_append (&servicedir_path, xdg_data_dirs))
+        goto oom;
+
+      if (!_dbus_string_append (&servicedir_path, ":"))
+        goto oom;
+    }
+  else
+    {
+      if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:"))
+        goto oom;
+    }
+
+  /*
+   * add configured datadir to defaults
+   * this may be the same as an xdg dir
+   * however the config parser should take
+   * care of duplicates
+   */
+  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR))
+    goto oom;
+
   if (!_dbus_split_paths_and_append (&servicedir_path,
                                      DBUS_UNIX_STANDARD_SESSION_SERVICEDIR,
                                      dirs))
@@ -3491,48 +3830,27 @@
 dbus_bool_t
 _dbus_get_standard_system_servicedirs (DBusList **dirs)
 {
-  const char *xdg_data_dirs;
+  /*
+   * DBUS_DATADIR may be the same as one of the standard directories. However,
+   * the config parser should take care of the duplicates.
+   *
+   * Also, append /lib as counterpart of /usr/share on the root
+   * directory (the root directory does not know /share), in order to
+   * facilitate early boot system bus activation where /usr might not
+   * be available.
+   */
+  static const char standard_search_path[] =
+    "/usr/local/share:"
+    "/usr/share:"
+    DBUS_DATADIR ":"
+    "/lib";
   DBusString servicedir_path;
 
-  if (!_dbus_string_init (&servicedir_path))
-    return FALSE;
+  _dbus_string_init_const (&servicedir_path, standard_search_path);
 
-  xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS");
-
-  if (xdg_data_dirs != NULL)
-    {
-      if (!_dbus_string_append (&servicedir_path, xdg_data_dirs))
-        goto oom;
-
-      if (!_dbus_string_append (&servicedir_path, ":"))
-        goto oom;
-    }
-  else
-    {
-      if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:"))
-        goto oom;
-    }
-
-  /*
-   * add configured datadir to defaults
-   * this may be the same as an xdg dir
-   * however the config parser should take
-   * care of duplicates
-   */
-  if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":"))
-        goto oom;
-
-  if (!_dbus_split_paths_and_append (&servicedir_path,
-                                     DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR,
-                                     dirs))
-    goto oom;
-
-  _dbus_string_free (&servicedir_path);
-  return TRUE;
-
- oom:
-  _dbus_string_free (&servicedir_path);
-  return FALSE;
+  return _dbus_split_paths_and_append (&servicedir_path,
+                                       DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR,
+                                       dirs);
 }
 
 /**
@@ -3652,10 +3970,11 @@
 }
 
 //PENDING(kdab) docs
-void
-_dbus_daemon_publish_session_bus_address (const char* addr)
+dbus_bool_t
+_dbus_daemon_publish_session_bus_address (const char* addr,
+                                          const char *scope)
 {
-
+  return TRUE;
 }
 
 //PENDING(kdab) docs
@@ -3751,4 +4070,122 @@
   return configure_time_path;
 }
 
+/**
+ * Closes all file descriptors except the first three (i.e. stdin,
+ * stdout, stderr).
+ */
+void
+_dbus_close_all (void)
+{
+  int maxfds, i;
+
+#ifdef __linux__
+  DIR *d;
+
+  /* On Linux we can optimize this a bit if /proc is available. If it
+     isn't available, fall back to the brute force way. */
+
+  d = opendir ("/proc/self/fd");
+  if (d)
+    {
+      for (;;)
+        {
+          struct dirent buf, *de;
+          int k, fd;
+          long l;
+          char *e = NULL;
+
+          k = readdir_r (d, &buf, &de);
+          if (k != 0 || !de)
+            break;
+
+          if (de->d_name[0] == '.')
+            continue;
+
+          errno = 0;
+          l = strtol (de->d_name, &e, 10);
+          if (errno != 0 || e == NULL || *e != '\0')
+            continue;
+
+          fd = (int) l;
+          if (fd < 3)
+            continue;
+
+          if (fd == dirfd (d))
+            continue;
+
+          close (fd);
+        }
+
+      closedir (d);
+      return;
+    }
+#endif
+
+  maxfds = sysconf (_SC_OPEN_MAX);
+
+  /* Pick something reasonable if for some reason sysconf says
+   * unlimited.
+   */
+  if (maxfds < 0)
+    maxfds = 1024;
+
+  /* close all inherited fds */
+  for (i = 3; i < maxfds; i++)
+    close (i);
+}
+
+/**
+ * **NOTE**: If you modify this function, please also consider making
+ * the corresponding change in GLib.  See
+ * glib/gutils.c:g_check_setuid().
+ *
+ * Returns TRUE if the current process was executed as setuid (or an
+ * equivalent __libc_enable_secure is available).  See:
+ * http://osdir.com/ml/linux.lfs.hardened/2007-04/msg00032.html
+ */
+dbus_bool_t
+_dbus_check_setuid (void)
+{
+  /* TODO: get __libc_enable_secure exported from glibc.
+   * See http://www.openwall.com/lists/owl-dev/2012/08/14/1
+   */
+#if 0 && defined(HAVE_LIBC_ENABLE_SECURE)
+  {
+    /* See glibc/include/unistd.h */
+    extern int __libc_enable_secure;
+    return __libc_enable_secure;
+  }
+#elif defined(HAVE_ISSETUGID)
+  /* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */
+  return issetugid ();
+#else
+  uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
+  gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
+
+  static dbus_bool_t check_setuid_initialised;
+  static dbus_bool_t is_setuid;
+
+  if (_DBUS_UNLIKELY (!check_setuid_initialised))
+    {
+#ifdef HAVE_GETRESUID
+      if (getresuid (&ruid, &euid, &suid) != 0 ||
+          getresgid (&rgid, &egid, &sgid) != 0)
+#endif /* HAVE_GETRESUID */
+        {
+          suid = ruid = getuid ();
+          sgid = rgid = getgid ();
+          euid = geteuid ();
+          egid = getegid ();
+        }
+
+      check_setuid_initialised = TRUE;
+      is_setuid = (ruid != euid || ruid != suid ||
+                   rgid != egid || rgid != sgid);
+
+    }
+  return is_setuid;
+#endif
+}
+
 /* tests in dbus-sysdeps-util.c */
diff --git a/dbus/dbus-sysdeps-unix.h b/dbus/dbus-sysdeps-unix.h
index 807d2cf..9b70896 100644
--- a/dbus/dbus-sysdeps-unix.h
+++ b/dbus/dbus-sysdeps-unix.h
@@ -63,8 +63,6 @@
                  int               start2,
                  int               len2);
 
-dbus_bool_t _dbus_open_unix_socket (int              *fd,
-                                    DBusError        *error);
 int _dbus_connect_unix_socket (const char     *path,
                                dbus_bool_t     abstract,
                                DBusError      *error);
@@ -72,6 +70,10 @@
                                dbus_bool_t     abstract,
                                DBusError      *error);
 
+int _dbus_connect_exec (const char     *path,
+                        char *const    argv[],
+                        DBusError      *error);
+
 int _dbus_listen_systemd_sockets (int       **fd,
                                  DBusError *error);
 
@@ -81,6 +83,10 @@
 dbus_bool_t _dbus_send_credentials (int              server_fd,
                                     DBusError       *error);
 
+dbus_bool_t _dbus_lookup_launchd_socket (DBusString *socket_path,
+                                         const char *launchd_env_var,
+                                         DBusError  *error);
+
 /** Information about a UNIX user */
 typedef struct DBusUserInfo  DBusUserInfo;
 /** Information about a UNIX group */
@@ -126,11 +132,12 @@
 
 dbus_uid_t    _dbus_getuid (void);
 dbus_uid_t    _dbus_geteuid (void);
-dbus_gid_t    _dbus_getgid (void);
 
 dbus_bool_t _dbus_parse_uid (const DBusString  *uid_str,
                              dbus_uid_t        *uid);
 
+void _dbus_close_all (void);
+
 /** @} */
 
 DBUS_END_DECLS
diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c
index a00203a..76423ab 100644
--- a/dbus/dbus-sysdeps-util-unix.c
+++ b/dbus/dbus-sysdeps-util-unix.c
@@ -42,6 +42,9 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 #include <grp.h>
 #include <sys/socket.h>
 #include <dirent.h>
@@ -251,8 +254,8 @@
       DBusString pid;
       int bytes;
 
-      _dbus_verbose ("writing our pid to pipe %"PRIuPTR"\n",
-                     print_pid_pipe->fd_or_handle);
+      _dbus_verbose ("writing our pid to pipe %d\n",
+                     print_pid_pipe->fd);
       
       if (!_dbus_string_init (&pid))
         {
@@ -369,11 +372,65 @@
 }
 #endif /* !HAVE_LIBAUDIT */
 
-void 
+
+/**
+ * Attempt to ensure that the current process can open
+ * at least @limit file descriptors.
+ *
+ * If @limit is lower than the current, it will not be
+ * lowered.  No error is returned if the request can
+ * not be satisfied.
+ *
+ * @limit Number of file descriptors
+ */
+void
+_dbus_request_file_descriptor_limit (unsigned int limit)
+{
+#ifdef HAVE_SETRLIMIT
+  struct rlimit lim;
+  struct rlimit target_lim;
+
+  /* No point to doing this practically speaking
+   * if we're not uid 0.  We expect the system
+   * bus to use this before we change UID, and
+   * the session bus takes the Linux default
+   * of 1024 for both cur and max.
+   */
+  if (getuid () != 0)
+    return;
+
+  if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
+    return;
+
+  if (lim.rlim_cur >= limit)
+    return;
+
+  /* Ignore "maximum limit", assume we have the "superuser"
+   * privileges.  On Linux this is CAP_SYS_RESOURCE.
+   */
+  target_lim.rlim_cur = target_lim.rlim_max = limit;
+  /* Also ignore errors; if we fail, we will at least work
+   * up to whatever limit we had, which seems better than
+   * just outright aborting.
+   *
+   * However, in the future we should probably log this so OS builders
+   * have a chance to notice any misconfiguration like dbus-daemon
+   * being started without CAP_SYS_RESOURCE.
+   */
+  setrlimit (RLIMIT_NOFILE, &target_lim);
+#endif
+}
+
+void
 _dbus_init_system_log (void)
 {
+#if HAVE_DECL_LOG_PERROR
+  openlog ("dbus", LOG_PID | LOG_PERROR, LOG_DAEMON);
+#else
   openlog ("dbus", LOG_PID, LOG_DAEMON);
+#endif
 }
+
 /**
  * Log a message to the system log file (e.g. syslog on Unix).
  *
@@ -418,10 +475,24 @@
         break;
       case DBUS_SYSTEM_LOG_FATAL:
         flags = LOG_DAEMON|LOG_CRIT;
+        break;
       default:
         return;
     }
 
+#ifndef HAVE_DECL_LOG_PERROR
+    {
+      /* vsyslog() won't write to stderr, so we'd better do it */
+      va_list tmp;
+
+      DBUS_VA_COPY (tmp, args);
+      fprintf (stderr, "dbus[" DBUS_PID_FORMAT "]: ", _dbus_getpid ());
+      vfprintf (stderr, msg, tmp);
+      fputc ('\n', stderr);
+      va_end (tmp);
+    }
+#endif
+
   vsyslog (flags, msg, args);
 
   if (severity == DBUS_SYSTEM_LOG_FATAL)
@@ -469,7 +540,7 @@
                        DBusError  *error)
 {
 
-  DBusString f;
+  DBusString u, f;
   dbus_bool_t result;
 
   result = FALSE;
@@ -485,8 +556,9 @@
       goto out;
     }
 
+  _dbus_string_init_const (&u, username);
 
-  if (!_dbus_string_append (&f, username))
+  if (!_dbus_concat_dir_and_file (&f, &u))
     {
       _DBUS_SET_OOM (error);
       goto out;
@@ -607,26 +679,14 @@
   return iter;
 }
 
-/* it is never safe to retrun a size smaller than sizeof(struct dirent)
- * because the libc *could* try to access the  whole structure
- * (for instance it could try to memset it).
- * it is also incorrect to return a size bigger than that, because
- * the libc would never use it.
- * The only correct and safe value this function can ever return is
- * sizeof(struct dirent).
- */
-static dbus_bool_t
-dirent_buf_size(DIR * dirp, size_t *size)
-{
-  *size = sizeof(struct dirent);
-  return TRUE;
-}
-
 /**
  * Get next file in the directory. Will not return "." or ".."  on
  * UNIX. If an error occurs, the contents of "filename" are
  * undefined. The error is never set if the function succeeds.
  *
+ * This function is not re-entrant, and not necessarily thread-safe.
+ * Only use it for test code or single-threaded utilities.
+ *
  * @param iter the iterator
  * @param filename string to be set to the next file in the dir
  * @param error return location for error
@@ -637,37 +697,24 @@
                                DBusString       *filename,
                                DBusError        *error)
 {
-  struct dirent *d, *ent;
-  size_t buf_size;
+  struct dirent *ent;
   int err;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
- 
-  if (!dirent_buf_size (iter->d, &buf_size))
-    {
-      dbus_set_error (error, DBUS_ERROR_FAILED,
-                      "Can't calculate buffer size when reading directory");
-      return FALSE;
-    }
-
-  d = (struct dirent *)dbus_malloc (buf_size);
-  if (!d)
-    {
-      dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
-                      "No memory to read directory entry");
-      return FALSE;
-    }
 
  again:
-  err = readdir_r (iter->d, d, &ent);
-  if (err || !ent)
+  errno = 0;
+  ent = readdir (iter->d);
+
+  if (!ent)
     {
+      err = errno;
+
       if (err != 0)
         dbus_set_error (error,
                         _dbus_error_from_errno (err),
                         "%s", _dbus_strerror (err));
 
-      dbus_free (d);
       return FALSE;
     }
   else if (ent->d_name[0] == '.' &&
@@ -681,12 +728,10 @@
         {
           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
                           "No memory to read directory entry");
-          dbus_free (d);
           return FALSE;
         }
       else
         {
-          dbus_free (d);
           return TRUE;
         }
     }
@@ -1031,11 +1076,11 @@
   
   for (i = 0; i < len; i++)
     {
-	  unsigned char c = (unsigned char) buf[i];
+      unsigned char c = (unsigned char) buf[i];
       if (c == '\0')
-        c = ' ';
+        buf[i] = ' ';
       else if (c < 0x20 || c > 127)
-        c = '?';
+        buf[i] = '?';
     }
 }
 
@@ -1105,10 +1150,10 @@
     goto fail;
   
   string_squash_nonprintable (&cmdline);  
-  
+
   if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
     goto oom;
-  
+
   _dbus_string_free (&cmdline);  
   _dbus_string_free (&path);
   return TRUE;
diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c
index 2f21409..111db9e 100644
--- a/dbus/dbus-sysdeps-util-win.c
+++ b/dbus/dbus-sysdeps-util-win.c
@@ -191,7 +191,7 @@
       DBusString pid;
       int bytes;
 
-      _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd_or_handle);
+      _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd);
 
       if (!_dbus_string_init (&pid))
         {
@@ -257,9 +257,14 @@
 }
 
 void
+_dbus_request_file_descriptor_limit (unsigned int limit)
+{
+}
+
+void
 _dbus_init_system_log (void)
 {
-    // FIXME!
+  /* OutputDebugStringA doesn't need any special initialization, do nothing */
 }
 
 /**
@@ -677,23 +682,6 @@
   dbus_free (iter);
 }
 
-/**
- * Checks whether the filename is an absolute path
- *
- * @param filename the filename
- * @returns #TRUE if an absolute path
- */
-dbus_bool_t
-_dbus_path_is_absolute (const DBusString *filename)
-{
-  if (_dbus_string_get_length (filename) > 0)
-    return _dbus_string_get_byte (filename, 1) == ':'
-           || _dbus_string_get_byte (filename, 0) == '\\'
-           || _dbus_string_get_byte (filename, 0) == '/';
-  else
-    return FALSE;
-}
-
 /** @} */ /* End of DBusInternalsUtils functions */
 
 /**
diff --git a/dbus/dbus-sysdeps-util.c b/dbus/dbus-sysdeps-util.c
index 68669cf..4b3d16f 100644
--- a/dbus/dbus-sysdeps-util.c
+++ b/dbus/dbus-sysdeps-util.c
@@ -28,8 +28,59 @@
 #include "dbus-string.h"
 #include "dbus-test.h"
 
-#ifdef DBUS_BUILD_TESTS
 #include <stdlib.h>
+
+#ifdef DBUS_WIN
+  /* do nothing, it's in stdlib.h */
+#elif (defined __APPLE__)
+# include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+#else
+extern char **environ;
+#endif
+
+/**
+ * Gets a #NULL-terminated list of key=value pairs from the
+ * environment. Use dbus_free_string_array to free it.
+ *
+ * @returns the environment or #NULL on OOM
+ */
+char **
+_dbus_get_environment (void)
+{
+  int i, length;
+  char **environment;
+
+  _dbus_assert (environ != NULL);
+
+  for (length = 0; environ[length] != NULL; length++);
+
+  /* Add one for NULL */
+  length++;
+
+  environment = dbus_new0 (char *, length);
+
+  if (environment == NULL)
+    return NULL;
+
+  for (i = 0; environ[i] != NULL; i++)
+    {
+      environment[i] = _dbus_strdup (environ[i]);
+
+      if (environment[i] == NULL)
+        break;
+    }
+
+  if (environ[i] != NULL)
+    {
+      dbus_free_string_array (environment);
+      environment = NULL;
+    }
+
+  return environment;
+}
+
+#ifdef DBUS_BUILD_TESTS
 static void
 check_dirname (const char *filename,
                const char *dirname)
@@ -80,10 +131,6 @@
 dbus_bool_t
 _dbus_sysdeps_test (void)
 {
-  DBusString str;
-  double val;
-  int pos;
-
 #ifdef DBUS_WIN
   check_dirname ("foo\\bar", "foo");
   check_dirname ("foo\\\\bar", "foo");
@@ -125,32 +172,6 @@
   check_dirname ("", ".");  
 #endif
 
-  _dbus_string_init_const (&str, "3.5");
-  if (!_dbus_string_parse_double (&str,
-				  0, &val, &pos))
-    {
-      _dbus_warn ("Failed to parse double");
-      exit (1);
-    }
-  if (ABS(3.5 - val) > 1e-6)
-    {
-      _dbus_warn ("Failed to parse 3.5 correctly, got: %f", val);
-      exit (1);
-    }
-  if (pos != 3)
-    {
-      _dbus_warn ("_dbus_string_parse_double of \"3.5\" returned wrong position %d", pos);
-      exit (1);
-    }
-
-  _dbus_string_init_const (&str, "0xff");
-  if (_dbus_string_parse_double (&str,
-                                 0, &val, &pos))
-    {
-      _dbus_warn ("Should not have parsed hex as double\n");
-      exit (1);
-    }
-
 #ifdef DBUS_WIN
   check_path_absolute ("c:/", TRUE);
   check_path_absolute ("c:/foo", TRUE);
diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c
index c2fe8d7..bc4951b 100644
--- a/dbus/dbus-sysdeps-win.c
+++ b/dbus/dbus-sysdeps-win.c
@@ -4,9 +4,9 @@
  * Copyright (C) 2002, 2003  Red Hat, Inc.
  * Copyright (C) 2003 CodeFactory AB
  * Copyright (C) 2005 Novell, Inc.
- * Copyright (C) 2006 Ralf Habacker <ralf.habacker@freenet.de>
  * Copyright (C) 2006 Peter Kümmel  <syntheticpp@gmx.net>
  * Copyright (C) 2006 Christian Ehrlicher <ch.ehrlicher@gmx.de>
+ * Copyright (C) 2006-2010 Ralf Habacker <ralf.habacker@freenet.de>
  *
  * Licensed under the Academic Free License version 2.1
  * 
@@ -37,10 +37,12 @@
 #endif
 
 #include "dbus-internals.h"
+#include "dbus-sha.h"
 #include "dbus-sysdeps.h"
 #include "dbus-threads.h"
 #include "dbus-protocol.h"
 #include "dbus-string.h"
+#include "dbus-sysdeps.h"
 #include "dbus-sysdeps-win.h"
 #include "dbus-protocol.h"
 #include "dbus-hash.h"
@@ -547,6 +549,10 @@
       bufsize *= 2;
 
       p = malloc (bufsize);
+
+      if (p == NULL)
+        return -1;
+
       len = _vsnprintf (p, bufsize - 1, format, args);
       free (p);
     }
@@ -793,11 +799,6 @@
  * Creates a full-duplex pipe (as in socketpair()).
  * Sets both ends of the pipe nonblocking.
  *
- * @todo libdbus only uses this for the debug-pipe server, so in
- * principle it could be in dbus-sysdeps-util.c, except that
- * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the
- * debug-pipe server is used.
- * 
  * @param fd1 return location for one end
  * @param fd2 return location for the other end
  * @param blocking #TRUE if pipe should be blocking
@@ -814,9 +815,6 @@
   struct sockaddr_in saddr;
   int len;
   u_long arg;
-  fd_set read_set, write_set;
-  struct timeval tv;
-  int res;
 
   _dbus_win_startup_winsock ();
 
@@ -952,7 +950,6 @@
   msgp += sprintf (msgp, "WSAEventSelect: to=%d\n\t", timeout_milliseconds);
   for (i = 0; i < n_fds; i++)
     {
-      static dbus_bool_t warned = FALSE;
       DBusPollFD *fdp = &fds[i];
 
 
@@ -1090,7 +1087,6 @@
   msgp += sprintf (msgp, "select: to=%d\n\t", timeout_milliseconds);
   for (i = 0; i < n_fds; i++)
     {
-      static dbus_bool_t warned = FALSE;
       DBusPollFD *fdp = &fds[i];
 
 
@@ -1128,12 +1124,11 @@
       max_fd = MAX (max_fd, fdp->fd);
     }
 
+  // Avoid random lockups with send(), for lack of a better solution so far
+  tv.tv_sec = timeout_milliseconds < 0 ? 1 : timeout_milliseconds / 1000;
+  tv.tv_usec = timeout_milliseconds < 0 ? 0 : (timeout_milliseconds % 1000) * 1000;
 
-  tv.tv_sec = timeout_milliseconds / 1000;
-  tv.tv_usec = (timeout_milliseconds % 1000) * 1000;
-
-  ready = select (max_fd + 1, &read_set, &write_set, &err_set,
-                  timeout_milliseconds < 0 ? NULL : &tv);
+  ready = select (max_fd + 1, &read_set, &write_set, &err_set, &tv);
 
   if (DBUS_SOCKET_API_RETURNS_ERROR (ready))
     {
@@ -1359,6 +1354,8 @@
         }
     }
 
+  _dbus_fd_set_close_on_exec (fd);
+
   if (!_dbus_set_fd_nonblocking (fd, error))
     {
       closesocket (fd);
@@ -1551,6 +1548,7 @@
 
   for (i = 0 ; i < nlisten_fd ; i++)
     {
+      _dbus_fd_set_close_on_exec (listen_fd[i]);
       if (!_dbus_set_fd_nonblocking (listen_fd[i], error))
         {
           goto failed;
@@ -1874,14 +1872,15 @@
 
 
 /**
- * Get current time, as in gettimeofday().
+ * Get current time, as in gettimeofday(). Never uses the monotonic
+ * clock.
  *
  * @param tv_sec return location for number of seconds
  * @param tv_usec return location for number of microseconds
  */
 void
-_dbus_get_current_time (long *tv_sec,
-                        long *tv_usec)
+_dbus_get_real_time (long *tv_sec,
+                     long *tv_usec)
 {
   FILETIME ft;
   dbus_uint64_t time64;
@@ -1903,6 +1902,20 @@
     *tv_usec = time64 % 1000000;
 }
 
+/**
+ * Get current time, as in gettimeofday(). Use the monotonic clock if
+ * available, to avoid problems when the system time changes.
+ *
+ * @param tv_sec return location for number of seconds
+ * @param tv_usec return location for number of microseconds
+ */
+void
+_dbus_get_monotonic_time (long *tv_sec,
+                          long *tv_usec)
+{
+  /* no implementation yet, fall back to wall-clock time */
+  _dbus_get_real_time (tv_sec, tv_usec);
+}
 
 /**
  * signal (SIGPIPE, SIG_IGN);
@@ -2050,10 +2063,6 @@
     return TRUE;
 }
 
-/* Forward declaration of prototype used in next function */
-static dbus_bool_t
-_dbus_get_install_root(char *prefix, int len);
-
 /*
  * replaces the term DBUS_PREFIX in configure_time_path by the
  * current dbus installation directory. On unix this function is a noop
@@ -2536,35 +2545,172 @@
 // mutex to determine if dbus-daemon is already started (per user)
 static const char *cDBusDaemonMutex = "DBusDaemonMutex";
 // named shm for dbus adress info (per user)
-#ifdef _DEBUG
-static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfoDebug";
-#else
 static const char *cDBusDaemonAddressInfo = "DBusDaemonAddressInfo";
-#endif
 
+static dbus_bool_t
+_dbus_get_install_root_as_hash(DBusString *out)
+{
+    DBusString install_path;
 
-void
-_dbus_daemon_publish_session_bus_address (const char* address)
+    char path[MAX_PATH*2];
+    int path_size = sizeof(path);
+
+    if (!_dbus_get_install_root(path,path_size))
+        return FALSE;
+
+    _dbus_string_init(&install_path);
+    _dbus_string_append(&install_path,path);
+
+    _dbus_string_init(out);
+    _dbus_string_tolower_ascii(&install_path,0,_dbus_string_get_length(&install_path));
+
+    if (!_dbus_sha_compute (&install_path, out))
+        return FALSE;
+
+    return TRUE;
+}
+
+static dbus_bool_t
+_dbus_get_address_string (DBusString *out, const char *basestring, const char *scope)
+{
+  _dbus_string_init(out);
+  _dbus_string_append(out,basestring);
+
+  if (!scope)
+    {
+      return TRUE;
+    }
+  else if (strcmp(scope,"*install-path") == 0
+        // for 1.3 compatibility
+        || strcmp(scope,"install-path") == 0)
+    {
+      DBusString temp;
+      if (!_dbus_get_install_root_as_hash(&temp))
+        {
+          _dbus_string_free(out);
+           return FALSE;
+        }
+      _dbus_string_append(out,"-");
+      _dbus_string_append(out,_dbus_string_get_const_data(&temp));
+      _dbus_string_free(&temp);
+    }
+  else if (strcmp(scope,"*user") == 0)
+    {
+      _dbus_string_append(out,"-");
+      if (!_dbus_append_user_from_current_process(out))
+        {
+           _dbus_string_free(out);
+           return FALSE;
+        }
+    }
+  else if (strlen(scope) > 0)
+    {
+      _dbus_string_append(out,"-");
+      _dbus_string_append(out,scope);
+      return TRUE;
+    }
+  return TRUE;
+}
+
+static dbus_bool_t
+_dbus_get_shm_name (DBusString *out,const char *scope)
+{
+  return _dbus_get_address_string (out,cDBusDaemonAddressInfo,scope);
+}
+
+static dbus_bool_t
+_dbus_get_mutex_name (DBusString *out,const char *scope)
+{
+  return _dbus_get_address_string (out,cDBusDaemonMutex,scope);
+}
+
+dbus_bool_t
+_dbus_daemon_is_session_bus_address_published (const char *scope)
 {
   HANDLE lock;
-  char *shared_addr = NULL;
-  DWORD ret;
+  DBusString mutex_name;
 
-  _dbus_assert (address);
-  // before _dbus_global_lock to keep correct lock/release order
-  hDBusDaemonMutex = CreateMutexA( NULL, FALSE, cDBusDaemonMutex );
-  ret = WaitForSingleObject( hDBusDaemonMutex, 1000 );
-  if ( ret != WAIT_OBJECT_0 ) {
-    _dbus_warn("Could not lock mutex %s (return code %ld). daemon already running? Bus address not published.\n", cDBusDaemonMutex, ret );
-    return;
-  }
+  if (!_dbus_get_mutex_name(&mutex_name,scope))
+    {
+      _dbus_string_free( &mutex_name );
+      return FALSE;
+    }
+
+  if (hDBusDaemonMutex)
+      return TRUE;
 
   // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs
   lock = _dbus_global_lock( cUniqueDBusInitMutex );
 
+  // we use CreateMutex instead of OpenMutex because of possible race conditions,
+  // see http://msdn.microsoft.com/en-us/library/ms684315%28VS.85%29.aspx
+  hDBusDaemonMutex = CreateMutexA( NULL, FALSE, _dbus_string_get_const_data(&mutex_name) );
+
+  /* The client uses mutex ownership to detect a running server, so the server should do so too.
+     Fortunally the client deletes the mutex in the lock protected area, so checking presence 
+     will work too.  */
+
+  _dbus_global_unlock( lock );
+
+  _dbus_string_free( &mutex_name );
+
+  if (hDBusDaemonMutex  == NULL)
+      return FALSE;
+  if (GetLastError() == ERROR_ALREADY_EXISTS)
+    {
+      CloseHandle(hDBusDaemonMutex);
+      hDBusDaemonMutex = NULL;
+      return TRUE;
+    }
+  // mutex wasn't created before, so return false.
+  // We leave the mutex name allocated for later reusage
+  // in _dbus_daemon_publish_session_bus_address.
+  return FALSE;
+}
+
+dbus_bool_t
+_dbus_daemon_publish_session_bus_address (const char* address, const char *scope)
+{
+  HANDLE lock;
+  char *shared_addr = NULL;
+  DBusString shm_name;
+  DBusString mutex_name;
+
+  _dbus_assert (address);
+
+  if (!_dbus_get_mutex_name(&mutex_name,scope))
+    {
+      _dbus_string_free( &mutex_name );
+      return FALSE;
+    }
+
+  // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs
+  lock = _dbus_global_lock( cUniqueDBusInitMutex );
+
+  if (!hDBusDaemonMutex)
+    {
+      hDBusDaemonMutex = CreateMutexA( NULL, FALSE, _dbus_string_get_const_data(&mutex_name) );
+    }
+  _dbus_string_free( &mutex_name );
+
+  // acquire the mutex
+  if (WaitForSingleObject( hDBusDaemonMutex, 10 ) != WAIT_OBJECT_0)
+    {
+      _dbus_global_unlock( lock );
+      CloseHandle( hDBusDaemonMutex );
+      return FALSE;
+    }
+
+  if (!_dbus_get_shm_name(&shm_name,scope))
+    {
+      _dbus_string_free( &shm_name );
+      _dbus_global_unlock( lock );
+      return FALSE;
+    }
+
   // create shm
   hDBusSharedMem = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
-                                      0, strlen( address ) + 1, cDBusDaemonAddressInfo );
+                                       0, strlen( address ) + 1, _dbus_string_get_const_data(&shm_name) );
   _dbus_assert( hDBusSharedMem );
 
   shared_addr = MapViewOfFile( hDBusSharedMem, FILE_MAP_WRITE, 0, 0, 0 );
@@ -2577,6 +2723,10 @@
   UnmapViewOfFile( shared_addr );
 
   _dbus_global_unlock( lock );
+  _dbus_verbose( "published session bus address at %s\n",_dbus_string_get_const_data (&shm_name) );
+
+  _dbus_string_free( &shm_name );
+  return TRUE;
 }
 
 void
@@ -2601,7 +2751,7 @@
 }
 
 static dbus_bool_t
-_dbus_get_autolaunch_shm (DBusString *address)
+_dbus_get_autolaunch_shm (DBusString *address, DBusString *shm_name)
 {
   HANDLE sharedMem;
   char *shared_addr;
@@ -2610,7 +2760,7 @@
   // read shm
   for(i=0;i<20;++i) {
       // we know that dbus-daemon is available, so we wait until shm is available
-      sharedMem = OpenFileMappingA( FILE_MAP_READ, FALSE, cDBusDaemonAddressInfo );
+      sharedMem = OpenFileMappingA( FILE_MAP_READ, FALSE, _dbus_string_get_const_data(shm_name));
       if( sharedMem == 0 )
           Sleep( 100 );
       if ( sharedMem != 0)
@@ -2638,39 +2788,48 @@
 }
 
 static dbus_bool_t
-_dbus_daemon_already_runs (DBusString *address)
+_dbus_daemon_already_runs (DBusString *address, DBusString *shm_name, const char *scope)
 {
   HANDLE lock;
   HANDLE daemon;
+  DBusString mutex_name;
   dbus_bool_t bRet = TRUE;
 
+  if (!_dbus_get_mutex_name(&mutex_name,scope))
+    {
+      _dbus_string_free( &mutex_name );
+      return FALSE;
+    }
+
   // sync _dbus_daemon_publish_session_bus_address, _dbus_daemon_unpublish_session_bus_address and _dbus_daemon_already_runs
   lock = _dbus_global_lock( cUniqueDBusInitMutex );
 
   // do checks
-  daemon = CreateMutexA( NULL, FALSE, cDBusDaemonMutex );
+  daemon = CreateMutexA( NULL, FALSE, _dbus_string_get_const_data(&mutex_name) );
   if(WaitForSingleObject( daemon, 10 ) != WAIT_TIMEOUT)
     {
       ReleaseMutex (daemon);
       CloseHandle (daemon);
 
       _dbus_global_unlock( lock );
+      _dbus_string_free( &mutex_name );
       return FALSE;
     }
 
   // read shm
-  bRet = _dbus_get_autolaunch_shm( address );
+  bRet = _dbus_get_autolaunch_shm( address, shm_name );
 
   // cleanup
   CloseHandle ( daemon );
 
   _dbus_global_unlock( lock );
+  _dbus_string_free( &mutex_name );
 
   return bRet;
 }
 
 dbus_bool_t
-_dbus_get_autolaunch_address (DBusString *address, 
+_dbus_get_autolaunch_address (const char *scope, DBusString *address,
                               DBusError *error)
 {
   HANDLE mutex;
@@ -2681,25 +2840,62 @@
   char dbus_exe_path[MAX_PATH];
   char dbus_args[MAX_PATH * 2];
   const char * daemon_name = DBUS_DAEMON_NAME ".exe";
-
-  mutex = _dbus_global_lock ( cDBusAutolaunchMutex );
+  DBusString shm_name;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
-  if (_dbus_daemon_already_runs(address))
+  if (!_dbus_get_shm_name(&shm_name,scope))
     {
-        _dbus_verbose("found already running dbus daemon\n");
+        dbus_set_error_const (error, DBUS_ERROR_FAILED, "could not determine shm name");
+        return FALSE;
+    }
+
+  mutex = _dbus_global_lock ( cDBusAutolaunchMutex );
+
+  if (_dbus_daemon_already_runs(address,&shm_name,scope))
+    {
+        _dbus_verbose( "found running dbus daemon at %s\n",
+                       _dbus_string_get_const_data (&shm_name) );
         retval = TRUE;
         goto out;
     }
 
   if (!SearchPathA(NULL, daemon_name, NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile))
     {
-      printf ("please add the path to %s to your PATH environment variable\n", daemon_name);
-      printf ("or start the daemon manually\n\n");
-      goto out;
+      // Look in directory containing dbus shared library
+      HMODULE hmod;
+      char dbus_module_path[MAX_PATH];
+      DWORD rc;
+
+      _dbus_verbose( "did not found dbus daemon executable on default search path, "
+            "trying path where dbus shared library is located");
+
+      hmod = _dbus_win_get_dll_hmodule();
+      rc = GetModuleFileNameA(hmod, dbus_module_path, sizeof(dbus_module_path));
+      if (rc <= 0)
+        {
+          dbus_set_error_const (error, DBUS_ERROR_FAILED, "could not retrieve dbus shared library file name");
+          retval = FALSE;
+          goto out;
+        }
+      else
+        {
+          char *ext_idx = strrchr(dbus_module_path, '\\');
+          if (ext_idx)
+          *ext_idx = '\0';
+          if (!SearchPathA(dbus_module_path, daemon_name, NULL, sizeof(dbus_exe_path), dbus_exe_path, &lpFile))
+            {
+              dbus_set_error_const (error, DBUS_ERROR_FAILED, "could not find dbus-daemon executable");
+              retval = FALSE;
+              printf ("please add the path to %s to your PATH environment variable\n", daemon_name);
+              printf ("or start the daemon manually\n\n");
+              goto out;
+            }
+          _dbus_verbose( "found dbus daemon executable at %s",dbus_module_path);
+        }
     }
 
+
   // Create process
   ZeroMemory( &si, sizeof(si) );
   si.cb = sizeof(si);
@@ -2713,11 +2909,15 @@
     {
       CloseHandle (pi.hThread);
       CloseHandle (pi.hProcess);
-      retval = _dbus_get_autolaunch_shm( address );
+      retval = _dbus_get_autolaunch_shm( address, &shm_name );
+      if (retval == FALSE)
+        dbus_set_error_const (error, DBUS_ERROR_FAILED, "Failed to get autolaunch address from launched dbus-daemon");
     }
-  
-  if (retval == FALSE)
-    dbus_set_error_const (error, DBUS_ERROR_FAILED, "Failed to launch dbus-daemon");
+  else
+    {
+      dbus_set_error_const (error, DBUS_ERROR_FAILED, "Failed to launch dbus-daemon");
+      retval = FALSE;
+    }
 
 out:
   if (retval)
@@ -2804,6 +3004,25 @@
       }
   }
 #else
+/*
+ the code for accessing services requires absolute base pathes
+ in case DBUS_DATADIR is relative make it absolute
+*/
+#ifdef DBUS_WIN
+  {
+    DBusString p;
+
+    _dbus_string_init_const (&p, DBUS_DATADIR);
+
+    if (!_dbus_path_is_absolute (&p))
+      {
+        char install_root[1000];
+        if (_dbus_get_install_root (install_root, sizeof(install_root)))
+          if (!_dbus_string_append (&servicedir_path, install_root))
+            goto oom;
+      }
+  }
+#endif
   if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR))
     goto oom;
 
@@ -2893,6 +3112,21 @@
 }
 
 /**
+ * Atomically get the value of an integer. It may change at any time
+ * thereafter, so this is mostly only useful for assertions.
+ *
+ * @param atomic pointer to the integer to get
+ * @returns the value at this moment
+ */
+dbus_int32_t
+_dbus_atomic_get (DBusAtomic *atomic)
+{
+  /* this is what GLib does, hopefully it's right... */
+  MemoryBarrier ();
+  return atomic->value;
+}
+
+/**
  * Called when the bus daemon is signaled to reload its configuration; any
  * caches should be nuked. Of course any caches that need explicit reload
  * are probably broken, but c'est la vie.
@@ -2923,12 +3157,10 @@
  * @param len length of buffer
  * @returns #FALSE on failure
  */
-static dbus_bool_t
+dbus_bool_t
 _dbus_get_install_root(char *prefix, int len)
 {
     //To find the prefix, we cut the filename and also \bin\ if present
-    char* p = 0;
-    int i;
     DWORD pathLength;
     char *lastSlash;
     SetLastError( 0 );
@@ -3082,7 +3314,6 @@
 {
   DBusString homedir;
   DBusString dotdir;
-  dbus_uid_t uid;
   const char *homepath;
   const char *homedrive;
 
@@ -3384,6 +3615,29 @@
   return TRUE;
 }
 
+/**
+ * Checks whether the filename is an absolute path
+ *
+ * @param filename the filename
+ * @returns #TRUE if an absolute path
+ */
+dbus_bool_t
+_dbus_path_is_absolute (const DBusString *filename)
+{
+  if (_dbus_string_get_length (filename) > 0)
+    return _dbus_string_get_byte (filename, 1) == ':'
+           || _dbus_string_get_byte (filename, 0) == '\\'
+           || _dbus_string_get_byte (filename, 0) == '/';
+  else
+    return FALSE;
+}
+
+dbus_bool_t
+_dbus_check_setuid (void)
+{
+  return FALSE;
+}
+
 /** @} end of sysdeps-win */
 /* tests in dbus-sysdeps-util.c */
 
diff --git a/dbus/dbus-sysdeps-win.h b/dbus/dbus-sysdeps-win.h
index a8ff943..74624b7 100644
--- a/dbus/dbus-sysdeps-win.h
+++ b/dbus/dbus-sysdeps-win.h
@@ -83,6 +83,8 @@
 dbus_bool_t _dbus_get_config_file_name(DBusString *config_file, 
                                        char *s);
 
+dbus_bool_t _dbus_get_install_root(char *prefix, int len);
+
 #endif
 
 /** @} end of sysdeps-win.h */
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index bab516d..04fb8d7 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -182,6 +182,11 @@
 const char*
 _dbus_getenv (const char *varname)
 {  
+  /* Don't respect any environment variables if the current process is
+   * setuid.  This is the equivalent of glibc's __secure_getenv().
+   */
+  if (_dbus_check_setuid ())
+    return NULL;
   return getenv (varname);
 }
 
@@ -208,47 +213,6 @@
 }
 
 /**
- * Gets a #NULL-terminated list of key=value pairs from the
- * environment. Use dbus_free_string_array to free it.
- *
- * @returns the environment or #NULL on OOM
- */
-char **
-_dbus_get_environment (void)
-{
-  int i, length;
-  char **environment;
-
-  _dbus_assert (environ != NULL);
-
-  for (length = 0; environ[length] != NULL; length++);
-
-  /* Add one for NULL */
-  length++;
-
-  environment = dbus_new0 (char *, length);
-
-  if (environment == NULL)
-    return NULL;
-
-  for (i = 0; environ[i] != NULL; i++)
-    {
-      environment[i] = _dbus_strdup (environ[i]);
-
-      if (environment[i] == NULL)
-        break;
-    }
-
-  if (environ[i] != NULL)
-    {
-      dbus_free_string_array (environment);
-      environment = NULL;
-    }
-
-  return environment;
-}
-
-/**
  * Split paths into a list of char strings
  * 
  * @param dirs string with pathes 
@@ -453,45 +417,6 @@
   return TRUE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/**
- * Appends a double to a DBusString.
- * 
- * @param str the string
- * @param value the floating point value
- * @returns #FALSE if not enough memory or other failure.
- */
-dbus_bool_t
-_dbus_string_append_double (DBusString *str,
-                            double      value)
-{
-#define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
-  int orig_len;
-  char *buf;
-  int i;
-  
-  orig_len = _dbus_string_get_length (str);
-
-  if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
-    return FALSE;
-
-  buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
-
-  snprintf (buf, MAX_LONG_LEN, "%g", value);
-
-  i = 0;
-  while (*buf)
-    {
-      ++buf;
-      ++i;
-    }
-  
-  _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
-  
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /**
  * Parses an integer contained in a DBusString. Either return parameter
  * may be #NULL if you aren't interested in it. The integer is parsed
@@ -570,223 +495,6 @@
   return TRUE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-static dbus_bool_t
-ascii_isspace (char c)
-{
-  return (c == ' ' ||
-	  c == '\f' ||
-	  c == '\n' ||
-	  c == '\r' ||
-	  c == '\t' ||
-	  c == '\v');
-}
-#endif /* DBUS_BUILD_TESTS */
-
-#ifdef DBUS_BUILD_TESTS
-static dbus_bool_t
-ascii_isdigit (char c)
-{
-  return c >= '0' && c <= '9';
-}
-#endif /* DBUS_BUILD_TESTS */
-
-#ifdef DBUS_BUILD_TESTS
-static dbus_bool_t
-ascii_isxdigit (char c)
-{
-  return (ascii_isdigit (c) ||
-	  (c >= 'a' && c <= 'f') ||
-	  (c >= 'A' && c <= 'F'));
-}
-#endif /* DBUS_BUILD_TESTS */
-
-#ifdef DBUS_BUILD_TESTS
-/* Calls strtod in a locale-independent fashion, by looking at
- * the locale data and patching the decimal comma to a point.
- *
- * Relicensed from glib.
- */
-static double
-ascii_strtod (const char *nptr,
-	      char      **endptr)
-{
-  /* FIXME: The Win32 C library's strtod() doesn't handle hex.
-   * Presumably many Unixes don't either.
-   */
-
-  char *fail_pos;
-  double val;
-  struct lconv *locale_data;
-  const char *decimal_point;
-  int decimal_point_len;
-  const char *p, *decimal_point_pos;
-  const char *end = NULL; /* Silence gcc */
-
-  fail_pos = NULL;
-
-#if HAVE_LOCALECONV
-  locale_data = localeconv ();
-  decimal_point = locale_data->decimal_point;
-#else
-  decimal_point = ".";
-#endif
-
-  decimal_point_len = strlen (decimal_point);
-  _dbus_assert (decimal_point_len != 0);
-  
-  decimal_point_pos = NULL;
-  if (decimal_point[0] != '.' ||
-      decimal_point[1] != 0)
-    {
-      p = nptr;
-      /* Skip leading space */
-      while (ascii_isspace (*p))
-	p++;
-      
-      /* Skip leading optional sign */
-      if (*p == '+' || *p == '-')
-	p++;
-      
-      if (p[0] == '0' &&
-	  (p[1] == 'x' || p[1] == 'X'))
-	{
-	  p += 2;
-	  /* HEX - find the (optional) decimal point */
-	  
-	  while (ascii_isxdigit (*p))
-	    p++;
-	  
-	  if (*p == '.')
-	    {
-	      decimal_point_pos = p++;
-	      
-	      while (ascii_isxdigit (*p))
-		p++;
-	      
-	      if (*p == 'p' || *p == 'P')
-		p++;
-	      if (*p == '+' || *p == '-')
-		p++;
-	      while (ascii_isdigit (*p))
-		p++;
-	      end = p;
-	    }
-	}
-      else
-	{
-	  while (ascii_isdigit (*p))
-	    p++;
-	  
-	  if (*p == '.')
-	    {
-	      decimal_point_pos = p++;
-	      
-	      while (ascii_isdigit (*p))
-		p++;
-	      
-	      if (*p == 'e' || *p == 'E')
-		p++;
-	      if (*p == '+' || *p == '-')
-		p++;
-	      while (ascii_isdigit (*p))
-		p++;
-	      end = p;
-	    }
-	}
-      /* For the other cases, we need not convert the decimal point */
-    }
-
-  /* Set errno to zero, so that we can distinguish zero results
-     and underflows */
-  _dbus_set_errno_to_zero ();
-  
-  if (decimal_point_pos)
-    {
-      char *copy, *c;
-
-      /* We need to convert the '.' to the locale specific decimal point */
-      copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
-      
-      c = copy;
-      memcpy (c, nptr, decimal_point_pos - nptr);
-      c += decimal_point_pos - nptr;
-      memcpy (c, decimal_point, decimal_point_len);
-      c += decimal_point_len;
-      memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
-      c += end - (decimal_point_pos + 1);
-      *c = 0;
-
-      val = strtod (copy, &fail_pos);
-
-      if (fail_pos)
-	{
-	  if (fail_pos > decimal_point_pos)
-	    fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
-	  else
-	    fail_pos = (char *)nptr + (fail_pos - copy);
-	}
-      
-      dbus_free (copy);
-	  
-    }
-  else
-    val = strtod (nptr, &fail_pos);
-
-  if (endptr)
-    *endptr = fail_pos;
-  
-  return val;
-}
-#endif /* DBUS_BUILD_TESTS */
-
-#ifdef DBUS_BUILD_TESTS
-/**
- * Parses a floating point number contained in a DBusString. Either
- * return parameter may be #NULL if you aren't interested in it. The
- * integer is parsed and stored in value_return. Return parameters are
- * not initialized if the function returns #FALSE.
- *
- * @param str the string
- * @param start the byte index of the start of the float
- * @param value_return return location of the float value or #NULL
- * @param end_return return location of the end of the float, or #NULL
- * @returns #TRUE on success
- */
-dbus_bool_t
-_dbus_string_parse_double (const DBusString *str,
-                           int               start,
-                           double           *value_return,
-                           int              *end_return)
-{
-  double v;
-  const char *p;
-  char *end;
-
-  p = _dbus_string_get_const_data_len (str, start,
-                                       _dbus_string_get_length (str) - start);
-
-  /* parsing hex works on linux but isn't portable, so intercept it
-   * here to get uniform behavior.
-   */
-  if (p[0] == '0' && (p[1] == 'x' || p[1] == 'X'))
-    return FALSE;
-  
-  end = NULL;
-  _dbus_set_errno_to_zero ();
-  v = ascii_strtod (p, &end);
-  if (end == NULL || end == p || errno != 0)
-    return FALSE;
-
-  if (value_return)
-    *value_return = v;
-  if (end_return)
-    *end_return = start + (end - p);
-
-  return TRUE;
-}
-#endif /* DBUS_BUILD_TESTS */
-
 /** @} */ /* DBusString group */
 
 /**
@@ -805,7 +513,7 @@
   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
                  n_bytes);
   
-  _dbus_get_current_time (NULL, &tv_usec);
+  _dbus_get_real_time (NULL, &tv_usec);
   srand (tv_usec);
   
   i = 0;
@@ -911,16 +619,14 @@
 #ifdef EPROTONOSUPPORT
     case EPROTONOSUPPORT:
       return DBUS_ERROR_NOT_SUPPORTED;
-#endif
-#ifdef WSAEPROTONOSUPPORT
+#elif defined(WSAEPROTONOSUPPORT)
     case WSAEPROTONOSUPPORT:
       return DBUS_ERROR_NOT_SUPPORTED;
 #endif
 #ifdef EAFNOSUPPORT
     case EAFNOSUPPORT:
       return DBUS_ERROR_NOT_SUPPORTED;
-#endif
-#ifdef WSAEAFNOSUPPORT
+#elif defined(WSAEAFNOSUPPORT)
     case WSAEAFNOSUPPORT:
       return DBUS_ERROR_NOT_SUPPORTED;
 #endif
@@ -951,32 +657,28 @@
 #ifdef ECONNREFUSED
     case ECONNREFUSED:
       return DBUS_ERROR_NO_SERVER;
-#endif
-#ifdef WSAECONNREFUSED
+#elif defined(WSAECONNREFUSED)
     case WSAECONNREFUSED:
       return DBUS_ERROR_NO_SERVER;
 #endif
 #ifdef ETIMEDOUT
     case ETIMEDOUT:
       return DBUS_ERROR_TIMEOUT;
-#endif
-#ifdef WSAETIMEDOUT
+#elif defined(WSAETIMEDOUT)
     case WSAETIMEDOUT:
       return DBUS_ERROR_TIMEOUT;
 #endif
 #ifdef ENETUNREACH
     case ENETUNREACH:
       return DBUS_ERROR_NO_NETWORK;
-#endif
-#ifdef WSAENETUNREACH
+#elif defined(WSAENETUNREACH)
     case WSAENETUNREACH:
       return DBUS_ERROR_NO_NETWORK;
 #endif
 #ifdef EADDRINUSE
     case EADDRINUSE:
       return DBUS_ERROR_ADDRESS_IN_USE;
-#endif
-#ifdef WSAEADDRINUSE
+#elif defined(WSAEADDRINUSE)
     case WSAEADDRINUSE:
       return DBUS_ERROR_ADDRESS_IN_USE;
 #endif
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index c98db36..eee9160 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -31,6 +31,10 @@
 #include <stdint.h>
 #endif
 
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
 #include <dbus/dbus-errors.h>
 #include <dbus/dbus-file.h>
 #include <dbus/dbus-string.h>
@@ -83,6 +87,7 @@
 
 void _dbus_abort (void) _DBUS_GNUC_NORETURN;
 
+dbus_bool_t _dbus_check_setuid (void);
 const char* _dbus_getenv (const char *varname);
 dbus_bool_t _dbus_setenv (const char *varname,
 			  const char *value);
@@ -121,8 +126,6 @@
  * 
  */
 
-dbus_bool_t _dbus_open_tcp_socket  (int              *fd,
-                                    DBusError        *error);
 dbus_bool_t _dbus_close_socket     (int               fd,
                                     DBusError        *error);
 int         _dbus_read_socket      (int               fd,
@@ -207,7 +210,9 @@
 dbus_bool_t _dbus_append_keyring_directory_for_credentials (DBusString      *directory,
                                                             DBusCredentials *credentials);
 
-void _dbus_daemon_publish_session_bus_address (const char* address);
+dbus_bool_t _dbus_daemon_is_session_bus_address_published (const char *scope);
+
+dbus_bool_t _dbus_daemon_publish_session_bus_address (const char* address, const char* shm_name);
 
 void _dbus_daemon_unpublish_session_bus_address (void);
 
@@ -242,6 +247,7 @@
 
 dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic);
 dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic);
+dbus_int32_t _dbus_atomic_get (DBusAtomic *atomic);
 
 
 /* AIX uses different values for poll */
@@ -303,8 +309,11 @@
 
 void _dbus_sleep_milliseconds (int milliseconds);
 
-void _dbus_get_current_time (long *tv_sec,
-                             long *tv_usec);
+void _dbus_get_monotonic_time (long *tv_sec,
+                               long *tv_usec);
+
+void _dbus_get_real_time (long *tv_sec,
+                          long *tv_usec);
 
 /**
  * directory interface
@@ -474,8 +483,9 @@
       _DBUS_BYTE_OF_PRIMITIVE (a, 6) == _DBUS_BYTE_OF_PRIMITIVE (b, 6) &&       \
       _DBUS_BYTE_OF_PRIMITIVE (a, 7) == _DBUS_BYTE_OF_PRIMITIVE (b, 7))
 
-dbus_bool_t _dbus_get_autolaunch_address (DBusString *address, 
-					  DBusError *error);
+dbus_bool_t _dbus_get_autolaunch_address (const char *scope,
+                                          DBusString *address,
+					                      DBusError  *error);
 
 dbus_bool_t _dbus_lookup_session_address (dbus_bool_t *supported,
                                           DBusString  *address,
@@ -514,6 +524,8 @@
 
 void _dbus_flush_caches (void);
 
+void _dbus_request_file_descriptor_limit (unsigned int limit);
+
 /*
  * replaces the term DBUS_PREFIX in configure_time_path by the
  * current dbus installation directory. On unix this function is a noop
@@ -528,4 +540,9 @@
 
 DBUS_END_DECLS
 
+
+#ifdef DBUS_WIN
+#include "dbus-sysdeps-win.h"
+#endif
+
 #endif /* DBUS_SYSDEPS_H */
diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c
index 99becb0..224a6c8 100644
--- a/dbus/dbus-test.c
+++ b/dbus/dbus-test.c
@@ -63,9 +63,9 @@
       printf ("%s: running %s tests\n", "dbus-test", test_name);
       if (!test ())
 	die (test_name);
-    }
 
-  check_memleaks ();
+      check_memleaks ();
+    }
 }
 
 static void
@@ -79,9 +79,9 @@
       printf ("%s: running %s tests\n", "dbus-test", test_name);
       if (!test (test_data_dir))
 	die (test_name);
-    }
 
-  check_memleaks ();
+      check_memleaks ();
+    }
 }
 
 #endif /* DBUS_BUILD_TESTS */
@@ -128,15 +128,7 @@
   
   run_test ("marshalling", specific_test, _dbus_marshal_test);
 
-#if 0
-  printf ("%s: running recursive marshalling tests\n", "dbus-test");
-  if (!_dbus_marshal_recursive_test ())
-    die ("recursive marshal");
-
-  check_memleaks ();
-#else
-  _dbus_warn ("recursive marshal tests disabled\n");
-#endif
+  run_test ("marshal-recursive", specific_test, _dbus_marshal_recursive_test);
 
   run_test ("byteswap", specific_test, _dbus_marshal_byteswap_test);
   
@@ -150,8 +142,6 @@
 
   run_test ("marshal-validate", specific_test, _dbus_marshal_validate_test);
 
-  run_test ("marshal-header", specific_test, _dbus_marshal_header_test);
-  
   run_data_test ("message", specific_test, _dbus_message_test, test_data_dir);
   
   run_test ("hash", specific_test, _dbus_hash_test);
@@ -164,24 +154,16 @@
 
 #ifdef DBUS_UNIX
   run_data_test ("userdb", specific_test, _dbus_userdb_test, test_data_dir);
+
+  run_test ("transport-unix", specific_test, _dbus_transport_unix_test);
 #endif
   
   run_test ("keyring", specific_test, _dbus_keyring_test);
-  
-#if 0
-  printf ("%s: running md5 tests\n", "dbus-test");
-  if (!_dbus_md5_test ())
-    die ("md5");
 
-  check_memleaks ();
-#endif
-  
   run_data_test ("sha", specific_test, _dbus_sha_test, test_data_dir);
   
   run_data_test ("auth", specific_test, _dbus_auth_test, test_data_dir);
 
-  run_data_test ("pending-call", specific_test, _dbus_pending_call_test, test_data_dir);
-  
   printf ("%s: completed successfully\n", "dbus-test");
 #else
   printf ("Not compiled with unit tests, not running any\n");
diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h
index 0238b0c..f254388 100644
--- a/dbus/dbus-test.h
+++ b/dbus/dbus-test.h
@@ -29,12 +29,10 @@
 #include <dbus/dbus-marshal-validate.h>
 
 dbus_bool_t _dbus_hash_test              (void);
-dbus_bool_t _dbus_dict_test              (void);
 dbus_bool_t _dbus_list_test              (void);
 dbus_bool_t _dbus_marshal_test           (void);
 dbus_bool_t _dbus_marshal_recursive_test (void);
 dbus_bool_t _dbus_marshal_byteswap_test  (void);
-dbus_bool_t _dbus_marshal_header_test    (void);
 dbus_bool_t _dbus_marshal_validate_test  (void);
 dbus_bool_t _dbus_misc_test              (void);
 dbus_bool_t _dbus_signature_test         (void);
@@ -44,16 +42,15 @@
 dbus_bool_t _dbus_server_test            (void);
 dbus_bool_t _dbus_message_test           (const char *test_data_dir);
 dbus_bool_t _dbus_auth_test              (const char *test_data_dir);
-dbus_bool_t _dbus_md5_test               (void);
 dbus_bool_t _dbus_sha_test               (const char *test_data_dir);
 dbus_bool_t _dbus_keyring_test           (void);
 dbus_bool_t _dbus_data_slot_test         (void);
 dbus_bool_t _dbus_sysdeps_test           (void);
 dbus_bool_t _dbus_spawn_test             (const char *test_data_dir);
 dbus_bool_t _dbus_userdb_test            (const char *test_data_dir);
+dbus_bool_t _dbus_transport_unix_test    (void);
 dbus_bool_t _dbus_memory_test            (void);
 dbus_bool_t _dbus_object_tree_test       (void);
-dbus_bool_t _dbus_pending_call_test      (const char *test_data_dir);
 dbus_bool_t _dbus_credentials_test       (const char *test_data_dir);
 
 void        dbus_internal_do_not_use_run_tests         (const char          *test_data_dir,
diff --git a/dbus/dbus-threads-internal.h b/dbus/dbus-threads-internal.h
index 11f9ce2..64e8bac 100644
--- a/dbus/dbus-threads-internal.h
+++ b/dbus/dbus-threads-internal.h
@@ -27,27 +27,69 @@
 #include <dbus/dbus-types.h>
 #include <dbus/dbus-threads.h>
 
+/**
+ * @addtogroup DBusThreadsInternals
+ * @{
+ */
+
+/**
+ * A mutex which is recursive if possible, else non-recursive.
+ * This is typically recursive, but that cannot be relied upon.
+ */
+typedef struct DBusRMutex DBusRMutex;
+
+/**
+ * A mutex suitable for use with condition variables.
+ * This is typically non-recursive.
+ */
+typedef struct DBusCMutex DBusCMutex;
+
+/** @} */
+
 DBUS_BEGIN_DECLS
 
-DBusMutex*   _dbus_mutex_new                 (void);
-void         _dbus_mutex_free                (DBusMutex         *mutex);
-void         _dbus_mutex_lock                (DBusMutex         *mutex);
-void         _dbus_mutex_unlock              (DBusMutex         *mutex);
-void         _dbus_mutex_new_at_location     (DBusMutex        **location_p);
-void         _dbus_mutex_free_at_location    (DBusMutex        **location_p);
+void         _dbus_rmutex_lock               (DBusRMutex       *mutex);
+void         _dbus_rmutex_unlock             (DBusRMutex       *mutex);
+void         _dbus_rmutex_new_at_location    (DBusRMutex      **location_p);
+void         _dbus_rmutex_free_at_location   (DBusRMutex      **location_p);
+
+void         _dbus_cmutex_lock               (DBusCMutex       *mutex);
+void         _dbus_cmutex_unlock             (DBusCMutex       *mutex);
+void         _dbus_cmutex_new_at_location    (DBusCMutex      **location_p);
+void         _dbus_cmutex_free_at_location   (DBusCMutex      **location_p);
 
 DBusCondVar* _dbus_condvar_new               (void);
 void         _dbus_condvar_free              (DBusCondVar       *cond);
 void         _dbus_condvar_wait              (DBusCondVar       *cond,
-                                              DBusMutex         *mutex);
+                                              DBusCMutex        *mutex);
 dbus_bool_t  _dbus_condvar_wait_timeout      (DBusCondVar       *cond,
-                                              DBusMutex         *mutex,
+                                              DBusCMutex        *mutex,
                                               int                timeout_milliseconds);
 void         _dbus_condvar_wake_one          (DBusCondVar       *cond);
-void         _dbus_condvar_wake_all          (DBusCondVar       *cond);
 void         _dbus_condvar_new_at_location   (DBusCondVar      **location_p);
 void         _dbus_condvar_free_at_location  (DBusCondVar      **location_p);
 
+/* Private to threading implementations and dbus-threads.c */
+
+DBusRMutex  *_dbus_platform_rmutex_new       (void);
+void         _dbus_platform_rmutex_free      (DBusRMutex       *mutex);
+void         _dbus_platform_rmutex_lock      (DBusRMutex       *mutex);
+void         _dbus_platform_rmutex_unlock    (DBusRMutex       *mutex);
+
+DBusCMutex  *_dbus_platform_cmutex_new       (void);
+void         _dbus_platform_cmutex_free      (DBusCMutex       *mutex);
+void         _dbus_platform_cmutex_lock      (DBusCMutex       *mutex);
+void         _dbus_platform_cmutex_unlock    (DBusCMutex       *mutex);
+
+DBusCondVar* _dbus_platform_condvar_new      (void);
+void         _dbus_platform_condvar_free     (DBusCondVar       *cond);
+void         _dbus_platform_condvar_wait     (DBusCondVar       *cond,
+                                              DBusCMutex        *mutex);
+dbus_bool_t  _dbus_platform_condvar_wait_timeout (DBusCondVar   *cond,
+                                              DBusCMutex        *mutex,
+                                              int                timeout_milliseconds);
+void         _dbus_platform_condvar_wake_one (DBusCondVar       *cond);
+
 DBUS_END_DECLS
 
 #endif /* DBUS_THREADS_INTERNAL_H */
diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
index 37b68ba..bb1169d 100644
--- a/dbus/dbus-threads.c
+++ b/dbus/dbus-threads.c
@@ -26,23 +26,16 @@
 #include "dbus-threads-internal.h"
 #include "dbus-list.h"
 
-static DBusThreadFunctions thread_functions =
-{
-  0,
-  NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL,
-  
-  NULL, NULL, NULL, NULL
-};
-
 static int thread_init_generation = 0;
  
-static DBusList *uninitialized_mutex_list = NULL;
+static DBusList *uninitialized_rmutex_list = NULL;
+static DBusList *uninitialized_cmutex_list = NULL;
 static DBusList *uninitialized_condvar_list = NULL;
 
 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
 #define _DBUS_DUMMY_MUTEX ((DBusMutex*)0xABCDEF)
+#define _DBUS_DUMMY_RMUTEX ((DBusRMutex *) _DBUS_DUMMY_MUTEX)
+#define _DBUS_DUMMY_CMUTEX ((DBusCMutex *) _DBUS_DUMMY_MUTEX)
 
 /** This is used for the no-op default mutex pointer, just to be distinct from #NULL */
 #define _DBUS_DUMMY_CONDVAR ((DBusCondVar*)0xABCDEF2)
@@ -50,7 +43,7 @@
 /**
  * @defgroup DBusThreadsInternals Thread functions
  * @ingroup  DBusInternals
- * @brief _dbus_mutex_lock(), etc.
+ * @brief _dbus_rmutex_lock(), etc.
  *
  * Functions and macros related to threads and thread locks.
  *
@@ -58,80 +51,116 @@
  */
 
 /**
- * Creates a new mutex using the function supplied to dbus_threads_init(),
+ * Creates a new mutex
  * or creates a no-op mutex if threads are not initialized.
  * May return #NULL even if threads are initialized, indicating
  * out-of-memory.
  *
- * @returns new mutex or #NULL
- */
-DBusMutex*
-_dbus_mutex_new (void)
-{
-  if (thread_functions.recursive_mutex_new)
-    return (* thread_functions.recursive_mutex_new) ();
-  else if (thread_functions.mutex_new)
-    return (* thread_functions.mutex_new) ();
-  else
-    return _DBUS_DUMMY_MUTEX;
-}
-
-/**
- * This does the same thing as _dbus_mutex_new.  It however
- * gives another level of indirection by allocating a pointer
- * to point to the mutex location.  This allows the threading
- * module to swap out dummy mutexes for real a real mutex so libraries
+ * If possible, the mutex returned by this function is recursive, to
+ * avoid deadlocks. However, that cannot be relied on.
+ *
+ * The extra level of indirection given by allocating a pointer
+ * to point to the mutex location allows the threading
+ * module to swap out dummy mutexes for a real mutex so libraries
  * can initialize threads even after the D-Bus API has been used.
  *
  * @param location_p the location of the new mutex, can return #NULL on OOM
  */
 void
-_dbus_mutex_new_at_location (DBusMutex **location_p)
+_dbus_rmutex_new_at_location (DBusRMutex **location_p)
 {
   _dbus_assert (location_p != NULL);
 
-  *location_p = _dbus_mutex_new();
-
-  if (thread_init_generation != _dbus_current_generation && *location_p)
+  if (thread_init_generation == _dbus_current_generation)
     {
-      if (!_dbus_list_append (&uninitialized_mutex_list, location_p))
-        {
-	  _dbus_mutex_free (*location_p);
-	  *location_p = NULL;
-	}
+      *location_p = _dbus_platform_rmutex_new ();
+    }
+  else
+    {
+      *location_p = _DBUS_DUMMY_RMUTEX;
+
+      if (!_dbus_list_append (&uninitialized_rmutex_list, location_p))
+        *location_p = NULL;
     }
 }
 
 /**
- * Frees a mutex created with dbus_mutex_new(); does
- * nothing if passed a #NULL pointer.
+ * Creates a new mutex
+ * or creates a no-op mutex if threads are not initialized.
+ * May return #NULL even if threads are initialized, indicating
+ * out-of-memory.
+ *
+ * The returned mutex is suitable for use with condition variables.
+ *
+ * The extra level of indirection given by allocating a pointer
+ * to point to the mutex location allows the threading
+ * module to swap out dummy mutexes for a real mutex so libraries
+ * can initialize threads even after the D-Bus API has been used.
+ *
+ * @param location_p the location of the new mutex, can return #NULL on OOM
  */
 void
-_dbus_mutex_free (DBusMutex *mutex)
+_dbus_cmutex_new_at_location (DBusCMutex **location_p)
 {
-  if (mutex)
+  _dbus_assert (location_p != NULL);
+
+  if (thread_init_generation == _dbus_current_generation)
     {
-      if (mutex && thread_functions.recursive_mutex_free)
-        (* thread_functions.recursive_mutex_free) (mutex);
-      else if (mutex && thread_functions.mutex_free)
-        (* thread_functions.mutex_free) (mutex);
+      *location_p = _dbus_platform_cmutex_new ();
+    }
+  else
+    {
+      *location_p = _DBUS_DUMMY_CMUTEX;
+
+      if (!_dbus_list_append (&uninitialized_cmutex_list, location_p))
+        *location_p = NULL;
     }
 }
 
 /**
- * Frees a mutex and removes it from the 
- * uninitialized_mutex_list;
+ * Frees a DBusRMutex or removes it from the uninitialized mutex list;
  * does nothing if passed a #NULL pointer.
  */
 void
-_dbus_mutex_free_at_location (DBusMutex **location_p)
+_dbus_rmutex_free_at_location (DBusRMutex **location_p)
 {
-  if (location_p)
-    {
-      if (thread_init_generation != _dbus_current_generation)
-        _dbus_list_remove (&uninitialized_mutex_list, location_p);
+  if (location_p == NULL)
+    return;
 
-      _dbus_mutex_free (*location_p);
+  if (thread_init_generation == _dbus_current_generation)
+    {
+      if (*location_p != NULL)
+        _dbus_platform_rmutex_free (*location_p);
+    }
+  else
+    {
+      _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_RMUTEX);
+
+      _dbus_list_remove (&uninitialized_rmutex_list, location_p);
+    }
+}
+
+/**
+ * Frees a DBusCMutex and removes it from the
+ * uninitialized mutex list;
+ * does nothing if passed a #NULL pointer.
+ */
+void
+_dbus_cmutex_free_at_location (DBusCMutex **location_p)
+{
+  if (location_p == NULL)
+    return;
+
+  if (thread_init_generation == _dbus_current_generation)
+    {
+      if (*location_p != NULL)
+        _dbus_platform_cmutex_free (*location_p);
+    }
+  else
+    {
+      _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_CMUTEX);
+
+      _dbus_list_remove (&uninitialized_cmutex_list, location_p);
     }
 }
 
@@ -141,15 +170,22 @@
  * recursive locks.
  */
 void
-_dbus_mutex_lock (DBusMutex *mutex)
+_dbus_rmutex_lock (DBusRMutex *mutex)
 {
-  if (mutex) 
-    {
-      if (thread_functions.recursive_mutex_lock)
-        (* thread_functions.recursive_mutex_lock) (mutex);
-      else if (thread_functions.mutex_lock)
-        (* thread_functions.mutex_lock) (mutex);
-    }
+  if (mutex && thread_init_generation == _dbus_current_generation)
+    _dbus_platform_rmutex_lock (mutex);
+}
+
+/**
+ * Locks a mutex. Does nothing if passed a #NULL pointer.
+ * Locks may be recursive if threading implementation initialized
+ * recursive locks.
+ */
+void
+_dbus_cmutex_lock (DBusCMutex *mutex)
+{
+  if (mutex && thread_init_generation == _dbus_current_generation)
+    _dbus_platform_cmutex_lock (mutex);
 }
 
 /**
@@ -158,15 +194,22 @@
  * @returns #TRUE on success
  */
 void
-_dbus_mutex_unlock (DBusMutex *mutex)
+_dbus_rmutex_unlock (DBusRMutex *mutex)
 {
-  if (mutex)
-    {
-      if (thread_functions.recursive_mutex_unlock)
-        (* thread_functions.recursive_mutex_unlock) (mutex);
-      else if (thread_functions.mutex_unlock)
-        (* thread_functions.mutex_unlock) (mutex);
-    }
+  if (mutex && thread_init_generation == _dbus_current_generation)
+    _dbus_platform_rmutex_unlock (mutex);
+}
+
+/**
+ * Unlocks a mutex. Does nothing if passed a #NULL pointer.
+ *
+ * @returns #TRUE on success
+ */
+void
+_dbus_cmutex_unlock (DBusCMutex *mutex)
+{
+  if (mutex && thread_init_generation == _dbus_current_generation)
+    _dbus_platform_cmutex_unlock (mutex);
 }
 
 /**
@@ -180,8 +223,8 @@
 DBusCondVar *
 _dbus_condvar_new (void)
 {
-  if (thread_functions.condvar_new)
-    return (* thread_functions.condvar_new) ();
+  if (thread_init_generation == _dbus_current_generation)
+    return _dbus_platform_condvar_new ();
   else
     return _DBUS_DUMMY_CONDVAR;
 }
@@ -191,7 +234,7 @@
  * This does the same thing as _dbus_condvar_new.  It however
  * gives another level of indirection by allocating a pointer
  * to point to the condvar location.  This allows the threading
- * module to swap out dummy condvars for real a real condvar so libraries
+ * module to swap out dummy condvars for a real condvar so libraries
  * can initialize threads even after the D-Bus API has been used.
  *
  * @returns the location of a new condvar or #NULL on OOM
@@ -200,15 +243,18 @@
 void 
 _dbus_condvar_new_at_location (DBusCondVar **location_p)
 {
-  *location_p = _dbus_condvar_new();
+  _dbus_assert (location_p != NULL);
 
-  if (thread_init_generation != _dbus_current_generation && *location_p)
+  if (thread_init_generation == _dbus_current_generation)
     {
+      *location_p = _dbus_condvar_new();
+    }
+  else
+    {
+      *location_p = _DBUS_DUMMY_CONDVAR;
+
       if (!_dbus_list_append (&uninitialized_condvar_list, location_p))
-        {
-          _dbus_condvar_free (*location_p);
-          *location_p = NULL;
-        }
+        *location_p = NULL;
     }
 }
 
@@ -220,8 +266,8 @@
 void
 _dbus_condvar_free (DBusCondVar *cond)
 {
-  if (cond && thread_functions.condvar_free)
-    (* thread_functions.condvar_free) (cond);
+  if (cond && thread_init_generation == _dbus_current_generation)
+    _dbus_platform_condvar_free (cond);
 }
 
 /**
@@ -232,12 +278,19 @@
 void
 _dbus_condvar_free_at_location (DBusCondVar **location_p)
 {
-  if (location_p)
-    {
-      if (thread_init_generation != _dbus_current_generation)
-        _dbus_list_remove (&uninitialized_condvar_list, location_p);
+  if (location_p == NULL)
+    return;
 
-      _dbus_condvar_free (*location_p);
+  if (thread_init_generation == _dbus_current_generation)
+    {
+      if (*location_p != NULL)
+        _dbus_platform_condvar_free (*location_p);
+    }
+  else
+    {
+      _dbus_assert (*location_p == NULL || *location_p == _DBUS_DUMMY_CONDVAR);
+
+      _dbus_list_remove (&uninitialized_condvar_list, location_p);
     }
 }
 
@@ -249,10 +302,10 @@
  */
 void
 _dbus_condvar_wait (DBusCondVar *cond,
-                    DBusMutex   *mutex)
+                    DBusCMutex  *mutex)
 {
-  if (cond && mutex && thread_functions.condvar_wait)
-    (* thread_functions.condvar_wait) (cond, mutex);
+  if (cond && mutex && thread_init_generation == _dbus_current_generation)
+    _dbus_platform_condvar_wait (cond, mutex);
 }
 
 /**
@@ -268,11 +321,12 @@
  */
 dbus_bool_t
 _dbus_condvar_wait_timeout (DBusCondVar               *cond,
-                            DBusMutex                 *mutex,
+                            DBusCMutex                *mutex,
                             int                        timeout_milliseconds)
 {
-  if (cond && mutex && thread_functions.condvar_wait)
-    return (* thread_functions.condvar_wait_timeout) (cond, mutex, timeout_milliseconds);
+  if (cond && mutex && thread_init_generation == _dbus_current_generation)
+    return _dbus_platform_condvar_wait_timeout (cond, mutex,
+                                                timeout_milliseconds);
   else
     return TRUE;
 }
@@ -285,32 +339,22 @@
 void
 _dbus_condvar_wake_one (DBusCondVar *cond)
 {
-  if (cond && thread_functions.condvar_wake_one)
-    (* thread_functions.condvar_wake_one) (cond);
-}
-
-/**
- * If there are threads waiting on the condition variable, wake
- * up all of them. 
- * Does nothing if passed a #NULL pointer.
- */
-void
-_dbus_condvar_wake_all (DBusCondVar *cond)
-{
-  if (cond && thread_functions.condvar_wake_all)
-    (* thread_functions.condvar_wake_all) (cond);
+  if (cond && thread_init_generation == _dbus_current_generation)
+    _dbus_platform_condvar_wake_one (cond);
 }
 
 static void
 shutdown_global_locks (void *data)
 {
-  DBusMutex ***locks = data;
+  DBusRMutex ***locks = data;
   int i;
 
   i = 0;
   while (i < _DBUS_N_GLOBAL_LOCKS)
     {
-      _dbus_mutex_free (*(locks[i]));
+      if (*(locks[i]) != NULL)
+        _dbus_platform_rmutex_free (*(locks[i]));
+
       *(locks[i]) = NULL;
       ++i;
     }
@@ -321,7 +365,8 @@
 static void
 shutdown_uninitialized_locks (void *data)
 {
-  _dbus_list_clear (&uninitialized_mutex_list);
+  _dbus_list_clear (&uninitialized_rmutex_list);
+  _dbus_list_clear (&uninitialized_cmutex_list);
   _dbus_list_clear (&uninitialized_condvar_list);
 }
 
@@ -332,19 +377,34 @@
 
   _dbus_assert (thread_init_generation != _dbus_current_generation);
 
-  link = uninitialized_mutex_list;
+  link = uninitialized_rmutex_list;
   while (link != NULL)
     {
-      DBusMutex **mp;
+      DBusRMutex **mp;
 
-      mp = (DBusMutex **)link->data;
-      _dbus_assert (*mp == _DBUS_DUMMY_MUTEX);
+      mp = link->data;
+      _dbus_assert (*mp == _DBUS_DUMMY_RMUTEX);
 
-      *mp = _dbus_mutex_new ();
+      *mp = _dbus_platform_rmutex_new ();
       if (*mp == NULL)
         goto fail_mutex;
 
-      link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
+      link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
+    }
+
+  link = uninitialized_cmutex_list;
+  while (link != NULL)
+    {
+      DBusCMutex **mp;
+
+      mp = link->data;
+      _dbus_assert (*mp == _DBUS_DUMMY_CMUTEX);
+
+      *mp = _dbus_platform_cmutex_new ();
+      if (*mp == NULL)
+        goto fail_mutex;
+
+      link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
     }
 
   link = uninitialized_condvar_list;
@@ -355,14 +415,15 @@
       cp = (DBusCondVar **)link->data;
       _dbus_assert (*cp == _DBUS_DUMMY_CONDVAR);
 
-      *cp = _dbus_condvar_new ();
+      *cp = _dbus_platform_condvar_new ();
       if (*cp == NULL)
         goto fail_condvar;
 
       link = _dbus_list_get_next_link (&uninitialized_condvar_list, link);
     }
 
-  _dbus_list_clear (&uninitialized_mutex_list);
+  _dbus_list_clear (&uninitialized_rmutex_list);
+  _dbus_list_clear (&uninitialized_cmutex_list);
   _dbus_list_clear (&uninitialized_condvar_list);
 
   if (!_dbus_register_shutdown_func (shutdown_uninitialized_locks,
@@ -377,12 +438,10 @@
     {
       DBusCondVar **cp;
 
-      cp = (DBusCondVar **)link->data;
+      cp = link->data;
 
-      if (*cp != _DBUS_DUMMY_CONDVAR)
-        _dbus_condvar_free (*cp);
-      else
-        break;
+      if (*cp != _DBUS_DUMMY_CONDVAR && *cp != NULL)
+        _dbus_platform_condvar_free (*cp);
 
       *cp = _DBUS_DUMMY_CONDVAR;
 
@@ -390,21 +449,34 @@
     }
 
  fail_mutex:
-  link = uninitialized_mutex_list;
+  link = uninitialized_rmutex_list;
   while (link != NULL)
     {
-      DBusMutex **mp;
+      DBusRMutex **mp;
 
-      mp = (DBusMutex **)link->data;
+      mp = link->data;
 
-      if (*mp != _DBUS_DUMMY_MUTEX)
-        _dbus_mutex_free (*mp);
-      else
-        break;
+      if (*mp != _DBUS_DUMMY_RMUTEX && *mp != NULL)
+        _dbus_platform_rmutex_free (*mp);
 
-      *mp = _DBUS_DUMMY_MUTEX;
+      *mp = _DBUS_DUMMY_RMUTEX;
 
-      link = _dbus_list_get_next_link (&uninitialized_mutex_list, link);
+      link = _dbus_list_get_next_link (&uninitialized_rmutex_list, link);
+    }
+
+  link = uninitialized_cmutex_list;
+  while (link != NULL)
+    {
+      DBusCMutex **mp;
+
+      mp = link->data;
+
+      if (*mp != _DBUS_DUMMY_CMUTEX && *mp != NULL)
+        _dbus_platform_cmutex_free (*mp);
+
+      *mp = _DBUS_DUMMY_CMUTEX;
+
+      link = _dbus_list_get_next_link (&uninitialized_cmutex_list, link);
     }
 
   return FALSE;
@@ -414,9 +486,8 @@
 init_locks (void)
 {
   int i;
-  DBusMutex ***dynamic_global_locks;
-  
-  DBusMutex **global_locks[] = {
+  DBusRMutex ***dynamic_global_locks;
+  DBusRMutex **global_locks[] = {
 #define LOCK_ADDR(name) (& _dbus_lock_##name)
     LOCK_ADDR (win_fds),
     LOCK_ADDR (sid_atom_cache),
@@ -443,14 +514,14 @@
 
   i = 0;
   
-  dynamic_global_locks = dbus_new (DBusMutex**, _DBUS_N_GLOBAL_LOCKS);
+  dynamic_global_locks = dbus_new (DBusRMutex**, _DBUS_N_GLOBAL_LOCKS);
   if (dynamic_global_locks == NULL)
     goto failed;
   
   while (i < _DBUS_N_ELEMENTS (global_locks))
     {
-      *global_locks[i] = _dbus_mutex_new ();
-      
+      *global_locks[i] = _dbus_platform_rmutex_new ();
+
       if (*global_locks[i] == NULL)
         goto failed;
 
@@ -473,7 +544,7 @@
                                      
   for (i = i - 1; i >= 0; i--)
     {
-      _dbus_mutex_free (*global_locks[i]);
+      _dbus_platform_rmutex_free (*global_locks[i]);
       *global_locks[i] = NULL;
     }
   return FALSE;
@@ -502,146 +573,19 @@
  */
 
 /**
- * 
- * Initializes threads. If this function is not called, the D-Bus
- * library will not lock any data structures.  If it is called, D-Bus
- * will do locking, at some cost in efficiency. Note that this
- * function must be called BEFORE the second thread is started.
+ * Initializes threads, like dbus_threads_init_default().
+ * This version previously allowed user-specified threading
+ * primitives, but since D-Bus 1.6 it ignores them and behaves
+ * exactly like dbus_threads_init_default().
  *
- * Almost always, you should use dbus_threads_init_default() instead.
- * The raw dbus_threads_init() is only useful if you require a
- * particular thread implementation for some reason.
- *
- * A possible reason to use dbus_threads_init() rather than
- * dbus_threads_init_default() is to insert debugging checks or print
- * statements.
- *
- * dbus_threads_init() may be called more than once.  The first one
- * wins and subsequent calls are ignored. (Unless you use
- * dbus_shutdown() to reset libdbus, which will let you re-init
- * threads.)
- *
- * Either recursive or nonrecursive mutex functions must be specified,
- * but not both. New code should provide only the recursive functions
- * - specifying the nonrecursive ones is deprecated.
- *
- * Because this function effectively sets global state, all code
- * running in a given application must agree on the thread
- * implementation. Most code won't care which thread implementation is
- * used, so there's no problem. However, usually libraries should not
- * call dbus_threads_init() or dbus_threads_init_default(), instead
- * leaving this policy choice to applications.
- *
- * The exception is for application frameworks (GLib, Qt, etc.)  and
- * D-Bus bindings based on application frameworks. These frameworks
- * define a cross-platform thread abstraction and can assume
- * applications using the framework are OK with using that thread
- * abstraction.
- *
- * However, even these app frameworks may find it easier to simply call
- * dbus_threads_init_default(), and there's no reason they shouldn't.
- * 
- * @param functions functions for using threads
+ * @param functions ignored, formerly functions for using threads
  * @returns #TRUE on success, #FALSE if no memory
  */
 dbus_bool_t
 dbus_threads_init (const DBusThreadFunctions *functions)
 {
-  dbus_bool_t mutex_set;
-  dbus_bool_t recursive_mutex_set;
-
-  _dbus_assert (functions != NULL);
-
-  /* these base functions are required. Future additions to
-   * DBusThreadFunctions may be optional.
-   */
-  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK);
-  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK);
-  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK);
-  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK);
-  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK);
-  _dbus_assert (functions->mask & DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK);
-  _dbus_assert (functions->condvar_new != NULL);
-  _dbus_assert (functions->condvar_free != NULL);
-  _dbus_assert (functions->condvar_wait != NULL);
-  _dbus_assert (functions->condvar_wait_timeout != NULL);
-  _dbus_assert (functions->condvar_wake_one != NULL);
-  _dbus_assert (functions->condvar_wake_all != NULL);
-
-  /* Either the mutex function set or recursive mutex set needs 
-   * to be available but not both
-   */
-  mutex_set = (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK) &&  
-              (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK) && 
-              (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK) &&
-              (functions->mask & DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK) &&
-               functions->mutex_new &&
-               functions->mutex_free &&
-               functions->mutex_lock &&
-               functions->mutex_unlock;
-
-  recursive_mutex_set = 
-              (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK) && 
-              (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK) && 
-              (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK) && 
-              (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK) &&
-                functions->recursive_mutex_new &&
-                functions->recursive_mutex_free &&
-                functions->recursive_mutex_lock &&
-                functions->recursive_mutex_unlock;
-
-  if (!(mutex_set || recursive_mutex_set))
-    _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 
-                              "functions sets should be passed into "
-                              "dbus_threads_init. Neither sets were passed.");
-
-  if (mutex_set && recursive_mutex_set)
-    _dbus_assert_not_reached ("Either the nonrecusrive or recursive mutex " 
-                              "functions sets should be passed into "
-                              "dbus_threads_init. Both sets were passed. "
-                              "You most likely just want to set the recursive "
-                              "mutex functions to avoid deadlocks in D-Bus.");
-                          
-  /* Check that all bits in the mask actually are valid mask bits.
-   * ensures people won't write code that breaks when we add
-   * new bits.
-   */
-  _dbus_assert ((functions->mask & ~DBUS_THREAD_FUNCTIONS_ALL_MASK) == 0);
-
-  if (thread_init_generation != _dbus_current_generation)
-    thread_functions.mask = 0; /* allow re-init in new generation */
- 
-  /* Silently allow multiple init
-   * First init wins and D-Bus will always use its threading system 
-   */ 
-  if (thread_functions.mask != 0)
+  if (thread_init_generation == _dbus_current_generation)
     return TRUE;
-  
-  thread_functions.mutex_new = functions->mutex_new;
-  thread_functions.mutex_free = functions->mutex_free;
-  thread_functions.mutex_lock = functions->mutex_lock;
-  thread_functions.mutex_unlock = functions->mutex_unlock;
-  
-  thread_functions.condvar_new = functions->condvar_new;
-  thread_functions.condvar_free = functions->condvar_free;
-  thread_functions.condvar_wait = functions->condvar_wait;
-  thread_functions.condvar_wait_timeout = functions->condvar_wait_timeout;
-  thread_functions.condvar_wake_one = functions->condvar_wake_one;
-  thread_functions.condvar_wake_all = functions->condvar_wake_all;
- 
-  if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK)
-    thread_functions.recursive_mutex_new = functions->recursive_mutex_new;
-  
-  if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK)
-    thread_functions.recursive_mutex_free = functions->recursive_mutex_free;
-  
-  if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK)
-    thread_functions.recursive_mutex_lock = functions->recursive_mutex_lock;
-
-  if (functions->mask & DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK)
-    thread_functions.recursive_mutex_unlock = functions->recursive_mutex_unlock;
-
-  thread_functions.mask = functions->mask;
 
   if (!init_locks ())
     return FALSE;
@@ -656,11 +600,10 @@
 /* Default thread implemenation */
 
 /**
- *
- * Calls dbus_threads_init() with a default set of
- * #DBusThreadFunctions appropriate for the platform.
- *
- * Most applications should use this rather than dbus_threads_init().
+ * Initializes threads. If this function is not called, the D-Bus
+ * library will not lock any data structures.  If it is called, D-Bus
+ * will do locking, at some cost in efficiency. Note that this
+ * function must be called BEFORE the second thread is started.
  *
  * It's safe to call dbus_threads_init_default() as many times as you
  * want, but only the first time will have an effect.
@@ -680,144 +623,11 @@
 /** @} */
 
 #ifdef DBUS_BUILD_TESTS
-/** Fake mutex used for debugging */
-typedef struct DBusFakeMutex DBusFakeMutex;
-/** Fake mutex used for debugging */
-struct DBusFakeMutex
-{
-  dbus_bool_t locked; /**< Mutex is "locked" */
-};	
-
-static DBusMutex *  dbus_fake_mutex_new            (void);
-static void         dbus_fake_mutex_free           (DBusMutex   *mutex);
-static dbus_bool_t  dbus_fake_mutex_lock           (DBusMutex   *mutex);
-static dbus_bool_t  dbus_fake_mutex_unlock         (DBusMutex   *mutex);
-static DBusCondVar* dbus_fake_condvar_new          (void);
-static void         dbus_fake_condvar_free         (DBusCondVar *cond);
-static void         dbus_fake_condvar_wait         (DBusCondVar *cond,
-                                                    DBusMutex   *mutex);
-static dbus_bool_t  dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
-                                                    DBusMutex   *mutex,
-                                                    int          timeout_msec);
-static void         dbus_fake_condvar_wake_one     (DBusCondVar *cond);
-static void         dbus_fake_condvar_wake_all     (DBusCondVar *cond);
-
-
-static const DBusThreadFunctions fake_functions =
-{
-  DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
-  DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
-  DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
-  DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK|
-  DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
-  dbus_fake_mutex_new,
-  dbus_fake_mutex_free,
-  dbus_fake_mutex_lock,
-  dbus_fake_mutex_unlock,
-  dbus_fake_condvar_new,
-  dbus_fake_condvar_free,
-  dbus_fake_condvar_wait,
-  dbus_fake_condvar_wait_timeout,
-  dbus_fake_condvar_wake_one,
-  dbus_fake_condvar_wake_all
-};
-
-static DBusMutex *
-dbus_fake_mutex_new (void)
-{
-  DBusFakeMutex *mutex;
-
-  mutex = dbus_new0 (DBusFakeMutex, 1);
-
-  return (DBusMutex *)mutex;
-}
-
-static void
-dbus_fake_mutex_free (DBusMutex *mutex)
-{
-  DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
-
-  _dbus_assert (!fake->locked);
-  
-  dbus_free (fake);
-}
-
-static dbus_bool_t
-dbus_fake_mutex_lock (DBusMutex *mutex)
-{
-  DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
-
-  _dbus_assert (!fake->locked);
-
-  fake->locked = TRUE;
-  
-  return TRUE;
-}
-
-static dbus_bool_t
-dbus_fake_mutex_unlock (DBusMutex *mutex)
-{
-  DBusFakeMutex *fake = (DBusFakeMutex*) mutex;
-
-  _dbus_assert (fake->locked);
-
-  fake->locked = FALSE;
-  
-  return TRUE;
-}
-
-static DBusCondVar*
-dbus_fake_condvar_new (void)
-{
-  return (DBusCondVar*) _dbus_strdup ("FakeCondvar");
-}
-
-static void
-dbus_fake_condvar_free (DBusCondVar *cond)
-{
-  dbus_free (cond);
-}
-
-static void
-dbus_fake_condvar_wait (DBusCondVar *cond,
-                        DBusMutex   *mutex)
-{
-  
-}
-
-static dbus_bool_t
-dbus_fake_condvar_wait_timeout (DBusCondVar *cond,
-                                DBusMutex   *mutex,
-                                int         timeout_msec)
-{
-  return TRUE;
-}
-
-static void
-dbus_fake_condvar_wake_one (DBusCondVar *cond)
-{
-
-}
-
-static void
-dbus_fake_condvar_wake_all (DBusCondVar *cond)
-{
-
-}
 
 dbus_bool_t
 _dbus_threads_init_debug (void)
 {
-#ifdef DBUS_WIN
   return _dbus_threads_init_platform_specific();
-#else
-  return dbus_threads_init (&fake_functions);
-#endif
 }
 
 #endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-threads.h b/dbus/dbus-threads.h
index ba07ca5..6d28a0b 100644
--- a/dbus/dbus-threads.h
+++ b/dbus/dbus-threads.h
@@ -139,24 +139,15 @@
 
 /**
  * Functions that must be implemented to make the D-Bus library
- * thread-aware. The recursive mutex functions should be specified
- * rather than the old, deprecated nonrecursive ones.
+ * thread-aware.
  *
- * The condition variable functions have to work with recursive
- * mutexes if you provide those, or with nonrecursive mutexes if you
- * provide those.
+ * If you supply both recursive and non-recursive mutexes,
+ * libdbus will use the non-recursive version for condition variables,
+ * and the recursive version in other contexts.
  *
- * If implementing threads using pthreads, be aware that
- * PTHREAD_MUTEX_RECURSIVE is broken in combination with condition
- * variables. libdbus relies on the Java-style behavior that when
- * waiting on a condition, the recursion count is saved and restored,
- * and the mutex is completely unlocked, not just decremented one
- * level of recursion.
- *
- * Thus with pthreads you probably have to roll your own emulated
- * recursive mutexes, you can't use PTHREAD_MUTEX_RECURSIVE. This is
- * what dbus_threads_init_default() does on platforms that use
- * pthreads.
+ * The condition variable functions have to work with nonrecursive
+ * mutexes if you provide those, or with recursive mutexes if you
+ * don't.
  */
 typedef struct
 {
diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c
index 1d4c2bf..544d00a 100644
--- a/dbus/dbus-transport-socket.c
+++ b/dbus/dbus-transport-socket.c
@@ -677,8 +677,8 @@
               _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
               _dbus_string_compact (&socket_transport->encoded_outgoing, 2048);
 
-              _dbus_connection_message_sent (transport->connection,
-                                             message);
+              _dbus_connection_message_sent_unlocked (transport->connection,
+                                                      message);
             }
         }
     }
@@ -1278,8 +1278,10 @@
   return (DBusTransport*) socket_transport;
 
  failed_4:
+  _dbus_watch_invalidate (socket_transport->read_watch);
   _dbus_watch_unref (socket_transport->read_watch);
  failed_3:
+  _dbus_watch_invalidate (socket_transport->write_watch);
   _dbus_watch_unref (socket_transport->write_watch);
  failed_2:
   _dbus_string_free (&socket_transport->encoded_incoming);
@@ -1335,12 +1337,12 @@
     goto error;
 
   if (family != NULL &&
-      (!_dbus_string_append (&address, "family=") ||
+      (!_dbus_string_append (&address, ",family=") ||
        !_dbus_string_append (&address, family)))
     goto error;
 
   if (noncefile != NULL &&
-      (!_dbus_string_append (&address, "noncefile=") ||
+      (!_dbus_string_append (&address, ",noncefile=") ||
        !_dbus_string_append (&address, noncefile)))
     goto error;
 
diff --git a/dbus/dbus-transport-unix.c b/dbus/dbus-transport-unix.c
index 6a713d1..6ba5c0b 100644
--- a/dbus/dbus-transport-unix.c
+++ b/dbus/dbus-transport-unix.c
@@ -22,6 +22,9 @@
  */
 
 #include <config.h>
+
+#include <stdio.h>
+
 #include "dbus-internals.h"
 #include "dbus-connection-internal.h"
 #include "dbus-transport-unix.h"
@@ -29,6 +32,7 @@
 #include "dbus-transport-protected.h"
 #include "dbus-watch.h"
 #include "dbus-sysdeps-unix.h"
+#include "dbus-test.h"
 
 /**
  * @defgroup DBusTransportUnix DBusTransport implementations for UNIX
@@ -108,6 +112,108 @@
 }
 
 /**
+ * Creates a new transport for the given binary and arguments. This
+ * creates a client-side of a transport. The process will be forked
+ * off and executed with stdin/stdout connected to a local AF_UNIX
+ * socket.
+ *
+ * @param path the path to the domain socket.
+ * @param argv Parameters list
+ * @param error address where an error can be returned.
+ * @returns a new transport, or #NULL on failure.
+ */
+static DBusTransport*
+_dbus_transport_new_for_exec (const char     *path,
+                              char *const     argv[],
+                              DBusError      *error)
+{
+  int fd;
+  DBusTransport *transport;
+  DBusString address;
+  unsigned i;
+  char *escaped;
+
+  _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+  if (!_dbus_string_init (&address))
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+      return NULL;
+    }
+
+  fd = -1;
+
+  escaped = dbus_address_escape_value (path);
+  if (!escaped)
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+      goto failed;
+    }
+
+  if (!_dbus_string_append (&address, "unixexec:path=") ||
+      !_dbus_string_append (&address, escaped))
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+      dbus_free (escaped);
+      goto failed;
+    }
+
+  dbus_free (escaped);
+
+  if (argv)
+    {
+      for (i = 0; argv[i]; i++)
+        {
+          dbus_bool_t success;
+
+          escaped = dbus_address_escape_value (argv[i]);
+          if (!escaped)
+            {
+              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+              goto failed;
+            }
+
+          success = _dbus_string_append_printf (&address, ",argv%u=%s", i, escaped);
+          dbus_free (escaped);
+
+          if (!success)
+            {
+              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+              goto failed;
+            }
+        }
+    }
+
+  fd = _dbus_connect_exec (path, argv, error);
+  if (fd < 0)
+    {
+      _DBUS_ASSERT_ERROR_IS_SET (error);
+      goto failed;
+    }
+
+  _dbus_verbose ("Successfully connected to process %s\n",
+                 path);
+
+  transport = _dbus_transport_new_for_socket (fd, NULL, &address);
+  if (transport == NULL)
+    {
+      dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+      goto failed;
+    }
+
+  _dbus_string_free (&address);
+
+  return transport;
+
+ failed:
+  if (fd >= 0)
+    _dbus_close_socket (fd, NULL);
+
+  _dbus_string_free (&address);
+  return NULL;
+}
+
+/**
  * Opens platform specific transport types.
  * 
  * @param entry the address entry to try opening
@@ -168,8 +274,135 @@
         {
           _DBUS_ASSERT_ERROR_IS_CLEAR (error);
           return DBUS_TRANSPORT_OPEN_OK;
-        }      
+        }
     }
+  else if (strcmp (method, "unixexec") == 0)
+    {
+      const char *path;
+      unsigned i;
+      char **argv;
+
+      path = dbus_address_entry_get_value (entry, "path");
+      if (path == NULL)
+        {
+          _dbus_set_bad_address (error, NULL, NULL,
+                                 "No process path specified");
+          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
+        }
+
+      /* First count argv arguments */
+      for (i = 1; ; i++)
+        {
+          char t[4+20+1]; /* "argv" plus space for a formatted base 10 64bit integer, plus NUL */
+
+          snprintf (t, sizeof(t), "argv%u", i);
+
+          if (!dbus_address_entry_get_value (entry, t))
+            break;
+        }
+
+      /* Allocate string array */
+      argv = dbus_new0 (char*, i+1);
+      if (!argv)
+        {
+          dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+
+      /* Fill in string array */
+      for (i = 0; ; i++)
+        {
+          char t[4+20+1];
+          const char *p;
+
+          snprintf (t, sizeof(t), "argv%u", i);
+
+          p = dbus_address_entry_get_value (entry, t);
+          if (!p)
+            {
+              if (i == 0)
+                /* If argv0 isn't specified, fill in the path instead */
+                p = path;
+              else
+                break;
+            }
+
+          argv[i] = _dbus_strdup (p);
+          if (!argv[i])
+            {
+              dbus_free_string_array (argv);
+              dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+              return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+            }
+        }
+
+      *transport_p = _dbus_transport_new_for_exec (path, argv, error);
+      dbus_free_string_array (argv);
+
+      if (*transport_p == NULL)
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+      else
+        {
+          _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+          return DBUS_TRANSPORT_OPEN_OK;
+        }
+    }
+#ifdef DBUS_ENABLE_LAUNCHD
+  else if (strcmp (method, "launchd") == 0)
+    {
+      DBusError tmp_error = DBUS_ERROR_INIT;
+      const char *launchd_env_var = dbus_address_entry_get_value (entry, "env");
+      const char *launchd_socket;
+      DBusString socket_path;
+      dbus_bool_t valid_socket;
+
+      if (!_dbus_string_init (&socket_path))
+        {
+          _DBUS_SET_OOM (error);
+          return FALSE;
+        }
+
+      if (launchd_env_var == NULL)
+        {
+          _dbus_set_bad_address (error, "launchd", "env", NULL);
+          return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
+        }
+
+      valid_socket = _dbus_lookup_launchd_socket (&socket_path, launchd_env_var, error);
+
+      if (dbus_error_is_set(error))
+        {
+          _dbus_string_free(&socket_path);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+
+      if (!valid_socket)
+        {
+          dbus_set_error(&tmp_error, DBUS_ERROR_BAD_ADDRESS,
+                         "launchd's env var %s does not exist", launchd_env_var);
+          dbus_error_free(error);
+          dbus_move_error(&tmp_error, error);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+
+      launchd_socket = _dbus_string_get_const_data(&socket_path);
+      *transport_p = _dbus_transport_new_for_domain_socket (launchd_socket, FALSE, error);
+
+      if (*transport_p == NULL)
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
+        }
+      else
+        {
+          _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+          return DBUS_TRANSPORT_OPEN_OK;
+        }
+    }
+#endif
   else
     {
       _DBUS_ASSERT_ERROR_IS_CLEAR (error);
@@ -178,3 +411,32 @@
 }
 
 /** @} */
+
+#ifdef DBUS_BUILD_TESTS
+
+dbus_bool_t
+_dbus_transport_unix_test (void)
+{
+  DBusConnection *c;
+  DBusError error;
+  dbus_bool_t ret;
+  const char *address;
+
+  dbus_error_init (&error);
+
+  c = dbus_connection_open ("unixexec:argv0=false,argv1=foobar,path=/bin/false", &error);
+  _dbus_assert (c != NULL);
+  _dbus_assert (!dbus_error_is_set (&error));
+
+  address = _dbus_connection_get_address (c);
+  _dbus_assert (address != NULL);
+
+  /* Let's see if the address got parsed, reordered and formatted correctly */
+  ret = strcmp (address, "unixexec:path=/bin/false,argv0=false,argv1=foobar") == 0;
+
+  dbus_connection_unref (c);
+
+  return ret;
+}
+
+#endif
diff --git a/dbus/dbus-transport-win.c b/dbus/dbus-transport-win.c
index faaf1bd..8fc1574 100644
--- a/dbus/dbus-transport-win.c
+++ b/dbus/dbus-transport-win.c
@@ -51,39 +51,8 @@
                                         DBusTransport    **transport_p,
                                         DBusError         *error)
 {
-  const char *method;
-
-  const char *host = dbus_address_entry_get_value (entry, "host");
-  const char *port = dbus_address_entry_get_value (entry, "port");
-  const char *family = dbus_address_entry_get_value (entry, "family");
-  const char *noncefile = dbus_address_entry_get_value (entry, "noncefile");
-
-  method = dbus_address_entry_get_method (entry);
-  _dbus_assert (method != NULL);
-
-  if (strcmp (method, "nonce-tcp") != 0)
-    {
-      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-      return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
-    }
-
-  if (port == NULL)
-    {
-      _dbus_set_bad_address (error, "nonce-tcp", "port", NULL);
-      return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
-    }
-
-  *transport_p = _dbus_transport_new_for_tcp_socket (host, port, family, noncefile, error);
-  if (*transport_p == NULL)
-    {
-      _DBUS_ASSERT_ERROR_IS_SET (error);
-      return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
-    }
-  else
-    {
-      _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-      return DBUS_TRANSPORT_OPEN_OK;
-    }
+  /* currently no Windows-specific transports */
+  return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
 }
 
 /** @} */
diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
index 1c12097..6b58fda 100644
--- a/dbus/dbus-transport.c
+++ b/dbus/dbus-transport.c
@@ -30,8 +30,8 @@
 #include "dbus-auth.h"
 #include "dbus-address.h"
 #include "dbus-credentials.h"
-#include "dbus-message-private.h"
-#include "dbus-marshal-header.h"
+#include "dbus-mainloop.h"
+#include "dbus-message.h"
 #ifdef DBUS_BUILD_TESTS
 #include "dbus-server-debug-pipe.h"
 #endif
@@ -71,12 +71,16 @@
   _dbus_verbose ("Unix FD counter value is now %d\n",
                  (int) _dbus_counter_get_unix_fd_value (counter));
 #endif
-  
+
   /* disable or re-enable the read watch for the transport if
    * required.
    */
   if (transport->vtable->live_messages_changed)
-    (* transport->vtable->live_messages_changed) (transport);
+    {
+      _dbus_connection_lock (transport->connection);
+      (* transport->vtable->live_messages_changed) (transport);
+      _dbus_connection_unlock (transport->connection);
+    }
 
   _dbus_transport_unref (transport);
 }
@@ -249,7 +253,6 @@
   int len, i;
 
   _dbus_assert (address != NULL);
-  _dbus_assert (*address != '\0');
 
   if (!dbus_parse_address (address, &entries, &len, error))
     return NULL;              /* not a valid address */
@@ -273,7 +276,7 @@
  * @returns a new transport, or #NULL on failure.
  */
 static DBusTransport*
-_dbus_transport_new_for_autolaunch (DBusError      *error)
+_dbus_transport_new_for_autolaunch (const char *scope, DBusError *error)
 {
   DBusString address;
   DBusTransport *result = NULL;
@@ -286,7 +289,7 @@
       return NULL;
     }
 
-  if (!_dbus_get_autolaunch_address (&address, error))
+  if (!_dbus_get_autolaunch_address (scope, &address, error))
     {
       _DBUS_ASSERT_ERROR_IS_SET (error);
       goto out;
@@ -315,7 +318,9 @@
 
   if (strcmp (method, "autolaunch") == 0)
     {
-      *transport_p = _dbus_transport_new_for_autolaunch (error);
+      const char *scope = dbus_address_entry_get_value (entry, "scope");
+
+      *transport_p = _dbus_transport_new_for_autolaunch (scope, error);
 
       if (*transport_p == NULL)
         {
@@ -382,25 +387,25 @@
     {
       DBusTransportOpenResult result;
 
-      _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&tmp_error);
+      _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
       result = (* open_funcs[i].func) (entry, &transport, &tmp_error);
 
       switch (result)
         {
         case DBUS_TRANSPORT_OPEN_OK:
-          _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&tmp_error);
+          _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
           goto out;
           break;
         case DBUS_TRANSPORT_OPEN_NOT_HANDLED:
-          _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&tmp_error);
+          _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
           /* keep going through the loop of open funcs */
           break;
         case DBUS_TRANSPORT_OPEN_BAD_ADDRESS:
-          _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&tmp_error);
+          _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
           goto out;
           break;
         case DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT:
-          _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&tmp_error);
+          _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
           goto out;
           break;
         }
@@ -415,13 +420,13 @@
                                NULL, NULL,
                                "Unknown address type (examples of valid types are \"tcp\" and on UNIX \"unix\")");
       
-      _DBUS_ASSERT_ERROR_CONTENT_IS_SET (&tmp_error);
+      _DBUS_ASSERT_ERROR_IS_SET (&tmp_error);
       dbus_move_error(&tmp_error, error);
       dbus_free (expected_guid);
     }
   else
     {
-      _DBUS_ASSERT_ERROR_CONTENT_IS_CLEAR (&tmp_error);
+      _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error);
 
       /* In the case of autostart the initial guid is NULL
        * and the autostart transport recursively calls
@@ -739,17 +744,6 @@
               _dbus_connection_unref_unlocked (transport->connection);
               return FALSE;
             }
-
-          if (transport->expected_guid == NULL)
-            {
-              transport->expected_guid = _dbus_strdup (server_guid);
-
-              if (transport->expected_guid == NULL)
-                {
-                  _dbus_verbose ("No memory to complete auth\n");
-                  return FALSE;
-                }
-            }
         }
 
       /* If we're the server, see if we want to allow this identity to proceed.
@@ -851,6 +845,8 @@
 {
   if (transport->is_server)
     return NULL;
+  else if (transport->authenticated)
+    return _dbus_auth_get_guid_from_server (transport->auth);
   else
     return transport->expected_guid;
 }
@@ -1150,6 +1146,13 @@
         }
       else
         {
+          /* We didn't call the notify function when we added the counter, so
+           * catch up now. Since we have the connection's lock, it's desirable
+           * that we bypass the notify function and call this virtual method
+           * directly. */
+          if (transport->vtable->live_messages_changed)
+            (* transport->vtable->live_messages_changed) (transport);
+
           /* pass ownership of link and message ref to connection */
           _dbus_connection_queue_received_message_link (transport->connection,
                                                         link);
@@ -1488,4 +1491,26 @@
   transport->allow_anonymous = value != FALSE;
 }
 
+#ifdef DBUS_ENABLE_STATS
+void
+_dbus_transport_get_stats (DBusTransport  *transport,
+                           dbus_uint32_t  *queue_bytes,
+                           dbus_uint32_t  *queue_fds,
+                           dbus_uint32_t  *peak_queue_bytes,
+                           dbus_uint32_t  *peak_queue_fds)
+{
+  if (queue_bytes != NULL)
+    *queue_bytes = _dbus_counter_get_size_value (transport->live_messages);
+
+  if (queue_fds != NULL)
+    *queue_fds = _dbus_counter_get_unix_fd_value (transport->live_messages);
+
+  if (peak_queue_bytes != NULL)
+    *peak_queue_bytes = _dbus_counter_get_peak_size_value (transport->live_messages);
+
+  if (peak_queue_fds != NULL)
+    *peak_queue_fds = _dbus_counter_get_peak_unix_fd_value (transport->live_messages);
+}
+#endif /* DBUS_ENABLE_STATS */
+
 /** @} */
diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h
index 0db048a..4b82151 100644
--- a/dbus/dbus-transport.h
+++ b/dbus/dbus-transport.h
@@ -97,6 +97,12 @@
 void               _dbus_transport_set_allow_anonymous    (DBusTransport              *transport,
                                                            dbus_bool_t                 value);
 
+/* if DBUS_ENABLE_STATS */
+void _dbus_transport_get_stats (DBusTransport  *transport,
+                                dbus_uint32_t  *queue_bytes,
+                                dbus_uint32_t  *queue_fds,
+                                dbus_uint32_t  *peak_queue_bytes,
+                                dbus_uint32_t  *peak_queue_fds);
 
 DBUS_END_DECLS
 
diff --git a/dbus/dbus-types.h b/dbus/dbus-types.h
index 54f348f..57fc586 100644
--- a/dbus/dbus-types.h
+++ b/dbus/dbus-types.h
@@ -134,6 +134,45 @@
  * giving a literal such as "325145246765ULL"
  */
 
+/**
+ * An 8-byte struct you could use to access int64 without having
+ * int64 support
+ */
+typedef struct
+{
+  dbus_uint32_t first32;  /**< first 32 bits in the 8 bytes (beware endian issues) */
+  dbus_uint32_t second32; /**< second 32 bits in the 8 bytes (beware endian issues) */
+} DBus8ByteStruct;
+
+/**
+ * A simple value union that lets you access bytes as if they
+ * were various types; useful when dealing with basic types via
+ * void pointers and varargs.
+ *
+ * This union also contains a pointer member (which can be used
+ * to retrieve a string from dbus_message_iter_get_basic(), for
+ * instance), so on future platforms it could conceivably be larger
+ * than 8 bytes.
+ */
+typedef union
+{
+  unsigned char bytes[8]; /**< as 8 individual bytes */
+  dbus_int16_t  i16;   /**< as int16 */
+  dbus_uint16_t u16;   /**< as int16 */
+  dbus_int32_t  i32;   /**< as int32 */
+  dbus_uint32_t u32;   /**< as int32 */
+  dbus_bool_t   bool_val; /**< as boolean */
+#ifdef DBUS_HAVE_INT64
+  dbus_int64_t  i64;   /**< as int64 */
+  dbus_uint64_t u64;   /**< as int64 */
+#endif
+  DBus8ByteStruct eight; /**< as 8-byte struct */
+  double dbl;          /**< as double */
+  unsigned char byt;   /**< as byte */
+  char *str;           /**< as char* (string, object path or signature) */
+  int fd;              /**< as Unix file descriptor */
+} DBusBasicValue;
+
 /** @} */
 
 #endif /* DBUS_TYPES_H */
diff --git a/dbus/dbus-userdb-util.c b/dbus/dbus-userdb-util.c
index c44c014..16bf229 100644
--- a/dbus/dbus-userdb-util.c
+++ b/dbus/dbus-userdb-util.c
@@ -28,6 +28,11 @@
 #include "dbus-protocol.h"
 #include <string.h>
 
+#if HAVE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#include <systemd/sd-login.h>
+#endif
+
 /**
  * @addtogroup DBusInternalsUtils
  * @{
@@ -47,7 +52,28 @@
 
   DBusUserDatabase *db;
   const DBusUserInfo *info;
-  dbus_bool_t result = FALSE; 
+  dbus_bool_t result = FALSE;
+
+#ifdef HAVE_SYSTEMD
+  if (sd_booted () > 0)
+    {
+      int r;
+
+      /* Check whether this user is logged in on at least one physical
+         seat */
+      r = sd_uid_get_seats (uid, 0, NULL);
+      if (r < 0)
+        {
+          dbus_set_error (error, _dbus_error_from_errno (-r),
+                          "Failed to determine seats of user \"" DBUS_UID_FORMAT "\": %s",
+                          uid,
+                          _dbus_strerror (-r));
+          return FALSE;
+        }
+
+      return (r > 0);
+    }
+#endif
 
 #ifdef HAVE_CONSOLE_OWNER_FILE
 
@@ -414,6 +440,7 @@
   dbus_uid_t uid;
   unsigned long *group_ids;
   int n_group_ids, i;
+  DBusError error;
 
   if (!_dbus_username_from_current_process (&username))
     _dbus_assert_not_reached ("didn't get username");
@@ -435,7 +462,17 @@
       printf(" %ld", group_ids[i]);
 
   printf ("\n");
- 
+
+  dbus_error_init (&error);
+  printf ("Is Console user: %i\n",
+          _dbus_is_console_user (uid, &error));
+  printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
+  dbus_error_free (&error);
+  printf ("Is Console user 4711: %i\n",
+          _dbus_is_console_user (4711, &error));
+  printf ("Invocation was OK: %s\n", error.message ? error.message : "yes");
+  dbus_error_free (&error);
+
   dbus_free (group_ids);
 
   return TRUE;
diff --git a/dbus/dbus-valgrind-internal.h b/dbus/dbus-valgrind-internal.h
new file mode 100644
index 0000000..55566ec
--- /dev/null
+++ b/dbus/dbus-valgrind-internal.h
@@ -0,0 +1,67 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-valgrind-internal.h - valgrind glue
+ *
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301  USA
+ *
+ */
+
+#ifndef DBUS_VALGRIND_INTERNAL_H
+#define DBUS_VALGRIND_INTERNAL_H
+
+#include "config.h"
+#include "dbus-internals.h"
+
+#ifdef WITH_VALGRIND
+#   include <memcheck.h>
+#   include <valgrind.h>
+#else
+#   define VALGRIND_CREATE_MEMPOOL(_1, _2, _3) /* nothing */
+#   define VALGRIND_DESTROY_MEMPOOL(_1) /* nothing */
+#   define VALGRIND_MEMPOOL_ALLOC(_1, _2, _3) /* nothing */
+#   define VALGRIND_MEMPOOL_FREE(_1, _2) /* nothing */
+
+/* Recent gcc will warn if you have a statement that's just a macro
+ * expanding to (0), but not if you have an inline stub function that
+ * always returns 0, so let's do the latter. */
+static inline int
+VALGRIND_MAKE_MEM_UNDEFINED (void   *addr,
+                             size_t  len)
+{
+  return 0;
+}
+
+static inline int
+VALGRIND_PRINTF (const char *format,
+                 ...)
+{
+  return 0;
+}
+
+static inline int
+VALGRIND_PRINTF_BACKTRACE (const char *format,
+                           ...)
+{
+  return 0;
+}
+
+#   define RUNNING_ON_VALGRIND 0
+#endif /* WITH_VALGRIND */
+
+#endif /* header guard */
diff --git a/dbus/dbus-watch.c b/dbus/dbus-watch.c
index 5acb202..b9f4ac2 100644
--- a/dbus/dbus-watch.c
+++ b/dbus/dbus-watch.c
@@ -50,6 +50,7 @@
   void *data;                          /**< Application data. */
   DBusFreeFunction free_data_function; /**< Free the application data. */
   unsigned int enabled : 1;            /**< Whether it's enabled. */
+  unsigned int oom_last_time : 1;      /**< Whether it was OOM last time. */
 };
 
 dbus_bool_t
@@ -58,6 +59,19 @@
   return watch->enabled;
 }
 
+dbus_bool_t
+_dbus_watch_get_oom_last_time (DBusWatch *watch)
+{
+  return watch->oom_last_time;
+}
+
+void
+_dbus_watch_set_oom_last_time (DBusWatch   *watch,
+                               dbus_bool_t  oom)
+{
+  watch->oom_last_time = oom;
+}
+
 /**
  * Creates a new DBusWatch. Used to add a file descriptor to be polled
  * by a main loop.
@@ -129,6 +143,9 @@
   watch->refcount -= 1;
   if (watch->refcount == 0)
     {
+      if (watch->fd != -1)
+        _dbus_warn ("this watch should have been invalidated");
+
       dbus_watch_set_data (watch, NULL, NULL); /* call free_data_function */
 
       if (watch->free_handler_data_function)
@@ -496,6 +513,8 @@
 int
 dbus_watch_get_fd (DBusWatch *watch)
 {
+  _dbus_return_val_if_fail (watch != NULL, -1);
+
   return dbus_watch_get_unix_fd(watch);
 }
 
@@ -515,6 +534,8 @@
 int
 dbus_watch_get_unix_fd (DBusWatch *watch)
 {
+  _dbus_return_val_if_fail (watch != NULL, -1);
+
   /* FIXME remove #ifdef and do this on a lower level
    * (watch should have set_socket and set_unix_fd and track
    * which it has, and the transport should provide the
@@ -542,6 +563,8 @@
 int
 dbus_watch_get_socket (DBusWatch *watch)
 {
+  _dbus_return_val_if_fail (watch != NULL, -1);
+
   return watch->fd;
 }
 
@@ -561,6 +584,7 @@
 unsigned int
 dbus_watch_get_flags (DBusWatch *watch)
 {
+  _dbus_return_val_if_fail (watch != NULL, 0);
   _dbus_assert ((watch->flags & VALID_WATCH_FLAGS) == watch->flags);
 
   return watch->flags;
@@ -576,6 +600,8 @@
 void*
 dbus_watch_get_data (DBusWatch *watch)
 {
+  _dbus_return_val_if_fail (watch != NULL, NULL);
+
   return watch->data;
 }
 
@@ -595,6 +621,8 @@
                      void             *data,
                      DBusFreeFunction  free_data_function)
 {
+  _dbus_return_if_fail (watch != NULL);
+
   _dbus_verbose ("Setting watch fd %d data to data = %p function = %p from data = %p function = %p\n",
                  dbus_watch_get_socket (watch),
                  data, free_data_function, watch->data, watch->free_data_function);
@@ -616,7 +644,8 @@
 dbus_bool_t
 dbus_watch_get_enabled (DBusWatch *watch)
 {
-  _dbus_assert (watch != NULL);
+  _dbus_return_val_if_fail (watch != NULL, FALSE);
+
   return watch->enabled;
 }
 
@@ -647,6 +676,8 @@
 dbus_watch_handle (DBusWatch    *watch,
                    unsigned int  flags)
 {
+  _dbus_return_val_if_fail (watch != NULL, FALSE);
+
 #ifndef DBUS_DISABLE_CHECKS
   if (watch->fd < 0 || watch->flags == 0)
     {
diff --git a/dbus/dbus-watch.h b/dbus/dbus-watch.h
index fa953ec..c583214 100644
--- a/dbus/dbus-watch.h
+++ b/dbus/dbus-watch.h
@@ -37,6 +37,8 @@
 
 typedef struct DBusWatchList DBusWatchList;
 
+#define _DBUS_WATCH_NVAL (1<<4)
+
 /** function to run when the watch is handled */
 typedef dbus_bool_t (* DBusWatchHandler) (DBusWatch    *watch,
                                           unsigned int  flags,
@@ -76,6 +78,10 @@
                                                dbus_bool_t              enabled);
 dbus_bool_t    _dbus_watch_get_enabled        (DBusWatch              *watch);
 
+dbus_bool_t    _dbus_watch_get_oom_last_time  (DBusWatch               *watch);
+void           _dbus_watch_set_oom_last_time  (DBusWatch               *watch,
+                                               dbus_bool_t              oom);
+
 /** @} */
 
 DBUS_END_DECLS
diff --git a/dbus/dbus.h b/dbus/dbus.h
index 1f09950..932ceab 100644
--- a/dbus/dbus.h
+++ b/dbus/dbus.h
@@ -39,6 +39,7 @@
 #include <dbus/dbus-server.h>
 #include <dbus/dbus-shared.h>
 #include <dbus/dbus-signature.h>
+#include <dbus/dbus-syntax.h>
 #include <dbus/dbus-threads.h>
 #include <dbus/dbus-types.h>
 
diff --git a/dbus/sd-daemon.c b/dbus/sd-daemon.c
index 8596961..9c23b91 100644
--- a/dbus/sd-daemon.c
+++ b/dbus/sd-daemon.c
@@ -32,7 +32,7 @@
 #include <sys/stat.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-#include <fcntl.h>
+#include <sys/fcntl.h>
 #include <netinet/in.h>
 #include <stdlib.h>
 #include <errno.h>
diff --git a/doc/.gitignore b/doc/.gitignore
index 3430689..1afe014 100644
--- a/doc/.gitignore
+++ b/doc/.gitignore
@@ -2,11 +2,17 @@
 .libs
 Makefile
 Makefile.in
+*.1.html
 *.lo
 *.la
 *.o
 api
+dbus.devhelp
 dbus-specification.html
 dbus-test-plan.html
 dbus-tutorial.html
 dbus-faq.html
+dbus-daemon.1
+dbus-docs
+dbus-docs.tar.gz
+doxygen.stamp
diff --git a/doc/Makefile.am b/doc/Makefile.am
index f76335f..b265987 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,28 +1,74 @@
-EXTRA_DIST= 					\
-	busconfig.dtd				\
-	diagram.png				\
-	diagram.svg				\
-	introspect.dtd				\
-	dbus-faq.xml				\
-	dbus-specification.xml			\
-	dbus-test-plan.xml			\
-	dbus-tutorial.xml			\
-	dcop-howto.txt				\
-	file-boilerplate.c			\
-	introspect.xsl				\
-	system-activation.txt
+apidir = @htmldir@/api
 
-HTML_FILES=					\
+# automake normally assumes that man pages are generated files;
+# these ones aren't, so we need the dist_ prefix to say that they're
+# their own source code
+dist_man1_MANS = \
+	dbus-cleanup-sockets.1 \
+	dbus-launch.1 \
+	dbus-monitor.1 \
+	dbus-send.1 \
+	dbus-uuidgen.1
+
+# on the other hand, this one is generated
+man1_MANS = \
+	dbus-daemon.1
+
+MAN_IN_FILES = dbus-daemon.1.in
+
+MAN_HTML_FILES = \
+	dbus-cleanup-sockets.1.html \
+	dbus-daemon.1.html \
+	dbus-launch.1.html \
+	dbus-monitor.1.html \
+	dbus-send.1.html \
+	dbus-uuidgen.1.html
+
+DTDS = \
+	busconfig.dtd \
+	introspect.dtd
+
+dist_doc_DATA = system-activation.txt
+
+# uploaded and distributed, but not installed
+STATIC_DOCS = \
+	dbus-faq.xml \
+	dbus-specification.xml \
+	dbus-test-plan.xml \
+	dbus-tutorial.xml \
+	dcop-howto.txt \
+	introspect.xsl \
+	$(DTDS)
+
+EXTRA_DIST = \
+	file-boilerplate.c \
+	doxygen_to_devhelp.xsl \
+	$(STATIC_DOCS) \
+	$(MAN_IN_FILES)
+
+html_DATA =
+
+dist_html_DATA =
+
+# diagram.png/diagram.svg aren't really HTML, but must go in the same
+# directory as the HTML to avoid broken links
+STATIC_HTML = \
+	diagram.png \
+	diagram.svg \
+	$(NULL)
+
+dist_html_DATA += $(STATIC_HTML)
+
+# we distribute these in the tarball so users don't necessarily need xmlto
+dist_html_DATA += $(XMLTO_OUTPUT)
+
+XMLTO_OUTPUT=					\
 	dbus-faq.html				\
 	dbus-specification.html			\
 	dbus-test-plan.html			\
 	dbus-tutorial.html
 
 if DBUS_XML_DOCS_ENABLED
-all-local: $(HTML_FILES)
-
-EXTRA_DIST += $(HTML_FILES)
-
 dbus-specification.html: dbus-specification.xml
 	$(XMLTO) html-nochunks $<
 
@@ -34,8 +80,97 @@
 
 dbus-faq.html: dbus-faq.xml
 	$(XMLTO) html-nochunks $<
-
 endif
 
+if DBUS_DOXYGEN_DOCS_ENABLED
+all-local:: doxygen.stamp
+
+doxygen.stamp: $(wildcard $(top_srcdir)/dbus/*.[ch])
+	$(AM_V_GEN)cd $(top_builddir) && doxygen Doxyfile
+	@touch $@
+
+if DBUS_HAVE_XSLTPROC
+html_DATA += dbus.devhelp
+
+dbus.devhelp: $(srcdir)/doxygen_to_devhelp.xsl doxygen.stamp
+	$(XSLTPROC) -o $@ $< api/xml/index.xml
+endif
+
+# this assumes CREATE_SUBDIRS isn't set to YES in Doxyfile
+# (which it isn't currently)
+install-data-local:: doxygen.stamp
+	$(MKDIR_P) $(DESTDIR)$(apidir)
+	$(INSTALL_DATA) api/html/* $(DESTDIR)$(apidir)
+
+uninstall-local::
+	rm -f $(DESTDIR)$(apidir)/*.html
+	rm -f $(DESTDIR)$(apidir)/*.png
+	rm -f $(DESTDIR)$(apidir)/*.css
+	rm -f $(DESTDIR)$(apidir)/*.js
+	rm -f $(DESTDIR)$(htmldir)/*.html
+	rm -f $(DESTDIR)$(docdir)/*.txt
+	rm -f $(DESTDIR)$(htmldir)/*.png
+	rm -f $(DESTDIR)$(htmldir)/*.svg
+	rmdir --ignore-fail-on-non-empty $(DESTDIR)$(apidir) || \
+		rmdir $(DESTDIR)$(apidir)
+endif
+
+if DBUS_HAVE_MAN2HTML
+html_DATA += $(MAN_HTML_FILES)
+
+%.1.html: %.1
+	$(AM_V_GEN)( $(MAN2HTML) < $< > $@.tmp && mv $@.tmp $@ )
+endif
+
+if DBUS_CAN_UPLOAD_DOCS
+BONUS_FILES = \
+	$(top_srcdir)/README \
+	$(top_srcdir)/HACKING \
+	$(top_srcdir)/AUTHORS \
+	$(top_srcdir)/NEWS \
+	$(top_srcdir)/COPYING \
+	$(top_srcdir)/ChangeLog
+
+dbus-docs: $(STATIC_DOCS) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp
+	$(AM_V_at)rm -rf $@ $@.tmp
+	$(AM_V_GEN)$(MKDIR_P) $@.tmp/api
+	$(AM_V_at)cd $(srcdir) && cp $(STATIC_DOCS) @abs_builddir@/$@.tmp
+	$(AM_V_at)cd $(srcdir) && cp $(dist_doc_DATA) @abs_builddir@/$@.tmp
+	$(AM_V_at)cd $(srcdir) && cp $(STATIC_HTML) @abs_builddir@/$@.tmp
+	$(AM_V_at)cp $(XMLTO_OUTPUT) @abs_builddir@/$@.tmp
+	$(AM_V_at)cp $(MAN_HTML_FILES) @abs_builddir@/$@.tmp
+	$(AM_V_at)cp $(BONUS_FILES) @abs_builddir@/$@.tmp
+	$(AM_V_at)cp -r api/html @abs_builddir@/$@.tmp/api
+	$(AM_V_at)mv $@.tmp $@
+
+dbus-docs.tar.gz: dbus-docs
+	$(AM_V_GEN)tar czf $@ $<
+
+DOC_SERVER = dbus.freedesktop.org
+DOC_WWW_DIR = /srv/dbus.freedesktop.org/www
+
+SPECIFICATION_SERVER = specifications.freedesktop.org
+SPECIFICATION_PATH = /srv/specifications.freedesktop.org/www/dbus/1.0
+
+maintainer-upload-docs: dbus-docs.tar.gz dbus-docs
+	scp dbus-docs.tar.gz $(DOC_SERVER):$(DOC_WWW_DIR)/
+	rsync -rpvzP --chmod=Dg+s,ug+rwX,o=rX \
+		dbus-docs/ $(DOC_SERVER):$(DOC_WWW_DIR)/doc/
+	cd $(srcdir) && scp -p $(DTDS) $(SPECIFICATION_SERVER):$(SPECIFICATION_PATH)/
+else
+maintainer-upload-docs:
+	@echo "Can't upload documentation! Re-run configure with"
+	@echo "  --enable-doxygen-docs --enable-xml-docs"
+	@echo "and ensure that man2html is installed."
+	@false
+endif
+
+clean-local:
+	rm -f $(html_DATA)
+	rm -rf api
+	rm -rf dbus-docs dbus-docs.tmp
+	rm -f *.1.html
+	rm -f doxygen.stamp
+
 maintainer-clean-local:
-	rm -f $(HTML_FILES)
+	rm -f $(XMLTO_OUTPUT)
diff --git a/doc/dbus-cleanup-sockets.1 b/doc/dbus-cleanup-sockets.1
new file mode 100644
index 0000000..a062d49
--- /dev/null
+++ b/doc/dbus-cleanup-sockets.1
@@ -0,0 +1,43 @@
+.\" 
+.\" dbus\-cleanup\-sockets manual page.
+.\" Copyright (C) 2003 Red Hat, Inc.
+.\"
+.TH dbus\-cleanup\-sockets 1
+.SH NAME
+dbus\-cleanup\-sockets \- clean up leftover sockets in a directory
+.SH SYNOPSIS
+.PP
+.B dbus\-cleanup\-sockets [DIRECTORY]
+
+.SH DESCRIPTION
+
+The \fIdbus\-cleanup\-sockets\fP command cleans up unused D\-Bus
+connection sockets. See http://www.freedesktop.org/software/dbus/ for
+more information about the big picture.
+
+.PP
+If given no arguments, \fIdbus\-cleanup\-sockets\fP cleans up sockets 
+in the standard default socket directory for the
+per\-user\-login\-session message bus; this is usually /tmp. 
+Optionally, you can pass a different directory on the command line.
+
+.PP
+On Linux, this program is essentially useless, because D\-Bus defaults
+to using "abstract sockets" that exist only in memory and don't have a
+corresponding file in /tmp. 
+
+.PP
+On most other flavors of UNIX, it's possible for the socket files to
+leak when programs using D\-Bus exit abnormally or without closing
+their D\-Bus connections. Thus, it might be interesting to run
+dbus\-cleanup\-sockets in a cron job to mop up any leaked sockets.
+Or you can just ignore the leaked sockets, they aren't really hurting
+anything, other than cluttering the output of "ls /tmp"
+
+.SH AUTHOR
+dbus\-cleanup\-sockets was adapted by Havoc Pennington from
+linc\-cleanup\-sockets written by Michael Meeks.
+
+.SH BUGS
+Please send bug reports to the D\-Bus mailing list or bug tracker,
+see http://www.freedesktop.org/software/dbus/
diff --git a/bus/dbus-daemon.1.in b/doc/dbus-daemon.1.in
similarity index 81%
rename from bus/dbus-daemon.1.in
rename to doc/dbus-daemon.1.in
index a54f863..53856e9 100644
--- a/bus/dbus-daemon.1.in
+++ b/doc/dbus-daemon.1.in
@@ -1,37 +1,37 @@
 .\"
-.\" dbus-daemon manual page.
+.\" dbus\-daemon manual page.
 .\" Copyright (C) 2003,2008 Red Hat, Inc.
 .\"
-.TH dbus-daemon 1
+.TH dbus\-daemon 1
 .SH NAME
-dbus-daemon \- Message bus daemon
+dbus\-daemon \- Message bus daemon
 .SH SYNOPSIS
 .PP
-.B dbus-daemon
-dbus-daemon [\-\-version] [\-\-session] [\-\-system] [\-\-config-file=FILE]
-[\-\-print-address[=DESCRIPTOR]] [\-\-print-pid[=DESCRIPTOR]] [\-\-fork]
+.B dbus\-daemon
+dbus\-daemon [\-\-version] [\-\-session] [\-\-system] [\-\-config\-file=FILE]
+[\-\-print\-address[=DESCRIPTOR]] [\-\-print\-pid[=DESCRIPTOR]] [\-\-fork]
 
 .SH DESCRIPTION
-\fIdbus-daemon\fP is the D-Bus message bus daemon. See
+\fIdbus\-daemon\fP is the D\-Bus message bus daemon. See
 http://www.freedesktop.org/software/dbus/ for more information about
-the big picture. D-Bus is first a library that provides one-to-one
-communication between any two applications; \fIdbus-daemon\fP is an
+the big picture. D\-Bus is first a library that provides one\-to\-one
+communication between any two applications; \fIdbus\-daemon\fP is an
 application that uses this library to implement a message bus
 daemon. Multiple programs connect to the message bus daemon and can
 exchange messages with one another.
 .PP
 There are two standard message bus instances: the systemwide message bus
 (installed on many systems as the "messagebus" init service) and the
-per-user-login-session message bus (started each time a user logs in).
-\fIdbus-daemon\fP is used for both of these instances, but with
+per\-user\-login\-session message bus (started each time a user logs in).
+\fIdbus\-daemon\fP is used for both of these instances, but with
 a different configuration file.
 .PP
 The \-\-session option is equivalent to
-"\-\-config-file=@EXPANDED_SYSCONFDIR@/dbus-1/session.conf" and the \-\-system
+"\-\-config\-file=@EXPANDED_SYSCONFDIR@/dbus\-1/session.conf" and the \-\-system
 option is equivalent to
-"\-\-config-file=@EXPANDED_SYSCONFDIR@/dbus-1/system.conf". By creating
-additional configuration files and using the \-\-config-file option,
-additional special-purpose message bus daemons could be created.
+"\-\-config\-file=@EXPANDED_SYSCONFDIR@/dbus\-1/system.conf". By creating
+additional configuration files and using the \-\-config\-file option,
+additional special\-purpose message bus daemons could be created.
 .PP
 The systemwide daemon is normally launched by an init script,
 standardly called simply "messagebus".
@@ -39,11 +39,11 @@
 The systemwide daemon is largely used for broadcasting system events,
 such as changes to the printer queue, or adding/removing devices.
 .PP
-The per-session daemon is used for various interprocess communication
+The per\-session daemon is used for various interprocess communication
 among desktop applications (however, it is not tied to X or the GUI
 in any way).
 .PP
-SIGHUP will cause the D-Bus daemon to PARTIALLY reload its
+SIGHUP will cause the D\-Bus daemon to PARTIALLY reload its
 configuration file and to flush its user/group information caches. Some
 configuration changes would require kicking all apps off the bus; so they will
 only take effect if you restart the daemon. Policy changes should take effect
@@ -52,55 +52,59 @@
 .SH OPTIONS
 The following options are supported:
 .TP
-.I "--config-file=FILE"
+.I "\-\-config\-file=FILE"
 Use the given configuration file.
 .TP
-.I "--fork"
+.I "\-\-fork"
 Force the message bus to fork and become a daemon, even if
 the configuration file does not specify that it should.
 In most contexts the configuration file already gets this
 right, though.
-.I "--nofork"
+.I "\-\-nofork"
 Force the message bus not to fork and become a daemon, even if
 the configuration file specifies that it should.
 .TP
-.I "--print-address[=DESCRIPTOR]"
+.I "\-\-print\-address[=DESCRIPTOR]"
 Print the address of the message bus to standard output, or
 to the given file descriptor. This is used by programs that
 launch the message bus.
 .TP
-.I "--print-pid[=DESCRIPTOR]"
+.I "\-\-print\-pid[=DESCRIPTOR]"
 Print the process ID of the message bus to standard output, or
 to the given file descriptor. This is used by programs that
 launch the message bus.
 .TP
-.I "--session"
-Use the standard configuration file for the per-login-session message
+.I "\-\-session"
+Use the standard configuration file for the per\-login\-session message
 bus.
 .TP
-.I "--system"
+.I "\-\-system"
 Use the standard configuration file for the systemwide message bus.
 .TP
-.I "--version"
+.I "\-\-version"
 Print the version of the daemon.
 .TP
-.I "--introspect"
-Print the introspection information for all D-Bus internal interfaces.
+.I "\-\-introspect"
+Print the introspection information for all D\-Bus internal interfaces.
 .TP
-.I "--address[=ADDRESS]"
+.I "\-\-address[=ADDRESS]"
 Set the address to listen on. This option overrides the address
 configured in the configuration file.
 .TP
-.I "--systemd-activation"
-Enable systemd-style service activation. Only useful in conjunction
+.I "\-\-systemd\-activation"
+Enable systemd\-style service activation. Only useful in conjunction
 with the systemd system and session manager on Linux.
+.TP
+.I "\-\-nopidfile"
+Don't write a PID file even if one is configured in the configuration
+files.
 
 .SH CONFIGURATION FILE
 
 A message bus daemon has a configuration file that specializes it
 for a particular application. For example, one configuration
 file might set up the message bus to be a systemwide message bus,
-while another might set it up to be a per-user-login-session bus.
+while another might set it up to be a per\-user\-login\-session bus.
 .PP
 The configuration file also establishes resource limits, security
 parameters, and so forth.
@@ -109,10 +113,10 @@
 specification and its backward compatibility is not guaranteed; this
 document is documentation, not specification.
 .PP
-The standard systemwide and per-session message bus setups are
-configured in the files "@EXPANDED_SYSCONFDIR@/dbus-1/system.conf" and
-"@EXPANDED_SYSCONFDIR@/dbus-1/session.conf".  These files normally
-<include> a system-local.conf or session-local.conf; you can put local
+The standard systemwide and per\-session message bus setups are
+configured in the files "@EXPANDED_SYSCONFDIR@/dbus\-1/system.conf" and
+"@EXPANDED_SYSCONFDIR@/dbus\-1/session.conf".  These files normally
+<include> a system\-local.conf or session\-local.conf; you can put local
 overrides in those files to avoid modifying the primary configuration
 files.
 
@@ -121,7 +125,7 @@
 doctype declaration:
 .nf
 
-   <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+   <!DOCTYPE busconfig PUBLIC "\-//freedesktop//DTD D\-Bus Bus Configuration 1.0//EN"
     "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 
 .fi
@@ -139,9 +143,9 @@
 .I "<type>"
 
 .PP
-The well-known type of the message bus. Currently known values are
+The well\-known type of the message bus. Currently known values are
 "system" and "session"; if other values are set, they should be
-either added to the D-Bus specification, or namespaced.  The last
+either added to the D\-Bus specification, or namespaced.  The last
 <type> element "wins" (previous values are ignored). This element
 only controls which message bus specific environment variables are
 set in activated clients.  Most of the policy that distinguishes a
@@ -149,7 +153,7 @@
 in the configuration file.
 
 .PP
-If the well-known type of the message bus is "session", then the
+If the well\-known type of the message bus is "session", then the
 DBUS_STARTER_BUS_TYPE environment variable will be set to "session"
 and the DBUS_SESSION_BUS_ADDRESS environment variable will be set
 to the address of the session bus.  Likewise, if the type of the
@@ -187,7 +191,7 @@
 This is intended to allow extension of the system bus by particular
 packages. For example, if CUPS wants to be able to send out
 notification of printer queue changes, it could install a file to
-@EXPANDED_SYSCONFDIR@/dbus-1/system.d that allowed all apps to receive
+@EXPANDED_SYSCONFDIR@/dbus\-1/system.d that allowed all apps to receive
 this message and allowed the printer daemon user to send it.
 
 .TP
@@ -229,7 +233,7 @@
 
 .PP
 Add an address that the bus should listen on. The
-address is in the standard D-Bus format that contains
+address is in the standard D\-Bus format that contains
 a transport name plus possible parameters/options.
 
 .PP
@@ -258,7 +262,7 @@
 A special case is using a port number of zero (or omitting the port),
 which means to choose an available port selected by the operating
 system. The port number chosen can be obtained with the
---print-address command line parameter and will be present in other
+\-\-print\-address command line parameter and will be present in other
 cases where the server reports its own address, such as when
 DBUS_SESSION_BUS_ADDRESS is set.
 
@@ -302,7 +306,7 @@
 
 .PP
 Service files tell the bus how to automatically start a program.
-They are primarily used with the per-user-session bus,
+They are primarily used with the per\-user\-session bus,
 not the systemwide bus.
 
 .TP
@@ -311,33 +315,33 @@
 .PP
 <standard_session_servicedirs/> is equivalent to specifying a series
 of <servicedir/> elements for each of the data directories in the "XDG
-Base Directory Specification" with the subdirectory "dbus-1/services",
-so for example "/usr/share/dbus-1/services" would be among the
+Base Directory Specification" with the subdirectory "dbus\-1/services",
+so for example "/usr/share/dbus\-1/services" would be among the
 directories searched.
 
 .PP
 The "XDG Base Directory Specification" can be found at
-http://freedesktop.org/wiki/Standards/basedir-spec if it hasn't moved,
+http://freedesktop.org/wiki/Standards/basedir\-spec if it hasn't moved,
 otherwise try your favorite search engine.
 
 .PP
 The <standard_session_servicedirs/> option is only relevant to the
-per-user-session bus daemon defined in
-@EXPANDED_SYSCONFDIR@/dbus-1/session.conf. Putting it in any other
+per\-user\-session bus daemon defined in
+@EXPANDED_SYSCONFDIR@/dbus\-1/session.conf. Putting it in any other
 configuration file would probably be nonsense.
 
 .TP
 .I "<standard_system_servicedirs/>"
 
 .PP
-<standard_system_servicedirs/> specifies the standard system-wide
+<standard_system_servicedirs/> specifies the standard system\-wide
 activation directories that should be searched for service files.
-This option defaults to @EXPANDED_DATADIR@/dbus-1/system-services.
+This option defaults to @EXPANDED_DATADIR@/dbus\-1/system\-services.
 
 .PP
 The <standard_system_servicedirs/> option is only relevant to the
-per-system bus daemon defined in
-@EXPANDED_SYSCONFDIR@/dbus-1/system.conf. Putting it in any other
+per\-system bus daemon defined in
+@EXPANDED_SYSCONFDIR@/dbus\-1/system.conf. Putting it in any other
 configuration file would probably be nonsense.
 
 .TP
@@ -346,11 +350,11 @@
 .PP
 <servicehelper/> specifies the setuid helper that is used to launch
 system daemons with an alternate user. Typically this should be
-the dbus-daemon-launch-helper executable in located in libexec.
+the dbus\-daemon\-launch\-helper executable in located in libexec.
 
 .PP
-The <servicehelper/> option is only relevant to the per-system bus daemon
-defined in @EXPANDED_SYSCONFDIR@/dbus-1/system.conf. Putting it in any other
+The <servicehelper/> option is only relevant to the per\-system bus daemon
+defined in @EXPANDED_SYSCONFDIR@/dbus\-1/system.conf. Putting it in any other
 configuration file would probably be nonsense.
 
 .TP
@@ -396,7 +400,7 @@
                                         connection
       "max_replies_per_connection" : max number of pending method
                                      replies per connection
-                                     (number of calls-in-progress)
+                                     (number of calls\-in\-progress)
       "reply_timeout"              : milliseconds (thousandths)
                                      until a method call times out
 .fi
@@ -408,7 +412,7 @@
 
 .PP
 max_completed_connections divided by max_connections_per_user is the
-number of users that can work together to denial-of-service all other users by using
+number of users that can work together to denial\-of\-service all other users by using
 up all connections on the systemwide bus.
 
 .PP
@@ -426,7 +430,7 @@
 and prevent unexpected traffic.
 
 .PP
-Currently, the system bus has a default-deny policy for sending method calls
+Currently, the system bus has a default\-deny policy for sending method calls
 and owning bus names.  Everything else, in particular reply messages, receive
 checks, and signals has a default allow policy.
 
@@ -449,14 +453,14 @@
 .PP
 Policies are applied to a connection as follows:
 .nf
-   - all context="default" policies are applied
-   - all group="connection's user's group" policies are applied
+   \- all context="default" policies are applied
+   \- all group="connection's user's group" policies are applied
      in undefined order
-   - all user="connection's auth user" policies are applied
+   \- all user="connection's auth user" policies are applied
      in undefined order
-   - all at_console="true" policies are applied
-   - all at_console="false" policies are applied
-   - all context="mandatory" policies are applied
+   \- all at_console="true" policies are applied
+   \- all at_console="false" policies are applied
+   \- all context="mandatory" policies are applied
 .fi
 
 .PP
@@ -497,6 +501,7 @@
    eavesdrop="true" | "false"
 
    own="name"
+   own_prefix="name"
    user="username"
    group="groupname"
 .fi
@@ -522,7 +527,7 @@
 owns services A, B, C, and sending to A is denied, sending to B or C
 will not work either.
 .PP
-The other send_* and receive_* attributes are purely textual/by-value
+The other send_* and receive_* attributes are purely textual/by\-value
 matches against the given field in the message header.
 .PP
 "Eavesdropping" occurs when an application receives a message that
@@ -569,6 +574,15 @@
 implement and maybe encourage sloppy security anyway.
 
 .PP
+<allow own_prefix="a.b"/> allows you to own the name "a.b" or any
+name whose first dot-separated elements are "a.b": in particular,
+you can own "a.b.c" or "a.b.c.d", but not "a.bc" or "a.c".
+This is useful when services like Telepathy and ReserveDevice
+define a meaning for subtrees of well-known names, such as
+org.freedesktop.Telepathy.ConnectionManager.(anything)
+and org.freedesktop.ReserveDevice1.(anything).
+
+.PP
 It does not make sense to deny a user or group inside a <policy>
 for a user or group; user/group denials can only be inside
 context="default" or context="mandatory" policies.
@@ -590,7 +604,7 @@
 Be careful with send_interface/receive_interface, because the
 interface field in messages is optional.  In particular, do NOT
 specify <deny send_interface="org.foo.Bar"/>!  This will cause
-no-interface messages to be blocked for all services, which is
+no\-interface messages to be blocked for all services, which is
 almost certainly not what you intended.  Always use rules of
 the form: <deny send_interface="org.foo.Bar" send_destination="org.foo.Service"/>
 
@@ -614,7 +628,7 @@
 .PP
 This means that if a connection asks to own the name
 "org.freedesktop.Foobar" then the source context will be the context
-of the connection and the target context will be "foo_t" - see the
+of the connection and the target context will be "foo_t" \- see the
 short discussion of SELinux below.
 
 .PP
@@ -668,7 +682,7 @@
 that class.
 
 .PP
-D-Bus performs SELinux security checks in two places.
+D\-Bus performs SELinux security checks in two places.
 
 .PP
 First, any time a message is routed from one connection to another
@@ -710,8 +724,8 @@
 through, it won't work. For the session bus, this is not a concern.
 .PP
 The simplest way to figure out what's happening on the bus is to run
-the \fIdbus-monitor\fP program, which comes with the D-Bus
-package. You can also send test messages with \fIdbus-send\fP. These
+the \fIdbus\-monitor\fP program, which comes with the D\-Bus
+package. You can also send test messages with \fIdbus\-send\fP. These
 programs have their own man pages.
 .PP
 If you want to know what the daemon itself is doing, you might consider
@@ -722,20 +736,20 @@
 To run a separate test copy of the daemon, for example you might open a terminal
 and type:
 .nf
-  DBUS_VERBOSE=1 dbus-daemon --session --print-address
+  DBUS_VERBOSE=1 dbus\-daemon \-\-session \-\-print\-address
 .fi
 .PP
 The test daemon address will be printed when the daemon starts. You will need
-to copy-and-paste this address and use it as the value of the
+to copy\-and\-paste this address and use it as the value of the
 DBUS_SESSION_BUS_ADDRESS environment variable when you launch the applications
 you want to test. This will cause those applications to connect to your
 test bus instead of the DBUS_SESSION_BUS_ADDRESS of your real session bus.
 .PP
-DBUS_VERBOSE=1 will have NO EFFECT unless your copy of D-Bus
+DBUS_VERBOSE=1 will have NO EFFECT unless your copy of D\-Bus
 was compiled with verbose mode enabled. This is not recommended in
 production builds due to performance impact. You may need to rebuild
-D-Bus if your copy was not built with debugging in mind. (DBUS_VERBOSE
-also affects the D-Bus library and thus applications using D-Bus; it may
+D\-Bus if your copy was not built with debugging in mind. (DBUS_VERBOSE
+also affects the D\-Bus library and thus applications using D\-Bus; it may
 be useful to see verbose output on both the client side and from the daemon.)
 .PP
 If you want to get fancy, you can create a custom bus
@@ -748,5 +762,5 @@
 See http://www.freedesktop.org/software/dbus/doc/AUTHORS
 
 .SH BUGS
-Please send bug reports to the D-Bus mailing list or bug tracker,
+Please send bug reports to the D\-Bus mailing list or bug tracker,
 see http://www.freedesktop.org/software/dbus/
diff --git a/doc/dbus-launch.1 b/doc/dbus-launch.1
new file mode 100644
index 0000000..e22a3be
--- /dev/null
+++ b/doc/dbus-launch.1
@@ -0,0 +1,211 @@
+.\" 
+.\" dbus\-launch manual page.
+.\" Copyright (C) 2003 Red Hat, Inc.
+.\"
+.TH dbus\-launch 1
+.SH NAME
+dbus\-launch \- Utility to start a message bus from a shell script
+.SH SYNOPSIS
+.PP
+.B dbus\-launch [\-\-version] [\-\-sh\-syntax] [\-\-csh\-syntax] [\-\-auto\-syntax] [\-\-exit\-with\-session] [\-\-autolaunch=MACHINEID] [\-\-config\-file=FILENAME] [PROGRAM] [ARGS...]
+
+.SH DESCRIPTION
+
+The \fIdbus\-launch\fP command is used to start a session bus 
+instance of \fIdbus\-daemon\fP from a shell script.
+It would normally be called from a user's login
+scripts. Unlike the daemon itself, \fIdbus\-launch\fP exits, so
+backticks or the $() construct can be used to read information from
+\fIdbus\-launch\fP.
+
+With no arguments, \fIdbus\-launch\fP will launch a session bus
+instance and print the address and PID of that instance to standard
+output.
+
+You may specify a program to be run; in this case, \fIdbus\-launch\fP
+will launch a session bus instance, set the appropriate environment
+variables so the specified program can find the bus, and then execute the
+specified program, with the specified arguments.  See below for
+examples.
+
+If you launch a program, \fIdbus\-launch\fP will not print the
+information about the new bus to standard output.
+
+When \fIdbus\-launch\fP prints bus information to standard output, by
+default it is in a simple key\-value pairs format. However, you may 
+request several alternate syntaxes using the \-\-sh\-syntax, \-\-csh\-syntax,
+\-\-binary\-syntax, or
+\-\-auto\-syntax options. Several of these cause \fIdbus\-launch\fP to emit shell code
+to set up the environment.
+
+With the \-\-auto\-syntax option, \fIdbus\-launch\fP looks at the value
+of the SHELL environment variable to determine which shell syntax
+should be used.  If SHELL ends in "csh", then csh\-compatible code is
+emitted; otherwise Bourne shell code is emitted.  Instead of passing
+\-\-auto\-syntax, you may explicitly specify a particular one by using
+\-\-sh\-syntax for Bourne syntax, or \-\-csh\-syntax for csh syntax.
+In scripts, it's more robust to avoid \-\-auto\-syntax and you hopefully
+know which shell your script is written in.
+
+.PP
+See http://www.freedesktop.org/software/dbus/ for more information
+about D\-Bus. See also the man page for \fIdbus\-daemon\fP.
+
+.SH EXAMPLES
+
+Distributions running
+.B dbus\-launch
+as part of a standard X session should run
+.B "dbus\-launch \-\-exit\-with\-session"
+after the X server has started and become available, as a wrapper around
+the "main" X client (typically a session manager or window manager), as in
+these examples:
+
+.RS
+.B "dbus\-launch \-\-exit\-with\-session gnome\-session"
+
+.B "dbus\-launch \-\-exit\-with\-session openbox"
+
+.B "dbus\-launch \-\-exit\-with\-session ~/.xsession"
+.RE
+
+If your distribution does not do this, you can achieve similar results
+by running your session or window manager in the same way in a script
+run by your X session, such as
+.BR ~/.xsession ,
+.B ~/.xinitrc
+or
+.BR ~/.Xclients .
+
+To start a D-Bus session within a text-mode session, you can run
+dbus-launch in the background. For instance, in a sh-compatible shell:
+
+.nf
+  ## test for an existing bus daemon, just to be safe
+  if test \-z "$DBUS_SESSION_BUS_ADDRESS" ; then
+      ## if not found, launch a new one
+      eval `dbus\-launch \-\-sh\-syntax`
+      echo "D\-Bus per\-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
+  fi
+.fi
+Note that in this case, dbus-launch will exit, and dbus-daemon will not be
+terminated automatically on logout.
+
+.SH AUTOMATIC LAUNCHING
+
+.PP
+If DBUS_SESSION_BUS_ADDRESS is not set for a process that tries to use
+D\-Bus, by default the process will attempt to invoke dbus\-launch with
+the \-\-autolaunch option to start up a new session bus or find the 
+existing bus address on the X display or in a file in
+~/.dbus/session\-bus/
+
+.PP
+Whenever an autolaunch occurs, the application that had to
+start a new bus will be in its own little world; it can effectively
+end up starting a whole new session if it tries to use a lot of 
+bus services. This can be suboptimal or even totally broken, depending
+on the app and what it tries to do.
+
+.PP
+There are two common reasons for autolaunch. One is ssh to a remote
+machine. The ideal fix for that would be forwarding of
+DBUS_SESSION_BUS_ADDRESS in the same way that DISPLAY is forwarded.
+In the meantime, you can edit the session.conf config file to 
+have your session bus listen on TCP, and manually set
+DBUS_SESSION_BUS_ADDRESS, if you like.
+
+.PP
+The second common reason for autolaunch is an su to another user, and
+display of X applications running as the second user on the display
+belonging to the first user. Perhaps the ideal fix in this case
+would be to allow the second user to connect to the session bus of the
+first user, just as they can connect to the first user's display.
+However, a mechanism for that has not been coded.
+
+.PP
+You can always avoid autolaunch by manually setting
+DBUS_SESSION_BUS_ADDRESS. Autolaunch happens because the default
+address if none is set is "autolaunch:", so if any other address is
+set there will be no autolaunch. You can however include autolaunch in
+an explicit session bus address as a fallback, for example
+DBUS_SESSION_BUS_ADDRESS="something:,autolaunch:" \- in that case if
+the first address doesn't work, processes will autolaunch. (The bus
+address variable contains a comma\-separated list of addresses to try.)
+
+.PP
+The \-\-autolaunch option is considered an internal implementation
+detail of libdbus, and in fact there are plans to change it. There's
+no real reason to use it outside of the libdbus implementation anyhow.
+
+.SH OPTIONS
+The following options are supported:
+.TP
+.I "\-\-auto\-syntax"
+Choose \-\-csh\-syntax or \-\-sh\-syntax based on the SHELL environment variable.
+
+.I "\-\-binary\-syntax"
+Write to stdout a nul\-terminated bus address, then the bus PID as a
+binary integer of size sizeof(pid_t), then the bus X window ID as a
+binary integer of size sizeof(long). Integers are in the machine's
+byte order, not network byte order or any other canonical byte order.
+
+.TP
+.I "\-\-close\-stderr"
+Close the standard error output stream before starting the D\-Bus
+daemon. This is useful if you want to capture dbus\-launch error
+messages but you don't want dbus\-daemon to keep the stream open to
+your application.
+
+.TP
+.I "\-\-config\-file=FILENAME"
+Pass \-\-config\-file=FILENAME to the bus daemon, instead of passing it 
+the \-\-session argument. See the man page for dbus\-daemon
+
+.TP
+.I "\-\-csh\-syntax"
+Emit csh compatible code to set up environment variables.
+
+.TP
+.I "\-\-exit\-with\-session"
+If this option is provided, a persistent "babysitter" process will be 
+created that watches stdin for HUP and tries to connect to the X
+server. If this process gets a HUP on stdin or loses its X connection,
+it kills the message bus daemon.
+
+.TP
+.I "\-\-autolaunch=MACHINEID"
+This option implies that \fIdbus\-launch\fP should scan for a
+previously\-started session and reuse the values found there. If no
+session is found, it will start a new session. The
+\-\-exit\-with\-session option is implied if \-\-autolaunch is given.
+This option is for the exclusive use of libdbus, you do not want to
+use it manually. It may change in the future.
+
+.TP
+.I "\-\-sh\-syntax"
+Emit Bourne\-shell compatible code to set up environment variables.
+
+.TP
+.I "\-\-version"
+Print the version of dbus\-launch
+
+.SH NOTES
+
+If you run
+.B "dbus\-launch myapp"
+(with any other options), dbus\-daemon will
+.I not
+exit when
+.B myapp
+terminates: this is because
+.B myapp
+is assumed to be part of a larger session, rather than a session in its
+own right.
+
+.SH AUTHOR
+See http://www.freedesktop.org/software/dbus/doc/AUTHORS
+
+.SH BUGS
+Please send bug reports to the D\-Bus mailing list or bug tracker,
+see http://www.freedesktop.org/software/dbus/
diff --git a/doc/dbus-monitor.1 b/doc/dbus-monitor.1
new file mode 100644
index 0000000..6282b9e
--- /dev/null
+++ b/doc/dbus-monitor.1
@@ -0,0 +1,78 @@
+.\" 
+.\" dbus\-monitor manual page.
+.\" Copyright (C) 2003 Red Hat, Inc.
+.\"
+.TH dbus\-monitor 1
+.SH NAME
+dbus\-monitor \- debug probe to print message bus messages
+.SH SYNOPSIS
+.PP
+.B dbus\-monitor
+[\-\-system | \-\-session | \-\-address ADDRESS] [\-\-profile | \-\-monitor]
+[watch expressions]
+
+.SH DESCRIPTION
+
+The \fIdbus\-monitor\fP command is used to monitor messages going
+through a D\-Bus message bus.  See
+http://www.freedesktop.org/software/dbus/ for more information about
+the big picture.
+
+.PP
+There are two well\-known message buses: the systemwide message bus
+(installed on many systems as the "messagebus" service) and the
+per\-user\-login\-session message bus (started each time a user logs in).
+The \-\-system and \-\-session options direct \fIdbus\-monitor\fP to
+monitor the system or session buses respectively.  If neither is
+specified, \fIdbus\-monitor\fP monitors the session bus.
+
+.PP
+\fIdbus\-monitor\fP has two different output modes, the 'classic'\-style
+monitoring mode and profiling mode. The profiling format is a compact
+format with a single line per message and microsecond\-resolution timing
+information. The \-\-profile and \-\-monitor options select the profiling
+and monitoring output format respectively. If neither is specified,
+\fIdbus\-monitor\fP uses the monitoring output format.
+
+.PP
+In order to get \fIdbus\-monitor\fP to see the messages you are interested
+in, you should specify a set of watch expressions as you would expect to
+be passed to the \fIdbus_bus_add_match\fP function.
+
+.PP 
+The message bus configuration may keep \fIdbus\-monitor\fP from seeing
+all messages, especially if you run the monitor as a non\-root user.
+
+.SH OPTIONS
+.TP
+.I "\-\-system"
+Monitor the system message bus.
+.TP
+.I "\-\-session"
+Monitor the session message bus.  (This is the default.)
+.TP
+.I "\-\-address ADDRESS"
+Monitor an arbitrary message bus given at ADDRESS.
+.TP
+.I "\-\-profile"
+Use the profiling output format.
+.TP
+.I "\-\-monitor"
+Use the monitoring output format.  (This is the default.)
+
+.SH EXAMPLE
+Here is an example of using dbus\-monitor to watch for the gnome typing
+monitor to say things
+.nf
+
+  dbus\-monitor "type='signal',sender='org.gnome.TypingMonitor',interface='org.gnome.TypingMonitor'"
+
+.fi
+
+.SH AUTHOR
+dbus\-monitor was written by Philip Blundell.
+The profiling output mode was added by Olli Salli.
+
+.SH BUGS
+Please send bug reports to the D\-Bus mailing list or bug tracker,
+see http://www.freedesktop.org/software/dbus/
diff --git a/doc/dbus-send.1 b/doc/dbus-send.1
new file mode 100644
index 0000000..131a60d
--- /dev/null
+++ b/doc/dbus-send.1
@@ -0,0 +1,109 @@
+.\" 
+.\" dbus\-send manual page.
+.\" Copyright (C) 2003 Red Hat, Inc.
+.\"
+.TH dbus\-send 1
+.SH NAME
+dbus\-send \- Send a message to a message bus
+.SH SYNOPSIS
+.PP
+.B dbus\-send
+[\fB\-\-system\fP | \fB\-\-session\fP]
+[\fB\-\-dest=\fINAME\fP]
+[\fB\-\-print\-reply\fP[\fB=literal\fP]]
+[\fB\-\-reply\-timeout=\fIMSEC\fP]
+[\fB\-\-type=\fITYPE\fP]
+\fIOBJECT_PATH\fP \fIINTERFACE\fB.\fIMEMBER\fP [\fICONTENTS\fP ...]
+
+.SH DESCRIPTION
+
+The \fIdbus\-send\fP command is used to send a message to a D\-Bus message
+bus. See http://www.freedesktop.org/software/dbus/ for more 
+information about the big picture.
+
+.PP
+There are two well\-known message buses: the systemwide message bus 
+(installed on many systems as the "messagebus" service) and the 
+per\-user\-login\-session message bus (started each time a user logs in).
+The \fB\-\-system\fP and \fB\-\-session\fP options direct
+\fBdbus\-send\fP to send messages to the system or session buses respectively.
+If neither is specified, \fBdbus\-send\fP sends to the session bus.
+
+.PP 
+Nearly all uses of \fBdbus\-send\fP must provide the \fB\-\-dest\fP argument
+which is the name of a connection on the bus to send the message to. If
+\fB\-\-dest\fP is omitted, no destination is set.
+
+.PP
+The object path and the name of the message to send must always be
+specified. Following arguments, if any, are the message contents
+(message arguments).  These are given as type\-specified values and 
+may include containers (arrays, dicts, and variants) as described below.
+
+.nf
+<contents>   ::= <item> | <container> [ <item> | <container>...]
+<item>       ::= <type>:<value>
+<container>  ::= <array> | <dict> | <variant>
+<array>      ::= array:<type>:<value>[,<value>...] 
+<dict>       ::= dict:<type>:<type>:<key>,<value>[,<key>,<value>...]
+<variant>    ::= variant:<type>:<value>
+<type>       ::= string | int16 | uint 16 | int32 | uint32 | int64 | uint64 | double | byte | boolean | objpath
+.fi
+
+D\-Bus supports more types than these, but \fBdbus\-send\fP currently
+does not.  Also, \fBdbus\-send\fP does not permit empty containers
+or nested containers (e.g. arrays of variants).
+
+.PP
+Here is an example invocation:
+.nf
+
+  dbus\-send \-\-dest=org.freedesktop.ExampleName               \\
+            /org/freedesktop/sample/object/name              \\
+            org.freedesktop.ExampleInterface.ExampleMethod   \\
+            int32:47 string:'hello world' double:65.32       \\
+            array:string:"1st item","next item","last item"  \\
+            dict:string:int32:"one",1,"two",2,"three",3      \\
+            variant:int32:\-8                                 \\
+            objpath:/org/freedesktop/sample/object/name 
+
+.fi
+
+Note that the interface is separated from a method or signal 
+name by a dot, though in the actual protocol the interface
+and the interface member are separate fields.
+
+.SH OPTIONS
+The following options are supported:
+.TP
+.BI \-\-dest= NAME
+Specify the name of the connection to receive the message.
+.TP
+.B "\-\-print\-reply"
+Block for a reply to the message sent, and print any reply received
+in a human-readable form.
+.TP
+.B "\-\-print\-reply=literal"
+Block for a reply to the message sent, and print the body of the
+reply. If the reply is an object path or a string, it is printed
+literally, with no punctuation, escape characters etc.
+.TP
+.BI \-\-reply\-timeout= MSEC
+Wait for a reply for up to \fIMSEC\fP milliseconds.
+The default is implementation\(hydefined, typically 25 seconds.
+.TP
+.B "\-\-system"
+Send to the system message bus.
+.TP
+.B "\-\-session"
+Send to the session message bus.  (This is the default.)
+.TP
+.BI \-\-type= TYPE
+Specify \fBmethod_call\fP or \fBsignal\fP (defaults to "\fBsignal\fP").
+
+.SH AUTHOR
+dbus\-send was written by Philip Blundell.
+
+.SH BUGS
+Please send bug reports to the D\-Bus mailing list or bug tracker,
+see http://www.freedesktop.org/software/dbus/
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index 3deb5c2..d806b8e 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -3,12 +3,11 @@
 "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"
 [
 ]>
-
 <article id="index">
   <articleinfo>
     <title>D-Bus Specification</title>
-    <releaseinfo>Version 0.14</releaseinfo>
-    <date>May 12, 2010</date>
+    <releaseinfo>Version 0.19</releaseinfo>
+    <date>2012-02-21</date>
     <authorgroup>
       <author>
 	<firstname>Havoc</firstname>
@@ -40,7 +39,123 @@
           </address>
 	</affiliation>
       </author>
+      <author>
+	<firstname>Sven</firstname>
+	<surname>Herzberg</surname>
+	<affiliation>
+	  <orgname>Imendio AB</orgname>
+	  <address>
+            <email>sven@imendio.com</email>
+          </address>
+	</affiliation>
+      </author>
+      <author>
+        <firstname>Simon</firstname>
+        <surname>McVittie</surname>
+        <affiliation>
+          <orgname>Collabora Ltd.</orgname>
+          <address>
+            <email>simon.mcvittie@collabora.co.uk</email>
+          </address>
+        </affiliation>
+      </author>
+      <author>
+        <firstname>David</firstname>
+        <surname>Zeuthen</surname>
+        <affiliation>
+          <orgname>Red Hat, Inc.</orgname>
+          <address>
+            <email>davidz@redhat.com</email>
+          </address>
+        </affiliation>
+      </author>
     </authorgroup>
+   <revhistory>
+     <revision>
+       <revnumber>current</revnumber>
+       <date><ulink url='http://cgit.freedesktop.org/dbus/dbus/log/doc/dbus-specification.xml'>commit log</ulink></date>
+       <authorinitials></authorinitials>
+       <revremark></revremark>
+     </revision>
+     <revision>
+       <revnumber>0.19</revnumber>
+       <date>20 February 2012</date>
+       <authorinitials>smcv/lp</authorinitials>
+       <revremark>formally define unique connection names and well-known
+        bus names; document best practices for interface, bus, member and
+        error names, and object paths; document the search path for session
+        and system services on Unix; document the systemd transport</revremark>
+     </revision>
+     <revision>
+       <revnumber>0.18</revnumber>
+       <date>29 July 2011</date>
+       <authorinitials>smcv</authorinitials>
+       <revremark>define eavesdropping, unicast, broadcast; add eavesdrop
+         match keyword; promote type system to a top-level section</revremark>
+     </revision>
+     <revision>
+       <revnumber>0.17</revnumber>
+       <date>1 June 2011</date>
+       <authorinitials>smcv/davidz</authorinitials>
+       <revremark>define ObjectManager; reserve extra pseudo-type-codes used
+         by GVariant</revremark>
+     </revision>
+     <revision>
+       <revnumber>0.16</revnumber>
+       <date>11 April 2011</date>
+       <authorinitials></authorinitials>
+       <revremark>add path_namespace, arg0namespace; argNpath matches object
+        paths</revremark>
+     </revision>
+     <revision>
+       <revnumber>0.15</revnumber>
+       <date>3 November 2010</date>
+       <authorinitials></authorinitials>
+       <revremark></revremark>
+     </revision>
+     <revision>
+       <revnumber>0.14</revnumber>
+       <date>12 May 2010</date>
+       <authorinitials></authorinitials>
+       <revremark></revremark>
+     </revision>
+     <revision>
+       <revnumber>0.13</revnumber>
+       <date>23 Dezember 2009</date>
+       <authorinitials></authorinitials>
+       <revremark></revremark>
+     </revision>
+     <revision>
+       <revnumber>0.12</revnumber>
+       <date>7 November, 2006</date>
+       <authorinitials></authorinitials>
+       <revremark></revremark>
+     </revision>
+     <revision>
+       <revnumber>0.11</revnumber>
+       <date>6 February 2005</date>
+       <authorinitials></authorinitials>
+       <revremark></revremark>
+     </revision>
+     <revision>
+       <revnumber>0.10</revnumber>
+       <date>28 January 2005</date>
+       <authorinitials></authorinitials>
+       <revremark></revremark>
+     </revision>
+     <revision>
+       <revnumber>0.9</revnumber>
+       <date>7 Januar 2005</date>
+       <authorinitials></authorinitials>
+       <revremark></revremark>
+     </revision>
+     <revision>
+       <revnumber>0.8</revnumber>
+       <date>06 September 2003</date>
+       <authorinitials></authorinitials>
+       <revremark>First released document.</revremark>
+     </revision>
+   </revhistory>
   </articleinfo>
 
   <sect1 id="introduction">
@@ -165,27 +280,13 @@
     
   </sect1>
 
-  <sect1 id="message-protocol">
-    <title>Message Protocol</title>
+  <sect1 id="type-system">
+    <title>Type System</title>
 
     <para>
-      A <firstterm>message</firstterm> consists of a
-      <firstterm>header</firstterm> and a <firstterm>body</firstterm>. If you
-      think of a message as a package, the header is the address, and the body
-      contains the package contents. The message delivery system uses the header
-      information to figure out where to send the message and how to interpret
-      it; the recipient interprets the body of the message.
-    </para>
-    
-    <para>
-      The body of the message is made up of zero or more
-      <firstterm>arguments</firstterm>, which are typed values, such as an
-      integer or a byte array.
-    </para>
-
-    <para>
-      Both header and body use the same type system and format for 
-      serializing data. Each type of value has a wire format. 
+      D-Bus has a type system, in which values of various types can be
+      serialized into a sequence of bytes referred to as the
+      <firstterm>wire format</firstterm> in a standard way.
       Converting a value from some other representation into the wire
       format is called <firstterm>marshaling</firstterm> and converting
       it back from the wire format is <firstterm>unmarshaling</firstterm>.
@@ -406,7 +507,10 @@
               </row><row>
                 <entry><literal>STRUCT</literal></entry>
                 <entry>114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')')</entry>
-                <entry>Struct</entry>
+                <entry>Struct; type code 114 'r' is reserved for use in
+                  bindings and implementations to represent the general
+                  concept of a struct, and must not appear in signatures
+                  used on D-Bus.</entry>
               </row><row>
                 <entry><literal>VARIANT</literal></entry>
                 <entry>118 (ASCII 'v') </entry>
@@ -414,12 +518,48 @@
               </row><row>
                 <entry><literal>DICT_ENTRY</literal></entry>
                 <entry>101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') </entry>
-                <entry>Entry in a dict or map (array of key-value pairs)</entry>
+                <entry>Entry in a dict or map (array of key-value pairs).
+                  Type code 101 'e' is reserved for use in bindings and
+                  implementations to represent the general concept of a
+                  dict or dict-entry, and must not appear in signatures
+                  used on D-Bus.</entry>
               </row><row>
                 <entry><literal>UNIX_FD</literal></entry>
                 <entry>104 (ASCII 'h')</entry>
                 <entry>Unix file descriptor</entry>
               </row>
+              <row>
+                <entry>(reserved)</entry>
+                <entry>109 (ASCII 'm')</entry>
+                <entry>Reserved for <ulink
+                    url="https://bugs.freedesktop.org/show_bug.cgi?id=27857">a
+                  'maybe' type compatible with the one in GVariant</ulink>,
+                  and must not appear in signatures used on D-Bus until
+                  specified here</entry>
+              </row>
+              <row>
+                <entry>(reserved)</entry>
+                <entry>42 (ASCII '*')</entry>
+                <entry>Reserved for use in bindings/implementations to
+                  represent any <firstterm>single complete type</firstterm>,
+                  and must not appear in signatures used on D-Bus.</entry>
+              </row>
+              <row>
+                <entry>(reserved)</entry>
+                <entry>63 (ASCII '?')</entry>
+                <entry>Reserved for use in bindings/implementations to
+                  represent any <firstterm>basic type</firstterm>, and must
+                  not appear in signatures used on D-Bus.</entry>
+              </row>
+              <row>
+                <entry>(reserved)</entry>
+                <entry>64 (ASCII '@'), 38 (ASCII '&amp;'),
+                  94 (ASCII '^')</entry>
+                <entry>Reserved for internal use by bindings/implementations,
+                  and must not appear in signatures used on D-Bus.
+                  GVariant uses these type-codes to encode calling
+                  conventions.</entry>
+              </row>
             </tbody>
           </tgroup>
         </informaltable>
@@ -651,9 +791,29 @@
           </itemizedlist>
         </para>
 
+        <para>
+          Object paths are often namespaced by starting with a reversed
+          domain name and containing an interface version number, in the
+          same way as
+          <link linkend="message-protocol-names-interface">interface
+            names</link> and
+          <link linkend="message-protocol-names-bus">well-known
+            bus names</link>.
+          This makes it possible to implement more than one service, or
+          more than one version of a service, in the same process,
+          even if the services share a connection but cannot otherwise
+          co-operate (for instance, if they are implemented by different
+          plugins).
+        </para>
+
+        <para>
+          For instance, if the owner of <literal>example.com</literal> is
+          developing a D-Bus API for a music player, they might use the
+          hierarchy of object paths that start with
+          <literal>/com/example/MusicPlayer1</literal> for its objects.
+        </para>
       </sect3>
 
-      
       <sect3 id="message-protocol-marshaling-signature">
         <title>Valid Signatures</title>
         <para>
@@ -705,6 +865,31 @@
       
     </sect2>
 
+  </sect1>
+
+  <sect1 id="message-protocol">
+    <title>Message Protocol</title>
+
+    <para>
+      A <firstterm>message</firstterm> consists of a
+      <firstterm>header</firstterm> and a <firstterm>body</firstterm>. If you
+      think of a message as a package, the header is the address, and the body
+      contains the package contents. The message delivery system uses the header
+      information to figure out where to send the message and how to interpret
+      it; the recipient interprets the body of the message.
+    </para>
+    
+    <para>
+      The body of the message is made up of zero or more
+      <firstterm>arguments</firstterm>, which are typed values, such as an
+      integer or a byte array.
+    </para>
+
+    <para>
+      Both header and body use the D-Bus <link linkend="type-system">type
+        system</link> and format for serializing data.
+    </para>
+
     <sect2 id="message-protocol-messages">
       <title>Message Format</title>
 
@@ -1072,21 +1257,48 @@
 	    <listitem><para>Interface names must not exceed the maximum name length.</para></listitem>
           </itemizedlist>
         </para>
+
+        <para>
+          Interface names should start with the reversed DNS domain name of
+          the author of the interface (in lower-case), like interface names
+          in Java. It is conventional for the rest of the interface name
+          to consist of words run together, with initial capital letters
+          on all words ("CamelCase"). Several levels of hierarchy can be used.
+          It is also a good idea to include the major version of the interface
+          in the name, and increment it if incompatible changes are made;
+          this way, a single object can implement several versions of an
+          interface in parallel, if necessary.
+        </para>
+
+        <para>
+          For instance, if the owner of <literal>example.com</literal> is
+          developing a D-Bus API for a music player, they might define
+          interfaces called <literal>com.example.MusicPlayer1</literal>,
+          <literal>com.example.MusicPlayer1.Track</literal> and
+          <literal>com.example.MusicPlayer1.Seekable</literal>.
+        </para>
+
+        <para>
+          D-Bus does not distinguish between the concepts that would be
+          called classes and interfaces in Java: either can be identified on
+          D-Bus by an interface name.
+        </para>
       </sect3>
       <sect3 id="message-protocol-names-bus">
         <title>Bus names</title>
         <para>
           Connections have one or more bus names associated with them.
-          A connection has exactly one bus name that is a unique connection
-          name. The unique connection name remains with the connection for
-          its entire lifetime.
+          A connection has exactly one bus name that is a <firstterm>unique
+            connection name</firstterm>. The unique connection name remains
+          with the connection for its entire lifetime.
           A bus name is of type <literal>STRING</literal>,
           meaning that it must be valid UTF-8. However, there are also
           some additional restrictions that apply to bus names 
           specifically:
           <itemizedlist>
             <listitem><para>Bus names that start with a colon (':')
-                character are unique connection names.
+                character are unique connection names. Other bus names
+                are called <firstterm>well-known bus names</firstterm>.
                 </para>
             </listitem>
             <listitem><para>Bus names are composed of 1 or more elements separated by
@@ -1113,6 +1325,31 @@
           Note that the hyphen ('-') character is allowed in bus names but
           not in interface names.
         </para>
+
+        <para>
+          Like <link linkend="message-protocol-names-interface">interface
+            names</link>, well-known bus names should start with the
+          reversed DNS domain name of the author of the interface (in
+          lower-case), and it is conventional for the rest of the well-known
+          bus name to consist of words run together, with initial
+          capital letters. As with interface names, including a version
+          number in well-known bus names is a good idea; it's possible to
+          have the well-known bus name for more than one version
+          simultaneously if backwards compatibility is required.
+        </para>
+
+        <para>
+          If a well-known bus name implies the presence of a "main" interface,
+          that "main" interface is often given the same name as
+          the well-known bus name, and situated at the corresponding object
+          path. For instance, if the owner of <literal>example.com</literal>
+          is developing a D-Bus API for a music player, they might define
+          that any application that takes the well-known name
+          <literal>com.example.MusicPlayer1</literal> should have an object
+          at the object path <literal>/com/example/MusicPlayer1</literal>
+          which implements the interface
+          <literal>com.example.MusicPlayer1</literal>.
+        </para>
       </sect3>
       <sect3 id="message-protocol-names-member">
         <title>Member names</title>
@@ -1127,12 +1364,31 @@
 	    <listitem><para>Must be at least 1 byte in length.</para></listitem>
           </itemizedlist>
         </para>
+
+        <para>
+          It is conventional for member names on D-Bus to consist of
+          capitalized words with no punctuation ("camel-case").
+          Method names should usually be verbs, such as
+          <literal>GetItems</literal>, and signal names should usually be
+          a description of an event, such as <literal>ItemsChanged</literal>.
+        </para>
       </sect3>
       <sect3 id="message-protocol-names-error">
         <title>Error names</title>
         <para>
           Error names have the same restrictions as interface names.
         </para>
+
+        <para>
+          Error names have the same naming conventions as interface
+          names, and often contain <literal>.Error.</literal>; for instance,
+          the owner of <literal>example.com</literal> might define the
+          errors <literal>com.example.MusicPlayer.Error.FileNotFound</literal>
+          and <literal>com.example.MusicPlayer.Error.OutOfMemory</literal>.
+          The errors defined by D-Bus itself, such as
+          <literal>org.freedesktop.DBus.Error.Failed</literal>, follow a
+          similar pattern.
+        </para>
       </sect3>
     </sect2>
 
@@ -2411,8 +2667,8 @@
       [FIXME we need to specify in detail each transport and its possible arguments]
     
       Current transports include: unix domain sockets (including 
-      abstract namespace on linux), TCP/IP, and a debug/testing transport using 
-      in-process pipes. Future possible transports include one that 
+      abstract namespace on linux), launchd, systemd, TCP/IP, an executed subprocess and a debug/testing transport
+      using in-process pipes. Future possible transports include one that
       tunnels over X11 protocol.
     </para>
   
@@ -2433,7 +2689,7 @@
 	would be padded by Nul bytes.
       </para>
       <para>
-        Unix domain sockets are not available on windows. 
+        Unix domain sockets are not available on Windows.
       </para>
       <sect3 id="transports-unix-domain-sockets-addresses">
         <title>Server Address Format</title>
@@ -2471,6 +2727,74 @@
        </informaltable>
       </sect3>
     </sect2>
+    <sect2 id="transports-launchd">
+      <title>launchd</title>
+      <para>
+        launchd is an open-source server management system that replaces init, inetd
+        and cron on Apple Mac OS X versions 10.4 and above. It provides a common session
+        bus address for each user and deprecates the X11-enabled D-Bus launcher on OSX.
+      </para>
+
+      <para>
+        launchd allocates a socket and provides it with the unix path through the
+        DBUS_LAUNCHD_SESSION_BUS_SOCKET variable in launchd's environment. Every process
+        spawned by launchd (or dbus-daemon, if it was started by launchd) can access
+        it through its environment.
+        Other processes can query for the launchd socket by executing:
+        $ launchctl getenv DBUS_LAUNCHD_SESSION_BUS_SOCKET
+        This is normally done by the D-Bus client library so doesn't have to be done
+        manually.
+      </para>
+      <para>
+        launchd is not available on Microsoft Windows.
+      </para>
+      <sect3 id="transports-launchd-addresses">
+        <title>Server Address Format</title>
+        <para>
+          launchd addresses are identified by the "launchd:" prefix
+          and support the following key/value pairs:
+        </para>
+        <informaltable>
+         <tgroup cols="3">
+          <thead>
+           <row>
+            <entry>Name</entry>
+            <entry>Values</entry>
+            <entry>Description</entry>
+           </row>
+          </thead>
+          <tbody>
+           <row>
+            <entry>env</entry>
+            <entry>(environment variable)</entry>
+            <entry>path of the unix domain socket for the launchd created dbus-daemon.</entry>
+          </row>
+        </tbody>
+        </tgroup>
+       </informaltable>
+      </sect3>
+    </sect2>
+    <sect2 id="transports-systemd">
+      <title>systemd</title>
+      <para>
+        systemd is an open-source server management system that
+        replaces init and inetd on newer Linux systems. It supports
+        socket activation. The D-Bus systemd transport is used to acquire
+        socket activation file descriptors from systemd and use them
+        as D-Bus transport when the current process is spawned by
+        socket activation from it.
+      </para>
+      <para>
+        The systemd transport accepts only one or more Unix domain or
+        TCP streams sockets passed in via socket activation.
+      </para>
+      <para>
+        The systemd transport is not available on non-Linux operating systems.
+      </para>
+      <para>
+        The systemd transport defines no parameter keys.
+      </para>
+    </sect2>
     <sect2 id="transports-tcp-sockets">
       <title>TCP Sockets</title>
       <para>
@@ -2482,7 +2806,7 @@
         over a network is unsecure. 
       </para>
       <para>  
-        Windows notes: Because of the tcp stack on windows does not provide sending 
+        Windows notes: Because of the tcp stack on Windows does not provide sending
         credentials over a tcp connection, the EXTERNAL authentification 
         mechanismus does not work. 
       </para>
@@ -2600,25 +2924,156 @@
        </informaltable>
       </sect3>
     </sect2>
+    <sect2 id="transports-exec">
+      <title>Executed Subprocesses on Unix</title>
+      <para>
+        This transport forks off a process and connects its standard
+        input and standard output with an anonymous Unix domain
+        socket. This socket is then used for communication by the
+        transport. This transport may be used to use out-of-process
+        forwarder programs as basis for the D-Bus protocol.
+      </para>
+      <para>
+        The forked process will inherit the standard error output and
+        process group from the parent process.
+      </para>
+      <para>
+        Executed subprocesses are not available on Windows.
+      </para>
+      <sect3 id="transports-exec-addresses">
+        <title>Server Address Format</title>
+        <para>
+          Executed subprocess addresses are identified by the "unixexec:" prefix
+          and support the following key/value pairs:
+        </para>
+        <informaltable>
+         <tgroup cols="3">
+          <thead>
+           <row>
+            <entry>Name</entry>
+            <entry>Values</entry>
+            <entry>Description</entry>
+           </row>
+          </thead>
+          <tbody>
+           <row>
+            <entry>path</entry>
+            <entry>(path)</entry>
+            <entry>Path of the binary to execute, either an absolute
+            path or a binary name that is searched for in the default
+            search path of the OS. This corresponds to the first
+            argument of execlp(). This key is mandatory.</entry>
+          </row>
+          <row>
+            <entry>argv0</entry>
+            <entry>(string)</entry>
+            <entry>The program name to use when executing the
+            binary. If omitted the same value as specified for path=
+            will be used. This corresponds to the second argument of
+            execlp().</entry>
+          </row>
+          <row>
+            <entry>argv1, argv2, ...</entry>
+            <entry>(string)</entry>
+            <entry>Arguments to pass to the binary. This corresponds
+            to the third and later arguments of execlp(). If a
+            specific argvX is not specified no further argvY for Y > X
+            are taken into account.</entry>
+          </row>
+        </tbody>
+        </tgroup>
+       </informaltable>
+      </sect3>
+    </sect2>
+   </sect1>
+   <sect1 id="meta-transports">
+    <title>Meta Transports</title>
+    <para>
+      Meta transports are a kind of transport with special enhancements or
+      behavior. Currently available meta transports include: autolaunch
+    </para>
 
-  </sect1>
+    <sect2 id="meta-transports-autolaunch">
+     <title>Autolaunch</title>
+     <para>The autolaunch transport provides a way for dbus clients to autodetect
+       a running dbus session bus and to autolaunch a session bus if not present.
+     </para>
+     <sect3 id="meta-transports-autolaunch-addresses">
+       <title>Server Address Format</title>
+       <para>
+         Autolaunch addresses uses the "autolaunch:" prefix and support the
+         following key/value pairs:
+       </para>
+       <informaltable>
+        <tgroup cols="3">
+         <thead>
+          <row>
+           <entry>Name</entry>
+           <entry>Values</entry>
+           <entry>Description</entry>
+          </row>
+         </thead>
+         <tbody>
+          <row>
+           <entry>scope</entry>
+           <entry>(string)</entry>
+           <entry>scope of autolaunch (Windows only)
+            <itemizedlist>
+             <listitem>
+              <para>
+               "*install-path" - limit session bus to dbus installation path.
+               The dbus installation path is determined from the location of
+               the shared dbus library. If the library is located in a 'bin'
+               subdirectory the installation root is the directory above,
+               otherwise the directory where the library lives is taken as
+               installation root.
+               <programlisting>
+                   &lt;install-root&gt;/bin/[lib]dbus-1.dll
+                   &lt;install-root&gt;/[lib]dbus-1.dll
+               </programlisting>
+              </para>
+             </listitem>
+             <listitem>
+              <para>
+               "*user" - limit session bus to the recent user.
+              </para>
+             </listitem>
+             <listitem>
+              <para>
+               other values - specify dedicated session bus like "release",
+               "debug" or other
+              </para>
+             </listitem>
+            </itemizedlist>
+           </entry>
+         </row>
+        </tbody>
+       </tgroup>
+      </informaltable>
+     </sect3>
 
-  <sect1 id="naming-conventions">
-    <title>Naming Conventions</title>
-    
-    <para>
-      D-Bus namespaces are all lowercase and correspond to reversed domain
-      names, as with Java. e.g. "org.freedesktop"
-    </para>
-    <para>
-      Interface, signal, method, and property names are "WindowsStyleCaps", note
-      that the first letter is capitalized, unlike Java.
-    </para>
-    <para>
-      Object paths are normally all lowercase with underscores used rather than
-      hyphens.
-    </para>
-  </sect1>
+     <sect3 id="meta-transports-autolaunch-windows-implementation">
+      <title>Windows implementation</title>
+      <para>
+        On start, the server opens a platform specific transport, creates a mutex
+        and a shared memory section containing the related session bus address.
+        This mutex will be inspected by the dbus client library to detect a
+        running dbus session bus. The access to the mutex and the shared memory
+        section are protected by global locks.
+      </para>
+      <para>
+       In the recent implementation the autolaunch transport uses a tcp transport
+       on localhost with a port choosen from the operating system. This detail may
+       change in the future.
+      </para>
+      <para>
+        Disclaimer: The recent implementation is in an early state and may not
+        work in all cirumstances and/or may have security issues. Because of this
+        the implementation is not documentated yet.
+      </para>
+     </sect3>
+    </sect2>
+   </sect1>
 
   <sect1 id="uuids">
     <title>UUIDs</title>
@@ -2748,6 +3203,22 @@
         </programlisting>
       </para>
       <para>
+        It is conventional to give D-Bus properties names consisting of
+        capitalized words without punctuation ("CamelCase"), like
+        <link linkend="message-protocol-names-member">member names</link>.
+        For instance, the GObject property
+        <literal>connection-status</literal> or the Qt property
+        <literal>connectionStatus</literal> could be represented on D-Bus
+        as <literal>ConnectionStatus</literal>.
+      </para>
+      <para>
+        Strictly speaking, D-Bus property names are not required to follow
+        the same naming restrictions as member names, but D-Bus property
+        names that would not be valid member names (in particular,
+        GObject-style dash-separated property names) can cause interoperability
+        problems and should be avoided.
+      </para>
+      <para>
         The available properties and whether they are writable can be determined
         by calling <literal>org.freedesktop.DBus.Introspectable.Introspect</literal>,
         see <xref linkend="standard-interfaces-introspectable"/>.
@@ -2793,6 +3264,114 @@
         annotation.
       </para>
     </sect2>
+
+    <sect2 id="standard-interfaces-objectmanager">
+      <title><literal>org.freedesktop.DBus.ObjectManager</literal></title>
+      <para>
+        An API can optionally make use of this interface for one or
+        more sub-trees of objects. The root of each sub-tree implements
+        this interface so other applications can get all objects,
+        interfaces and properties in a single method call.  It is
+        appropriate to use this interface if users of the tree of
+        objects are expected to be interested in all interfaces of all
+        objects in the tree; a more granular API should be used if
+        users of the objects are expected to be interested in a small
+        subset of the objects, a small subset of their interfaces, or
+        both.
+      </para>
+      <para>
+        The method that applications can use to get all objects and
+        properties is <literal>GetManagedObjects</literal>:
+      </para>
+      <para>
+        <programlisting>
+          org.freedesktop.DBus.ObjectManager.GetManagedObjects (out DICT&lt;OBJPATH,DICT&lt;STRING,DICT&lt;STRING,VARIANT&gt;&gt;&gt; objpath_interfaces_and_properties);
+        </programlisting>
+      </para>
+      <para>
+        The return value of this method is a dict whose keys are
+        object paths. All returned object paths are children of the
+        object path implementing this interface, i.e. their object
+        paths start with the ObjectManager's object path plus '/'.
+      </para>
+      <para>
+        Each value is a dict whose keys are interfaces names.  Each
+        value in this inner dict is the same dict that would be
+        returned by the <link
+        linkend="standard-interfaces-properties">org.freedesktop.DBus.Properties.GetAll()</link>
+        method for that combination of object path and interface. If
+        an interface has no properties, the empty dict is returned.
+      </para>
+      <para>
+        Changes are emitted using the following two signals:
+      </para>
+      <para>
+        <programlisting>
+          org.freedesktop.DBus.ObjectManager.InterfacesAdded (OBJPATH object_path,
+                                                              DICT&lt;STRING,DICT&lt;STRING,VARIANT&gt;&gt; interfaces_and_properties);
+          org.freedesktop.DBus.ObjectManager.InterfacesRemoved (OBJPATH object_path,
+                                                                ARRAY&lt;STRING&gt; interfaces);
+        </programlisting>
+      </para>
+      <para>
+        The <literal>InterfacesAdded</literal> signal is emitted when
+        either a new object is added or when an existing object gains
+        one or more interfaces. The
+        <literal>InterfacesRemoved</literal> signal is emitted
+        whenever an object is removed or it loses one or more
+        interfaces. The second parameter of the
+        <literal>InterfacesAdded</literal> signal contains a dict with
+        the interfaces and properties (if any) that have been added to
+        the given object path. Similarly, the second parameter of the
+        <literal>InterfacesRemoved</literal> signal contains an array
+        of the interfaces that were removed. Note that changes on
+        properties on existing interfaces are not reported using this
+        interface - an application should also monitor the existing <link
+        linkend="standard-interfaces-properties">PropertiesChanged</link>
+        signal on each object.
+      </para>
+      <para>
+        Applications SHOULD NOT export objects that are children of an
+        object (directly or otherwise) implementing this interface but
+        which are not returned in the reply from the
+        <literal>GetManagedObjects()</literal> method of this
+        interface on the given object.
+      </para>
+      <para>
+        The intent of the <literal>ObjectManager</literal> interface
+        is to make it easy to write a robust client
+        implementation. The trivial client implementation only needs
+        to make two method calls:
+      </para>
+      <para>
+        <programlisting>
+          org.freedesktop.DBus.AddMatch (bus_proxy,
+                                         "type='signal',name='org.example.App',path_namespace='/org/example/App'");
+          objects = org.freedesktop.DBus.ObjectManager.GetManagedObjects (app_proxy);
+        </programlisting>
+      </para>
+      <para>
+        on the message bus and the remote application's
+        <literal>ObjectManager</literal>, respectively. Whenever a new
+        remote object is created (or an existing object gains a new
+        interface), the <literal>InterfacesAdded</literal> signal is
+        emitted, and since this signal contains all properties for the
+        interfaces, no calls to the
+        <literal>org.freedesktop.Properties</literal> interface on the
+        remote object are needed. Additionally, since the initial
+        <literal>AddMatch()</literal> rule already includes signal
+        messages from the newly created child object, no new
+        <literal>AddMatch()</literal> call is needed.
+      </para>
+
+      <para>
+        <emphasis>
+          The <literal>org.freedesktop.DBus.ObjectManager</literal>
+          interface was added in version 0.17 of the D-Bus
+          specification.
+        </emphasis>
+      </para>
+    </sect2>
   </sect1>
 
   <sect1 id="introspection-format">
@@ -2995,35 +3574,10 @@
       </para>
 
       <para>
-        Messages may have a <literal>DESTINATION</literal> field (see <xref
-        linkend="message-protocol-header-fields"/>).  If the
-        <literal>DESTINATION</literal> field is present, it specifies a message
-        recipient by name. Method calls and replies normally specify this field.
-      </para>
-
-      <para>
-        Signals normally do not specify a destination; they are sent to all
-        applications with <firstterm>message matching rules</firstterm> that
-        match the message.
-      </para>
-
-      <para>
-        When the message bus receives a method call, if the
-        <literal>DESTINATION</literal> field is absent, the call is taken to be
-        a standard one-to-one message and interpreted by the message bus
-        itself. For example, sending an
-        <literal>org.freedesktop.DBus.Peer.Ping</literal> message with no
-        <literal>DESTINATION</literal> will cause the message bus itself to
-        reply to the ping immediately; the message bus will not make this
-        message visible to other applications.
-      </para>
-
-      <para>
-        Continuing the <literal>org.freedesktop.DBus.Peer.Ping</literal> example, if
-        the ping message were sent with a <literal>DESTINATION</literal> name of
-        <literal>com.yoyodyne.Screensaver</literal>, then the ping would be
-        forwarded, and the Yoyodyne Corporation screensaver application would be
-        expected to reply to the ping.
+        Applications may send <firstterm>unicast messages</firstterm> to
+        a specific recipient or to the message bus itself, or
+        <firstterm>broadcast messages</firstterm> to all interested recipients.
+        See <xref linkend="message-bus-routing"/> for details.
       </para>
     </sect2>
 
@@ -3457,20 +4011,122 @@
 
     <sect2 id="message-bus-routing">
       <title>Message Bus Message Routing</title>
+
       <para>
-        FIXME 
+        Messages may have a <literal>DESTINATION</literal> field (see <xref
+          linkend="message-protocol-header-fields"/>), resulting in a
+        <firstterm>unicast message</firstterm>.  If the
+        <literal>DESTINATION</literal> field is present, it specifies a message
+        recipient by name. Method calls and replies normally specify this field.
+        The message bus must send messages (of any type) with the
+        <literal>DESTINATION</literal> field set to the specified recipient,
+        regardless of whether the recipient has set up a match rule matching
+        the message.
       </para>
+
+      <para>
+        When the message bus receives a signal, if the
+        <literal>DESTINATION</literal> field is absent, it is considered to
+        be a <firstterm>broadcast signal</firstterm>, and is sent to all
+        applications with <firstterm>message matching rules</firstterm> that
+        match the message. Most signal messages are broadcasts.
+      </para>
+
+      <para>
+        Unicast signal messages (those with a <literal>DESTINATION</literal>
+        field) are not commonly used, but they are treated like any unicast
+        message: they are delivered to the specified receipient,
+        regardless of its match rules.  One use for unicast signals is to
+        avoid a race condition in which a signal is emitted before the intended
+        recipient can call <xref linkend="bus-messages-add-match"/> to
+        receive that signal: if the signal is sent directly to that recipient
+        using a unicast message, it does not need to add a match rule at all,
+        and there is no race condition.  Another use for unicast signals,
+        on message buses whose security policy prevents eavesdropping, is to
+        send sensitive information which should only be visible to one
+        recipient.
+      </para>
+
+      <para>
+        When the message bus receives a method call, if the
+        <literal>DESTINATION</literal> field is absent, the call is taken to be
+        a standard one-to-one message and interpreted by the message bus
+        itself. For example, sending an
+        <literal>org.freedesktop.DBus.Peer.Ping</literal> message with no
+        <literal>DESTINATION</literal> will cause the message bus itself to
+        reply to the ping immediately; the message bus will not make this
+        message visible to other applications.
+      </para>
+
+      <para>
+        Continuing the <literal>org.freedesktop.DBus.Peer.Ping</literal> example, if
+        the ping message were sent with a <literal>DESTINATION</literal> name of
+        <literal>com.yoyodyne.Screensaver</literal>, then the ping would be
+        forwarded, and the Yoyodyne Corporation screensaver application would be
+        expected to reply to the ping.
+      </para>
+
+      <para>
+        Message bus implementations may impose a security policy which
+        prevents certain messages from being sent or received.
+        When a message cannot be sent or received due to a security
+        policy, the message bus should send an error reply, unless the
+        original message had the <literal>NO_REPLY</literal> flag.
+      </para>
+
+      <sect3 id="message-bus-routing-eavesdropping">
+        <title>Eavesdropping</title>
+        <para>
+          Receiving a unicast message whose <literal>DESTINATION</literal>
+          indicates a different recipient is called
+          <firstterm>eavesdropping</firstterm>. On a message bus which acts as
+          a security boundary (like the standard system bus), the security
+          policy should usually prevent eavesdropping, since unicast messages
+          are normally kept private and may contain security-sensitive
+          information.
+        </para>
+
+        <para>
+          Eavesdropping is mainly useful for debugging tools, such as
+          the <literal>dbus-monitor</literal> tool in the reference
+          implementation of D-Bus. Tools which eavesdrop on the message bus
+          should be careful to avoid sending a reply or error in response to
+          messages intended for a different client.
+        </para>
+
+        <para>
+          Clients may attempt to eavesdrop by adding match rules
+          (see <xref linkend="message-bus-routing-match-rules"/>) containing
+          the <literal>eavesdrop='true'</literal> match. If the message bus'
+          security policy does not allow eavesdropping, the match rule can
+          still be added, but will not have any practical effect. For
+          compatibility with older message bus implementations, if adding such
+          a match rule results in an error reply, the client may fall back to
+          adding the same rule with the <literal>eavesdrop</literal> match
+          omitted.
+        </para>
+      </sect3>
+
       <sect3 id="message-bus-routing-match-rules">
         <title>Match Rules</title>
         <para>
-	  An important part of the message bus routing protocol is match  
-	  rules. Match rules describe what messages can be sent to a client
-          based on the contents of the message.  When a message is routed
-          through the bus it is compared to clients' match rules.  If any
-          of the rules match, the message is dispatched to the client.
-          If none of the rules match the message never leaves the bus.  This
-          is an effective way to control traffic over the bus and to make sure
-          only relevant message need to be processed by the client.
+	  An important part of the message bus routing protocol is match
+          rules. Match rules describe the messages that should be sent to a
+          client, based on the contents of the message.  Broadcast signals
+          are only sent to clients which have a suitable match rule: this
+          avoids waking up client processes to deal with signals that are
+          not relevant to that client.
+        </para>
+        <para>
+          Messages that list a client as their <literal>DESTINATION</literal>
+          do not need to match the client's match rules, and are sent to that
+          client regardless. As a result, match rules are mainly used to
+          receive a subset of broadcast signals.
+        </para>
+        <para>
+          Match rules can also be used for eavesdropping
+          (see <xref linkend="message-bus-routing-eavesdropping"/>),
+          if the security policy of the message bus allows it.
         </para>
         <para>
           Match rules are added using the AddMatch bus method 
@@ -3530,6 +4186,43 @@
                   path match is path='/org/freedesktop/Hal/Manager'</entry>
                 </row>
                 <row>
+                  <entry><literal>path_namespace</literal></entry>
+                  <entry>An object path</entry>
+                  <entry>
+                    <para>
+                      Matches messages which are sent from or to an
+                      object for which the object path is either the
+                      given value, or that value followed by one or
+                      more path components.
+                    </para>
+
+                    <para>
+                      For example,
+                      <literal>path_namespace='/com/example/foo'</literal>
+                      would match signals sent by
+                      <literal>/com/example/foo</literal>
+                      or by
+                      <literal>/com/example/foo/bar</literal>,
+                      but not by
+                      <literal>/com/example/foobar</literal>.
+                    </para>
+
+                    <para>
+                      Using both <literal>path</literal> and
+                      <literal>path_namespace</literal> in the same match
+                      rule is not allowed.
+                    </para>
+
+                    <para>
+                      <emphasis>
+                        This match key was added in version 0.16 of the
+                        D-Bus specification and implemented by the bus
+                        daemon in dbus 1.5.0 and later.
+                      </emphasis>
+                    </para>
+                </entry>
+                </row>
+                <row>
                   <entry><literal>destination</literal></entry>
                   <entry>A unique name (see <xref linkend="term-unique-name"/>)</entry>
                   <entry>Matches messages which are being sent to the given unique name. An
@@ -3539,24 +4232,99 @@
                   <entry><literal>arg[0, 1, 2, 3, ...]</literal></entry>
                   <entry>Any string</entry>
                   <entry>Arg matches are special and are used for further restricting the 
-                  match based on the arguments in the body of a message.  As of this time
-                  only string arguments can be matched.  An example of an argument match 
+                  match based on the arguments in the body of a message. Only arguments of type
+                  STRING can be matched in this way. An example of an argument match 
                   would be arg3='Foo'. Only argument indexes from 0 to 63 should be 
                   accepted.</entry>
                 </row>
                 <row>
                   <entry><literal>arg[0, 1, 2, 3, ...]path</literal></entry>
                   <entry>Any string</entry>
-                  <entry>Argument path matches provide a specialised form of wildcard
-                  matching for path-like namespaces. As with normal argument matches,
-                  if the argument is exactly equal to the string given in the match
-                  rule then the rule is satisfied. Additionally, there is also a
-                  match when either the string given in the match rule or the
-                  appropriate message argument ends with '/' and is a prefix of the
-                  other. An example argument path match is arg0path='/aa/bb/'. This
-                  would match messages with first arguments of '/', '/aa/',
-                  '/aa/bb/', '/aa/bb/cc/' and '/aa/bb/cc'. It would not match
-                  messages with first arguments of '/aa/b', '/aa' or even '/aa/bb'.</entry>
+                  <entry>
+                    <para>Argument path matches provide a specialised form of wildcard matching for
+                      path-like namespaces. They can match arguments whose type is either STRING or
+                      OBJECT_PATH. As with normal argument matches,
+                      if the argument is exactly equal to the string given in the match
+                      rule then the rule is satisfied. Additionally, there is also a
+                      match when either the string given in the match rule or the
+                      appropriate message argument ends with '/' and is a prefix of the
+                      other. An example argument path match is arg0path='/aa/bb/'. This
+                      would match messages with first arguments of '/', '/aa/',
+                      '/aa/bb/', '/aa/bb/cc/' and '/aa/bb/cc'. It would not match
+                      messages with first arguments of '/aa/b', '/aa' or even '/aa/bb'.</para>
+
+                    <para>This is intended for monitoring “directories” in file system-like
+                      hierarchies, as used in the <citetitle>dconf</citetitle> configuration
+                      system. An application interested in all nodes in a particular hierarchy would
+                      monitor <literal>arg0path='/ca/example/foo/'</literal>. Then the service could
+                      emit a signal with zeroth argument <literal>"/ca/example/foo/bar"</literal> to
+                      represent a modification to the “bar” property, or a signal with zeroth
+                      argument <literal>"/ca/example/"</literal> to represent atomic modification of
+                      many properties within that directory, and the interested application would be
+                      notified in both cases.</para>
+                    <para>
+                      <emphasis>
+                        This match key was added in version 0.12 of the
+                        D-Bus specification, implemented for STRING
+                        arguments by the bus daemon in dbus 1.2.0 and later,
+                        and implemented for OBJECT_PATH arguments in dbus 1.5.0
+                        and later.
+                      </emphasis>
+                    </para>
+                  </entry>
+                </row>
+                <row>
+                  <entry><literal>arg0namespace</literal></entry>
+                  <entry>Like a bus name, except that the string is not
+                    required to contain a '.' (period)</entry>
+                  <entry>
+                    <para>Match messages whose first argument is of type STRING, and is a bus name
+                      or interface name within the specified namespace. This is primarily intended
+                      for watching name owner changes for a group of related bus names, rather than
+                      for a single name or all name changes.</para>
+
+                    <para>Because every valid interface name is also a valid
+                      bus name, this can also be used for messages whose
+                      first argument is an interface name.</para>
+
+                    <para>For example, the match rule
+                      <literal>member='NameOwnerChanged',arg0namespace='com.example.backend'</literal>
+                      matches name owner changes for bus names such as
+                      <literal>com.example.backend.foo</literal>,
+                      <literal>com.example.backend.foo.bar</literal>, and
+                      <literal>com.example.backend</literal> itself.</para>
+
+                    <para>See also <xref linkend='bus-messages-name-owner-changed'/>.</para>
+                    <para>
+                      <emphasis>
+                        This match key was added in version 0.16 of the
+                        D-Bus specification and implemented by the bus
+                        daemon in dbus 1.5.0 and later.
+                      </emphasis>
+                    </para>
+                  </entry>
+                </row>
+                <row>
+                  <entry><literal>eavesdrop</literal></entry>
+                  <entry><literal>'true'</literal>, <literal>'false'</literal></entry>
+                  <entry>Since D-Bus 1.5.6, match rules do not
+                    match messages which have a <literal>DESTINATION</literal>
+                    field unless the match rule specifically
+                    requests this
+                    (see <xref linkend="message-bus-routing-eavesdropping"/>)
+                    by specifying <literal>eavesdrop='true'</literal>
+                    in the match rule.  <literal>eavesdrop='false'</literal>
+                    restores the default behaviour. Messages are
+                    delivered to their <literal>DESTINATION</literal>
+                    regardless of match rules, so this match does not
+                    affect normal delivery of unicast messages.
+                    If the message bus has a security policy which forbids
+                    eavesdropping, this match may still be used without error,
+                    but will not have any practical effect.
+                    In older versions of D-Bus, this match was not allowed
+                    in match rules, and all match rules behaved as if
+                    <literal>eavesdrop='true'</literal> had been used.
+                  </entry>
                 </row>
               </tbody>
             </tgroup>
@@ -3589,17 +4357,27 @@
         <xref linkend="message-bus-types"/>.
       </para>
       <para>
-        [FIXME the file format should be much better specified than "similar to
-        .desktop entries" esp. since desktop entries are already
-        badly-specified. ;-)] Service description files have the ".service" file
+        Service description files have the ".service" file
         extension. The message bus will only load service description files
         ending with .service; all other files will be ignored.  The file format
         is similar to that of <ulink
-        url="http://www.freedesktop.org/standards/desktop-entry-spec/desktop-entry-spec.html">desktop
+        url="http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html">desktop
         entries</ulink>. All service description files must be in UTF-8
         encoding. To ensure that there will be no name collisions, service files
         must be namespaced using the same mechanism as messages and service
         names.
+      </para>
+
+      <para>
+        [FIXME the file format should be much better specified than "similar to
+        .desktop entries" esp. since desktop entries are already
+        badly-specified. ;-)]
+        These sections from the specification apply to service files as well:
+
+        <itemizedlist>
+          <listitem><para>General syntax</para></listitem>
+          <listitem><para>Comment format</para></listitem>
+        </itemizedlist>
 
         <figure>
 	  <title>Example service description file</title>
@@ -3694,11 +4472,237 @@
           The environment variable should have precedence over the 
           root window property.
         </para>
-        <para>
-          [FIXME specify location of .service files, probably using 
-          DESKTOP_DIRS etc. from basedir specification, though login session 
-          bus is not really desktop-specific]
-        </para>
+        <para>The address of the login session message bus is given in the
+        <literal>DBUS_SESSION_BUS_ADDRESS</literal> environment variable. If
+        DBUS_SESSION_BUS_ADDRESS is not set, or if it's set to the string
+        "autolaunch:", the system should use platform-specific methods of
+        locating a running D-Bus session server, or starting one if a running
+        instance cannot be found. Note that this mechanism is not recommended
+        for attempting to determine if a daemon is running. It is inherently
+        racy to attempt to make this determination, since the bus daemon may
+        be started just before or just after the determination is made.
+        Therefore, it is recommended that applications do not try to make this
+        determination for their functionality purposes, and instead they
+        should attempt to start the server.</para>
+
+        <sect4 id="message-bus-types-login-x-windows">
+          <title>X Windowing System</title>
+          <para>
+            For the X Windowing System, the application must locate the
+            window owner of the selection represented by the atom formed by
+            concatenating:
+            <itemizedlist>
+              <listitem>
+                <para>the literal string "_DBUS_SESSION_BUS_SELECTION_"</para>
+              </listitem>
+
+              <listitem>
+                <para>the current user's username</para>
+              </listitem>
+
+              <listitem>
+                <para>the literal character '_' (underscore)</para>
+              </listitem>
+
+              <listitem>
+                <para>the machine's ID</para>
+              </listitem>
+            </itemizedlist>
+          </para>
+
+          <para>
+            The following properties are defined for the window that owns
+            this X selection:
+            <informaltable frame="all">
+              <tgroup cols="2">
+                <tbody>
+                  <row>
+                    <entry>
+                      <para>Atom</para>
+                    </entry>
+
+                    <entry>
+                      <para>meaning</para>
+                    </entry>
+                  </row>
+
+                  <row>
+                    <entry>
+                      <para>_DBUS_SESSION_BUS_ADDRESS</para>
+                    </entry>
+
+                    <entry>
+                      <para>the actual address of the server socket</para>
+                    </entry>
+                  </row>
+
+                  <row>
+                    <entry>
+                      <para>_DBUS_SESSION_BUS_PID</para>
+                    </entry>
+
+                    <entry>
+                      <para>the PID of the server process</para>
+                    </entry>
+                  </row>
+                </tbody>
+              </tgroup>
+            </informaltable>
+          </para>
+
+          <para>
+            At least the _DBUS_SESSION_BUS_ADDRESS property MUST be
+            present in this window.
+          </para>
+
+          <para>
+            If the X selection cannot be located or if reading the
+            properties from the window fails, the implementation MUST conclude
+            that there is no D-Bus server running and proceed to start a new
+            server. (See below on concurrency issues)
+          </para>
+
+          <para>
+            Failure to connect to the D-Bus server address thus obtained
+            MUST be treated as a fatal connection error and should be reported
+            to the application.
+          </para>
+
+          <para>
+            As an alternative, an implementation MAY find the information
+            in the following file located in the current user's home directory,
+            in subdirectory .dbus/session-bus/:
+            <itemizedlist>
+              <listitem>
+                <para>the machine's ID</para>
+              </listitem>
+
+              <listitem>
+                <para>the literal character '-' (dash)</para>
+              </listitem>
+
+              <listitem>
+                <para>the X display without the screen number, with the
+                following prefixes removed, if present: ":", "localhost:"
+                ."localhost.localdomain:". That is, a display of
+                "localhost:10.0" produces just the number "10"</para>
+              </listitem>
+            </itemizedlist>
+          </para>
+
+          <para>
+            The contents of this file NAME=value assignment pairs and
+            lines starting with # are comments (no comments are allowed
+            otherwise). The following variable names are defined:
+            <informaltable
+              frame="all">
+              <tgroup cols="2">
+                <tbody>
+                  <row>
+                    <entry>
+                      <para>Variable</para>
+                    </entry>
+
+                    <entry>
+                      <para>meaning</para>
+                    </entry>
+                  </row>
+
+                  <row>
+                    <entry>
+                      <para>DBUS_SESSION_BUS_ADDRESS</para>
+                    </entry>
+
+                    <entry>
+                      <para>the actual address of the server socket</para>
+                    </entry>
+                  </row>
+
+                  <row>
+                    <entry>
+                      <para>DBUS_SESSION_BUS_PID</para>
+                    </entry>
+
+                    <entry>
+                      <para>the PID of the server process</para>
+                    </entry>
+                  </row>
+
+                  <row>
+                    <entry>
+                      <para>DBUS_SESSION_BUS_WINDOWID</para>
+                    </entry>
+
+                    <entry>
+                      <para>the window ID</para>
+                    </entry>
+                  </row>
+                </tbody>
+              </tgroup>
+            </informaltable>
+          </para>
+
+          <para>
+            At least the DBUS_SESSION_BUS_ADDRESS variable MUST be present
+            in this file.
+          </para>
+
+          <para>
+            Failure to open this file MUST be interpreted as absence of a
+            running server. Therefore, the implementation MUST proceed to
+            attempting to launch a new bus server if the file cannot be
+            opened.
+          </para>
+
+          <para>
+            However, success in opening this file MUST NOT lead to the
+            conclusion that the server is running. Thus, a failure to connect to
+            the bus address obtained by the alternative method MUST NOT be
+            considered a fatal error. If the connection cannot be established,
+            the implementation MUST proceed to check the X selection settings or
+            to start the server on its own.
+          </para>
+
+          <para>
+            If the implementation concludes that the D-Bus server is not
+            running it MUST attempt to start a new server and it MUST also
+            ensure that the daemon started as an effect of the "autolaunch"
+            mechanism provides the lookup mechanisms described above, so
+            subsequent calls can locate the newly started server. The
+            implementation MUST also ensure that if two or more concurrent
+            initiations happen, only one server remains running and all other
+            initiations are able to obtain the address of this server and
+            connect to it. In other words, the implementation MUST ensure that
+            the X selection is not present when it attempts to set it, without
+            allowing another process to set the selection between the
+            verification and the setting (e.g., by using XGrabServer /
+            XungrabServer).
+          </para>
+        </sect4>
+        <sect4>
+          <title></title>
+          <para>
+            On Unix systems, the session bus should search for .service files
+            in <literal>$XDG_DATA_DIRS/dbus-1/services</literal> as defined
+            by the
+            <ulink url="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG Base Directory Specification</ulink>.
+            Implementations may also search additional locations, which
+            should be searched with lower priority than anything in
+            XDG_DATA_HOME, XDG_DATA_DIRS or their respective defaults;
+            for example, the reference implementation also
+            looks in <literal>${datadir}/dbus-1/services</literal> as
+            set at compile time.
+          </para>
+          <para>
+            As described in the XDG Base Directory Specification, software
+            packages should install their session .service files to their
+            configured <literal>${datadir}/dbus-1/services</literal>,
+            where <literal>${datadir}</literal> is as defined by the GNU
+            coding standards. System administrators or users can arrange
+            for these service files to be read by setting XDG_DATA_DIRS or by
+            symlinking them into the default locations.
+          </para>
+        </sect4>
       </sect3>
       <sect3 id="message-bus-types-system">
         <title>System message bus</title>
@@ -3723,7 +4727,32 @@
           </footnote>
         </para>
         <para>
-          [FIXME specify location of system bus .service files]
+          On Unix systems, the system bus should default to searching
+          for .service files in
+          <literal>/usr/local/share/dbus-1/system-services</literal>,
+          <literal>/usr/share/dbus-1/system-services</literal> and
+          <literal>/lib/dbus-1/system-services</literal>, with that order
+          of precedence. It may also search other implementation-specific
+          locations, but should not vary these locations based on environment
+          variables.
+          <footnote>
+            <para>
+              The system bus is security-sensitive and is typically executed
+              by an init system with a clean environment. Its launch helper
+              process is particularly security-sensitive, and specifically
+              clears its own environment.
+            </para>
+          </footnote>
+        </para>
+        <para>
+          Software packages should install their system .service
+          files to their configured
+          <literal>${datadir}/dbus-1/system-services</literal>,
+          where <literal>${datadir}</literal> is as defined by the GNU
+          coding standards. System administrators can arrange
+          for these service files to be read by editing the system bus'
+          configuration file or by symlinking them into the default
+          locations.
         </para>
       </sect3>
     </sect2>
@@ -4410,6 +5439,11 @@
               can be thought of as "well-known names" and are 
               used to find applications that offer specific functionality.
         </para>
+
+        <para>
+          See <xref linkend="message-protocol-names-bus"/> for details of
+          the syntax and naming conventions for bus names.
+        </para>
       </glossdef>
     </glossentry>
       
@@ -4448,10 +5482,14 @@
 
     <glossentry id="namespace"><glossterm>Namespace</glossterm>
       <glossdef>
-	<para>
-          Used to prevent collisions when defining new interfaces or bus
-	  names. The convention used is the same one Java uses for defining
-	  classes: a reversed domain name.
+        <para>
+          Used to prevent collisions when defining new interfaces, bus names
+          etc. The convention used is the same one Java uses for defining
+          classes: a reversed domain name.
+          See <xref linkend="message-protocol-names-bus"/>,
+          <xref linkend="message-protocol-names-interface"/>,
+          <xref linkend="message-protocol-names-error"/>,
+          <xref linkend="message-protocol-marshaling-object-path"/>.
         </para>
       </glossdef>
     </glossentry>
diff --git a/tools/dbus-uuidgen.1 b/doc/dbus-uuidgen.1
similarity index 66%
rename from tools/dbus-uuidgen.1
rename to doc/dbus-uuidgen.1
index 480fd18..8ed8dd2 100644
--- a/tools/dbus-uuidgen.1
+++ b/doc/dbus-uuidgen.1
@@ -1,36 +1,36 @@
 .\" 
-.\" dbus-uuidgen manual page.
+.\" dbus\-uuidgen manual page.
 .\" Copyright (C) 2006 Red Hat, Inc.
 .\"
-.TH dbus-uuidgen 1
+.TH dbus\-uuidgen 1
 .SH NAME
-dbus-uuidgen \- Utility to generate UUIDs
+dbus\-uuidgen \- Utility to generate UUIDs
 .SH SYNOPSIS
 .PP
-.B dbus-uuidgen [\-\-version] [\-\-ensure[=FILENAME]] [\-\-get[=FILENAME]]
+.B dbus\-uuidgen [\-\-version] [\-\-ensure[=FILENAME]] [\-\-get[=FILENAME]]
 
 .SH DESCRIPTION
 
-The \fIdbus-uuidgen\fP command generates or reads a universally unique ID.
+The \fIdbus\-uuidgen\fP command generates or reads a universally unique ID.
 
 .PP
-Note that the D-Bus UUID has no relationship to RFC 4122 and does not generate
+Note that the D\-Bus UUID has no relationship to RFC 4122 and does not generate
 UUIDs compatible with that spec. Many systems have a separate command
 for that (often called "uuidgen").
 
 .PP
 See http://www.freedesktop.org/software/dbus/ for more information
-about D-Bus.
+about D\-Bus.
 
 .PP
-The primary usage of \fIdbus-uuidgen\fP is to run in the post-install
-script of a D-Bus package like this:
+The primary usage of \fIdbus\-uuidgen\fP is to run in the post\-install
+script of a D\-Bus package like this:
 .nf
-  dbus-uuidgen --ensure
+  dbus\-uuidgen \-\-ensure
 .fi
 
 .PP
-This will ensure that /var/lib/dbus/machine-id exists and has the uuid in it.
+This will ensure that /var/lib/dbus/machine\-id exists and has the uuid in it.
 It won't overwrite an existing uuid, since this id should remain fixed
 for a single machine until the next reboot at least.
 
@@ -43,15 +43,15 @@
 IDs, and so forth.
 
 .PP
-If you run \fIdbus-uuidgen\fP with no options it just prints a new uuid made
+If you run \fIdbus\-uuidgen\fP with no options it just prints a new uuid made
 up out of thin air.
 
 .PP
-If you run it with --get, it prints the machine UUID by default, or
+If you run it with \-\-get, it prints the machine UUID by default, or
 the UUID in the specified file if you specify a file.
 
 .PP
-If you try to change an existing machine-id on a running system, it will
+If you try to change an existing machine\-id on a running system, it will
 probably result in bad things happening. Don't try to change this file. Also,
 don't make it the same on two different systems; it needs to be different
 anytime there are two different kernels running.
@@ -63,27 +63,27 @@
 .SH OPTIONS
 The following options are supported:
 .TP
-.I "--get[=FILENAME]"
-If a filename is not given, defaults to localstatedir/lib/dbus/machine-id
+.I "\-\-get[=FILENAME]"
+If a filename is not given, defaults to localstatedir/lib/dbus/machine\-id
 (localstatedir is usually /var). If this file exists and is valid, the
 uuid in the file is printed on stdout. Otherwise, the command exits 
 with a nonzero status.
 
 .TP
-.I "--ensure[=FILENAME]"
-If a filename is not given, defaults to localstatedir/lib/dbus/machine-id
+.I "\-\-ensure[=FILENAME]"
+If a filename is not given, defaults to localstatedir/lib/dbus/machine\-id
 (localstatedir is usually /var). If this file exists then it will be
 validated, and a failure code returned if it contains the wrong thing.
 If the file does not exist, it will be created with a new uuid in it.
 On success, prints no output.
 
 .TP
-.I "--version"
-Print the version of dbus-uuidgen
+.I "\-\-version"
+Print the version of dbus\-uuidgen
 
 .SH AUTHOR
 See http://www.freedesktop.org/software/dbus/doc/AUTHORS
 
 .SH BUGS
-Please send bug reports to the D-Bus mailing list or bug tracker,
+Please send bug reports to the D\-Bus mailing list or bug tracker,
 see http://www.freedesktop.org/software/dbus/
diff --git a/doc/doxygen_to_devhelp.xsl b/doc/doxygen_to_devhelp.xsl
new file mode 100644
index 0000000..72098f9
--- /dev/null
+++ b/doc/doxygen_to_devhelp.xsl
@@ -0,0 +1,40 @@
+<xsl:stylesheet
+    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+    xmlns:fo="http://www.w3.org/1999/XSL/Format"
+    version="1.0">
+
+<xsl:output method="xml" version="1.0" indent="yes"/>
+
+<xsl:param name="prefix"></xsl:param>
+
+<xsl:template match="/">
+  <book title="D-Bus: A system for interprocess communication"
+        name="dbus"
+        link="dbus-tutorial.html">
+  <chapters>
+     <sub name="Tutorial" link="{$prefix}dbus-tutorial.html"/>
+     <sub name="FAQ" link="{$prefix}dbus-faq.html"/>
+     <sub name="Specification" link="{$prefix}dbus-specification.html"/>
+     <sub name="API Reference" link="{$prefix}api/index.html"/>
+  </chapters>
+
+  <functions>
+    <xsl:apply-templates select="doxygenindex/compound[@kind='group']/member[@kind='function']"/>
+  </functions>
+  </book>
+</xsl:template>
+
+<xsl:template match="member">
+  <xsl:param name="name"><xsl:value-of select="name"/></xsl:param>
+  <xsl:param name="refid"><xsl:value-of select="@refid"/></xsl:param>
+  <xsl:param name="before"><xsl:value-of select="substring-before($refid,'_1')"/></xsl:param>
+  <xsl:param name="after"><xsl:value-of select="substring-after($refid,'_1')"/></xsl:param>
+  <xsl:param name="link"><xsl:value-of select="$before"/>.html#<xsl:value-of select="$after"/></xsl:param>
+  <xsl:if test="starts-with($name,'dbus') or starts-with($name, 'DBus')">
+    <xsl:if test="starts-with($refid,'group__') and contains($refid, '_1')">
+       <function name="{$name}" link="{$prefix}api/{$link}"/>
+    </xsl:if>
+  </xsl:if>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/m4/as-ac-expand.m4 b/m4/as-ac-expand.m4
new file mode 100644
index 0000000..deebd2b
--- /dev/null
+++ b/m4/as-ac-expand.m4
@@ -0,0 +1,49 @@
+dnl as-ac-expand.m4 0.2.0                                   -*- autoconf -*-
+dnl autostars m4 macro for expanding directories using configure's prefix
+
+dnl (C) 2003, 2004, 2005 Thomas Vander Stichele <thomas at apestaart dot org>
+
+dnl Copying and distribution of this file, with or without modification,
+dnl are permitted in any medium without royalty provided the copyright
+dnl notice and this notice are preserved.
+
+dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
+
+dnl example:
+dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
+dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
+
+AC_DEFUN([AS_AC_EXPAND],
+[
+  EXP_VAR=[$1]
+  FROM_VAR=[$2]
+
+  dnl first expand prefix and exec_prefix if necessary
+  prefix_save=$prefix
+  exec_prefix_save=$exec_prefix
+
+  dnl if no prefix given, then use /usr/local, the default prefix
+  if test "x$prefix" = "xNONE"; then
+    prefix="$ac_default_prefix"
+  fi
+  dnl if no exec_prefix given, then use prefix
+  if test "x$exec_prefix" = "xNONE"; then
+    exec_prefix=$prefix
+  fi
+
+  full_var="$FROM_VAR"
+  dnl loop until it doesn't change anymore
+  while true; do
+    new_full_var="`eval echo $full_var`"
+    if test "x$new_full_var" = "x$full_var"; then break; fi
+    full_var=$new_full_var
+  done
+
+  dnl clean up
+  full_var=$new_full_var
+  AC_SUBST([$1], "$full_var")
+
+  dnl restore prefix and exec_prefix
+  prefix=$prefix_save
+  exec_prefix=$exec_prefix_save
+])
diff --git a/m4/compiler.m4 b/m4/compiler.m4
new file mode 100644
index 0000000..5aff5d8
--- /dev/null
+++ b/m4/compiler.m4
@@ -0,0 +1,67 @@
+# compiler.m4 - autoconf macros for compiler settings
+#
+# Copyright © 2005 Scott James Remnant <scott@netsplit.com>.
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+# 
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+# COMPILER_WARNINGS
+# ----------------------
+# Add configure option to enable additional compiler warnings and treat
+# them as errors.
+AC_DEFUN([COMPILER_WARNINGS],
+[AC_ARG_ENABLE(compiler-warnings,
+	AS_HELP_STRING([--enable-compiler-warnings],
+	               [Enable additional compiler warnings]),
+[if test "x$enable_compiler_warnings" = "xyes"; then
+	if test "x$GCC" = "xyes"; then
+                CFLAGS="-Wall -Werror $CFLAGS"
+        fi
+	if test "x$GXX" = "xyes"; then
+		CXXFLAGS="-Wall -Werror $CXXFLAGS"
+	fi
+fi])dnl
+])# COMPILER_WARNINGS
+
+# COMPILER_OPTIMISATIONS
+# ---------------------------
+# Add configure option to disable optimisations.
+AC_DEFUN([COMPILER_OPTIMISATIONS],
+[AC_ARG_ENABLE(compiler-optimisations,
+	AS_HELP_STRING([--disable-compiler-optimisations],
+		       [Disable compiler optimisations]),
+[if test "x$enable_compiler_optimisations" = "xno"; then
+	[CFLAGS=`echo "$CFLAGS" | sed -e "s/ -O[1-9]*\b/ -O0/g"`]
+fi])dnl
+])# COMPILER_OPTIMISATIONS
+
+# COMPILER_COVERAGE
+# ----------------------
+# Add configure option to enable coverage data.
+AC_DEFUN([COMPILER_COVERAGE],
+[AC_ARG_ENABLE(compiler-coverage,
+	AS_HELP_STRING([--enable-compiler-coverage],
+		       [Enable generation of coverage data]),
+[if test "x$enable_compiler_coverage" = "xyes"; then
+	if test "x$GCC" = "xyes"; then
+		CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage"
+	fi
+fi])dnl
+])# COMPILER_COVERAGE
diff --git a/acinclude.m4 b/m4/pkg.m4
similarity index 68%
rename from acinclude.m4
rename to m4/pkg.m4
index b288925..64be747 100644
--- a/acinclude.m4
+++ b/m4/pkg.m4
@@ -153,81 +153,3 @@
 	ifelse([$3], , :, [$3])
 fi[]dnl
 ])# PKG_CHECK_MODULES
-
-
-
-dnl a macro to check for ability to create python extensions
-dnl  AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
-dnl function also defines PYTHON_INCLUDES
-AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
-[AC_REQUIRE([AM_PATH_PYTHON])
-AC_MSG_CHECKING(for headers required to compile python extensions)
-dnl deduce PYTHON_INCLUDES
-py_prefix=`$PYTHON -c "import sys; print sys.prefix"`
-py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
-PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
-if test "$py_prefix" != "$py_exec_prefix"; then
-  PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}"
-fi
-AC_SUBST(PYTHON_INCLUDES)
-dnl check if the headers exist:
-save_CPPFLAGS="$CPPFLAGS"
-CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
-AC_TRY_CPP([#include <Python.h>],dnl
-[AC_MSG_RESULT(found)
-$1],dnl
-[AC_MSG_RESULT(not found)
-$2])
-CPPFLAGS="$save_CPPFLAGS"
-])
-
-
-dnl as-ac-expand.m4 0.2.0                                   -*- autoconf -*-
-dnl autostars m4 macro for expanding directories using configure's prefix
-
-dnl (C) 2003, 2004, 2005 Thomas Vander Stichele <thomas at apestaart dot org>
-
-dnl Copying and distribution of this file, with or without modification,
-dnl are permitted in any medium without royalty provided the copyright
-dnl notice and this notice are preserved.
-
-dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
-
-dnl example:
-dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
-dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
-
-AC_DEFUN([AS_AC_EXPAND],
-[
-  EXP_VAR=[$1]
-  FROM_VAR=[$2]
-
-  dnl first expand prefix and exec_prefix if necessary
-  prefix_save=$prefix
-  exec_prefix_save=$exec_prefix
-
-  dnl if no prefix given, then use /usr/local, the default prefix
-  if test "x$prefix" = "xNONE"; then
-    prefix="$ac_default_prefix"
-  fi
-  dnl if no exec_prefix given, then use prefix
-  if test "x$exec_prefix" = "xNONE"; then
-    exec_prefix=$prefix
-  fi
-
-  full_var="$FROM_VAR"
-  dnl loop until it doesn't change anymore
-  while true; do
-    new_full_var="`eval echo $full_var`"
-    if test "x$new_full_var" = "x$full_var"; then break; fi
-    full_var=$new_full_var
-  done
-
-  dnl clean up
-  full_var=$new_full_var
-  AC_SUBST([$1], "$full_var")
-
-  dnl restore prefix and exec_prefix
-  prefix=$prefix_save
-  exec_prefix=$exec_prefix_save
-])
diff --git a/m4/tp-compiler-flag.m4 b/m4/tp-compiler-flag.m4
new file mode 100644
index 0000000..06deaba
--- /dev/null
+++ b/m4/tp-compiler-flag.m4
@@ -0,0 +1,43 @@
+dnl A version of AS_COMPILER_FLAG that supports both C and C++.
+dnl Based on:
+
+dnl as-compiler-flag.m4 0.1.0
+dnl autostars m4 macro for detection of compiler flags
+dnl David Schleef <ds@schleef.org>
+dnl $Id: as-compiler-flag.m4,v 1.1 2005/06/18 18:02:46 burgerman Exp $
+
+dnl TP_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED])
+dnl Tries to compile with the given CFLAGS and CXXFLAGS.
+dnl
+dnl Runs ACTION-IF-ACCEPTED if the compiler for the currently selected
+dnl AC_LANG can compile with the flags, and ACTION-IF-NOT-ACCEPTED otherwise.
+
+AC_DEFUN([TP_COMPILER_FLAG],
+[
+  AC_MSG_CHECKING([to see if compiler understands $1])
+
+  save_CFLAGS="$CFLAGS"
+  save_CXXFLAGS="$CXXFLAGS"
+  CFLAGS="$CFLAGS $1"
+  CXXFLAGS="$CXXFLAGS $1"
+
+  AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
+  CFLAGS="$save_CFLAGS"
+  CXXFLAGS="$save_CXXFLAGS"
+
+  if test "X$flag_ok" = Xyes ; then
+    $2
+    true
+  else
+    $3
+    true
+  fi
+  AC_MSG_RESULT([$flag_ok])
+])
+
+dnl TP_ADD_COMPILER_FLAG(VARIABLE, CFLAGS)
+dnl Append CFLAGS to VARIABLE if the compiler supports them.
+AC_DEFUN([TP_ADD_COMPILER_FLAG],
+[
+  TP_COMPILER_FLAG([$2], [$1="[$]$1 $2"])
+])
diff --git a/m4/tp-compiler-warnings.m4 b/m4/tp-compiler-warnings.m4
new file mode 100644
index 0000000..ee4af31
--- /dev/null
+++ b/m4/tp-compiler-warnings.m4
@@ -0,0 +1,49 @@
+dnl TP_COMPILER_WARNINGS(VARIABLE, WERROR_BY_DEFAULT, DESIRABLE, UNDESIRABLE)
+dnl $1 (VARIABLE): the variable to put flags into
+dnl $2 (WERROR_BY_DEFAULT): a command returning true if -Werror should be the
+dnl     default
+dnl $3 (DESIRABLE): warning flags we want (e.g. all extra shadow)
+dnl $4 (UNDESIRABLE): warning flags we don't want (e.g.
+dnl   missing-field-initializers unused-parameter)
+AC_DEFUN([TP_COMPILER_WARNINGS],
+[
+  AC_REQUIRE([AC_ARG_ENABLE])dnl
+  AC_REQUIRE([AC_HELP_STRING])dnl
+  AC_REQUIRE([TP_COMPILER_FLAG])dnl
+
+  tp_warnings=""
+  for tp_flag in $3; do
+    TP_COMPILER_FLAG([-W$tp_flag], [tp_warnings="$tp_warnings -W$tp_flag"])
+  done
+
+  tp_error_flags="-Werror"
+  TP_COMPILER_FLAG([-Werror], [tp_werror=yes], [tp_werror=no])
+
+  for tp_flag in $4; do
+    TP_COMPILER_FLAG([-Wno-$tp_flag],
+      [tp_warnings="$tp_warnings -Wno-$tp_flag"])
+dnl Yes, we do need to use both -Wno-foo and -Wno-error=foo. Simon says:
+dnl     some warnings we explicitly don't want, like unused-parameter, but
+dnl     they're in -Wall. when a distro using cdbs compiles us, we have:
+dnl       -Werror -Wno-unused-parameter      -Wall
+dnl         ^ from us                         ^ from cdbs
+dnl     which turns -Wunused-parameter back on, in effect
+    TP_COMPILER_FLAG([-Wno-error=$tp_flag],
+      [tp_error_flags="$tp_error_flags -Wno-error=$tp_flag"], [tp_werror=no])
+  done
+
+  AC_ARG_ENABLE([Werror],
+    AC_HELP_STRING([--disable-Werror],
+      [compile without -Werror (normally enabled in development builds)]),
+    tp_werror=$enableval, :)
+
+  if test "x$tp_werror" = xyes && $2; then
+dnl We put -Wno-error=foo before -Wno-foo because clang interprets -Wall
+dnl -Werror -Wno-foo -Wno-error=foo as “make foo a non-fatal warning”, but does
+dnl what we want if you reverse them.
+    $1="$tp_error_flags $tp_warnings"
+  else
+    $1="$tp_warnings"
+  fi
+
+])
diff --git a/test/.gitignore b/test/.gitignore
index f7a6587..1337de6 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -15,6 +15,7 @@
 *.gcov
 break-loader
 spawn-test
+test-corrupt
 test-exit
 test-segfault
 test-service
@@ -23,3 +24,7 @@
 shell-test
 test-shell-service
 test-names
+test-loopback
+test-relay
+test-dbus-daemon
+test-marshal
diff --git a/test/Makefile.am b/test/Makefile.am
index 58d313a..e944899 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -4,157 +4,324 @@
 SUBDIRS= . name-test 
 DIST_SUBDIRS=name-test
 
-INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS) 
+# CPPFLAGS for binaries that are normally dynamic
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	$(DBUS_STATIC_BUILD_CPPFLAGS) \
+	$(GLIB_CFLAGS) \
+	$(DBUS_GLIB_CFLAGS) \
+	$(NULL)
 
-libdbus_testutils_la_SOURCES = test-utils.h test-utils.c
+# improve backtraces from test stuff
+AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
+
+# CPPFLAGS for binaries that are always static
+static_cppflags = \
+	$(AM_CPPFLAGS) \
+	-DDBUS_STATIC_BUILD \
+	$(NULL)
+
+libdbus_testutils_la_CPPFLAGS = \
+	$(static_cppflags)
+libdbus_testutils_la_SOURCES = \
+	test-utils.c \
+	test-utils.h \
+	$(NULL)
+libdbus_testutils_la_LIBADD = \
+	$(top_builddir)/dbus/libdbus-internal.la \
+	$(NULL)
 
 noinst_LTLIBRARIES = libdbus-testutils.la
 
 if DBUS_BUILD_TESTS
 ## break-loader removed for now
-## most of these binaries are used in tests but are not themselves tests
-TEST_BINARIES=test-service test-names test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever
+## these binaries are used in tests but are not themselves tests
+TEST_BINARIES = \
+	spawn-test \
+	test-exit \
+	test-names \
+	test-segfault \
+	test-service \
+	test-shell-service \
+	test-sleep-forever \
+	$(NULL)
 
-## these are the things to run in make check (i.e. they are actual tests)
-## (binaries in here must also be in TEST_BINARIES)
-TESTS=shell-test
-else
+## These are conceptually part of directories that come earlier in SUBDIRS
+## order, but we don't want to run them til we arrive in this directory,
+## since they depend on stuff from this directory
+TESTS = \
+	../bus/bus-test$(EXEEXT) \
+	../bus/bus-test-system$(EXEEXT) \
+	../dbus/dbus-test$(EXEEXT) \
+	$(NULL)
+
+if DBUS_UNIX
+TESTS += ../bus/bus-test-launch-helper$(EXEEXT)
+endif
+
+else !DBUS_BUILD_TESTS
+
 TEST_BINARIES=
 TESTS=
-endif
 
-if DBUS_GCOV_ENABLED
-GCOV_BINARIES=decode-gcov
-else
-GCOV_BINARIES=
-endif
+endif !DBUS_BUILD_TESTS
 
-noinst_PROGRAMS= $(TEST_BINARIES) $(GCOV_BINARIES)
+noinst_PROGRAMS= $(TEST_BINARIES)
 
-test_service_SOURCES=				\
-	test-service.c
+test_service_CPPFLAGS = $(static_cppflags)
+test_service_LDADD = libdbus-testutils.la
+test_names_CPPFLAGS = $(static_cppflags)
+test_names_LDADD = libdbus-testutils.la
+## break_loader_CPPFLAGS = $(static_cppflags)
+## break_loader_LDADD = $(top_builddir)/dbus/libdbus-internal.la
+test_shell_service_CPPFLAGS = $(static_cppflags)
+test_shell_service_LDADD = libdbus-testutils.la
+shell_test_CPPFLAGS = $(static_cppflags)
+shell_test_LDADD = libdbus-testutils.la
+spawn_test_CPPFLAGS = $(static_cppflags)
+spawn_test_LDADD = $(top_builddir)/dbus/libdbus-internal.la
 
-test_names_SOURCES=				\
-	test-names.c
+test_refs_SOURCES = internals/refs.c
+test_refs_CPPFLAGS = $(static_cppflags)
+test_refs_LDADD = libdbus-testutils.la $(GLIB_LIBS)
 
-##break_loader_SOURCES=				\
-##	break-loader.c
+test_syslog_SOURCES = internals/syslog.c
+test_syslog_CPPFLAGS = $(static_cppflags)
+test_syslog_LDADD = libdbus-testutils.la $(GLIB_LIBS)
 
-test_shell_service_SOURCES =			\
-	test-shell-service.c
+EXTRA_DIST = dbus-test-runner
 
-shell_test_SOURCES=                             \
-        shell-test.c
+testexecdir = $(libdir)/dbus-1.0/test
 
-spawn_test_SOURCES=				\
-	spawn-test.c
+testexec_PROGRAMS =
 
-test_exit_SOURCES =				\
-	test-exit.c
+installable_tests = \
+	shell-test \
+	$(NULL)
 
-test_segfault_SOURCES =				\
-	test-segfault.c
+if DBUS_WITH_GLIB
+installable_tests += \
+	test-corrupt \
+	test-dbus-daemon \
+	test-dbus-daemon-eavesdrop \
+	test-loopback \
+	test-marshal \
+	test-refs \
+	test-relay \
+	test-syntax \
+	test-syslog \
+	$(NULL)
+endif DBUS_WITH_GLIB
 
-test_sleep_forever_SOURCES =			\
-	test-sleep-forever.c
+installcheck_tests =
+installcheck_environment = \
+	DBUS_TEST_DAEMON=$(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon$(EXEEXT) \
+	DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus \
+	DBUS_TEST_SYSCONFDIR=$(DESTDIR)$(sysconfdir)
 
-decode_gcov_SOURCES=				\
-	decode-gcov.c
+TESTS_ENVIRONMENT = \
+	DBUS_BLOCK_ON_ABORT=1 \
+	DBUS_FATAL_WARNINGS=1 \
+	DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT) \
+	DBUS_TEST_DATA=@abs_top_builddir@/test/data \
+	DBUS_TEST_HOMEDIR=@abs_top_builddir@/dbus \
+	$(NULL)
 
-# When any programs are not linked to libdbus-internal, fix this.
-AM_CPPFLAGS=-DDBUS_STATIC_BUILD
-TEST_LIBS=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_TEST_LIBS)
+test_corrupt_SOURCES = corrupt.c
+test_corrupt_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+    $(GLIB_LIBS) \
+    $(DBUS_GLIB_LIBS)
 
-test_service_LDADD=libdbus-testutils.la $(TEST_LIBS)
-test_service_LDFLAGS=@R_DYNAMIC_LDFLAG@
-test_names_LDADD=libdbus-testutils.la $(TEST_LIBS)
-test_names_LDFLAGS=@R_DYNAMIC_LDFLAG@
-## break_loader_LDADD= $(TEST_LIBS)
-## break_loader_LDFLAGS=@R_DYNAMIC_LDFLAG@
-test_shell_service_LDADD=libdbus-testutils.la $(TEST_LIBS)
-test_shell_service_LDFLAGS=@R_DYNAMIC_LDFLAG@
-shell_test_LDADD=libdbus-testutils.la $(TEST_LIBS)
-shell_test_LDFLAGS=@R_DYNAMIC_LDFLAG@
-spawn_test_LDADD=$(TEST_LIBS)
-spawn_test_LDFLAGS=@R_DYNAMIC_LDFLAG@
-decode_gcov_LDADD=$(TEST_LIBS)
-decode_gcov_LDFLAGS=@R_DYNAMIC_LDFLAG@
+test_loopback_SOURCES = loopback.c
+test_loopback_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+    $(GLIB_LIBS) \
+    $(DBUS_GLIB_LIBS)
 
-EXTRA_DIST=
+test_relay_SOURCES = relay.c
+test_relay_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+    $(GLIB_LIBS) \
+    $(DBUS_GLIB_LIBS)
 
-## keep these in creation order, i.e. uppermost dirs first 
-TESTDIRS=					\
-	data					\
-	data/valid-messages			\
-	data/invalid-messages			\
-	data/incomplete-messages		\
-	data/auth				\
-	data/sha-1				\
-	data/valid-config-files			\
-	data/valid-config-files-system		\
-	data/valid-config-files/basic.d		\
-	data/valid-config-files/session.d	\
-	data/valid-config-files/system.d	\
-	data/valid-service-files		\
-	data/valid-service-files-system		\
-	data/invalid-service-files-system	\
-	data/invalid-config-files		\
-	data/invalid-config-files-system	\
-	data/equiv-config-files			\
-	data/equiv-config-files/basic		\
-	data/equiv-config-files/basic/basic.d	\
-	data/equiv-config-files/entities	\
-	data/equiv-config-files/entities/basic.d
+test_dbus_daemon_SOURCES = dbus-daemon.c
+test_dbus_daemon_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+    $(GLIB_LIBS) \
+    $(DBUS_GLIB_LIBS)
 
+test_dbus_daemon_eavesdrop_SOURCES = dbus-daemon-eavesdrop.c
+test_dbus_daemon_eavesdrop_CPPFLAGS = $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS)
+test_dbus_daemon_eavesdrop_LDFLAGS = @R_DYNAMIC_LDFLAG@
+test_dbus_daemon_eavesdrop_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+    $(GLIB_LIBS) \
+    $(DBUS_GLIB_LIBS)
 
-FIND_TESTS=find . -type f -a \( -name "*.message" -o -name "*.message-raw" -o -name "*.auth-script" -o -name "*.sha1" -o -name "*.txt" -o -name "*.conf" -o -name "*.service" \)
+test_marshal_SOURCES = marshal.c
+test_marshal_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+    $(GLIB_LIBS) \
+    $(DBUS_GLIB_LIBS)
 
-dist-hook:
-	for D in $(TESTDIRS); do						\
-		test -d $(distdir)/$$D || mkdir $(distdir)/$$D || exit 1 ;	\
-	done ;									\
-	FILES=`(cd $(srcdir) && $(FIND_TESTS) -o -name "*.in" -a -not -name Makefile.in | grep -Ev "(.svn|CVS)" )` ;					\
-        for F in $$FILES; do							\
-                echo '-- Disting file '$$F ;					\
-		cp -f $(srcdir)/$$F $(distdir)/$$F || exit 1 ;				\
-	done
+test_syntax_SOURCES = syntax.c
+test_syntax_LDADD = $(top_builddir)/dbus/libdbus-1.la \
+    $(GLIB_LIBS)
 
-## copy tests to builddir so that generated tests and static tests 
+if DBUS_ENABLE_MODULAR_TESTS
+TESTS += $(installable_tests)
+installcheck_tests += $(installable_tests)
+
+if DBUS_ENABLE_INSTALLED_TESTS
+  testexec_PROGRAMS += $(installable_tests)
+else !DBUS_ENABLE_INSTALLED_TESTS
+  noinst_PROGRAMS += $(installable_tests)
+endif !DBUS_ENABLE_INSTALLED_TESTS
+
+endif DBUS_ENABLE_MODULAR_TESTS
+
+# If we're installing the tests into a DESTDIR we can't run them
+# again using the installed copy, because we don't know how to
+# do a portable equivalent of setting LD_LIBRARY_PATH.
+installcheck-local:
+	$(MAKE) check-TESTS TESTS='$$(installcheck_tests)' \
+		TESTS_ENVIRONMENT='$$(installcheck_environment)'
+if DBUS_ENABLE_INSTALLED_TESTS
+	test -n "$(DESTDIR)" || \
+	$(installcheck_environment) \
+		$(srcdir)/dbus-test-runner \
+		$(testexecdir) \
+		$(testexec_PROGRAMS)
+endif DBUS_ENABLE_INSTALLED_TESTS
+
+in_data = \
+	data/valid-config-files-system/debug-allow-all-fail.conf.in \
+	data/valid-config-files-system/debug-allow-all-pass.conf.in \
+	data/valid-config-files/debug-allow-all-sha1.conf.in \
+	data/valid-config-files/debug-allow-all.conf.in \
+	data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \
+	data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \
+	data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in \
+	data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in \
+	data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in \
+	data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in \
+	data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in \
+	data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in \
+	data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in \
+	data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in \
+	data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in \
+	data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in \
+	data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in \
+	$(NULL)
+
+EXTRA_DIST += $(in_data)
+
+static_data = \
+	name-test/tmp-session-like-system.conf \
+	data/auth/anonymous-client-successful.auth-script \
+	data/auth/anonymous-server-successful.auth-script \
+	data/auth/cancel.auth-script \
+	data/auth/client-out-of-mechanisms.auth-script \
+	data/auth/external-failed.auth-script \
+	data/auth/external-root.auth-script \
+	data/auth/external-silly.auth-script \
+	data/auth/external-successful.auth-script \
+	data/auth/extra-bytes.auth-script \
+	data/auth/fail-after-n-attempts.auth-script \
+	data/auth/fallback.auth-script \
+	data/auth/invalid-command-client.auth-script \
+	data/auth/invalid-command.auth-script \
+	data/auth/invalid-hex-encoding.auth-script \
+	data/auth/mechanisms.auth-script \
+	data/equiv-config-files/basic/basic-1.conf \
+	data/equiv-config-files/basic/basic-2.conf \
+	data/equiv-config-files/basic/basic.d/basic.conf \
+	data/equiv-config-files/entities/basic.d/basic.conf \
+	data/equiv-config-files/entities/entities-1.conf \
+	data/equiv-config-files/entities/entities-2.conf \
+	data/incomplete-messages/missing-body.message \
+	data/invalid-config-files/badselinux-1.conf \
+	data/invalid-config-files/badselinux-2.conf \
+	data/invalid-config-files/circular-1.conf \
+	data/invalid-config-files/circular-2.conf \
+	data/invalid-config-files/circular-3.conf \
+	data/invalid-config-files/not-well-formed.conf \
+	data/invalid-config-files/truncated-file.conf \
+	data/invalid-messages/array-of-nil.message \
+	data/invalid-messages/array-with-mixed-types.message \
+	data/invalid-messages/bad-boolean-array.message \
+	data/invalid-messages/bad-boolean.message \
+	data/invalid-messages/bad-endian.message \
+	data/invalid-messages/bad-header-field-alignment.message \
+	data/invalid-messages/boolean-has-no-value.message-raw \
+	data/invalid-messages/local-namespace.message \
+	data/invalid-messages/no-dot-in-name.message \
+	data/invalid-messages/not-nul-header-padding.message \
+	data/invalid-messages/overlong-name.message \
+	data/invalid-messages/too-little-header-padding.message \
+	data/invalid-messages/too-much-header-padding-by-far.message \
+	data/invalid-messages/too-much-header-padding.message \
+	data/invalid-messages/too-short-dict.message \
+	data/sha-1/Readme.txt \
+	data/sha-1/bit-hashes.sha1 \
+	data/sha-1/bit-messages.sha1 \
+	data/sha-1/byte-hashes.sha1 \
+	data/sha-1/byte-messages.sha1 \
+	data/valid-config-files/basic.conf \
+	data/valid-config-files/basic.d/basic.conf \
+	data/valid-config-files/entities.conf \
+	data/valid-config-files/incoming-limit.conf \
+	data/valid-config-files/many-rules.conf \
+	data/valid-config-files/system.d/test.conf \
+	data/valid-messages/array-of-array-of-uint32.message \
+	data/valid-messages/dict-simple.message \
+	data/valid-messages/dict.message \
+	data/valid-messages/emptiness.message \
+	data/valid-messages/lots-of-arguments.message \
+	data/valid-messages/no-padding.message \
+	data/valid-messages/opposite-endian.message \
+	data/valid-messages/recursive-types.message \
+	data/valid-messages/simplest-manual.message \
+	data/valid-messages/simplest.message \
+	data/valid-messages/standard-acquire-service.message \
+	data/valid-messages/standard-hello.message \
+	data/valid-messages/standard-list-services.message \
+	data/valid-messages/standard-service-exists.message \
+	data/valid-messages/unknown-header-field.message \
+	$(NULL)
+
+EXTRA_DIST += $(static_data)
+
+## copy tests to builddir so that generated tests and static tests
 ## are all in one place.
 all-local:
-	for D in $(TESTDIRS); do								\
-		test -d $(top_builddir)/test/$$D || mkdir $(top_builddir)/test/$$D || exit 1 ;	\
-	done ;											\
-	if ! (test $(srcdir) = . || test $(srcdir) -ef .) ; then								\
-		FILES=`(cd $(srcdir) && $(FIND_TESTS) | grep -Ev "(.svn|CVS)" )` ;					\
-	        for F in $$FILES; do								\
-			SRC=$(srcdir)/$$F ;							\
-			DEST=$(top_builddir)/test/$$F ;						\
-	                echo '-- Copying test file '$$F ;					\
-			cp $$SRC $$DEST || exit 1 ;						\
-			chmod u+w $$DEST || exit 1 ;						\
-		done ;										\
-	else											\
-		echo '-- No need to copy test data as srcdir = builddir' ;			\
-	fi ;											\
-	echo '-- Copying' $(top_builddir)/bus/*.conf 'to test directory' ;			\
-	cp $(top_builddir)/bus/*.conf $(top_builddir)/test/data/valid-config-files || exit 1 ;  \
-	chmod u+w $(top_builddir)/test/data/valid-config-files/*.conf || exit 1
-
-## this doesn't clean generated test data files when srcdir=builddir
-clean-local:
-	if test $(srcdir) != . ; then					\
-		FILES=`(cd $(top_builddir)/test && $(FIND_TESTS) | grep -Ev "(.svn|CVS)" )` ;	\
-	        for F in $$FILES; do					\
-			DEST=$(top_builddir)/test/$$F ;			\
-	                echo '-- Deleting test file '$$F ;		\
-			rm $$DEST || exit 1 ;				\
-		done ;							\
-		REVERSEDIRS= ;						\
-		for D in $(TESTDIRS); do				\
-			REVERSEDIRS="$$D $$REVERSEDIRS" ;		\
-		done ;							\
-		for D in $$REVERSEDIRS; do				\
-			rmdir $(top_builddir)/test/$$D || exit 1 ;	\
-		done ;							\
+	$(AM_V_at)$(MKDIR_P) data/valid-config-files/session.d
+	$(AM_V_at)set -e && \
+	if test $(srcdir) = . || test $(srcdir) -ef .; then \
+		echo '-- No need to copy test data as srcdir = builddir'; \
+	else \
+		for F in $(static_data); do \
+			$(MKDIR_P) $${F%/*}; \
+			rm -f $$F; \
+			cp $(srcdir)/$$F $$F; \
+		done; \
 	fi
+
+## this doesn't clean most copied test data files when srcdir=builddir
+clean-local:
+	$(AM_V_at)if test $(srcdir) = . || test $(srcdir) -ef .; then \
+		echo '-- No need to clean test data as srcdir = builddir'; \
+	else \
+		rm -f $(static_data); \
+	fi
+
+imported_data = \
+	data/valid-config-files/session.conf \
+	data/valid-config-files/system.conf \
+	$(NULL)
+
+noinst_DATA = $(imported_data)
+CLEANFILES = $(noinst_DATA)
+
+data/valid-config-files/session.conf: $(top_builddir)/bus/session.conf
+	$(AM_V_at)$(MKDIR_P) data/valid-config-files
+	$(AM_V_GEN)cp $< $@
+
+data/valid-config-files/system.conf: $(top_builddir)/bus/system.conf
+	$(AM_V_at)$(MKDIR_P) data/valid-config-files
+	$(AM_V_GEN)cp $< $@
diff --git a/test/break-loader.c b/test/break-loader.c
index 7bfa722..e62b8c2 100644
--- a/test/break-loader.c
+++ b/test/break-loader.c
@@ -446,7 +446,7 @@
     {
       int b;
       b = _dbus_string_get_byte (mutated, i);
-      if (_dbus_type_is_valid (b))
+      if (dbus_type_is_valid (b))
         {
           _dbus_string_set_byte (mutated, i, random_type ());
           return;
@@ -667,7 +667,7 @@
 
     fprintf (stderr, "could not open/read /dev/urandom, using current time for seed\n");
 
-    _dbus_get_current_time (NULL, &tv_usec);
+    _dbus_get_monotonic_time (NULL, &tv_usec);
 
     seed = tv_usec;
   }
diff --git a/test/corrupt.c b/test/corrupt.c
new file mode 100644
index 0000000..0249590
--- /dev/null
+++ b/test/corrupt.c
@@ -0,0 +1,376 @@
+/* Regression test for being disconnected by a corrupt message (fd.o #15578)
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2010-2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+typedef struct {
+    DBusError e;
+
+    DBusServer *server;
+    DBusConnection *server_conn;
+    /* queue of DBusMessage */
+    GQueue client_messages;
+
+    DBusConnection *client_conn;
+} Fixture;
+
+static void
+assert_no_error (const DBusError *e)
+{
+  if (G_UNLIKELY (dbus_error_is_set (e)))
+    g_error ("expected success but got error: %s: %s", e->name, e->message);
+}
+
+static DBusHandlerResult
+client_message_cb (DBusConnection *client_conn,
+    DBusMessage *message,
+    void *data)
+{
+  Fixture *f = data;
+
+  g_assert (client_conn == f->client_conn);
+  g_queue_push_tail (&f->client_messages, dbus_message_ref (message));
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+new_conn_cb (DBusServer *server,
+    DBusConnection *server_conn,
+    void *data)
+{
+  Fixture *f = data;
+
+  g_assert (f->server_conn == NULL);
+  f->server_conn = dbus_connection_ref (server_conn);
+  dbus_connection_setup_with_g_main (server_conn, NULL);
+}
+
+static void
+setup (Fixture *f,
+    gconstpointer addr)
+{
+  dbus_error_init (&f->e);
+  g_queue_init (&f->client_messages);
+
+  f->server = dbus_server_listen (addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->server != NULL);
+
+  dbus_server_set_new_connection_function (f->server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->server, NULL);
+}
+
+static void
+test_connect (Fixture *f,
+    gconstpointer addr G_GNUC_UNUSED)
+{
+  dbus_bool_t have_mem;
+
+  g_assert (f->server_conn == NULL);
+
+  f->client_conn = dbus_connection_open_private (
+      dbus_server_get_address (f->server), &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->client_conn != NULL);
+  dbus_connection_setup_with_g_main (f->client_conn, NULL);
+
+  while (f->server_conn == NULL)
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+
+  have_mem = dbus_connection_add_filter (f->client_conn,
+      client_message_cb, f, NULL);
+  g_assert (have_mem);
+}
+
+static void
+test_message (Fixture *f,
+    gconstpointer addr)
+{
+  dbus_bool_t have_mem;
+  dbus_uint32_t serial;
+  DBusMessage *outgoing, *incoming;
+
+  test_connect (f, addr);
+
+  outgoing = dbus_message_new_signal ("/com/example/Hello",
+      "com.example.Hello", "Greeting");
+  g_assert (outgoing != NULL);
+
+  have_mem = dbus_connection_send (f->server_conn, outgoing, &serial);
+  g_assert (have_mem);
+  g_assert (serial != 0);
+
+  while (g_queue_is_empty (&f->client_messages))
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+
+  g_assert_cmpuint (g_queue_get_length (&f->client_messages), ==, 1);
+
+  incoming = g_queue_pop_head (&f->client_messages);
+
+  g_assert (!dbus_message_contains_unix_fds (incoming));
+  g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
+      "com.example.Hello");
+  g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
+  g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_signature (incoming), ==, "");
+  g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello");
+  g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial);
+
+  dbus_message_unref (incoming);
+
+  dbus_message_unref (outgoing);
+}
+
+static void
+send_n_bytes (GSocket *socket,
+              const gchar *blob,
+              gssize blob_len)
+{
+  gssize len, total_sent;
+  GError *gerror = NULL;
+
+  total_sent = 0;
+
+  while (total_sent < blob_len)
+    {
+      len = g_socket_send (socket,
+                           blob + total_sent,
+                           blob_len - total_sent,
+                           NULL, &gerror);
+
+      /* this is NULL-safe: a NULL error does not match */
+      if (g_error_matches (gerror, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+        {
+          /* we could wait for G_IO_OUT, but life's too short; just sleep */
+          g_clear_error (&gerror);
+          g_usleep (G_USEC_PER_SEC / 10);
+          continue;
+        }
+
+      g_assert_no_error (gerror);
+      g_assert (len >= 0);
+      total_sent += len;
+    }
+}
+
+/* Enough bytes for it to be obvious that this connection is broken */
+#define CORRUPT_LEN 1024
+
+/* All-zero is not a valid D-Bus message header - for a start, this is
+ * protocol version 1, not 0 */
+static const gchar not_a_dbus_message[CORRUPT_LEN] = { 0 };
+
+static void
+test_corrupt (Fixture *f,
+    gconstpointer addr)
+{
+  GSocket *socket;
+  GError *gerror = NULL;
+  int fd;
+  DBusMessage *incoming;
+
+  test_message (f, addr);
+
+  dbus_connection_flush (f->server_conn);
+
+  /* OK, now the connection is working, let's break it! Don't try this
+   * at home; splicing arbitrary bytes into the middle of the stream is
+   * specifically documented as not a valid thing to do. Who'd have thought? */
+  if (!dbus_connection_get_socket (f->server_conn, &fd))
+    g_error ("failed to steal fd from server connection");
+
+  socket = g_socket_new_from_fd (fd, &gerror);
+  g_assert_no_error (gerror);
+  g_assert (socket != NULL);
+
+  send_n_bytes (socket, not_a_dbus_message, CORRUPT_LEN);
+
+  /* Now spin on the client connection: the server just sent it complete
+   * rubbish, so it should disconnect */
+  while (g_queue_is_empty (&f->client_messages))
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+
+  incoming = g_queue_pop_head (&f->client_messages);
+
+  g_assert (!dbus_message_contains_unix_fds (incoming));
+  g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
+      "org.freedesktop.DBus.Local");
+  g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Disconnected");
+  g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_signature (incoming), ==, "");
+  g_assert_cmpstr (dbus_message_get_path (incoming), ==,
+      "/org/freedesktop/DBus/Local");
+
+  dbus_message_unref (incoming);
+  g_object_unref (socket);
+}
+
+static void
+test_byte_order (Fixture *f,
+    gconstpointer addr)
+{
+  GSocket *socket;
+  GError *gerror = NULL;
+  int fd;
+  char *blob;
+  const gchar *arg = not_a_dbus_message;
+  const gchar * const *args = &arg;
+  int blob_len;
+  DBusMessage *message;
+  dbus_bool_t mem;
+
+  test_message (f, addr);
+
+  message = dbus_message_new_signal ("/", "a.b", "c");
+  g_assert (message != NULL);
+  /* Append 0xFF bytes, so that the length of the body when byte-swapped
+   * is 0xFF000000, which is invalid */
+  mem = dbus_message_append_args (message,
+      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &args, 0xFF,
+      DBUS_TYPE_INVALID);
+  g_assert (mem);
+  mem = dbus_message_marshal (message, &blob, &blob_len);
+  g_assert (mem);
+  g_assert_cmpuint (blob_len, >, 0xFF);
+  g_assert (blob != NULL);
+
+  dbus_message_unref (message);
+
+  /* Break the message by changing its claimed byte order, without actually
+   * byteswapping anything. We happen to know that byte order is the first
+   * byte. */
+  if (blob[0] == 'B')
+    blob[0] = 'l';
+  else
+    blob[0] = 'B';
+
+  /* OK, now the connection is working, let's break it */
+
+  dbus_connection_flush (f->server_conn);
+
+  if (!dbus_connection_get_socket (f->server_conn, &fd))
+    g_error ("failed to steal fd from server connection");
+
+  socket = g_socket_new_from_fd (fd, &gerror);
+  g_assert_no_error (gerror);
+  g_assert (socket != NULL);
+
+  send_n_bytes (socket, blob, blob_len);
+
+  dbus_free (blob);
+
+  /* Now spin on the client connection: the server just sent it a faulty
+   * message, so it should disconnect */
+  while (g_queue_is_empty (&f->client_messages))
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+
+  message = g_queue_pop_head (&f->client_messages);
+
+  g_assert (!dbus_message_contains_unix_fds (message));
+  g_assert_cmpstr (dbus_message_get_destination (message), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_error_name (message), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_interface (message), ==,
+      "org.freedesktop.DBus.Local");
+  g_assert_cmpstr (dbus_message_get_member (message), ==, "Disconnected");
+  g_assert_cmpstr (dbus_message_get_sender (message), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_signature (message), ==, "");
+  g_assert_cmpstr (dbus_message_get_path (message), ==,
+      "/org/freedesktop/DBus/Local");
+
+  dbus_message_unref (message);
+  g_object_unref (socket);
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer addr G_GNUC_UNUSED)
+{
+  if (f->client_conn != NULL)
+    {
+      dbus_connection_close (f->client_conn);
+      dbus_connection_unref (f->client_conn);
+      f->client_conn = NULL;
+    }
+
+  if (f->server_conn != NULL)
+    {
+      dbus_connection_close (f->server_conn);
+      dbus_connection_unref (f->server_conn);
+      f->server_conn = NULL;
+    }
+
+  if (f->server != NULL)
+    {
+      dbus_server_disconnect (f->server);
+      dbus_server_unref (f->server);
+      f->server = NULL;
+    }
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_type_init ();
+
+  g_test_add ("/corrupt/tcp", Fixture, "tcp:host=127.0.0.1", setup,
+      test_corrupt, teardown);
+
+#ifdef DBUS_UNIX
+  g_test_add ("/corrupt/unix", Fixture, "unix:tmpdir=/tmp", setup,
+      test_corrupt, teardown);
+#endif
+
+  g_test_add ("/corrupt/byte-order/tcp", Fixture, "tcp:host=127.0.0.1", setup,
+      test_byte_order, teardown);
+
+  return g_test_run ();
+}
diff --git a/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in b/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in
index 16ace26..7822ffc 100644
--- a/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in
+++ b/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in
@@ -1,4 +1,4 @@
 [D-BUS Service]
-Exec=@TEST_SERVICE_BINARY@
+Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@
 User=anyrandomuser
 
diff --git a/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in b/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in
index 01b898c..691e009 100644
--- a/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in
+++ b/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in
@@ -1,4 +1,3 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteNoUser
-Exec=@TEST_SERVICE_BINARY@
-
+Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@
diff --git a/test/data/valid-config-files-system/debug-allow-all-fail.conf.cmake b/test/data/valid-config-files-system/debug-allow-all-fail.conf.cmake
deleted file mode 100644
index 0c73d8c..0000000
--- a/test/data/valid-config-files-system/debug-allow-all-fail.conf.cmake
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->
-
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-  <listen>@TEST_LISTEN@</listen>
-  <type>system</type>
-  <servicehelper>@TEST_LAUNCH_HELPER_BINARY@</servicehelper>
-  <servicedir>@TEST_INVALID_SERVICE_SYSTEM_DIR@</servicedir>
-  <policy context="default">
-    <allow send_interface="*"/>
-    <allow receive_interface="*"/>
-    <allow own="*"/>
-    <allow user="*"/>
-  </policy>
-</busconfig>
diff --git a/test/data/valid-config-files-system/debug-allow-all-fail.conf.in b/test/data/valid-config-files-system/debug-allow-all-fail.conf.in
index 93a548c..bab178f 100644
--- a/test/data/valid-config-files-system/debug-allow-all-fail.conf.in
+++ b/test/data/valid-config-files-system/debug-allow-all-fail.conf.in
@@ -4,10 +4,10 @@
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 <busconfig>
   <listen>debug-pipe:name=test-server</listen>
-  <listen>unix:tmpdir=@TEST_SOCKET_DIR@</listen>
+  <listen>@TEST_LISTEN@</listen>
   <type>system</type>
   <servicehelper>@TEST_LAUNCH_HELPER_BINARY@</servicehelper>
-  <servicedir>@TEST_INVALID_SERVICE_SYSTEM_DIR@</servicedir>
+  <servicedir>@DBUS_TEST_DATA@/invalid-service-files-system</servicedir>
   <policy context="default">
     <allow send_interface="*"/>
     <allow receive_interface="*"/>
diff --git a/test/data/valid-config-files-system/debug-allow-all-pass.conf.cmake b/test/data/valid-config-files-system/debug-allow-all-pass.conf.cmake
deleted file mode 100644
index d46ec18..0000000
--- a/test/data/valid-config-files-system/debug-allow-all-pass.conf.cmake
+++ /dev/null
@@ -1,16 +0,0 @@
-<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->
-
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-  <listen>@TEST_LISTEN@</listen>
-  <type>system</type>
-  <servicehelper>@TEST_LAUNCH_HELPER_BINARY@</servicehelper>
-  <servicedir>@TEST_VALID_SERVICE_SYSTEM_DIR@</servicedir>
-  <policy context="default">
-    <allow send_interface="*"/>
-    <allow receive_interface="*"/>
-    <allow own="*"/>
-    <allow user="*"/>
-  </policy>
-</busconfig>
diff --git a/test/data/valid-config-files-system/debug-allow-all-pass.conf.in b/test/data/valid-config-files-system/debug-allow-all-pass.conf.in
index 5b7ffd1..3836673 100644
--- a/test/data/valid-config-files-system/debug-allow-all-pass.conf.in
+++ b/test/data/valid-config-files-system/debug-allow-all-pass.conf.in
@@ -4,10 +4,10 @@
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 <busconfig>
   <listen>debug-pipe:name=test-server</listen>
-  <listen>unix:tmpdir=@TEST_SOCKET_DIR@</listen>
+  <listen>@TEST_LISTEN@</listen>
   <type>system</type>
   <servicehelper>@TEST_LAUNCH_HELPER_BINARY@</servicehelper>
-  <servicedir>@TEST_VALID_SERVICE_SYSTEM_DIR@</servicedir>
+  <servicedir>@DBUS_TEST_DATA@/valid-service-files-system</servicedir>
   <policy context="default">
     <allow send_interface="*"/>
     <allow receive_interface="*"/>
diff --git a/test/data/valid-config-files/check-own-rules.conf b/test/data/valid-config-files/check-own-rules.conf
new file mode 100644
index 0000000..bc2f415
--- /dev/null
+++ b/test/data/valid-config-files/check-own-rules.conf
@@ -0,0 +1,14 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <user>mybususer</user>
+  <listen>unix:path=/foo/bar</listen>
+  <listen>tcp:port=1234</listen>
+  <servicedir>/usr/share/foo</servicedir>
+  <policy context="default">
+    <allow user="*"/>
+    <deny own="*"/>
+    <allow own_prefix="org.freedesktop.ManySystems"/>
+  </policy>
+
+</busconfig>
diff --git a/test/data/valid-config-files/debug-allow-all-sha1.conf.cmake b/test/data/valid-config-files/debug-allow-all-sha1.conf.cmake
deleted file mode 100644
index 416267c..0000000
--- a/test/data/valid-config-files/debug-allow-all-sha1.conf.cmake
+++ /dev/null
@@ -1,15 +0,0 @@
-<!-- Bus that listens on a debug pipe and requires SHA1 auth, used to test SHA1 -->
-
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-  <listen>@TEST_LISTEN@</listen>
-  <servicedir>@TEST_VALID_SERVICE_DIR@</servicedir>
-  <auth>DBUS_COOKIE_SHA1</auth>
-  <policy context="default">
-    <allow send_interface="*"/>
-    <allow receive_interface="*"/>
-    <allow own="*"/>
-    <allow user="*"/>
-  </policy>
-</busconfig>
diff --git a/test/data/valid-config-files/debug-allow-all-sha1.conf.in b/test/data/valid-config-files/debug-allow-all-sha1.conf.in
index 34c5085..8baee7d 100644
--- a/test/data/valid-config-files/debug-allow-all-sha1.conf.in
+++ b/test/data/valid-config-files/debug-allow-all-sha1.conf.in
@@ -4,8 +4,8 @@
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 <busconfig>
   <listen>debug-pipe:name=test-server</listen>
-  <listen>unix:tmpdir=@TEST_SOCKET_DIR@</listen>
-  <servicedir>@TEST_VALID_SERVICE_DIR@</servicedir>
+  <listen>@TEST_LISTEN@</listen>
+  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
   <auth>DBUS_COOKIE_SHA1</auth>
   <policy context="default">
     <allow send_interface="*"/>
diff --git a/test/data/valid-config-files/debug-allow-all.conf.cmake b/test/data/valid-config-files/debug-allow-all.conf.cmake
deleted file mode 100644
index 94bb21e..0000000
--- a/test/data/valid-config-files/debug-allow-all.conf.cmake
+++ /dev/null
@@ -1,14 +0,0 @@
-<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->
-
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-<busconfig>
-  <listen>@TEST_LISTEN@</listen>
-  <servicedir>@TEST_VALID_SERVICE_DIR@</servicedir>
-  <policy context="default">
-    <allow send_interface="*"/>
-    <allow receive_interface="*"/>
-    <allow own="*"/>
-    <allow user="*"/>
-  </policy>
-</busconfig>
diff --git a/test/data/valid-config-files/debug-allow-all.conf.in b/test/data/valid-config-files/debug-allow-all.conf.in
index 3514296..00df20d 100644
--- a/test/data/valid-config-files/debug-allow-all.conf.in
+++ b/test/data/valid-config-files/debug-allow-all.conf.in
@@ -4,8 +4,8 @@
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
 <busconfig>
   <listen>debug-pipe:name=test-server</listen>
-  <listen>unix:tmpdir=@TEST_SOCKET_DIR@</listen>
-  <servicedir>@TEST_VALID_SERVICE_DIR@</servicedir>
+  <listen>@TEST_LISTEN@</listen>
+  <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
   <policy context="default">
     <allow send_interface="*"/>
     <allow receive_interface="*"/>
diff --git a/test/data/valid-config-files/incoming-limit.conf b/test/data/valid-config-files/incoming-limit.conf
new file mode 100644
index 0000000..abfab3f
--- /dev/null
+++ b/test/data/valid-config-files/incoming-limit.conf
@@ -0,0 +1,18 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+  <!-- Our well-known bus type, don't change this -->
+  <type>session</type>
+  <listen>unix:tmpdir=/tmp</listen>
+
+  <policy context="default">
+    <!-- Allow everything to be sent -->
+    <allow send_destination="*" eavesdrop="true"/>
+    <!-- Allow everything to be received -->
+    <allow eavesdrop="true"/>
+    <!-- Allow anyone to own anything -->
+    <allow own="*"/>
+  </policy>
+
+  <limit name="max_incoming_bytes">1</limit>
+</busconfig>
diff --git a/test/data/valid-config-files/many-rules.conf b/test/data/valid-config-files/many-rules.conf
index 0a15e83..2393162 100644
--- a/test/data/valid-config-files/many-rules.conf
+++ b/test/data/valid-config-files/many-rules.conf
@@ -14,10 +14,11 @@
     <deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
     <deny send_path="/foo/bar/SystemObjectThing" send_member="Reboot"/> 
     <deny own="org.freedesktop.System"/>
+    <deny own_prefix="org.freedesktop.ManySystems"/>
     <deny send_destination="org.freedesktop.System"/>
     <deny receive_sender="org.freedesktop.System"/>
     <deny user="root"/>
-    <deny group="root"/>
+    <deny group="bin"/>
     <allow send_type="error"/>
     <allow send_type="method_call"/>
     <allow send_type="method_return"/>
@@ -32,10 +33,11 @@
     <deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
     <deny send_path="/foo/bar/SystemObjectThing" send_member="Reboot"/> 
     <deny own="org.freedesktop.System"/>
+    <deny own_prefix="org.freedesktop.ManySystems"/>
     <deny send_destination="org.freedesktop.System"/>
     <deny receive_sender="org.freedesktop.System"/>
     <deny user="root"/>
-    <deny group="root"/>
+    <deny group="bin"/>
     <allow send_type="error"/>
     <allow send_type="method_call"/>
     <allow send_type="method_return"/>
diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in
index bd0e58e..3076f3b 100644
--- a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in
+++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service.in
@@ -1,5 +1,5 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteEchoService
-Exec=@TEST_SERVICE_BINARY@
+Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@
 User=anyrandomuser
 
diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in
index 18d16d1..705d714 100644
--- a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in
+++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service.in
@@ -1,5 +1,5 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteSegfaultService
-Exec=@TEST_SEGFAULT_BINARY@
+Exec=@DBUS_TEST_EXEC@/test-segfault@EXEEXT@
 User=anyrandomuser
 
diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in
index 9195e17..870835e 100644
--- a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in
+++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in
@@ -1,5 +1,5 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteShellEchoServiceFail
-Exec=@TEST_SHELL_SERVICE_BINARY@ "this should 'fail' because of an unterminated quote 
+Exec=@DBUS_TEST_EXEC@/test-shell-service@EXEEXT@ "this should 'fail' because of an unterminated quote
 User=anyrandomuser
 
diff --git a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in
index 2236ce5..6647261 100644
--- a/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in
+++ b/test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in
@@ -1,5 +1,5 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess
-Exec=@TEST_SHELL_SERVICE_BINARY@ -test "that" 'we get' back --what "we put in"
+Exec=@DBUS_TEST_EXEC@/test-shell-service@EXEEXT@ -test "that" 'we get' back --what "we put in"
 User=anyrandomuser
 
diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in
index 2cbdaa8..0fdfead 100644
--- a/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in
+++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service.in
@@ -1,4 +1,4 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuite.PrivServer
-Exec=@TEST_PRIVSERVER_BINARY@
+Exec=@DBUS_TEST_EXEC@/name-test/test-privserver@EXEEXT@
 
diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in
index 4202351..a22a77d 100644
--- a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in
+++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service.in
@@ -1,4 +1,3 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteEchoService
-Exec=@TEST_SERVICE_BINARY@
-
+Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@
diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in
index 49fcac3..633862c 100644
--- a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in
+++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service.in
@@ -1,3 +1,3 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteForkingEchoService
-Exec=@TEST_SERVICE_BINARY@ org.freedesktop.DBus.TestSuiteForkingEchoService fork
+Exec=@DBUS_TEST_EXEC@/test-service@EXEEXT@ org.freedesktop.DBus.TestSuiteForkingEchoService fork
diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in
index 73c7b55..7625427 100644
--- a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in
+++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service.in
@@ -1,4 +1,4 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteSegfaultService
-Exec=@TEST_SEGFAULT_BINARY@
+Exec=@DBUS_TEST_EXEC@/test-segfault@EXEEXT@
 
diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in
index 4404c78..8f5964a 100644
--- a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in
+++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service.in
@@ -1,4 +1,3 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteShellEchoServiceFail
-Exec=@TEST_SHELL_SERVICE_BINARY@ "this should 'fail' because of an unterminated quote 
-
+Exec=@DBUS_TEST_EXEC@/test-shell-service@EXEEXT@ "this should 'fail' because of an unterminated quote
diff --git a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in
index e568846..a52887e 100644
--- a/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in
+++ b/test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service.in
@@ -1,4 +1,4 @@
 [D-BUS Service]
 Name=org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess
-Exec=@TEST_SHELL_SERVICE_BINARY@ -test "that" 'we get' back --what "we put in"
+Exec=@DBUS_TEST_EXEC@/test-shell-service@EXEEXT@ -test "that" 'we get' back --what "we put in"
 
diff --git a/test/dbus-daemon-eavesdrop.c b/test/dbus-daemon-eavesdrop.c
new file mode 100644
index 0000000..0bd923d
--- /dev/null
+++ b/test/dbus-daemon-eavesdrop.c
@@ -0,0 +1,555 @@
+/* Integration tests for the eavesdrop=true|false keyword in DBusMatchRule
+ *
+ * Author: Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
+ * Based on: tests/dbus-daemon.c by Simon McVittie
+ * Copyright © 2010-2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <string.h>
+
+#ifdef DBUS_WIN
+# include <io.h>
+# include <windows.h>
+#else
+# include <signal.h>
+# include <unistd.h>
+#endif
+
+#define SENDER_NAME "test.eavesdrop.sender"
+#define SENDER_PATH "/test/eavesdrop/sender"
+#define SENDER_IFACE SENDER_NAME
+#define SENDER_SIGNAL_NAME "Signal"
+#define SENDER_STOPPER_NAME "Stopper"
+
+/* This rule is equivalent to the one added to a proxy connecting to
+ * SENDER_NAME+SENDER_IFACE, plus restricting on signal name.
+ * Being more restrictive, if the connection receives what we need, for sure
+ * the original proxy rule will match it */
+#define RECEIVER_RULE "sender='" SENDER_NAME "'," \
+  "interface='" SENDER_IFACE "'," \
+  "type='signal'," \
+  "member='" SENDER_SIGNAL_NAME "'"
+#define POLITELISTENER_RULE RECEIVER_RULE
+#define EAVESDROPPER_RULE RECEIVER_RULE ",eavesdrop=true"
+
+#define STOPPER_RULE "sender='" SENDER_NAME \
+  "',interface='" SENDER_IFACE "',type='signal',member='" SENDER_STOPPER_NAME "'"
+
+/* a connection received a signal to whom? */
+typedef enum {
+  NONE_YET = 0,
+  TO_ME,
+  TO_OTHER,
+  BROADCAST,
+} SignalDst;
+
+typedef struct {
+    DBusError e;
+    GError *ge;
+
+    GPid daemon_pid;
+
+    /* eavedrop keyword tests */
+    DBusConnection *sender;
+    DBusConnection *receiver;
+    SignalDst receiver_dst;
+    dbus_bool_t receiver_got_stopper;
+    DBusConnection *eavesdropper;
+    SignalDst eavesdropper_dst;
+    dbus_bool_t eavesdropper_got_stopper;
+    DBusConnection *politelistener;
+    SignalDst politelistener_dst;
+    dbus_bool_t politelistener_got_stopper;
+} Fixture;
+
+#define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
+static void
+_assert_no_error (const DBusError *e,
+    const char *file,
+    int line)
+{
+  if (G_UNLIKELY (dbus_error_is_set (e)))
+    g_error ("%s:%d: expected success but got error: %s: %s",
+        file, line, e->name, e->message);
+}
+
+static gchar *
+spawn_dbus_daemon (gchar *binary,
+    gchar *configuration,
+    GPid *daemon_pid)
+{
+  GError *error = NULL;
+  GString *address;
+  gint address_fd;
+  gchar *argv[] = {
+      binary,
+      configuration,
+      "--nofork",
+      "--print-address=1", /* stdout */
+      NULL
+  };
+
+  g_spawn_async_with_pipes (NULL, /* working directory */
+      argv,
+      NULL, /* envp */
+      G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
+      NULL, /* child_setup */
+      NULL, /* user data */
+      daemon_pid,
+      NULL, /* child's stdin = /dev/null */
+      &address_fd,
+      NULL, /* child's stderr = our stderr */
+      &error);
+  g_assert_no_error (error);
+
+  address = g_string_new (NULL);
+
+  /* polling until the dbus-daemon writes out its address is a bit stupid,
+   * but at least it's simple, unlike dbus-launch... in principle we could
+   * use select() here, but life's too short */
+  while (1)
+    {
+      gssize bytes;
+      gchar buf[4096];
+      gchar *newline;
+
+      bytes = read (address_fd, buf, sizeof (buf));
+
+      if (bytes > 0)
+        g_string_append_len (address, buf, bytes);
+
+      newline = strchr (address->str, '\n');
+
+      if (newline != NULL)
+        {
+          g_string_truncate (address, newline - address->str);
+          break;
+        }
+
+      g_usleep (G_USEC_PER_SEC / 10);
+    }
+
+  return g_string_free (address, FALSE);
+}
+
+static DBusConnection *
+connect_to_bus (const gchar *address)
+{
+  DBusConnection *conn;
+  DBusError error = DBUS_ERROR_INIT;
+  dbus_bool_t ok;
+
+  conn = dbus_connection_open_private (address, &error);
+  assert_no_error (&error);
+  g_assert (conn != NULL);
+
+  ok = dbus_bus_register (conn, &error);
+  assert_no_error (&error);
+  g_assert (ok);
+  g_assert (dbus_bus_get_unique_name (conn) != NULL);
+
+  dbus_connection_setup_with_g_main (conn, NULL);
+  return conn;
+}
+
+/* send a unicast signal to <self> to ensure that no other connection
+ * listening is the actual recipient for the signal */
+static DBusHandlerResult
+sender_send_unicast_to_sender (Fixture *f)
+{
+  DBusMessage *signal;
+
+  signal = dbus_message_new_signal (SENDER_PATH, SENDER_IFACE,
+      SENDER_SIGNAL_NAME);
+  dbus_message_set_destination (signal, dbus_bus_get_unique_name (f->sender));
+
+  if (signal == NULL)
+    g_error ("OOM");
+
+  if (!dbus_connection_send (f->sender, signal, NULL))
+    g_error ("OOM");
+
+  dbus_message_unref (signal);
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/* send a unicast signal to <receiver>, making <politelistener> and
+ * <eavesdropper> not a actual recipient for it */
+static DBusHandlerResult
+sender_send_unicast_to_receiver (Fixture *f)
+{
+  DBusMessage *signal;
+
+  signal = dbus_message_new_signal (SENDER_PATH, SENDER_IFACE, SENDER_SIGNAL_NAME);
+  dbus_message_set_destination (signal, dbus_bus_get_unique_name (f->receiver));
+
+  if (signal == NULL)
+    g_error ("OOM");
+
+  if (!dbus_connection_send (f->sender, signal, NULL))
+    g_error ("OOM");
+
+  dbus_message_unref (signal);
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+sender_send_broadcast (Fixture *f)
+{
+  DBusMessage *signal;
+
+  signal = dbus_message_new_signal (SENDER_PATH, SENDER_IFACE, SENDER_SIGNAL_NAME);
+  dbus_message_set_destination (signal, NULL);
+
+  if (signal == NULL)
+    g_error ("OOM");
+
+  if (!dbus_connection_send (f->sender, signal, NULL))
+    g_error ("OOM");
+
+  dbus_message_unref (signal);
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/* Send special broadcast signal to indicate that the connections can "stop"
+ * listening and check their results.
+ * DBus does not re-order messages, so when the three connections have received
+ * this signal, we are sure that any message sent before it has also been
+ * dispatched. */
+static DBusHandlerResult
+sender_send_stopper (Fixture *f)
+{
+  DBusMessage *signal;
+
+  signal = dbus_message_new_signal (SENDER_PATH, SENDER_IFACE, SENDER_STOPPER_NAME);
+  dbus_message_set_destination (signal, NULL);
+
+  if (signal == NULL)
+    g_error ("OOM");
+
+  if (!dbus_connection_send (f->sender, signal, NULL))
+    g_error ("OOM");
+
+  dbus_message_unref (signal);
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+/* Ignore NameAcquired, then depending on the signal received:
+ * - updates f-><conn>_dst based on the destination of the message
+ * - asserts that <conn> received the stop signal
+ */
+static DBusHandlerResult
+signal_filter (DBusConnection *connection,
+    DBusMessage *message,
+    void *user_data)
+{
+  Fixture *f = user_data;
+  SignalDst *dst = NULL;
+  DBusConnection **conn;
+  dbus_bool_t *got_stopper;
+
+  if (0 == strcmp (dbus_message_get_member (message), "NameAcquired"))
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  if (connection == f->receiver)
+    {
+      dst = &(f->receiver_dst);
+      conn = &(f->receiver);
+      got_stopper = &(f->receiver_got_stopper);
+    }
+  else if (connection == f->eavesdropper)
+    {
+      dst = &(f->eavesdropper_dst);
+      conn = &(f->eavesdropper);
+      got_stopper = &(f->eavesdropper_got_stopper);
+    }
+  else if (connection == f->politelistener)
+    {
+      dst = &(f->politelistener_dst);
+      conn = &(f->politelistener);
+      got_stopper = &(f->politelistener_got_stopper);
+    }
+  else
+    {
+      g_error ("connection not matching");
+    }
+
+  if (0 == strcmp (dbus_message_get_member (message), SENDER_SIGNAL_NAME))
+    {
+      if (dbus_message_get_destination (message) == NULL)
+        *dst = BROADCAST;
+      else if (0 == strcmp (dbus_message_get_destination (message), dbus_bus_get_unique_name (*conn)))
+        *dst = TO_ME;
+      else /* if (dbus_message_get_destination (message) != NULL) */
+        *dst = TO_OTHER;
+    }
+  else if (0 == strcmp (dbus_message_get_member (message), SENDER_STOPPER_NAME))
+    {
+      *got_stopper = TRUE;
+    }
+  else
+    {
+      g_error ("got unknown member from message: %s",
+          dbus_message_get_member (message));
+    }
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+add_receiver_filter (Fixture *f)
+{
+  DBusError e = DBUS_ERROR_INIT;
+
+  dbus_bus_add_match (f->receiver, RECEIVER_RULE, &e);
+  assert_no_error (&e);
+  dbus_bus_add_match (f->receiver, STOPPER_RULE, &e);
+  assert_no_error (&e);
+
+  if (!dbus_connection_add_filter (f->receiver,
+        signal_filter, f, NULL))
+    g_error ("OOM");
+}
+
+static void
+add_eavesdropper_filter (Fixture *f)
+{
+  DBusError e = DBUS_ERROR_INIT;
+
+  dbus_bus_add_match (f->eavesdropper, EAVESDROPPER_RULE, &e);
+  assert_no_error (&e);
+  dbus_bus_add_match (f->eavesdropper, STOPPER_RULE, &e);
+  assert_no_error (&e);
+
+  if (!dbus_connection_add_filter (f->eavesdropper,
+        signal_filter, f, NULL))
+    g_error ("OOM");
+}
+
+static void
+add_politelistener_filter (Fixture *f)
+{
+  DBusError e = DBUS_ERROR_INIT;
+
+  dbus_bus_add_match (f->politelistener, POLITELISTENER_RULE, &e);
+  assert_no_error (&e);
+  dbus_bus_add_match (f->politelistener, STOPPER_RULE, &e);
+  assert_no_error (&e);
+
+  if (!dbus_connection_add_filter (f->politelistener,
+        signal_filter, f, NULL))
+    g_error ("OOM");
+}
+
+static void
+setup (Fixture *f,
+    gconstpointer context G_GNUC_UNUSED)
+{
+  gchar *dbus_daemon;
+  gchar *config;
+  gchar *address;
+
+  f->ge = NULL;
+  dbus_error_init (&f->e);
+
+  dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
+
+  if (dbus_daemon == NULL)
+    dbus_daemon = g_strdup ("dbus-daemon");
+
+  if (g_getenv ("DBUS_TEST_SYSCONFDIR") != NULL)
+    {
+      config = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
+          g_getenv ("DBUS_TEST_SYSCONFDIR"));
+    }
+  else if (g_getenv ("DBUS_TEST_DATA") != NULL)
+    {
+      config = g_strdup_printf (
+          "--config-file=%s/valid-config-files/session.conf",
+          g_getenv ("DBUS_TEST_DATA"));
+    }
+  else
+    {
+      config = g_strdup ("--session");
+    }
+
+  address = spawn_dbus_daemon (dbus_daemon, config, &f->daemon_pid);
+
+  g_free (dbus_daemon);
+  g_free (config);
+
+  f->sender = connect_to_bus (address);
+  dbus_bus_request_name (f->sender, SENDER_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+      &(f->e));
+  f->receiver = connect_to_bus (address);
+  f->eavesdropper = connect_to_bus (address);
+  f->politelistener = connect_to_bus (address);
+  add_receiver_filter (f);
+  add_politelistener_filter (f);
+  add_eavesdropper_filter (f);
+
+  g_free (address);
+}
+
+static void
+test_eavesdrop_broadcast (Fixture *f,
+    gconstpointer context G_GNUC_UNUSED)
+{
+  sender_send_broadcast (f);
+  sender_send_stopper (f);
+
+  while (!f->receiver_got_stopper ||
+      !f->politelistener_got_stopper ||
+      !f->eavesdropper_got_stopper)
+    g_main_context_iteration (NULL, TRUE);
+
+  /* all the three connection can receive a broadcast */
+  g_assert_cmpint (f->receiver_dst, ==, BROADCAST);
+  g_assert_cmpint (f->politelistener_dst, ==, BROADCAST);
+  g_assert_cmpint (f->eavesdropper_dst, ==, BROADCAST);
+}
+
+/* a way to say that none of the listening connection are destination of the
+ * signal */
+static void
+test_eavesdrop_unicast_to_sender (Fixture *f,
+    gconstpointer context G_GNUC_UNUSED)
+{
+  sender_send_unicast_to_sender (f);
+  sender_send_stopper (f);
+
+  while (!f->receiver_got_stopper ||
+      !f->politelistener_got_stopper ||
+      !f->eavesdropper_got_stopper)
+    g_main_context_iteration (NULL, TRUE);
+
+  /* not directed to it and not broadcasted, they cannot receive it */
+  g_assert_cmpint (f->receiver_dst, ==, NONE_YET);
+  g_assert_cmpint (f->politelistener_dst, ==, NONE_YET);
+  /* eavesdrop=true, it will receive the signal even though it's not directed
+   * to it */
+  g_assert_cmpint (f->eavesdropper_dst, ==, TO_OTHER);
+}
+
+static void
+test_eavesdrop_unicast_to_receiver (Fixture *f,
+    gconstpointer context G_GNUC_UNUSED)
+{
+  sender_send_unicast_to_receiver (f);
+  sender_send_stopper (f);
+
+  while (!f->receiver_got_stopper ||
+      !f->politelistener_got_stopper ||
+      !f->eavesdropper_got_stopper)
+    g_main_context_iteration (NULL, TRUE);
+
+  /* direct to him */
+  g_assert_cmpint (f->receiver_dst, ==, TO_ME);
+  /* not directed to it and not broadcasted, it cannot receive it */
+  g_assert_cmpint (f->politelistener_dst, ==, NONE_YET);
+  /* eavesdrop=true, it will receive the signal even though it's not directed
+   * to it */
+  g_assert_cmpint (f->eavesdropper_dst, ==, TO_OTHER);
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer context G_GNUC_UNUSED)
+{
+  dbus_error_free (&f->e);
+  g_clear_error (&f->ge);
+
+  if (f->sender != NULL)
+    {
+      dbus_connection_close (f->sender);
+      dbus_connection_unref (f->sender);
+      f->sender = NULL;
+    }
+
+  if (f->receiver != NULL)
+    {
+      dbus_connection_remove_filter (f->receiver,
+          signal_filter, f);
+
+      dbus_connection_close (f->receiver);
+      dbus_connection_unref (f->receiver);
+      f->receiver = NULL;
+    }
+
+  if (f->politelistener != NULL)
+    {
+      dbus_connection_remove_filter (f->politelistener,
+          signal_filter, f);
+
+      dbus_connection_close (f->politelistener);
+      dbus_connection_unref (f->politelistener);
+      f->politelistener = NULL;
+    }
+
+  if (f->eavesdropper != NULL)
+    {
+      dbus_connection_remove_filter (f->eavesdropper,
+          signal_filter, f);
+
+      dbus_connection_close (f->eavesdropper);
+      dbus_connection_unref (f->eavesdropper);
+      f->eavesdropper = NULL;
+    }
+
+#ifdef DBUS_WIN
+  TerminateProcess (f->daemon_pid, 1);
+#else
+  kill (f->daemon_pid, SIGTERM);
+#endif
+
+  g_spawn_close_pid (f->daemon_pid);
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+
+  g_test_add ("/eavedrop/match_keyword/broadcast", Fixture, NULL,
+      setup, test_eavesdrop_broadcast, teardown);
+  g_test_add ("/eavedrop/match_keyword/unicast_to_receiver", Fixture, NULL,
+      setup, test_eavesdrop_unicast_to_receiver,
+      teardown);
+  g_test_add ("/eavedrop/match_keyword/unicast_to_sender", Fixture, NULL,
+      setup, test_eavesdrop_unicast_to_sender, teardown);
+
+  return g_test_run ();
+}
diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c
new file mode 100644
index 0000000..cc87153
--- /dev/null
+++ b/test/dbus-daemon.c
@@ -0,0 +1,368 @@
+/* Integration tests for the dbus-daemon
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2010-2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include <string.h>
+
+#ifdef DBUS_WIN
+# include <io.h>
+# include <windows.h>
+#else
+# include <signal.h>
+# include <unistd.h>
+#endif
+
+typedef struct {
+    gboolean skip;
+
+    DBusError e;
+    GError *ge;
+
+    GPid daemon_pid;
+
+    DBusConnection *left_conn;
+
+    DBusConnection *right_conn;
+    gboolean right_conn_echo;
+} Fixture;
+
+#define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
+static void
+_assert_no_error (const DBusError *e,
+    const char *file,
+    int line)
+{
+  if (G_UNLIKELY (dbus_error_is_set (e)))
+    g_error ("%s:%d: expected success but got error: %s: %s",
+        file, line, e->name, e->message);
+}
+
+static gchar *
+spawn_dbus_daemon (gchar *binary,
+    gchar *configuration,
+    GPid *daemon_pid)
+{
+  GError *error = NULL;
+  GString *address;
+  gint address_fd;
+  gchar *argv[] = {
+      binary,
+      configuration,
+      "--nofork",
+      "--print-address=1", /* stdout */
+      NULL
+  };
+
+  g_spawn_async_with_pipes (NULL, /* working directory */
+      argv,
+      NULL, /* envp */
+      G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
+      NULL, /* child_setup */
+      NULL, /* user data */
+      daemon_pid,
+      NULL, /* child's stdin = /dev/null */
+      &address_fd,
+      NULL, /* child's stderr = our stderr */
+      &error);
+  g_assert_no_error (error);
+
+  address = g_string_new (NULL);
+
+  /* polling until the dbus-daemon writes out its address is a bit stupid,
+   * but at least it's simple, unlike dbus-launch... in principle we could
+   * use select() here, but life's too short */
+  while (1)
+    {
+      gssize bytes;
+      gchar buf[4096];
+      gchar *newline;
+
+      bytes = read (address_fd, buf, sizeof (buf));
+
+      if (bytes > 0)
+        g_string_append_len (address, buf, bytes);
+
+      newline = strchr (address->str, '\n');
+
+      if (newline != NULL)
+        {
+          g_string_truncate (address, newline - address->str);
+          break;
+        }
+
+      g_usleep (G_USEC_PER_SEC / 10);
+    }
+
+  return g_string_free (address, FALSE);
+}
+
+static DBusConnection *
+connect_to_bus (const gchar *address)
+{
+  DBusConnection *conn;
+  DBusError error = DBUS_ERROR_INIT;
+  dbus_bool_t ok;
+
+  conn = dbus_connection_open_private (address, &error);
+  assert_no_error (&error);
+  g_assert (conn != NULL);
+
+  ok = dbus_bus_register (conn, &error);
+  assert_no_error (&error);
+  g_assert (ok);
+  g_assert (dbus_bus_get_unique_name (conn) != NULL);
+
+  dbus_connection_setup_with_g_main (conn, NULL);
+  return conn;
+}
+
+static DBusHandlerResult
+echo_filter (DBusConnection *connection,
+    DBusMessage *message,
+    void *user_data)
+{
+  DBusMessage *reply;
+
+  if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  reply = dbus_message_new_method_return (message);
+
+  if (reply == NULL)
+    g_error ("OOM");
+
+  if (!dbus_connection_send (connection, reply, NULL))
+    g_error ("OOM");
+
+  dbus_message_unref (reply);
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+typedef struct {
+    const char *bug_ref;
+    guint min_messages;
+    const char *config_file;
+} Config;
+
+static void
+setup (Fixture *f,
+    gconstpointer context)
+{
+  const Config *config = context;
+  gchar *dbus_daemon;
+  gchar *arg;
+  gchar *address;
+
+  f->ge = NULL;
+  dbus_error_init (&f->e);
+
+  if (config != NULL && config->config_file != NULL)
+    {
+      if (g_getenv ("DBUS_TEST_DATA") == NULL)
+        {
+          g_message ("SKIP: set DBUS_TEST_DATA to a directory containing %s",
+              config->config_file);
+          f->skip = TRUE;
+          return;
+        }
+
+      arg = g_strdup_printf (
+          "--config-file=%s/%s",
+          g_getenv ("DBUS_TEST_DATA"), config->config_file);
+    }
+  else if (g_getenv ("DBUS_TEST_SYSCONFDIR") != NULL)
+    {
+      arg = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
+          g_getenv ("DBUS_TEST_SYSCONFDIR"));
+    }
+  else if (g_getenv ("DBUS_TEST_DATA") != NULL)
+    {
+      arg = g_strdup_printf (
+          "--config-file=%s/valid-config-files/session.conf",
+          g_getenv ("DBUS_TEST_DATA"));
+    }
+  else
+    {
+      arg = g_strdup ("--session");
+    }
+
+  dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
+
+  if (dbus_daemon == NULL)
+    dbus_daemon = g_strdup ("dbus-daemon");
+
+  address = spawn_dbus_daemon (dbus_daemon, arg, &f->daemon_pid);
+
+  g_free (dbus_daemon);
+  g_free (arg);
+
+  f->left_conn = connect_to_bus (address);
+  f->right_conn = connect_to_bus (address);
+  g_free (address);
+}
+
+static void
+add_echo_filter (Fixture *f)
+{
+  if (!dbus_connection_add_filter (f->right_conn, echo_filter, NULL, NULL))
+    g_error ("OOM");
+
+  f->right_conn_echo = TRUE;
+}
+
+static void
+pc_count (DBusPendingCall *pc,
+    void *data)
+{
+  guint *received_p = data;
+
+  (*received_p)++;
+}
+
+static void
+test_echo (Fixture *f,
+    gconstpointer context)
+{
+  const Config *config = context;
+  guint count = 2000;
+  guint sent;
+  guint received = 0;
+  double elapsed;
+
+  if (f->skip)
+    return;
+
+  if (config != NULL && config->bug_ref != NULL)
+    g_test_bug (config->bug_ref);
+
+  if (g_test_perf ())
+    count = 100000;
+
+  if (config != NULL)
+    count = MAX (config->min_messages, count);
+
+  add_echo_filter (f);
+
+  g_test_timer_start ();
+
+  for (sent = 0; sent < count; sent++)
+    {
+      DBusMessage *m = dbus_message_new_method_call (
+          dbus_bus_get_unique_name (f->right_conn), "/",
+          "com.example", "Spam");
+      DBusPendingCall *pc;
+
+      if (m == NULL)
+        g_error ("OOM");
+
+      if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
+                                            DBUS_TIMEOUT_INFINITE) ||
+          pc == NULL)
+        g_error ("OOM");
+
+      if (dbus_pending_call_get_completed (pc))
+        pc_count (pc, &received);
+      else if (!dbus_pending_call_set_notify (pc, pc_count, &received,
+            NULL))
+        g_error ("OOM");
+
+      dbus_pending_call_unref (pc);
+      dbus_message_unref (m);
+    }
+
+  while (received < count)
+    g_main_context_iteration (NULL, TRUE);
+
+  elapsed = g_test_timer_elapsed ();
+
+  g_test_maximized_result (count / elapsed, "%u messages / %f seconds",
+      count, elapsed);
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer context G_GNUC_UNUSED)
+{
+  dbus_error_free (&f->e);
+  g_clear_error (&f->ge);
+
+  if (f->left_conn != NULL)
+    {
+      dbus_connection_close (f->left_conn);
+      dbus_connection_unref (f->left_conn);
+      f->left_conn = NULL;
+    }
+
+  if (f->right_conn != NULL)
+    {
+      if (f->right_conn_echo)
+        {
+          dbus_connection_remove_filter (f->right_conn, echo_filter, NULL);
+          f->right_conn_echo = FALSE;
+        }
+
+      dbus_connection_close (f->right_conn);
+      dbus_connection_unref (f->right_conn);
+      f->right_conn = NULL;
+    }
+
+  if (f->daemon_pid != 0)
+    {
+#ifdef DBUS_WIN
+      TerminateProcess (f->daemon_pid, 1);
+#else
+      kill (f->daemon_pid, SIGTERM);
+#endif
+
+      g_spawn_close_pid (f->daemon_pid);
+      f->daemon_pid = 0;
+    }
+}
+
+static Config limited_config = {
+    "34393", 10000, "valid-config-files/incoming-limit.conf"
+};
+
+int
+main (int argc,
+    char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+
+  g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown);
+  g_test_add ("/echo/limited", Fixture, &limited_config,
+      setup, test_echo, teardown);
+
+  return g_test_run ();
+}
diff --git a/test/dbus-test-runner b/test/dbus-test-runner
new file mode 100644
index 0000000..a3dc396
--- /dev/null
+++ b/test/dbus-test-runner
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+set -e
+
+dir="$1"
+shift
+
+if ! test -d "$dir"; then
+  echo "Usage: dbus-test-runner directory [executable...]"
+  exit 0
+fi
+
+passed=0
+failed=0
+skipped=0
+
+for prog in "$@"; do
+  e=0
+  "$dir/$prog" || e=$?
+  case $e in
+    (0)
+      echo "PASS: $prog"
+      passed=`expr $passed + 1`
+      ;;
+    (77)
+      echo "SKIP: $prog"
+      skipped=`expr $skipped + 1`
+      ;;
+    (*)
+      echo "FAIL: $prog"
+      failed=`expr $failed + 1`
+      ;;
+  esac
+done
+
+if test $failed = 0; then
+  # avoid saying "FAIL", to make it easy to grep results!
+  echo "PASSED $passed / SKIPPED $skipped"
+  exit 0
+else
+  echo "PASSED $passed / FAILED $failed / SKIPPED $skipped"
+  exit 1
+fi
diff --git a/test/decode-gcov.c b/test/decode-gcov.c
deleted file mode 100644
index 3b2a152..0000000
--- a/test/decode-gcov.c
+++ /dev/null
@@ -1,2653 +0,0 @@
- /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/* decode-gcov.c gcov decoder program
- *
- * Copyright (C) 2003  Red Hat Inc.
- *
- * Partially derived from gcov,
- * Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
- * 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
- *
- * This file is NOT licensed under the Academic Free License
- * as it is largely derived from gcov.c and gcov-io.h in the
- * gcc source code.
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <config.h>
-#define DBUS_COMPILATION /* cheat */
-#include <dbus/dbus-list.h>
-#include <dbus/dbus-string.h>
-#include <dbus/dbus-sysdeps.h>
-#include <dbus/dbus-marshal.h>
-#include <dbus/dbus-hash.h>
-#undef DBUS_COMPILATION
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef DBUS_HAVE_INT64
-#error "gcov support can't be built without 64-bit integer support"
-#endif
-
-static void
-die (const char *message)
-{
-  fprintf (stderr, "%s", message);
-  exit (1);
-}
-
-/* This bizarro function is from gcov-io.h in gcc source tree */
-static int
-fetch_long (long        *dest,
-            const char  *source,
-            size_t       bytes)
-{
-  long value = 0;
-  int i;
-                                                                                
-  for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
-    if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
-      return 1;
-                                                                                
-  for (; i >= 0; i--)
-    value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
-                                                                                
-  if ((source[bytes - 1] & 128) && (value > 0))
-    value = - value;
-                                                                                
-  *dest = value;
-  return 0;
-}
-
-static int
-fetch_long64 (dbus_int64_t *dest,
-              const char   *source,
-              size_t        bytes)
-{
-  dbus_int64_t value = 0;
-  int i;
-                                                                                
-  for (i = bytes - 1; (size_t) i > (sizeof (*dest) - 1); i--)
-    if (source[i] & ((size_t) i == (bytes - 1) ? 127 : 255 ))
-      return 1;
-                                                                                
-  for (; i >= 0; i--)
-    value = value * 256 + (source[i] & ((size_t)i == (bytes - 1) ? 127 : 255));
-                                                                                
-  if ((source[bytes - 1] & 128) && (value > 0))
-    value = - value;
-                                                                                
-  *dest = value;
-  return 0;
-}
-
-#define BB_FILENAME 	(-1)
-#define BB_FUNCTION 	(-2)
-#define BB_ENDOFLIST	0
-
-static dbus_bool_t
-string_get_int (const DBusString *str,
-                int               start,
-                long             *val)
-{
-  const char *p;
-  
-  if ((_dbus_string_get_length (str) - start) < 4)
-    return FALSE;
-
-  p = _dbus_string_get_const_data (str);
-
-  p += start;
-
-  fetch_long (val, p, 4);
-  
-  return TRUE;
-}
-
-static dbus_bool_t
-string_get_int64 (const DBusString *str,
-                  int               start,
-                  dbus_int64_t     *val)
-{
-  const char *p;
-  
-  if ((_dbus_string_get_length (str) - start) < 8)
-    return FALSE;
-
-  p = _dbus_string_get_const_data (str);
-
-  p += start;
-
-  fetch_long64 (val, p, 8);
-  
-  return TRUE;
-}
-
-static dbus_bool_t
-string_get_string (const DBusString *str,
-                   int               start,
-                   long              terminator,
-                   DBusString       *val,
-                   int              *end)
-{
-  int i;
-  long n;
-  
-  i = start;
-  while (string_get_int (str, i, &n))
-    {
-      unsigned char b;
-      
-      i += 4;
-      
-      if (n == terminator)
-        break;
-
-      b = n & 0xff;
-      if (b)
-        {
-          _dbus_string_append_byte (val, b);
-          b = (n >> 8) & 0xff;
-          if (b)
-            {
-              _dbus_string_append_byte (val, b);
-              b = (n >> 16) & 0xff;
-              if (b)
-                {
-                  _dbus_string_append_byte (val, b);
-                  b = (n >> 24) & 0xff;
-                  if (b)
-                    _dbus_string_append_byte (val, b);
-                }
-            }
-        }
-    }
-
-  *end = i;
-  
-  return TRUE;
-}
-
-#ifdef DBUS_HAVE_GCC33_GCOV
-/* In gcc33 .bbg files, there's a function name of the form:
- *   -1, length, name (padded to 4), -1, checksum
- */
-static dbus_bool_t
-string_get_function (const DBusString *str,
-                     int               start,
-                     DBusString       *funcname,
-                     int              *checksum,
-                     int              *next)
-{
-  int end;
-  long val;
-  int i;
-
-  i = start;
-  
-  if (!string_get_int (str, i, &val))
-    die ("no room for -1 before function name\n");
-        
-  i += 4;
-
-  if (val != -1)
-    die ("value before function name is not -1\n");
-  
-  if (!string_get_int (str, i, &val))
-    die ("no length found for function name\n");
-        
-  i += 4;
-
-  end = i + val;
-  if (end > _dbus_string_get_length (str))
-    die ("Function name length points past end of file\n");
-
-  if (!_dbus_string_append (funcname,
-                            _dbus_string_get_const_data (str) + i))
-    die ("no memory\n");
-        
-  /* skip alignment padding the length doesn't include the nul so add 1
-   */
-  i = _DBUS_ALIGN_VALUE (end + 1, 4);
-        
-  if (!string_get_int (str, i, &val) ||
-      val != -1)
-    die ("-1 at end of function name not found\n");
-        
-  i += 4;
-
-  if (!string_get_int (str, i, &val))
-    die ("no checksum found at end of function name\n");
-        
-  i += 4;
-
-  *checksum = val;
-
-  *next = i;
-
-  return TRUE;
-}
-#endif /* DBUS_HAVE_GCC33_GCOV */
-
-static void
-dump_bb_file (const DBusString *contents)
-{
-  int i;
-  long val;
-  int n_functions;
-
-  n_functions = 0;
-  i = 0;
-  while (string_get_int (contents, i, &val))
-    {
-      i += 4;
-      
-      switch (val)
-        {
-        case BB_FILENAME:
-          {
-            DBusString f;
-
-            if (!_dbus_string_init (&f))
-              die ("no memory\n");
-
-            if (string_get_string (contents, i,
-                                   BB_FILENAME,
-                                   &f, &i))
-              {
-                printf ("File %s\n", _dbus_string_get_const_data (&f));
-              }
-            _dbus_string_free (&f);
-          }
-          break;
-        case BB_FUNCTION:
-          {
-            DBusString f;
-            if (!_dbus_string_init (&f))
-              die ("no memory\n");
-
-            if (string_get_string (contents, i,
-                                   BB_FUNCTION,
-                                   &f, &i))
-              {
-                printf ("Function %s\n", _dbus_string_get_const_data (&f));
-              }
-            _dbus_string_free (&f);
-
-            n_functions += 1;
-          }
-          break;
-        case BB_ENDOFLIST:
-          printf ("End of block\n");
-          break;
-        default:
-          printf ("Line %ld\n", val);
-          break;
-        }
-    }
-
-  printf ("%d functions in file\n", n_functions);
-}
-
-#define FLAG_ON_TREE 0x1
-#define FLAG_FAKE 0x2
-#define FLAG_FALL_THROUGH 0x4
-
-static void
-dump_bbg_file (const DBusString *contents)
-{
-  int i;
-  long val;
-  int n_functions;
-  int n_arcs;
-  int n_blocks;
-  int n_arcs_off_tree;
-  
-  n_arcs_off_tree = 0;
-  n_blocks = 0;
-  n_arcs = 0;
-  n_functions = 0;
-  i = 0;
-  while (i < _dbus_string_get_length (contents))
-    {
-      long n_blocks_in_func;
-      long n_arcs_in_func; 
-      int j;
-
-#ifdef DBUS_HAVE_GCC33_GCOV
-      /* In gcc33 .bbg files, there's a function name of the form:
-       *   -1, length, name (padded to 4), -1, checksum
-       * after that header on each function description, it's
-       * the same as in gcc32
-       */
-
-      {
-        DBusString funcname;
-        int checksum;
-        
-        if (!_dbus_string_init (&funcname))
-          die ("no memory\n");
-
-        if (!string_get_function (contents, i,
-                                  &funcname, &checksum, &i))
-          die ("could not read function name\n");
-        
-        printf ("Function name is \"%s\" checksum %d\n",
-                _dbus_string_get_const_data (&funcname),
-                checksum);
-        
-        _dbus_string_free (&funcname);
-      }
-#endif /* DBUS_HAVE_GCC33_GCOV */
-      
-      if (!string_get_int (contents, i, &val))
-        die ("no count of blocks in func found\n");
-      
-      i += 4;
-      
-      n_blocks_in_func = val;
-
-      if (!string_get_int (contents, i, &n_arcs_in_func))
-        break;
-
-      i += 4;
-
-      printf ("Function has %ld blocks and %ld arcs\n",
-              n_blocks_in_func, n_arcs_in_func);
-
-      n_functions += 1;
-      n_blocks += n_blocks_in_func;
-      n_arcs += n_arcs_in_func;
-      
-      j = 0;
-      while (j < n_blocks_in_func)
-        {
-          long n_arcs_in_block;
-          int k;
-          
-          if (!string_get_int (contents, i, &n_arcs_in_block))
-            break;
-
-          i += 4;
-
-          printf ("  Block has %ld arcs\n", n_arcs_in_block);
-          
-          k = 0;
-          while (k < n_arcs_in_block)
-            {
-              long destination_block;
-              long flags;
-              
-              if (!string_get_int (contents, i, &destination_block))
-                break;
-
-              i += 4;
-              
-              if (!string_get_int (contents, i, &flags))
-                break;
-
-              i += 4;
-
-              printf ("    Arc has destination block %ld flags 0x%lx\n",
-                      destination_block, flags);
-
-              if ((flags & FLAG_ON_TREE) == 0)
-                n_arcs_off_tree += 1;
-              
-              ++k;
-            }
-
-          if (k < n_arcs_in_block)
-            break;
-          
-          ++j;
-        }
-
-      if (j < n_blocks_in_func)
-        break;
-
-      if (!string_get_int (contents, i, &val))
-        break;
-
-      i += 4;
-
-      if (val != -1)
-        die ("-1 separator not found\n");
-    }
-
-  printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
-          n_functions, n_blocks, n_arcs, n_arcs_off_tree);
-}
-
-#ifndef DBUS_HAVE_GCC33_GCOV
-
-/* gcc 3.2 version:
- * The da file contains first a count of arcs in the file,
- * then a count of executions for all "off tree" arcs
- * in the file.
- */
-static void
-dump_da_file (const DBusString *contents)
-{
-  int i;
-  dbus_int64_t val;
-  int n_arcs;
-  int claimed_n_arcs;
-
-  i = 0;
-  if (!string_get_int64 (contents, i, &val))
-    return;
-
-  i += 8;
-  
-  printf ("%ld arcs in file\n", (long) val);
-  claimed_n_arcs = val;
-  
-  n_arcs = 0;
-  while (string_get_int64 (contents, i, &val))
-    {
-      i += 8;
-
-      printf ("%ld executions of arc %d\n",
-              (long) val, n_arcs);
-
-      ++n_arcs;
-    }
-
-  if (n_arcs != claimed_n_arcs)
-    {
-      printf ("File claimed to have %d arcs but only had %d\n",
-              claimed_n_arcs, n_arcs);
-    }
-}
-
-#else /* DBUS_HAVE_GCC33_GCOV */
-
-/* gcc 3.3 version:
- * The da file is more complex than 3.2.
- *
- * We have a magic value of "-123" only it isn't really
- * -123, it's -123 as encoded by the crackass gcov-io.h
- * routines. Anyway, 4 bytes.
- *
- * We then have:
- *
- *   - 4 byte count of how many functions in the following list
- *   - 4 byte length of random extra data
- *   - the random extra data, just skip it, info pages have some
- *     details on what might be in there or see __bb_exit_func in gcc
- *   - then for each function (number of functions given above):
- *     . -1, length, funcname, alignment padding, -1
- *     . checksum
- *     . 4 byte number of arcs in function
- *     . 8 bytes each, a count of execution for each arc
- *
- * Now, the whole thing *starting with the magic* can repeat.
- * This is caused by multiple runs of the profiled app appending
- * to the file.
- */
-static void
-dump_da_file (const DBusString *contents)
-{
-  int i;
-  dbus_int64_t v64;
-  long val;
-  int n_sections;
-  int total_functions;
-
-  total_functions = 0;
-  n_sections = 0;
-
-  i = 0;
-  while (i < _dbus_string_get_length (contents))
-    {
-      int claimed_n_functions;
-      int n_functions;
-      int total_arcs;
-
-      printf (".da file section %d\n", n_sections);
-      
-      if (!string_get_int (contents, i, &val))
-        die ("no magic found in .da file\n");
-
-      i += 4;
-
-      if (val != -123)
-        die ("wrong file magic in .da file\n");
-
-      if (!string_get_int (contents, i, &val))
-        die ("no function count in .da file\n");
-      i += 4;
-      claimed_n_functions = val;
-
-      printf ("%d functions expected in section %d of .da file\n",
-              claimed_n_functions, n_sections);
-      
-      if (!string_get_int (contents, i, &val))
-        die ("no extra data length in .da file\n");
-
-      i += 4;
-
-      i += val;
-
-      total_arcs = 0;
-      n_functions = 0;
-      while (n_functions < claimed_n_functions)
-        {
-          DBusString funcname;
-          int checksum;
-          int claimed_n_arcs;
-          int n_arcs;
-          
-          if (!_dbus_string_init (&funcname))
-            die ("no memory\n");
-          
-          if (!string_get_function (contents, i,
-                                    &funcname, &checksum, &i))
-            die ("could not read function name\n");
-          
-          if (!string_get_int (contents, i, &val))
-            die ("no arc count for function\n");
-          
-          i += 4;
-          claimed_n_arcs = val;
-          
-          printf ("  %d arcs in function %d %s checksum %d\n",
-                  claimed_n_arcs, n_functions,
-                  _dbus_string_get_const_data (&funcname),
-                  checksum);
-          
-          n_arcs = 0;
-          while (n_arcs < claimed_n_arcs)
-            {
-              if (!string_get_int64 (contents, i, &v64))
-                die ("did not get execution count for arc\n");
-              
-              i += 8;
-              
-              printf ("    %ld executions of arc %d (total arcs %d)\n",
-                      (long) v64, n_arcs, total_arcs + n_arcs);
-              
-              ++n_arcs;
-            }
-
-          _dbus_string_free (&funcname);
-
-          total_arcs += n_arcs;
-          ++n_functions;
-        }
-
-      printf ("total of %d functions and %d arcs in section %d\n",
-              n_functions, total_arcs, n_sections);
-      
-      total_functions += n_functions;
-      ++n_sections;
-    }
-
-  printf ("%d total function sections in %d total .da file sections\n",
-          total_functions, n_sections);
-}
-
-#endif /* DBUS_HAVE_GCC33_GCOV */
-
-typedef struct Arc Arc;
-typedef struct Block Block;
-typedef struct Function Function;
-typedef struct File File;
-typedef struct Line Line;
-
-struct Arc
-{
-  int source;
-  int target;
-  dbus_int64_t arc_count;
-  unsigned int count_valid : 1;
-  unsigned int on_tree : 1;
-  unsigned int fake : 1;
-  unsigned int fall_through : 1;
-  Arc *pred_next;
-  Arc *succ_next;
-};
-
-struct Block
-{
-  Arc *succ;
-  Arc *pred;
-  dbus_int64_t succ_count;
-  dbus_int64_t pred_count;
-  dbus_int64_t exec_count;
-  DBusList *lines;
-  unsigned int count_valid : 1;
-  unsigned int on_tree : 1;
-  unsigned int inside_dbus_build_tests : 1;
-};
-
-struct Function
-{
-  char *name;
-  int checksum;
-  Block *block_graph;
-  int n_blocks;
-  /* number of blocks in DBUS_BUILD_TESTS */
-  int n_test_blocks;
-  int n_test_blocks_executed;
-  /* number of blocks outside DBUS_BUILD_TESTS */
-  int n_nontest_blocks;
-  int n_nontest_blocks_executed;
-  /* Summary result flags */
-  unsigned int unused : 1;
-  unsigned int inside_dbus_build_tests : 1;
-  unsigned int partial : 1; /* only some of the blocks were executed */
-};
-
-struct Line
-{
-  int    number;
-  char  *text;
-  DBusList *blocks;
-  unsigned int inside_dbus_build_tests : 1;
-  unsigned int partial : 1; /* only some of the blocks were executed */
-};
-
-struct File
-{
-  char *name;
-  Line *lines;
-  int   n_lines;
-  DBusList *functions;
-};
-
-static void
-function_add_arc (Function *function,
-                  long      source,
-                  long      target,
-                  long      flags)
-{
-  Arc *arc;
-
-  arc = dbus_new0 (Arc, 1);
-  if (arc == NULL)
-    die ("no memory\n");
-  
-  arc->target = target;
-  arc->source = source;
-
-  arc->succ_next = function->block_graph[source].succ;
-  function->block_graph[source].succ = arc;
-  function->block_graph[source].succ_count += 1;
-
-  arc->pred_next = function->block_graph[target].pred;
-  function->block_graph[target].pred = arc;
-  function->block_graph[target].pred_count += 1;
-
-  if ((flags & FLAG_ON_TREE) != 0)
-    arc->on_tree = TRUE;
-
-  if ((flags & FLAG_FAKE) != 0)
-    arc->fake = TRUE;
-
-  if ((flags & FLAG_FALL_THROUGH) != 0)
-    arc->fall_through = TRUE;
-}
-
-
-static Arc*
-reverse_arcs (Arc *arc)
-{
-  struct Arc *prev = 0;
-  struct Arc *next;
-
-  for ( ; arc; arc = next)
-    {
-      next = arc->succ_next;
-      arc->succ_next = prev;
-      prev = arc;
-    }
-
-  return prev;
-}
-
-static void
-function_reverse_succ_arcs (Function *func)
-{
-  /* Must reverse the order of all succ arcs, to ensure that they match
-   * the order of the data in the .da file.
-   */
-  int i;
-  
-  for (i = 0; i < func->n_blocks; i++)
-    if (func->block_graph[i].succ)
-      func->block_graph[i].succ = reverse_arcs (func->block_graph[i].succ);
-}
-
-static void
-get_functions_from_bbg (const DBusString  *contents,
-                        DBusList         **functions)
-{
-  int i;
-  long val;
-  int n_functions;
-  int n_arcs;
-  int n_blocks;
-  int n_arcs_off_tree;
-
-#if 0
-  printf ("Loading arcs and blocks from .bbg file\n");
-#endif
-  
-  n_arcs_off_tree = 0;
-  n_blocks = 0;
-  n_arcs = 0;
-  n_functions = 0;
-  i = 0;
-  while (i < _dbus_string_get_length (contents))
-    {
-      Function *func;
-      long n_blocks_in_func;
-      long n_arcs_in_func; 
-      int j;
-
-#ifdef DBUS_HAVE_GCC33_GCOV
-      DBusString funcname;
-      int checksum;
-
-      /* In gcc33 .bbg files, there's a function name of the form:
-       *   -1, length, name (padded to 4), -1, checksum
-       * after that header on each function description, it's
-       * the same as in gcc32
-       */
-      if (!_dbus_string_init (&funcname))
-        die ("no memory\n");
-      
-      if (!string_get_function (contents, i,
-                                &funcname, &checksum, &i))
-        die ("could not read function name\n");
-#endif /* DBUS_HAVE_GCC33_GCOV */
-
-      if (!string_get_int (contents, i, &val))
-        break;
-      
-      n_blocks_in_func = val;
-      
-      i += 4;
-
-      if (!string_get_int (contents, i, &n_arcs_in_func))
-        break;
-
-      i += 4;
-
-      n_functions += 1;
-      n_blocks += n_blocks_in_func;
-      n_arcs += n_arcs_in_func;
-
-      func = dbus_new0 (Function, 1);
-      if (func == NULL)
-        die ("no memory\n");
-
-#ifdef DBUS_HAVE_GCC33_GCOV
-      func->name = _dbus_strdup (_dbus_string_get_const_data (&funcname));
-      func->checksum = checksum;
-      _dbus_string_free (&funcname);
-#endif
-      
-      func->block_graph = dbus_new0 (Block, n_blocks_in_func);
-      func->n_blocks = n_blocks_in_func;
-      
-      j = 0;
-      while (j < n_blocks_in_func)
-        {
-          long n_arcs_in_block;
-          int k;
-          
-          if (!string_get_int (contents, i, &n_arcs_in_block))
-            break;
-
-          i += 4;
-          
-          k = 0;
-          while (k < n_arcs_in_block)
-            {
-              long destination_block;
-              long flags;
-              
-              if (!string_get_int (contents, i, &destination_block))
-                break;
-
-              i += 4;
-              
-              if (!string_get_int (contents, i, &flags))
-                break;
-
-              i += 4;
-
-              if ((flags & FLAG_ON_TREE) == 0)
-                n_arcs_off_tree += 1;
-
-              function_add_arc (func, j, destination_block,
-                                flags);
-              
-              ++k;
-            }
-
-          if (k < n_arcs_in_block)
-            break;
-          
-          ++j;
-        }
-
-      if (j < n_blocks_in_func)
-        break;
-
-      function_reverse_succ_arcs (func);
-      
-      if (!_dbus_list_append (functions, func))
-        die ("no memory\n");
-      
-      if (!string_get_int (contents, i, &val))
-        break;
-
-      i += 4;
-
-      if (val != -1)
-        die ("-1 separator not found in .bbg file\n");
-    }
-
-#if 0
-  printf ("%d functions %d blocks %d arcs %d off-tree arcs in file\n",
-          n_functions, n_blocks, n_arcs, n_arcs_off_tree);
-#endif
-  
-  _dbus_assert (n_functions == _dbus_list_get_length (functions));
-}
-
-#ifdef DBUS_HAVE_GCC33_GCOV
-static void
-add_counts_from_da (const DBusString  *contents,
-                    DBusList         **functions)
-{
-  int i;
-  dbus_int64_t v64;
-  long val;
-  int n_sections;
-  DBusList *link;
-  Function *current_func;  
-  int current_block;
-  Arc *current_arc;
-
-  n_sections = 0;
-
-  i = 0;
-  while (i < _dbus_string_get_length (contents))
-    {
-      int claimed_n_functions;
-      int n_functions;
-      
-      if (!string_get_int (contents, i, &val))
-        die ("no magic found in .da file\n");
-
-      i += 4;
-
-      if (val != -123)
-        die ("wrong file magic in .da file\n");
-
-      if (!string_get_int (contents, i, &val))
-        die ("no function count in .da file\n");
-      i += 4;
-      claimed_n_functions = val;
-      
-      if (!string_get_int (contents, i, &val))
-        die ("no extra data length in .da file\n");
-
-      i += 4;
-
-      i += val;
-
-      link = _dbus_list_get_first_link (functions);
-      if (link == NULL)
-        goto no_more_functions;
-      
-      n_functions = 0;
-      while (n_functions < claimed_n_functions && link != NULL)
-        {
-          DBusString funcname;
-          int checksum;
-          int claimed_n_arcs;
-          int n_arcs;
-
-          current_func = link->data;
-          current_block = 0;
-          current_arc = current_func->block_graph[current_block].succ;
-          
-          if (!_dbus_string_init (&funcname))
-            die ("no memory\n");
-          
-          if (!string_get_function (contents, i,
-                                    &funcname, &checksum, &i))
-            die ("could not read function name\n");
-
-          if (!_dbus_string_equal_c_str (&funcname, current_func->name))
-            {
-              fprintf (stderr, "Expecting .da info for %s but got %s\n",
-                       current_func->name,
-                       _dbus_string_get_const_data (&funcname));
-              exit (1);
-            }
-          
-          if (checksum != current_func->checksum)
-            die (".da file checksum doesn't match checksum from .bbg file\n");
-          
-          if (!string_get_int (contents, i, &val))
-            die ("no arc count for function\n");
-          
-          i += 4;
-          claimed_n_arcs = val;
-
-          /* For each arc in the profile, find the corresponding
-           * arc in the function and increment its count
-           */
-          n_arcs = 0;
-          while (n_arcs < claimed_n_arcs)
-            {
-              if (!string_get_int64 (contents, i, &v64))
-                die ("did not get execution count for arc\n");
-              
-              i += 8;
-
-              /* Find the next arc in the function that isn't on tree */
-              while (current_arc == NULL ||
-                     current_arc->on_tree)
-                {
-                  if (current_arc == NULL)
-                    {
-                      ++current_block;
-              
-                      if (current_block >= current_func->n_blocks)
-                        die ("too many blocks in function\n");
-              
-                      current_arc = current_func->block_graph[current_block].succ;
-                    }
-                  else
-                    {
-                      current_arc = current_arc->succ_next;
-                    }
-                }
-              
-              _dbus_assert (current_arc != NULL);
-              _dbus_assert (!current_arc->on_tree);
-              
-              current_arc->arc_count = v64;
-              current_arc->count_valid = TRUE;
-              current_func->block_graph[current_block].succ_count -= 1;
-              current_func->block_graph[current_arc->target].pred_count -= 1;
-              
-              ++n_arcs;
-              
-              current_arc = current_arc->succ_next;
-            }
-
-          _dbus_string_free (&funcname);
-
-          link = _dbus_list_get_next_link (functions, link);
-          ++n_functions;
-
-          if (link == NULL && n_functions < claimed_n_functions)
-            {
-              fprintf (stderr, "Ran out of functions loading .da file\n");
-              goto no_more_functions;
-            }
-        }
-
-    no_more_functions:
-      
-      ++n_sections;
-    }
-}
-#else /* DBUS_HAVE_GCC33_GCOV */
-static void
-add_counts_from_da (const DBusString  *contents,
-                    DBusList         **functions)
-{
-  int i;
-  dbus_int64_t val;
-  int n_arcs;
-  int claimed_n_arcs;
-  DBusList *link;
-  Function *current_func;  
-  int current_block;
-  Arc *current_arc;
-
-#if 0
-  printf ("Loading execution count for each arc from .da file\n");
-#endif
-  
-  i = 0;
-  if (!string_get_int64 (contents, i, &val))
-    return;
-
-  i += 8;
-  
-  claimed_n_arcs = val;
-
-  link = _dbus_list_get_first_link (functions);
-  if (link == NULL)
-    goto done;
-
-  current_func = link->data;
-  current_block = 0;
-  current_arc = current_func->block_graph[current_block].succ;
-  
-  n_arcs = 0;
-  while (string_get_int64 (contents, i, &val))
-    {
-      i += 8;
-
-      while (current_arc == NULL ||
-             current_arc->on_tree)
-        {
-          if (current_arc == NULL)
-            {
-              ++current_block;
-              
-              if (current_block == current_func->n_blocks)
-                {
-                  link = _dbus_list_get_next_link (functions, link);
-                  if (link == NULL)
-                    {
-                      fprintf (stderr, "Ran out of functions loading .da file\n");
-                      goto done;
-                    }
-                  current_func = link->data;
-                  current_block = 0;
-                }
-              
-              current_arc = current_func->block_graph[current_block].succ;
-            }
-          else
-            {
-              current_arc = current_arc->succ_next;
-            }
-        }
-
-      _dbus_assert (current_arc != NULL);
-      _dbus_assert (!current_arc->on_tree);
-
-      current_arc->arc_count = val;
-      current_arc->count_valid = TRUE;
-      current_func->block_graph[current_block].succ_count -= 1;
-      current_func->block_graph[current_arc->target].pred_count -= 1;
-      
-      ++n_arcs;
-
-      current_arc = current_arc->succ_next;
-    }
-
- done:
-  
-  if (n_arcs != claimed_n_arcs)
-    {
-      fprintf (stderr, "File claimed to have %d arcs but only had %d\n",
-               claimed_n_arcs, n_arcs);
-      exit (1);
-    }
-
-#if 0
-  printf ("%d arcs in file\n", n_arcs);
-#endif
-}
-#endif
-
-static void
-function_solve_graph (Function *func)
-{
-  int passes, changes;
-  dbus_int64_t total;
-  int i;
-  Arc *arc;
-  Block *block_graph;
-  int n_blocks;
-
-#if 0
-  printf ("Solving function graph\n");
-#endif
-  
-  n_blocks = func->n_blocks;
-  block_graph = func->block_graph;
-
-  /* For every block in the file,
-     - if every exit/entrance arc has a known count, then set the block count
-     - if the block count is known, and every exit/entrance arc but one has
-     a known execution count, then set the count of the remaining arc
-
-     As arc counts are set, decrement the succ/pred count, but don't delete
-     the arc, that way we can easily tell when all arcs are known, or only
-     one arc is unknown.  */
-
-  /* The order that the basic blocks are iterated through is important.
-     Since the code that finds spanning trees starts with block 0, low numbered
-     arcs are put on the spanning tree in preference to high numbered arcs.
-     Hence, most instrumented arcs are at the end.  Graph solving works much
-     faster if we propagate numbers from the end to the start.
-
-     This takes an average of slightly more than 3 passes.  */
-
-  changes = 1;
-  passes = 0;
-  while (changes)
-    {
-      passes++;
-      changes = 0;
-
-      for (i = n_blocks - 1; i >= 0; i--)
-	{
-	  if (! block_graph[i].count_valid)
-	    {
-	      if (block_graph[i].succ_count == 0)
-		{
-		  total = 0;
-		  for (arc = block_graph[i].succ; arc;
-		       arc = arc->succ_next)
-		    total += arc->arc_count;
-		  block_graph[i].exec_count = total;
-		  block_graph[i].count_valid = 1;
-		  changes = 1;
-		}
-	      else if (block_graph[i].pred_count == 0)
-		{
-		  total = 0;
-		  for (arc = block_graph[i].pred; arc;
-		       arc = arc->pred_next)
-		    total += arc->arc_count;
-		  block_graph[i].exec_count = total;
-		  block_graph[i].count_valid = 1;
-		  changes = 1;
-		}
-	    }
-	  if (block_graph[i].count_valid)
-	    {
-	      if (block_graph[i].succ_count == 1)
-		{
-		  total = 0;
-		  /* One of the counts will be invalid, but it is zero,
-		     so adding it in also doesn't hurt.  */
-		  for (arc = block_graph[i].succ; arc;
-		       arc = arc->succ_next)
-		    total += arc->arc_count;
-		  /* Calculate count for remaining arc by conservation.  */
-		  total = block_graph[i].exec_count - total;
-		  /* Search for the invalid arc, and set its count.  */
-		  for (arc = block_graph[i].succ; arc;
-		       arc = arc->succ_next)
-		    if (! arc->count_valid)
-		      break;
-		  if (! arc)
-		    die ("arc == NULL\n");
-		  arc->count_valid = 1;
-		  arc->arc_count = total;
-		  block_graph[i].succ_count -= 1;
-
-		  block_graph[arc->target].pred_count -= 1;
-		  changes = 1;
-		}
-	      if (block_graph[i].pred_count == 1)
-		{
-		  total = 0;
-		  /* One of the counts will be invalid, but it is zero,
-		     so adding it in also doesn't hurt.  */
-		  for (arc = block_graph[i].pred; arc;
-		       arc = arc->pred_next)
-		    total += arc->arc_count;
-		  /* Calculate count for remaining arc by conservation.  */
-		  total = block_graph[i].exec_count - total;
-		  /* Search for the invalid arc, and set its count.  */
-		  for (arc = block_graph[i].pred; arc;
-		       arc = arc->pred_next)
-		    if (! arc->count_valid)
-		      break;
-		  if (! arc)
-                    die ("arc == NULL\n");
-		  arc->count_valid = 1;
-		  arc->arc_count = total;
-		  block_graph[i].pred_count -= 1;
-
-		  block_graph[arc->source].succ_count -= 1;
-		  changes = 1;
-		}
-	    }
-	}
-    }
-
-  /* If the graph has been correctly solved, every block will have a
-   * succ and pred count of zero.
-   */
-  {
-    dbus_bool_t header = FALSE;
-    for (i = 0; i < n_blocks; i++)
-      {
-        if (block_graph[i].succ_count || block_graph[i].pred_count)
-          {
-            if (!header)
-              {
-                fprintf (stderr, "WARNING: Block graph solved incorrectly for function %s\n",
-                         func->name);
-                fprintf (stderr, " this error reflects a bug in decode-gcov.c or perhaps bogus data\n");
-                header = TRUE;
-              }
-            fprintf (stderr, " block %d has succ_count = %d pred_count = %d\n",
-                     i, (int) block_graph[i].succ_count, (int) block_graph[i].pred_count);
-          }
-      }
-  }
-}
-
-static void
-solve_graphs (DBusList **functions)
-{
-  DBusList *link;
-
-  link = _dbus_list_get_first_link (functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      function_solve_graph (func);
-      
-      link = _dbus_list_get_next_link (functions, link);
-    }
-}
-
-static void
-load_functions_for_c_file (const DBusString *filename,
-                           DBusList        **functions)
-{
-  DBusString bbg_filename;
-  DBusString da_filename;
-  DBusString gcno_filename;
-  DBusString gcda_filename;
-  DBusString contents;
-  DBusString *name;
-  DBusError error;
-
-  /* With latest gcc it's .gcno instead of .bbg and
-   * gcda instead of .da
-   */
-  
-  dbus_error_init (&error);
-  
-  if (!_dbus_string_init (&bbg_filename) ||
-      !_dbus_string_init (&da_filename) ||
-      !_dbus_string_init (&gcno_filename) ||
-      !_dbus_string_init (&gcda_filename) ||
-      !_dbus_string_copy (filename, 0, &bbg_filename, 0) ||
-      !_dbus_string_copy (filename, 0, &da_filename, 0) ||
-      !_dbus_string_copy (filename, 0, &gcno_filename, 0) ||
-      !_dbus_string_copy (filename, 0, &gcda_filename, 0) ||
-      !_dbus_string_init (&contents))
-    die ("no memory\n");
-
-  _dbus_string_shorten (&bbg_filename, 2);
-  _dbus_string_shorten (&da_filename, 2);
-
-  if (!_dbus_string_append (&bbg_filename, ".bbg") ||
-      !_dbus_string_append (&da_filename, ".da") ||
-      !_dbus_string_append (&bbg_filename, ".gcno") ||
-      !_dbus_string_append (&bbg_filename, ".gcda"))
-    die ("no memory\n");
-
-  if (_dbus_file_exists (_dbus_string_get_const_data (&gcno_filename)))
-    name = &gcno_filename;
-  else
-    name = &bbg_filename;
-  
-  if (!_dbus_file_get_contents (&contents, name,
-                                &error))
-    {
-      fprintf (stderr, "Could not open file: %s\n",
-               error.message);
-      exit (1);
-    }
-
-  get_functions_from_bbg (&contents, functions);
-
-  _dbus_string_set_length (&contents, 0);
-
-  if (_dbus_file_exists (_dbus_string_get_const_data (&gcda_filename)))
-    name = &gcda_filename;
-  else
-    name = &da_filename;
-  
-  if (!_dbus_file_get_contents (&contents, name,
-                                &error))
-    {
-      /* Try .libs/file.da */
-      int slash;
-
-      if (_dbus_string_find_byte_backward (name,
-                                           _dbus_string_get_length (name),
-                                           '/',
-                                           &slash))
-        {
-          DBusString libs;
-          _dbus_string_init_const (&libs, "/.libs");
-
-          if (!_dbus_string_copy (&libs, 0, name, slash))
-            die ("no memory");
-
-          dbus_error_free (&error);
-          if (!_dbus_file_get_contents (&contents, name,
-                                        &error))
-            {
-              fprintf (stderr, "Could not open file: %s\n",
-                       error.message);
-              exit (1);
-            }
-        }
-      else
-        {
-          fprintf (stderr, "Could not open file: %s\n",
-                   error.message);
-          exit (1);
-        }
-    }
-  
-  add_counts_from_da (&contents, functions);
-  
-  solve_graphs (functions);
-
-  _dbus_string_free (&contents);
-  _dbus_string_free (&da_filename);
-  _dbus_string_free (&bbg_filename);
-}
-
-static void
-get_lines_from_bb_file (const DBusString *contents,
-                        File             *fl)
-{
-  int i;
-  long val;
-  int n_functions;
-  dbus_bool_t in_our_file;
-  DBusList *link;
-  Function *func;
-  int block;
-
-#if 0
-  printf ("Getting line numbers for blocks from .bb file\n");
-#endif
-  
-  /* There's this "filename" field in the .bb file which
-   * mysteriously comes *after* the first function in the
-   * file in the .bb file; and every .bb file seems to
-   * have only one filename. I don't understand
-   * what's going on here, so just set in_our_file = TRUE
-   * at the start categorically.
-   */
-  
-  block = 0;
-  func = NULL;
-  in_our_file = TRUE;
-  link = _dbus_list_get_first_link (&fl->functions);
-  n_functions = 0;
-  i = 0;
-  while (string_get_int (contents, i, &val))
-    {
-      i += 4;
-      
-      switch (val)
-        {
-        case BB_FILENAME:
-          {
-            DBusString f;
-
-            if (!_dbus_string_init (&f))
-              die ("no memory\n");
-
-            if (string_get_string (contents, i,
-                                   BB_FILENAME,
-                                   &f, &i))
-              {
-                /* fl->name is a full path and the filename in .bb is
-                 * not.
-                 */
-                DBusString tmp_str;
-
-                _dbus_string_init_const (&tmp_str, fl->name);
-                
-                if (_dbus_string_ends_with_c_str (&tmp_str,
-                                                  _dbus_string_get_const_data (&f)))
-                  in_our_file = TRUE;
-                else
-                  in_our_file = FALSE;
-                
-#if 0
-                fprintf (stderr,
-                         "File %s in .bb, looking for %s, in_our_file = %d\n",
-                         _dbus_string_get_const_data (&f),
-                         fl->name,
-                         in_our_file);
-#endif
-              }
-            _dbus_string_free (&f);
-          }
-          break;
-        case BB_FUNCTION:
-          {
-            DBusString f;
-            if (!_dbus_string_init (&f))
-              die ("no memory\n");
-
-            if (string_get_string (contents, i,
-                                   BB_FUNCTION,
-                                   &f, &i))
-              {
-#if 0
-                fprintf (stderr, "Function %s\n", _dbus_string_get_const_data (&f));
-#endif
-
-                block = 0;
-                
-                if (in_our_file)
-                  {
-                    if (link == NULL)
-                      {
-                        fprintf (stderr, "No function object for function %s\n",
-                                 _dbus_string_get_const_data (&f));
-                      }
-                    else
-                      {
-                        func = link->data;
-                        link = _dbus_list_get_next_link (&fl->functions, link);
-
-                        if (func->name == NULL)
-                          {
-                            if (!_dbus_string_copy_data (&f, &func->name))
-                              die ("no memory\n");
-                          }
-                        else
-                          {
-                            if (!_dbus_string_equal_c_str (&f, func->name))
-                              {
-                                fprintf (stderr, "got function name \"%s\" (%d) from .bbg file, but \"%s\" (%d) from .bb file\n",
-                                         func->name, strlen (func->name),
-                                         _dbus_string_get_const_data (&f),
-                                         _dbus_string_get_length (&f));
-
-                              }
-                          }
-                      }
-                  }
-              }
-            _dbus_string_free (&f);
-
-            n_functions += 1;
-          }
-          break;
-        case BB_ENDOFLIST:
-          block += 1;
-          break;
-        default:
-#if 0
-          fprintf (stderr, "Line %ld\n", val);
-#endif
-
-          if (val >= fl->n_lines)
-            {
-              fprintf (stderr, "Line %ld but file only has %d lines\n",
-                       val, fl->n_lines);
-            }
-          else if (func != NULL)
-            {
-              val -= 1; /* To convert the 1-based line number to 0-based */
-              _dbus_assert (val >= 0);
-              
-              if (block < func->n_blocks)
-                {
-                  if (!_dbus_list_append (&func->block_graph[block].lines,
-                                          &fl->lines[val]))
-                    die ("no memory\n");
-                  
-                  
-                  if (!_dbus_list_append (&fl->lines[val].blocks,
-                                          &func->block_graph[block]))
-                    die ("no memory\n");
-                }
-              else
-                {
-                  fprintf (stderr, "Line number for block %d but function only has %d blocks\n",
-                           block, func->n_blocks);
-                }
-            }
-          else
-            {
-              fprintf (stderr, "Line %ld given outside of any function\n",
-                       val);
-            }
-          
-          break;
-        }
-    }
-
-#if 0
-  printf ("%d functions in file\n", n_functions);
-#endif
-}
-
-
-static void
-load_block_line_associations (const DBusString *filename,
-                              File             *f)
-{
-  DBusString bb_filename;
-  DBusString contents;
-  DBusError error;
-
-  dbus_error_init (&error);
-  
-  if (!_dbus_string_init (&bb_filename) ||
-      !_dbus_string_copy (filename, 0, &bb_filename, 0) ||
-      !_dbus_string_init (&contents))
-    die ("no memory\n");
-
-  _dbus_string_shorten (&bb_filename, 2);
-
-  if (!_dbus_string_append (&bb_filename, ".bb"))
-    die ("no memory\n");
-      
-  if (!_dbus_file_get_contents (&contents, &bb_filename,
-                                &error))
-    {
-      fprintf (stderr, "Could not open file: %s\n",
-               error.message);
-      exit (1);
-    }
-  
-  get_lines_from_bb_file (&contents, f);
-
-  _dbus_string_free (&contents);
-  _dbus_string_free (&bb_filename);
-}
-
-static int
-count_lines_in_string (const DBusString *str)
-{
-  int n_lines;
-  const char *p;
-  const char *prev;
-  const char *end;
-  const char *last_line_end;
-
-#if 0
-  printf ("Counting lines in source file\n");
-#endif
-  
-  n_lines = 0;  
-  prev = NULL;
-  p = _dbus_string_get_const_data (str);
-  end = p + _dbus_string_get_length (str);
-  last_line_end = p;
-  while (p != end)
-    {
-      /* too lazy to handle \r\n as one linebreak */
-      if (*p == '\n' || *p == '\r')
-        {
-          ++n_lines;
-          last_line_end = p + 1;
-        }
-
-      prev = p;
-      ++p;
-    }
-
-  if (last_line_end != p)
-    ++n_lines;
-  
-  return n_lines;
-}
-
-static void
-fill_line_content (const DBusString *str,
-                   Line             *lines)
-{
-  int n_lines;
-  const char *p;
-  const char *prev;
-  const char *end;
-  const char *last_line_end;
-
-#if 0
-  printf ("Saving contents of each line in source file\n");
-#endif
-  
-  n_lines = 0;
-  prev = NULL;
-  p = _dbus_string_get_const_data (str);
-  end = p + _dbus_string_get_length (str);
-  last_line_end = p;
-  while (p != end)
-    {
-      if (*p == '\n' || *p == '\r')
-        {
-          lines[n_lines].text = dbus_malloc0 (p - last_line_end + 1);
-          if (lines[n_lines].text == NULL)
-            die ("no memory\n");
-
-          memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
-          lines[n_lines].number = n_lines + 1;
-          
-          ++n_lines;
-
-          last_line_end = p + 1;
-        }
-
-      prev = p;
-      ++p;
-    }
-
-  if (p != last_line_end)
-    {
-      memcpy (lines[n_lines].text, last_line_end, p - last_line_end);
-      ++n_lines;
-    }
-}
-
-static void
-mark_inside_dbus_build_tests (File  *f)
-{
-  int i;
-  DBusList *link;
-  int inside_depth;
-
-  inside_depth = 0;
-  i = 0;
-  while (i < f->n_lines)
-    {
-      Line *l = &f->lines[i];
-      dbus_bool_t is_verbose;
-
-      is_verbose = strstr (l->text, "_dbus_verbose") != NULL;
-
-      if (inside_depth == 0)
-        {
-          const char *a, *b;
-          
-          a = strstr (l->text, "#if");
-          b = strstr (l->text, "DBUS_BUILD_TESTS");
-          if (a && b && (a < b))
-            inside_depth += 1;
-        }
-      else
-        {
-          if (strstr (l->text, "#if") != NULL)
-            inside_depth += 1;
-          else if (strstr (l->text, "#endif") != NULL)
-            inside_depth -= 1;
-        }
-
-      if (inside_depth > 0 || is_verbose)
-        {
-          /* Mark the line and its blocks */
-          DBusList *blink;
-
-          l->inside_dbus_build_tests = TRUE;
-          
-          blink = _dbus_list_get_first_link (&l->blocks);
-          while (blink != NULL)
-            {
-              Block *b = blink->data;
-
-              b->inside_dbus_build_tests = TRUE;
-              
-              blink = _dbus_list_get_next_link (&l->blocks, blink);
-            }
-        }
-      
-      ++i;
-    }
-
-  /* Now mark functions where for all blocks that are associated
-   * with a source line, the block is inside_dbus_build_tests.
-   */
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      /* The issue is that some blocks aren't associated with a source line.
-       * Assume they are inside/outside tests according to the source
-       * line of the preceding block. For the first block, make it
-       * match the first following block with a line associated.
-       */
-      if (func->block_graph[0].lines == NULL)
-        {
-          /* find first following line */
-          i = 1;
-          while (i < func->n_blocks)
-            {
-              if (func->block_graph[i].lines != NULL)
-                {
-                  func->block_graph[0].inside_dbus_build_tests =
-                    func->block_graph[i].inside_dbus_build_tests;
-                  break;
-                }
-              
-              ++i;
-            }
-        }
-
-      /* Now mark all blocks but the first */
-      i = 1;
-      while (i < func->n_blocks)
-        {
-          if (func->block_graph[i].lines == NULL)
-            {
-              func->block_graph[i].inside_dbus_build_tests =
-                func->block_graph[i-1].inside_dbus_build_tests;
-            }
-          
-          ++i;
-        }
-      
-      i = 0;
-      while (i < func->n_blocks)
-        {
-          /* Break as soon as any block is not a test block */
-          if (func->block_graph[i].lines != NULL &&
-              !func->block_graph[i].inside_dbus_build_tests)
-            break;
-          
-          ++i;
-        }
-
-      if (i == func->n_blocks)
-        func->inside_dbus_build_tests = TRUE;
-      
-      link = _dbus_list_get_next_link (&f->functions, link);
-    } 
-}
-
-static void
-mark_coverage (File  *f)
-{
-  int i;
-  DBusList *link;
-  
-  i = 0;
-  while (i < f->n_lines)
-    {
-      Line *l = &f->lines[i];
-      DBusList *blink;
-      int n_blocks;
-      int n_blocks_executed;
-
-      n_blocks = 0;
-      n_blocks_executed = 0;
-      blink = _dbus_list_get_first_link (&l->blocks);
-      while (blink != NULL)
-        {
-          Block *b = blink->data;
-          
-          if (b->exec_count > 0)
-            n_blocks_executed += 1;
-
-          n_blocks += 1;
-          
-          blink = _dbus_list_get_next_link (&l->blocks, blink);
-        }
-
-      if (n_blocks_executed > 0 &&
-          n_blocks_executed < n_blocks)
-        l->partial = TRUE;
-
-      ++i;
-    }
-
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-      int i;
-      int n_test_blocks;
-      int n_test_blocks_executed;
-      int n_nontest_blocks;
-      int n_nontest_blocks_executed;
-      
-      n_test_blocks = 0;
-      n_test_blocks_executed = 0;
-      n_nontest_blocks = 0;
-      n_nontest_blocks_executed = 0;      
-
-      i = 0;
-      while (i < func->n_blocks)
-        {
-          if (!func->block_graph[i].inside_dbus_build_tests)
-            {
-              n_nontest_blocks += 1;
-
-              if (func->block_graph[i].exec_count > 0)
-                n_nontest_blocks_executed += 1;
-            }
-          else
-            {
-              n_test_blocks += 1;
-
-              if (func->block_graph[i].exec_count > 0)
-                n_test_blocks_executed += 1;
-            }
-
-          ++i;
-        }
-      
-      if (n_nontest_blocks_executed > 0 &&
-          n_nontest_blocks_executed < n_nontest_blocks)
-        func->partial = TRUE;
-
-      if (n_nontest_blocks_executed == 0 &&
-          n_nontest_blocks > 0)
-        func->unused = TRUE;
-      
-      func->n_test_blocks = n_test_blocks;
-      func->n_test_blocks_executed = n_test_blocks_executed;
-      func->n_nontest_blocks = n_nontest_blocks;
-      func->n_nontest_blocks_executed = n_nontest_blocks_executed;
-      
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-}
-
-static File*
-load_c_file (const DBusString *filename)
-{
-  DBusString contents;
-  DBusError error;
-  File *f;
-  
-  f = dbus_new0 (File, 1);
-  if (f == NULL)
-    die ("no memory\n");
-
-  if (!_dbus_string_copy_data (filename, &f->name))
-    die ("no memory\n");
-  
-  if (!_dbus_string_init (&contents))
-    die ("no memory\n");
-      
-  dbus_error_init (&error);
-
-  if (!_dbus_file_get_contents (&contents, filename,
-                                &error))
-    {
-      fprintf (stderr, "Could not open file: %s\n",
-               error.message);
-      dbus_error_free (&error);
-      exit (1);
-    }
-      
-  load_functions_for_c_file (filename, &f->functions);
-
-  f->n_lines = count_lines_in_string (&contents);
-  f->lines = dbus_new0 (Line, f->n_lines);
-  if (f->lines == NULL)
-    die ("no memory\n");
-
-  fill_line_content (&contents, f->lines);
-  
-  _dbus_string_free (&contents);
-
-  load_block_line_associations (filename, f);
-
-  mark_inside_dbus_build_tests (f);
-  mark_coverage (f);
-  
-  return f;
-}
-
-typedef struct Stats Stats;
-
-struct Stats
-{
-  int n_blocks;
-  int n_blocks_executed;
-  int n_blocks_inside_dbus_build_tests;
-  
-  int n_lines; /* lines that have blocks on them */
-  int n_lines_executed;
-  int n_lines_partial;
-  int n_lines_inside_dbus_build_tests;
-  
-  int n_functions;
-  int n_functions_executed;
-  int n_functions_partial;
-  int n_functions_inside_dbus_build_tests;
-};
-
-static dbus_bool_t
-line_was_executed (Line *l)
-{
-  DBusList *link;
-
-  link = _dbus_list_get_first_link (&l->blocks);
-  while (link != NULL)
-    {
-      Block *b = link->data;
-
-      if (b->exec_count > 0)
-        return TRUE;
-      
-      link = _dbus_list_get_next_link (&l->blocks, link);
-    }
-
-  return FALSE;
-}
-
-
-static int
-line_exec_count (Line *l)
-{
-  DBusList *link;
-  dbus_int64_t total;
-
-  total = 0;
-  link = _dbus_list_get_first_link (&l->blocks);
-  while (link != NULL)
-    {
-      Block *b = link->data;
-
-      total += b->exec_count;
-      
-      link = _dbus_list_get_next_link (&l->blocks, link);
-    }
-
-  return total;
-}
-
-static void
-merge_stats_for_file (Stats *stats,
-                      File  *f)
-{
-  int i;
-  DBusList *link;
-  
-  for (i = 0; i < f->n_lines; ++i)
-    {
-      Line *l = &f->lines[i];
-      
-      if (l->inside_dbus_build_tests)
-        {
-          stats->n_lines_inside_dbus_build_tests += 1;
-          continue;
-        }
-      
-      if (line_was_executed (l))
-        stats->n_lines_executed += 1;
-
-      if (l->blocks != NULL)
-        stats->n_lines += 1;
-
-      if (l->partial)
-        stats->n_lines_partial += 1;
-    }
-
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      if (func->inside_dbus_build_tests)
-        stats->n_functions_inside_dbus_build_tests += 1;
-      else
-        {
-          stats->n_functions += 1;
-
-          if (!func->unused)
-            stats->n_functions_executed += 1;
-          
-          if (func->partial)
-            stats->n_functions_partial += 1;
-        }
-
-      stats->n_blocks_inside_dbus_build_tests +=
-        func->n_test_blocks;
-      
-      stats->n_blocks_executed +=
-        func->n_nontest_blocks_executed;
-      
-      stats->n_blocks +=
-        func->n_nontest_blocks;
-
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-}
-
-/* The output of this matches gcov exactly ("diff" shows no difference) */
-static void
-print_annotated_source_gcov_format (File *f)
-{
-  int i;
-  
-  i = 0;
-  while (i < f->n_lines)
-    {
-      Line *l = &f->lines[i];
-
-      if (l->blocks != NULL)
-        {
-          int exec_count;
-          
-          exec_count = line_exec_count (l);
-          
-          if (exec_count > 0)
-            printf ("%12d    %s\n",
-                    exec_count, l->text);
-          else
-            printf ("      ######    %s\n", l->text);
-        }
-      else
-        {
-          printf ("\t\t%s\n", l->text);
-        }
-          
-      ++i;
-    }
-}
-
-static void
-print_annotated_source (File *f)
-{
-  int i;
-  
-  i = 0;
-  while (i < f->n_lines)
-    {
-      Line *l = &f->lines[i];
-
-      if (l->inside_dbus_build_tests)
-        printf ("*");
-      else
-        printf (" ");
-      
-      if (l->blocks != NULL)
-        {
-          int exec_count;
-          
-          exec_count = line_exec_count (l);
-          
-          if (exec_count > 0)
-            printf ("%12d    %s\n",
-                    exec_count, l->text);
-          else
-            printf ("      ######    %s\n", l->text);
-        }
-      else
-        {
-          printf ("\t\t%s\n", l->text);
-        }
-          
-      ++i;
-    }
-}
-
-static void
-print_block_superdetails (File *f)
-{
-  DBusList *link;
-  int i;
-  
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      printf ("=== %s():\n", func->name);
-
-      i = 0;
-      while (i < func->n_blocks)
-        {
-          Block *b = &func->block_graph[i];
-          DBusList *l;
-          
-          printf ("  %5d executed %d times%s\n", i,
-                  (int) b->exec_count,
-                  b->inside_dbus_build_tests ?
-                  " [inside DBUS_BUILD_TESTS]" : "");
-                  
-          l = _dbus_list_get_first_link (&b->lines);
-          while (l != NULL)
-            {
-              Line *line = l->data;
-
-              printf ("4%d\t%s\n", line->number, line->text);
-
-              l = _dbus_list_get_next_link (&b->lines, l);
-            }
-          
-          ++i;
-        }
-      
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-}
-
-static void
-print_one_file (const DBusString *filename)
-{
-  if (_dbus_string_ends_with_c_str (filename, ".bb"))
-    {
-      DBusString contents;
-      DBusError error;
-      
-      if (!_dbus_string_init (&contents))
-        die ("no memory\n");
-      
-      dbus_error_init (&error);
-
-      if (!_dbus_file_get_contents (&contents, filename,
-                                    &error))
-        {
-          fprintf (stderr, "Could not open file: %s\n",
-                   error.message);
-          dbus_error_free (&error);
-          exit (1);
-        }
-      
-      dump_bb_file (&contents);
-
-      _dbus_string_free (&contents);
-    }
-  else if (_dbus_string_ends_with_c_str (filename, ".bbg"))
-    {
-      DBusString contents;
-      DBusError error;
-      
-      if (!_dbus_string_init (&contents))
-        die ("no memory\n");
-      
-      dbus_error_init (&error);
-
-      if (!_dbus_file_get_contents (&contents, filename,
-                                    &error))
-        {
-          fprintf (stderr, "Could not open file: %s\n",
-                   error.message);
-          dbus_error_free (&error);
-          exit (1);
-        }
-      
-      dump_bbg_file (&contents);
-
-      _dbus_string_free (&contents);
-    }
-  else if (_dbus_string_ends_with_c_str (filename, ".da"))
-    {
-      DBusString contents;
-      DBusError error;
-      
-      if (!_dbus_string_init (&contents))
-        die ("no memory\n");
-      
-      dbus_error_init (&error);
-
-      if (!_dbus_file_get_contents (&contents, filename,
-                                    &error))
-        {
-          fprintf (stderr, "Could not open file: %s\n",
-                   error.message);
-          dbus_error_free (&error);
-          exit (1);
-        }
-      
-      dump_da_file (&contents);
-
-      _dbus_string_free (&contents);
-    }
-  else if (_dbus_string_ends_with_c_str (filename, ".c"))
-    {
-      File *f;
-      
-      f = load_c_file (filename);
-
-      print_annotated_source (f);
-    }
-  else
-    {
-      fprintf (stderr, "Unknown file type %s\n",
-               _dbus_string_get_const_data (filename));
-      exit (1);
-    }
-}
-
-static void
-print_untested_functions (File *f)
-{
-  DBusList *link;
-  dbus_bool_t found;
-
-  found = FALSE;
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      if (func->unused &&
-          !func->inside_dbus_build_tests)
-        found = TRUE;
-      
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-
-  if (!found)
-    return;
-  
-  printf ("Untested functions in %s\n", f->name);
-  printf ("=======\n");
-  
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      if (func->unused &&
-          !func->inside_dbus_build_tests)
-        printf ("  %s\n", func->name);
-      
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-
-  printf ("\n");
-}
-
-static void
-print_poorly_tested_functions (File  *f,
-                               Stats *stats)
-{
-  DBusList *link;
-  dbus_bool_t found;
-
-#define TEST_FRACTION(function) ((function)->n_nontest_blocks_executed / (double) (function)->n_nontest_blocks)
-
-#define AVERAGE_COVERAGE ((stats)->n_blocks_executed / (double) (stats)->n_blocks)
-  
-#define POORLY_TESTED(function) (!(function)->unused &&                 \
-                                 (function)->n_nontest_blocks > 0 &&    \
-                                 TEST_FRACTION (function) < AVERAGE_COVERAGE)
-  
-  found = FALSE;
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      if (POORLY_TESTED (func))
-        found = TRUE;
-      
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-
-  if (!found)
-    return;
-
-  printf ("Below average functions in %s\n", f->name);
-  printf ("=======\n");
-  
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      if (POORLY_TESTED (func))
-        printf ("  %s (%d%%)\n", func->name,
-                (int) (TEST_FRACTION (func) * 100));
-      
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-
-  printf ("\n");
-}
-
-static int
-func_cmp (const void *a,
-          const void *b)
-{
-  Function *af = *(Function**) a;
-  Function *bf = *(Function**) b;
-  int a_untested = af->n_nontest_blocks - af->n_nontest_blocks_executed;
-  int b_untested = bf->n_nontest_blocks - bf->n_nontest_blocks_executed;
-  
-  /* Sort by number of untested blocks */
-  return b_untested - a_untested;
-}
-
-static void
-print_n_untested_blocks_by_function (File  *f,
-                                     Stats *stats)
-{
-  DBusList *link;
-  Function **funcs;
-  int n_found;
-  int i;
-  
-  n_found = 0;
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      if (func->n_nontest_blocks_executed <
-          func->n_nontest_blocks)
-        n_found += 1;
-      
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-
-  if (n_found == 0)
-    return;
-
-  /* make an array so we can use qsort */
-  
-  funcs = dbus_new (Function*, n_found);
-  if (funcs == NULL)
-    return;
-  
-  i = 0;
-  link = _dbus_list_get_first_link (&f->functions);
-  while (link != NULL)
-    {
-      Function *func = link->data;
-
-      if (func->n_nontest_blocks_executed <
-          func->n_nontest_blocks)
-        {
-          funcs[i] = func;
-          ++i;
-        }
-
-      link = _dbus_list_get_next_link (&f->functions, link);
-    }
-
-  _dbus_assert (i == n_found);
-  
-  qsort (funcs, n_found, sizeof (Function*),
-         func_cmp);
-  
-  printf ("Incomplete functions in %s\n", f->name);
-  printf ("=======\n");
-
-  i = 0;
-  while (i < n_found)
-    {
-      Function *func = funcs[i];
-
-      printf ("  %s (%d/%d untested blocks)\n",
-              func->name,
-              func->n_nontest_blocks - func->n_nontest_blocks_executed,
-              func->n_nontest_blocks);
-      
-      ++i;
-    }
-
-  dbus_free (funcs);
-
-  printf ("\n");
-}
-
-static void
-print_stats (Stats      *stats,
-             const char *of_what)
-{
-  int completely;
-  
-  printf ("Summary (%s)\n", of_what);
-  printf ("=======\n");
-  printf ("  %g%% blocks executed (%d of %d)\n",
-          (stats->n_blocks_executed / (double) stats->n_blocks) * 100.0,
-          stats->n_blocks_executed,
-          stats->n_blocks);
-
-  printf ("     (ignored %d blocks of test-only/debug-only code)\n",
-          stats->n_blocks_inside_dbus_build_tests);
-      
-  printf ("  %g%% functions executed (%d of %d)\n",
-          (stats->n_functions_executed / (double) stats->n_functions) * 100.0,
-          stats->n_functions_executed,
-          stats->n_functions);
-
-  completely = stats->n_functions_executed - stats->n_functions_partial;
-  printf ("  %g%% functions completely executed (%d of %d)\n",
-          (completely / (double) stats->n_functions) * 100.0,
-          completely,
-          stats->n_functions);
-
-  printf ("     (ignored %d functions of test-only/debug-only code)\n",
-          stats->n_functions_inside_dbus_build_tests);
-      
-  printf ("  %g%% lines executed (%d of %d)\n",
-          (stats->n_lines_executed / (double) stats->n_lines) * 100.0,
-          stats->n_lines_executed,
-          stats->n_lines);
-
-  completely = stats->n_lines_executed - stats->n_lines_partial;
-  printf ("  %g%% lines completely executed (%d of %d)\n",
-          (completely / (double) stats->n_lines) * 100.0,
-          completely,
-          stats->n_lines);
-
-  printf ("     (ignored %d lines of test-only/debug-only code)\n",
-          stats->n_lines_inside_dbus_build_tests);
-
-  printf ("\n");
-}
-
-typedef enum
-{
-  MODE_PRINT,
-  MODE_REPORT,
-  MODE_BLOCKS,
-  MODE_GCOV
-} Mode;
-
-int
-main (int argc, char **argv)
-{
-  DBusString filename;
-  int i;
-  Mode m;
-  
-  if (argc < 2)
-    {
-      fprintf (stderr, "Must specify files on command line\n");
-      return 1;
-    }
-
-  m = MODE_PRINT;
-  i = 1;
-
-  if (strcmp (argv[i], "--report") == 0)
-    {
-      m = MODE_REPORT;
-      ++i;
-    }
-  else if (strcmp (argv[i], "--blocks") == 0)
-    {
-      m = MODE_BLOCKS;
-      ++i;
-    }
-  else if (strcmp (argv[i], "--gcov") == 0)
-    {
-      m = MODE_GCOV;
-      ++i;
-    }
-
-  
-  if (i == argc)
-    {
-      fprintf (stderr, "Must specify files on command line\n");
-      return 1;
-    }
-
-  if (m == MODE_PRINT)
-    {
-      while (i < argc)
-        {
-          _dbus_string_init_const (&filename, argv[i]);
-          
-          print_one_file (&filename);
-          
-          ++i;
-        }
-    }
-  else if (m == MODE_BLOCKS || m == MODE_GCOV)
-    {
-      while (i < argc)
-        {
-          File *f;
-          
-          _dbus_string_init_const (&filename, argv[i]);
-      
-          f = load_c_file (&filename);
-
-          if (m == MODE_BLOCKS)
-            print_block_superdetails (f);
-          else if (m == MODE_GCOV)
-            print_annotated_source_gcov_format (f);
-          
-          ++i;
-        }
-    }
-  else if (m == MODE_REPORT)
-    {
-      Stats stats = { 0, };
-      DBusList *files;
-      DBusList *link;
-      DBusHashTable *stats_by_dir;
-      DBusHashIter iter;
-      
-      files = NULL;
-      while (i < argc)
-        {
-          _dbus_string_init_const (&filename, argv[i]);
-
-          if (_dbus_string_ends_with_c_str (&filename, ".c"))
-            {
-              File *f;
-              
-              f = load_c_file (&filename);
-              
-              if (!_dbus_list_append (&files, f))
-                die ("no memory\n");
-            }
-          else
-            {
-              fprintf (stderr, "Unknown file type %s\n",
-                       _dbus_string_get_const_data (&filename));
-              exit (1);
-            }
-          
-          ++i;
-        }
-
-      link = _dbus_list_get_first_link (&files);
-      while (link != NULL)
-        {
-          File *f = link->data;
-
-          merge_stats_for_file (&stats, f);
-          
-          link = _dbus_list_get_next_link (&files, link);
-        }
-
-      print_stats (&stats, "all files");
-
-      stats_by_dir = _dbus_hash_table_new (DBUS_HASH_STRING,
-                                           dbus_free, dbus_free);
-      
-      link = _dbus_list_get_first_link (&files);
-      while (link != NULL)
-        {
-          File *f = link->data;
-          DBusString dirname;
-          char *dirname_c;
-          Stats *dir_stats;
-          
-          _dbus_string_init_const (&filename, f->name);
-            
-          if (!_dbus_string_init (&dirname))
-            die ("no memory\n");
-
-          if (!_dbus_string_get_dirname (&filename, &dirname) ||
-              !_dbus_string_copy_data (&dirname, &dirname_c))
-            die ("no memory\n");
-
-          dir_stats = _dbus_hash_table_lookup_string (stats_by_dir,
-                                                      dirname_c);
-
-          if (dir_stats == NULL)
-            {
-              dir_stats = dbus_new0 (Stats, 1);
-              if (!_dbus_hash_table_insert_string (stats_by_dir, dirname_c,
-                                                   dir_stats))
-                die ("no memory\n");
-            }
-          else
-            dbus_free (dirname_c);
-          
-          merge_stats_for_file (dir_stats, f);
-          
-          link = _dbus_list_get_next_link (&files, link);
-        }
-
-      _dbus_hash_iter_init (stats_by_dir, &iter);
-      while (_dbus_hash_iter_next (&iter))
-        {
-          const char *dirname = _dbus_hash_iter_get_string_key (&iter);
-          Stats *dir_stats = _dbus_hash_iter_get_value (&iter);
-
-          print_stats (dir_stats, dirname);
-        }
-
-      _dbus_hash_table_unref (stats_by_dir);
-
-      link = _dbus_list_get_first_link (&files);
-      while (link != NULL)
-        {
-          File *f = link->data;
-
-          print_untested_functions (f);
-          
-          link = _dbus_list_get_next_link (&files, link);
-        }
-
-      link = _dbus_list_get_first_link (&files);
-      while (link != NULL)
-        {
-          File *f = link->data;
-
-          print_poorly_tested_functions (f, &stats);
-          
-          link = _dbus_list_get_next_link (&files, link);
-        }
-
-      link = _dbus_list_get_first_link (&files);
-      while (link != NULL)
-        {
-          File *f = link->data;
-          
-          print_n_untested_blocks_by_function (f, &stats);
-          
-          link = _dbus_list_get_next_link (&files, link);
-        }
-    }
-  
-  return 0;
-}
diff --git a/test/internals/refs.c b/test/internals/refs.c
new file mode 100644
index 0000000..db43a4d
--- /dev/null
+++ b/test/internals/refs.c
@@ -0,0 +1,608 @@
+/* Regression test for thread-safe reference-counting
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define DBUS_COMPILATION    /* this test uses libdbus-internal */
+#include <dbus/dbus.h>
+#include <dbus/dbus-connection-internal.h>
+#include <dbus/dbus-mainloop.h>
+#include <dbus/dbus-message-internal.h>
+#include <dbus/dbus-pending-call-internal.h>
+#include <dbus/dbus-server-protected.h>
+#include "test-utils.h"
+
+static void
+assert_no_error (const DBusError *e)
+{
+  if (G_UNLIKELY (dbus_error_is_set (e)))
+    g_error ("expected success but got error: %s: %s", e->name, e->message);
+}
+
+#define N_THREADS 200
+#define N_REFS 10000
+G_STATIC_ASSERT (((unsigned) N_THREADS * (unsigned) N_REFS) < G_MAXINT32);
+
+static dbus_int32_t connection_slot = -1;
+static dbus_int32_t server_slot = -1;
+static dbus_int32_t message_slot = -1;
+static dbus_int32_t pending_call_slot = -1;
+
+typedef struct {
+  DBusError e;
+  DBusLoop *loop;
+  DBusServer *server;
+  DBusConnection *connection;
+  DBusConnection *server_connection;
+  DBusMessage *message;
+  GThread *threads[N_THREADS];
+  gboolean last_unref;
+} Fixture;
+
+typedef void *(*RefFunc) (void *);
+typedef void (*VoidFunc) (void *);
+
+typedef struct {
+  void *thing;
+  RefFunc ref;
+  VoidFunc ref_void;
+  VoidFunc unref;
+  void *mutex;
+  VoidFunc lock;
+  VoidFunc unlock;
+} Thread;
+
+/* provide backwards compatibility shim when building with a glib <= 2.30.x */
+#if !GLIB_CHECK_VERSION(2,31,0)
+#define g_thread_new(name,func,data) g_thread_create(func,data,TRUE,NULL)
+#endif
+
+static gpointer
+ref_thread (gpointer data)
+{
+  Thread *thread = data;
+  int i;
+
+  for (i = 0; i < N_REFS; i++)
+    {
+      if (thread->lock != NULL)
+        (thread->lock) (thread->mutex);
+
+      if (thread->ref != NULL)
+        {
+          gpointer ret = (thread->ref) (thread->thing);
+
+          g_assert (ret == thread->thing);
+        }
+      else
+        {
+          (thread->ref_void) (thread->thing);
+        }
+
+      if (thread->unlock != NULL)
+        (thread->unlock) (thread->mutex);
+    }
+
+  return NULL;
+}
+
+static gpointer
+cycle_thread (gpointer data)
+{
+  Thread *thread = data;
+  int i;
+
+  for (i = 0; i < N_REFS; i++)
+    {
+      if (thread->lock != NULL)
+        (thread->lock) (thread->mutex);
+
+      if (thread->ref != NULL)
+        {
+          gpointer ret = (thread->ref) (thread->thing);
+
+          g_assert (ret == thread->thing);
+        }
+      else
+        {
+          (thread->ref_void) (thread->thing);
+        }
+
+      (thread->unref) (thread->thing);
+
+      if (thread->unlock != NULL)
+        (thread->unlock) (thread->mutex);
+    }
+
+  return NULL;
+}
+
+static gpointer
+unref_thread (gpointer data)
+{
+  Thread *thread = data;
+  int i;
+
+  for (i = 0; i < N_REFS; i++)
+    {
+      if (thread->lock != NULL)
+        (thread->lock) (thread->mutex);
+
+      (thread->unref) (thread->thing);
+
+      if (thread->unlock != NULL)
+        (thread->unlock) (thread->mutex);
+    }
+
+  return NULL;
+}
+
+static void
+last_unref (void *data)
+{
+  Fixture *f = data;
+
+  g_assert (!f->last_unref);
+  f->last_unref = TRUE;
+}
+
+static void
+wait_for_all_threads (Fixture *f)
+{
+  int i;
+
+  for (i = 0; i < N_THREADS; i++)
+    g_thread_join (f->threads[i]);
+}
+
+static void
+new_conn_cb (DBusServer *server,
+    DBusConnection *server_connection,
+    void *data)
+{
+  Fixture *f = data;
+
+  g_assert (f->server_connection == NULL);
+  f->server_connection = dbus_connection_ref (server_connection);
+
+  test_connection_setup (f->loop, f->server_connection);
+}
+
+static void
+setup (Fixture *f,
+    gconstpointer data)
+{
+  if (!dbus_threads_init_default ())
+    g_error ("OOM");
+
+  f->loop = _dbus_loop_new ();
+  g_assert (f->loop != NULL);
+
+  dbus_error_init (&f->e);
+
+  f->server = dbus_server_listen ("tcp:host=127.0.0.1", &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->server != NULL);
+
+  if (!dbus_connection_allocate_data_slot (&connection_slot))
+    g_error ("OOM");
+
+  if (!dbus_server_allocate_data_slot (&server_slot))
+    g_error ("OOM");
+
+  if (!dbus_message_allocate_data_slot (&message_slot))
+    g_error ("OOM");
+
+  if (!dbus_pending_call_allocate_data_slot (&pending_call_slot))
+    g_error ("OOM");
+}
+
+static void
+setup_connection (Fixture *f,
+    gconstpointer data)
+{
+  char *address;
+
+  setup (f, data);
+
+  dbus_server_set_new_connection_function (f->server,
+      new_conn_cb, f, NULL);
+
+  if (!test_server_setup (f->loop, f->server))
+    g_error ("failed to set up server");
+
+  address = dbus_server_get_address (f->server);
+  g_assert (address != NULL);
+  f->connection = dbus_connection_open_private (address, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->connection != NULL);
+  dbus_free (address);
+
+  if (!test_connection_setup (f->loop, f->connection))
+    g_error ("failed to set up connection");
+
+  while (f->server_connection == NULL)
+    _dbus_loop_iterate (f->loop, TRUE);
+
+  test_connection_shutdown (f->loop, f->connection);
+  test_server_shutdown (f->loop, f->server);
+}
+
+static void
+test_connection (Fixture *f,
+    gconstpointer data)
+{
+  Thread public_api = { f->connection,
+    (RefFunc) dbus_connection_ref,
+    NULL,
+    (VoidFunc) dbus_connection_unref,
+    NULL,
+    NULL,
+    NULL };
+  Thread internal_api = { f->connection,
+    (RefFunc) _dbus_connection_ref_unlocked,
+    NULL,
+    (VoidFunc) _dbus_connection_unref_unlocked,
+    f->connection,
+    (VoidFunc) _dbus_connection_lock,
+    (VoidFunc) _dbus_connection_unlock };
+  int i;
+
+  /* Use a slot as a pseudo-weakref */
+  if (!dbus_connection_set_data (f->connection, connection_slot, f,
+        last_unref))
+    g_error ("OOM");
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      if ((i % 2) == 0)
+        f->threads[i] = g_thread_new (NULL, ref_thread, &public_api);
+      else
+        f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api);
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      if ((i % 2) == 0)
+        f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api);
+      else
+        f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api);
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      if ((i % 2) == 0)
+        f->threads[i] = g_thread_new (NULL, unref_thread, &public_api);
+      else
+        f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api);
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  /* Destroy the connection. This should be the last-unref. */
+  g_assert (!f->last_unref);
+  dbus_connection_close (f->connection);
+  dbus_connection_unref (f->connection);
+  f->connection = NULL;
+  g_assert (f->last_unref);
+}
+
+static void
+server_lock (void *server)
+{
+  SERVER_LOCK (((DBusServer *) server));
+}
+
+static void
+server_unlock (void *server)
+{
+  SERVER_UNLOCK (((DBusServer *) server));
+}
+
+static void
+test_server (Fixture *f,
+    gconstpointer data)
+{
+  Thread public_api = { f->server,
+    (RefFunc) dbus_server_ref,
+    NULL,
+    (VoidFunc) dbus_server_unref,
+    NULL,
+    NULL,
+    NULL };
+  Thread internal_api = { f->server,
+    NULL,
+    (VoidFunc) _dbus_server_ref_unlocked,
+    (VoidFunc) _dbus_server_unref_unlocked,
+    f->server,
+    server_lock,
+    server_unlock };
+  int i;
+
+  if (!dbus_server_set_data (f->server, server_slot, f, last_unref))
+    g_error ("OOM");
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      if ((i % 2) == 0)
+        f->threads[i] = g_thread_new (NULL, ref_thread, &public_api);
+      else
+        f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api);
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      if ((i % 2) == 0)
+        f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api);
+      else
+        f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api);
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      if ((i % 2) == 0)
+        f->threads[i] = g_thread_new (NULL, unref_thread, &public_api);
+      else
+        f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api);
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  /* Destroy the server. This should be the last-unref. */
+  g_assert (!f->last_unref);
+  dbus_server_disconnect (f->server);
+  dbus_server_unref (f->server);
+  f->server = NULL;
+  g_assert (f->last_unref);
+}
+
+static void
+test_message (Fixture *f,
+    gconstpointer data)
+{
+  DBusMessage *message = dbus_message_new_signal ("/foo", "foo.bar.baz",
+      "Foo");
+  Thread public_api = { message,
+    (RefFunc) dbus_message_ref,
+    NULL,
+    (VoidFunc) dbus_message_unref,
+    NULL,
+    NULL,
+    NULL };
+  int i;
+
+  if (!dbus_message_set_data (message, message_slot, f, last_unref))
+    g_error ("OOM");
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      f->threads[i] = g_thread_new (NULL, ref_thread, &public_api);
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api);
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      f->threads[i] = g_thread_new (NULL, unref_thread, &public_api);
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  /* Destroy the server. This should be the last-unref. */
+  g_assert (!f->last_unref);
+  dbus_message_unref (message);
+  g_assert (f->last_unref);
+}
+
+static void
+test_pending_call (Fixture *f,
+    gconstpointer data)
+{
+  Thread public_api = { NULL,
+    (RefFunc) dbus_pending_call_ref,
+    NULL,
+    (VoidFunc) dbus_pending_call_unref,
+    NULL,
+    NULL,
+    NULL };
+  Thread internal_api = { NULL,
+    (RefFunc) _dbus_pending_call_ref_unlocked,
+    NULL,
+    (VoidFunc) dbus_pending_call_unref,
+    f->connection,
+    (VoidFunc) _dbus_connection_lock,
+    (VoidFunc) _dbus_connection_unlock };
+  /* This one can't be used to ref, only to cycle or unref. */
+  Thread unref_and_unlock_api = { NULL,
+    (RefFunc) _dbus_pending_call_ref_unlocked,
+    NULL,
+    (VoidFunc) _dbus_pending_call_unref_and_unlock,
+    f->connection,
+    (VoidFunc) _dbus_connection_lock,
+    NULL };
+  int i;
+  DBusPendingCall *pending_call;
+
+  _dbus_connection_lock (f->connection);
+  pending_call = _dbus_pending_call_new_unlocked (f->connection,
+      DBUS_TIMEOUT_INFINITE, NULL);
+  g_assert (pending_call != NULL);
+  _dbus_connection_unlock (f->connection);
+
+  public_api.thing = pending_call;
+  internal_api.thing = pending_call;
+  unref_and_unlock_api.thing = pending_call;
+
+  if (!dbus_pending_call_set_data (pending_call, pending_call_slot, f,
+        last_unref))
+    g_error ("OOM");
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      if ((i % 2) == 0)
+        f->threads[i] = g_thread_new (NULL, ref_thread, &public_api);
+      else
+        f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api);
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      switch (i % 3)
+        {
+          case 0:
+            f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api);
+            break;
+          case 1:
+            f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api);
+            break;
+          default:
+            f->threads[i] = g_thread_new (NULL, cycle_thread,
+                &unref_and_unlock_api);
+        }
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  for (i = 0; i < N_THREADS; i++)
+    {
+      switch (i % 3)
+        {
+          case 0:
+            f->threads[i] = g_thread_new (NULL, unref_thread, &public_api);
+            break;
+          case 1:
+            f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api);
+            break;
+          default:
+            f->threads[i] = g_thread_new (NULL, unref_thread,
+                &unref_and_unlock_api);
+        }
+
+      g_assert (f->threads[i] != NULL);
+    }
+
+  wait_for_all_threads (f);
+
+  /* Destroy the pending call. This should be the last-unref. */
+  g_assert (!f->last_unref);
+  dbus_pending_call_unref (pending_call);
+  g_assert (f->last_unref);
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer data)
+{
+  if (f->server_connection != NULL)
+    {
+      dbus_connection_close (f->server_connection);
+      dbus_connection_unref (f->server_connection);
+    }
+
+  if (f->connection != NULL)
+    {
+      dbus_connection_close (f->connection);
+      dbus_connection_unref (f->connection);
+    }
+
+  if (f->server != NULL)
+    {
+      dbus_server_disconnect (f->server);
+      dbus_server_unref (f->server);
+    }
+
+  dbus_connection_free_data_slot (&connection_slot);
+  dbus_server_free_data_slot (&server_slot);
+  dbus_message_free_data_slot (&message_slot);
+  dbus_pending_call_free_data_slot (&pending_call_slot);
+
+  _dbus_loop_unref (f->loop);
+  dbus_error_free (&f->e);
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  /* In GLib >= 2.24, < 2.31 this acts like g_thread_init() but avoids
+   * the deprecation of that function. In GLib >= 2.32 this is not
+   * necessary at all.
+   */
+  g_type_init ();
+
+  g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+
+  g_test_add ("/refs/connection", Fixture, NULL, setup_connection,
+      test_connection, teardown);
+  g_test_add ("/refs/message", Fixture, NULL, setup,
+      test_message, teardown);
+  g_test_add ("/refs/pending-call", Fixture, NULL, setup_connection,
+      test_pending_call, teardown);
+  g_test_add ("/refs/server", Fixture, NULL, setup,
+      test_server, teardown);
+
+  return g_test_run ();
+}
diff --git a/test/internals/syslog.c b/test/internals/syslog.c
new file mode 100644
index 0000000..4f6b7c2
--- /dev/null
+++ b/test/internals/syslog.c
@@ -0,0 +1,100 @@
+/* Manual regression test for syslog support
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <glib.h>
+
+#define DBUS_COMPILATION    /* this test uses libdbus-internal */
+#include <dbus/dbus.h>
+#include <dbus/dbus-sysdeps.h>
+
+typedef struct {
+    int dummy;
+} Fixture;
+
+static void
+setup (Fixture *f,
+    gconstpointer data)
+{
+}
+
+/* hopefully clear enough that people don't think these messages in syslog
+ * are a bug */
+#define MESSAGE "regression test for _dbus_system_log(): "
+
+static void
+test_syslog (Fixture *f,
+    gconstpointer data)
+{
+  if (g_test_trap_fork (0, 0))
+    {
+      _dbus_init_system_log ();
+      _dbus_system_log (DBUS_SYSTEM_LOG_FATAL, MESSAGE "%d", 23);
+      /* should not be reached: exit 0 so the assertion in the main process
+       * will fail */
+      exit (0);
+    }
+
+  g_test_trap_assert_failed ();
+  g_test_trap_assert_stderr ("*" MESSAGE "23\n*");
+
+  if (g_test_trap_fork (0, 0))
+    {
+      _dbus_init_system_log ();
+      _dbus_system_log (DBUS_SYSTEM_LOG_INFO, MESSAGE "%d", 42);
+      _dbus_system_log (DBUS_SYSTEM_LOG_SECURITY, MESSAGE "%d", 666);
+      exit (0);
+    }
+
+  g_test_trap_assert_passed ();
+  g_test_trap_assert_stderr ("*" MESSAGE "42\n*" MESSAGE "666\n*");
+
+  /* manual test (this is the best we can do on Windows) */
+  _dbus_init_system_log ();
+  _dbus_system_log (DBUS_SYSTEM_LOG_INFO, MESSAGE "%d", 42);
+  _dbus_system_log (DBUS_SYSTEM_LOG_SECURITY, MESSAGE "%d", 666);
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer data)
+{
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+
+  g_test_add ("/syslog", Fixture, NULL, setup, test_syslog, teardown);
+
+  return g_test_run ();
+}
diff --git a/test/loopback.c b/test/loopback.c
new file mode 100644
index 0000000..d0d69c8
--- /dev/null
+++ b/test/loopback.c
@@ -0,0 +1,211 @@
+/* Simple sanity-check for loopback through TCP and Unix sockets.
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2010-2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+typedef struct {
+    DBusError e;
+
+    DBusServer *server;
+    DBusConnection *server_conn;
+    /* queue of DBusMessage */
+    GQueue server_messages;
+
+    DBusConnection *client_conn;
+} Fixture;
+
+static void
+assert_no_error (const DBusError *e)
+{
+  if (G_UNLIKELY (dbus_error_is_set (e)))
+    g_error ("expected success but got error: %s: %s", e->name, e->message);
+}
+
+static DBusHandlerResult
+server_message_cb (DBusConnection *server_conn,
+    DBusMessage *message,
+    void *data)
+{
+  Fixture *f = data;
+
+  g_assert (server_conn == f->server_conn);
+  g_queue_push_tail (&f->server_messages, dbus_message_ref (message));
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+new_conn_cb (DBusServer *server,
+    DBusConnection *server_conn,
+    void *data)
+{
+  Fixture *f = data;
+  dbus_bool_t have_mem;
+
+  g_assert (f->server_conn == NULL);
+  f->server_conn = dbus_connection_ref (server_conn);
+  dbus_connection_setup_with_g_main (server_conn, NULL);
+
+  have_mem = dbus_connection_add_filter (server_conn,
+      server_message_cb, f, NULL);
+  g_assert (have_mem);
+}
+
+static void
+setup (Fixture *f,
+    gconstpointer addr)
+{
+  dbus_error_init (&f->e);
+  g_queue_init (&f->server_messages);
+
+  f->server = dbus_server_listen (addr, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->server != NULL);
+
+  dbus_server_set_new_connection_function (f->server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->server, NULL);
+}
+
+static void
+test_connect (Fixture *f,
+    gconstpointer addr G_GNUC_UNUSED)
+{
+  g_assert (f->server_conn == NULL);
+
+  f->client_conn = dbus_connection_open_private (
+      dbus_server_get_address (f->server), &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->client_conn != NULL);
+  dbus_connection_setup_with_g_main (f->client_conn, NULL);
+
+  while (f->server_conn == NULL)
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+}
+
+static void
+test_message (Fixture *f,
+    gconstpointer addr)
+{
+  dbus_bool_t have_mem;
+  dbus_uint32_t serial;
+  DBusMessage *outgoing, *incoming;
+
+  test_connect (f, addr);
+
+  outgoing = dbus_message_new_signal ("/com/example/Hello",
+      "com.example.Hello", "Greeting");
+  g_assert (outgoing != NULL);
+
+  have_mem = dbus_connection_send (f->client_conn, outgoing, &serial);
+  g_assert (have_mem);
+  g_assert (serial != 0);
+
+  while (g_queue_is_empty (&f->server_messages))
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+
+  g_assert_cmpuint (g_queue_get_length (&f->server_messages), ==, 1);
+
+  incoming = g_queue_pop_head (&f->server_messages);
+
+  g_assert (!dbus_message_contains_unix_fds (incoming));
+  g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
+      "com.example.Hello");
+  g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
+  g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
+  g_assert_cmpstr (dbus_message_get_signature (incoming), ==, "");
+  g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello");
+  g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial);
+
+  dbus_message_unref (incoming);
+
+  dbus_message_unref (outgoing);
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer addr G_GNUC_UNUSED)
+{
+  if (f->client_conn != NULL)
+    {
+      dbus_connection_close (f->client_conn);
+      dbus_connection_unref (f->client_conn);
+      f->client_conn = NULL;
+    }
+
+  if (f->server_conn != NULL)
+    {
+      dbus_connection_close (f->server_conn);
+      dbus_connection_unref (f->server_conn);
+      f->server_conn = NULL;
+    }
+
+  if (f->server != NULL)
+    {
+      dbus_server_disconnect (f->server);
+      dbus_server_unref (f->server);
+      f->server = NULL;
+    }
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add ("/connect/tcp", Fixture, "tcp:host=127.0.0.1", setup,
+      test_connect, teardown);
+  g_test_add ("/message/tcp", Fixture, "tcp:host=127.0.0.1", setup,
+      test_message, teardown);
+
+  g_test_add ("/connect/nonce-tcp", Fixture, "nonce-tcp:host=127.0.0.1", setup,
+      test_connect, teardown);
+  g_test_add ("/message/nonce-tcp", Fixture, "nonce-tcp:host=127.0.0.1", setup,
+      test_message, teardown);
+
+#ifdef DBUS_UNIX
+  g_test_add ("/connect/unix", Fixture, "unix:tmpdir=/tmp", setup,
+      test_connect, teardown);
+  g_test_add ("/message/unix", Fixture, "unix:tmpdir=/tmp", setup,
+      test_message, teardown);
+#endif
+
+  return g_test_run ();
+}
diff --git a/test/marshal.c b/test/marshal.c
new file mode 100644
index 0000000..e9ac7e3
--- /dev/null
+++ b/test/marshal.c
@@ -0,0 +1,257 @@
+/* Simple sanity-check for D-Bus message serialization.
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2010-2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+typedef struct {
+    DBusError e;
+} Fixture;
+
+static void
+assert_no_error (const DBusError *e)
+{
+  if (G_UNLIKELY (dbus_error_is_set (e)))
+    g_error ("expected success but got error: %s: %s", e->name, e->message);
+}
+
+static void
+setup (Fixture *f,
+    gconstpointer arg G_GNUC_UNUSED)
+{
+  dbus_error_init (&f->e);
+}
+
+/* this is meant to be obviously correct, not efficient! */
+static guint32
+get_uint32 (const gchar *blob,
+    gsize offset,
+    char endian)
+{
+  if (endian == 'l')
+    {
+      return
+        blob[offset] |
+        (blob[offset + 1] << 8) |
+        (blob[offset + 2] << 16) |
+        (blob[offset + 3] << 24);
+    }
+  else if (endian == 'B')
+    {
+      return
+        (blob[offset] << 24) |
+        (blob[offset + 1] << 16) |
+        (blob[offset + 2] << 8) |
+        blob[offset + 3];
+    }
+  else
+    {
+      g_assert_not_reached ();
+    }
+}
+
+#define BLOB_LENGTH (sizeof (le_blob) - 1)
+#define OFFSET_BODY_LENGTH (4)
+#define OFFSET_SERIAL (8)
+
+const gchar le_blob[] =
+    /* byte 0 */
+    /* yyyyuu fixed headers */
+    "l"                     /* little-endian */
+    "\2"                    /* reply (which is the simplest message) */
+    "\2"                    /* no auto-starting */
+    "\1"                    /* D-Bus version = 1 */
+    /* byte 4 */
+    "\4\0\0\0"              /* bytes in body = 4 */
+    /* byte 8 */
+    "\x78\x56\x34\x12"      /* serial number = 0x12345678 */
+    /* byte 12 */
+    /* a(uv) variable headers start here */
+    "\x0f\0\0\0"            /* bytes in array of variable headers = 15 */
+                            /* pad to 8-byte boundary = nothing */
+    /* byte 16 */
+    "\5"                    /* in reply to: */
+        "\1u\0"             /* variant signature = u */
+                            /* pad to 4-byte boundary = nothing */
+        "\x12\xef\xcd\xab"  /* 0xabcdef12 */
+                            /* pad to 8-byte boundary = nothing */
+    /* byte 24 */
+    "\x08"                  /* signature: */
+        "\1g\0"             /* variant signature = g */
+        "\1u\0"             /* 1 byte, u, NUL (no alignment needed) */
+        "\0"                /* pad to 8-byte boundary for body */
+    /* body; byte 32 */
+    "\xef\xbe\xad\xde"      /* 0xdeadbeef */
+    ;
+
+const gchar be_blob[] =
+    /* byte 0 */
+    /* yyyyuu fixed headers */
+    "B"                     /* big-endian */
+    "\2"                    /* reply (which is the simplest message) */
+    "\2"                    /* no auto-starting */
+    "\1"                    /* D-Bus version = 1 */
+    /* byte 4 */
+    "\0\0\0\4"              /* bytes in body = 4 */
+    /* byte 8 */
+    "\x12\x34\x56\x78"      /* serial number = 0x12345678 */
+    /* byte 12 */
+    /* a(uv) variable headers start here */
+    "\0\0\0\x0f"            /* bytes in array of variable headers = 15 */
+                            /* pad to 8-byte boundary = nothing */
+    /* byte 16 */
+    "\5"                    /* in reply to: */
+        "\1u\0"             /* variant signature = u */
+                            /* pad to 4-byte boundary = nothing */
+        "\xab\xcd\xef\x12"  /* 0xabcdef12 */
+                            /* pad to 8-byte boundary = nothing */
+    /* byte 24 */
+    "\x08"                  /* signature: */
+        "\1g\0"             /* variant signature = g */
+        "\1u\0"             /* 1 byte, u, NUL (no alignment needed) */
+        "\0"                /* pad to 8-byte boundary for body */
+    /* body; byte 32 */
+    "\xde\xad\xbe\xef"      /* 0xdeadbeef */
+    ;
+
+static void
+test_endian (Fixture *f,
+    gconstpointer arg)
+{
+  const gchar *blob = arg;
+  char *output;
+  DBusMessage *m;
+  int len;
+  dbus_uint32_t u;
+  dbus_bool_t ok;
+
+  g_assert_cmpuint ((guint) sizeof (le_blob), ==, (guint) sizeof (be_blob));
+
+  g_assert_cmpuint (get_uint32 (blob, OFFSET_BODY_LENGTH, blob[0]), ==, 4);
+  g_assert_cmpuint (get_uint32 (blob, OFFSET_SERIAL, blob[0]), ==,
+      0x12345678u);
+
+  len = dbus_message_demarshal_bytes_needed (blob, sizeof (le_blob));
+  /* everything in the string except the implicit "\0" at the end is part of
+   * the message */
+  g_assert_cmpint (len, ==, BLOB_LENGTH);
+
+  m = dbus_message_demarshal (blob, sizeof (le_blob), &f->e);
+  assert_no_error (&f->e);
+  g_assert (m != NULL);
+
+  g_assert_cmpuint (dbus_message_get_serial (m), ==, 0x12345678u);
+  g_assert_cmpuint (dbus_message_get_reply_serial (m), ==, 0xabcdef12u);
+  g_assert_cmpstr (dbus_message_get_signature (m), ==, "u");
+
+  /* Implementation detail: appending to the message results in it being
+   * byteswapped into compiler byte order, which exposed a bug in libdbus,
+   * fd.o #38120. (If that changes, this test might not exercise that
+   * particular bug but will still be valid.) */
+  u = 0xdecafbadu;
+  ok = dbus_message_append_args (m,
+      DBUS_TYPE_UINT32, &u,
+      DBUS_TYPE_INVALID);
+  g_assert (ok);
+
+  dbus_message_marshal (m, &output, &len);
+
+  g_assert (output[0] == 'l' || output[0] == 'B');
+  /* the single-byte fields are unaffected, even if the endianness was
+   * swapped */
+  g_assert_cmpint (output[1], ==, blob[1]);
+  g_assert_cmpint (output[2], ==, blob[2]);
+  g_assert_cmpint (output[3], ==, blob[3]);
+  /* the length and serial are in the new endianness, the length has expanded
+   * to 8, and the serial is correct */
+  g_assert_cmpuint (get_uint32 (output, OFFSET_BODY_LENGTH, output[0]), ==, 8);
+  g_assert_cmpuint (get_uint32 (output, OFFSET_SERIAL, output[0]), ==,
+      0x12345678u);
+  /* the second "u" in the signature replaced a padding byte, so only
+   * the length of the body changed */
+  g_assert_cmpint (len, ==, BLOB_LENGTH + 4);
+}
+
+static void
+test_needed (Fixture *f,
+    gconstpointer arg)
+{
+  const gchar *blob = arg;
+
+  /* We need at least 16 bytes to know how long the message is - that's just
+   * a fact of the D-Bus protocol. */
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, 0), ==, 0);
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, 15), ==, 0);
+  /* This is enough that we should be able to tell how much we need. */
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, 16), ==, BLOB_LENGTH);
+  /* The header is 32 bytes long (here), so that's another interesting
+   * boundary. */
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, 31), ==, BLOB_LENGTH);
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, 32), ==, BLOB_LENGTH);
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, 33), ==, BLOB_LENGTH);
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH - 1), ==,
+      BLOB_LENGTH);
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH), ==,
+      BLOB_LENGTH);
+  g_assert_cmpint (
+      dbus_message_demarshal_bytes_needed (blob, sizeof (be_blob)), ==,
+      BLOB_LENGTH);
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer arg G_GNUC_UNUSED)
+{
+  dbus_error_free (&f->e);
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add ("/demarshal/le", Fixture, le_blob, setup, test_endian, teardown);
+  g_test_add ("/demarshal/be", Fixture, be_blob, setup, test_endian, teardown);
+  g_test_add ("/demarshal/needed/le", Fixture, le_blob, setup, test_needed,
+      teardown);
+  g_test_add ("/demarshal/needed/be", Fixture, be_blob, setup, test_needed,
+      teardown);
+
+  return g_test_run ();
+}
diff --git a/test/name-test/.gitignore b/test/name-test/.gitignore
index 7e4233e..09f7ad3 100644
--- a/test/name-test/.gitignore
+++ b/test/name-test/.gitignore
@@ -2,9 +2,14 @@
 .libs
 Makefile
 Makefile.in
+echo-error-output.tmp
+run-with-tmp-session-bus.conf
+test-ids
 test-names
 test-pending-call-dispatch
 test-pending-call-timeout
+test-privserver
+test-privserver-client
+test-shutdown
 test-threads-init
-test-ids
-run-with-tmp-session-bus.conf
+test-autolaunch
diff --git a/test/name-test/Makefile.am b/test/name-test/Makefile.am
index 11dc56d..6aaf178 100644
--- a/test/name-test/Makefile.am
+++ b/test/name-test/Makefile.am
@@ -1,10 +1,18 @@
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_TEST_CFLAGS) -DDBUS_COMPILATION
+# Everything in this directory is statically-linked to libdbus-internal
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	-DDBUS_COMPILATION \
+	-DDBUS_STATIC_BUILD \
+	$(NULL)
+
+# if assertions are enabled, improve backtraces
+AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
 
 ## note that TESTS has special meaning (stuff to use in make check)
 ## so if adding tests not to be run in make check, don't add them to 
 ## TESTS
 if DBUS_BUILD_TESTS
-TESTS_ENVIRONMENT=DBUS_TOP_BUILDDIR=@abs_top_builddir@ DBUS_TOP_SRCDIR=@abs_top_srcdir@
+TESTS_ENVIRONMENT=DBUS_TOP_BUILDDIR=@abs_top_builddir@ DBUS_TOP_SRCDIR=@abs_top_srcdir@ PYTHON=@PYTHON@
 TESTS=run-test.sh run-test-systemserver.sh
 else
 TESTS=
@@ -16,52 +24,16 @@
 
 ## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we
 ## build even when not doing "make check"
-noinst_PROGRAMS=test-pending-call-dispatch test-pending-call-timeout test-threads-init test-ids test-shutdown test-privserver test-privserver-client
+noinst_PROGRAMS=test-pending-call-dispatch test-pending-call-timeout test-threads-init test-ids test-shutdown test-privserver test-privserver-client test-autolaunch
 
-AM_CPPFLAGS = -DDBUS_STATIC_BUILD
-test_pending_call_dispatch_SOURCES =		\
-	test-pending-call-dispatch.c
+test_pending_call_dispatch_LDADD=$(top_builddir)/dbus/libdbus-internal.la
+test_pending_call_timeout_LDADD=$(top_builddir)/dbus/libdbus-internal.la
+test_threads_init_LDADD=$(top_builddir)/dbus/libdbus-internal.la
+test_ids_LDADD=$(top_builddir)/dbus/libdbus-internal.la
 
-test_pending_call_dispatch_LDADD=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_TEST_LIBS)
-test_pending_call_dispatch_LDFLAGS=@R_DYNAMIC_LDFLAG@
-
-test_pending_call_timeout_SOURCES =		\
-	test-pending-call-timeout.c
-
-test_pending_call_timeout_LDADD=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_TEST_LIBS)
-test_pending_call_timeout_LDFLAGS=@R_DYNAMIC_LDFLAG@
-
-test_threads_init_SOURCES =            \
-	test-threads-init.c
-
-test_threads_init_LDADD=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_TEST_LIBS)
-test_threads_init_LDFLAGS=@R_DYNAMIC_LDFLAG@
-
-test_ids_SOURCES =            \
-	test-ids.c
-
-test_ids_LDADD=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_TEST_LIBS)
-test_ids_LDFLAGS=@R_DYNAMIC_LDFLAG@
-
-test_shutdown_SOURCES =            \
-	test-shutdown.c
-
-test_shutdown_CFLAGS=
-test_shutdown_LDADD=$(top_builddir)/dbus/libdbus-internal.la ../libdbus-testutils.la $(DBUS_TEST_LIBS)
-test_shutdown_LDFLAGS=@R_DYNAMIC_LDFLAG@
-
-test_privserver_SOURCES =            \
-	test-privserver.c
-
-test_privserver_CFLAGS=
-test_privserver_LDADD=$(top_builddir)/dbus/libdbus-internal.la ../libdbus-testutils.la $(DBUS_TEST_LIBS)
-test_privserver_LDFLAGS=@R_DYNAMIC_LDFLAG@
-
-test_privserver_client_SOURCES =            \
-	test-privserver-client.c
-
-test_privserver_client_CFLAGS=
-test_privserver_client_LDADD=$(top_builddir)/dbus/libdbus-internal.la ../libdbus-testutils.la $(DBUS_TEST_LIBS)
-test_privserver_client_LDFLAGS=@R_DYNAMIC_LDFLAG@
+test_shutdown_LDADD=../libdbus-testutils.la
+test_privserver_LDADD=../libdbus-testutils.la
+test_privserver_client_LDADD=../libdbus-testutils.la
+test_autolaunch_LDADD=../libdbus-testutils.la
 
 endif
diff --git a/test/name-test/run-test-systemserver.sh b/test/name-test/run-test-systemserver.sh
index d3b8d55..afd1f04 100755
--- a/test/name-test/run-test-systemserver.sh
+++ b/test/name-test/run-test-systemserver.sh
@@ -41,10 +41,11 @@
 fi
 
 echo "running test echo signal"
-if ! python $DBUS_TOP_SRCDIR/test/name-test/test-wait-for-echo.py; then
+if test "x$PYTHON" = "x:"; then
+  echo "Skipped test-echo-signal: Python interpreter not found"
+elif ! $PYTHON $DBUS_TOP_SRCDIR/test/name-test/test-wait-for-echo.py; then
   echo "Failed test-wait-for-echo"
   exit 1
 fi
 
-
 exit 0
diff --git a/test/name-test/run-test.sh b/test/name-test/run-test.sh
index 832ce0a..cad5937 100644
--- a/test/name-test/run-test.sh
+++ b/test/name-test/run-test.sh
@@ -49,7 +49,12 @@
 ${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-shutdown || die "test-shutdown failed"
 
 echo "running test activation forking"
-if ! python $DBUS_TOP_SRCDIR/test/name-test/test-activation-forking.py; then
+if test "x$PYTHON" = "x:"; then
+  echo "Skipped test-activation-forking: Python interpreter not found"
+elif ! $PYTHON $DBUS_TOP_SRCDIR/test/name-test/test-activation-forking.py; then
   echo "Failed test-activation-forking"
   exit 1
 fi
+
+echo "running test-autolaunch"
+${DBUS_TOP_BUILDDIR}/libtool --mode=execute $DEBUG $DBUS_TOP_BUILDDIR/test/name-test/test-autolaunch || die "test-autolaunch failed"
diff --git a/test/name-test/test-autolaunch.c b/test/name-test/test-autolaunch.c
new file mode 100644
index 0000000..5e51989
--- /dev/null
+++ b/test/name-test/test-autolaunch.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <dbus/dbus.h>
+#include "dbus/dbus-sysdeps.h"
+
+int
+main (int argc, char *argv[])
+{
+  DBusConnection *conn = NULL;
+  DBusError error;
+
+  _dbus_setenv ("DBUS_SESSION_BUS_ADDRESS", NULL);
+
+  dbus_error_init (&error);
+
+  conn = dbus_bus_get (DBUS_BUS_SESSION, &error);
+
+#ifdef DBUS_ENABLE_X11_AUTOLAUNCH
+  if (dbus_error_is_set (&error))
+    {
+      fprintf (stderr, "*** Failed to autolaunch session bus: %s\n",
+               error.message);
+      dbus_error_free (&error);
+      return 1;
+    }
+#else
+  /* We don't necessarily expect it to *work* without X (although it might -
+   * for instance on Mac OS it might have used launchd). Just check that the
+   * results are consistent. */
+
+  if (dbus_error_is_set (&error) && conn != NULL)
+    {
+      fprintf (stderr, "*** Autolaunched session bus, but an error was set!\n");
+      return 1;
+    }
+#endif
+
+  if (!dbus_error_is_set (&error) && conn == NULL)
+    {
+      fprintf (stderr, "*** Failed to autolaunch session bus but no error was set\n");
+      return 1;
+    }
+
+  return 0;
+}
diff --git a/test/name-test/test-pending-call-dispatch.c b/test/name-test/test-pending-call-dispatch.c
index 57582d4..c8b5a46 100644
--- a/test/name-test/test-pending-call-dispatch.c
+++ b/test/name-test/test-pending-call-dispatch.c
@@ -98,9 +98,9 @@
     {
       long delta;
       
-      _dbus_get_current_time (&start_tv_sec, &start_tv_usec);
+      _dbus_get_monotonic_time (&start_tv_sec, &start_tv_usec);
       _run_iteration (conn);
-      _dbus_get_current_time (&end_tv_sec, &end_tv_usec);
+      _dbus_get_monotonic_time (&end_tv_sec, &end_tv_usec);
 
       /* we just care about seconds */
       delta = end_tv_sec - start_tv_sec;
diff --git a/test/name-test/test-pending-call-timeout.c b/test/name-test/test-pending-call-timeout.c
index 381113b..d051fab 100644
--- a/test/name-test/test-pending-call-timeout.c
+++ b/test/name-test/test-pending-call-timeout.c
@@ -82,9 +82,9 @@
     {
       long delta;
       
-      _dbus_get_current_time (&start_tv_sec, &start_tv_usec);
+      _dbus_get_monotonic_time (&start_tv_sec, &start_tv_usec);
       _run_iteration (conn);
-      _dbus_get_current_time (&end_tv_sec, &end_tv_usec);
+      _dbus_get_monotonic_time (&end_tv_sec, &end_tv_usec);
 
       /* we just care about seconds */
       delta = end_tv_sec - start_tv_sec;
diff --git a/test/name-test/test-privserver-client.c b/test/name-test/test-privserver-client.c
index d02eea8..e7f4896 100644
--- a/test/name-test/test-privserver-client.c
+++ b/test/name-test/test-privserver-client.c
@@ -11,18 +11,52 @@
   exit (1);
 }
 
+#define PRIVSERVER_SERVICE "org.freedesktop.DBus.TestSuite.PrivServer"
+#define PRIVSERVER_INTERFACE PRIVSERVER_SERVICE
+#define PRIVSERVER_DIED_RULE \
+      "type='signal',sender='" DBUS_SERVICE_DBUS "'," \
+      "interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged'," \
+      "arg0='" PRIVSERVER_SERVICE "',arg2=''"
+
+static DBusHandlerResult
+filter_session_message (DBusConnection     *connection,
+                        DBusMessage        *message,
+                        void               *user_data)
+{
+  dbus_bool_t *service_died_p = user_data;
+  const char *name, *old_owner, *new_owner;
+
+  if (dbus_message_is_signal (message,
+                              DBUS_INTERFACE_DBUS,
+                              "NameOwnerChanged") &&
+      dbus_message_has_sender (message, DBUS_SERVICE_DBUS) &&
+      dbus_message_get_args (message, NULL,
+                             DBUS_TYPE_STRING, &name,
+                             DBUS_TYPE_STRING, &old_owner,
+                             DBUS_TYPE_STRING, &new_owner,
+                             DBUS_TYPE_INVALID) &&
+      strcmp (name, PRIVSERVER_SERVICE) == 0 &&
+      old_owner[0] != '\0' &&
+      new_owner[0] == '\0')
+    {
+      *service_died_p = TRUE;
+    }
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
 static DBusHandlerResult 
 filter_private_message (DBusConnection     *connection,
                         DBusMessage        *message,
                         void               *user_data)
 {
+  dbus_bool_t *private_conn_lost_p = user_data;
+
   if (dbus_message_is_signal (message,
                               DBUS_INTERFACE_LOCAL,
                               "Disconnected"))
     {
-       DBusLoop *loop = user_data;      
-       _dbus_loop_quit (loop);
-       return DBUS_HANDLER_RESULT_HANDLED;
+      *private_conn_lost_p = TRUE;
     }
   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
@@ -37,9 +71,12 @@
   DBusMessage *reply;
   DBusConnection *privconn;
   char *addr;
-  char *comma;
+  dbus_bool_t service_died;
+  dbus_bool_t private_conn_lost;
 
   dbus_error_init (&error);
+  service_died = FALSE;
+  private_conn_lost = FALSE;
 
   loop = _dbus_loop_new ();
 
@@ -47,10 +84,19 @@
   if (!session)
     die ("couldn't access session bus\n");
   dbus_connection_set_exit_on_disconnect (session, FALSE);
-  msg = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuite.PrivServer",
-                                      "/",
-                                      "org.freedesktop.DBus.TestSuite.PrivServer",
-                                      "GetPrivateAddress");
+  test_connection_setup (loop, session);
+
+  dbus_bus_add_match (session, PRIVSERVER_DIED_RULE, &error);
+  if (dbus_error_is_set (&error))
+    die ("couldn't add match rule \"%s\": %s: %s", PRIVSERVER_DIED_RULE,
+         error.name, error.message);
+
+  if (!dbus_connection_add_filter (session, filter_session_message,
+                                   &service_died, NULL))
+    die ("couldn't add filter to session bus\n");
+
+  msg = dbus_message_new_method_call (PRIVSERVER_SERVICE, "/",
+                                      PRIVSERVER_INTERFACE, "GetPrivateAddress");
   if (!(reply = dbus_connection_send_with_reply_and_block (session, msg, -1, &error)))
     die ("couldn't send message: %s\n", error.message);
   dbus_message_unref (msg);
@@ -71,24 +117,29 @@
   dbus_message_unref (reply);
 
   dbus_connection_set_exit_on_disconnect (privconn, FALSE);
-  dbus_connection_add_filter (privconn, filter_private_message, loop, NULL);
+  if (!dbus_connection_add_filter (privconn, filter_private_message,
+                                   &private_conn_lost, NULL))
+    die ("couldn't add filter to private connection\n");
   test_connection_setup (loop, privconn);
 
-  msg = dbus_message_new_method_call ("org.freedesktop.DBus.TestSuite.PrivServer",
-                                      "/",
-                                      "org.freedesktop.DBus.TestSuite.PrivServer",
-                                      "Quit");
+  msg = dbus_message_new_method_call (PRIVSERVER_SERVICE, "/",
+                                      PRIVSERVER_INTERFACE, "Quit");
   if (!dbus_connection_send (session, msg, NULL))
     die ("couldn't send Quit message\n");
   dbus_message_unref (msg);
 
-  _dbus_loop_run (loop);  
+  while (!service_died || !private_conn_lost)
+    _dbus_loop_iterate (loop, TRUE);
 
+  dbus_connection_remove_filter (session, filter_session_message,
+                                 &service_died);
+  dbus_bus_remove_match (session, PRIVSERVER_DIED_RULE, NULL);
   test_connection_shutdown (loop, session);
   dbus_connection_unref (session);
 
   test_connection_shutdown (loop, privconn);
-  dbus_connection_remove_filter (privconn, filter_private_message, loop);
+  dbus_connection_remove_filter (privconn, filter_private_message,
+                                 &private_conn_lost);
   dbus_connection_unref (privconn);
 
   _dbus_loop_unref (loop);
diff --git a/test/relay.c b/test/relay.c
new file mode 100644
index 0000000..f4129d0
--- /dev/null
+++ b/test/relay.c
@@ -0,0 +1,322 @@
+/* Regression test for passing unmodified messages between connections
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2010-2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+/* This is basically a miniature dbus-daemon. We relay messages from the client
+ * on the left to the client on the right.
+ *
+ * left      socket     left      dispatch     right    socket     right
+ * client ===========>  server --------------> server ===========> client
+ * conn                 conn                   conn                conn
+ *
+ * In the real dbus-daemon, the client connections would be out-of-process,
+ * but here we're cheating and doing everything in-process.
+ */
+
+typedef struct {
+    DBusError e;
+
+    DBusServer *server;
+
+    DBusConnection *left_client_conn;
+    DBusConnection *left_server_conn;
+
+    DBusConnection *right_server_conn;
+    DBusConnection *right_client_conn;
+    /* queue of DBusMessage received by right_client_conn */
+    GQueue messages;
+} Fixture;
+
+static void
+assert_no_error (const DBusError *e)
+{
+  if (G_UNLIKELY (dbus_error_is_set (e)))
+    g_error ("expected success but got error: %s: %s", e->name, e->message);
+}
+
+static DBusHandlerResult
+server_message_cb (DBusConnection *server_conn,
+    DBusMessage *message,
+    void *data)
+{
+  Fixture *f = data;
+
+  g_assert (server_conn == f->left_server_conn);
+  g_assert (f->right_server_conn != NULL);
+
+  dbus_connection_send (f->right_server_conn, message, NULL);
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+right_client_message_cb (DBusConnection *client_conn,
+    DBusMessage *message,
+    void *data)
+{
+  Fixture *f = data;
+
+  g_assert (client_conn == f->right_client_conn);
+  g_queue_push_tail (&f->messages, dbus_message_ref (message));
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+new_conn_cb (DBusServer *server,
+    DBusConnection *server_conn,
+    void *data)
+{
+  Fixture *f = data;
+  dbus_bool_t have_mem;
+
+  if (f->left_server_conn == NULL)
+    {
+      f->left_server_conn = dbus_connection_ref (server_conn);
+
+      have_mem = dbus_connection_add_filter (server_conn,
+          server_message_cb, f, NULL);
+      g_assert (have_mem);
+    }
+  else
+    {
+      g_assert (f->right_server_conn == NULL);
+      f->right_server_conn = dbus_connection_ref (server_conn);
+    }
+
+  dbus_connection_setup_with_g_main (server_conn, NULL);
+}
+
+static void
+setup (Fixture *f,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  dbus_error_init (&f->e);
+  g_queue_init (&f->messages);
+
+  f->server = dbus_server_listen ("tcp:host=127.0.0.1", &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->server != NULL);
+
+  dbus_server_set_new_connection_function (f->server,
+      new_conn_cb, f, NULL);
+  dbus_server_setup_with_g_main (f->server, NULL);
+}
+
+static void
+test_connect (Fixture *f,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  dbus_bool_t have_mem;
+  char *address;
+
+  g_assert (f->left_server_conn == NULL);
+  g_assert (f->right_server_conn == NULL);
+
+  address = dbus_server_get_address (f->server);
+  g_assert (address != NULL);
+
+  f->left_client_conn = dbus_connection_open_private (address, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->left_client_conn != NULL);
+  dbus_connection_setup_with_g_main (f->left_client_conn, NULL);
+
+  while (f->left_server_conn == NULL)
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+
+  f->right_client_conn = dbus_connection_open_private (address, &f->e);
+  assert_no_error (&f->e);
+  g_assert (f->right_client_conn != NULL);
+  dbus_connection_setup_with_g_main (f->right_client_conn, NULL);
+
+  dbus_free (address);
+
+  while (f->right_server_conn == NULL)
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+
+  have_mem = dbus_connection_add_filter (f->right_client_conn,
+      right_client_message_cb, f, NULL);
+  g_assert (have_mem);
+}
+
+static dbus_uint32_t
+send_one (Fixture *f,
+    const char *member)
+{
+  dbus_bool_t have_mem;
+  dbus_uint32_t serial;
+  DBusMessage *outgoing;
+
+  outgoing = dbus_message_new_signal ("/com/example/Hello",
+      "com.example.Hello", member);
+  g_assert (outgoing != NULL);
+
+  have_mem = dbus_connection_send (f->left_client_conn, outgoing, &serial);
+  g_assert (have_mem);
+  g_assert (serial != 0);
+
+  dbus_message_unref (outgoing);
+  return serial;
+}
+
+static void
+test_relay (Fixture *f,
+    gconstpointer data)
+{
+  DBusMessage *incoming;
+
+  test_connect (f, data);
+
+  send_one (f, "First");
+  send_one (f, "Second");
+
+  while (g_queue_get_length (&f->messages) < 2)
+    {
+      g_print (".");
+      g_main_context_iteration (NULL, TRUE);
+    }
+
+  g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 2);
+
+  incoming = g_queue_pop_head (&f->messages);
+  g_assert_cmpstr (dbus_message_get_member (incoming), ==, "First");
+  dbus_message_unref (incoming);
+
+  incoming = g_queue_pop_head (&f->messages);
+  g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Second");
+  dbus_message_unref (incoming);
+}
+
+/* An arbitrary number of messages */
+#define MANY 8192
+
+static void
+test_limit (Fixture *f,
+    gconstpointer data)
+{
+  DBusMessage *incoming;
+  guint i;
+
+  test_connect (f, data);
+
+  /* This was an attempt to reproduce fd.o #34393. It didn't work. */
+  g_test_bug ("34393");
+  dbus_connection_set_max_received_size (f->left_server_conn, 1);
+  g_main_context_iteration (NULL, TRUE);
+
+  for (i = 0; i < MANY; i++)
+    {
+      gchar *buf = g_strdup_printf ("Message%u", i);
+
+      send_one (f, buf);
+      g_free (buf);
+    }
+
+  i = 0;
+
+  while (i < MANY)
+    {
+      while (g_queue_is_empty (&f->messages))
+        {
+          g_main_context_iteration (NULL, TRUE);
+        }
+
+      while ((incoming = g_queue_pop_head (&f->messages)) != NULL)
+        {
+          i++;
+          dbus_message_unref (incoming);
+        }
+    }
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  if (f->left_client_conn != NULL)
+    {
+      dbus_connection_close (f->left_client_conn);
+      dbus_connection_unref (f->left_client_conn);
+      f->left_client_conn = NULL;
+    }
+
+  if (f->right_client_conn != NULL)
+    {
+      dbus_connection_close (f->right_client_conn);
+      dbus_connection_unref (f->right_client_conn);
+      f->right_client_conn = NULL;
+    }
+
+  if (f->left_server_conn != NULL)
+    {
+      dbus_connection_close (f->left_server_conn);
+      dbus_connection_unref (f->left_server_conn);
+      f->left_server_conn = NULL;
+    }
+
+  if (f->right_server_conn != NULL)
+    {
+      dbus_connection_close (f->right_server_conn);
+      dbus_connection_unref (f->right_server_conn);
+      f->right_server_conn = NULL;
+    }
+
+  if (f->server != NULL)
+    {
+      dbus_server_disconnect (f->server);
+      dbus_server_unref (f->server);
+      f->server = NULL;
+    }
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
+
+  g_test_add ("/connect", Fixture, NULL, setup,
+      test_connect, teardown);
+  g_test_add ("/relay", Fixture, NULL, setup,
+      test_relay, teardown);
+  g_test_add ("/limit", Fixture, NULL, setup,
+      test_limit, teardown);
+
+  return g_test_run ();
+}
diff --git a/test/syntax.c b/test/syntax.c
new file mode 100644
index 0000000..88db963
--- /dev/null
+++ b/test/syntax.c
@@ -0,0 +1,289 @@
+/* Simple sanity-check for D-Bus syntax validation.
+ *
+ * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
+ * Copyright © 2010-2011 Nokia Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+typedef struct {
+    DBusError e;
+} Fixture;
+
+typedef struct {
+    dbus_bool_t (*function) (const char *, DBusError *);
+    const char * const * valid;
+    const char * const * invalid;
+} Test;
+
+Test paths, interfaces, members, errors, bus_names, signatures,
+     single_signatures, strings;
+
+const char * const valid_paths[] = {
+    "/",
+    "/a",
+    "/_",
+    "/a/b/c",
+    "/com/example/123",
+    "/org/freedesktop/DBus",
+    "/org/freedesktop/Telepathy/AccountManager",
+    NULL
+};
+
+const char * const invalid_paths[] = {
+    "",
+    ".",
+    "//",
+    "/a/",
+    "/-",
+    "/com//example/MyApp",
+    "/$",
+    "/\xa9",      /* © in latin-1 */
+    "/\xc2\xa9",  /* © in UTF-8 */
+    NULL
+};
+
+const char * const valid_interfaces[] = {
+    "com.example",
+    "com.example.a0",
+    "org.freedesktop.DBus",
+    NULL
+};
+
+const char * const invalid_interfaces[] = {
+   "",
+    "com",
+    "com.example.",
+    "com.example..a0",
+    "com.example.0a",
+    "com.example.a$",
+    "com.example.a\xa9",
+    "com.example.a\xc2\xa9",
+    NULL
+};
+
+const char * const valid_members[] = {
+    "_",
+    "a",
+    "a0",
+    "GetAll",
+    "BadgerMushroomSnake",
+    NULL
+};
+
+const char * const invalid_members[] = {
+    "",
+    "-",
+    "a-",
+    "0",
+    "0_",
+    "Badger.Mushroom",
+    "a$",
+    "a\xa9",
+    "a\xc2\xa9",
+    NULL
+};
+
+const char * const valid_errors[] = {
+    "com.example",
+    "com.example.a0",
+    "org.freedesktop.DBus.NameHasNoOwner",
+    NULL
+};
+
+const char * const invalid_errors[] = {
+   "",
+    "com",
+    "com.example.",
+    "com.example..a0",
+    "com.example.0a",
+    "com.example.a$",
+    "com.example.a\xa9",
+    "com.example.a\xc2\xa9",
+    NULL
+};
+
+const char * const valid_bus_names[] = {
+    "com.example",
+    "com.example.a0",
+    "com.example._",
+    ":1.42",
+    ":1.2.3.4.5",
+    ":com.example",
+    "org.freedesktop.DBus",
+    NULL
+};
+
+const char * const invalid_bus_names[] = {
+   "",
+    "com",
+    "com.example.",
+    "com.example..a0",
+    "com.example.0a",
+    "com.example.a:b",
+    "com.example.a\xa9",
+    "com.example.a\xc2\xa9",
+    NULL
+};
+
+const char * const valid_signatures[] = {
+    "",
+    "a{sv}",
+    NULL
+};
+
+const char * const invalid_signatures[] = {
+    "a",
+    "a{s_}",
+    NULL
+};
+
+const char * const valid_single_signatures[] = {
+    "s",
+    "a{sv}",
+    NULL
+};
+
+const char * const invalid_single_signatures[] = {
+    "",
+    "a",
+    "sv",
+    "a{sv}as",
+    NULL
+};
+
+const char * const valid_strings[] = {
+    "",
+    "\xc2\xa9",
+    NULL
+};
+
+const char * const invalid_strings[] = {
+    "\xa9",
+    NULL
+};
+
+static void
+setup (Fixture *f,
+    gconstpointer arg G_GNUC_UNUSED)
+{
+  dbus_error_init (&f->e);
+
+#define FILL_TEST(name, func) \
+  do { \
+    (name).function = (func); \
+    (name).valid = valid_ ## name; \
+    (name).invalid = invalid_ ## name; \
+  } while (0)
+
+  FILL_TEST (paths, dbus_validate_path);
+  FILL_TEST (interfaces, dbus_validate_interface);
+  FILL_TEST (members, dbus_validate_member);
+  FILL_TEST (errors, dbus_validate_error_name);
+  FILL_TEST (bus_names, dbus_validate_bus_name);
+  FILL_TEST (signatures, dbus_signature_validate);
+  FILL_TEST (single_signatures, dbus_signature_validate_single);
+  FILL_TEST (strings, dbus_validate_utf8);
+}
+
+static void
+test_syntax (Fixture *f,
+    gconstpointer arg)
+{
+  const Test *test = arg;
+  int i;
+
+  g_assert (test != NULL);
+  g_assert (test->function != NULL);
+  g_assert (test->valid != NULL);
+  g_assert (test->invalid != NULL);
+
+  for (i = 0; test->valid[i] != NULL; i++)
+    {
+      dbus_bool_t ok = test->function (test->valid[i], &f->e);
+
+      if (dbus_error_is_set (&f->e))
+        g_error ("%s was considered invalid: %s: %s", test->valid[i],
+            f->e.name, f->e.message);
+
+      if (!ok)
+        g_error ("%s was considered invalid without an error", test->valid[i]);
+    }
+
+  for (i = 0; test->invalid[i] != NULL; i++)
+    {
+      dbus_bool_t ok = test->function (test->invalid[i], &f->e);
+
+      if (ok)
+        g_error ("%s should have been considered invalid", test->invalid[i]);
+
+      if (!dbus_error_is_set (&f->e))
+        g_error ("%s should have an error set", test->invalid[i]);
+
+      if (!dbus_validate_error_name (f->e.name, NULL))
+        g_error ("%s produced an invalid error name: %s",
+            test->invalid[i], f->e.name);
+
+      if (!dbus_validate_utf8 (f->e.message, NULL))
+        g_error ("%s produced an invalid error message: %s",
+            test->invalid[i], f->e.message);
+
+      dbus_error_free (&f->e);
+    }
+}
+
+static void
+teardown (Fixture *f,
+    gconstpointer arg G_GNUC_UNUSED)
+{
+  dbus_error_free (&f->e);
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add ("/syntax/path", Fixture, &paths, setup, test_syntax, teardown);
+  g_test_add ("/syntax/interface", Fixture, &interfaces,
+      setup, test_syntax, teardown);
+  g_test_add ("/syntax/error", Fixture, &errors,
+      setup, test_syntax, teardown);
+  g_test_add ("/syntax/member", Fixture, &members,
+      setup, test_syntax, teardown);
+  g_test_add ("/syntax/bus-name", Fixture, &bus_names,
+      setup, test_syntax, teardown);
+  g_test_add ("/syntax/signature", Fixture, &signatures,
+      setup, test_syntax, teardown);
+  g_test_add ("/syntax/single-signature", Fixture, &single_signatures,
+      setup, test_syntax, teardown);
+  g_test_add ("/syntax/utf8", Fixture, &strings,
+      setup, test_syntax, teardown);
+
+  return g_test_run ();
+}
diff --git a/test/test-service.c b/test/test-service.c
index 6627ea7..7181fa3 100644
--- a/test/test-service.c
+++ b/test/test-service.c
@@ -477,7 +477,14 @@
       dbus_error_free (&error);
       exit (1);
     }
-  
+
+  if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+    {
+      fprintf (stderr, "Unable to acquire service: code %d\n", result);
+      _dbus_verbose ("*** Failed to acquire service: %d\n", result);
+      exit (1);
+    }
+
   _dbus_verbose ("*** Test service entering main loop\n");
   _dbus_loop_run (loop);
   
diff --git a/test/test-shell-service.c b/test/test-shell-service.c
index 57c1612..32a8832 100644
--- a/test/test-shell-service.c
+++ b/test/test-shell-service.c
@@ -176,6 +176,13 @@
       exit (1);
     }
 
+  if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+    {
+      fprintf (stderr, "Unable to acquire service: code %d\n", result);
+      _dbus_verbose ("*** Failed to acquire service: %d\n", result);
+      exit (1);
+    }
+
   _dbus_verbose ("*** Test service entering main loop\n");
   _dbus_loop_run (loop);
 
diff --git a/test/test-utils.c b/test/test-utils.c
index eda20cd..c3c3ed3 100644
--- a/test/test-utils.c
+++ b/test/test-utils.c
@@ -9,23 +9,12 @@
 } CData;
 
 static dbus_bool_t
-connection_watch_callback (DBusWatch     *watch,
-                           unsigned int   condition,
-                           void          *data)
-{
-  return dbus_watch_handle (watch, condition);
-}
-
-static dbus_bool_t
 add_watch (DBusWatch *watch,
 	   void      *data)
 {
   CData *cd = data;
 
-  return _dbus_loop_add_watch (cd->loop,
-                               watch,
-                               connection_watch_callback,
-                               cd, NULL);
+  return _dbus_loop_add_watch (cd->loop, watch);
 }
 
 static void
@@ -34,16 +23,16 @@
 {
   CData *cd = data;
   
-  _dbus_loop_remove_watch (cd->loop,
-                           watch, connection_watch_callback, cd);  
+  _dbus_loop_remove_watch (cd->loop, watch);
 }
 
 static void
-connection_timeout_callback (DBusTimeout   *timeout,
-                             void          *data)
+toggle_watch (DBusWatch  *watch,
+              void       *data)
 {
-  /* Can return FALSE on OOM but we just let it fire again later */
-  dbus_timeout_handle (timeout);
+  CData *cd = data;
+
+  _dbus_loop_toggle_watch (cd->loop, watch);
 }
 
 static dbus_bool_t
@@ -52,8 +41,7 @@
 {
   CData *cd = data;
 
-  return _dbus_loop_add_timeout (cd->loop,
-                                 timeout, connection_timeout_callback, cd, NULL);
+  return _dbus_loop_add_timeout (cd->loop, timeout);
 }
 
 static void
@@ -62,8 +50,7 @@
 {
   CData *cd = data;
 
-  _dbus_loop_remove_timeout (cd->loop,
-                             timeout, connection_timeout_callback, cd);
+  _dbus_loop_remove_timeout (cd->loop, timeout);
 }
 
 static void
@@ -125,15 +112,10 @@
   if (cd == NULL)
     goto nomem;
 
-  /* Because dbus-mainloop.c checks dbus_timeout_get_enabled(),
-   * dbus_watch_get_enabled() directly, we don't have to provide
-   * "toggled" callbacks.
-   */
-  
   if (!dbus_connection_set_watch_functions (connection,
                                             add_watch,
                                             remove_watch,
-                                            NULL,
+                                            toggle_watch,
                                             cd, cdata_free))
     goto nomem;
 
@@ -226,27 +208,21 @@
 }
 
 static dbus_bool_t
-server_watch_callback (DBusWatch     *watch,
-                       unsigned int   condition,
-                       void          *data)
-{
-  /* FIXME this can be done in dbus-mainloop.c
-   * if the code in activation.c for the babysitter
-   * watch handler is fixed.
-   */
-
-  return dbus_watch_handle (watch, condition);
-}
-
-static dbus_bool_t
 add_server_watch (DBusWatch  *watch,
                   void       *data)
 {
   ServerData *context = data;
 
-  return _dbus_loop_add_watch (context->loop,
-                               watch, server_watch_callback, context,
-                               NULL);
+  return _dbus_loop_add_watch (context->loop, watch);
+}
+
+static void
+toggle_server_watch (DBusWatch  *watch,
+                     void       *data)
+{
+  ServerData *context = data;
+
+  _dbus_loop_toggle_watch (context->loop, watch);
 }
 
 static void
@@ -255,16 +231,7 @@
 {
   ServerData *context = data;
   
-  _dbus_loop_remove_watch (context->loop,
-                           watch, server_watch_callback, context);
-}
-
-static void
-server_timeout_callback (DBusTimeout   *timeout,
-                         void          *data)
-{
-  /* can return FALSE on OOM but we just let it fire again later */
-  dbus_timeout_handle (timeout);
+  _dbus_loop_remove_watch (context->loop, watch);
 }
 
 static dbus_bool_t
@@ -273,8 +240,7 @@
 {
   ServerData *context = data;
 
-  return _dbus_loop_add_timeout (context->loop,
-                                 timeout, server_timeout_callback, context, NULL);
+  return _dbus_loop_add_timeout (context->loop, timeout);
 }
 
 static void
@@ -283,8 +249,7 @@
 {
   ServerData *context = data;
   
-  _dbus_loop_remove_timeout (context->loop,
-                             timeout, server_timeout_callback, context);
+  _dbus_loop_remove_timeout (context->loop, timeout);
 }
 
 dbus_bool_t
@@ -300,20 +265,24 @@
   if (!dbus_server_set_watch_functions (server,
                                         add_server_watch,
                                         remove_server_watch,
-                                        NULL,
+                                        toggle_server_watch,
                                         sd,
                                         serverdata_free))
     {
-      return FALSE;
+      goto nomem;
     }
 
+  sd = serverdata_new (loop, server);
+  if (sd == NULL)
+    goto nomem;
+
   if (!dbus_server_set_timeout_functions (server,
                                           add_server_timeout,
                                           remove_server_timeout,
                                           NULL,
                                           sd, serverdata_free))
     {
-      return FALSE;
+      goto nomem;
     }   
   return TRUE;
 
@@ -330,6 +299,8 @@
 test_server_shutdown (DBusLoop         *loop,
                       DBusServer       *server)
 {
+  dbus_server_disconnect (server);
+
   if (!dbus_server_set_watch_functions (server,
                                         NULL, NULL, NULL,
                                         NULL,
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 271c150..cfd54b8 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,14 +1,29 @@
 configdir=$(sysconfdir)/dbus-1
 
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_X_CFLAGS) -DDBUS_LOCALEDIR=\"@EXPANDED_DATADIR@/locale\" -DDBUS_COMPILATION -DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\"
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	$(DBUS_STATIC_BUILD_CPPFLAGS) \
+	$(DBUS_X_CFLAGS) \
+	-DDBUS_COMPILATION \
+	-DDBUS_MACHINE_UUID_FILE=\""$(localstatedir)/lib/dbus/machine-id"\" \
+	$(NULL)
 
-extra_bin_programs=
+# if assertions are enabled, improve backtraces
+AM_LDFLAGS = @R_DYNAMIC_LDFLAG@
+
+bin_PROGRAMS = \
+	dbus-launch \
+	dbus-monitor \
+	dbus-send \
+	$(NULL)
+
 if DBUS_UNIX
-extra_bin_programs += dbus-cleanup-sockets dbus-uuidgen
+bin_PROGRAMS += \
+	dbus-cleanup-sockets \
+	dbus-uuidgen \
+	$(NULL)
 endif
 
-bin_PROGRAMS=dbus-launch dbus-send dbus-monitor $(extra_bin_programs)
-
 dbus_send_SOURCES=				\
 	dbus-print-message.c			\
 	dbus-print-message.h			\
@@ -36,23 +51,30 @@
 dbus_uuidgen_SOURCES=				\
 	dbus-uuidgen.c
 
-dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS)
-dbus_send_LDFLAGS=@R_DYNAMIC_LDFLAG@
+dbus_send_LDADD = \
+	$(top_builddir)/dbus/libdbus-1.la \
+	$(NULL)
 
-dbus_monitor_LDADD= $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS)
-dbus_monitor_LDFLAGS=@R_DYNAMIC_LDFLAG@
+dbus_monitor_LDADD = \
+	$(top_builddir)/dbus/libdbus-1.la \
+	$(NETWORK_libs) \
+	$(NULL)
 
-dbus_uuidgen_LDADD= $(top_builddir)/dbus/libdbus-1.la $(DBUS_CLIENT_LIBS)
-dbus_uuidgen_LDFLAGS=@R_DYNAMIC_LDFLAG@
+dbus_uuidgen_LDADD = \
+	$(top_builddir)/dbus/libdbus-1.la \
+	$(NULL)
 
-dbus_launch_LDADD= $(DBUS_X_LIBS) $(DBUS_CLIENT_LIBS)
-dbus_launch_LDFLAGS=@R_DYNAMIC_LDFLAG@
+dbus_launch_LDADD = \
+	$(DBUS_X_LIBS) \
+	$(NULL)
 
-man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1 dbus-uuidgen.1
-EXTRA_DIST = $(man_MANS) run-with-tmp-session-bus.sh strtoll.c strtoull.c
+EXTRA_DIST = run-with-tmp-session-bus.sh strtoll.c strtoull.c
 CLEANFILES = 				\
 	run-with-tmp-session-bus.conf
 
-#create the /var/lib/data directory for dbus-uuidgen
-localstatelibdir = $(localstatedir)/lib/dbus
-localstatelib_DATA =
+# create the /var/lib/dbus directory for dbus-uuidgen
+install-data-local:
+	$(MKDIR_P) $(DESTDIR)$(localstatedir)/lib/dbus
+
+installcheck-local:
+	test -d $(DESTDIR)$(localstatedir)/lib/dbus
diff --git a/tools/dbus-cleanup-sockets.1 b/tools/dbus-cleanup-sockets.1
deleted file mode 100644
index ca669f4..0000000
--- a/tools/dbus-cleanup-sockets.1
+++ /dev/null
@@ -1,43 +0,0 @@
-.\" 
-.\" dbus-cleanup-sockets manual page.
-.\" Copyright (C) 2003 Red Hat, Inc.
-.\"
-.TH dbus-cleanup-sockets 1
-.SH NAME
-dbus-cleanup-sockets \- clean up leftover sockets in a directory
-.SH SYNOPSIS
-.PP
-.B dbus-cleanup-sockets [DIRECTORY]
-
-.SH DESCRIPTION
-
-The \fIdbus-cleanup-sockets\fP command cleans up unused D-Bus
-connection sockets. See http://www.freedesktop.org/software/dbus/ for
-more information about the big picture.
-
-.PP
-If given no arguments, \fIdbus-cleanup-sockets\fP cleans up sockets 
-in the standard default socket directory for the
-per-user-login-session message bus; this is usually /tmp. 
-Optionally, you can pass a different directory on the command line.
-
-.PP
-On Linux, this program is essentially useless, because D-Bus defaults
-to using "abstract sockets" that exist only in memory and don't have a
-corresponding file in /tmp. 
-
-.PP
-On most other flavors of UNIX, it's possible for the socket files to
-leak when programs using D-Bus exit abnormally or without closing
-their D-Bus connections. Thus, it might be interesting to run
-dbus-cleanup-sockets in a cron job to mop up any leaked sockets.
-Or you can just ignore the leaked sockets, they aren't really hurting
-anything, other than cluttering the output of "ls /tmp"
-
-.SH AUTHOR
-dbus-cleanup-sockets was adapted by Havoc Pennington from
-linc-cleanup-sockets written by Michael Meeks.
-
-.SH BUGS
-Please send bug reports to the D-Bus mailing list or bug tracker,
-see http://www.freedesktop.org/software/dbus/
diff --git a/tools/dbus-cleanup-sockets.c b/tools/dbus-cleanup-sockets.c
index 487c4b0..1b6709a 100644
--- a/tools/dbus-cleanup-sockets.c
+++ b/tools/dbus-cleanup-sockets.c
@@ -138,16 +138,31 @@
   return se;
 }
 
-#if 0
 static void
 free_socket_entry (SocketEntry *se)
 {
-  free (se->name);
-  if (se->fd >= 0)
-    close (se->fd);
-  free (se);
+  if (se)
+    {
+      free (se->name);
+      if (se->fd >= 0)
+        close (se->fd);
+      free (se);
+    }
 }
-#endif
+
+static void
+free_socket_entries (SocketEntry** entries,
+                     int           n_entries)
+{
+  int i;
+
+  if (entries)
+    {
+      for (i = 0; i < n_entries; ++i)
+        free_socket_entry (entries[i]);
+      free (entries);
+    }
+}
 
 static void
 read_sockets (const char    *dir,
@@ -350,6 +365,8 @@
     }
 
   unhandled_count += (n_entries - alive_count - cleaned_count);
+
+  free_socket_entries (entries, n_entries);
 }
 
 #endif /* AF_UNIX */
diff --git a/tools/dbus-launch-win.c b/tools/dbus-launch-win.c
index ea4bf0d..215fac3 100644
--- a/tools/dbus-launch-win.c
+++ b/tools/dbus-launch-win.c
@@ -130,9 +130,10 @@
      fprintf (stderr, "%ls %ls\n", dbusDaemonPath, command);
 #else
    command[0] = L'\0';
-   /* Windows CE has a different interpretation of cmdline: Start with argv[1].  */
-   wcscpy_s (command, sizeof (command), dbusDaemonPath);
-   wcscat_s (command, sizeof (command), L" --session");
+   /* Windows cmdline starts with path, which can contain spaces.  */
+   wcscpy_s (command, sizeof (command), L"\"");
+   wcscat_s (command, sizeof (command), dbusDaemonPath);
+   wcscat_s (command, sizeof (command), L"\" --session");
    if (verbose)
      fprintf (stderr, "%ls\n", command);
 #endif
diff --git a/tools/dbus-launch-x11.c b/tools/dbus-launch-x11.c
index fe49222..c7e3330 100644
--- a/tools/dbus-launch-x11.c
+++ b/tools/dbus-launch-x11.c
@@ -248,7 +248,7 @@
   user = getpwuid (getuid ());
   if (user == NULL)
     {
-      verbose ("Could not determine the user informations; aborting X11 integration.\n");
+      verbose ("Could not determine user information; aborting X11 integration.\n");
       return FALSE;
     }
   user_name = xstrdup(user->pw_name);
@@ -293,6 +293,7 @@
 int
 x11_get_address (char **paddress, pid_t *pid, long *wid)
 {
+  int result;
   Atom type;
   Window owner;
   int format;
@@ -310,10 +311,10 @@
     *wid = (long) owner;
 
   /* get the bus address */
-  XGetWindowProperty (xdisplay, owner, address_atom, 0, 1024, False,
-                      XA_STRING, &type, &format, &items, &after,
-                      (unsigned char **) &data);
-  if (type == None || after != 0 || data == NULL || format != 8)
+  result = XGetWindowProperty (xdisplay, owner, address_atom, 0, 1024, False,
+                              XA_STRING, &type, &format, &items, &after,
+                              (unsigned char **) &data);
+  if (result != Success || type == None || after != 0 || data == NULL || format != 8)
     return FALSE;               /* error */
 
   *paddress = xstrdup (data);
@@ -323,10 +324,10 @@
   if (pid != NULL)
     {
       *pid = 0;
-      XGetWindowProperty (xdisplay, owner, pid_atom, 0, sizeof pid, False,
-                          XA_CARDINAL, &type, &format, &items, &after,
-                          (unsigned char **) &data);
-      if (type != None && after == 0 && data != NULL && format == 32)
+      result = XGetWindowProperty (xdisplay, owner, pid_atom, 0, sizeof pid, False,
+                                   XA_CARDINAL, &type, &format, &items, &after,
+                                   (unsigned char **) &data);
+      if (result == Success && type != None && after == 0 && data != NULL && format == 32)
         *pid = (pid_t) *(long*) data;
       XFree (data);
     }
@@ -404,6 +405,7 @@
     return FALSE;
 
   f = fopen (session_file, "w");
+  free (session_file);
   if (f == NULL)
     return FALSE;               /* some kind of error */
   fprintf (f,
@@ -420,7 +422,6 @@
            address, (long)pid, (long)wid);
 
   fclose (f);
-  free (session_file);
 
   return TRUE;
 }
diff --git a/tools/dbus-launch.1 b/tools/dbus-launch.1
deleted file mode 100644
index 0ea1949..0000000
--- a/tools/dbus-launch.1
+++ /dev/null
@@ -1,183 +0,0 @@
-.\" 
-.\" dbus-launch manual page.
-.\" Copyright (C) 2003 Red Hat, Inc.
-.\"
-.TH dbus-launch 1
-.SH NAME
-dbus-launch \- Utility to start a message bus from a shell script
-.SH SYNOPSIS
-.PP
-.B dbus-launch [\-\-version] [\-\-sh-syntax] [\-\-csh-syntax] [\-\-auto-syntax] [\-\-exit-with-session] [\-\-autolaunch=MACHINEID] [\-\-config-file=FILENAME] [PROGRAM] [ARGS...]
-
-.SH DESCRIPTION
-
-The \fIdbus-launch\fP command is used to start a session bus 
-instance of \fIdbus-daemon\fP from a shell script.
-It would normally be called from a user's login
-scripts. Unlike the daemon itself, \fIdbus-launch\fP exits, so
-backticks or the $() construct can be used to read information from
-\fIdbus-launch\fP.
-
-With no arguments, \fIdbus-launch\fP will launch a session bus
-instance and print the address and pid of that instance to standard
-output.
-
-You may specify a program to be run; in this case, \fIdbus-launch\fP
-will launch a session bus instance, set the appropriate environment
-variables so the specified program can find the bus, and then execute the
-specified program, with the specified arguments.  See below for
-examples.
-
-If you launch a program, \fIdbus-launch\fP will not print the
-information about the new bus to standard output.
-
-When \fIdbus-launch\fP prints bus information to standard output, by
-default it is in a simple key-value pairs format. However, you may 
-request several alternate syntaxes using the \-\-sh-syntax, \-\-csh-syntax,
-\-\-binary-syntax, or
-\-\-auto-syntax options. Several of these cause \fIdbus-launch\fP to emit shell code
-to set up the environment.
-
-With the \-\-auto-syntax option, \fIdbus-launch\fP looks at the value
-of the SHELL environment variable to determine which shell syntax
-should be used.  If SHELL ends in "csh", then csh-compatible code is
-emitted; otherwise Bourne shell code is emitted.  Instead of passing
-\-\-auto-syntax, you may explicity specify a particular one by using
-\-\-sh-syntax for Bourne syntax, or \-\-csh-syntax for csh syntax.
-In scripts, it's more robust to avoid \-\-auto-syntax and you hopefully
-know which shell your script is written in.
-
-.PP
-See http://www.freedesktop.org/software/dbus/ for more information
-about D-Bus. See also the man page for \fIdbus-daemon\fP.
-
-.PP
-Here is an example of how to use \fIdbus-launch\fP with an 
-sh-compatible shell to start the per-session bus daemon:
-.nf
-
-  ## test for an existing bus daemon, just to be safe
-  if test -z "$DBUS_SESSION_BUS_ADDRESS" ; then
-      ## if not found, launch a new one
-      eval `dbus-launch --sh-syntax --exit-with-session`
-      echo "D-Bus per-session daemon address is: $DBUS_SESSION_BUS_ADDRESS"
-  fi
-
-.fi
-You might run something like that in your login scripts.
-
-.PP
-Another way to use \fIdbus-launch\fP is to run your main session
-program, like so:
-.nf
-
-dbus-launch gnome-session
-
-.fi
-The above would likely be appropriate for ~/.xsession or ~/.Xclients.
-
-.SH AUTOMATIC LAUNCHING
-
-.PP
-If DBUS_SESSION_BUS_ADDRESS is not set for a process that tries to use
-D-Bus, by default the process will attempt to invoke dbus-launch with
-the --autolaunch option to start up a new session bus or find the 
-existing bus address on the X display or in a file in
-~/.dbus/session-bus/
-
-.PP
-Whenever an autolaunch occurs, the application that had to
-start a new bus will be in its own little world; it can effectively
-end up starting a whole new session if it tries to use a lot of 
-bus services. This can be suboptimal or even totally broken, depending
-on the app and what it tries to do.
-
-.PP
-There are two common reasons for autolaunch. One is ssh to a remote
-machine. The ideal fix for that would be forwarding of
-DBUS_SESSION_BUS_ADDRESS in the same way that DISPLAY is forwarded.
-In the meantime, you can edit the session.conf config file to 
-have your session bus listen on TCP, and manually set
-DBUS_SESSION_BUS_ADDRESS, if you like.
-
-.PP
-The second common reason for autolaunch is an su to another user, and
-display of X applications running as the second user on the display
-belonging to the first user. Perhaps the ideal fix in this case
-would be to allow the second user to connect to the session bus of the
-first user, just as they can connect to the first user's display.
-However, a mechanism for that has not been coded.
-
-.PP
-You can always avoid autolaunch by manually setting
-DBUS_SESSION_BUS_ADDRESS. Autolaunch happens because the default
-address if none is set is "autolaunch:", so if any other address is
-set there will be no autolaunch. You can however include autolaunch in
-an explicit session bus address as a fallback, for example
-DBUS_SESSION_BUS_ADDRESS="something:,autolaunch:" - in that case if
-the first address doesn't work, processes will autolaunch. (The bus
-address variable contains a comma-separated list of addresses to try.)
-
-.PP
-The --autolaunch option is considered an internal implementation
-detail of libdbus, and in fact there are plans to change it. There's
-no real reason to use it outside of the libdbus implementation anyhow.
-
-.SH OPTIONS
-The following options are supported:
-.TP
-.I "--auto-syntax"
-Choose \-\-csh-syntax or \-\-sh-syntax based on the SHELL environment variable.
-
-.I "--binary-syntax"
-Write to stdout a nul-terminated bus address, then the bus PID as a
-binary integer of size sizeof(pid_t), then the bus X window ID as a
-binary integer of size sizeof(long). Integers are in the machine's
-byte order, not network byte order or any other canonical byte order.
-
-.TP
-.I "--close-stderr"
-Close the standard error output stream before starting the D-Bus
-daemon. This is useful if you want to capture dbus-launch error
-messages but you don't want dbus-daemon to keep the stream open to
-your application.
-
-.TP
-.I "--config-file=FILENAME"
-Pass \-\-config-file=FILENAME to the bus daemon, instead of passing it 
-the \-\-session argument. See the man page for dbus-daemon
-
-.TP
-.I "--csh-syntax"
-Emit csh compatible code to set up environment variables.
-
-.TP
-.I "--exit-with-session"
-If this option is provided, a persistent "babysitter" process will be 
-created that watches stdin for HUP and tries to connect to the X
-server. If this process gets a HUP on stdin or loses its X connection,
-it kills the message bus daemon.
-
-.TP
-.I "--autolaunch=MACHINEID"
-This option implies that \fIdbus-launch\fP should scan for a
-previously-started session and reuse the values found there. If no
-session is found, it will start a new session. The
-\-\-exit-with-session option is implied if \-\-autolaunch is given.
-This option is for the exclusive use of libdbus, you do not want to
-use it manually. It may change in the future.
-
-.TP
-.I "--sh-syntax"
-Emit Bourne-shell compatible code to set up environment variables.
-
-.TP
-.I "--version"
-Print the version of dbus-launch
-
-.SH AUTHOR
-See http://www.freedesktop.org/software/dbus/doc/AUTHORS
-
-.SH BUGS
-Please send bug reports to the D-Bus mailing list or bug tracker,
-see http://www.freedesktop.org/software/dbus/
diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c
index 6fa9c92..1ec9ae5 100644
--- a/tools/dbus-launch.c
+++ b/tools/dbus-launch.c
@@ -43,6 +43,47 @@
 extern Display *xdisplay;
 #endif
 
+/* PROCESSES
+ *
+ * If you are in a shell and run "dbus-launch myapp", here is what happens:
+ *
+ * shell [*]
+ *   \- main()               --exec--> myapp[*]
+ *      \- "intermediate parent"
+ *         \- bus-runner     --exec--> dbus-daemon --fork
+ *         \- babysitter[*]            \- final dbus-daemon[*]
+ *
+ * Processes marked [*] survive the initial flurry of activity.
+ *
+ * If you run "dbus-launch --sh-syntax" then the diagram is the same, except
+ * that main() prints variables and exits 0 instead of exec'ing myapp.
+ *
+ * PIPES
+ *
+ * dbus-daemon --print-pid     -> bus_pid_to_launcher_pipe     -> main
+ * dbus-daemon --print-address -> bus_address_to_launcher_pipe -> main
+ * main                        -> bus_pid_to_babysitter_pipe   -> babysitter
+ *
+ * The intermediate parent looks pretty useless at first glance. Its purpose
+ * is to avoid the bus-runner becoming a zombie: when the intermediate parent
+ * terminates, the bus-runner and babysitter are reparented to init, which
+ * reaps them if they have finished. We can't rely on main() to reap arbitrary
+ * children because it might exec myapp, after which it can't be relied on to
+ * reap its children. We *can* rely on main() to reap the intermediate parent,
+ * because that happens before it execs myapp.
+ *
+ * It's unclear why dbus-daemon needs to fork, but we explicitly tell it to
+ * for some reason, then wait for it. If we left it undefined, a forking
+ * dbus-daemon would get the parent process reparented to init and reaped
+ * when the intermediate parent terminated, and a non-forking dbus-daemon
+ * would get reparented to init and carry on there.
+ *
+ * myapp is exec'd by the process that initially ran main() so that it's
+ * the shell's child, so the shell knows how to do job control and stuff.
+ * This is desirable for the "dbus-launch an application" use-case, less so
+ * for the "dbus-launch a test suite in an isolated session" use-case.
+ */
+
 static char* machine_uuid = NULL;
 
 const char*
@@ -451,11 +492,20 @@
   else
     tty_fd = -1;
 
-  if (tty_fd >= 0)
-    verbose ("stdin isatty(), monitoring it\n");
+  if (x_fd >= 0)
+    {
+      verbose ("session lifetime is defined by X, not monitoring stdin\n");
+      tty_fd = -1;
+    }
+  else if (tty_fd >= 0)
+    {
+      verbose ("stdin isatty(), monitoring it\n");
+    }
   else
-    verbose ("stdin was not a TTY, not monitoring it\n");  
-  
+    {
+      verbose ("stdin was not a TTY, not monitoring it\n");
+    }
+
   if (tty_fd < 0 && x_fd < 0)
     {
       fprintf (stderr, "No terminal on standard input and no X display; cannot attach message bus to session lifetime\n");
@@ -690,10 +740,11 @@
            int binary_syntax,
            int argc, char **argv, int remaining_args)
 {
+  char *envvar = NULL;
+  char **args = NULL;
+
   if (runprog)
     {
-      char *envvar;
-      char **args;
       int i;
 
       envvar = malloc (strlen ("DBUS_SESSION_BUS_ADDRESS=") +
@@ -737,6 +788,12 @@
   close (2);
   exit (0);
 oom:
+  if (envvar)
+    free (envvar);
+
+  if (args)
+    free (args);
+
   fprintf (stderr, "Out of memory!");
   exit (1);
 }
@@ -910,7 +967,11 @@
       fprintf (stderr, "Autolaunch requested, but X11 support not compiled in.\n"
 	       "Cannot continue.\n");
       exit (1);
-#else
+#else /* DBUS_BUILD_X11 */
+#ifndef DBUS_ENABLE_X11_AUTOLAUNCH
+      fprintf (stderr, "X11 autolaunch support disabled at compile time.\n");
+      exit (1);
+#else /* DBUS_ENABLE_X11_AUTOLAUNCH */
       char *address;
       pid_t pid;
       long wid;
@@ -947,11 +1008,12 @@
 			   bourne_shell_syntax, binary_syntax, argc, argv, remaining_args);
 	  exit (0);
 	}
+#endif /* DBUS_ENABLE_X11_AUTOLAUNCH */
     }
-   else if (read_machine_uuid_if_needed())
+  else if (read_machine_uuid_if_needed())
     {
       x11_init();
-#endif
+#endif /* DBUS_BUILD_X11 */
     }
 
 
@@ -1170,7 +1232,7 @@
 
       close (bus_pid_to_launcher_pipe[READ_END]);
 
-#ifdef DBUS_BUILD_X11
+#ifdef DBUS_ENABLE_X11_AUTOLAUNCH
       if (xdisplay != NULL)
         {
           verbose("Saving x11 address\n");
diff --git a/tools/dbus-monitor.1 b/tools/dbus-monitor.1
deleted file mode 100644
index c24c14d..0000000
--- a/tools/dbus-monitor.1
+++ /dev/null
@@ -1,78 +0,0 @@
-.\" 
-.\" dbus-monitor manual page.
-.\" Copyright (C) 2003 Red Hat, Inc.
-.\"
-.TH dbus-monitor 1
-.SH NAME
-dbus-monitor \- debug probe to print message bus messages
-.SH SYNOPSIS
-.PP
-.B dbus-monitor
-[\-\-system | \-\-session | \-\-address ADDRESS] [\-\-profile | \-\-monitor]
-[watch expressions]
-
-.SH DESCRIPTION
-
-The \fIdbus-monitor\fP command is used to monitor messages going
-through a D-Bus message bus.  See
-http://www.freedesktop.org/software/dbus/ for more information about
-the big picture.
-
-.PP
-There are two well-known message buses: the systemwide message bus
-(installed on many systems as the "messagebus" service) and the
-per-user-login-session message bus (started each time a user logs in).
-The \-\-system and \-\-session options direct \fIdbus-monitor\fP to
-monitor the system or session buses respectively.  If neither is
-specified, \fIdbus-monitor\fP monitors the session bus.
-
-.PP
-\fIdbus-monitor\fP has two different output modes, the 'classic'-style
-monitoring mode and profiling mode. The profiling format is a compact
-format with a single line per message and microsecond-resolution timing
-information. The \-\-profile and \-\-monitor options select the profiling
-and monitoring output format respectively. If neither is specified,
-\fIdbus-monitor\fP uses the monitoring output format.
-
-.PP
-In order to get \fIdbus-monitor\fP to see the messages you are interested
-in, you should specify a set of watch expressions as you would expect to
-be passed to the \fIdbus_bus_add_match\fP function.
-
-.PP 
-The message bus configuration may keep \fIdbus-monitor\fP from seeing
-all messages, especially if you run the monitor as a non-root user.
-
-.SH OPTIONS
-.TP
-.I "--system"
-Monitor the system message bus.
-.TP
-.I "--session"
-Monitor the session message bus.  (This is the default.)
-.TP
-.I "--address ADDRESS"
-Monitor an arbitrary message bus given at ADDRESS.
-.TP
-.I "--profile"
-Use the profiling output format.
-.TP
-.I "--monitor"
-Use the monitoring output format.  (This is the default.)
-
-.SH EXAMPLE
-Here is an example of using dbus-monitor to watch for the gnome typing
-monitor to say things
-.nf
-
-  dbus-monitor "type='signal',sender='org.gnome.TypingMonitor',interface='org.gnome.TypingMonitor'"
-
-.fi
-
-.SH AUTHOR
-dbus-monitor was written by Philip Blundell.
-The profiling output mode was added by Olli Salli.
-
-.SH BUGS
-Please send bug reports to the D-Bus mailing list or bug tracker,
-see http://www.freedesktop.org/software/dbus/
diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c
index d20faa5..a4b5478 100644
--- a/tools/dbus-monitor.c
+++ b/tools/dbus-monitor.c
@@ -35,6 +35,8 @@
 
 #include "dbus-print-message.h"
 
+#define EAVESDROPPING_RULE "eavesdrop=true"
+
 #ifdef DBUS_WIN
 
 /* gettimeofday is not defined on windows */
@@ -76,6 +78,13 @@
 }
 #endif
 
+inline static void
+oom (const char *doing)
+{
+  fprintf (stderr, "OOM while %s\n", doing);
+  exit (1);
+}
+
 static DBusHandlerResult
 monitor_filter_func (DBusConnection     *connection,
 		     DBusMessage        *message,
@@ -95,7 +104,11 @@
   return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+#ifdef __APPLE__
+#define PROFILE_TIMED_FORMAT "%s\t%lu\t%d"
+#else
 #define PROFILE_TIMED_FORMAT "%s\t%lu\t%lu"
+#endif
 #define TRAP_NULL_STRING(str) ((str) ? (str) : "<none>")
 
 typedef enum
@@ -211,12 +224,19 @@
   exit (ecode);
 }
 
-static dbus_bool_t sigint_received = FALSE;
-
 static void
-sigint_handler (int signum)
+only_one_type (dbus_bool_t *seen_bus_type,
+               char        *name)
 {
-  sigint_received = TRUE;
+  if (*seen_bus_type)
+    {
+      fprintf (stderr, "I only support monitoring one bus at a time!\n");
+      usage (name, 1);
+    }
+  else
+    {
+      *seen_bus_type = TRUE;
+    }
 }
 
 int
@@ -227,6 +247,7 @@
   DBusBusType type = DBUS_BUS_SESSION;
   DBusHandleMessageFunction filter_func = monitor_filter_func;
   char *address = NULL;
+  dbus_bool_t seen_bus_type = FALSE;
   
   int i = 0, j = 0, numFilters = 0;
   char **filters = NULL;
@@ -247,19 +268,27 @@
       char *arg = argv[i];
 
       if (!strcmp (arg, "--system"))
-	type = DBUS_BUS_SYSTEM;
+        {
+          only_one_type (&seen_bus_type, argv[0]);
+          type = DBUS_BUS_SYSTEM;
+        }
       else if (!strcmp (arg, "--session"))
-	type = DBUS_BUS_SESSION;
+        {
+          only_one_type (&seen_bus_type, argv[0]);
+          type = DBUS_BUS_SESSION;
+        }
       else if (!strcmp (arg, "--address"))
-	{
-	  if (i+1 < argc)
-	    {
-	      address = argv[i+1];
-	      i++;
-	    }
-	  else
-	    usage (argv[0], 1);
-	}
+        {
+          only_one_type (&seen_bus_type, argv[0]);
+
+          if (i+1 < argc)
+            {
+              address = argv[i+1];
+              i++;
+            }
+          else
+            usage (argv[0], 1);
+        }
       else if (!strcmp (arg, "--help"))
 	usage (argv[0], 0);
       else if (!strcmp (arg, "--monitor"))
@@ -271,11 +300,21 @@
       else if (arg[0] == '-')
 	usage (argv[0], 1);
       else {
-	numFilters++;
-       filters = (char **)realloc(filters, numFilters * sizeof(char *));
-	filters[j] = (char *)malloc((strlen(arg) + 1) * sizeof(char *));
-	snprintf(filters[j], strlen(arg) + 1, "%s", arg);
-	j++;
+          unsigned int filter_len;
+          numFilters++;
+          /* Prepend a rule (and a comma) to enable the monitor to eavesdrop.
+           * Prepending allows the user to add eavesdrop=false at command line
+           * in order to disable eavesdropping when needed */
+          filter_len = strlen (EAVESDROPPING_RULE) + 1 + strlen (arg) + 1;
+
+          filters = (char **) realloc (filters, numFilters * sizeof (char *));
+          if (filters == NULL)
+            oom ("adding a new filter slot");
+          filters[j] = (char *) malloc (filter_len * sizeof (char *));
+          if (filters[j] == NULL)
+            oom ("adding a new filter");
+          snprintf (filters[j], filter_len, "%s,%s", EAVESDROPPING_RULE, arg);
+          j++;
       }
     }
 
@@ -341,22 +380,22 @@
   else
     {
       dbus_bus_add_match (connection,
-		          "type='signal'",
+		          EAVESDROPPING_RULE ",type='signal'",
 		          &error);
       if (dbus_error_is_set (&error))
         goto lose;
       dbus_bus_add_match (connection,
-		          "type='method_call'",
+		          EAVESDROPPING_RULE ",type='method_call'",
 		          &error);
       if (dbus_error_is_set (&error))
         goto lose;
       dbus_bus_add_match (connection,
-		          "type='method_return'",
+		          EAVESDROPPING_RULE ",type='method_return'",
 		          &error);
       if (dbus_error_is_set (&error))
         goto lose;
       dbus_bus_add_match (connection,
-		          "type='error'",
+		          EAVESDROPPING_RULE ",type='error'",
 		          &error);
       if (dbus_error_is_set (&error))
         goto lose;
diff --git a/tools/dbus-send.1 b/tools/dbus-send.1
deleted file mode 100644
index 4878c3d..0000000
--- a/tools/dbus-send.1
+++ /dev/null
@@ -1,95 +0,0 @@
-.\" 
-.\" dbus-send manual page.
-.\" Copyright (C) 2003 Red Hat, Inc.
-.\"
-.TH dbus-send 1
-.SH NAME
-dbus-send \- Send a message to a message bus
-.SH SYNOPSIS
-.PP
-.B dbus-send
-[\-\-system | \-\-session] [\-\-dest=NAME] [\-\-print-reply]
-[\-\-type=TYPE] <destination object path> <message name> [contents ...]
-
-.SH DESCRIPTION
-
-The \fIdbus-send\fP command is used to send a message to a D-Bus message
-bus. See http://www.freedesktop.org/software/dbus/ for more 
-information about the big picture.
-
-.PP
-There are two well-known message buses: the systemwide message bus 
-(installed on many systems as the "messagebus" service) and the 
-per-user-login-session message bus (started each time a user logs in).
-The \-\-system and \-\-session options direct \fIdbus-send\fP to send
-messages to the system or session buses respectively.  If neither is
-specified, \fIdbus-send\fP sends to the session bus.
-
-.PP 
-Nearly all uses of \fIdbus-send\fP must provide the \-\-dest argument
-which is the name of a connection on the bus to send the message to. If
-\-\-dest is omitted, no destination is set.
-
-.PP
-The object path and the name of the message to send must always be
-specified. Following arguments, if any, are the message contents
-(message arguments).  These are given as type-specified values and 
-may include containers (arrays, dicts, and variants) as described below.
-
-.nf
-<contents>   ::= <item> | <container> [ <item> | <container>...]
-<item>       ::= <type>:<value>
-<container>  ::= <array> | <dict> | <variant>
-<array>      ::= array:<type>:<value>[,<value>...] 
-<dict>       ::= dict:<type>:<type>:<key>,<value>[,<key>,<value>...]
-<variant>    ::= variant:<type>:<value>
-<type>       ::= string | int16 | uint 16 | int32 | uint32 | int64 | uint64 | double | byte | boolean | objpath
-.fi
-
-D-Bus supports more types than these, but \fIdbus-send\fP currently
-does not.  Also, \fIdbus-send\fP does not permit empty containers
-or nested containers (e.g. arrays of variants).
-
-.PP
-Here is an example invocation:
-.nf
-
-  dbus-send \-\-dest=org.freedesktop.ExampleName               \\
-            /org/freedesktop/sample/object/name              \\
-            org.freedesktop.ExampleInterface.ExampleMethod   \\
-            int32:47 string:'hello world' double:65.32       \\
-            array:string:"1st item","next item","last item"  \\
-            dict:string:int32:"one",1,"two",2,"three",3      \\
-            variant:int32:-8                                 \\
-            objpath:/org/freedesktop/sample/object/name 
-
-.fi
-
-Note that the interface is separated from a method or signal 
-name by a dot, though in the actual protocol the interface
-and the interface member are separate fields.
-
-.SH OPTIONS
-The following options are supported:
-.TP
-.I "--dest=NAME"
-Specify the name of the connection to receive the message.
-.TP
-.I "--print-reply"
-Block for a reply to the message sent, and print any reply received.
-.TP
-.I "--system"
-Send to the system message bus.
-.TP
-.I "--session"
-Send to the session message bus.  (This is the default.)
-.TP
-.I "--type=TYPE"
-Specify "method_call" or "signal" (defaults to "signal").
-
-.SH AUTHOR
-dbus-send was written by Philip Blundell.
-
-.SH BUGS
-Please send bug reports to the D-Bus mailing list or bug tracker,
-see http://www.freedesktop.org/software/dbus/
diff --git a/tools/dbus-send.c b/tools/dbus-send.c
index c7d5090..e403a58 100644
--- a/tools/dbus-send.c
+++ b/tools/dbus-send.c
@@ -51,7 +51,7 @@
 static void
 usage (int ecode)
 {
-  fprintf (stderr, "Usage: %s [--help] [--system | --session | --address=ADDRESS] [--dest=NAME] [--type=TYPE] [--print-reply=(literal)] [--reply-timeout=MSEC] <destination object path> <message name> [contents ...]\n", appname);
+  fprintf (stderr, "Usage: %s [--help] [--system | --session | --address=ADDRESS] [--dest=NAME] [--type=TYPE] [--print-reply[=literal]] [--reply-timeout=MSEC] <destination object path> <message name> [contents ...]\n", appname);
   exit (ecode);
 }
 
@@ -302,10 +302,8 @@
 	usage (1);
       else if (path == NULL)
         path = arg;
-      else if (name == NULL)
+      else /* name == NULL guaranteed by the 'while' loop */
         name = arg;
-      else
-        usage (1);
     }
 
   if (name == NULL)
diff --git a/tools/dbus-viewer.c b/tools/dbus-viewer.c
deleted file mode 100644
index 2fd2847..0000000
--- a/tools/dbus-viewer.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/* dbus-viewer.c Graphical D-Bus frontend utility
- *
- * Copyright (C) 2003 Red Hat, Inc.
- *
- * Licensed under the Academic Free License version 2.1
- * 
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-#include <config.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <gtk/gtk.h>
-#include "dbus-tree-view.h"
-#include "dbus-names-model.h"
-#include <glib/dbus-gparser.h>
-#include <glib/dbus-gutils.h>
-#include <dbus/dbus-glib.h>
-#include <glib/gi18n.h>
-
-static void
-show_error_dialog (GtkWindow *transient_parent,
-                   GtkWidget **weak_ptr,
-                   const char *message_format,
-                   ...)
-{
-  char *message;
-  va_list args;
-
-  if (message_format)
-    {
-      va_start (args, message_format);
-      message = g_strdup_vprintf (message_format, args);
-      va_end (args);
-    }
-  else
-    message = NULL;
-
-  if (weak_ptr == NULL || *weak_ptr == NULL)
-    {
-      GtkWidget *dialog;
-      dialog = gtk_message_dialog_new (transient_parent,
-                                       GTK_DIALOG_DESTROY_WITH_PARENT,
-                                       GTK_MESSAGE_ERROR,
-                                       GTK_BUTTONS_CLOSE,
-                                       message);
-
-      g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), NULL);
-
-      if (weak_ptr != NULL)
-        {
-          *weak_ptr = dialog;
-          g_object_add_weak_pointer (G_OBJECT (dialog), (void**)weak_ptr);
-        }
-
-      gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
-      
-      gtk_widget_show_all (dialog);
-    }
-  else 
-    {
-      g_return_if_fail (GTK_IS_MESSAGE_DIALOG (*weak_ptr));
-
-      gtk_label_set_text (GTK_LABEL (GTK_MESSAGE_DIALOG (*weak_ptr)->label), message);
-
-      gtk_window_present (GTK_WINDOW (*weak_ptr));
-    }
-}
-
-typedef struct
-{
-  DBusGConnection *connection;
-  
-  GtkWidget *window;
-  GtkWidget *treeview;
-  GtkWidget *name_menu;
-
-  GtkTreeModel *names_model;
-
-  GtkWidget *error_dialog;
-  
-} TreeWindow;
-
-
-static void
-tree_window_set_node (TreeWindow *w,
-                      NodeInfo   *node)
-{
-  char **path;
-  const char *name;
-
-  name = node_info_get_name (node);
-  if (name == NULL ||
-      name[0] != '/')
-    {
-      g_printerr (_("Assuming root node is at path /, since no absolute path is specified"));
-      name = "/";
-    }
-
-  path = _dbus_gutils_split_path (name);
-  
-  dbus_tree_view_update (GTK_TREE_VIEW (w->treeview),
-                         (const char**) path,
-                         node);
-
-  g_strfreev (path);
-}
-
-typedef struct
-{
-  DBusGConnection *connection;
-  char *service_name;
-  GError *error;
-  NodeInfo *node;
-  TreeWindow *window; /* Not touched from child thread */
-} LoadFromServiceData;
-
-static gboolean
-load_child_nodes (const char *service_name,
-                  NodeInfo   *parent,
-                  GString    *path,
-                  GError    **error)
-{
-  DBusGConnection *connection;
-  GSList *tmp;
-  
-  connection = dbus_g_bus_get (DBUS_BUS_SESSION, error);
-  if (connection == NULL)
-    return FALSE;
-  
-  tmp = node_info_get_nodes (parent);
-  while (tmp != NULL)
-    {
-      DBusGProxy *proxy;
-      char *data;
-      NodeInfo *child;
-      NodeInfo *complete_child;
-      int save_len;
-
-      complete_child = NULL;
-      
-      child = tmp->data;
-
-      save_len = path->len;
-
-      if (save_len > 1)
-        g_string_append (path, "/");
-      g_string_append (path, base_info_get_name ((BaseInfo*)child));
-
-      if (*service_name == ':')
-        {
-          proxy = dbus_g_proxy_new_for_name (connection,
-                                             service_name,
-                                             path->str,
-                                             DBUS_INTERFACE_INTROSPECTABLE);
-          g_assert (proxy != NULL);
-        }
-      else
-        {
-          proxy = dbus_g_proxy_new_for_name_owner (connection,
-                                                   service_name,
-                                                   path->str,
-                                                   DBUS_INTERFACE_INTROSPECTABLE,
-                                                   error);
-          if (proxy == NULL)
-            goto done;
-        }
-  
-      if (!dbus_g_proxy_call (proxy, "Introspect", error,
-                              G_TYPE_INVALID,
-			      G_TYPE_STRING, &data,
-			      G_TYPE_INVALID))
-	  goto done;
-      
-      complete_child = description_load_from_string (data, -1, error);
-      g_free (data);
-      if (complete_child == NULL)
-        {
-          g_printerr ("%s\n", data);
-          goto done;
-        }
-      
-    done:
-      g_object_unref (proxy);
-
-      if (complete_child == NULL)
-        return FALSE;
-
-      /* change complete_child's name to relative */
-      base_info_set_name ((BaseInfo*)complete_child,
-                          base_info_get_name ((BaseInfo*)child));
-      
-      /* Stitch in complete_child rather than child */
-      node_info_replace_node (parent, child, complete_child);
-      node_info_unref (complete_child); /* ref still held by parent */
-      
-      /* Now recurse */
-      if (!load_child_nodes (service_name, complete_child, path, error))
-        return FALSE;
-
-      /* restore path */
-      g_string_set_size (path, save_len);
-      
-      tmp = tmp->next;
-    }
-
-  return TRUE;
-}
-
-static gboolean
-load_from_service_complete_idle (void *data)
-{
-  /* Called in main thread */
-  GThread *thread = data;
-  LoadFromServiceData *d;
-  NodeInfo *node;
-
-  d = g_thread_join (thread);
-
-  node = d->node;
-  
-  if (d->error)
-    {
-      g_assert (d->node == NULL);
-      show_error_dialog (GTK_WINDOW (d->window->window), &d->window->error_dialog,
-                         _("Unable to load \"%s\": %s\n"),
-                         d->service_name, d->error->message);
-      g_error_free (d->error);
-    }
-  else
-    {
-      g_assert (d->error == NULL);
-
-      tree_window_set_node (d->window, node);
-      node_info_unref (node);
-    }
-
-  g_free (d->service_name);
-  dbus_g_connection_unref (d->connection);
-  g_free (d);
-
-  return FALSE;
-}
-
-static void*
-load_from_service_thread_func (void *thread_data)
-{  
-  DBusGProxy *root_proxy;
-  const char *data;
-  NodeInfo *node;
-  GString *path;
-  LoadFromServiceData *lfsd;
-
-  lfsd = thread_data;
-
-  node = NULL;
-  path = NULL;
- 
-#if 1
-  /* this will end up autolaunching the service when we introspect it */
-  root_proxy = dbus_g_proxy_new_for_name (lfsd->connection,
-                                          lfsd->service_name,
-                                          "/",
-                                          DBUS_INTERFACE_INTROSPECTABLE);
-  g_assert (root_proxy != NULL);
-#else
-  /* this will be an error if the service doesn't exist */
-  root_proxy = dbus_g_proxy_new_for_name_owner (lfsd->connection,
-                                                lfsd->service_name,
-                                                "/",
-                                                DBUS_INTERFACE_INTROSPECTABLE,
-                                                &lfsd->error);
-  if (root_proxy == NULL)
-    {
-      g_printerr ("Failed to get owner of '%s'\n", lfsd->service_name);
-      return lfsd->data;
-    }
-#endif
-  
-  if (!dbus_g_proxy_call (root_proxy, "Introspect", &lfsd->error,
-			  G_TYPE_INVALID,
-			  G_TYPE_STRING, &data,
-			  G_TYPE_INVALID))
-    {
-      g_printerr ("Failed to Introspect() %s\n",
-		  dbus_g_proxy_get_bus_name (root_proxy));
-      goto out;
-    }
-
-  node = description_load_from_string (data, -1, &lfsd->error);
-
-  /* g_print ("%s\n", data); */
-  
-  if (node == NULL)
-    goto out;
-
-  base_info_set_name ((BaseInfo*)node, "/");
-
-  path = g_string_new ("/");
-  
-  if (!load_child_nodes (dbus_g_proxy_get_bus_name (root_proxy),
-                         node, path, &lfsd->error))
-    {
-      node_info_unref (node);
-      node = NULL;
-      goto out;
-    }
-  
- out:
-  g_object_unref (root_proxy);
-
-  if (path)
-    g_string_free (path, TRUE);
-
-  lfsd->node = node;
-  g_assert (lfsd->node || lfsd->error);
-  g_assert (lfsd->node == NULL || lfsd->error == NULL);
-
-  /* Add idle to main thread that will join us back */
-  g_idle_add (load_from_service_complete_idle, g_thread_self ());
-  
-  return lfsd;
-}
-
-static void
-start_load_from_service (TreeWindow      *w,
-                         DBusGConnection *connection,
-                         const char      *service_name)
-{
-  LoadFromServiceData *d;
-
-  d = g_new0 (LoadFromServiceData, 1);
-  
-  d->connection = dbus_g_connection_ref (connection);
-  d->service_name = g_strdup (service_name);
-  d->error = NULL;
-  d->node = NULL;
-  d->window = w;
-  
-  g_thread_create (load_from_service_thread_func, d, TRUE, NULL);
-}
-
-static void
-tree_window_set_service (TreeWindow *w,
-                         const char *service_name)
-{
-  start_load_from_service (w, w->connection, service_name);
-}
-
-static void
-name_combo_changed_callback (GtkComboBox *combo,
-                             TreeWindow  *w)
-{
-  GtkTreeIter iter;
-
-  if (gtk_combo_box_get_active_iter (combo, &iter))
-    {
-      GtkTreeModel *model;
-      char *text;
-
-      model = gtk_combo_box_get_model (combo);
-      gtk_tree_model_get (model, &iter, 0, &text, -1);
-
-      if (text)
-        {
-          tree_window_set_service (w, text);
-          g_free (text);
-        }
-    }
-}
-
-static void
-window_closed_callback (GtkWidget  *window,
-                        TreeWindow *w)
-{
-  g_assert (window == w->window);
-  w->window = NULL;
-  gtk_main_quit ();
-}
-
-static TreeWindow*
-tree_window_new (DBusGConnection *connection,
-                 GtkTreeModel    *names_model)
-{
-  TreeWindow *w;
-  GtkWidget *sw;
-  GtkWidget *vbox;
-  GtkWidget *hbox;
-  GtkWidget *combo;
-
-  /* Should use glade, blah */
-  
-  w = g_new0 (TreeWindow, 1);
-  w->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-
-  gtk_window_set_title (GTK_WINDOW (w->window), "D-Bus Viewer");
-  gtk_window_set_default_size (GTK_WINDOW (w->window), 400, 500);
-
-  g_signal_connect (w->window, "destroy", G_CALLBACK (window_closed_callback),
-                    w);
-  gtk_container_set_border_width (GTK_CONTAINER (w->window), 6);
-
-  vbox = gtk_vbox_new (FALSE, 6);
-  gtk_container_add (GTK_CONTAINER (w->window), vbox);
-
-  /* Create names option menu */
-  if (connection)
-    {
-      GtkCellRenderer *cell;
-
-      w->connection = connection;
-      
-      w->names_model = names_model;
-
-      combo = gtk_combo_box_new_with_model (w->names_model);
-
-      cell = gtk_cell_renderer_text_new ();
-      gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell, TRUE);
-      gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell,
-                                      "text", 0,
-                                      NULL);
-      
-      gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
-
-      g_signal_connect (combo, "changed",
-                        G_CALLBACK (name_combo_changed_callback),
-                        w);
-    }
-  
-  /* Create tree view */
-  hbox = gtk_hbox_new (FALSE, 6);
-  gtk_container_add (GTK_CONTAINER (vbox), hbox);
-  
-  sw = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
-                                  GTK_POLICY_AUTOMATIC,
-                                  GTK_POLICY_AUTOMATIC);
-
-  gtk_box_pack_start (GTK_BOX (hbox), sw, TRUE, TRUE, 0);
-
-  w->treeview = dbus_tree_view_new ();
-
-  gtk_container_add (GTK_CONTAINER (sw), w->treeview);
-
-  /* Show everything */
-  gtk_widget_show_all (w->window);
-
-  return w;
-}
-
-static void
-usage (int ecode)
-{
-  fprintf (stderr, "dbus-viewer [--version] [--help]\n");
-  exit (ecode);
-}
-
-static void
-version (void)
-{
-  printf ("D-Bus Message Bus Viewer %s\n"
-          "Copyright (C) 2003 Red Hat, Inc.\n"
-          "This is free software; see the source for copying conditions.\n"
-          "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
-          VERSION);
-  exit (0);
-}
-
-int
-main (int argc, char **argv)
-{
-  int i;
-  GSList *files;
-  gboolean end_of_args;
-  GSList *tmp;
-  gboolean services;
-  DBusGConnection *connection;
-  GError *error;
-  GtkTreeModel *names_model;
-
-  g_thread_init (NULL);
-  dbus_g_thread_init ();
-  
-  bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR);
-  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-  textdomain (GETTEXT_PACKAGE);
-  
-  gtk_init (&argc, &argv);
-
-  services = FALSE;
-  end_of_args = FALSE;
-  files = NULL;
-  i = 1;
-  while (i < argc)
-    {
-      const char *arg = argv[i];
-
-      if (!end_of_args)
-        {
-          if (strcmp (arg, "--help") == 0 ||
-              strcmp (arg, "-h") == 0 ||
-              strcmp (arg, "-?") == 0)
-            usage (0);
-          else if (strcmp (arg, "--version") == 0)
-            version ();
-          else if (strcmp (arg, "--services") == 0)
-            services = TRUE;
-          else if (arg[0] == '-' &&
-                   arg[1] == '-' &&
-                   arg[2] == '\0')
-            end_of_args = TRUE;
-          else if (arg[0] == '-')
-            {
-              usage (1);
-            }
-          else
-            {
-              files = g_slist_prepend (files, (char*) arg);
-            }
-        }
-      else
-        files = g_slist_prepend (files, (char*) arg);
-      
-      ++i;
-    }
-
-  if (services || files == NULL)
-    {
-      error = NULL;
-      connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
-      if (connection == NULL)
-        {
-          g_printerr ("Could not open bus connection: %s\n",
-                      error->message);
-          g_error_free (error);
-          exit (1);
-        }
-
-      g_assert (connection == dbus_g_bus_get (DBUS_BUS_SESSION, NULL));
-
-      names_model = names_model_new (connection);
-    }
-  else
-    {
-      connection = NULL;
-      names_model = NULL;
-    }
-
-  if (files == NULL)
-    {
-      TreeWindow *w;
-
-      w = tree_window_new (connection, names_model);
-    }
-  
-  files = g_slist_reverse (files);
-
-  tmp = files;
-  while (tmp != NULL)
-    {
-      const char *filename;
-      TreeWindow *w;
-
-      filename = tmp->data;
-      
-      if (services)
-        {
-          w = tree_window_new (connection, names_model);
-          tree_window_set_service (w, filename);
-        }
-      else
-        {
-          NodeInfo *node;
-          
-          error = NULL;
-          node = description_load_from_file (filename,
-                                             &error);
-          
-          if (node == NULL)
-            {
-              g_assert (error != NULL);
-              show_error_dialog (NULL, NULL,
-                                 _("Unable to load \"%s\": %s\n"),
-                                 filename, error->message);
-              g_error_free (error);
-            }
-          else
-            {
-              w = tree_window_new (connection, names_model);
-              tree_window_set_node (w, node);
-              node_info_unref (node);
-            }
-        }
-      
-      tmp = tmp->next;
-    }
-
-  gtk_main ();
-  
-  return 0;
-}
-
diff --git a/tools/lcov.am b/tools/lcov.am
new file mode 100644
index 0000000..7ba4991
--- /dev/null
+++ b/tools/lcov.am
@@ -0,0 +1,43 @@
+# Copyright © 2008-2011 Collabora Ltd.
+# Copyright © 2008-2011 Nokia Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+lcov-reset:
+	lcov --directory @abs_top_srcdir@ --zerocounters
+
+lcov-report:
+	lcov --directory @abs_top_srcdir@ --capture \
+		--output-file @abs_top_builddir@/lcov.info
+	$(mkdir_p) @abs_top_builddir@/lcov.html
+	git_commit=`GIT_DIR=@abs_top_srcdir@/.git git log -1 --pretty=format:%h 2>/dev/null`;\
+	genhtml --title "@PACKAGE_STRING@ $$git_commit" \
+		--output-directory @abs_top_builddir@/lcov.html lcov.info
+	@echo
+	@echo 'lcov report can be found in:'
+	@echo 'file://@abs_top_builddir@/lcov.html/index.html'
+	@echo
+
+lcov-check:
+	$(MAKE) lcov-reset
+	$(MAKE) check $(LCOV_CHECK_ARGS)
+	$(MAKE) lcov-report
+
+## vim:set ft=automake:
diff --git a/tools/run-with-tmp-session-bus.sh b/tools/run-with-tmp-session-bus.sh
index 982184a..c39999f 100644
--- a/tools/run-with-tmp-session-bus.sh
+++ b/tools/run-with-tmp-session-bus.sh
@@ -1,4 +1,4 @@
-#! /bin/bash
+#! /bin/sh
 
 SCRIPTNAME=$0
 WRAPPED_SCRIPT=$1
diff --git a/update-dbus-docs.sh b/update-dbus-docs.sh
deleted file mode 100755
index 627f0a7..0000000
--- a/update-dbus-docs.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#! /bin/bash
-
-function die()
-{
-    echo $* 2>&1
-    exit 1
-}
-
-if test -n "$FDUSER" ; then
-    echo "Using freedesktop.org account $FDUSER"
-    user="$FDUSER@"
-else
-    echo "Using freedesktop.org account from ~/.ssh/config, or local username"
-fi
-
-CHECKOUTDIR=`mktemp -d || echo /tmp/dbus-for-docs`
-export CVSROOT=":ext:${user}cvs.freedesktop.org:/cvs/dbus"
-
-cd $CHECKOUTDIR || die "could not changedir to $CHECKOUTDIR"
-
-echo "Checking out to directory "`pwd`
-
-/bin/rm -rf dbus/doc || true ## get rid of old doxygen, etc.
-cvs co dbus || die "failed to cvs update"
-cd dbus || die "could not cd to dbus"
-
-echo "Configuring and building docs"
-
-## the configure flags are explicit so if you lack xmlto, etc. 
-## you won't fail to update those docs
-./autogen.sh --enable-xml-docs=yes --enable-doxygen-docs=yes || die "could not autogen"
-doxygen Doxyfile || die "could not run Doxygen"
-make -C doc || die "could not build docs"
-
-MANFILES=`find -name "dbus*.1"`
-for M in $MANFILES ; do
-    BASENAME=`basename $M`
-    echo "Converting $M to $BASENAME.html"
-    man2html $M > doc/$BASENAME.html
-done
-
-echo "Packing docs into tarball"
-cp README HACKING AUTHORS NEWS COPYING ChangeLog doc/ || die "could not copy in assorted files"
-tar cfz dbus-docs.tar.gz doc/*.dtd doc/*.xsl doc/*.xml doc/*.html doc/*.txt doc/api/html/*.html doc/api/html/*.css doc/api/html/*.png doc/api/html/*.gif doc/HACKING doc/AUTHORS doc/NEWS doc/ChangeLog doc/TODO doc/README doc/COPYING doc/*.png doc/*.svg || die "could not tar up docs"
-
-tar tfz dbus-docs.tar.gz | sort > tarball.list || die "could not list tarball contents"
-find doc -not -type d | grep -v CVS | grep -v -E '.~[0-9.]+~' | grep -v Makefile | grep -vE '.c$' | grep -v man3dbus | grep -v .cvsignore | sort > filesystem.list || die "could not list doc/* contents"
-
-diff -u filesystem.list tarball.list || die "some files were not included"
-
-echo "Uploading docs to server"
-scp dbus-docs.tar.gz "${user}"dbus.freedesktop.org:
-ssh "${user}"dbus.freedesktop.org '(cd /srv/dbus.freedesktop.org/www/ && /bin/cp -f ~/dbus-docs.tar.gz . && tar zxf dbus-docs.tar.gz && echo "Successfully unpacked tarball on server")'
-
-echo "Uploading DTD to server"
-scp -p doc/introspect.dtd "${user}"dbus.freedesktop.org:/srv/specifications.freedesktop.org/www/dbus/1.0/introspect.dtd