dbus/dbus dbus-object-tree.c,1.1,1.2 dbus-object-tree.h,1.1,1.2 dbus-pending-call.c,1.1,1.2 dbus-pending-call.h,1.1,1.2 Makefile.am,1.56,1.57 dbus-address.c,1.10,1.11 dbus-auth.c,1.28,1.29 dbus-bus.c,1.24,1.25 dbus-bus.h,1.7,1.8 dbus-connection-internal.h,1.12,1.13 dbus-connection.c,1.69,1.70 dbus-connection.h,1.24,1.25 dbus-dataslot.h,1.3,1.4 dbus-errors.c,1.21,1.22 dbus-errors.h,1.19,1.20 dbus-hash.c,1.14,1.15 dbus-hash.h,1.9,1.10 dbus-internals.c,1.30,1.31 dbus-internals.h,1.36,1.37 dbus-keyring.c,1.18,1.19 dbus-mainloop.c,1.12,1.13 dbus-mainloop.h,1.3,1.4 dbus-marshal.c,1.41,1.42 dbus-marshal.h,1.17,1.18 dbus-md5.h,1.1,1.2 dbus-message-builder.c,1.18,1.19 dbus-message.c,1.103,1.104 dbus-message.h,1.42,1.43 dbus-protocol.h,1.20,1.21 dbus-server-debug-pipe.c,1.12,1.13 dbus-server-protected.h,1.10,1.11 dbus-server-unix.c,1.18,1.19 dbus-server.c,1.29,1.30 dbus-sha.h,1.1,1.2 dbus-spawn.c,1.12,1.13 dbus-string.c,1.41,1.42 dbus-string.h,1.20,1.21 dbus-sysdeps.c,1.64,1.65 dbus-sysdeps.h,1.35,1.36 dbus-test.c,1.30,1.31 dbus-test.h,1.22,1.23 dbus-threads.c,1.17,1.18 dbus-threads.h,1.3,1.4 dbus-timeout.c,1.10,1.11 dbus-transport-protected.h,1.9,1.10 dbus-transport.c,1.33,1.34 dbus-types.h,1.7,1.8 dbus-userdb.c,1.4,1.5 dbus-watch.c,1.13,1.14 dbus.h,1.15,1.16

Havoc Pennington hp@pdx.freedesktop.org
Mon, 29 Sep 2003 19:33:26 -0700


Update of /cvs/dbus/dbus/dbus
In directory pdx:/tmp/cvs-serv18265/dbus

Modified Files:
	Makefile.am dbus-address.c dbus-auth.c dbus-bus.c dbus-bus.h 
	dbus-connection-internal.h dbus-connection.c dbus-connection.h 
	dbus-dataslot.h dbus-errors.c dbus-errors.h dbus-hash.c 
	dbus-hash.h dbus-internals.c dbus-internals.h dbus-keyring.c 
	dbus-mainloop.c dbus-mainloop.h dbus-marshal.c dbus-marshal.h 
	dbus-md5.h dbus-message-builder.c dbus-message.c 
	dbus-message.h dbus-protocol.h dbus-server-debug-pipe.c 
	dbus-server-protected.h dbus-server-unix.c dbus-server.c 
	dbus-sha.h dbus-spawn.c dbus-string.c dbus-string.h 
	dbus-sysdeps.c dbus-sysdeps.h dbus-test.c dbus-test.h 
	dbus-threads.c dbus-threads.h dbus-timeout.c 
	dbus-transport-protected.h dbus-transport.c dbus-types.h 
	dbus-userdb.c dbus-watch.c dbus.h 
Added Files:
	dbus-object-tree.c dbus-object-tree.h dbus-pending-call.c 
	dbus-pending-call.h 
Log Message:
2003-09-29  Havoc Pennington  <hp@pobox.com>

	* Merge dbus-object-names branch. To see the entire patch 
	do cvs diff -r DBUS_OBJECT_NAMES_BRANCHPOINT -r dbus-object-names,
	it's huuuuge though.
	To revert, I tagged DBUS_BEFORE_OBJECT_NAMES_MERGE.
	
2003-09-28  Havoc Pennington  <hp@pobox.com>

	* HACKING: update to reflect new server

2003-09-26  Seth Nickell  <seth@gnome.org>

	* python/dbus.py:
	* python/examples/example-signals.py:

	Start implementing some notions of signals. The API
	is really terrible, but they sort of work (with the
	exception of being able to filter by service, and to
	transmit signals *as* a particular service). Need to
	figure out how to make messages come from the service
	we registered :-(
	
	* python/dbus_bindings.pyx.in:

	Removed duplicate message_handler callbacks.
	
2003-09-25  Havoc Pennington  <hp@redhat.com>

	* bus/session.conf.in: fix my mess

2003-09-25  Havoc Pennington  <hp@pobox.com>

	* bus/session.conf.in: fix security policy, reported by Seth Nickell

2003-09-25  Seth Nickell  <seth@gnome.org>

	* python/examples/example-service.py:

	Johan notices complete wrong code in example-service, but
	completely wrong in a way that works exactly the same (!).
	Johan is confused, how could this possibly work? Example
	code fails to serve purpose of making things clear.
	Seth fixes.

2003-09-25  Mark McLoughlin  <mark@skynet.ie>

	* doc/dbus-specification.sgml: don't require header fields
	to be 4-byte aligned and specify that fields should be
	distinguished from padding by the fact that zero is not
	a valid field name.
	
	* doc/TODO: remove re-alignment item and add item to doc
	the OBJECT_PATH type.
	
	* dbus/dbus-message.c:
	(HeaderField): rename the original member to value_offset
	and introduce a name_offset member to keep track of where
	the field actually begins.
	(adjust_field_offsets): remove.
	(append_int_field), (append_uint_field),
	(append_string_field): don't align the start of the header
	field to a 4-byte boundary.
	(get_next_field): impl finding the next marhsalled field
	after a given field.
	(re_align_field_recurse): impl re-aligning a number of
	already marshalled fields.
	(delete_field): impl deleting a field of any type and
	re-aligning any following fields.
	(delete_int_or_uint_field), (delete_string_field): remove.
	(set_int_field), (set_uint_field): no need to re-check
	that we have the correct type for the field.
	(set_string_field): ditto and impl re-aligning any
	following fields.
	(decode_header_data): update to take into account that
	the fields aren't 4-byte aligned any more and the new
	way to distinguish padding from header fields. Also,
	don't exit when there is too much header padding.
	(process_test_subdir): print the directory.
	(_dbus_message_test): add test to make sure a following
	field is re-aligned correctly after field deletion.
	
	* dbus/dbus-string.[ch]:
	(_dbus_string_insert_bytes): rename from insert_byte and
	allow the insert of multiple bytes.
	(_dbus_string_test): test inserting multiple bytes.

	* dbus/dbus-marshal.c: (_dbus_marshal_set_string): add
	warning note to docs about having to re-align any
	marshalled values following the string.
	
	* dbus/dbus-message-builder.c:
	(append_string_field), (_dbus_message_data_load):
	don't align the header field.
	
	* dbus/dbus-auth.c: (process_test_subdir): print the
	directory.
	
	* test/break-loader.c: (randomly_add_one_byte): upd. for
	insert_byte change.
	
	* test/data/invalid-messages/bad-header-field-alignment.message:
	new test case.
	
	* test/data/valid-messages/unknown-header-field.message: shove
	a dict in the unknown field.

2003-09-25  Seth Nickell  <seth@gnome.org>

	* python/dbus.py:
	* python/dbus_bindings.pyx.in:

	Handle return values.
	
	* python/examples/example-client.py:
	* python/examples/example-service.py:

	Pass back return values from the service to the client.
	
2003-09-24  Seth Nickell  <seth@gnome.org>

	* python/dbus.py:

	Connect Object methods (when you are sharing an object) up... pass
	in a list of methods to be shared. Sharing all the methods just
	worked out too weird. You can now create nice Services over the
	DBus in Python. :-)
	
	* python/dbus_bindings.pyx.in:

	Keep references to user_data tuples passed into C functions so 
	Python doesn't garbage collect on us.

	Implement MethodReturn and Error subclasses of Message for creating
	DBusMessage's of those types.
	
	* python/examples/example-client.py:
	* python/examples/example-service.py:

	Simple example code showing both how create DBus services and objects,
	and how to use them.

2003-09-23  Havoc Pennington  <hp@pobox.com>

	* glib/dbus-gproxy.c (dbus_gproxy_manager_filter): implement

2003-09-23  Havoc Pennington  <hp@redhat.com>

	* glib/dbus-gproxy.c (dbus_gproxy_connect_signal): implement
	(dbus_gproxy_disconnect_signal): implement
	(dbus_gproxy_manager_remove_signal_match): implement
	(dbus_gproxy_manager_add_signal_match): implement
	(dbus_gproxy_oneway_call): implement

2003-09-23  Havoc Pennington  <hp@pobox.com>

	* glib/dbus-gproxy.c (struct DBusGProxy): convert to a GObject
	subclass. This means dropping the transparent thread safety of the
	proxy; you now need a separate proxy per-thread, or your own
	locking on the proxy. Probably right anyway.
	(dbus_gproxy_ref, dbus_gproxy_unref): nuke, just use g_object_ref

2003-09-22  Havoc Pennington  <hp@redhat.com>

	* glib/dbus-gproxy.c (dbus_gproxy_manager_get): implement

2003-09-21  Seth Nickell  <seth@gnome.org>

        First checkin of the Python bindings.
	
	* python/.cvsignore:
	* python/Makefile.am:
	* python/dbus_bindings.pyx.in:
	* python/dbus_h_wrapper.h:

	Pieces for Pyrex to operate on, building a dbus_bindings.so
	python module for low-level access to the DBus APIs.
	
	* python/dbus.py:

	High-level Python module for accessing DBus objects.

	* configure.in:
	* Makefile.am:

	Build stuff for the python bindings.

	* acinclude.m4:

	Extra macro needed for finding the Python C header files.

2003-09-21  Havoc Pennington  <hp@pobox.com>

	* glib/dbus-gproxy.c (dbus_gproxy_manager_new): start
	implementing the proxy manager, didn't get very far.

	* dbus/dbus-bus.c (dbus_bus_add_match): new
	(dbus_bus_remove_match): new

	* glib/dbus-gproxy.c (dbus_gproxy_new_for_service): add a
	path_name argument; adjust the other not-yet-implemented 
	gproxy constructors to be what I think they should be.

2003-09-21  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-bus.c (dbus_bus_get): set exit_on_disconnect to TRUE
	by default for message bus connections.

	* dbus/dbus-connection.c (dbus_connection_dispatch): exit if
	exit_on_disconnect flag is set and we process the disconnected
	signal.
	(dbus_connection_set_exit_on_disconnect): new function

2003-09-21  Havoc Pennington  <hp@pobox.com>

	Get matching rules mostly working in the bus; only actually
	parsing the rule text remains. However, the client side of
	"signal connections" hasn't been started, this patch is only the
	bus side.
	
	* dbus/dispatch.c: fix for the matching rules changes
	
	* bus/driver.c (bus_driver_handle_remove_match)
	(bus_driver_handle_add_match): send an ack reply from these
	method calls

	* glib/dbus-gproxy.c (dbus_gproxy_begin_call): fix order of
	arguments, reported by Seth Nickell

	* bus/config-parser.c (append_rule_from_element): support
	eavesdrop=true|false attribute on policies so match rules 
	can be prevented from snooping on the system bus.

	* bus/dbus-daemon-1.1.in: consistently use terminology "sender"
	and "destination" in attribute names; fix some docs bugs; 
	add eavesdrop=true|false attribute

	* bus/driver.c (bus_driver_handle_add_match)
	(bus_driver_handle_remove_match): handle AddMatch, RemoveMatch
	messages

	* dbus/dbus-protocol.h (DBUS_SERVICE_ORG_FREEDESKTOP_BROADCAST): get
	rid of broadcast service concept, signals are just always broadcast

	* bus/signals.c, bus/dispatch.c, bus/connection.c, bus/bus.c:
	mostly implement matching rules stuff (currently only exposed as signal
	connections)

2003-09-21  Mark McLoughlin  <mark@skynet.ie>

	* doc/dbus-specification.sgml: Change the header field name
	to be an enum and update the rest of the spec to reference
	the fields using the conventinal name.

	* dbus/dbus-protocol.h: update to reflect the spec.

	* doc/TODO: add item to remove the 4 byte alignment requirement.
	
	* dbus/dbus-message.c: Remove the code to generalise the
	header/body length and serial number header fields as named
	header fields so we can reference field names using the 
	protocol values.
	(append_int_field), (append_uint_field), (append_string_field):
	Append the field name as a byte rather than four chars.
	(delete_int_or_uint_field), (delete_string_field): reflect the
	fact that the field name and typecode now occupy 4 bytes instead
	of 8.
	(decode_string_field), (decode_header_data): update to reflect
	protocol changes and move the field specific encoding from
	decode_string_field() back into decode_header_data().
	
	* dbus/dbus-internals.[ch]: (_dbus_header_field_to_string):
	Add utility to aid debugging.
	
	* dbus/dbus-message-builder.c:
	(append_string_field), (_dbus_message_data_load): Update to
	reflect protocol changes; Change the FIELD_NAME directive
	to HEADER_FIELD and allow it to take the field's conventional
	name rather than the actual value.
	
	* test/data/*/*.message: Update to use HEADER_FIELD instead
	of FIELD_NAME; Always align the header on an 8 byte boundary
	*before* updating the header length.

2003-09-15  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-pending-call.c: add the get/set object data
	boilerplate as for DBusConnection, etc. Use generic object data
	for the notify callback.

	* glib/dbus-gparser.c (parse_node): parse child nodes

	* tools/dbus-viewer.c: more hacking on the dbus-viewer
	
	* glib/dbus-gutils.c (_dbus_gutils_split_path): add a file to
	contain functions shared between the convenience lib and the
	installed lib

	* glib/Makefile.am (libdbus_glib_1_la_LDFLAGS): add
	-export-symbols-regex to the GLib library

	* dbus/dbus-object-tree.c (_dbus_object_tree_dispatch_and_unlock):
	fix the locking in here, and add a default handler for
	Introspect() that just returns sub-nodes.

2003-09-14  Havoc Pennington  <hp@pobox.com>

	* glib/dbus-gthread.c (dbus_g_thread_init): rename to make g_foo
	rather than gfoo consistent

	* glib/dbus-gproxy.h: delete for now, move contents to
	dbus-glib.h, because the include files don't work right since we
	aren't in the dbus/ subdir.
	
	* glib/dbus-gproxy.c (dbus_gproxy_send): finish implementing
	(dbus_gproxy_end_call): finish
	(dbus_gproxy_begin_call): finish

	* glib/dbus-gmain.c (dbus_set_g_error): new

	* glib/dbus-gobject.c (handle_introspect): include information
	about child nodes in the introspection

	* dbus/dbus-connection.c (dbus_connection_list_registered): new
	function to help in implementation of introspection

	* dbus/dbus-object-tree.c
	(_dbus_object_tree_list_registered_and_unlock): new function

2003-09-12  Havoc Pennington  <hp@pobox.com>

	* glib/dbus-gidl.h: add common base class for all the foo_info
	types

        * tools/dbus-viewer.c: add GTK-based introspection UI thingy
	similar to kdcop

	* test/Makefile.am: try test srcdir -ef . in addition to test
	srcdir = ., one of them should work (yeah lame)
	
        * glib/Makefile.am: build the "idl" parser stuff as a convenience
	library
	
	* glib/dbus-gparser.h: make description_load routines return
	NodeInfo* not Parser*

	* Makefile.am (SUBDIRS): build test dir after all library dirs

	* configure.in: add GTK+ detection

2003-09-07  Havoc Pennington  <hp@pobox.com>

	* Make Doxygen contented.

2003-09-07  Havoc Pennington  <hp@pobox.com>

	* doc/dbus-specification.sgml: more updates

2003-09-06  Havoc Pennington  <hp@pobox.com>

	* doc/dbus-specification.sgml: partial updates

	* bus/dbus-daemon-1.1.in: fix the config file docs for the
	zillionth time; hopefully I edited the right file this time.

	* bus/config-parser.c (append_rule_from_element): support
	send_type, send_path, receive_type, receive_path

	* bus/policy.c: add message type and path to the list of things
	that can be "firewalled"

2003-09-06  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-connection.c (dbus_connection_register_fallback): add this
	(dbus_connection_register_object_path): make this not handle
	messages to paths below the given path

2003-09-03  Havoc Pennington  <hp@pobox.com>

	* test/glib/Makefile.am: add this with random glib-linked test
	programs

	* glib/Makefile.am: remove the random test programs from here,
	leave only the unit tests

	* glib/dbus-gobject.c (_dbus_gobject_test): add test for 
	uscore/javacaps conversion, and fix	
	(get_object_property, set_object_property): change to .NET
	convention for mapping props to methods, set_FooBar/get_FooBar, 
	since one language has such a convention we may as well copy it. 
	Plus real methods in either getFooBar or get_foo_bar style won't 
	collide with this convention.

2003-09-01  Havoc Pennington  <hp@pobox.com>

	* glib/dbus-gparser.c: implement

	* glib/dbus-gobject.c: start implementing skeletons support

	* configure.in: when disabling checks/assert, also define
	G_DISABLE_ASSERT and G_DISABLE_CHECKS

2003-09-01  Havoc Pennington  <hp@pobox.com>

	* glib/Makefile.am: rearrange a bunch of files and get "make
	check" framework set up

2003-08-31  Havoc Pennington  <hp@pobox.com>

	* fix build with --disable-tests

2003-08-30  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-connection.c: purge DBusMessageHandler

	* dbus/dbus-message-handler.c: remove DBusMessageHandler, just 
	use callbacks everywhere

2003-08-30  Havoc Pennington  <hp@pobox.com>

	* test/data/valid-config-files/system.d/test.conf: change to 
	root for the user so warnings don't get printed

	* dbus/dbus-message.c: add dbus_message_get_path,
	dbus_message_set_path
	
	* dbus/dbus-object-tree.c (do_test_dispatch): add test of
	dispatching to a path

	* dbus/dbus-string.c (_dbus_string_validate_path): add

	* dbus/dbus-marshal.c (_dbus_demarshal_object_path): implement
	(_dbus_marshal_object_path): implement

	* dbus/dbus-protocol.h (DBUS_HEADER_FIELD_PATH): new header field 
	to contain the path to the target object
	(DBUS_HEADER_FIELD_SENDER_SERVICE): rename
	DBUS_HEADER_FIELD_SENDER to explicitly say it's the sender service

2003-08-30  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object-tree.c: write tests and fix the discovered bugs

2003-08-29  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object-tree.c: modify to allow overlapping paths to be
	registered
	(struct DBusObjectSubtree): shrink this
	a lot, since we may have a lot of them
	(_dbus_object_tree_free_all_unlocked): implement
	(_dbus_object_tree_dispatch_and_unlock): implement

2003-08-29  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-internals.h: fix _DBUS_N_GLOBAL_LOCKS

2003-08-28  Havoc Pennington  <hp@pobox.com>

	purge DBusObjectID
	
	* dbus/dbus-connection.c: port to no ObjectID, create a
	DBusObjectTree, rename ObjectTree to ObjectPath in public API

	* dbus/dbus-connection.h (struct DBusObjectTreeVTable): delete 
	everything except UnregisterFunction and MessageFunction
	
	* dbus/dbus-marshal.c: port away from DBusObjectID, 
	add DBUS_TYPE_OBJECT_PATH
	
	* dbus/dbus-object-registry.[hc], dbus/dbus-object.[hc], 
	dbus/dbus-objectid.[hc]: remove these, we are moving to 
	path-based object IDs

2003-08-25  Havoc Pennington  <hp@pobox.com>

        Just noticed that dbus_message_test is hosed, I wonder when I
	broke that. I thought make check was passing earlier...
	
	* dbus/dbus-object-tree.c: add new "object tree" to match DCOP 
	container tree, will replace most of dbus-object-registry

	* dbus/dbus-string.c (_dbus_string_append_printf_valist): fix C99
	screwup

2003-08-19  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-message.c (decode_string_field): support FIELD_SENDER
	(dbus_message_is_error): fix this function

	* bus/dbus-daemon-1.1: clarify logic on when <deny>/<allow> rules
	match

	* bus/policy.c (bus_client_policy_check_can_receive): fix code to
	reflect clarified man page
	(bus_client_policy_check_can_send): ditto
	
	* bus/session.conf.in: fixup

	* bus/system.conf.in: fixup

2003-08-18  Havoc Pennington  <hp@redhat.com>

	* dbus/dbus-hash.c (_dbus_hash_table_insert_two_strings): fix

	* dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix
	dumb bug created earlier (wrong order of args to
	decode_header_data())
	
	* tools/dbus-send.c: port

	* tools/dbus-print-message.c (print_message): port

        * test/data/*messages: port all messages over
	
        * dbus/dbus-message-builder.c: support including 
	message type
	
        * bus/driver.c: port over
	
	* bus/dispatch.c: port over to new stuff

	* dbus/dbus-connection.c (_dbus_connection_new_for_transport):
	rename disconnect signal to "Disconnected"

2003-08-17  Havoc Pennington  <hp@pobox.com>

	This doesn't compile yet, but syncing up so I can hack on it from
	work. What are branches for if not broken code? ;-)
	
	* dbus/dbus-protocol.h: remove DBUS_HEADER_FIELD_NAME, add
	DBUS_HEADER_FIELD_INTERFACE, DBUS_HEADER_FIELD_MEMBER,
	DBUS_HEADER_FIELD_ERROR_NAME
	
	* dbus/dbus-hash.c: Introduce DBUS_HASH_TWO_STRINGS as hack to use
	for the interface+member pairs
	(string_hash): change to use g_str_hash algorithm
	(find_direct_function, find_string_function): refactor these to
	share most code.
	
	* dbus/dbus-message.c: port all of this over to support 
	interface/member fields instead of name field

	* dbus/dbus-object-registry.c: port over
	
	* dbus/dbus-string.c (_dbus_string_validate_interface): rename
	from _dbus_string_validate_name

	* bus/dbus-daemon-1.1: change file format for the 
	<deny>/<allow> stuff to match new message naming scheme

	* bus/policy.c: port over

	* bus/config-parser.c: parse new format
	
2003-08-16  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object-registry.c (add_and_remove_objects): remove
	broken assertion

	* glib/dbus-gproxy.c: some hacking

2003-08-15  Havoc Pennington  <hp@redhat.com>

	* dbus/dbus-pending-call.c (dbus_pending_call_block): implement

	* dbus/dbus-connection.c
	(dbus_connection_send_with_reply_and_block): factor out internals;
	change to convert any error replies to DBusError instead of 
	returning them as a message

2003-08-15  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-connection.c, 
	dbus/dbus-pending-call.c: Finish the pending call stuff

2003-08-14  Havoc Pennington  <hp@redhat.com>

	* dbus/dbus-pending-call.c: start on new object that will replace
	DBusMessageHandler and ReplyHandlerData for tracking outstanding
	replies

	* dbus/dbus-gproxy.c: start on proxy object used to communicate
	with remote interfaces

	* dbus/dbus-gidl.c: do the boring boilerplate in here
	
2003-08-12  Havoc Pennington  <hp@pobox.com>

	* bus/dispatch.c (bus_dispatch): make this return proper 
	DBusHandlerResult to avoid DBUS_ERROR_UNKNOWN_METHOD

	* dbus/dbus-errors.c (dbus_set_error): use
	_dbus_string_append_printf_valist

	* dbus/dbus-string.c (_dbus_string_append_printf_valist)
	(_dbus_string_append_printf): new

	* dbus/dbus-errors.h (DBUS_ERROR_UNKNOWN_MESSAGE): change to
	UNKNOWN_METHOD

	* dbus/dbus-connection.c (dbus_connection_dispatch): handle
	DBUS_HANDLER_RESULT_NEED_MEMORY; send default error reply if a
	message is unhandled.

2003-08-11  Havoc Pennington  <hp@pobox.com>

	* bus/test.c (client_disconnect_handler): change to return
	HANDLED (would have been REMOVE_MESSAGE)

	* dbus/dbus-object.h (enum DBusHandlerResult): rename to
	HANDLED/NOT_YET_HANDLED instead of
	REMOVE_MESSAGE/ALLOW_MORE_HANDLERS to make it clearer how it 
	should be used.

2003-08-10  Havoc Pennington  <hp@pobox.com>

	* tools/dbus-send.c (main): add --type argument, for now
	supporting only method_call and signal types.

	* tools/dbus-print-message.c: print message type

	* dbus/dbus-connection.c (_dbus_connection_new_for_transport):
	init connection->objects

	* doc/dbus-specification.sgml: fix sgml

	* bus/*.c: port over to object-instance API changes

	* test/test-service.c: ditto
	
	* dbus/dbus-message.c (dbus_message_create_header): allow #NULL
	name, we will have to fix up the rest of the code to also handle
	this
	(dbus_message_new): generic message-creation call
	(set_string_field): allow appending name field

2003-08-06  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object-registry.c: implement signal connection 
	and dispatch

	* dbus/dbus-connection.c (_dbus_connection_unref_unlocked): new

	* dbus/dbus-internals.c (_dbus_memdup): new function

2003-08-02  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-message.c (dbus_message_get_no_reply)
	(dbus_message_set_no_reply): add these and remove
	set_is_error/get_is_error

	* dbus/dbus-protocol.h, doc/dbus-specification.sgml: 
	remove the ERROR flag, since there's now an ERROR type

2003-08-01  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object-registry.c (_dbus_object_registry_handle_and_unlock):
	implement

	* dbus/dbus-message.c (dbus_message_get_type): new function

	* doc/dbus-specification.sgml: add "type" byte to messages

2003-08-01  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-protocol.h (DBUS_MESSAGE_TYPE_*): introduce
	a message type enum to distinguish kinds of message
	(DBUS_HEADER_FLAG_NO_REPLY_EXPECTED): flag for a message 
	that need not be replied to

2003-08-01  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-marshal.c: adapt to DBusObjectID changes
	(unpack_8_octets): fix no-64-bit-int bug

	* dbus/dbus-object-registry.c (validate_id): validate the 
	connection ID bits, not just the instance ID.

	* dbus/dbus-connection.c (_dbus_connection_init_id): initialize
	the connection-global 33 bits of the object ID

	* dbus/dbus-object-registry.c (info_from_entry): fill in 
	object ID in the new way

	* dbus/dbus-objectid.h: rather than high/low bits, specifically 
	define server/client/instance bits.

2003-07-30  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-connection.c (dbus_connection_register_object): fix
	build

2003-07-13  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object.h (struct DBusObjectVTable): add padding
	fields to DBusObjectVTable and DBusObjectInfo

2003-07-12  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object-registry.c: implement unit test,
	fix bugs discovered in process

	* dbus/dbus-connection.c: remove handler_table and
	register_handler(), add DBusObjectRegistry usage

	* dbus/dbus-objectid.c (dbus_object_id_is_null)
	(dbus_object_id_set_null): new functions

2003-07-08  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object.c: implement some of this

	* dbus/dbus-object-registry.c
	(_dbus_object_registry_add_and_unlock): fill in the object_id out
	param
	(_dbus_object_registry_new): handle OOM

2003-07-08  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-object.h: sketch out an API for registering objects
	with a connection, that allows us to use as little as 24 bytes
	per object and lets application code represent an object in 
	any conceivable way.

	* dbus/dbus-object-registry.c: implement the hard bits of the
	DBusConnection aspect of object API. Not yet wired up.
	
2003-07-06  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-marshal.c (_dbus_marshal_set_object_id): new function
	(_dbus_marshal_object_id): new
	(_dbus_demarshal_object_id): new
	(_dbus_marshal_get_arg_end_pos): support object ID type, and
	consolidate identical switch cases. Don't conditionalize handling
	of DBUS_TYPE_UINT64, need to handle the type always.
	(_dbus_marshal_validate_arg): consolidate identical cases, and
	handle DBUS_TYPE_OBJECT_ID

	* dbus/dbus-objectid.c: new file with DBusObjectID data type.

	* dbus/dbus-protocol.h: add DBUS_TYPE_OBJECT_ID

2003-09-28  Havoc Pennington  <hp@pobox.com>

	* real 0.13 release

2003-09-28  Havoc Pennington  <hp@pobox.com>

	* doc/Makefile.am (dbus-specification.html): testing a funky hack
	to work with Debian db2html

2003-09-28  Havoc Pennington  <hp@pobox.com>

	* configure.in: 0.13

	* doc/Makefile.am (dbus-test-plan.html): accept nonexistence of
	stylesheet-images for benefit of Debian
	
	Change back to using filesystem-linked sockets for the system
	bus, so only root can create the default system bus address.
	
	* bus/system.conf.in: change to use
	DBUS_SYSTEM_BUS_DEFAULT_ADDRESS

	* dbus/Makefile.am (INCLUDES): remove DBUS_SYSTEM_BUS_PATH define
	from here.

	* configure.in: define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS
	here, and AC_DEFINE DBUS_SYSTEM_PATH

2003-08-09  Anders Carlsson  <andersca@codefactory.se>

	* doc/TODO:
	* doc/busconfig.dtd:
	Add busconfig DTD.
	
2003-08-09  Anders Carlsson  <andersca@codefactory.se>

	* doc/dbus-specification.sgml:
	Add activation reply values.
	
2003-08-05  Havoc Pennington  <hp@redhat.com>

	* configure.in: 0.12

2003-08-05  Anders Carlsson  <andersca@codefactory.se>

	* glib/dbus-gmain.c: (watch_fd_new), (watch_fd_ref),
	(watch_fd_unref), (dbus_gsource_check), (dbus_gsource_dispatch),
	(add_watch), (remove_watch), (create_source):
	Refcount fds, fixes some reentrancy issues.
	
2003-07-30  Havoc Pennington  <hp@redhat.com>

	* dbus/dbus-bus.c (init_connections_unlocked): fix default system
	bus address to be abstract if we have abstract sockets

	* NEWS: update

2003-07-28  Havoc Pennington  <hp@redhat.com>

	* bus/messagebus.in: fix to avoid processname/servicename 
	confusion, from Michael Kearey
	https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=100965
	
2003-07-23  Havoc Pennington  <hp@pobox.com>

	* dbus/dbus-message.c (dbus_message_iter_get_named): 
	fix from Andy Hanton to remove broken "+1"

2003-07-16  Havoc Pennington  <hp@pobox.com>

	* tools/dbus-launch.c (babysit): close stdout/stderr in the
	babysitter process, as suggested by Thomas Leonard, so 
	an "eval `dbus-launch --exit-with-session`" will actually 
	return

2003-07-16  Havoc Pennington  <hp@pobox.com>

	* configure.in: print out EXPANDED_* variables in the summary at
	the end; clean up the code that computes EXPANDED_ variables and
	get the ones using exec_prefix right. Should make things work
	when you build without --prefix








Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/dbus/Makefile.am,v
retrieving revision 1.56
retrieving revision 1.57
diff -u -d -r1.56 -r1.57
--- Makefile.am	29 Sep 2003 01:43:52 -0000	1.56
+++ Makefile.am	30 Sep 2003 02:32:52 -0000	1.57
@@ -15,7 +15,7 @@
 	dbus-macros.h				\
 	dbus-memory.h				\
 	dbus-message.h				\
-	dbus-message-handler.h			\
+	dbus-pending-call.h			\
 	dbus-protocol.h				\
 	dbus-server.h				\
 	dbus-threads.h				\
@@ -39,8 +39,10 @@
 	dbus-keyring.c				\
 	dbus-keyring.h				\
 	dbus-message.c				\
-	dbus-message-handler.c			\
 	dbus-message-internal.h			\
+	dbus-object-tree.c			\
+	dbus-object-tree.h			\
+	dbus-pending-call.c			\
 	dbus-resources.c			\
 	dbus-resources.h			\
 	dbus-server.c				\

Index: dbus-address.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-address.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- dbus-address.c	3 May 2003 23:20:34 -0000	1.10
+++ dbus-address.c	30 Sep 2003 02:32:52 -0000	1.11
@@ -25,22 +25,29 @@
 #include "dbus-address.h"
 #include "dbus-internals.h"
 #include "dbus-list.h"
+#include "dbus-string.h"
 
 /**
- * @defgroup DBusAddress Address parsing
- * @ingroup  DBus
- * @brief Parsing addresses of D-BUS servers.
+ * @defgroup DBusAddressInternals Address parsing
+ * @ingroup  DBusInternals
+ * @brief Implementation of parsing addresses of D-BUS servers.
  *
  * @{
  */
+
+/**
+ * Internals of DBusAddressEntry 
+ */
 struct DBusAddressEntry
 {
-  DBusString method;
+  DBusString method; /**< The address type (unix, tcp, etc.) */
 
-  DBusList *keys;
-  DBusList *values;
+  DBusList *keys;    /**< List of keys */
+  DBusList *values;  /**< List of values */
 };
 
+/** @} */ /* End of internals */
+
 static void
 dbus_address_entry_free (DBusAddressEntry *entry)
 {
@@ -71,6 +78,13 @@
   dbus_free (entry);
 }
 
+/**
+ * @defgroup DBusAddress Address parsing
+ * @ingroup  DBus
+ * @brief Parsing addresses of D-BUS servers.
+ *
+ * @{
+ */
 
 /**
  * Frees a #NULL-terminated array of address entries.
@@ -371,7 +385,7 @@
 }
 
 
-/** @} */
+/** @} */ /* End of public API */
 
 #ifdef DBUS_BUILD_TESTS
 #include "dbus-test.h"

Index: dbus-auth.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-auth.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- dbus-auth.c	11 May 2003 07:59:08 -0000	1.28
+++ dbus-auth.c	30 Sep 2003 02:32:52 -0000	1.29
@@ -28,8 +28,6 @@
 #include "dbus-sha.h"
 #include "dbus-userdb.h"
 
-/* See doc/dbus-sasl-profile.txt */
-
 /**
  * @defgroup DBusAuth Authentication
  * @ingroup  DBusInternals
@@ -75,10 +73,13 @@
                                                         const DBusString *command,
                                                         const DBusString *args);
 
+/**
+ * Handler for a given auth protocol command
+ */
 typedef struct
 {
-  const char *command;
-  DBusProcessAuthCommandFunction func;
+  const char *command; /**< Name of the command */
+  DBusProcessAuthCommandFunction func; /**< Function to handle the command */
 } DBusAuthCommandHandler;
 
 /**
@@ -113,18 +114,21 @@
  */
 typedef void        (* DBusAuthShutdownFunction) (DBusAuth       *auth);
 
+/**
+ * Virtual table representing a particular auth mechanism.
+ */
 typedef struct
 {
-  const char *mechanism;
-  DBusAuthDataFunction server_data_func;
-  DBusAuthEncodeFunction server_encode_func;
-  DBusAuthDecodeFunction server_decode_func;
-  DBusAuthShutdownFunction server_shutdown_func;
-  DBusInitialResponseFunction client_initial_response_func;
-  DBusAuthDataFunction client_data_func;
-  DBusAuthEncodeFunction client_encode_func;
-  DBusAuthDecodeFunction client_decode_func;
-  DBusAuthShutdownFunction client_shutdown_func;
+  const char *mechanism; /**< Name of the mechanism */
+  DBusAuthDataFunction server_data_func; /**< Function on server side for DATA */
+  DBusAuthEncodeFunction server_encode_func; /**< Function on server side to encode */
+  DBusAuthDecodeFunction server_decode_func; /**< Function on server side to decode */
+  DBusAuthShutdownFunction server_shutdown_func; /**< Function on server side to shut down */
+  DBusInitialResponseFunction client_initial_response_func; /**< Function on client side to handle initial response */
+  DBusAuthDataFunction client_data_func; /**< Function on client side for DATA */
+  DBusAuthEncodeFunction client_encode_func; /**< Function on client side for encode */
+  DBusAuthDecodeFunction client_decode_func; /**< Function on client side for decode */
+  DBusAuthShutdownFunction client_shutdown_func; /**< Function on client side for shutdown */
 } DBusAuthMechanismHandler;
 
 /**
@@ -174,17 +178,23 @@
   unsigned int buffer_outstanding : 1; /**< Buffer is "checked out" for reading data into */
 };
 
+/**
+ * "Subclass" of DBusAuth for client side
+ */
 typedef struct
 {
-  DBusAuth base;
+  DBusAuth base;    /**< Parent class */
 
   DBusList *mechs_to_try; /**< Mechanisms we got from the server that we're going to try using */
   
 } DBusAuthClient;
 
+/**
+ * "Subclass" of DBusAuth for server side.
+ */
 typedef struct
 {
-  DBusAuth base;
+  DBusAuth base;    /**< Parent class */
 
   int failures;     /**< Number of times client has been rejected */
   int max_failures; /**< Number of times we reject before disconnect */
@@ -2370,7 +2380,7 @@
       goto failed;
     }
 
-  printf ("Testing:\n");
+  printf ("Testing %s:\n", subdir);
   
  next:
   while (_dbus_directory_get_next_file (dir, &filename, &error))

Index: dbus-bus.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-bus.c,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- dbus-bus.c	29 Sep 2003 01:43:52 -0000	1.24
+++ dbus-bus.c	30 Sep 2003 02:32:52 -0000	1.25
@@ -25,6 +25,7 @@
 #include "dbus-bus.h"
 #include "dbus-protocol.h"
 #include "dbus-internals.h"
+#include "dbus-message.h"
 #include <string.h>
 
 /**
@@ -52,6 +53,10 @@
  * Block of message-bus-related data we attach to each
  * #DBusConnection used with these convenience functions.
  *
+ *
+ * @todo get rid of most of these; they should be done
+ * with DBusGProxy and the Qt equivalent, i.e. the same
+ * way any other interface would be used.
  */
 typedef struct
 {
@@ -338,6 +343,12 @@
       _DBUS_UNLOCK (bus);
       return NULL;
     }
+
+  /* By default we're bound to the lifecycle of
+   * the message bus.
+   */
+  dbus_connection_set_exit_on_disconnect (connection,
+                                          TRUE);
   
   if (!dbus_bus_register (connection, error))
     {
@@ -403,9 +414,10 @@
       return TRUE;
     }
   
-  message = dbus_message_new (DBUS_MESSAGE_HELLO,
-                              DBUS_SERVICE_DBUS);
-			      
+  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+                                          "Hello"); 
 
   if (!message)
     {
@@ -521,9 +533,10 @@
   _dbus_return_val_if_fail (service_name != NULL, 0);
   _dbus_return_val_if_error_is_set (error, 0);
   
-  message = dbus_message_new (DBUS_MESSAGE_ACQUIRE_SERVICE,
-                              DBUS_SERVICE_DBUS);
-
+  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+                                          "AcquireService");
 
   if (message == NULL)
     {
@@ -595,8 +608,10 @@
   _dbus_return_val_if_fail (service_name != NULL, FALSE);
   _dbus_return_val_if_error_is_set (error, FALSE);
   
-  message = dbus_message_new (DBUS_MESSAGE_SERVICE_EXISTS,
-                              DBUS_SERVICE_DBUS);
+  message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+                                          DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+                                          DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+                                          "ServiceExists");
   if (message == NULL)
     {
       _DBUS_SET_OOM (error);
@@ -657,8 +672,10 @@
   DBusMessage *msg;
   DBusMessage *reply;
 
-  msg = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE,
-      			  DBUS_SERVICE_DBUS);
+  msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+                                      DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+                                      DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+                                      "ActivateService");
 
   if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name,
 			  	 DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID))
@@ -669,7 +686,7 @@
     }
 
   reply = dbus_connection_send_with_reply_and_block (connection, msg,
-		  					 -1, error);
+                                                     -1, error);
   dbus_message_unref (msg);
 
   if (reply == NULL)
@@ -698,5 +715,125 @@
   return TRUE;
 }
 
+static void
+send_no_return_values (DBusConnection *connection,
+                       DBusMessage    *msg,
+                       DBusError      *error)
+{
+  if (error)
+    {
+      /* Block to check success codepath */
+      DBusMessage *reply;
+      
+      reply = dbus_connection_send_with_reply_and_block (connection, msg,
+                                                         -1, error);
+      
+      if (reply == NULL)
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          return;
+        }
+
+      if (dbus_set_error_from_message (error, reply))
+        {
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          dbus_message_unref (reply);
+          return;
+        }
+
+      dbus_message_unref (reply);
+    }
+  else
+    {
+      /* Silently-fail nonblocking codepath */
+      if (!dbus_connection_send (connection, msg, NULL))
+        return;
+    }
+}
+
+/**
+ * Adds a match rule to match messages going through the message bus.
+ * The "rule" argument is the string form of a match rule.
+ *
+ * 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.
+ *
+ * If you pass non-#NULL for the error this function will
+ * block until it gets a reply.
+ *
+ * Normal API conventions would have the function return
+ * a boolean value indicating whether the error was set,
+ * but that would require blocking always to determine
+ * the return value.
+ * 
+ * @param connection connection to the message bus
+ * @param rule textual form of match rule
+ * @param error location to store any errors
+ */
+void
+dbus_bus_add_match (DBusConnection *connection,
+                    const char     *rule,
+                    DBusError      *error)
+{
+  DBusMessage *msg;
+
+  msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+                                      DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+                                      DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+                                      "AddMatch");
+
+  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule,
+                                 DBUS_TYPE_INVALID))
+    {
+      dbus_message_unref (msg);
+      _DBUS_SET_OOM (error);
+      return;
+    }
+
+  send_no_return_values (connection, msg, error);
+
+  dbus_message_unref (msg);
+}
+
+/**
+ * Removes a previously-added match rule "by value" (the most
+ * recently-added identical rule gets removed).  The "rule" argument
+ * is the string form of a match rule.
+ *
+ * If you pass #NULL for the error, this function will not
+ * block; otherwise it will. See detailed explanation in
+ * docs for dbus_bus_add_match().
+ * 
+ * @param connection connection to the message bus
+ * @param rule textual form of match rule
+ * @param error location to store any errors
+ */
+void
+dbus_bus_remove_match (DBusConnection *connection,
+                       const char     *rule,
+                       DBusError      *error)
+{
+  DBusMessage *msg;
+
+  msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+                                      DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+                                      DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+                                      "RemoveMatch");
+
+  if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule,
+                                 DBUS_TYPE_INVALID))
+    {
+      dbus_message_unref (msg);
+      _DBUS_SET_OOM (error);
+      return;
+    }
+
+  send_no_return_values (connection, msg, error);
+
+  dbus_message_unref (msg);
+}
 
 /** @} */

Index: dbus-bus.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-bus.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- dbus-bus.h	14 May 2003 02:40:41 -0000	1.7
+++ dbus-bus.h	30 Sep 2003 02:32:52 -0000	1.8
@@ -59,6 +59,13 @@
 					   dbus_uint32_t  *reply,
 					   DBusError      *error);
 
+void            dbus_bus_add_match        (DBusConnection *connection,
+                                           const char     *rule,
+                                           DBusError      *error);
+void            dbus_bus_remove_match     (DBusConnection *connection,
+                                           const char     *rule,
+                                           DBusError      *error);
+
 DBUS_END_DECLS;
 
 #endif /* DBUS_BUS_H */

Index: dbus-connection-internal.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-connection-internal.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- dbus-connection-internal.h	18 Apr 2003 04:18:57 -0000	1.12
+++ dbus-connection-internal.h	30 Sep 2003 02:32:52 -0000	1.13
@@ -29,6 +29,8 @@
 #include <dbus/dbus-transport.h>
 #include <dbus/dbus-resources.h>
 #include <dbus/dbus-list.h>
+#include <dbus/dbus-timeout.h>
+#include <dbus/dbus-dataslot.h>
 
 DBUS_BEGIN_DECLS;
 
@@ -39,9 +41,13 @@
   DBUS_ITERATION_BLOCK      = 1 << 2  /**< Block if nothing to do. */
 } DBusIterationFlags;
 
+/** default timeout value when waiting for a message reply */
+#define _DBUS_DEFAULT_TIMEOUT_VALUE (15 * 1000)
+
 void              _dbus_connection_lock                        (DBusConnection     *connection);
 void              _dbus_connection_unlock                      (DBusConnection     *connection);
 void              _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,
@@ -72,16 +78,52 @@
                                                                 unsigned int        flags,
                                                                 int                 timeout_milliseconds);
 void              _dbus_connection_notify_disconnected         (DBusConnection     *connection);
-void              _dbus_connection_handler_destroyed_locked    (DBusConnection     *connection,
-                                                                DBusMessageHandler *handler);
-dbus_bool_t       _dbus_message_handler_add_connection         (DBusMessageHandler *handler,
-                                                                DBusConnection     *connection);
-void              _dbus_message_handler_remove_connection      (DBusMessageHandler *handler,
-                                                                DBusConnection     *connection);
-DBusHandlerResult _dbus_message_handler_handle_message         (DBusMessageHandler *handler,
-                                                                DBusConnection     *connection,
+
+DBusPendingCall*  _dbus_pending_call_new                       (DBusConnection     *connection,
+                                                                int                 timeout_milliseconds,
+                                                                DBusTimeoutHandler  timeout_handler);
+void              _dbus_pending_call_notify                    (DBusPendingCall    *pending);
+void              _dbus_connection_remove_pending_call         (DBusConnection     *connection,
+                                                                DBusPendingCall    *pending);
+DBusMessage*      _dbus_connection_block_for_reply             (DBusConnection     *connection,
+                                                                dbus_uint32_t       client_serial,
+                                                                int                 timeout_milliseconds);
+void              _dbus_pending_call_complete_and_unlock       (DBusPendingCall    *pending,
                                                                 DBusMessage        *message);
 
+
+/**
+ * @addtogroup DBusPendingCallInternals DBusPendingCall implementation details
+ * @{
+ */
+/**
+ * @brief Internals of DBusPendingCall
+ *
+ * Object representing a reply message that we're waiting for.
+ */
+struct DBusPendingCall
+{
+  DBusAtomic refcount;                            /**< reference count */
+
+  DBusDataSlotList slot_list;                     /**< Data stored by allocated integer ID */
+  
+  DBusPendingCallNotifyFunction function;         /**< Notifier when reply arrives. */
+
+  DBusConnection *connection;                     /**< Connections we're associated with */
+  DBusMessage *reply;                             /**< Reply (after we've received it) */
+  DBusTimeout *timeout;                           /**< Timeout */
+
+  DBusList *timeout_link;                         /**< Preallocated timeout response */
+  
+  dbus_uint32_t reply_serial;                     /**< Expected serial of reply */
+
+  unsigned int completed : 1;                     /**< TRUE if completed */
+  unsigned int timeout_added : 1;                 /**< Have added the timeout */
+};
+
+/** @} End of DBusPendingCallInternals */
+
+
 DBUS_END_DECLS;
 
 #endif /* DBUS_CONNECTION_INTERNAL_H */

Index: dbus-connection.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-connection.c,v
retrieving revision 1.69
retrieving revision 1.70
diff -u -d -r1.69 -r1.70
--- dbus-connection.c	22 Jun 2003 19:39:47 -0000	1.69
+++ dbus-connection.c	30 Sep 2003 02:32:52 -0000	1.70
@@ -31,10 +31,12 @@
 #include "dbus-list.h"
 #include "dbus-hash.h"
 #include "dbus-message-internal.h"
-#include "dbus-message-handler.h"
 #include "dbus-threads.h"
 #include "dbus-protocol.h"
 #include "dbus-dataslot.h"
+#include "dbus-string.h"
+#include "dbus-pending-call.h"
+#include "dbus-object-tree.h"
 
 #if 0
 #define CONNECTION_LOCK(connection)   do {                      \
@@ -77,7 +79,7 @@
  * you to set a function to be used to monitor the dispatch status.
  *
  * If you're using GLib or Qt add-on libraries for D-BUS, there are
- * special convenience functions in those libraries that hide
+ * special convenience APIs in those libraries that hide
  * all the details of dispatch and watch/timeout monitoring.
  * For example, dbus_connection_setup_with_g_main().
  *
@@ -122,8 +124,32 @@
  * @{
  */
 
-/** default timeout value when waiting for a message reply */
-#define DEFAULT_TIMEOUT_VALUE (15 * 1000)
+/**
+ * Internal struct representing a message filter function 
+ */
+typedef struct DBusMessageFilter DBusMessageFilter;
+
+/**
+ * Internal struct representing a message filter function 
+ */
+struct DBusMessageFilter
+{
+  DBusAtomic refcount; /**< Reference count */
+  DBusHandleMessageFunction function; /**< Function to call to filter */
+  void *user_data; /**< User data for the function */
+  DBusFreeFunction free_user_data_function; /**< Function to free the user data */
+};
+
+
+/**
+ * Internals of DBusPreallocatedSend
+ */
+struct DBusPreallocatedSend
+{
+  DBusConnection *connection; /**< Connection we'd send the message to */
+  DBusList *queue_link;       /**< Preallocated link in the queue */
+  DBusList *counter_link;     /**< Preallocated link in the resource counter */
+};
 
 static dbus_bool_t _dbus_modify_sigpipe = TRUE;
 
@@ -157,12 +183,11 @@
   DBusWatchList *watches;      /**< Stores active watches. */
   DBusTimeoutList *timeouts;   /**< Stores active timeouts. */
   
-  DBusHashTable *handler_table; /**< Table of registered DBusMessageHandler */
   DBusList *filter_list;        /**< List of filters. */
 
   DBusDataSlotList slot_list;   /**< Data stored by allocated integer ID */
 
-  DBusHashTable *pending_replies;  /**< Hash of message serials and their message handlers. */  
+  DBusHashTable *pending_replies;  /**< Hash of message serials to #DBusPendingCall. */  
   
   dbus_uint32_t client_serial;       /**< Client serial. Increments each time a message is sent  */
   DBusList *disconnect_message_link; /**< Preallocated list node for queueing the disconnection message */
@@ -180,30 +205,38 @@
   DBusList *link_cache; /**< A cache of linked list links to prevent contention
                          *   for the global linked list mempool lock
                          */
-};
-
-typedef struct
-{
-  DBusConnection *connection;
-  DBusMessageHandler *handler;
-  DBusTimeout *timeout;
-  int serial;
-
-  DBusList *timeout_link; /* Preallocated timeout response */
-  
-  dbus_bool_t timeout_added;
-  dbus_bool_t connection_added;
-} ReplyHandlerData;
+  DBusObjectTree *objects; /**< Object path handlers registered with this connection */
 
-static void reply_handler_data_free (ReplyHandlerData *data);
+  unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */
+};
 
 static void               _dbus_connection_remove_timeout_locked             (DBusConnection     *connection,
                                                                               DBusTimeout        *timeout);
 static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked      (DBusConnection     *connection);
 static void               _dbus_connection_update_dispatch_status_and_unlock (DBusConnection     *connection,
                                                                               DBusDispatchStatus  new_status);
+static void               _dbus_connection_last_unref                        (DBusConnection     *connection);
 
+static void
+_dbus_message_filter_ref (DBusMessageFilter *filter)
+{
+  _dbus_assert (filter->refcount.value > 0);
+  _dbus_atomic_inc (&filter->refcount);
+}
 
+static void
+_dbus_message_filter_unref (DBusMessageFilter *filter)
+{
+  _dbus_assert (filter->refcount.value > 0);
+
+  if (_dbus_atomic_dec (&filter->refcount) == 1)
+    {
+      if (filter->free_user_data_function)
+        (* filter->free_user_data_function) (filter->user_data);
+      
+      dbus_free (filter);
+    }
+}
 
 /**
  * Acquires the connection lock.
@@ -281,7 +314,7 @@
 _dbus_connection_queue_received_message_link (DBusConnection  *connection,
                                               DBusList        *link)
 {
-  ReplyHandlerData *reply_handler_data;
+  DBusPendingCall *pending;
   dbus_int32_t reply_serial;
   DBusMessage *message;
   
@@ -295,14 +328,15 @@
   reply_serial = dbus_message_get_reply_serial (message);
   if (reply_serial != -1)
     {
-      reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies,
-							reply_serial);
-      if (reply_handler_data != NULL)
+      pending = _dbus_hash_table_lookup_int (connection->pending_replies,
+                                             reply_serial);
+      if (pending != NULL)
 	{
-	  if (reply_handler_data->timeout_added)
+	  if (pending->timeout_added)
 	    _dbus_connection_remove_timeout_locked (connection,
-						    reply_handler_data->timeout);
-	  reply_handler_data->timeout_added = FALSE;
+                                                    pending->timeout);
+
+	  pending->timeout_added = FALSE;
 	}
     }
   
@@ -310,9 +344,11 @@
 
   _dbus_connection_wakeup_mainloop (connection);
   
-  _dbus_assert (dbus_message_get_name (message) != NULL);
   _dbus_verbose ("Message %p (%s) added to incoming queue %p, %d incoming\n",
-                 message, dbus_message_get_name (message),
+                 message,
+                 dbus_message_get_interface (message) ?
+                 dbus_message_get_interface (message) :
+                 "no interface",
                  connection,
                  connection->n_incoming);
 }
@@ -395,7 +431,10 @@
   connection->n_outgoing -= 1;
 
   _dbus_verbose ("Message %p (%s) removed from outgoing queue %p, %d left to send\n",
-                 message, dbus_message_get_name (message),
+                 message,
+                 dbus_message_get_interface (message) ?
+                 dbus_message_get_interface (message) :
+                 "no interface",
                  connection, connection->n_outgoing);
 
   /* Save this link in the link cache also */
@@ -553,6 +592,118 @@
     }
 }
 
+static dbus_bool_t
+_dbus_connection_attach_pending_call_unlocked (DBusConnection  *connection,
+                                               DBusPendingCall *pending)
+{
+  _dbus_assert (pending->reply_serial != 0);
+
+  if (!_dbus_connection_add_timeout (connection, pending->timeout))
+    return FALSE;
+  
+  if (!_dbus_hash_table_insert_int (connection->pending_replies,
+                                    pending->reply_serial,
+                                    pending))
+    {
+      _dbus_connection_remove_timeout (connection, pending->timeout);
+      return FALSE;
+    }
+  
+  pending->timeout_added = TRUE;
+  pending->connection = connection;
+
+  dbus_pending_call_ref (pending);
+  
+  return TRUE;
+}
+
+static void
+free_pending_call_on_hash_removal (void *data)
+{
+  DBusPendingCall *pending;
+  
+  if (data == NULL)
+    return;
+
+  pending = data;
+
+  if (pending->connection)
+    {
+      if (pending->timeout_added)
+        {
+          _dbus_connection_remove_timeout (pending->connection,
+                                           pending->timeout);
+          pending->timeout_added = FALSE;
+        }
+
+      pending->connection = NULL;
+      
+      dbus_pending_call_unref (pending);
+    }
+}
+
+static void
+_dbus_connection_detach_pending_call_and_unlock (DBusConnection  *connection,
+                                                 DBusPendingCall *pending)
+{
+  /* The idea here is to avoid finalizing the pending call
+   * with the lock held, since there's a destroy notifier
+   * in pending call that goes out to application code.
+   */
+  dbus_pending_call_ref (pending);
+  _dbus_hash_table_remove_int (connection->pending_replies,
+                               pending->reply_serial);
+  CONNECTION_UNLOCK (connection);
+  dbus_pending_call_unref (pending);
+}
+
+/**
+ * Removes a pending call from the connection, such that
+ * the pending reply will be ignored. May drop the last
+ * reference to the pending call.
+ *
+ * @param connection the connection
+ * @param pending the pending call
+ */
+void
+_dbus_connection_remove_pending_call (DBusConnection  *connection,
+                                      DBusPendingCall *pending)
+{
+  CONNECTION_LOCK (connection);
+  _dbus_connection_detach_pending_call_and_unlock (connection, pending);
+}
+
+/**
+ * Completes a pending call with the given message,
+ * or if the message is #NULL, by timing out the pending call.
+ * 
+ * @param pending the pending call
+ * @param message the message to complete the call with, or #NULL
+ *  to time out the call
+ */
+void
+_dbus_pending_call_complete_and_unlock (DBusPendingCall *pending,
+                                        DBusMessage     *message)
+{
+  if (message == NULL)
+    {
+      message = pending->timeout_link->data;
+      _dbus_list_clear (&pending->timeout_link);
+    }
+
+  _dbus_verbose ("  handing message %p to pending call\n", message);
+  
+  _dbus_assert (pending->reply == NULL);
+  pending->reply = message;
+  dbus_message_ref (pending->reply);
+  
+  dbus_pending_call_ref (pending); /* in case there's no app with a ref held */
+  _dbus_connection_detach_pending_call_and_unlock (pending->connection, pending);
+  
+  /* Must be called unlocked since it invokes app callback */
+  _dbus_pending_call_notify (pending);
+  dbus_pending_call_unref (pending);
+}
 
 /**
  * Acquire the transporter I/O path. This must be done before
@@ -664,7 +815,7 @@
   DBusConnection *connection;
   DBusWatchList *watch_list;
   DBusTimeoutList *timeout_list;
-  DBusHashTable *handler_table, *pending_replies;
+  DBusHashTable *pending_replies;
   DBusMutex *mutex;
   DBusCondVar *message_returned_cond;
   DBusCondVar *dispatch_cond;
@@ -672,10 +823,10 @@
   DBusList *disconnect_link;
   DBusMessage *disconnect_message;
   DBusCounter *outgoing_counter;
+  DBusObjectTree *objects;
   
   watch_list = NULL;
   connection = NULL;
-  handler_table = NULL;
   pending_replies = NULL;
   timeout_list = NULL;
   mutex = NULL;
@@ -685,6 +836,7 @@
   disconnect_link = NULL;
   disconnect_message = NULL;
   outgoing_counter = NULL;
+  objects = NULL;
   
   watch_list = _dbus_watch_list_new ();
   if (watch_list == NULL)
@@ -692,17 +844,12 @@
 
   timeout_list = _dbus_timeout_list_new ();
   if (timeout_list == NULL)
-    goto error;
-  
-  handler_table =
-    _dbus_hash_table_new (DBUS_HASH_STRING,
-                          dbus_free, NULL);
-  if (handler_table == NULL)
-    goto error;
+    goto error;  
 
   pending_replies =
     _dbus_hash_table_new (DBUS_HASH_INT,
-			  NULL, (DBusFreeFunction)reply_handler_data_free);
+			  NULL,
+                          (DBusFreeFunction)free_pending_call_on_hash_removal);
   if (pending_replies == NULL)
     goto error;
   
@@ -726,7 +873,10 @@
   if (io_path_cond == NULL)
     goto error;
 
-  disconnect_message = dbus_message_new (DBUS_MESSAGE_LOCAL_DISCONNECT, NULL);
+  disconnect_message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_LOCAL,
+                                                DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+                                                "Disconnected");
+  
   if (disconnect_message == NULL)
     goto error;
 
@@ -737,6 +887,10 @@
   outgoing_counter = _dbus_counter_new ();
   if (outgoing_counter == NULL)
     goto error;
+
+  objects = _dbus_object_tree_new (connection);
+  if (objects == NULL)
+    goto error;
   
   if (_dbus_modify_sigpipe)
     _dbus_disable_sigpipe ();
@@ -749,11 +903,12 @@
   connection->transport = transport;
   connection->watches = watch_list;
   connection->timeouts = timeout_list;
-  connection->handler_table = handler_table;
   connection->pending_replies = pending_replies;
   connection->outgoing_counter = outgoing_counter;
   connection->filter_list = NULL;
   connection->last_dispatch_status = DBUS_DISPATCH_COMPLETE; /* so we're notified first time there's data */
+  connection->objects = objects;
+  connection->exit_on_disconnect = FALSE;
   
   _dbus_data_slot_list_init (&connection->slot_list);
 
@@ -790,9 +945,6 @@
   if (connection != NULL)
     dbus_free (connection);
 
-  if (handler_table)
-    _dbus_hash_table_unref (handler_table);
-
   if (pending_replies)
     _dbus_hash_table_unref (pending_replies);
   
@@ -804,6 +956,9 @@
 
   if (outgoing_counter)
     _dbus_counter_unref (outgoing_counter);
+
+  if (objects)
+    _dbus_object_tree_unref (objects);
   
   return NULL;
 }
@@ -825,6 +980,39 @@
 #endif
 }
 
+/**
+ * Decrements the reference count of a DBusConnection.
+ * Requires that the caller already holds the connection lock.
+ *
+ * @param connection the connection.
+ */
+void
+_dbus_connection_unref_unlocked (DBusConnection *connection)
+{
+  dbus_bool_t last_unref;
+
+  _dbus_return_if_fail (connection != NULL);
+
+  /* The connection lock is better than the global
+   * lock in the atomic increment fallback
+   */
+  
+#ifdef DBUS_HAVE_ATOMIC_INT
+  last_unref = (_dbus_atomic_dec (&connection->refcount) == 1);
+#else  
+  _dbus_assert (connection->refcount.value > 0);
+
+  connection->refcount.value -= 1;
+  last_unref = (connection->refcount.value == 0);
+#if 0
+  printf ("unref_unlocked() connection %p count = %d\n", connection, connection->refcount.value);
+#endif
+#endif
+  
+  if (last_unref)
+    _dbus_connection_last_unref (connection);
+}
+
 static dbus_uint32_t
 _dbus_connection_get_next_client_serial (DBusConnection *connection)
 {
@@ -839,50 +1027,6 @@
 }
 
 /**
- * Used to notify a connection when a DBusMessageHandler is
- * destroyed, so the connection can drop any reference
- * to the handler. This is a private function, but still
- * takes the connection lock. Don't call it with the lock held.
- *
- * @todo needs to check in pending_replies too.
- * 
- * @param connection the connection
- * @param handler the handler
- */
-void
-_dbus_connection_handler_destroyed_locked (DBusConnection     *connection,
-					   DBusMessageHandler *handler)
-{
-  DBusHashIter iter;
-  DBusList *link;
-
-  CONNECTION_LOCK (connection);
-  
-  _dbus_hash_iter_init (connection->handler_table, &iter);
-  while (_dbus_hash_iter_next (&iter))
-    {
-      DBusMessageHandler *h = _dbus_hash_iter_get_value (&iter);
-
-      if (h == handler)
-        _dbus_hash_iter_remove_entry (&iter);
-    }
-
-  link = _dbus_list_get_first_link (&connection->filter_list);
-  while (link != NULL)
-    {
-      DBusMessageHandler *h = link->data;
-      DBusList *next = _dbus_list_get_next_link (&connection->filter_list, link);
-
-      if (h == handler)
-        _dbus_list_remove_link (&connection->filter_list,
-                                link);
-      
-      link = next;
-    }
-  CONNECTION_UNLOCK (connection);
-}
-
-/**
  * A callback for use with dbus_watch_new() to create a DBusWatch.
  * 
  * @todo This is basically a hack - we could delete _dbus_transport_handle_watch()
@@ -1019,7 +1163,6 @@
 static void
 _dbus_connection_last_unref (DBusConnection *connection)
 {
-  DBusHashIter iter;
   DBusList *link;
 
   _dbus_verbose ("Finalizing connection %p\n", connection);
@@ -1032,6 +1175,8 @@
   _dbus_assert (!_dbus_transport_get_is_connected (connection->transport));
 
   /* ---- We're going to call various application callbacks here, hope it doesn't break anything... */
+  _dbus_object_tree_free_all_unlocked (connection->objects);
+  
   dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL);
   dbus_connection_set_wakeup_main_function (connection, NULL, NULL, NULL);
   dbus_connection_set_unix_user_function (connection, NULL, NULL, NULL);
@@ -1043,29 +1188,24 @@
   connection->timeouts = NULL;
 
   _dbus_data_slot_list_free (&connection->slot_list);
-  /* ---- Done with stuff that invokes application callbacks */
-  
-  _dbus_hash_iter_init (connection->handler_table, &iter);
-  while (_dbus_hash_iter_next (&iter))
-    {
-      DBusMessageHandler *h = _dbus_hash_iter_get_value (&iter);
-      
-      _dbus_message_handler_remove_connection (h, connection);
-    }
   
   link = _dbus_list_get_first_link (&connection->filter_list);
   while (link != NULL)
     {
-      DBusMessageHandler *h = link->data;
+      DBusMessageFilter *filter = link->data;
       DBusList *next = _dbus_list_get_next_link (&connection->filter_list, link);
-      
-      _dbus_message_handler_remove_connection (h, connection);
+
+      filter->function = NULL;
+      _dbus_message_filter_unref (filter); /* calls app callback */
+      link->data = NULL;
       
       link = next;
     }
+  _dbus_list_clear (&connection->filter_list);
+  
+  /* ---- Done with stuff that invokes application callbacks */
 
-  _dbus_hash_table_unref (connection->handler_table);
-  connection->handler_table = NULL;
+  _dbus_object_tree_unref (connection->objects);  
 
   _dbus_hash_table_unref (connection->pending_replies);
   connection->pending_replies = NULL;
@@ -1219,12 +1359,29 @@
   return res;
 }
 
-struct DBusPreallocatedSend
+/**
+ * Set whether _exit() should be called when the connection receives a
+ * disconnect signal. The call to _exit() comes after any handlers for
+ * the disconnect signal run; handlers can cancel the exit by calling
+ * this function.
+ *
+ * By default, exit_on_disconnect is #FALSE; but for message bus
+ * connections returned from dbus_bus_get() it will be toggled on
+ * by default.
+ *
+ * @param connection the connection
+ * @param exit_on_disconnect #TRUE if _exit() should be called after a disconnect signal
+ */
+void
+dbus_connection_set_exit_on_disconnect (DBusConnection *connection,
+                                        dbus_bool_t     exit_on_disconnect)
 {
-  DBusConnection *connection;
-  DBusList *queue_link;
-  DBusList *counter_link;
-};
+  _dbus_return_if_fail (connection != NULL);
+
+  CONNECTION_LOCK (connection);
+  connection->exit_on_disconnect = exit_on_disconnect != FALSE;
+  CONNECTION_UNLOCK (connection);
+}
 
 static DBusPreallocatedSend*
 _dbus_connection_preallocate_send_unlocked (DBusConnection *connection)
@@ -1350,7 +1507,9 @@
 
   _dbus_verbose ("Message %p (%s) added to outgoing queue %p, %d pending to send\n",
                  message,
-                 dbus_message_get_name (message),
+                 dbus_message_get_interface (message) ?
+                 dbus_message_get_interface (message) :
+                 "no interface",
                  connection,
                  connection->n_outgoing);
 
@@ -1398,7 +1557,12 @@
   _dbus_return_if_fail (preallocated != NULL);
   _dbus_return_if_fail (message != NULL);
   _dbus_return_if_fail (preallocated->connection == connection);
-  _dbus_return_if_fail (dbus_message_get_name (message) != NULL);
+  _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL ||
+                        (dbus_message_get_interface (message) != NULL &&
+                         dbus_message_get_member (message) != NULL));
+  _dbus_return_if_fail (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL ||
+                        (dbus_message_get_interface (message) != NULL &&
+                         dbus_message_get_member (message) != NULL));
   
   CONNECTION_LOCK (connection);
   _dbus_connection_send_preallocated_unlocked (connection,
@@ -1407,6 +1571,28 @@
   CONNECTION_UNLOCK (connection);  
 }
 
+static dbus_bool_t
+_dbus_connection_send_unlocked (DBusConnection *connection,
+                                DBusMessage    *message,
+                                dbus_uint32_t  *client_serial)
+{
+  DBusPreallocatedSend *preallocated;
+
+  _dbus_assert (connection != NULL);
+  _dbus_assert (message != NULL);
+  
+  preallocated = _dbus_connection_preallocate_send_unlocked (connection);
+  if (preallocated == NULL)
+    return FALSE;
+
+
+  _dbus_connection_send_preallocated_unlocked (connection,
+                                               preallocated,
+                                               message,
+                                               client_serial);
+  return TRUE;
+}
+
 /**
  * Adds a message to the outgoing message queue. Does not block to
  * write the message to the network; that happens asynchronously. To
@@ -1430,50 +1616,41 @@
                       DBusMessage    *message,
                       dbus_uint32_t  *client_serial)
 {
-  DBusPreallocatedSend *preallocated;
-
   _dbus_return_val_if_fail (connection != NULL, FALSE);
   _dbus_return_val_if_fail (message != NULL, FALSE);
 
   CONNECTION_LOCK (connection);
-  
-  preallocated = _dbus_connection_preallocate_send_unlocked (connection);
-  if (preallocated == NULL)
+
+  if (!_dbus_connection_send_unlocked (connection, message, client_serial))
     {
       CONNECTION_UNLOCK (connection);
       return FALSE;
     }
-  else
-    {
-      _dbus_connection_send_preallocated_unlocked (connection,
-                                                   preallocated,
-                                                   message,
-                                                   client_serial);
-      CONNECTION_UNLOCK (connection);
-      return TRUE;
-    }
+
+  CONNECTION_UNLOCK (connection);
+  return TRUE;
 }
 
 static dbus_bool_t
 reply_handler_timeout (void *data)
 {
   DBusConnection *connection;
-  ReplyHandlerData *reply_handler_data = data;
   DBusDispatchStatus status;
+  DBusPendingCall *pending = data;
 
-  connection = reply_handler_data->connection;
+  connection = pending->connection;
   
   CONNECTION_LOCK (connection);
-  if (reply_handler_data->timeout_link)
+  if (pending->timeout_link)
     {
       _dbus_connection_queue_synthesized_message_link (connection,
-						       reply_handler_data->timeout_link);
-      reply_handler_data->timeout_link = NULL;
+						       pending->timeout_link);
+      pending->timeout_link = NULL;
     }
 
   _dbus_connection_remove_timeout (connection,
-				   reply_handler_data->timeout);
-  reply_handler_data->timeout_added = FALSE;
+				   pending->timeout);
+  pending->timeout_added = FALSE;
 
   status = _dbus_connection_get_dispatch_status_unlocked (connection);
 
@@ -1483,52 +1660,29 @@
   return TRUE;
 }
 
-static void
-reply_handler_data_free (ReplyHandlerData *data)
-{
-  if (!data)
-    return;
-
-  if (data->timeout_added)
-    _dbus_connection_remove_timeout_locked (data->connection,
-					    data->timeout);
-
-  if (data->connection_added)
-    _dbus_message_handler_remove_connection (data->handler,
-					     data->connection);
-
-  if (data->timeout_link)
-    {
-      dbus_message_unref ((DBusMessage *)data->timeout_link->data);
-      _dbus_list_free_link (data->timeout_link);
-    }
-  
-  dbus_message_handler_unref (data->handler);
-  
-  dbus_free (data);
-}
-
 /**
  * Queues a message to send, as with dbus_connection_send_message(),
- * but also sets up a DBusMessageHandler to receive a reply to the
+ * but also returns a #DBusPendingCall used to receive a reply to the
  * message. If no reply is received in the given timeout_milliseconds,
- * expires the pending reply and sends the DBusMessageHandler a
- * synthetic error reply (generated in-process, not by the remote
- * application) indicating that a timeout occurred.
+ * this function expires the pending reply and generates a synthetic
+ * error reply (generated in-process, not by the remote application)
+ * indicating that a timeout occurred.
  *
- * Reply handlers see their replies after message filters see them,
- * but before message handlers added with
- * dbus_connection_register_handler() see them, regardless of the
- * reply message's name. Reply handlers are only handed a single
- * message as a reply, after one reply has been seen the handler is
- * removed. If a filter filters out the reply before the handler sees
- * it, the reply is immediately timed out and a timeout error reply is
+ * A #DBusPendingCall will see a reply message after any filters, but
+ * before any object instances or other handlers. A #DBusPendingCall
+ * will always see exactly one reply message, unless it's cancelled
+ * with dbus_pending_call_cancel().
+ * 
+ * If a filter filters out the reply before the handler sees it, the
+ * reply is immediately timed out and a timeout error reply is
  * generated. If a filter removes the timeout error reply then the
- * reply handler will never be called. Filters should not do this.
+ * #DBusPendingCall will get confused. Filtering the timeout error
+ * is thus considered a bug and will print a warning.
  * 
- * If #NULL is passed for the reply_handler, the timeout reply will
- * still be generated and placed into the message queue, but no
- * specific message handler will receive the reply.
+ * If #NULL is passed for the pending_return, the #DBusPendingCall
+ * will still be generated internally, and used to track
+ * the message reply timeout. This means a timeout error will
+ * occur if no reply arrives, unlike with dbus_connection_send().
  *
  * 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
@@ -1538,7 +1692,7 @@
  * 
  * @param connection the connection
  * @param message the message to send
- * @param reply_handler message handler expecting the reply, or #NULL
+ * @param pending_return return location for a #DBusPendingCall object, or #NULL
  * @param timeout_milliseconds timeout in milliseconds or -1 for default
  * @returns #TRUE if the message is successfully queued, #FALSE if no memory.
  *
@@ -1546,63 +1700,30 @@
 dbus_bool_t
 dbus_connection_send_with_reply (DBusConnection     *connection,
                                  DBusMessage        *message,
-                                 DBusMessageHandler *reply_handler,
+                                 DBusPendingCall   **pending_return,
                                  int                 timeout_milliseconds)
 {
-  DBusTimeout *timeout;
-  ReplyHandlerData *data;
+  DBusPendingCall *pending;
   DBusMessage *reply;
   DBusList *reply_link;
   dbus_int32_t serial = -1;
 
   _dbus_return_val_if_fail (connection != NULL, FALSE);
   _dbus_return_val_if_fail (message != NULL, FALSE);
-  _dbus_return_val_if_fail (reply_handler != NULL, FALSE);
   _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
-  
-  if (timeout_milliseconds == -1)
-    timeout_milliseconds = DEFAULT_TIMEOUT_VALUE;
-
-  data = dbus_new0 (ReplyHandlerData, 1);
 
-  if (!data)
-    return FALSE;
+  if (pending_return)
+    *pending_return = NULL;
   
-  timeout = _dbus_timeout_new (timeout_milliseconds, reply_handler_timeout,
-			       data, NULL);
+  pending = _dbus_pending_call_new (connection,
+                                    timeout_milliseconds,
+                                    reply_handler_timeout);
 
-  if (!timeout)
-    {
-      reply_handler_data_free (data);
-      return FALSE;
-    }
+  if (pending == NULL)
+    return FALSE;
 
   CONNECTION_LOCK (connection);
   
-  /* Add timeout */
-  if (!_dbus_connection_add_timeout (connection, timeout))
-    {
-      reply_handler_data_free (data);
-      _dbus_timeout_unref (timeout);
-      CONNECTION_UNLOCK (connection);
-      return FALSE;
-    }
-
-  /* The connection now owns the reference to the timeout. */
-  _dbus_timeout_unref (timeout);
-  
-  data->timeout_added = TRUE;
-  data->timeout = timeout;
-  data->connection = connection;
-  
-  if (!_dbus_message_handler_add_connection (reply_handler, connection))
-    {
-      CONNECTION_UNLOCK (connection);
-      reply_handler_data_free (data);
-      return FALSE;
-    }
-  data->connection_added = TRUE;
-  
   /* Assign a serial to the message */
   if (dbus_message_get_serial (message) == 0)
     {
@@ -1610,17 +1731,14 @@
       _dbus_message_set_serial (message, serial);
     }
 
-  data->handler = reply_handler;
-  data->serial = serial;
-
-  dbus_message_handler_ref (reply_handler);
+  pending->reply_serial = serial;
 
-  reply = dbus_message_new_error_reply (message, DBUS_ERROR_NO_REPLY,
-					"No reply within specified time");
+  reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY,
+                                  "No reply within specified time");
   if (!reply)
     {
       CONNECTION_UNLOCK (connection);
-      reply_handler_data_free (data);
+      dbus_pending_call_unref (pending);
       return FALSE;
     }
 
@@ -1629,33 +1747,42 @@
     {
       CONNECTION_UNLOCK (connection);
       dbus_message_unref (reply);
-      reply_handler_data_free (data);
+      dbus_pending_call_unref (pending);
       return FALSE;
     }
 
-  data->timeout_link = reply_link;
-  
-  /* Insert the serial in the pending replies hash. */
-  if (!_dbus_hash_table_insert_int (connection->pending_replies, serial, data))
+  pending->timeout_link = reply_link;
+
+  /* Insert the serial in the pending replies hash;
+   * hash takes a refcount on DBusPendingCall.
+   * Also, add the timeout.
+   */
+  if (!_dbus_connection_attach_pending_call_unlocked (connection,
+                                                      pending))
     {
       CONNECTION_UNLOCK (connection);
-      reply_handler_data_free (data);      
+      dbus_pending_call_unref (pending);
       return FALSE;
     }
-
-  CONNECTION_UNLOCK (connection);
   
-  if (!dbus_connection_send (connection, message, NULL))
+  if (!_dbus_connection_send_unlocked (connection, message, NULL))
     {
-      /* This will free the handler data too */
-      _dbus_hash_table_remove_int (connection->pending_replies, serial);
+      _dbus_connection_detach_pending_call_and_unlock (connection,
+                                                       pending);
       return FALSE;
     }
 
+  if (pending_return)
+    {
+      dbus_pending_call_ref (pending);
+      *pending_return = pending;
+    }
+
+  CONNECTION_UNLOCK (connection);
+  
   return TRUE;
 }
 
-
 static DBusMessage*
 check_for_reply_unlocked (DBusConnection *connection,
                           dbus_uint32_t   client_serial)
@@ -1682,45 +1809,34 @@
 }
 
 /**
- * Sends a message and blocks a certain time period while waiting for a reply.
- * This function does not dispatch any message handlers until the main loop
- * has been reached. This function is used to do non-reentrant "method calls."
- * If a reply is received, it is returned, and removed from the incoming
- * message queue. If it is not received, #NULL is returned and the
- * error is set to #DBUS_ERROR_NO_REPLY. If something else goes
- * wrong, result is set to whatever is appropriate, such as
- * #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED.
+ * Blocks a certain time period while waiting for a reply.
+ * If no reply arrives, returns #NULL.
  *
  * @todo could use performance improvements (it keeps scanning
  * the whole message queue for example) and has thread issues,
  * see comments in source
  *
  * @param connection the connection
- * @param message the message to send
+ * @param client_serial the reply serial to wait for
  * @param timeout_milliseconds timeout in milliseconds or -1 for default
- * @param error return location for error message
- * @returns the message that is the reply or #NULL with an error code if the
- * function fails.
+ * @returns the message that is the reply or #NULL if no reply
  */
-DBusMessage *
-dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
-                                           DBusMessage        *message,
-                                           int                 timeout_milliseconds,
-                                           DBusError          *error)
+DBusMessage*
+_dbus_connection_block_for_reply (DBusConnection     *connection,
+                                  dbus_uint32_t       client_serial,
+                                  int                 timeout_milliseconds)
 {
-  dbus_uint32_t client_serial;
   long start_tv_sec, start_tv_usec;
   long end_tv_sec, end_tv_usec;
   long tv_sec, tv_usec;
   DBusDispatchStatus status;
 
   _dbus_return_val_if_fail (connection != NULL, NULL);
-  _dbus_return_val_if_fail (message != NULL, NULL);
-  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);  
-  _dbus_return_val_if_error_is_set (error, NULL);
+  _dbus_return_val_if_fail (client_serial != 0, NULL);
+  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
   
   if (timeout_milliseconds == -1)
-    timeout_milliseconds = DEFAULT_TIMEOUT_VALUE;
+    timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
 
   /* it would probably seem logical to pass in _DBUS_INT_MAX
    * for infinite timeout, but then math below would get
@@ -1729,14 +1845,6 @@
   if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
     timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
   
-  if (!dbus_connection_send (connection, message, &client_serial))
-    {
-      _DBUS_SET_OOM (error);
-      return NULL;
-    }
-
-  message = NULL;
-  
   /* Flush message queue */
   dbus_connection_flush (connection);
 
@@ -1778,8 +1886,7 @@
         {          
           status = _dbus_connection_get_dispatch_status_unlocked (connection);
 
-          _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply %s\n",
-                         dbus_message_get_name (reply));
+          _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply\n");
 
           /* Unlocks, and calls out to user code */
           _dbus_connection_update_dispatch_status_and_unlock (connection, status);
@@ -1831,11 +1938,6 @@
 
   _dbus_verbose ("dbus_connection_send_with_reply_and_block(): Waited %ld milliseconds and got no reply\n",
                  (tv_sec - start_tv_sec) * 1000 + (tv_usec - start_tv_usec) / 1000);
-  
-  if (dbus_connection_get_is_connected (connection))
-    dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
-  else
-    dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
 
   /* unlocks and calls out to user code */
   _dbus_connection_update_dispatch_status_and_unlock (connection, status);
@@ -1844,6 +1946,70 @@
 }
 
 /**
+ * Sends a message and blocks a certain time period while waiting for
+ * a reply.  This function does not reenter the main loop,
+ * i.e. messages other than the reply are queued up but not
+ * processed. This function is used to do non-reentrant "method
+ * calls."
+ * 
+ * If a normal reply is received, it is returned, and removed from the
+ * incoming message queue. If it is not received, #NULL is returned
+ * and the error is set to #DBUS_ERROR_NO_REPLY.  If an error reply is
+ * received, it is converted to a #DBusError and returned as an error,
+ * then the reply message is deleted. If something else goes wrong,
+ * result is set to whatever is appropriate, such as
+ * #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED.
+ *
+ * @param connection the connection
+ * @param message the message to send
+ * @param timeout_milliseconds timeout in milliseconds or -1 for default
+ * @param error return location for error message
+ * @returns the message that is the reply or #NULL with an error code if the
+ * function fails.
+ */
+DBusMessage *
+dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
+                                           DBusMessage        *message,
+                                           int                 timeout_milliseconds,
+                                           DBusError          *error)
+{
+  dbus_uint32_t client_serial;
+  DBusMessage *reply;
+  
+  _dbus_return_val_if_fail (connection != NULL, NULL);
+  _dbus_return_val_if_fail (message != NULL, NULL);
+  _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);  
+  _dbus_return_val_if_error_is_set (error, NULL);
+  
+  if (!dbus_connection_send (connection, message, &client_serial))
+    {
+      _DBUS_SET_OOM (error);
+      return NULL;
+    }
+
+  reply = _dbus_connection_block_for_reply (connection,
+                                            client_serial,
+                                            timeout_milliseconds);
+  
+  if (reply == NULL)
+    {
+      if (dbus_connection_get_is_connected (connection))
+        dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
+      else
+        dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
+
+      return NULL;
+    }
+  else if (dbus_set_error_from_message (error, reply))
+    {
+      dbus_message_unref (reply);
+      return NULL;
+    }
+  else
+    return reply;
+}
+
+/**
  * Blocks until the outgoing message queue is empty.
  *
  * @param connection the connection.
@@ -1908,6 +2074,8 @@
   DBusDispatchStatus status;
 
   _dbus_return_val_if_fail (connection != NULL, NULL);
+  /* can't borrow during dispatch */
+  _dbus_return_val_if_fail (!connection->dispatch_acquired, NULL);
   
   /* this is called for the side effect that it queues
    * up any messages from the transport
@@ -1943,6 +2111,8 @@
 {
   _dbus_return_if_fail (connection != NULL);
   _dbus_return_if_fail (message != NULL);
+  /* can't borrow during dispatch */
+  _dbus_return_if_fail (!connection->dispatch_acquired);
   
   CONNECTION_LOCK (connection);
   
@@ -1971,6 +2141,8 @@
 
   _dbus_return_if_fail (connection != NULL);
   _dbus_return_if_fail (message != NULL);
+  /* can't borrow during dispatch */
+  _dbus_return_if_fail (!connection->dispatch_acquired);
   
   CONNECTION_LOCK (connection);
  
@@ -2007,7 +2179,10 @@
       connection->n_incoming -= 1;
 
       _dbus_verbose ("Message %p (%s) removed from incoming queue %p, %d incoming\n",
-                     link->data, dbus_message_get_name (link->data),
+                     link->data,
+                     dbus_message_get_interface (link->data) ?
+                     dbus_message_get_interface (link->data) :
+                     "no interface",
                      connection, connection->n_incoming);
 
       return link;
@@ -2040,6 +2215,25 @@
     return NULL;
 }
 
+static void
+_dbus_connection_putback_message_link_unlocked (DBusConnection *connection,
+                                                DBusList       *message_link)
+{
+  _dbus_assert (message_link != NULL);
+  /* You can't borrow a message while a link is outstanding */
+  _dbus_assert (connection->message_borrowed == NULL);
+
+  _dbus_list_prepend_link (&connection->incoming_messages,
+                           message_link);
+  connection->n_incoming += 1;
+
+  _dbus_verbose ("Message %p (%s) put back into queue %p, %d incoming\n",
+                 message_link->data,
+                 dbus_message_get_interface (message_link->data) ?
+                 dbus_message_get_interface (message_link->data) :
+                 "no interface",
+                 connection, connection->n_incoming);
+}
 
 /**
  * Returns the first-received message from the incoming message queue,
@@ -2215,18 +2409,22 @@
  * does not necessarily dispatch a message, as the data may
  * be part of authentication or the like.
  *
+ * @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY
+ *
+ * @todo right now a message filter gets run on replies to a pending
+ * call in here, but not in the case where we block without
+ * entering the main loop.
+ * 
  * @param connection the connection
  * @returns dispatch status
  */
 DBusDispatchStatus
 dbus_connection_dispatch (DBusConnection *connection)
 {
-  DBusMessageHandler *handler;
   DBusMessage *message;
   DBusList *link, *filter_list_copy, *message_link;
   DBusHandlerResult result;
-  ReplyHandlerData *reply_handler_data;
-  const char *name;
+  DBusPendingCall *pending;
   dbus_int32_t reply_serial;
   DBusDispatchStatus status;
 
@@ -2272,11 +2470,11 @@
 
   message = message_link->data;
   
-  result = DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+  result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
   reply_serial = dbus_message_get_reply_serial (message);
-  reply_handler_data = _dbus_hash_table_lookup_int (connection->pending_replies,
-						    reply_serial);
+  pending = _dbus_hash_table_lookup_int (connection->pending_replies,
+                                         reply_serial);
   
   if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy))
     {
@@ -2294,7 +2492,7 @@
     }
   
   _dbus_list_foreach (&filter_list_copy,
-		      (DBusForeachFunction)dbus_message_handler_ref,
+		      (DBusForeachFunction)_dbus_message_filter_ref,
 		      NULL);
 
   /* We're still protected from dispatch() reentrancy here
@@ -2305,92 +2503,164 @@
   link = _dbus_list_get_first_link (&filter_list_copy);
   while (link != NULL)
     {
-      DBusMessageHandler *handler = link->data;
+      DBusMessageFilter *filter = link->data;
       DBusList *next = _dbus_list_get_next_link (&filter_list_copy, link);
 
       _dbus_verbose ("  running filter on message %p\n", message);
-      result = _dbus_message_handler_handle_message (handler, connection,
-                                                     message);
+      result = (* filter->function) (connection, message, filter->user_data);
 
-      if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE)
+      if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
 	break;
 
       link = next;
     }
 
   _dbus_list_foreach (&filter_list_copy,
-		      (DBusForeachFunction)dbus_message_handler_unref,
+		      (DBusForeachFunction)_dbus_message_filter_unref,
 		      NULL);
   _dbus_list_clear (&filter_list_copy);
   
   CONNECTION_LOCK (connection);
 
+  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
+    goto out;
+  
   /* Did a reply we were waiting on get filtered? */
-  if (reply_handler_data && result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE)
+  if (pending && result == DBUS_HANDLER_RESULT_HANDLED)
     {
       /* Queue the timeout immediately! */
-      if (reply_handler_data->timeout_link)
+      if (pending->timeout_link)
 	{
 	  _dbus_connection_queue_synthesized_message_link (connection,
-							   reply_handler_data->timeout_link);
-	  reply_handler_data->timeout_link = NULL;
+							   pending->timeout_link);
+	  pending->timeout_link = NULL;
 	}
       else
 	{
 	  /* We already queued the timeout? Then it was filtered! */
-	  _dbus_warn ("The timeout error with reply serial %d was filtered, so the reply handler will never be called.\n", reply_serial);
+	  _dbus_warn ("The timeout error with reply serial %d was filtered, so the DBusPendingCall will never stop pending.\n", reply_serial);
 	}
     }
   
-  if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE)
+  if (result == DBUS_HANDLER_RESULT_HANDLED)
     goto out;
-
-  if (reply_handler_data)
+  
+  if (pending)
     {
-      CONNECTION_UNLOCK (connection);
+      _dbus_pending_call_complete_and_unlock (pending, message);
 
-      _dbus_verbose ("  running reply handler on message %p\n", message);
+      pending = NULL;
       
-      result = _dbus_message_handler_handle_message (reply_handler_data->handler,
-						     connection, message);
-      reply_handler_data_free (reply_handler_data);
       CONNECTION_LOCK (connection);
       goto out;
     }
+
+  /* We're still protected from dispatch() reentrancy here
+   * since we acquired the dispatcher
+   */
+  _dbus_verbose ("  running object path dispatch on message %p (%s)\n",
+                 message,
+                 dbus_message_get_interface (message) ?
+                 dbus_message_get_interface (message) :
+                 "no interface");
   
-  name = dbus_message_get_name (message);
-  if (name != NULL)
+  result = _dbus_object_tree_dispatch_and_unlock (connection->objects,
+                                                  message);
+  
+  CONNECTION_LOCK (connection);
+
+  if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
+    goto out;
+
+  if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
     {
-      handler = _dbus_hash_table_lookup_string (connection->handler_table,
-                                                name);
-      if (handler != NULL)
+      DBusMessage *reply;
+      DBusString str;
+      DBusPreallocatedSend *preallocated;
+
+      _dbus_verbose ("  sending error %s\n",
+                     DBUS_ERROR_UNKNOWN_METHOD);
+      
+      if (!_dbus_string_init (&str))
         {
-	  /* We're still protected from dispatch() reentrancy here
-	   * since we acquired the dispatcher
-           */
-	  CONNECTION_UNLOCK (connection);
+          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+          goto out;
+        }
+              
+      if (!_dbus_string_append_printf (&str,
+                                       "Method \"%s\" on interface \"%s\" doesn't exist\n",
+                                       dbus_message_get_member (message),
+                                       dbus_message_get_interface (message)))
+        {
+          _dbus_string_free (&str);
+          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+          goto out;
+        }
+      
+      reply = dbus_message_new_error (message,
+                                      DBUS_ERROR_UNKNOWN_METHOD,
+                                      _dbus_string_get_const_data (&str));
+      _dbus_string_free (&str);
 
-          _dbus_verbose ("  running app handler on message %p (%s)\n",
-                         message, dbus_message_get_name (message));
-          
-          result = _dbus_message_handler_handle_message (handler, connection,
-                                                         message);
-	  CONNECTION_LOCK (connection);
-          if (result == DBUS_HANDLER_RESULT_REMOVE_MESSAGE)
-            goto out;
+      if (reply == NULL)
+        {
+          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+          goto out;
+        }
+      
+      preallocated = _dbus_connection_preallocate_send_unlocked (connection);
+
+      if (preallocated == NULL)
+        {
+          dbus_message_unref (reply);
+          result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+          goto out;
         }
-    }
 
+      _dbus_connection_send_preallocated_unlocked (connection, preallocated,
+                                                   reply, NULL);
+
+      dbus_message_unref (reply);
+      
+      result = DBUS_HANDLER_RESULT_HANDLED;
+    }
+  
   _dbus_verbose ("  done dispatching %p (%s) on connection %p\n", message,
-                 dbus_message_get_name (message), connection);
+                 dbus_message_get_interface (message) ?
+                 dbus_message_get_interface (message) :
+                 "no interface",
+                 connection);
   
  out:
+  if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
+    {
+      /* Put message back, and we'll start over.
+       * Yes this means handlers must be idempotent if they
+       * don't return HANDLED; c'est la vie.
+       */
+      _dbus_connection_putback_message_link_unlocked (connection,
+                                                      message_link);
+    }
+  else
+    {
+      if (connection->exit_on_disconnect &&
+          dbus_message_is_signal (message,
+                                  DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+                                  "Disconnected"))
+        {
+          _dbus_verbose ("Exiting on Disconnected signal\n");
+          CONNECTION_UNLOCK (connection);
+          _dbus_exit (1);
+          _dbus_assert_not_reached ("Call to exit() returned");
+        }
+      
+      _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);
-
-  _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
-                                 */
   
   status = _dbus_connection_get_dispatch_status_unlocked (connection);
 
@@ -2704,226 +2974,248 @@
 }
 
 /**
- * Adds a message filter. Filters are handlers that are run on
- * all incoming messages, prior to the normal handlers
- * registered with dbus_connection_register_handler().
- * Filters are run in the order that they were added.
- * The same handler can be added as a filter more than once, in
- * which case it will be run more than once.
- * Filters added during a filter callback won't be run on the
- * message being processed.
+ * Adds a message filter. Filters are handlers that are run on all
+ * incoming messages, prior to the objects registered with
+ * dbus_connection_register_object_path().  Filters are run in the
+ * order that they were added.  The same handler can be added as a
+ * filter more than once, in which case it will be run more than once.
+ * Filters added during a filter callback won't be run on the message
+ * being processed.
  *
- * The connection does NOT add a reference to the message handler;
- * instead, if the message handler is finalized, the connection simply
- * forgets about it. Thus the caller of this function must keep a
- * reference to the message handler.
+ * @todo we don't run filters on messages while blocking without
+ * entering the main loop, since filters are run as part of
+ * dbus_connection_dispatch().
  *
  * @param connection the connection
- * @param handler the handler
+ * @param function function to handle messages
+ * @param user_data user data to pass to the function
+ * @param free_data_function function to use for freeing user data
  * @returns #TRUE on success, #FALSE if not enough memory.
  */
 dbus_bool_t
-dbus_connection_add_filter (DBusConnection      *connection,
-                            DBusMessageHandler  *handler)
+dbus_connection_add_filter (DBusConnection            *connection,
+                            DBusHandleMessageFunction  function,
+                            void                      *user_data,
+                            DBusFreeFunction           free_data_function)
 {
+  DBusMessageFilter *filter;
+  
   _dbus_return_val_if_fail (connection != NULL, FALSE);
-  _dbus_return_val_if_fail (handler != NULL, FALSE);
+  _dbus_return_val_if_fail (function != NULL, FALSE);
 
+  filter = dbus_new0 (DBusMessageFilter, 1);
+  if (filter == NULL)
+    return FALSE;
+
+  filter->refcount.value = 1;
+  
   CONNECTION_LOCK (connection);
-  if (!_dbus_message_handler_add_connection (handler, connection))
-    {
-      CONNECTION_UNLOCK (connection);
-      return FALSE;
-    }
 
   if (!_dbus_list_append (&connection->filter_list,
-                          handler))
+                          filter))
     {
-      _dbus_message_handler_remove_connection (handler, connection);
+      _dbus_message_filter_unref (filter);
       CONNECTION_UNLOCK (connection);
       return FALSE;
     }
 
+  /* Fill in filter after all memory allocated,
+   * so we don't run the free_user_data_function
+   * if the add_filter() fails
+   */
+  
+  filter->function = function;
+  filter->user_data = user_data;
+  filter->free_user_data_function = free_data_function;
+        
   CONNECTION_UNLOCK (connection);
   return TRUE;
 }
 
 /**
  * Removes a previously-added message filter. It is a programming
- * error to call this function for a handler that has not
- * been added as a filter. If the given handler was added
- * more than once, only one instance of it will be removed
- * (the most recently-added instance).
+ * error to call this function for a handler that has not been added
+ * as a filter. If the given handler was added more than once, only
+ * one instance of it will be removed (the most recently-added
+ * instance).
  *
  * @param connection the connection
- * @param handler the handler to remove
+ * @param function the handler to remove
+ * @param user_data user data for the handler to remove
  *
  */
 void
-dbus_connection_remove_filter (DBusConnection      *connection,
-                               DBusMessageHandler  *handler)
+dbus_connection_remove_filter (DBusConnection            *connection,
+                               DBusHandleMessageFunction  function,
+                               void                      *user_data)
 {
+  DBusList *link;
+  DBusMessageFilter *filter;
+  
   _dbus_return_if_fail (connection != NULL);
-  _dbus_return_if_fail (handler != NULL);
+  _dbus_return_if_fail (function != NULL);
   
   CONNECTION_LOCK (connection);
-  if (!_dbus_list_remove_last (&connection->filter_list, handler))
+
+  filter = NULL;
+  
+  link = _dbus_list_get_last_link (&connection->filter_list);
+  while (link != NULL)
     {
-      _dbus_warn ("Tried to remove a DBusConnection filter that had not been added\n");
-      CONNECTION_UNLOCK (connection);
-      return;
+      filter = link->data;
+
+      if (filter->function == function &&
+          filter->user_data == user_data)
+        {
+          _dbus_list_remove_link (&connection->filter_list, link);
+          filter->function = NULL;
+          
+          break;
+        }
+        
+      link = _dbus_list_get_prev_link (&connection->filter_list, link);
     }
+  
+  CONNECTION_UNLOCK (connection);
 
-  _dbus_message_handler_remove_connection (handler, connection);
+#ifndef DBUS_DISABLE_CHECKS
+  if (filter == NULL)
+    {
+      _dbus_warn ("Attempt to remove filter function %p user data %p, but no such filter has been added\n",
+                  function, user_data);
+      return;
+    }
+#endif
+  
+  /* Call application code */
+  if (filter->free_user_data_function)
+    (* filter->free_user_data_function) (filter->user_data);
 
-  CONNECTION_UNLOCK (connection);
+  filter->free_user_data_function = NULL;
+  filter->user_data = NULL;
+  
+  _dbus_message_filter_unref (filter);
 }
 
 /**
- * Registers a handler for a list of message names. A single handler
- * can be registered for any number of message names, but each message
- * name can only have one handler at a time. It's not allowed to call
- * this function with the name of a message that already has a
- * handler. If the function returns #FALSE, the handlers were not
- * registered due to lack of memory.
+ * Registers a handler for a given path in the object hierarchy.
+ * The given vtable handles messages sent to exactly the given path.
  *
- * The connection does NOT add a reference to the message handler;
- * instead, if the message handler is finalized, the connection simply
- * forgets about it. Thus the caller of this function must keep a
- * reference to the message handler.
  *
- * @todo the messages_to_handle arg may be more convenient if it's a
- * single string instead of an array. Though right now MessageHandler
- * is sort of designed to say be associated with an entire object with
- * multiple methods, that's why for example the connection only
- * weakrefs it.  So maybe the "manual" API should be different.
- * 
  * @param connection the connection
- * @param handler the handler
- * @param messages_to_handle the messages to handle
- * @param n_messages the number of message names in messages_to_handle
- * @returns #TRUE on success, #FALSE if no memory or another handler already exists
- * 
- **/
+ * @param path #NULL-terminated array 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
+ */
 dbus_bool_t
-dbus_connection_register_handler (DBusConnection     *connection,
-                                  DBusMessageHandler *handler,
-                                  const char        **messages_to_handle,
-                                  int                 n_messages)
+dbus_connection_register_object_path (DBusConnection              *connection,
+                                      const char                 **path,
+                                      const DBusObjectPathVTable  *vtable,
+                                      void                        *user_data)
 {
-  int i;
-
-  _dbus_return_val_if_fail (connection != NULL, FALSE);
-  _dbus_return_val_if_fail (handler != NULL, FALSE);
-  _dbus_return_val_if_fail (n_messages >= 0, FALSE);
-  _dbus_return_val_if_fail (n_messages == 0 || messages_to_handle != NULL, FALSE);
+  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] != NULL, FALSE);
+  _dbus_return_val_if_fail (vtable != NULL, FALSE);
+
   CONNECTION_LOCK (connection);
-  i = 0;
-  while (i < n_messages)
-    {
-      DBusHashIter iter;
-      char *key;
 
-      key = _dbus_strdup (messages_to_handle[i]);
-      if (key == NULL)
-        goto failed;
-      
-      if (!_dbus_hash_iter_lookup (connection->handler_table,
-                                   key, TRUE,
-                                   &iter))
-        {
-          dbus_free (key);
-          goto failed;
-        }
+  retval = _dbus_object_tree_register (connection->objects,
+                                       FALSE,
+                                       path, vtable,
+                                       user_data);
 
-      if (_dbus_hash_iter_get_value (&iter) != NULL)
-        {
-          _dbus_warn ("Bug in application: attempted to register a second handler for %s\n",
-                      messages_to_handle[i]);
-          dbus_free (key); /* won't have replaced the old key with the new one */
-          goto failed;
-        }
+  CONNECTION_UNLOCK (connection);
 
-      if (!_dbus_message_handler_add_connection (handler, connection))
-        {
-          _dbus_hash_iter_remove_entry (&iter);
-          /* key has freed on nuking the entry */
-          goto failed;
-        }
-      
-      _dbus_hash_iter_set_value (&iter, handler);
+  return retval;
+}
 
-      ++i;
-    }
-  
-  CONNECTION_UNLOCK (connection);
-  return TRUE;
+/**
+ * Registers a fallback handler for a given subsection of the object
+ * hierarchy.  The given vtable handles messages at or below the given
+ * path. You can use this to establish a default message handling
+ * policy for a whole "subdirectory."
+ *
+ * @param connection the connection
+ * @param path #NULL-terminated array 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
+ */
+dbus_bool_t
+dbus_connection_register_fallback (DBusConnection              *connection,
+                                   const char                 **path,
+                                   const DBusObjectPathVTable  *vtable,
+                                   void                        *user_data)
+{
+  dbus_bool_t retval;
   
- failed:
-  /* unregister everything registered so far,
-   * so we don't fail partially
-   */
-  dbus_connection_unregister_handler (connection,
-                                      handler,
-                                      messages_to_handle,
-                                      i);
+  _dbus_return_val_if_fail (connection != NULL, FALSE);
+  _dbus_return_val_if_fail (path != NULL, FALSE);
+  _dbus_return_val_if_fail (path[0] != NULL, FALSE);
+  _dbus_return_val_if_fail (vtable != NULL, FALSE);
+
+  CONNECTION_LOCK (connection);
+
+  retval = _dbus_object_tree_register (connection->objects,
+                                       TRUE,
+                                       path, vtable,
+                                       user_data);
 
   CONNECTION_UNLOCK (connection);
-  return FALSE;
+
+  return retval;
 }
 
 /**
- * Unregisters a handler for a list of message names. The handlers
- * must have been previously registered.
+ * Unregisters the handler registered with exactly the given path.
+ * It's a bug to call this function for a path that isn't registered.
+ * Can unregister both fallback paths and object paths.
  *
  * @param connection the connection
- * @param handler the handler
- * @param messages_to_handle the messages to handle
- * @param n_messages the number of message names in messages_to_handle
- * 
- **/
+ * @param path the #NULL-terminated array of path elements
+ */
 void
-dbus_connection_unregister_handler (DBusConnection     *connection,
-                                    DBusMessageHandler *handler,
-                                    const char        **messages_to_handle,
-                                    int                 n_messages)
+dbus_connection_unregister_object_path (DBusConnection              *connection,
+                                        const char                 **path)
 {
-  int i;
-
   _dbus_return_if_fail (connection != NULL);
-  _dbus_return_if_fail (handler != NULL);
-  _dbus_return_if_fail (n_messages >= 0);
-  _dbus_return_if_fail (n_messages == 0 || messages_to_handle != NULL);
-  
+  _dbus_return_if_fail (path != NULL);
+  _dbus_return_if_fail (path[0] != NULL);
+
   CONNECTION_LOCK (connection);
-  i = 0;
-  while (i < n_messages)
-    {
-      DBusHashIter iter;
 
-      if (!_dbus_hash_iter_lookup (connection->handler_table,
-                                   (char*) messages_to_handle[i], FALSE,
-                                   &iter))
-        {
-          _dbus_warn ("Bug in application: attempted to unregister handler for %s which was not registered\n",
-                      messages_to_handle[i]);
-        }
-      else if (_dbus_hash_iter_get_value (&iter) != handler)
-        {
-          _dbus_warn ("Bug in application: attempted to unregister handler for %s which was registered by a different handler\n",
-                      messages_to_handle[i]);
-        }
-      else
-        {
-          _dbus_hash_iter_remove_entry (&iter);
-          _dbus_message_handler_remove_connection (handler, connection);
-        }
+  return _dbus_object_tree_unregister_and_unlock (connection->objects,
+                                                  path);
+}
 
-      ++i;
-    }
+/**
+ * Lists the registered fallback handlers and object path handlers at
+ * the given parent_path. The returned array should be freed with
+ * dbus_free_string_array().
+ *
+ * @param connection the connection
+ * @param parent_path the path to list the child handlers of
+ * @param child_entries returns #NULL-terminated array of children
+ * @returns #FALSE if no memory to allocate the child entries
+ */
+dbus_bool_t
+dbus_connection_list_registered (DBusConnection              *connection,
+                                 const char                 **parent_path,
+                                 char                      ***child_entries)
+{
+  _dbus_return_val_if_fail (connection != NULL, FALSE);
+  _dbus_return_val_if_fail (parent_path != NULL, FALSE);
+  _dbus_return_val_if_fail (child_entries != NULL, FALSE);
 
-  CONNECTION_UNLOCK (connection);
+  CONNECTION_LOCK (connection);
+
+  return _dbus_object_tree_list_registered_and_unlock (connection->objects,
+                                                       parent_path,
+                                                       child_entries);
 }
 
 static DBusDataSlotAllocator slot_allocator;

Index: dbus-connection.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-connection.h,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- dbus-connection.h	22 Jun 2003 19:39:47 -0000	1.24
+++ dbus-connection.h	30 Sep 2003 02:32:52 -0000	1.25
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-connection.h DBusConnection object
  *
- * Copyright (C) 2002  Red Hat Inc.
+ * Copyright (C) 2002, 2003  Red Hat Inc.
  *
  * Licensed under the Academic Free License version 1.2
  * 
@@ -28,22 +28,17 @@
 #define DBUS_CONNECTION_H
 
 #include <dbus/dbus-errors.h>
-#include <dbus/dbus-message.h>
 #include <dbus/dbus-memory.h>
+#include <dbus/dbus-message.h>
 
 DBUS_BEGIN_DECLS;
 
-typedef struct DBusConnection DBusConnection;
 typedef struct DBusWatch DBusWatch;
 typedef struct DBusTimeout DBusTimeout;
-typedef struct DBusMessageHandler DBusMessageHandler;
 typedef struct DBusPreallocatedSend DBusPreallocatedSend;
-
-typedef enum
-{
-  DBUS_HANDLER_RESULT_REMOVE_MESSAGE,     /**< Remove this message, no further processing. */
-  DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS /**< Run any additional handlers that are interested in this message. */
-} DBusHandlerResult;
+typedef struct DBusPendingCall DBusPendingCall;
+typedef struct DBusConnection DBusConnection;
+typedef struct DBusObjectPathVTable DBusObjectPathVTable;
 
 typedef enum
 {
@@ -63,6 +58,13 @@
   DBUS_DISPATCH_NEED_MEMORY    /**< More memory is needed to continue. */
 } DBusDispatchStatus;
 
+typedef enum
+{
+  DBUS_HANDLER_RESULT_HANDLED,         /**< Message has had its effect */ 
+  DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Message has not had any effect */
+  DBUS_HANDLER_RESULT_NEED_MEMORY      /**< Need more memory to return another result */
+} DBusHandlerResult;
+
 typedef dbus_bool_t (* DBusAddWatchFunction)       (DBusWatch      *watch,
                                                     void           *data);
 typedef void        (* DBusWatchToggledFunction)   (DBusWatch      *watch,
@@ -83,6 +85,14 @@
                                                     unsigned long   uid,
                                                     void           *data);
 
+typedef void (* DBusPendingCallNotifyFunction) (DBusPendingCall *pending,
+                                                void            *user_data);
+
+
+typedef DBusHandlerResult (* DBusHandleMessageFunction) (DBusConnection     *connection,
+                                                         DBusMessage        *message,
+                                                         void               *user_data);
+
 DBusConnection*    dbus_connection_open                         (const char                 *address,
                                                                  DBusError                  *error);
 void               dbus_connection_ref                          (DBusConnection             *connection);
@@ -90,6 +100,8 @@
 void               dbus_connection_disconnect                   (DBusConnection             *connection);
 dbus_bool_t        dbus_connection_get_is_connected             (DBusConnection             *connection);
 dbus_bool_t        dbus_connection_get_is_authenticated         (DBusConnection             *connection);
+void               dbus_connection_set_exit_on_disconnect       (DBusConnection             *connection,
+                                                                 dbus_bool_t                 exit_on_disconnect);
 void               dbus_connection_flush                        (DBusConnection             *connection);
 DBusMessage*       dbus_connection_borrow_message               (DBusConnection             *connection);
 void               dbus_connection_return_message               (DBusConnection             *connection,
@@ -104,7 +116,7 @@
                                                                  dbus_uint32_t              *client_serial);
 dbus_bool_t        dbus_connection_send_with_reply              (DBusConnection             *connection,
                                                                  DBusMessage                *message,
-                                                                 DBusMessageHandler         *reply_handler,
+                                                                 DBusPendingCall           **pending_return,
                                                                  int                         timeout_milliseconds);
 DBusMessage *      dbus_connection_send_with_reply_and_block    (DBusConnection             *connection,
                                                                  DBusMessage                *message,
@@ -156,22 +168,18 @@
 dbus_bool_t dbus_timeout_handle       (DBusTimeout      *timeout);
 dbus_bool_t dbus_timeout_get_enabled  (DBusTimeout      *timeout);
 
-/* Handlers */
-dbus_bool_t dbus_connection_add_filter         (DBusConnection      *connection,
-                                                DBusMessageHandler  *handler);
-void        dbus_connection_remove_filter      (DBusConnection      *connection,
-                                                DBusMessageHandler  *handler);
+/* Filters */
 
-dbus_bool_t dbus_connection_register_handler   (DBusConnection      *connection,
-                                                DBusMessageHandler  *handler,
-                                                const char         **messages_to_handle,
-                                                int                  n_messages);
-void        dbus_connection_unregister_handler (DBusConnection      *connection,
-                                                DBusMessageHandler  *handler,
-                                                const char         **messages_to_handle,
-                                                int                  n_messages);
+dbus_bool_t dbus_connection_add_filter    (DBusConnection            *connection,
+                                           DBusHandleMessageFunction  function,
+                                           void                      *user_data,
+                                           DBusFreeFunction           free_data_function);
+void        dbus_connection_remove_filter (DBusConnection            *connection,
+                                           DBusHandleMessageFunction  function,
+                                           void                      *user_data);
 
 
+/* Other */
 dbus_bool_t dbus_connection_allocate_data_slot (dbus_int32_t     *slot_p);
 void        dbus_connection_free_data_slot     (dbus_int32_t     *slot_p);
 dbus_bool_t dbus_connection_set_data           (DBusConnection   *connection,
@@ -200,6 +208,44 @@
                                                               dbus_uint32_t        *client_serial);
 
 
+/* Object tree functionality */
+
+typedef void              (* DBusObjectPathUnregisterFunction) (DBusConnection  *connection,
+                                                                void            *user_data);
+typedef DBusHandlerResult (* DBusObjectPathMessageFunction)    (DBusConnection  *connection,
+                                                                DBusMessage     *message,
+                                                                void            *user_data);
+
+/**
+ * Virtual table that must be implemented to handle a portion of the
+ * object path hierarchy.
+ */
+struct DBusObjectPathVTable
+{
+  DBusObjectPathUnregisterFunction   unregister_function; /**< Function to unregister this handler */
+  DBusObjectPathMessageFunction      message_function; /**< Function to handle messages */
+  
+  void (* dbus_internal_pad1) (void *); /**< Reserved for future expansion */
+  void (* dbus_internal_pad2) (void *); /**< Reserved for future expansion */
+  void (* dbus_internal_pad3) (void *); /**< Reserved for future expansion */
+  void (* dbus_internal_pad4) (void *); /**< Reserved for future expansion */
+};
+
+dbus_bool_t dbus_connection_register_object_path   (DBusConnection              *connection,
+                                                    const char                 **path,
+                                                    const DBusObjectPathVTable  *vtable,
+                                                    void                        *user_data);
+dbus_bool_t dbus_connection_register_fallback      (DBusConnection              *connection,
+                                                    const char                 **path,
+                                                    const DBusObjectPathVTable  *vtable,
+                                                    void                        *user_data);
+void        dbus_connection_unregister_object_path (DBusConnection              *connection,
+                                                    const char                 **path);
+
+dbus_bool_t dbus_connection_list_registered        (DBusConnection              *connection,
+                                                    const char                 **parent_path,
+                                                    char                      ***child_entries);
+
 DBUS_END_DECLS;
 
 #endif /* DBUS_CONNECTION_H */

Index: dbus-dataslot.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-dataslot.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- dbus-dataslot.h	22 Jun 2003 19:39:47 -0000	1.3
+++ dbus-dataslot.h	30 Sep 2003 02:32:52 -0000	1.4
@@ -40,12 +40,18 @@
 };
 
 typedef struct DBusAllocatedSlot DBusAllocatedSlot;
+
+/** An allocated slot for storing data
+ */
 struct DBusAllocatedSlot
 {
   dbus_int32_t slot_id;  /**< ID of this slot */
   int          refcount; /**< Number of uses of the slot */
 };
 
+/**
+ * An allocator that tracks a set of slot IDs.
+ */
 struct DBusDataSlotAllocator
 {
   DBusAllocatedSlot *allocated_slots; /**< Allocated slots */
@@ -54,6 +60,10 @@
   DBusMutex *lock;        /**< thread lock */
 };
 
+/**
+ * Data structure that stores the actual user data set at a given
+ * slot.
+ */
 struct DBusDataSlotList
 {
   DBusDataSlot *slots;   /**< Data slots */

Index: dbus-errors.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-errors.c,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -d -r1.21 -r1.22
--- dbus-errors.c	29 Apr 2003 22:57:13 -0000	1.21
+++ dbus-errors.c	30 Sep 2003 02:32:52 -0000	1.22
@@ -23,53 +23,26 @@
  */
 #include "dbus-errors.h"
 #include "dbus-internals.h"
+#include "dbus-string.h"
 #include <stdarg.h>
-#include <stdio.h>
 #include <string.h>
 
 /**
- * @defgroup DBusErrors Error reporting
- * @ingroup  DBus
- * @brief Error reporting
- *
- * Types and functions related to reporting errors.
- *
- *
- * In essence D-BUS error reporting works as follows:
- *
- * @code
- * DBusError error;
- * dbus_error_init (&error);
- * dbus_some_function (arg1, arg2, &error);
- * if (dbus_error_is_set (&error))
- *   {
- *     fprintf (stderr, "an error occurred: %s\n", error.message);
- *     dbus_error_free (&error);
- *   }
- * @endcode
- *
- * There are some rules. An error passed to a D-BUS function must
- * always be unset; you can't pass in an error that's already set.  If
- * a function has a return code indicating whether an error occurred,
- * and also a #DBusError parameter, then the error will always be set
- * if and only if the return code indicates an error occurred. i.e.
- * the return code and the error are never going to disagree.
- *
- * An error only needs to be freed if it's been set, not if
- * it's merely been initialized.
- *
- * You can check the specific error that occurred using
- * dbus_error_has_name().
- * 
+ * @defgroup DBusErrorInternals Error reporting internals
+ * @ingroup  DBusInternals
+ * @brief Error reporting internals
  * @{
  */
-
+ 
+/**
+ * Internals of DBusError
+ */
 typedef struct
 {
   const char *name; /**< error name */
   char *message; /**< error message */
 
-  unsigned int const_message : 1; /** Message is not owned by DBusError */
+  unsigned int const_message : 1; /**< Message is not owned by DBusError */
 
   unsigned int dummy2 : 1; /**< placeholder */
   unsigned int dummy3 : 1; /**< placeholder */
@@ -127,6 +100,45 @@
     return error;
 }
 
+/** @} */ /* End of internals */
+
+/**
+ * @defgroup DBusErrors Error reporting
+ * @ingroup  DBus
+ * @brief Error reporting
+ *
+ * Types and functions related to reporting errors.
+ *
+ *
+ * In essence D-BUS error reporting works as follows:
+ *
+ * @code
+ * DBusError error;
+ * dbus_error_init (&error);
+ * dbus_some_function (arg1, arg2, &error);
+ * if (dbus_error_is_set (&error))
+ *   {
+ *     fprintf (stderr, "an error occurred: %s\n", error.message);
+ *     dbus_error_free (&error);
+ *   }
+ * @endcode
+ *
+ * There are some rules. An error passed to a D-BUS function must
+ * always be unset; you can't pass in an error that's already set.  If
+ * a function has a return code indicating whether an error occurred,
+ * and also a #DBusError parameter, then the error will always be set
+ * if and only if the return code indicates an error occurred. i.e.
+ * the return code and the error are never going to disagree.
+ *
+ * An error only needs to be freed if it's been set, not if
+ * it's merely been initialized.
+ *
+ * You can check the specific error that occurred using
+ * dbus_error_has_name().
+ * 
+ * @{
+ */
+
 /**
  * Initializes a DBusError structure. Does not allocate
  * any memory; the error only needs to be freed
@@ -292,9 +304,6 @@
  *
  * @todo should be called dbus_error_set()
  *
- * @todo stdio.h shouldn't be included in this file,
- * should write _dbus_string_append_printf instead
- * 
  * @param error the error.
  * @param name the error name (not copied!!!)
  * @param format printf-style format string.
@@ -306,11 +315,9 @@
 		...)
 {
   DBusRealError *real;
+  DBusString str;
   va_list args;
-  int message_length;
-  char *message;
-  char c;
-
+  
   if (error == NULL)
     return;
 
@@ -321,31 +328,46 @@
   _dbus_assert (error->name == NULL);
   _dbus_assert (error->message == NULL);
 
-  if (format == NULL)
-    format = message_from_error (name);
-  
-  va_start (args, format);
-  /* Measure the message length */
-  message_length = vsnprintf (&c, 1, format, args) + 1;
-  va_end (args);
-  
-  message = dbus_malloc (message_length);
+  if (!_dbus_string_init (&str))
+    goto nomem;
   
-  if (!message)
+  if (format == NULL)
     {
-      dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL);
-      return;
+      if (!_dbus_string_append (&str,
+                                message_from_error (name)))
+        {
+          _dbus_string_free (&str);
+          goto nomem;
+        }
+    }
+  else
+    {
+      va_start (args, format);
+      if (!_dbus_string_append_printf_valist (&str, format, args))
+        {
+          _dbus_string_free (&str);
+          goto nomem;
+        }
+      va_end (args);
     }
-  
-  va_start (args, format);  
-  vsprintf (message, format, args);  
-  va_end (args);
 
   real = (DBusRealError *)error;
+
+  if (!_dbus_string_steal_data (&str, &real->message))
+    {
+      _dbus_string_free (&str);
+      goto nomem;
+    }
   
   real->name = name;
-  real->message = message;
   real->const_message = FALSE;
+
+  _dbus_string_free (&str);
+
+  return;
+  
+ nomem:
+  dbus_set_error_const (error, DBUS_ERROR_NO_MEMORY, NULL);      
 }
 
-/** @} */
+/** @} */ /* End public API */

Index: dbus-errors.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-errors.h,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- dbus-errors.h	5 Apr 2003 19:03:40 -0000	1.19
+++ dbus-errors.h	30 Sep 2003 02:32:52 -0000	1.20
@@ -35,6 +35,9 @@
 
 typedef struct DBusError DBusError;
 
+/**
+ * Object representing an exception.
+ */
 struct DBusError
 {
   const char *name;    /**< error name */
@@ -50,13 +53,8 @@
 };
 
 #define DBUS_ERROR_FAILED                     "org.freedesktop.DBus.Error.Failed"
-#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Activate.ServiceNotFound"
-#define DBUS_ERROR_SPAWN_EXEC_FAILED          "org.freedesktop.DBus.Error.Spawn.ExecFailed"
-#define DBUS_ERROR_SPAWN_FORK_FAILED          "org.freedesktop.DBus.Error.Spawn.ForkFailed"
-#define DBUS_ERROR_SPAWN_CHILD_EXITED         "org.freedesktop.DBus.Error.Spawn.ChildExited"
-#define DBUS_ERROR_SPAWN_CHILD_SIGNALED       "org.freedesktop.DBus.Error.Spawn.ChildSignaled"
-#define DBUS_ERROR_SPAWN_FAILED               "org.freedesktop.DBus.Error.Spawn.Failed"
 #define DBUS_ERROR_NO_MEMORY                  "org.freedesktop.DBus.Error.NoMemory"
+#define DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND "org.freedesktop.DBus.Error.ServiceNotFound"
 #define DBUS_ERROR_SERVICE_DOES_NOT_EXIST     "org.freedesktop.DBus.Error.ServiceDoesNotExist"
 #define DBUS_ERROR_NO_REPLY                   "org.freedesktop.DBus.Error.NoReply"
 #define DBUS_ERROR_IO_ERROR                   "org.freedesktop.DBus.Error.IOError"
@@ -72,8 +70,14 @@
 #define DBUS_ERROR_DISCONNECTED               "org.freedesktop.DBus.Error.Disconnected"
 #define DBUS_ERROR_INVALID_ARGS               "org.freedesktop.DBus.Error.InvalidArgs"
 #define DBUS_ERROR_FILE_NOT_FOUND             "org.freedesktop.DBus.Error.FileNotFound"
-#define DBUS_ERROR_UNKNOWN_MESSAGE            "org.freedesktop.DBus.Error.UnknownMessage"
+#define DBUS_ERROR_UNKNOWN_METHOD             "org.freedesktop.DBus.Error.UnknownMethod"
 #define DBUS_ERROR_TIMED_OUT                  "org.freedesktop.DBus.Error.TimedOut"
+#define DBUS_ERROR_MATCH_RULE_NOT_FOUND       "org.freedesktop.DBus.Error.MatchRuleNotFound"
+#define DBUS_ERROR_SPAWN_EXEC_FAILED          "org.freedesktop.DBus.Error.Spawn.ExecFailed"
+#define DBUS_ERROR_SPAWN_FORK_FAILED          "org.freedesktop.DBus.Error.Spawn.ForkFailed"
+#define DBUS_ERROR_SPAWN_CHILD_EXITED         "org.freedesktop.DBus.Error.Spawn.ChildExited"
+#define DBUS_ERROR_SPAWN_CHILD_SIGNALED       "org.freedesktop.DBus.Error.Spawn.ChildSignaled"
+#define DBUS_ERROR_SPAWN_FAILED               "org.freedesktop.DBus.Error.Spawn.Failed"
 
 void        dbus_error_init      (DBusError       *error);
 void        dbus_error_free      (DBusError       *error);

Index: dbus-hash.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-hash.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- dbus-hash.c	5 May 2003 03:13:35 -0000	1.14
+++ dbus-hash.c	30 Sep 2003 02:32:52 -0000	1.15
@@ -221,26 +221,32 @@
   int n_entries_on_init;     /**< used to detect table resize since initialization */
 } DBusRealHashIter;
 
-static DBusHashEntry* find_direct_function (DBusHashTable          *table,
-                                            void                   *key,
-                                            dbus_bool_t             create_if_not_found,
-                                            DBusHashEntry        ***bucket,
-                                            DBusPreallocatedHash   *preallocated);
-static DBusHashEntry* find_string_function (DBusHashTable          *table,
-                                            void                   *key,
-                                            dbus_bool_t             create_if_not_found,
-                                            DBusHashEntry        ***bucket,
-                                            DBusPreallocatedHash   *preallocated);
-static unsigned int   string_hash          (const char             *str);
-static void           rebuild_table        (DBusHashTable          *table);
-static DBusHashEntry* alloc_entry          (DBusHashTable          *table);
-static void           remove_entry         (DBusHashTable          *table,
-                                            DBusHashEntry         **bucket,
-                                            DBusHashEntry          *entry);
-static void           free_entry           (DBusHashTable          *table,
-                                            DBusHashEntry          *entry);
-static void           free_entry_data      (DBusHashTable          *table,
-                                            DBusHashEntry          *entry);
+static DBusHashEntry* find_direct_function      (DBusHashTable          *table,
+                                                 void                   *key,
+                                                 dbus_bool_t             create_if_not_found,
+                                                 DBusHashEntry        ***bucket,
+                                                 DBusPreallocatedHash   *preallocated);
+static DBusHashEntry* find_string_function      (DBusHashTable          *table,
+                                                 void                   *key,
+                                                 dbus_bool_t             create_if_not_found,
+                                                 DBusHashEntry        ***bucket,
+                                                 DBusPreallocatedHash   *preallocated);
+static DBusHashEntry* find_two_strings_function (DBusHashTable          *table,
+                                                 void                   *key,
+                                                 dbus_bool_t             create_if_not_found,
+                                                 DBusHashEntry        ***bucket,
+                                                 DBusPreallocatedHash   *preallocated);
+static unsigned int   string_hash               (const char             *str);
+static unsigned int   two_strings_hash          (const char             *str);
+static void           rebuild_table             (DBusHashTable          *table);
+static DBusHashEntry* alloc_entry               (DBusHashTable          *table);
+static void           remove_entry              (DBusHashTable          *table,
+                                                 DBusHashEntry         **bucket,
+                                                 DBusHashEntry          *entry);
+static void           free_entry                (DBusHashTable          *table,
+                                                 DBusHashEntry          *entry);
+static void           free_entry_data           (DBusHashTable          *table,
+                                                 DBusHashEntry          *entry);
 
 
 /** @} */
@@ -323,6 +329,9 @@
     case DBUS_HASH_STRING:
       table->find_function = find_string_function;
       break;
+    case DBUS_HASH_TWO_STRINGS:
+      table->find_function = find_two_strings_function;
+      break;
     default:
       _dbus_assert_not_reached ("Unknown hash table type");
       break;
@@ -685,6 +694,24 @@
 }
 
 /**
+ * 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;
+}
+
+/**
  * A low-level but efficient interface for manipulating the hash
  * table.  It's efficient because you can get, set, and optionally
  * create the hash entry while only running the hash function one
@@ -803,64 +830,64 @@
   return entry;
 }
 
+/* This is g_str_hash from GLib which was
+ * extensively discussed/tested/profiled
+ */
 static unsigned int
 string_hash (const char *str)
 {
-  register unsigned int result;
-  register int c;
+  const char *p = str;
+  unsigned int h = *p;
 
-  /*
-   * I tried a zillion different hash functions and asked many other
-   * people for advice.  Many people had their own favorite functions,
-   * all different, but no-one had much idea why they were good ones.
-   * I chose the one below (multiply by 9 and add new character)
-   * because of the following reasons:
-   *
-   * 1. Multiplying by 10 is perfect for keys that are decimal strings,
-   *    and multiplying by 9 is just about as good.
-   * 2. Times-9 is (shift-left-3) plus (old).  This means that each
-   *    character's bits hang around in the low-order bits of the
-   *    hash value for ever, plus they spread fairly rapidly up to
-   *    the high-order bits to fill out the hash value.  This seems
-   *    works well both for decimal and non-decimal strings.
-   */
+  if (h)
+    for (p += 1; *p != '\0'; p++)
+      h = (h << 5) - h + *p;
 
-  /* FIXME the hash function in GLib is better than this one */
-  
-  result = 0;
-  while (TRUE)
-    {
-      c = *str;
-      str++;
-      if (c == 0)
-        break;
-      
-      result += (result << 3) + c;
-    }
+  return h;
+}
+
+/* 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 result;
+  return h;
 }
 
+/** Key comparison function */
+typedef int (* KeyCompareFunc) (const void *key_a, const void *key_b);
+
 static DBusHashEntry*
-find_string_function (DBusHashTable        *table,
-                      void                 *key,
-                      dbus_bool_t           create_if_not_found,
-                      DBusHashEntry      ***bucket,
-                      DBusPreallocatedHash *preallocated)
+find_generic_function (DBusHashTable        *table,
+                       void                 *key,
+                       unsigned int          idx,
+                       KeyCompareFunc        compare_func,
+                       dbus_bool_t           create_if_not_found,
+                       DBusHashEntry      ***bucket,
+                       DBusPreallocatedHash *preallocated)
 {
   DBusHashEntry *entry;
-  unsigned int idx;
 
   if (bucket)
     *bucket = NULL;
-  
-  idx = string_hash (key) & table->mask;
 
   /* Search all of the entries in this bucket. */
   entry = table->buckets[idx];
   while (entry != NULL)
     {
-      if (strcmp (key, entry->key) == 0)
+      if ((compare_func == NULL && key == entry->key) ||
+          (compare_func != NULL && (* compare_func) (key, entry->key) == 0))
         {
           if (bucket)
             *bucket = &(table->buckets[idx]);
@@ -878,50 +905,75 @@
     entry = add_entry (table, idx, key, bucket, preallocated);
   else if (preallocated)
     _dbus_hash_table_free_preallocated_entry (table, preallocated);
-
+  
   return entry;
 }
 
 static DBusHashEntry*
-find_direct_function (DBusHashTable        *table,
+find_string_function (DBusHashTable        *table,
                       void                 *key,
                       dbus_bool_t           create_if_not_found,
                       DBusHashEntry      ***bucket,
                       DBusPreallocatedHash *preallocated)
 {
-  DBusHashEntry *entry;
   unsigned int idx;
+  
+  idx = string_hash (key) & table->mask;
 
-  if (bucket)
-    *bucket = NULL;
+  return find_generic_function (table, key, idx,
+                                (KeyCompareFunc) strcmp, create_if_not_found, bucket,
+                                preallocated);
+}
+
+static int
+two_strings_cmp (const char *a,
+                 const char *b)
+{
+  size_t len_a;
+  size_t len_b;
+  int res;
   
-  idx = RANDOM_INDEX (table, key) & table->mask;
+  res = strcmp (a, b);
+  if (res != 0)
+    return res;
 
-  /* Search all of the entries in this bucket. */
-  entry = table->buckets[idx];
-  while (entry != NULL)
-    {
-      if (key == entry->key)
-        {
-          if (bucket)
-            *bucket = &(table->buckets[idx]);
+  len_a = strlen (a);
+  len_b = strlen (b);
 
-          if (preallocated)
-            _dbus_hash_table_free_preallocated_entry (table, preallocated);
-          
-          return entry;
-        }
-      
-      entry = entry->next;
-    }
+  return strcmp (a + len_a + 1, b + len_b + 1);
+}
 
-  /* Entry not found.  Add a new one to the bucket. */
-  if (create_if_not_found)
-    entry = add_entry (table, idx, key, bucket, preallocated);
-  else if (preallocated)
-    _dbus_hash_table_free_preallocated_entry (table, preallocated);
+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 entry;
+  return find_generic_function (table, key, idx,
+                                (KeyCompareFunc) two_strings_cmp, create_if_not_found, bucket,
+                                preallocated);
+}
+
+static DBusHashEntry*
+find_direct_function (DBusHashTable        *table,
+                      void                 *key,
+                      dbus_bool_t           create_if_not_found,
+                      DBusHashEntry      ***bucket,
+                      DBusPreallocatedHash *preallocated)
+{
+  unsigned int idx;
+  
+  idx = RANDOM_INDEX (table, key) & table->mask;
+
+
+  return find_generic_function (table, key, idx,
+                                NULL, create_if_not_found, bucket,
+                                preallocated);
 }
 
 static void
@@ -1021,6 +1073,9 @@
             case DBUS_HASH_STRING:
               idx = string_hash (entry->key) & table->mask;
               break;
+            case DBUS_HASH_TWO_STRINGS:
+              idx = two_strings_hash (entry->key) & table->mask;
+              break;
             case DBUS_HASH_INT:
             case DBUS_HASH_ULONG:
             case DBUS_HASH_POINTER:
@@ -1070,6 +1125,31 @@
 }
 
 /**
+ * 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;
+}
+
+/**
  * Looks up the value for a given integer in a hash table
  * of type #DBUS_HASH_INT. Returns %NULL if the value
  * is not present. (A not-present entry is indistinguishable
@@ -1184,6 +1264,34 @@
  * @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;
+}
+
+/**
+ * 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_int (DBusHashTable *table,
                              int            key)
 {
@@ -1312,6 +1420,47 @@
  * @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;
+}
+
+/**
+ * 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_int (DBusHashTable *table,
                              int            key,
                              void          *value)
@@ -1536,6 +1685,28 @@
   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
@@ -1548,6 +1719,7 @@
   DBusHashTable *table1;
   DBusHashTable *table2;
   DBusHashTable *table3;
+  DBusHashTable *table4;
   DBusHashIter iter;
 #define N_HASH_KEYS 5000
   char **keys;
@@ -1569,7 +1741,16 @@
   i = 0;
   while (i < N_HASH_KEYS)
     {
-      sprintf (keys[i], "Hash key %d", i); 
+      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");
@@ -1588,6 +1769,12 @@
                                  NULL, dbus_free);
   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
@@ -1624,10 +1811,22 @@
       if (!_dbus_hash_table_insert_ulong (table3,
                                           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);
@@ -1640,6 +1839,10 @@
       value = _dbus_hash_table_lookup_ulong (table3, i);
       _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;
     }
@@ -1654,9 +1857,13 @@
 
       _dbus_hash_table_remove_ulong (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;
     }
@@ -1664,12 +1871,15 @@
   _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

Index: dbus-hash.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-hash.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- dbus-hash.h	11 Apr 2003 00:03:06 -0000	1.9
+++ dbus-hash.h	30 Sep 2003 02:32:52 -0000	1.10
@@ -29,17 +29,17 @@
 
 DBUS_BEGIN_DECLS;
 
-/* The iterator is on the stack, but its real fields are
- * hidden privately.
+/** Hash iterator object. The iterator is on the stack, but its real
+ * fields are hidden privately.
  */
 struct DBusHashIter
 {
-  void *dummy1;
-  void *dummy2;
-  void *dummy3;
-  void *dummy4;
-  int   dummy5;
-  int   dummy6;
+  void *dummy1; /**< Do not use. */
+  void *dummy2; /**< Do not use. */
+  void *dummy3; /**< Do not use. */
+  void *dummy4; /**< Do not use. */
+  int   dummy5; /**< Do not use. */
+  int   dummy6; /**< Do not use. */
 };
 
 typedef struct DBusHashTable DBusHashTable;
@@ -52,61 +52,68 @@
  */
 typedef enum
 {
-  DBUS_HASH_STRING,  /**< Hash keys are strings. */
-  DBUS_HASH_INT,     /**< Hash keys are integers. */
-  DBUS_HASH_POINTER, /**< Hash keys are pointers. */
-  DBUS_HASH_ULONG    /**< Hash keys are unsigned long. */
+  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_ULONG          /**< Hash keys are unsigned long. */
 } DBusHashType;
-
-DBusHashTable* _dbus_hash_table_new            (DBusHashType      type,
-                                                DBusFreeFunction  key_free_function,
-                                                DBusFreeFunction  value_free_function);
-void           _dbus_hash_table_ref            (DBusHashTable    *table);
-void           _dbus_hash_table_unref          (DBusHashTable    *table);
-void           _dbus_hash_iter_init            (DBusHashTable    *table,
-                                                DBusHashIter     *iter);
-dbus_bool_t    _dbus_hash_iter_next            (DBusHashIter     *iter);
-void           _dbus_hash_iter_remove_entry    (DBusHashIter     *iter);
-void*          _dbus_hash_iter_get_value       (DBusHashIter     *iter);
-void           _dbus_hash_iter_set_value       (DBusHashIter     *iter,
-                                                void             *value);
-int            _dbus_hash_iter_get_int_key     (DBusHashIter     *iter);
-const char*    _dbus_hash_iter_get_string_key  (DBusHashIter     *iter);
-unsigned long  _dbus_hash_iter_get_ulong_key   (DBusHashIter     *iter);
-dbus_bool_t    _dbus_hash_iter_lookup          (DBusHashTable    *table,
-                                                void             *key,
-                                                dbus_bool_t       create_if_not_found,
-                                                DBusHashIter     *iter);
-void*          _dbus_hash_table_lookup_string  (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_ulong   (DBusHashTable    *table,
-                                                unsigned long     key);
-dbus_bool_t    _dbus_hash_table_remove_string  (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_ulong   (DBusHashTable    *table,
-                                                unsigned long     key);
-dbus_bool_t    _dbus_hash_table_insert_string  (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_ulong   (DBusHashTable    *table,
-                                                unsigned long     key,
-                                                void             *value);
-int            _dbus_hash_table_get_n_entries  (DBusHashTable    *table);
-
+DBusHashTable* _dbus_hash_table_new                (DBusHashType      type,
+                                                    DBusFreeFunction  key_free_function,
+                                                    DBusFreeFunction  value_free_function);
+void           _dbus_hash_table_ref                (DBusHashTable    *table);
+void           _dbus_hash_table_unref              (DBusHashTable    *table);
+void           _dbus_hash_iter_init                (DBusHashTable    *table,
+                                                    DBusHashIter     *iter);
+dbus_bool_t    _dbus_hash_iter_next                (DBusHashIter     *iter);
+void           _dbus_hash_iter_remove_entry        (DBusHashIter     *iter);
+void*          _dbus_hash_iter_get_value           (DBusHashIter     *iter);
+void           _dbus_hash_iter_set_value           (DBusHashIter     *iter,
+                                                    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);
+unsigned long  _dbus_hash_iter_get_ulong_key       (DBusHashIter     *iter);
+dbus_bool_t    _dbus_hash_iter_lookup              (DBusHashTable    *table,
+                                                    void             *key,
+                                                    dbus_bool_t       create_if_not_found,
+                                                    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_ulong       (DBusHashTable    *table,
+                                                    unsigned long     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_ulong       (DBusHashTable    *table,
+                                                    unsigned long     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_ulong       (DBusHashTable    *table,
+                                                    unsigned long     key,
+                                                    void             *value);
+int            _dbus_hash_table_get_n_entries      (DBusHashTable    *table);
 
 /* Preallocation */
 typedef struct DBusPreallocatedHash DBusPreallocatedHash;

Index: dbus-internals.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-internals.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- dbus-internals.c	9 Jun 2003 22:09:34 -0000	1.30
+++ dbus-internals.c	30 Sep 2003 02:32:52 -0000	1.31
@@ -248,7 +248,7 @@
 char*
 _dbus_strdup (const char *str)
 {
-  int len;
+  size_t len;
   char *copy;
   
   if (str == NULL)
@@ -266,6 +266,29 @@
 }
 
 /**
+ * Duplicates a block of memory. Returns
+ * #NULL on failure.
+ *
+ * @param mem memory to copy
+ * @param n_bytes number of bytes to copy
+ * @returns the copy
+ */
+void*
+_dbus_memdup (const void  *mem,
+              size_t       n_bytes)
+{
+  void *copy;
+
+  copy = dbus_malloc (n_bytes);
+  if (copy == NULL)
+    return NULL;
+
+  memcpy (copy, mem, n_bytes);
+  
+  return copy;
+}
+
+/**
  * Duplicates a string array. Result may be freed with
  * dbus_free_string_array(). Returns #NULL if memory allocation fails.
  * If the array to be duplicated is #NULL, returns #NULL.
@@ -366,7 +389,40 @@
     }
 }
 
+/**
+ * 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_SERVICE:
+      return "service";
+    case DBUS_HEADER_FIELD_SENDER_SERVICE:
+      return "sender-service";
+    default:
+      return "unknown";
+    }
+}
+
 #ifndef DBUS_DISABLE_CHECKS
+/** String used in _dbus_return_if_fail macro */
 const char _dbus_return_if_fail_warning_format[] =
 "Arguments to %s were incorrect, assertion \"%s\" failed in file %s line %d.\n"
 "This is normally a bug in some application using the D-BUS library.\n";

Index: dbus-internals.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-internals.h,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- dbus-internals.h	22 Jun 2003 20:46:17 -0000	1.36
+++ dbus-internals.h	30 Sep 2003 02:32:52 -0000	1.37
@@ -144,6 +144,8 @@
   ((void*)_DBUS_ALIGN_VALUE(this, boundary))
 
 char*       _dbus_strdup                (const char  *str);
+void*       _dbus_memdup                (const void  *mem,
+                                         size_t       n_bytes);
 dbus_bool_t _dbus_string_array_contains (const char **array,
                                          const char  *str);
 char**      _dbus_dup_string_array      (const char **array);
@@ -182,7 +184,8 @@
                                     int                  len);
 
 
-const char* _dbus_type_to_string (int type);
+const char* _dbus_type_to_string         (int type);
+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 ((error), DBUS_ERROR_NO_MEMORY, _dbus_no_memory_message)
@@ -228,10 +231,10 @@
 
 _DBUS_DECLARE_GLOBAL_LOCK (list);
 _DBUS_DECLARE_GLOBAL_LOCK (connection_slots);
+_DBUS_DECLARE_GLOBAL_LOCK (pending_call_slots);
 _DBUS_DECLARE_GLOBAL_LOCK (server_slots);
 _DBUS_DECLARE_GLOBAL_LOCK (message_slots);
 _DBUS_DECLARE_GLOBAL_LOCK (atomic);
-_DBUS_DECLARE_GLOBAL_LOCK (message_handler);
 _DBUS_DECLARE_GLOBAL_LOCK (bus);
 _DBUS_DECLARE_GLOBAL_LOCK (shutdown_funcs);
 _DBUS_DECLARE_GLOBAL_LOCK (system_users);

Index: dbus-keyring.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-keyring.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- dbus-keyring.c	5 May 2003 03:13:35 -0000	1.18
+++ dbus-keyring.c	30 Sep 2003 02:32:52 -0000	1.19
@@ -85,6 +85,9 @@
 #define MAX_KEYS_IN_FILE 256
 #endif
 
+/**
+ * A single key from the cookie file
+ */
 typedef struct
 {
   dbus_int32_t id; /**< identifier used to refer to the key */

Index: dbus-mainloop.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-mainloop.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- dbus-mainloop.c	28 Jun 2003 22:56:27 -0000	1.12
+++ dbus-mainloop.c	30 Sep 2003 02:32:52 -0000	1.13
@@ -23,10 +23,12 @@
 
 #include "dbus-mainloop.h"
 
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-sysdeps.h>
 
-#define MAINLOOP_SPEW 1
+#define MAINLOOP_SPEW 0
 
 struct DBusLoop
 {
@@ -876,3 +878,4 @@
   _dbus_sleep_milliseconds (_dbus_get_oom_wait ());
 }
 
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */

Index: dbus-mainloop.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-mainloop.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- dbus-mainloop.h	10 Apr 2003 05:12:19 -0000	1.3
+++ dbus-mainloop.h	30 Sep 2003 02:32:52 -0000	1.4
@@ -24,6 +24,8 @@
 #ifndef DBUS_MAINLOOP_H
 #define DBUS_MAINLOOP_H
 
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
 #include <dbus/dbus.h>
 
 typedef struct DBusLoop DBusLoop;
@@ -68,4 +70,7 @@
 int  _dbus_get_oom_wait    (void);
 void _dbus_wait_for_memory (void);
 
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
 #endif /* DBUS_MAINLOOP_H */
+

Index: dbus-marshal.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-marshal.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- dbus-marshal.c	28 Jun 2003 23:03:26 -0000	1.41
+++ dbus-marshal.c	30 Sep 2003 02:32:52 -0000	1.42
@@ -73,13 +73,17 @@
 }
 #endif /* !DBUS_HAVE_INT64 */
 
+/**
+ * Union used to manipulate 8 bytes as if they
+ * were various types. 
+ */
 typedef union
 {
 #ifdef DBUS_HAVE_INT64
-  dbus_int64_t  s;
-  dbus_uint64_t u;
+  dbus_int64_t  s; /**< 64-bit integer */
+  dbus_uint64_t u; /**< 64-bit unsinged integer */
 #endif
-  double d;
+  double d;        /**< double */
 } DBusOctets8;
 
 static DBusOctets8
@@ -98,7 +102,8 @@
     r.u = DBUS_UINT64_FROM_BE (*(dbus_uint64_t*)data);
 #else
   r.d = *(double*)data;
-  swap_bytes (&r, sizeof (r));
+  if (byte_order != DBUS_COMPILER_BYTE_ORDER)
+    swap_bytes ((unsigned char*) &r, sizeof (r));
 #endif
   
   return r;
@@ -390,6 +395,10 @@
  * an existing string or the wrong length will be deleted
  * and replaced with the new string.
  *
+ * Note: no attempt is made by this function to re-align
+ * any data which has been already marshalled after this
+ * string. Use with caution.
+ *
  * @param str the string to write the marshalled string to
  * @param offset the byte offset where string should be written
  * @param byte_order the byte order to use
@@ -423,6 +432,30 @@
   return TRUE;
 }
 
+/**
+ * Sets the existing marshaled object path at the given offset to a new
+ * value. The given offset must point to an existing object path or this
+ * function doesn't make sense.
+ *
+ * @todo implement this function
+ *
+ * @param str the string to write the marshalled path to
+ * @param offset the byte offset where path should be written
+ * @param byte_order the byte order to use
+ * @param path the new path
+ * @param path_len number of elements in the path
+ */
+void
+_dbus_marshal_set_object_path (DBusString         *str,
+                               int                 byte_order,
+                               int                 offset,
+                               const char        **path,
+                               int                 path_len)
+{
+
+  /* FIXME */
+}
+
 static dbus_bool_t
 marshal_4_octets (DBusString   *str,
                   int           byte_order,
@@ -682,7 +715,7 @@
 #ifdef DBUS_HAVE_INT64
           *((dbus_uint64_t*)d) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)d));
 #else
-          swap_bytes (d, 8);
+          swap_bytes ((unsigned char*) d, 8);
 #endif
           d += 8;
         }
@@ -844,6 +877,58 @@
   return FALSE;      
 }
 
+/**
+ * Marshals an object path value.
+ * 
+ * @param str the string to append the marshalled value to
+ * @param byte_order the byte order to use
+ * @param path the path
+ * @param path_len length of the path
+ * @returns #TRUE on success
+ */
+dbus_bool_t
+_dbus_marshal_object_path (DBusString            *str,
+                           int                    byte_order,
+                           const char           **path,
+                           int                    path_len)
+{
+  int array_start, old_string_len;
+  int i;
+  
+  old_string_len = _dbus_string_get_length (str);
+  
+  /* Set the length to 0 temporarily */
+  if (!_dbus_marshal_uint32 (str, byte_order, 0))
+    goto nomem;
+
+  array_start = _dbus_string_get_length (str);
+  
+  i = 0;
+  while (i < path_len)
+    {
+      if (!_dbus_string_append_byte (str, '/'))
+        goto nomem;
+      
+      if (!_dbus_string_append (str, path[0]))
+        goto nomem;
+
+      ++i;
+    }
+
+  /* Write the length now that we know it */
+  _dbus_marshal_set_uint32 (str, byte_order,
+			    _DBUS_ALIGN_VALUE (old_string_len, sizeof(dbus_uint32_t)),
+			    _dbus_string_get_length (str) - array_start);  
+
+  return TRUE;
+
+ nomem:
+  /* Restore the previous length */
+  _dbus_string_set_length (str, old_string_len);
+  
+  return FALSE;
+}
+
 static dbus_uint32_t
 demarshal_4_octets (const DBusString *str,
                     int               byte_order,
@@ -1174,7 +1259,7 @@
 #ifdef DBUS_HAVE_INT64
           retval[i].u = DBUS_UINT64_SWAP_LE_BE (retval[i].u);
 #else
-          swap_bytes (&retval[i], 8);
+          swap_bytes ((unsigned char *) &retval[i], 8);
 #endif
         }
     }
@@ -1393,6 +1478,105 @@
   return FALSE;
 }
 
+/** Set to 1 to get a bunch of spew about disassembling the path string */
+#define VERBOSE_DECOMPOSE 0
+
+/**
+ * Demarshals an object path.  A path of just "/" is
+ * represented as an empty vector of strings.
+ * 
+ * @param str the string containing the data
+ * @param byte_order the byte order
+ * @param pos the position in the string
+ * @param new_pos the new position of the string
+ * @param path address to store new object path
+ * @param path_len length of stored path
+ */
+dbus_bool_t
+_dbus_demarshal_object_path (const DBusString *str,
+                             int               byte_order,
+                             int               pos,
+                             int              *new_pos,
+                             char           ***path,
+                             int              *path_len)
+{
+  int len;
+  char **retval;
+  const char *data;
+  int n_components;
+  int i, j, comp;
+  
+  len = _dbus_demarshal_uint32 (str, byte_order, pos, &pos);
+  data = _dbus_string_get_const_data_len (str, pos, len + 1);
+  _dbus_assert (data != NULL);
+
+#if VERBOSE_DECOMPOSE
+  _dbus_verbose ("Decomposing path \"%s\"\n",
+                 data);
+#endif
+  
+  n_components = 0;
+  i = 0;
+  while (i < len)
+    {
+      if (data[i] == '/')
+        n_components += 1;
+      ++i;
+    }
+  
+  retval = dbus_new0 (char*, n_components + 1);
+
+  if (retval == NULL)
+    return FALSE;
+
+  comp = 0;
+  i = 0;
+  while (i < len)
+    {
+      if (data[i] == '/')
+        ++i;
+      j = i;
+
+      while (j < len && data[j] != '/')
+        ++j;
+
+      /* Now [i, j) is the path component */
+      _dbus_assert (i < j);
+      _dbus_assert (data[i] != '/');
+      _dbus_assert (j == len || data[j] == '/');
+
+#if VERBOSE_DECOMPOSE
+      _dbus_verbose ("  (component in [%d,%d))\n",
+                     i, j);
+#endif
+      
+      retval[comp] = _dbus_memdup (&data[i], j - i + 1);
+      if (retval[comp] == NULL)
+        {
+          dbus_free_string_array (retval);
+          return FALSE;
+        }
+      retval[comp][j-i] = '\0';
+#if VERBOSE_DECOMPOSE
+      _dbus_verbose ("  (component %d = \"%s\")\n",
+                     comp, retval[comp]);
+#endif
+
+      ++comp;
+      i = j;
+    }
+  _dbus_assert (i == len);
+  
+  *path = retval;
+  if (path_len)
+    *path_len = n_components;
+  
+  if (new_pos)
+    *new_pos = pos + len + 1;
+  
+  return TRUE;
+}
+
 /** 
  * Returns the position right after the end of an argument.  PERFORMS
  * NO VALIDATION WHATSOEVER. The message must have been previously
@@ -1435,32 +1619,18 @@
       break;
 
     case DBUS_TYPE_INT32:
-      *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
-
-      break;
-
     case DBUS_TYPE_UINT32:
-      *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t);
-
+      *end_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4;
       break;
 
-#ifdef DBUS_HAVE_INT64
     case DBUS_TYPE_INT64:
-      *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int64_t)) + sizeof (dbus_int64_t);
-
-      break;
-
     case DBUS_TYPE_UINT64:
-      *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint64_t)) + sizeof (dbus_uint64_t);
-
-      break;
-#endif /* DBUS_HAVE_INT64 */
-      
     case DBUS_TYPE_DOUBLE:
-      *end_pos = _DBUS_ALIGN_VALUE (pos, sizeof (double)) + sizeof (double);
-
+      
+      *end_pos = _DBUS_ALIGN_VALUE (pos, 8) + 8;
       break;
 
+    case DBUS_TYPE_OBJECT_PATH:
     case DBUS_TYPE_STRING:
       {
 	int len;
@@ -1664,6 +1834,7 @@
     case DBUS_TYPE_NIL:
       break;
 
+    case DBUS_TYPE_OBJECT_PATH:
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_NAMED:      
     case DBUS_TYPE_ARRAY:
@@ -1744,10 +1915,6 @@
  * returns #TRUE if a valid arg begins at "pos"
  *
  * @todo security: need to audit this function.
- *
- * @todo For array types that can't be invalid, we should not
- * walk the whole array validating it. e.g. just skip all the
- * int values in an int array.
  * 
  * @param str a string
  * @param byte_order the byte order to use
@@ -1842,21 +2009,7 @@
       break;
 
     case DBUS_TYPE_INT64:
-    case DBUS_TYPE_UINT64:
-      {
-        int align_8 = _DBUS_ALIGN_VALUE (pos, 8);
-        
-        if (!_dbus_string_validate_nul (str, pos,
-                                        align_8 - pos))
-          {
-            _dbus_verbose ("int64/uint64 alignment padding not initialized to nul\n");
-            return FALSE;
-          }
-
-        *end_pos = align_8 + 8;
-      }
-      break;
-      
+    case DBUS_TYPE_UINT64:      
     case DBUS_TYPE_DOUBLE:
       {
         int align_8 = _DBUS_ALIGN_VALUE (pos, 8);
@@ -1866,7 +2019,7 @@
         if (!_dbus_string_validate_nul (str, pos,
                                         align_8 - pos))
           {
-            _dbus_verbose ("double alignment padding not initialized to nul\n");
+            _dbus_verbose ("double/int64/uint64/objid alignment padding not initialized to nul\n");
             return FALSE;
           }
 
@@ -1874,6 +2027,7 @@
       }
       break;
 
+    case DBUS_TYPE_OBJECT_PATH:
     case DBUS_TYPE_STRING:
       {
 	int len;
@@ -1887,6 +2041,12 @@
 
         if (!validate_string (str, pos, len, end_pos))
           return FALSE;
+
+        if (type == DBUS_TYPE_OBJECT_PATH)
+          {
+            if (!_dbus_string_validate_path (str, pos, len))
+              return FALSE;
+          }
       }
       break;
 
@@ -2478,7 +2638,6 @@
   s = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, 0, NULL);
   _dbus_assert (strcmp (s, "Hello") == 0);
   dbus_free (s);
-
   
   _dbus_string_free (&str);
       

Index: dbus-marshal.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-marshal.h,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- dbus-marshal.h	23 Apr 2003 03:33:52 -0000	1.17
+++ dbus-marshal.h	30 Sep 2003 02:32:52 -0000	1.18
@@ -152,11 +152,17 @@
                                       int               offset,
                                       dbus_uint64_t     value);
 #endif /* DBUS_HAVE_INT64 */
-dbus_bool_t _dbus_marshal_set_string (DBusString       *str,
-                                      int               byte_order,
-                                      int               offset,
-                                      const DBusString *value,
-				      int               len);
+
+dbus_bool_t _dbus_marshal_set_string      (DBusString         *str,
+                                           int                 byte_order,
+                                           int                 offset,
+                                           const DBusString   *value,
+                                           int                 len);
+void        _dbus_marshal_set_object_path (DBusString         *str,
+                                           int                 byte_order,
+                                           int                 offset,
+                                           const char        **path,
+                                           int                 path_len);
 
 dbus_bool_t   _dbus_marshal_int32          (DBusString            *str,
 					    int                    byte_order,
@@ -208,6 +214,11 @@
 					    int                    byte_order,
 					    const char           **value,
 					    int                    len);
+dbus_bool_t   _dbus_marshal_object_path    (DBusString            *str,
+					    int                    byte_order,
+                                            const char           **path,
+                                            int                    path_len);
+
 double        _dbus_demarshal_double       (const DBusString      *str,
 					    int                    byte_order,
 					    int                    pos,
@@ -278,9 +289,12 @@
 					    int                   *new_pos,
 					    char                ***array,
 					    int                   *array_len);
-
-
-
+dbus_bool_t   _dbus_demarshal_object_path  (const DBusString      *str,
+					    int                    byte_order,
+					    int                    pos,
+                                            int                   *new_pos,
+                                            char                ***path,
+                                            int                   *path_len);
 
 dbus_bool_t _dbus_marshal_get_arg_end_pos (const DBusString *str,
                                            int               byte_order,

Index: dbus-md5.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-md5.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- dbus-md5.h	19 Feb 2003 03:18:54 -0000	1.1
+++ dbus-md5.h	30 Sep 2003 02:32:52 -0000	1.2
@@ -31,11 +31,14 @@
 
 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 */
+  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);

Index: dbus-message-builder.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-message-builder.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- dbus-message-builder.c	1 Jul 2003 20:21:35 -0000	1.18
+++ dbus-message-builder.c	30 Sep 2003 02:32:53 -0000	1.19
@@ -40,9 +40,12 @@
  * @{
  */
 
+/**
+ * Saved length
+ */
 typedef struct
 {
-  DBusString name;
+  DBusString name; /**< Name of the length */
   int start;  /**< Calculate length since here */
   int length; /**< length to write */
   int offset; /**< where to write it into the data */
@@ -265,6 +268,73 @@
   return TRUE;
 }
 
+static int
+message_type_from_string (const DBusString *str,
+                          int               start)
+{
+  const char *s;
+
+  s = _dbus_string_get_const_data_len (str, start,
+                                       _dbus_string_get_length (str) - start);
+
+  if (strncmp (s, "method_call", strlen ("method_call")) == 0)
+    return DBUS_MESSAGE_TYPE_METHOD_CALL;
+  else if (strncmp (s, "method_return", strlen ("method_return")) == 0)
+    return DBUS_MESSAGE_TYPE_METHOD_RETURN;
+  else if (strncmp (s, "signal", strlen ("signal")) == 0)
+    return DBUS_MESSAGE_TYPE_SIGNAL;
+  else if (strncmp (s, "error", strlen ("error")) == 0)
+    return DBUS_MESSAGE_TYPE_ERROR;
+  else if (strncmp (s, "invalid", strlen ("invalid")) == 0)
+    return DBUS_MESSAGE_TYPE_INVALID;
+  else
+    return -1;
+}
+
+static dbus_bool_t
+append_string_field (DBusString *dest,
+                     int         endian,
+                     int         field,
+                     int         type,
+                     const char *value)
+{
+  int len;
+  
+  if (!_dbus_string_append_byte (dest, field))
+    {
+      _dbus_warn ("couldn't append field name byte\n");
+      return FALSE;
+    }
+  
+  if (!_dbus_string_append_byte (dest, type))
+    {
+      _dbus_warn ("could not append typecode byte\n");
+      return FALSE;
+    }
+
+  len = strlen (value);
+
+  if (!_dbus_marshal_uint32 (dest, endian, len))
+    {
+      _dbus_warn ("couldn't append string length\n");
+      return FALSE;
+    }
+  
+  if (!_dbus_string_append (dest, value))
+    {
+      _dbus_warn ("couldn't append field value\n");
+      return FALSE;
+    }
+
+  if (!_dbus_string_append_byte (dest, 0))
+    {
+      _dbus_warn ("couldn't append string nul term\n");
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
 /**
  * Reads the given filename, which should be in "message description
  * language" (look at some examples), and builds up the message data
@@ -274,7 +344,8 @@
  * 
  * The file format is:
  * @code
- *   VALID_HEADER normal header; byte order, padding, header len, body len, serial
+ *   VALID_HEADER <type> normal header; byte order, type, padding, header len, body len, serial
+ *   REQUIRED_FIELDS add required fields with placeholder values
  *   BIG_ENDIAN switch to big endian
  *   LITTLE_ENDIAN switch to little endian
  *   OPPOSITE_ENDIAN switch to opposite endian
@@ -286,7 +357,7 @@
  *                     (or if no START_LENGTH, absolute length)
  *   LENGTH <name> inserts the saved length of the same name
  *   CHOP <N> chops last N bytes off the data
- *   FIELD_NAME <abcd> inserts 4-byte field name
+ *   HEADER_FIELD <fieldname> inserts a header field name byte
  *   TYPE <typename> inserts a typecode byte 
  * @endcode
  * 
@@ -299,6 +370,7 @@
  *   UINT64 <N> marshals a UINT64
  *   DOUBLE <N> marshals a double
  *   STRING 'Foo' marshals a string
+ *   OBJECT_PATH '/foo/bar' marshals an object path
  *   BYTE_ARRAY { 'a', 3, 4, 5, 6} marshals a BYTE array
  *   BOOLEAN_ARRAY { false, true, false} marshals a BOOLEAN array
  *   INT32_ARRAY { 3, 4, 5, 6} marshals an INT32 array
@@ -386,6 +458,13 @@
         {
           int i;
           DBusString name;
+          int message_type;
+
+          if (_dbus_string_get_length (&line) < (int) strlen ("VALID_HEADER "))
+            {
+              _dbus_warn ("no args to VALID_HEADER\n");
+              goto parse_failed;
+            }
           
           if (!_dbus_string_append_byte (dest, endian))
             {
@@ -393,8 +472,22 @@
               goto parse_failed;
             }
 
+          message_type = message_type_from_string (&line,
+                                                   strlen ("VALID_HEADER "));
+          if (message_type < 0)
+            {
+              _dbus_warn ("VALID_HEADER not followed by space then known message type\n");
+              goto parse_failed;
+            }
+          
+          if (!_dbus_string_append_byte (dest, message_type))
+            {
+              _dbus_warn ("could not append message type\n");
+              goto parse_failed;
+            }
+          
           i = 0;
-          while (i < 3)
+          while (i < 2)
             {
               if (!_dbus_string_append_byte (dest, '\0'))
                 {
@@ -424,6 +517,25 @@
             }
         }
       else if (_dbus_string_starts_with_c_str (&line,
+                                               "REQUIRED_FIELDS"))
+        {
+          if (!append_string_field (dest, endian,
+                                    DBUS_HEADER_FIELD_INTERFACE,
+                                    DBUS_TYPE_STRING,
+                                    "org.freedesktop.BlahBlahInterface"))
+            goto parse_failed;
+          if (!append_string_field (dest, endian,
+                                    DBUS_HEADER_FIELD_MEMBER,
+                                    DBUS_TYPE_STRING,
+                                    "BlahBlahMethod"))
+            goto parse_failed;
+          if (!append_string_field (dest, endian,
+                                    DBUS_HEADER_FIELD_PATH,
+                                    DBUS_TYPE_OBJECT_PATH,
+                                    "/blah/blah/path"))
+            goto parse_failed;
+        }
+      else if (_dbus_string_starts_with_c_str (&line,
                                                "BIG_ENDIAN"))
         {
           endian = DBUS_BIG_ENDIAN;
@@ -561,25 +673,42 @@
           PERFORM_UNALIGN (dest);
         }
       else if (_dbus_string_starts_with_c_str (&line,
-                                               "FIELD_NAME"))
+                                               "HEADER_FIELD"))
         {
+	  int field;
+
           _dbus_string_delete_first_word (&line);
 
-          if (_dbus_string_get_length (&line) != 4)
+          if (_dbus_string_starts_with_c_str (&line, "INVALID"))
+            field = DBUS_HEADER_FIELD_INVALID;
+          else if (_dbus_string_starts_with_c_str (&line, "PATH"))
+	    field = DBUS_HEADER_FIELD_PATH;
+          else if (_dbus_string_starts_with_c_str (&line, "INTERFACE"))
+	    field = DBUS_HEADER_FIELD_INTERFACE;
+          else if (_dbus_string_starts_with_c_str (&line, "MEMBER"))
+	    field = DBUS_HEADER_FIELD_MEMBER;
+          else if (_dbus_string_starts_with_c_str (&line, "ERROR_NAME"))
+	    field = DBUS_HEADER_FIELD_ERROR_NAME;
+          else if (_dbus_string_starts_with_c_str (&line, "REPLY_SERIAL"))
+	    field = DBUS_HEADER_FIELD_REPLY_SERIAL;
+          else if (_dbus_string_starts_with_c_str (&line, "SERVICE"))
+	    field = DBUS_HEADER_FIELD_SERVICE;
+          else if (_dbus_string_starts_with_c_str (&line, "SENDER_SERVICE"))
+	    field = DBUS_HEADER_FIELD_SENDER_SERVICE;
+	  else if (_dbus_string_starts_with_c_str (&line, "UNKNOWN"))
+	    field = 22; /* random unknown header field */
+          else
             {
-              _dbus_warn ("Field name must be four characters not \"%s\"\n",
-                          _dbus_string_get_const_data (&line));
+              _dbus_warn ("%s is not a valid header field name\n",
+			  _dbus_string_get_const_data (&line));
               goto parse_failed;
             }
 
-          if (unalign)
-            unalign = FALSE;
-          else
-            _dbus_string_align_length (dest, 4);
-          
-          if (!_dbus_string_copy (&line, 0, dest,
-                                  _dbus_string_get_length (dest)))
-            goto parse_failed;
+          if (!_dbus_string_append_byte (dest, field))
+	    {
+              _dbus_warn ("could not append header field name byte\n");
+	      goto parse_failed;
+	    }
         }
       else if (_dbus_string_starts_with_c_str (&line,
                                                "TYPE"))
@@ -604,6 +733,8 @@
             code = DBUS_TYPE_DOUBLE;
           else if (_dbus_string_starts_with_c_str (&line, "STRING"))
             code = DBUS_TYPE_STRING;
+          else if (_dbus_string_starts_with_c_str (&line, "OBJECT_PATH"))
+            code = DBUS_TYPE_OBJECT_PATH;
           else if (_dbus_string_starts_with_c_str (&line, "NAMED"))
             code = DBUS_TYPE_NAMED;
           else if (_dbus_string_starts_with_c_str (&line, "ARRAY"))
@@ -1226,6 +1357,36 @@
           
           PERFORM_UNALIGN (dest);
         }
+      else if (_dbus_string_starts_with_c_str (&line,
+                                               "OBJECT_PATH"))
+        {
+          SAVE_FOR_UNALIGN (dest, 4);
+          int size_offset;
+          int old_len;
+          
+          _dbus_string_delete_first_word (&line);
+          
+          size_offset = _dbus_string_get_length (dest);
+          size_offset = _DBUS_ALIGN_VALUE (size_offset, 4);
+          if (!_dbus_marshal_uint32 (dest, endian, 0))
+            {
+              _dbus_warn ("Failed to append string size\n");
+              goto parse_failed;
+            }
+
+          old_len = _dbus_string_get_length (dest);
+          if (!append_quoted_string (dest, &line, 0, NULL))
+            {
+              _dbus_warn ("Failed to append quoted string\n");
+              goto parse_failed;
+            }
+
+          _dbus_marshal_set_uint32 (dest, endian, size_offset,
+                                    /* subtract 1 for nul */
+                                    _dbus_string_get_length (dest) - old_len - 1);
+          
+          PERFORM_UNALIGN (dest);
+        }      
       else
         goto parse_failed;
       

Index: dbus-message.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-message.c,v
retrieving revision 1.103
retrieving revision 1.104
diff -u -d -r1.103 -r1.104
--- dbus-message.c	23 Jul 2003 15:11:39 -0000	1.103
+++ dbus-message.c	30 Sep 2003 02:32:53 -0000	1.104
@@ -42,37 +42,31 @@
  * @{
  */
 
-enum
-{
-  FIELD_HEADER_LENGTH,
-  FIELD_BODY_LENGTH,
-  FIELD_CLIENT_SERIAL,
-  FIELD_NAME,
-  FIELD_SERVICE,
-  FIELD_SENDER,
-  FIELD_REPLY_SERIAL,
-
-  FIELD_LAST
-};
-
-static dbus_bool_t field_is_named[FIELD_LAST] =
-{
-  FALSE, /* FIELD_HEADER_LENGTH */
-  FALSE, /* FIELD_BODY_LENGTH */
-  FALSE, /* FIELD_CLIENT_SERIAL */
-  TRUE,  /* FIELD_NAME */
-  TRUE,  /* FIELD_SERVICE */
-  TRUE,  /* FIELD_SENDER */
-  TRUE   /* FIELD_REPLY_SERIAL */
-};
-
+/**
+ * Cached information about a header field in the message
+ */
 typedef struct
 {
-  int offset; /**< Offset to start of field (location of name of field
-               * for named fields)
-               */
+  int name_offset;  /**< Offset to name of field */
+  int value_offset; /**< Offset to value of field */
 } HeaderField;
 
+/** Offset to byte order from start of header */
+#define BYTE_ORDER_OFFSET    0
+/** Offset to type from start of header */
+#define TYPE_OFFSET          1
+/** Offset to flags from start of header */
+#define FLAGS_OFFSET         2
+/** Offset to version from start of header */
+#define VERSION_OFFSET       3
+/** Offset to header length from start of header */
+#define HEADER_LENGTH_OFFSET 4
+/** Offset to body length from start of header */
+#define BODY_LENGTH_OFFSET   8
+/** Offset to client serial from start of header */
+#define CLIENT_SERIAL_OFFSET 12
+
+
 /**
  * @brief Internals of DBusMessage
  * 
@@ -89,9 +83,9 @@
                       * independently realloc it.
                       */
 
-  HeaderField header_fields[FIELD_LAST]; /**< Track the location
-                                           * of each field in "header"
-                                           */
+  HeaderField header_fields[DBUS_HEADER_FIELD_LAST + 1]; /**< Track the location
+							  * of each field in "header"
+							  */
 
   dbus_uint32_t client_serial; /**< Cached client serial value for speed */
   dbus_uint32_t reply_serial;  /**< Cached reply serial value for speed */
@@ -188,26 +182,6 @@
   return TRUE;
 }
 
-static void
-adjust_field_offsets (DBusMessage *message,
-                      int          offsets_after,
-                      int          delta)
-{
-  int i;
-
-  if (delta == 0)
-    return;
-  
-  i = 0;
-  while (i < FIELD_LAST)
-    {
-      if (message->header_fields[i].offset > offsets_after)
-        message->header_fields[i].offset += delta;
-
-      ++i;
-    }
-}
-
 #ifdef DBUS_BUILD_TESTS
 /* tests-only until it's actually used */
 static dbus_int32_t
@@ -216,9 +190,9 @@
 {
   int offset;
 
-  _dbus_assert (field < FIELD_LAST);
+  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
   
-  offset = message->header_fields[field].offset;
+  offset = message->header_fields[field].value_offset;
   
   if (offset < 0)
     return -1; /* useless if -1 is a valid value of course */
@@ -236,9 +210,9 @@
 {
   int offset;
   
-  _dbus_assert (field < FIELD_LAST);
+  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
   
-  offset = message->header_fields[field].offset;
+  offset = message->header_fields[field].value_offset;
   
   if (offset < 0)
     return -1; /* useless if -1 is a valid value of course */
@@ -257,9 +231,9 @@
   int offset;
   const char *data;
 
-  offset = message->header_fields[field].offset;
+  offset = message->header_fields[field].value_offset;
 
-  _dbus_assert (field < FIELD_LAST);
+  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
   
   if (offset < 0)
     return NULL;
@@ -280,25 +254,45 @@
   return data + (offset + 4); 
 }
 
+/* returns FALSE if no memory, TRUE with NULL path if no field */
+static dbus_bool_t
+get_path_field_decomposed (DBusMessage  *message,
+                           int           field,
+                           char       ***path)
+{
+  int offset;
+
+  offset = message->header_fields[field].value_offset;
+
+  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
+  
+  if (offset < 0)
+    {
+      *path = NULL;
+      return TRUE;
+    }
+
+  return _dbus_demarshal_object_path (&message->header,
+                                      message->byte_order,
+                                      offset,
+                                      NULL,
+                                      path, NULL);
+}
+
 #ifdef DBUS_BUILD_TESTS
 static dbus_bool_t
 append_int_field (DBusMessage *message,
                   int          field,
-                  const char  *name,
                   int          value)
 {
-  int orig_len;
-
   _dbus_assert (!message->locked);
 
   clear_header_padding (message);
   
-  orig_len = _dbus_string_get_length (&message->header);
-  
-  if (!_dbus_string_align_length (&message->header, 4))
-    goto failed;  
+  message->header_fields[field].name_offset =
+    _dbus_string_get_length (&message->header);
   
-  if (!_dbus_string_append_len (&message->header, name, 4))
+  if (!_dbus_string_append_byte (&message->header, field))
     goto failed;
 
   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_INT32))
@@ -307,7 +301,7 @@
   if (!_dbus_string_align_length (&message->header, 4))
     goto failed;
   
-  message->header_fields[field].offset =
+  message->header_fields[field].value_offset =
     _dbus_string_get_length (&message->header);
   
   if (!_dbus_marshal_int32 (&message->header, message->byte_order,
@@ -320,8 +314,10 @@
   return TRUE;
   
  failed:
-  message->header_fields[field].offset = -1;
-  _dbus_string_set_length (&message->header, orig_len);
+  _dbus_string_set_length (&message->header,
+			   message->header_fields[field].name_offset);
+  message->header_fields[field].name_offset  = -1;
+  message->header_fields[field].value_offset = -1;
 
   /* this must succeed because it was allocated on function entry and
    * DBusString doesn't ever realloc smaller
@@ -335,21 +331,16 @@
 static dbus_bool_t
 append_uint_field (DBusMessage *message,
                    int          field,
-                   const char  *name,
-                   int          value)
+		   int          value)
 {
-  int orig_len;
-
   _dbus_assert (!message->locked);
 
   clear_header_padding (message);
   
-  orig_len = _dbus_string_get_length (&message->header);
-  
-  if (!_dbus_string_align_length (&message->header, 4))
-    goto failed;  
+  message->header_fields[field].name_offset =
+    _dbus_string_get_length (&message->header);
   
-  if (!_dbus_string_append_len (&message->header, name, 4))
+  if (!_dbus_string_append_byte (&message->header, field))
     goto failed;
 
   if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_UINT32))
@@ -358,7 +349,7 @@
   if (!_dbus_string_align_length (&message->header, 4))
     goto failed;
   
-  message->header_fields[field].offset =
+  message->header_fields[field].value_offset =
     _dbus_string_get_length (&message->header);
   
   if (!_dbus_marshal_uint32 (&message->header, message->byte_order,
@@ -371,8 +362,10 @@
   return TRUE;
   
  failed:
-  message->header_fields[field].offset = -1;
-  _dbus_string_set_length (&message->header, orig_len);
+  _dbus_string_set_length (&message->header,
+			   message->header_fields[field].name_offset);
+  message->header_fields[field].name_offset  = -1;
+  message->header_fields[field].value_offset = -1;
 
   /* this must succeed because it was allocated on function entry and
    * DBusString doesn't ever realloc smaller
@@ -385,30 +378,26 @@
 static dbus_bool_t
 append_string_field (DBusMessage *message,
                      int          field,
-                     const char  *name,
+                     int          type,
                      const char  *value)
 {
-  int orig_len;
-
   _dbus_assert (!message->locked);
 
   clear_header_padding (message);
   
-  orig_len = _dbus_string_get_length (&message->header);
-
-  if (!_dbus_string_align_length (&message->header, 4))
-    goto failed;
+  message->header_fields[field].name_offset =
+    _dbus_string_get_length (&message->header);
   
-  if (!_dbus_string_append_len (&message->header, name, 4))
+  if (!_dbus_string_append_byte (&message->header, field))
     goto failed;
   
-  if (!_dbus_string_append_byte (&message->header, DBUS_TYPE_STRING))
+  if (!_dbus_string_append_byte (&message->header, type))
     goto failed;
 
   if (!_dbus_string_align_length (&message->header, 4))
     goto failed;
   
-  message->header_fields[field].offset =
+  message->header_fields[field].value_offset =
     _dbus_string_get_length (&message->header);
   
   if (!_dbus_marshal_string (&message->header, message->byte_order,
@@ -421,8 +410,10 @@
   return TRUE;
   
  failed:
-  message->header_fields[field].offset = -1;
-  _dbus_string_set_length (&message->header, orig_len);
+  _dbus_string_set_length (&message->header,
+			   message->header_fields[field].name_offset);
+  message->header_fields[field].name_offset  = -1;
+  message->header_fields[field].value_offset = -1;
 
   /* this must succeed because it was allocated on function entry and
    * DBusString doesn't ever realloc smaller
@@ -433,73 +424,205 @@
   return FALSE;
 }
 
-#ifdef DBUS_BUILD_TESTS
-/* This isn't used, but building it when tests are enabled just to
- * keep it compiling if we need it in future
- */
-static void
-delete_int_or_uint_field (DBusMessage *message,
-                          int          field)
+static int
+get_next_field (DBusMessage *message,
+		int          field)
 {
-  int offset = message->header_fields[field].offset;
+  int offset = message->header_fields[field].name_offset;
+  int closest;
+  int i;
+  int retval = DBUS_HEADER_FIELD_INVALID;
 
-  _dbus_assert (!message->locked);
-  _dbus_assert (field_is_named[field]);
-  
-  if (offset < 0)
-    return;  
+  i = 0;
+  closest = _DBUS_INT_MAX;
+  while (i < DBUS_HEADER_FIELD_LAST)
+    {
+      if (message->header_fields[i].name_offset > offset &&
+	  message->header_fields[i].name_offset < closest)
+	{
+	  closest = message->header_fields[i].name_offset;
+	  retval = i;
+	}
+      ++i;
+    }
 
-  clear_header_padding (message);
-  
-  /* The field typecode and name take up 8 bytes */
-  _dbus_string_delete (&message->header,
-                       offset - 8,
-                       12);
+  return retval;
+}
 
-  message->header_fields[field].offset = -1;
-  
-  adjust_field_offsets (message,
-                        offset - 8,
-                        - 12);
+static dbus_bool_t
+re_align_field_recurse (DBusMessage *message,
+			int          field,
+			int          offset)
+{
+  int old_name_offset  = message->header_fields[field].name_offset;
+  int old_value_offset = message->header_fields[field].value_offset;
+  int prev_padding, padding, delta;
+  int type;
+  int next_field;
+  int pos = offset;
 
-  append_header_padding (message);
+  /* padding between the typecode byte and the value itself */
+  prev_padding = old_value_offset - old_name_offset + 2;
+
+  pos++;
+  type = _dbus_string_get_byte (&message->header, pos);
+
+  pos++;
+  switch (type)
+    {
+    case DBUS_TYPE_NIL:
+    case DBUS_TYPE_BYTE:
+    case DBUS_TYPE_BOOLEAN:
+      padding = 0;
+      break;
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_OBJECT_PATH:
+      padding = _DBUS_ALIGN_VALUE (pos, 4) - pos;
+      break;
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_UINT64:
+    case DBUS_TYPE_DOUBLE:
+      padding = _DBUS_ALIGN_VALUE (pos, 8) - pos;
+      break;
+    case DBUS_TYPE_NAMED:
+    case DBUS_TYPE_ARRAY:
+    case DBUS_TYPE_DICT:
+      _dbus_assert_not_reached ("no defined header fields may contain a named, array or dict value");
+      break;
+    case DBUS_TYPE_INVALID:
+    default:
+      _dbus_assert_not_reached ("invalid type in marshalled header");
+      break;
+    }
+
+  delta = padding - prev_padding;
+  if (delta > 0)
+    {
+      if (!_dbus_string_insert_bytes (&message->header, pos, delta, 0))
+	return FALSE;
+    }
+  else if (delta < 0)
+    {
+      _dbus_string_delete (&message->header, pos, -delta);
+    }
+
+  next_field = get_next_field (message, field);
+  if (next_field != DBUS_HEADER_FIELD_INVALID)
+    {
+      int next_offset = message->header_fields[next_field].name_offset;
+
+      _dbus_assert (next_offset > 0);
+
+      if (!re_align_field_recurse (message, field,
+				   pos + padding + (next_offset - old_value_offset)))
+	goto failed;
+    }
+  else
+    {
+      if (!append_header_padding (message))
+	goto failed;
+    }
+
+  message->header_fields[field].name_offset  = offset;
+  message->header_fields[field].value_offset = pos + padding;
+
+  return TRUE;
+
+ failed:
+  if (delta > 0)
+    {
+      _dbus_string_delete (&message->header, pos, delta);
+    }
+  else if (delta < 0)
+    {
+      /* this must succeed because it was allocated on function entry and
+       * DBusString doesn't ever realloc smaller
+       */
+    _dbus_string_insert_bytes (&message->header, pos, -delta, 0);
+    }
+
+  return FALSE;
 }
-#endif
 
-static void
-delete_string_field (DBusMessage *message,
-                     int          field)
+static dbus_bool_t
+delete_field (DBusMessage *message,
+	      int          field)
 {
-  int offset = message->header_fields[field].offset;
-  int len;
-  int delete_len;
-  
+  int offset = message->header_fields[field].name_offset;
+  int next_field;
+
   _dbus_assert (!message->locked);
-  _dbus_assert (field_is_named[field]);
   
   if (offset < 0)
-    return;
+    return FALSE;
 
   clear_header_padding (message);
-  
-  get_string_field (message, field, &len);
-  
-  /* The field typecode and name take up 8 bytes, and the nul
-   * termination is 1 bytes, string length integer is 4 bytes
-   */
-  delete_len = 8 + 4 + 1 + len;
-  
-  _dbus_string_delete (&message->header,
-                       offset - 8,
-                       delete_len);
 
-  message->header_fields[field].offset = -1;
-  
-  adjust_field_offsets (message,
-                        offset - 8,
-                        - delete_len);
+  next_field = get_next_field (message, field);
+  if (next_field == DBUS_HEADER_FIELD_INVALID)
+    {
+      _dbus_string_set_length (&message->header, offset);
 
-  append_header_padding (message);
+      message->header_fields[field].name_offset  = -1;
+      message->header_fields[field].value_offset = -1;
+      
+      /* this must succeed because it was allocated on function entry and
+       * DBusString doesn't ever realloc smaller
+       */
+      if (!append_header_padding (message))
+	_dbus_assert_not_reached ("failed to reappend header padding");
+
+      return TRUE;
+    }
+  else
+    {
+      DBusString deleted;
+      int next_offset = message->header_fields[next_field].name_offset;
+
+      _dbus_assert (next_offset > 0);
+
+      if (!_dbus_string_init (&deleted))
+	goto failed;
+
+      if (!_dbus_string_move_len (&message->header,
+				  offset, next_offset - offset,
+				  &deleted, 0))
+	{
+	  _dbus_string_free (&deleted);
+	  goto failed;
+	}
+
+      /* appends the header padding */
+      if (!re_align_field_recurse (message, next_field, offset))
+	{
+	  /* this must succeed because it was allocated on function entry and
+	   * DBusString doesn't ever realloc smaller
+	   */
+	  if (!_dbus_string_copy (&deleted, 0, &message->header, offset))
+	    _dbus_assert_not_reached ("failed to revert to original field");
+
+	  _dbus_string_free (&deleted);
+	  goto failed;
+	}
+
+      _dbus_string_free (&deleted);
+      
+      message->header_fields[field].name_offset  = -1;
+      message->header_fields[field].value_offset = -1;
+
+      return TRUE;
+
+    failed:
+      /* this must succeed because it was allocated on function entry and
+       * DBusString doesn't ever realloc smaller
+       */
+      if (!append_header_padding (message))
+	_dbus_assert_not_reached ("failed to reappend header padding");
+
+      return FALSE;
+    }
 }
 
 #ifdef DBUS_BUILD_TESTS
@@ -508,20 +631,14 @@
                int          field,
                int          value)
 {
-  int offset = message->header_fields[field].offset;
+  int offset = message->header_fields[field].value_offset;
 
   _dbus_assert (!message->locked);
   
   if (offset < 0)
     {
       /* need to append the field */
-
-      switch (field)
-        {
-        default:
-          _dbus_assert_not_reached ("appending an int field we don't support appending");
-          return FALSE;
-        }
+      return append_int_field (message, field, value);
     }
   else
     {
@@ -539,24 +656,14 @@
                 int           field,
                 dbus_uint32_t value)
 {
-  int offset = message->header_fields[field].offset;
+  int offset = message->header_fields[field].value_offset;
 
   _dbus_assert (!message->locked);
   
   if (offset < 0)
     {
       /* need to append the field */
-
-      switch (field)
-        {
-        case FIELD_REPLY_SERIAL:
-          return append_uint_field (message, field,
-                                    DBUS_HEADER_FIELD_REPLY,
-                                    value);
-        default:
-          _dbus_assert_not_reached ("appending a uint field we don't support appending");
-          return FALSE;
-        }
+      return append_uint_field (message, field, value);
     }
   else
     {
@@ -571,9 +678,10 @@
 static dbus_bool_t
 set_string_field (DBusMessage *message,
                   int          field,
+                  int          type,
                   const char  *value)
 {
-  int offset = message->header_fields[field].offset;
+  int offset = message->header_fields[field].value_offset;
 
   _dbus_assert (!message->locked);
   _dbus_assert (value != NULL);
@@ -581,48 +689,59 @@
   if (offset < 0)
     {      
       /* need to append the field */
-
-      switch (field)
-        {
-        case FIELD_SENDER:
-          return append_string_field (message, field,
-                                      DBUS_HEADER_FIELD_SENDER,
-                                      value);
-        default:
-          _dbus_assert_not_reached ("appending a string field we don't support appending");
-          return FALSE;
-        }
+      return append_string_field (message, field, type, value);
     }
   else
     {
       DBusString v;
-      int old_len;
-      int new_len;
+      char *old_value;
+      int next_field;
+      int next_offset;
       int len;
       
       clear_header_padding (message);
-      
-      old_len = _dbus_string_get_length (&message->header);
+
+      old_value = _dbus_demarshal_string (&message->header,
+					  message->byte_order,
+					  offset,
+					  &next_offset);
+      if (!old_value)
+	goto failed;
 
       len = strlen (value);
-      
+
       _dbus_string_init_const_len (&v, value,
 				   len + 1); /* include nul */
       if (!_dbus_marshal_set_string (&message->header,
                                      message->byte_order,
-                                     offset, &v,
-				     len))
-        goto failed;
-      
-      new_len = _dbus_string_get_length (&message->header);
+                                     offset, &v, len))
+	{
+	  dbus_free (old_value);
+	  goto failed;
+	}
 
-      adjust_field_offsets (message,
-                            offset,
-                            new_len - old_len);
+      next_field = get_next_field (message, field);
+      if (next_field != DBUS_HEADER_FIELD_INVALID)
+	{
+	  /* re-appends the header padding */
+	  if (!re_align_field_recurse (message, next_field, next_offset))
+	    {
+	      len = strlen (old_value);
+
+	      _dbus_string_init_const_len (&v, old_value,
+					  len + 1); /* include nul */
+	      if (!_dbus_marshal_set_string (&message->header,
+					     message->byte_order,
+					     offset, &v, len))
+		_dbus_assert_not_reached ("failed to revert to original string");
+
+	      dbus_free (old_value);
+	      goto failed;
+	    }
+	}
+
+      dbus_free (old_value);
 
-      if (!append_header_padding (message))
-	goto failed;
-      
       return TRUE;
 
     failed:
@@ -649,9 +768,12 @@
 {
   _dbus_assert (!message->locked);
   _dbus_assert (dbus_message_get_serial (message) == 0);
-  
-  set_uint_field (message, FIELD_CLIENT_SERIAL,
-                  serial);
+
+  _dbus_marshal_set_uint32 (&message->header,
+                            message->byte_order,
+                            CLIENT_SERIAL_OFFSET,
+			    serial);
+
   message->client_serial = serial;
 }
 
@@ -669,7 +791,8 @@
 {
   _dbus_assert (!message->locked);
 
-  if (set_uint_field (message, FIELD_REPLY_SERIAL,
+  if (set_uint_field (message,
+		      DBUS_HEADER_FIELD_REPLY_SERIAL,
                       reply_serial))
     {
       message->reply_serial = reply_serial;
@@ -803,14 +926,25 @@
 
 static dbus_bool_t
 dbus_message_create_header (DBusMessage *message,
-                            const char  *name,
-                            const char  *service)
+                            int          type,
+                            const char  *service,
+                            const char  *path,
+                            const char  *interface,
+                            const char  *member,
+                            const char  *error_name)
 {
   unsigned int flags;
+
+  _dbus_assert ((interface && member) ||
+                (error_name) ||
+                !(interface || member || error_name));
   
   if (!_dbus_string_append_byte (&message->header, message->byte_order))
     return FALSE;
 
+  if (!_dbus_string_append_byte (&message->header, type))
+    return FALSE;
+  
   flags = 0;
   if (!_dbus_string_append_byte (&message->header, flags))
     return FALSE;
@@ -818,37 +952,61 @@
   if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION))
     return FALSE;
 
-  if (!_dbus_string_append_byte (&message->header, 0))
-    return FALSE;
-
-  message->header_fields[FIELD_HEADER_LENGTH].offset = 4;
   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
     return FALSE;
 
-  message->header_fields[FIELD_BODY_LENGTH].offset = 8;
   if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0))
     return FALSE;
 
-  message->header_fields[FIELD_CLIENT_SERIAL].offset = 12;
   if (!_dbus_marshal_int32 (&message->header, message->byte_order, -1))
     return FALSE;
   
-  /* Marshal message service */
+  /* Marshal all the fields (Marshall Fields?) */
+  
+  if (path != NULL)
+    {
+      if (!append_string_field (message,
+                                DBUS_HEADER_FIELD_PATH,
+				DBUS_TYPE_OBJECT_PATH,
+                                path))
+        return FALSE;
+    }
+  
   if (service != NULL)
     {
       if (!append_string_field (message,
-                                FIELD_SERVICE,
                                 DBUS_HEADER_FIELD_SERVICE,
+				DBUS_TYPE_STRING,
                                 service))
         return FALSE;
     }
 
-  _dbus_assert (name != NULL);
-  if (!append_string_field (message,
-                            FIELD_NAME,
-                            DBUS_HEADER_FIELD_NAME,
-                            name))
-    return FALSE;
+  if (interface != NULL)
+    {
+      if (!append_string_field (message,
+                                DBUS_HEADER_FIELD_INTERFACE,
+				DBUS_TYPE_STRING,
+                                interface))
+        return FALSE;
+    }
+
+  if (member != NULL)
+    {
+      if (!append_string_field (message,
+                                DBUS_HEADER_FIELD_MEMBER,
+				DBUS_TYPE_STRING,
+                                member))
+        return FALSE;
+    }
+
+  if (error_name != NULL)
+    {
+      if (!append_string_field (message,
+                                DBUS_HEADER_FIELD_ERROR_NAME,
+				DBUS_TYPE_STRING,
+                                error_name))
+        return FALSE;
+    }
   
   return TRUE;
 }
@@ -868,13 +1026,15 @@
   if (!message->locked)
     {
       /* Fill in our lengths */
-      set_uint_field (message,
-                      FIELD_HEADER_LENGTH,
-                      _dbus_string_get_length (&message->header));
+      _dbus_marshal_set_uint32 (&message->header,
+				message->byte_order,
+				HEADER_LENGTH_OFFSET,
+				_dbus_string_get_length (&message->header));
 
-      set_uint_field (message,
-                      FIELD_BODY_LENGTH,
-                      _dbus_string_get_length (&message->body));
+      _dbus_marshal_set_uint32 (&message->header,
+				message->byte_order,
+				BODY_LENGTH_OFFSET,
+				_dbus_string_get_length (&message->body));
 
       message->locked = TRUE;
     }
@@ -920,9 +1080,10 @@
   _dbus_data_slot_list_init (&message->slot_list);
   
   i = 0;
-  while (i < FIELD_LAST)
+  while (i <= DBUS_HEADER_FIELD_LAST)
     {
-      message->header_fields[i].offset = -1;
+      message->header_fields[i].name_offset  = -1;
+      message->header_fields[i].value_offset = -1;
       ++i;
     }
   
@@ -942,31 +1103,71 @@
   return message;
 }
 
-
 /**
- * Constructs a new message. Returns #NULL if memory can't be
- * allocated for the message. The service may be #NULL in which case
- * no service is set; this is appropriate when using D-BUS in a
- * peer-to-peer context (no message bus).
+ * Constructs a new message of the given message type.
+ * Types include #DBUS_MESSAGE_TYPE_METHOD_CALL,
+ * #DBUS_MESSAGE_TYPE_SIGNAL, and so forth.
  *
- * @param name name of the message
- * @param destination_service service that the message should be sent to or #NULL
+ * @param message_type type of message
+ * @returns new message or #NULL If no memory
+ */
+DBusMessage*
+dbus_message_new (int message_type)
+{
+  DBusMessage *message;
+
+  _dbus_return_val_if_fail (message_type != DBUS_MESSAGE_TYPE_INVALID, NULL);
+  
+  message = dbus_message_new_empty_header ();
+  if (message == NULL)
+    return NULL;
+  
+  if (!dbus_message_create_header (message,
+                                   message_type,
+                                   NULL, NULL, NULL, NULL, NULL))
+    {
+      dbus_message_unref (message);
+      return NULL;
+    }
+  
+  return message;
+}
+
+/**
+ * Constructs a new message to invoke a method on a remote
+ * object. Returns #NULL if memory can't be allocated for the
+ * message. The service may be #NULL in which case no service is set;
+ * this is appropriate when using D-BUS in a peer-to-peer context (no
+ * message bus). The interface may be #NULL, which means that
+ * if multiple methods with the given name exist it is undefined
+ * which one will be invoked.
+  *
+ * @param service service that the message should be sent to or #NULL
+ * @param path object path the message should be sent to
+ * @param interface interface to invoke method on
+ * @param method method to invoke
+ * 
  * @returns a new DBusMessage, free with dbus_message_unref()
  * @see dbus_message_unref()
  */
 DBusMessage*
-dbus_message_new (const char *name,
-                  const char *destination_service)		  
+dbus_message_new_method_call (const char *service,
+                              const char *path,
+                              const char *interface,
+                              const char *method)
 {
   DBusMessage *message;
 
-  _dbus_return_val_if_fail (name != NULL, NULL);
+  _dbus_return_val_if_fail (path != NULL, NULL);
+  _dbus_return_val_if_fail (method != NULL, NULL);
   
   message = dbus_message_new_empty_header ();
   if (message == NULL)
     return NULL;
   
-  if (!dbus_message_create_header (message, name, destination_service))
+  if (!dbus_message_create_header (message,
+                                   DBUS_MESSAGE_TYPE_METHOD_CALL,
+                                   service, path, interface, method, NULL))
     {
       dbus_message_unref (message);
       return NULL;
@@ -976,37 +1177,42 @@
 }
 
 /**
- * Constructs a message that is a reply to some other
- * message. Returns #NULL if memory can't be allocated
- * for the message.
+ * Constructs a message that is a reply to a method call. Returns
+ * #NULL if memory can't be allocated for the message.
  *
- * @param original_message the message which the created
+ * @param method_call the message which the created
  * message is a reply to.
  * @returns a new DBusMessage, free with dbus_message_unref()
- * @see dbus_message_new(), dbus_message_unref()
+ * @see dbus_message_new_method_call(), dbus_message_unref()
  */ 
 DBusMessage*
-dbus_message_new_reply (DBusMessage *original_message)
+dbus_message_new_method_return (DBusMessage *method_call)
 {
   DBusMessage *message;
-  const char *sender, *name;
-
-  _dbus_return_val_if_fail (original_message != NULL, NULL);
-  
-  sender = get_string_field (original_message,
-                             FIELD_SENDER, NULL);
-  name = get_string_field (original_message,
-			   FIELD_NAME, NULL);
+  const char *sender;
 
-  /* sender is allowed to be null here in peer-to-peer case */
+  _dbus_return_val_if_fail (method_call != NULL, NULL);
   
-  message = dbus_message_new (name, sender);
+  sender = get_string_field (method_call,
+                             DBUS_HEADER_FIELD_SENDER_SERVICE,
+			     NULL);
   
+  /* sender is allowed to be null here in peer-to-peer case */
+
+  message = dbus_message_new_empty_header ();
   if (message == NULL)
     return NULL;
+  
+  if (!dbus_message_create_header (message,
+                                   DBUS_MESSAGE_TYPE_METHOD_RETURN,
+                                   sender, NULL, NULL, NULL, NULL))
+    {
+      dbus_message_unref (message);
+      return NULL;
+    }
 
   if (!dbus_message_set_reply_serial (message,
-                                      dbus_message_get_serial (original_message)))
+                                      dbus_message_get_serial (method_call)))
     {
       dbus_message_unref (message);
       return NULL;
@@ -1016,40 +1222,86 @@
 }
 
 /**
+ * Constructs a new message representing a signal emission. Returns
+ * #NULL if memory can't be allocated for the message.
+ * A signal is identified by its originating interface, and
+ * the name of the signal.
+ *
+ * @param path the path to the object emitting the signal
+ * @param interface the interface the signal is emitted from
+ * @param name name of the signal
+ * @returns a new DBusMessage, free with dbus_message_unref()
+ * @see dbus_message_unref()
+ */
+DBusMessage*
+dbus_message_new_signal (const char *path,
+                         const char *interface,
+                         const char *name)
+{
+  DBusMessage *message;
+
+  _dbus_return_val_if_fail (path != NULL, NULL);
+  _dbus_return_val_if_fail (interface != NULL, NULL);
+  _dbus_return_val_if_fail (name != NULL, NULL);
+  
+  message = dbus_message_new_empty_header ();
+  if (message == NULL)
+    return NULL;
+  
+  if (!dbus_message_create_header (message,
+                                   DBUS_MESSAGE_TYPE_SIGNAL,
+                                   NULL, path, interface, name, NULL))
+    {
+      dbus_message_unref (message);
+      return NULL;
+    }
+  
+  return message;
+}
+
+/**
  * Creates a new message that is an error reply to a certain message.
+ * Error replies are possible in response to method calls primarily.
  *
- * @param original_message the original message
+ * @param reply_to the original message
  * @param error_name the error name
  * @param error_message the error message string or #NULL for none
  * @returns a new error message
  */
 DBusMessage*
-dbus_message_new_error_reply (DBusMessage *original_message,
-			      const char  *error_name,
-			      const char  *error_message)
+dbus_message_new_error (DBusMessage *reply_to,
+                        const char  *error_name,
+                        const char  *error_message)
 {
   DBusMessage *message;
   const char *sender;
   DBusMessageIter iter;
 
-  _dbus_return_val_if_fail (original_message != NULL, NULL);
+  _dbus_return_val_if_fail (reply_to != NULL, NULL);
   _dbus_return_val_if_fail (error_name != NULL, NULL);
   
-  sender = get_string_field (original_message,
-                             FIELD_SENDER, NULL);
+  sender = get_string_field (reply_to,
+                             DBUS_HEADER_FIELD_SENDER_SERVICE,
+			     NULL);
 
   /* sender may be NULL for non-message-bus case or
    * when the message bus is dealing with an unregistered
    * connection.
    */
-  
-  message = dbus_message_new (error_name, sender);
-  
+  message = dbus_message_new_empty_header ();
   if (message == NULL)
     return NULL;
+  
+  if (!dbus_message_create_header (message,
+                                   DBUS_MESSAGE_TYPE_ERROR,
+                                   sender, NULL, NULL, NULL, error_name))
+    {
+      dbus_message_unref (message);
+      return NULL;
+    }
 
   if (!dbus_message_set_reply_serial (message,
-                                      dbus_message_get_serial (original_message)))
+                                      dbus_message_get_serial (reply_to)))
     {
       dbus_message_unref (message);
       return NULL;
@@ -1064,8 +1316,6 @@
           return NULL;
         }
     }
-
-  dbus_message_set_is_error (message, TRUE);
   
   return message;
 }
@@ -1129,9 +1379,9 @@
       return NULL;
     }
 
-  for (i = 0; i < FIELD_LAST; i++)
+  for (i = 0; i <= DBUS_HEADER_FIELD_LAST; i++)
     {
-      retval->header_fields[i].offset = message->header_fields[i].offset;
+      retval->header_fields[i] = message->header_fields[i];
     }
   
   return retval;
@@ -1201,17 +1451,268 @@
 }
 
 /**
- * Gets the name of a message.
+ * Gets the type of a message. Types include
+ * DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_METHOD_RETURN,
+ * DBUS_MESSAGE_TYPE_ERROR, DBUS_MESSAGE_TYPE_SIGNAL, but other types
+ * are allowed and all code must silently ignore messages of unknown
+ * type. DBUS_MESSAGE_TYPE_INVALID will never be returned, however.
+ *
  *
  * @param message the message
- * @returns the message name (should not be freed)
+ * @returns the type of the message
+ */
+int
+dbus_message_get_type (DBusMessage *message)
+{
+  int type;
+
+  type = _dbus_string_get_byte (&message->header, 1);
+  _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID);
+
+  return type;
+}
+
+/**
+ * Sets the object path this message is being sent to (for
+ * DBUS_MESSAGE_TYPE_METHOD_CALL) or the one a signal is being
+ * emitted from (for DBUS_MESSAGE_TYPE_SIGNAL).
+ *
+ * @param message the message
+ * @param object_path the path
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+dbus_message_set_path (DBusMessage   *message,
+                       const char    *object_path)
+{
+  _dbus_return_val_if_fail (message != NULL, FALSE);
+  _dbus_return_val_if_fail (!message->locked, FALSE);
+  
+  if (object_path == NULL)
+    {
+      delete_field (message, DBUS_HEADER_FIELD_PATH);
+      return TRUE;
+    }
+  else
+    {
+      return set_string_field (message,
+                               DBUS_HEADER_FIELD_PATH,
+                               DBUS_TYPE_OBJECT_PATH,
+                               object_path);
+    }
+}
+
+/**
+ * Gets the object path this message is being sent to
+ * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
+ * from (for DBUS_MESSAGE_TYPE_SIGNAL).
+ *
+ * @param message the message
+ * @returns the path (should not be freed)
  */
 const char*
-dbus_message_get_name (DBusMessage *message)
+dbus_message_get_path (DBusMessage   *message)
 {
   _dbus_return_val_if_fail (message != NULL, NULL);
   
-  return get_string_field (message, FIELD_NAME, NULL);
+  return get_string_field (message, DBUS_HEADER_FIELD_PATH, NULL);
+}
+
+/**
+ * Gets the object path this message is being sent to
+ * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
+ * from (for DBUS_MESSAGE_TYPE_SIGNAL) in a decomposed
+ * format (one array element per path component).
+ * Free the returned array with dbus_free_string_array().
+ *
+ * An empty but non-NULL path array means the path "/".
+ * So the path "/foo/bar" becomes { "foo", "bar", NULL }
+ * and the path "/" becomes { NULL }.
+ *
+ * @param message the message
+ * @param path place to store allocated array of path components; #NULL set here if no path field exists
+ * @returns #FALSE if no memory to allocate the array
+ */
+dbus_bool_t
+dbus_message_get_path_decomposed (DBusMessage   *message,
+                                  char        ***path)
+{
+  _dbus_return_val_if_fail (message != NULL, FALSE);
+  _dbus_return_val_if_fail (path != NULL, FALSE);
+
+  return get_path_field_decomposed (message,
+				    DBUS_HEADER_FIELD_PATH,
+                                    path);
+}
+
+/**
+ * Sets the interface this message is being sent to
+ * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or
+ * the interface a signal is being emitted from
+ * (for DBUS_MESSAGE_TYPE_SIGNAL).
+ *
+ * @param message the message
+ * @param interface the interface
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+dbus_message_set_interface (DBusMessage  *message,
+                            const char   *interface)
+{
+  _dbus_return_val_if_fail (message != NULL, FALSE);
+  _dbus_return_val_if_fail (!message->locked, FALSE);
+  
+  if (interface == NULL)
+    {
+      delete_field (message, DBUS_HEADER_FIELD_INTERFACE);
+      return TRUE;
+    }
+  else
+    {
+      return set_string_field (message,
+                               DBUS_HEADER_FIELD_INTERFACE,
+                               DBUS_TYPE_STRING,
+                               interface);
+    }
+}
+
+/**
+ * Gets the interface this message is being sent to
+ * (for DBUS_MESSAGE_TYPE_METHOD_CALL) or being emitted
+ * from (for DBUS_MESSAGE_TYPE_SIGNAL).
+ * The interface name is fully-qualified (namespaced).
+ *
+ * @param message the message
+ * @returns the message interface (should not be freed)
+ */
+const char*
+dbus_message_get_interface (DBusMessage *message)
+{
+  _dbus_return_val_if_fail (message != NULL, NULL);
+  
+  return get_string_field (message, DBUS_HEADER_FIELD_INTERFACE, NULL);
+}
+
+/**
+ * Sets the interface member being invoked
+ * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted
+ * (DBUS_MESSAGE_TYPE_SIGNAL).
+ * The interface name is fully-qualified (namespaced).
+ *
+ * @param message the message
+ * @param member the member
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+dbus_message_set_member (DBusMessage  *message,
+                       const char   *member)
+{
+  _dbus_return_val_if_fail (message != NULL, FALSE);
+  _dbus_return_val_if_fail (!message->locked, FALSE);
+  
+  if (member == NULL)
+    {
+      delete_field (message, DBUS_HEADER_FIELD_MEMBER);
+      return TRUE;
+    }
+  else
+    {
+      return set_string_field (message,
+                               DBUS_HEADER_FIELD_MEMBER,
+                               DBUS_TYPE_STRING,
+                               member);
+    }
+}
+
+/**
+ * Gets the interface member being invoked
+ * (DBUS_MESSAGE_TYPE_METHOD_CALL) or emitted
+ * (DBUS_MESSAGE_TYPE_SIGNAL).
+ * 
+ * @param message the message
+ * @returns the member name (should not be freed)
+ */
+const char*
+dbus_message_get_member (DBusMessage *message)
+{
+  _dbus_return_val_if_fail (message != NULL, NULL);
+  
+  return get_string_field (message,
+			   DBUS_HEADER_FIELD_MEMBER,
+			   NULL);
+}
+
+/**
+ * Sets the name of the error (DBUS_MESSAGE_TYPE_ERROR).
+ * The name is fully-qualified (namespaced).
+ *
+ * @param message the message
+ * @param error_name the name
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+dbus_message_set_error_name (DBusMessage  *message,
+                             const char   *error_name)
+{
+  _dbus_return_val_if_fail (message != NULL, FALSE);
+  _dbus_return_val_if_fail (!message->locked, FALSE);
+  
+  if (error_name == NULL)
+    {
+      delete_field (message, DBUS_HEADER_FIELD_ERROR_NAME);
+      return TRUE;
+    }
+  else
+    {
+      return set_string_field (message,
+                               DBUS_HEADER_FIELD_ERROR_NAME,
+                               DBUS_TYPE_STRING,
+                               error_name);
+    }
+}
+
+/**
+ * Gets the error name (DBUS_MESSAGE_TYPE_ERROR only).
+ * 
+ * @param message the message
+ * @returns the error name (should not be freed)
+ */
+const char*
+dbus_message_get_error_name (DBusMessage *message)
+{
+  _dbus_return_val_if_fail (message != NULL, NULL);
+  
+  return get_string_field (message,
+			   DBUS_HEADER_FIELD_ERROR_NAME,
+			   NULL);
+}
+
+/**
+ * Sets the message's destination service.
+ *
+ * @param message the message
+ * @param destination the destination service name
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+dbus_message_set_destination (DBusMessage  *message,
+                              const char   *destination)
+{
+  _dbus_return_val_if_fail (message != NULL, FALSE);
+  _dbus_return_val_if_fail (!message->locked, FALSE);
+  
+  if (destination == NULL)
+    {
+      delete_field (message, DBUS_HEADER_FIELD_SERVICE);
+      return TRUE;
+    }
+  else
+    {
+      return set_string_field (message,
+                               DBUS_HEADER_FIELD_SERVICE,
+                               DBUS_TYPE_STRING,
+                               destination);
+    }
 }
 
 /**
@@ -1225,7 +1726,9 @@
 {
   _dbus_return_val_if_fail (message != NULL, NULL);
   
-  return get_string_field (message, FIELD_SERVICE, NULL);
+  return get_string_field (message,
+			   DBUS_HEADER_FIELD_SERVICE,
+			   NULL);
 }
 
 /**
@@ -3677,58 +4180,62 @@
 
   if (sender == NULL)
     {
-      delete_string_field (message, FIELD_SENDER);
+      delete_field (message, DBUS_HEADER_FIELD_SENDER_SERVICE);
       return TRUE;
     }
   else
     {
       return set_string_field (message,
-                               FIELD_SENDER,
+                               DBUS_HEADER_FIELD_SENDER_SERVICE,
+                               DBUS_TYPE_STRING,
                                sender);
     }
 }
 
 /**
- * Sets a flag indicating that the message is an error reply
- * message, i.e. an "exception" rather than a normal response.
+ * Sets a flag indicating that the message does not want a reply; if
+ * this flag is set, the other end of the connection may (but is not
+ * required to) optimize by not sending method return or error
+ * replies. If this flag is set, there is no way to know whether the
+ * message successfully arrived at the remote end.
  *
  * @param message the message
- * @param is_error_reply #TRUE if this is an error message.
+ * @param no_reply #TRUE if no reply is desired
  */
 void
-dbus_message_set_is_error (DBusMessage *message,
-                           dbus_bool_t  is_error_reply)
+dbus_message_set_no_reply (DBusMessage *message,
+                           dbus_bool_t  no_reply)
 {
   char *header;
 
   _dbus_return_if_fail (message != NULL);
   _dbus_return_if_fail (!message->locked);
   
-  header = _dbus_string_get_data_len (&message->header, 1, 1);
+  header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1);
   
-  if (is_error_reply)
-    *header |= DBUS_HEADER_FLAG_ERROR;
+  if (no_reply)
+    *header |= DBUS_HEADER_FLAG_NO_REPLY_EXPECTED;
   else
-    *header &= ~DBUS_HEADER_FLAG_ERROR;    
+    *header &= ~DBUS_HEADER_FLAG_NO_REPLY_EXPECTED;    
 }
 
 /**
- * Returns #TRUE if the message is an error
- * reply to some previous message we sent.
+ * Returns #TRUE if the message does not expect
+ * a reply.
  *
  * @param message the message
- * @returns #TRUE if the message is an error
+ * @returns #TRUE if the message sender isn't waiting for a reply
  */
 dbus_bool_t
-dbus_message_get_is_error (DBusMessage *message)
+dbus_message_get_no_reply (DBusMessage *message)
 {
   const char *header;
 
   _dbus_return_val_if_fail (message != NULL, FALSE);
   
-  header = _dbus_string_get_const_data_len (&message->header, 1, 1);
+  header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1);
 
-  return (*header & DBUS_HEADER_FLAG_ERROR) != 0;
+  return (*header & DBUS_HEADER_FLAG_NO_REPLY_EXPECTED) != 0;
 }
 
 /**
@@ -3743,31 +4250,120 @@
 {
   _dbus_return_val_if_fail (message != NULL, NULL);
   
-  return get_string_field (message, FIELD_SENDER, NULL);
+  return get_string_field (message, 
+			   DBUS_HEADER_FIELD_SENDER_SERVICE,
+			   NULL);
+}
+
+static dbus_bool_t
+_dbus_message_has_type_interface_member (DBusMessage *message,
+                                         int          type,
+                                         const char  *interface,
+                                         const char  *method)
+{
+  const char *n;
+
+  _dbus_assert (message != NULL);
+  _dbus_assert (interface != NULL);
+  _dbus_assert (method != NULL);
+
+  if (dbus_message_get_type (message) != type)
+    return FALSE;
+
+  /* Optimize by checking the short method name first
+   * instead of the longer interface name
+   */  
+
+  n = dbus_message_get_member (message);
+
+  if (n && strcmp (n, method) == 0)
+    {
+      n = dbus_message_get_interface (message);
+      
+      if (n && strcmp (n, interface) == 0)
+        return TRUE;
+    }
+
+  return FALSE;
 }
 
 /**
- * Checks whether the message has the given name.
- * If the message has no name or has a different
- * name, returns #FALSE.
+ * Checks whether the message is a method call with the given
+ * interface and member fields.  If the message is not
+ * #DBUS_MESSAGE_TYPE_METHOD_CALL, or has a different interface or member field,
+ * returns #FALSE.
  *
  * @param message the message
- * @param name the name to check (must not be #NULL)
+ * @param interface the name to check (must not be #NULL)
+ * @param method the name to check (must not be #NULL)
  * 
- * @returns #TRUE if the message has the given name
+ * @returns #TRUE if the message is the specified method call
  */
 dbus_bool_t
-dbus_message_has_name (DBusMessage *message,
-                       const char  *name)
+dbus_message_is_method_call (DBusMessage *message,
+                             const char  *interface,
+                             const char  *method)
 {
-  const char *n;
+  _dbus_return_val_if_fail (message != NULL, FALSE);
+  _dbus_return_val_if_fail (interface != NULL, FALSE);
+  _dbus_return_val_if_fail (method != NULL, FALSE);
 
+  return _dbus_message_has_type_interface_member (message,
+                                                  DBUS_MESSAGE_TYPE_METHOD_CALL,
+                                                  interface, method);
+}
+
+/**
+ * Checks whether the message is a signal with the given
+ * interface and member fields.  If the message is not
+ * #DBUS_MESSAGE_TYPE_SIGNAL, or has a different interface or member field,
+ * returns #FALSE.
+ *
+ * @param message the message
+ * @param interface the name to check (must not be #NULL)
+ * @param signal_name the name to check (must not be #NULL)
+ * 
+ * @returns #TRUE if the message is the specified signal
+ */
+dbus_bool_t
+dbus_message_is_signal (DBusMessage *message,
+                        const char  *interface,
+                        const char  *signal_name)
+{
   _dbus_return_val_if_fail (message != NULL, FALSE);
-  _dbus_return_val_if_fail (name != NULL, FALSE);
+  _dbus_return_val_if_fail (interface != NULL, FALSE);
+  _dbus_return_val_if_fail (signal_name != NULL, FALSE);
+
+  return _dbus_message_has_type_interface_member (message,
+                                                  DBUS_MESSAGE_TYPE_SIGNAL,
+                                                  interface, signal_name);
+}
+
+/**
+ * Checks whether the message is an error reply with the given error
+ * name.  If the message is not #DBUS_MESSAGE_TYPE_ERROR, or has a
+ * different name, returns #FALSE.
+ *
+ * @param message the message
+ * @param error_name the name to check (must not be #NULL)
+ * 
+ * @returns #TRUE if the message is the specified error
+ */
+dbus_bool_t
+dbus_message_is_error (DBusMessage *message,
+                        const char  *error_name)
+{
+  const char *n;
   
-  n = dbus_message_get_name (message);
+  _dbus_return_val_if_fail (message != NULL, FALSE);
+  _dbus_return_val_if_fail (error_name != NULL, FALSE);
 
-  if (n && strcmp (n, name) == 0)
+  if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
+    return FALSE;
+
+  n = dbus_message_get_error_name (message);
+
+  if (n && strcmp (n, error_name) == 0)
     return TRUE;
   else
     return FALSE;
@@ -3833,7 +4429,7 @@
 /**
  * Sets a #DBusError based on the contents of the given
  * message. The error is only set if the message
- * is an error message, as in dbus_message_get_is_error().
+ * is an error message, as in DBUS_MESSAGE_TYPE_ERROR.
  * The name of the error is set to the name of the message,
  * and the error message is set to the first argument
  * if the argument exists and is a string.
@@ -3856,7 +4452,7 @@
   _dbus_return_val_if_fail (message != NULL, FALSE);
   _dbus_return_val_if_error_is_set (error, FALSE);
   
-  if (!dbus_message_get_is_error (message))
+  if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
     return FALSE;
 
   str = NULL;
@@ -3864,7 +4460,7 @@
                          DBUS_TYPE_STRING, &str,
                          DBUS_TYPE_INVALID);
 
-  dbus_set_error (error, dbus_message_get_name (message),
+  dbus_set_error (error, dbus_message_get_error_name (message),
                   str ? "%s" : NULL, str);
 
   dbus_free (str);
@@ -4039,51 +4635,31 @@
  */
 #define DBUS_MINIMUM_HEADER_SIZE 16
 
-/** Pack four characters as in "abcd" into a uint32 */
-#define FOUR_CHARS_TO_UINT32(a, b, c, d)                \
-                      ((((dbus_uint32_t)a) << 24) |     \
-                       (((dbus_uint32_t)b) << 16) |     \
-                       (((dbus_uint32_t)c) << 8)  |     \
-                       ((dbus_uint32_t)d))
-
-/** DBUS_HEADER_FIELD_NAME packed into a dbus_uint32_t */
-#define DBUS_HEADER_FIELD_NAME_AS_UINT32    \
-  FOUR_CHARS_TO_UINT32 ('n', 'a', 'm', 'e')
-
-/** DBUS_HEADER_FIELD_SERVICE packed into a dbus_uint32_t */
-#define DBUS_HEADER_FIELD_SERVICE_AS_UINT32 \
-  FOUR_CHARS_TO_UINT32 ('s', 'r', 'v', 'c')
-
-/** DBUS_HEADER_FIELD_REPLY packed into a dbus_uint32_t */
-#define DBUS_HEADER_FIELD_REPLY_AS_UINT32   \
-  FOUR_CHARS_TO_UINT32 ('r', 'p', 'l', 'y')
-
-/** DBUS_HEADER_FIELD_SENDER Packed into a dbus_uint32_t */
-#define DBUS_HEADER_FIELD_SENDER_AS_UINT32  \
-  FOUR_CHARS_TO_UINT32 ('s', 'n', 'd', 'r')
-
 static dbus_bool_t
 decode_string_field (const DBusString   *data,
-                     HeaderField         fields[FIELD_LAST],
+		     int                 field,
+                     HeaderField        *header_field,
+		     DBusString         *field_data,
                      int                 pos,
-                     int                 type,
-                     int                 field,
-                     const char         *field_name)
+                     int                 type)
 {
-  DBusString tmp;
   int string_data_pos;
+
+  _dbus_assert (header_field != NULL);
+  _dbus_assert (field_data != NULL);
   
-  if (fields[field].offset >= 0)
+  if (header_field->name_offset >= 0)
     {
       _dbus_verbose ("%s field provided twice\n",
-                     field_name);
+		     _dbus_header_field_to_string (field));
       return FALSE;
     }
 
   if (type != DBUS_TYPE_STRING)
     {
       _dbus_verbose ("%s field has wrong type %s\n",
-                     field_name, _dbus_type_to_string (type));
+                     _dbus_header_field_to_string (field),
+		     _dbus_type_to_string (type));
       return FALSE;
     }
 
@@ -4094,40 +4670,16 @@
   string_data_pos = _DBUS_ALIGN_VALUE (pos, 4) + 4;
   _dbus_assert (string_data_pos < _dbus_string_get_length (data));
   
-  _dbus_string_init_const (&tmp,
+  _dbus_string_init_const (field_data,
                            _dbus_string_get_const_data (data) + string_data_pos);
 
-  if (field == FIELD_NAME)
-    {
-      if (!_dbus_string_validate_name (&tmp, 0, _dbus_string_get_length (&tmp)))
-        {
-          _dbus_verbose ("%s field has invalid content \"%s\"\n",
-                         field_name, _dbus_string_get_const_data (&tmp));
-          return FALSE;
-        }
-      
-      if (_dbus_string_starts_with_c_str (&tmp,
-                                          DBUS_NAMESPACE_LOCAL_MESSAGE))
-        {
-          _dbus_verbose ("Message is in the local namespace\n");
-          return FALSE;
-        }
-    }
-  else
-    {
-      if (!_dbus_string_validate_service (&tmp, 0, _dbus_string_get_length (&tmp)))
-        {
-          _dbus_verbose ("%s field has invalid content \"%s\"\n",
-                         field_name, _dbus_string_get_const_data (&tmp));
-          return FALSE;
-        }
-    }
-  
-  fields[field].offset = _DBUS_ALIGN_VALUE (pos, 4);
+  header_field->name_offset  = pos;
+  header_field->value_offset = _DBUS_ALIGN_VALUE (pos, 4);
   
 #if 0
-  _dbus_verbose ("Found field %s name at offset %d\n",
-                 field_name, fields[field].offset);
+  _dbus_verbose ("Found field %s at offset %d\n",
+                 _dbus_header_field_to_string (field),
+		 header_field->value_offset);
 #endif
 
   return TRUE;
@@ -4137,47 +4689,38 @@
 decode_header_data (const DBusString   *data,
 		    int		        header_len,
 		    int                 byte_order,
-                    HeaderField         fields[FIELD_LAST],
+                    int                 message_type,
+                    HeaderField         fields[DBUS_HEADER_FIELD_LAST + 1],
 		    int                *message_padding)
 {
-  const char *field;
+  DBusString field_data;
   int pos, new_pos;
   int i;
+  int field;
   int type;
   
   if (header_len < 16)
-    return FALSE;
+    {
+      _dbus_verbose ("Header length %d is too short\n", header_len);
+      return FALSE;
+    }
   
   i = 0;
-  while (i < FIELD_LAST)
+  while (i <= DBUS_HEADER_FIELD_LAST)
     {
-      fields[i].offset = -1;
+      fields[i].name_offset  = -1;
+      fields[i].value_offset = -1;
       ++i;
     }
   
-  fields[FIELD_HEADER_LENGTH].offset = 4;
-  fields[FIELD_BODY_LENGTH].offset = 8;   
-  fields[FIELD_CLIENT_SERIAL].offset = 12;
-  
-  /* Now handle the named fields. A real named field is at least 4
-   * bytes for the name, plus a type code (1 byte) plus padding.  So
-   * if we have less than 8 bytes left, it must be alignment padding,
-   * not a field. While >= 8 bytes can't be entirely alignment
-   * padding.
-   */  
   pos = 16;
-  while ((pos + 7) < header_len)
+  while (pos < header_len)
     {
-      pos = _DBUS_ALIGN_VALUE (pos, 4);
-      
-      if ((pos + 4) > header_len)
-        return FALSE;      
-      
-      field =_dbus_string_get_const_data_len (data, pos, 4);
-      pos += 4;
+      field = _dbus_string_get_byte (data, pos);
+      if (field == DBUS_HEADER_FIELD_INVALID)
+	break; /* Must be padding */
+      pos++;
 
-      _dbus_assert (_DBUS_ALIGN_ADDRESS (field, 4) == field);
-      
       if (!_dbus_marshal_validate_type (data, pos, &type, &pos))
 	{
           _dbus_verbose ("Failed to validate type of named header field\n");
@@ -4196,51 +4739,146 @@
           return FALSE;
         }
       
-      switch (DBUS_UINT32_FROM_BE (*(int*)field))
+      switch (field)
         {
-        case DBUS_HEADER_FIELD_SERVICE_AS_UINT32:
-          if (!decode_string_field (data, fields, pos, type,
-                                    FIELD_SERVICE,
-                                    DBUS_HEADER_FIELD_SERVICE))
+        case DBUS_HEADER_FIELD_SERVICE:
+          if (!decode_string_field (data, field, &fields[field],
+				    &field_data, pos, type))
             return FALSE;
+
+	  if (!_dbus_string_validate_service (&field_data, 0,
+					      _dbus_string_get_length (&field_data)))
+	    {
+	      _dbus_verbose ("service field has invalid content \"%s\"\n",
+			     _dbus_string_get_const_data (&field_data));
+	      return FALSE;
+	    }
           break;
 
-        case DBUS_HEADER_FIELD_NAME_AS_UINT32:
-          if (!decode_string_field (data, fields, pos, type,
-                                    FIELD_NAME,
-                                    DBUS_HEADER_FIELD_NAME))
+        case DBUS_HEADER_FIELD_INTERFACE:
+	  if (!decode_string_field (data, field, &fields[field],
+				    &field_data, pos, type))
             return FALSE;
+
+	  if (!_dbus_string_validate_interface (&field_data, 0,
+						_dbus_string_get_length (&field_data)))
+	    {
+	      _dbus_verbose ("interface field has invalid content \"%s\"\n",
+			     _dbus_string_get_const_data (&field_data));
+	      return FALSE;
+	    }
+      
+	  if (_dbus_string_equal_c_str (&field_data,
+					DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL))
+	    {
+	      _dbus_verbose ("Message is on the local interface\n");
+	      return FALSE;
+	    }
           break;
 
-	case DBUS_HEADER_FIELD_SENDER_AS_UINT32:
-          if (!decode_string_field (data, fields, pos, type,
-                                    FIELD_SENDER,
-                                    DBUS_HEADER_FIELD_SENDER))
+        case DBUS_HEADER_FIELD_MEMBER:
+          if (!decode_string_field (data, field, &fields[field],
+				    &field_data, pos, type))
+            return FALSE;
+	  
+	  if (!_dbus_string_validate_member (&field_data, 0,
+					     _dbus_string_get_length (&field_data)))
+	    {
+	      _dbus_verbose ("member field has invalid content \"%s\"\n",
+			     _dbus_string_get_const_data (&field_data));
+	      return FALSE;
+	    }
+          break;
+
+        case DBUS_HEADER_FIELD_ERROR_NAME:
+          if (!decode_string_field (data, field, &fields[field],
+				    &field_data, pos, type))
+            return FALSE;
+	  
+	  if (!_dbus_string_validate_error_name (&field_data, 0,
+						 _dbus_string_get_length (&field_data)))
+	    {
+	      _dbus_verbose ("error-name field has invalid content \"%s\"\n",
+			     _dbus_string_get_const_data (&field_data));
+	      return FALSE;
+	    }
+          break;
+          
+	case DBUS_HEADER_FIELD_SENDER_SERVICE:
+          if (!decode_string_field (data, field, &fields[field],
+				    &field_data, pos, type))
             return FALSE;
+	  
+	  if (!_dbus_string_validate_service (&field_data, 0,
+					      _dbus_string_get_length (&field_data)))
+	    {
+	      _dbus_verbose ("sender-service field has invalid content \"%s\"\n",
+			     _dbus_string_get_const_data (&field_data));
+	      return FALSE;
+	    }
 	  break;
+
+	case DBUS_HEADER_FIELD_PATH:
+
+          /* Path was already validated as part of standard
+           * type validation, since there's an OBJECT_PATH
+           * type.
+           */
           
-	case DBUS_HEADER_FIELD_REPLY_AS_UINT32:
-          if (fields[FIELD_REPLY_SERIAL].offset >= 0)
+          if (fields[field].name_offset >= 0)
             {
-              _dbus_verbose ("%s field provided twice\n",
-                             DBUS_HEADER_FIELD_REPLY);
+              _dbus_verbose ("path field provided twice\n");
+              return FALSE;
+            }
+          if (type != DBUS_TYPE_OBJECT_PATH)
+            {
+              _dbus_verbose ("path field has wrong type\n");
+              return FALSE;
+            }
+
+          fields[field].name_offset  = pos;
+          fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4);
+
+          /* No forging signals from the local path */
+          {
+            const char *s;
+            s = _dbus_string_get_const_data_len (data,
+                                                 fields[field].value_offset,
+                                                 _dbus_string_get_length (data) -
+                                                 fields[field].value_offset);
+            if (strcmp (s, DBUS_PATH_ORG_FREEDESKTOP_LOCAL) == 0)
+              {
+                _dbus_verbose ("Message is on the local path\n");
+                return FALSE;
+              }
+          }
+          
+          _dbus_verbose ("Found path at offset %d\n",
+                         fields[field].value_offset);
+	  break;
+          
+	case DBUS_HEADER_FIELD_REPLY_SERIAL:
+          if (fields[field].name_offset >= 0)
+            {
+              _dbus_verbose ("reply field provided twice\n");
               return FALSE;
             }
 
           if (type != DBUS_TYPE_UINT32)
             {
-              _dbus_verbose ("%s field has wrong type\n", DBUS_HEADER_FIELD_REPLY);
+              _dbus_verbose ("reply field has wrong type\n");
               return FALSE;
             }
           
-          fields[FIELD_REPLY_SERIAL].offset = _DBUS_ALIGN_VALUE (pos, 4);
+          fields[field].name_offset  = pos;
+          fields[field].value_offset = _DBUS_ALIGN_VALUE (pos, 4);
 
           _dbus_verbose ("Found reply serial at offset %d\n",
-                         fields[FIELD_REPLY_SERIAL].offset);
+                         fields[field].value_offset);
 	  break;
 
         default:
-	  _dbus_verbose ("Ignoring an unknown header field: %.4s at offset %d\n",
+	  _dbus_verbose ("Ignoring an unknown header field: %d at offset %d\n",
 			 field, pos);
 	}
       
@@ -4250,7 +4888,11 @@
   if (pos < header_len)
     {
       /* Alignment padding, verify that it's nul */
-      _dbus_assert ((header_len - pos) < 8);
+      if ((header_len - pos) >= 8)
+	{
+	  _dbus_verbose ("too much header alignment padding\n");
+	  return FALSE;
+	}
 
       if (!_dbus_string_validate_nul (data,
                                       pos, (header_len - pos)))
@@ -4260,12 +4902,40 @@
         }
     }
 
-  /* Name field is mandatory */
-  if (fields[FIELD_NAME].offset < 0)
+  /* Depending on message type, enforce presence of certain fields. */
+  switch (message_type)
     {
-      _dbus_verbose ("No %s field provided\n",
-                     DBUS_HEADER_FIELD_NAME);
-      return FALSE;
+    case DBUS_MESSAGE_TYPE_SIGNAL:
+    case DBUS_MESSAGE_TYPE_METHOD_CALL:
+      if (fields[DBUS_HEADER_FIELD_PATH].value_offset < 0)
+        {
+          _dbus_verbose ("No path field provided\n");
+          return FALSE;
+        }
+      /* FIXME make this optional, only for method calls */
+      if (fields[DBUS_HEADER_FIELD_INTERFACE].value_offset < 0)
+        {
+          _dbus_verbose ("No interface field provided\n");
+          return FALSE;
+        }
+      if (fields[DBUS_HEADER_FIELD_MEMBER].value_offset < 0)
+        {
+          _dbus_verbose ("No member field provided\n");
+          return FALSE;
+        }
+      break;
+    case DBUS_MESSAGE_TYPE_ERROR:
+      if (fields[DBUS_HEADER_FIELD_ERROR_NAME].value_offset < 0)
+        {
+          _dbus_verbose ("No error-name field provided\n");
+          return FALSE;
+        }
+      break;
+    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+      break;
+    default:
+      /* An unknown type, spec requires us to ignore it */
+      break;
     }
   
   if (message_padding)
@@ -4298,6 +4968,13 @@
 /**
  * Converts buffered data into messages.
  *
+ * @todo we need to check that the proper named header fields exist
+ * for each message type.
+ * 
+ * @todo If a message has unknown type, we should probably eat it
+ * right here rather than passing it out to applications.  However
+ * it's not an error to see messages of unknown type.
+ * 
  * @param loader the loader.
  * @returns #TRUE if we had enough memory to finish.
  */
@@ -4311,22 +4988,22 @@
     {
       DBusMessage *message;      
       const char *header_data;
-      int byte_order, header_len, body_len, header_padding;
+      int byte_order, message_type, header_len, body_len, header_padding;
       dbus_uint32_t header_len_unsigned, body_len_unsigned;
       
       header_data = _dbus_string_get_const_data_len (&loader->data, 0, 16);
 
       _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data);
 
-      if (header_data[2] != DBUS_MAJOR_PROTOCOL_VERSION)
+      if (header_data[VERSION_OFFSET] != DBUS_MAJOR_PROTOCOL_VERSION)
         {
           _dbus_verbose ("Message has protocol version %d ours is %d\n",
-                         (int) header_data[2], DBUS_MAJOR_PROTOCOL_VERSION);
+                         (int) header_data[VERSION_OFFSET], DBUS_MAJOR_PROTOCOL_VERSION);
           loader->corrupted = TRUE;
           return TRUE;
         }
       
-      byte_order = header_data[0];
+      byte_order = header_data[BYTE_ORDER_OFFSET];
 
       if (byte_order != DBUS_LITTLE_ENDIAN &&
 	  byte_order != DBUS_BIG_ENDIAN)
@@ -4337,6 +5014,18 @@
 	  return TRUE;
 	}
 
+      /* Unknown types are ignored, but INVALID is
+       * disallowed
+       */
+      message_type = header_data[TYPE_OFFSET];
+      if (message_type == DBUS_MESSAGE_TYPE_INVALID)
+        {
+          _dbus_verbose ("Message with bad type '%d' received\n",
+                         message_type);
+	  loader->corrupted = TRUE;
+	  return TRUE;
+        }      
+      
       header_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 4);
       body_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 8);
 
@@ -4383,14 +5072,16 @@
 
       if (_dbus_string_get_length (&loader->data) >= (header_len + body_len))
 	{
-          HeaderField fields[FIELD_LAST];
+          HeaderField fields[DBUS_HEADER_FIELD_LAST + 1];
           int i;
           int next_arg;          
 
 #if 0
 	  _dbus_verbose_bytes_of_string (&loader->data, 0, header_len + body_len);
 #endif	  
- 	  if (!decode_header_data (&loader->data, header_len, byte_order,
+ 	  if (!decode_header_data (&loader->data,
+                                   header_len, byte_order,
+                                   message_type,
                                    fields, &header_padding))
 	    {
               _dbus_verbose ("Header was invalid\n");
@@ -4448,7 +5139,7 @@
 	  
           /* Copy in the offsets we found */
           i = 0;
-          while (i < FIELD_LAST)
+          while (i <= DBUS_HEADER_FIELD_LAST)
             {
               message->header_fields[i] = fields[i];
               ++i;
@@ -4498,9 +5189,12 @@
            * earlier)
            */
           message->reply_serial = get_uint_field (message,
-                                                  FIELD_REPLY_SERIAL);
-          message->client_serial = get_uint_field (message,
-                                                   FIELD_CLIENT_SERIAL);
+						  DBUS_HEADER_FIELD_REPLY_SERIAL);
+	  
+          message->client_serial = _dbus_demarshal_uint32 (&message->header,
+							   message->byte_order,
+							   CLIENT_SERIAL_OFFSET,
+							   NULL);
           
 	  _dbus_verbose ("Loaded message %p\n", message);
 	}
@@ -5076,8 +5770,10 @@
   client_serial = dbus_message_get_serial (message);
 
   /* can't use set_serial due to the assertions at the start of it */
-  set_uint_field (message, FIELD_CLIENT_SERIAL,
-                  client_serial);
+  _dbus_marshal_set_uint32 (&message->header,
+                            message->byte_order,
+                            CLIENT_SERIAL_OFFSET,
+                            client_serial);
   
   if (client_serial != dbus_message_get_serial (message))
     {
@@ -5467,7 +6163,7 @@
       goto failed;
     }
 
-  printf ("Testing:\n");
+  printf ("Testing %s:\n", subdir);
   
  next:
   while (_dbus_directory_get_next_file (dir, &filename, &error))
@@ -5499,10 +6195,11 @@
       printf ("    %s\n",
               _dbus_string_get_const_data (&filename));
       
-      _dbus_verbose (" expecting %s\n",
+      _dbus_verbose (" expecting %s for %s\n",
                      validity == _DBUS_MESSAGE_VALID ? "valid" :
                      (validity == _DBUS_MESSAGE_INVALID ? "invalid" :
-                      (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")));
+                      (validity == _DBUS_MESSAGE_INCOMPLETE ? "incomplete" : "unknown")),
+                     _dbus_string_get_const_data (&filename));
       
       if (! (*function) (&full_path, is_raw, validity, user_data))
         {
@@ -5821,26 +6518,37 @@
   
   _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter));
 
-  message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test");
-  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test"));
+  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
+                                          "/org/freedesktop/TestPath",
+                                          "Foo.TestInterface",
+                                          "TestMethod");
+  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
+  _dbus_assert (dbus_message_is_method_call (message, "Foo.TestInterface",
+                                             "TestMethod"));
   _dbus_message_set_serial (message, 1234);
-  dbus_message_set_sender (message, "org.foo.bar");
-  _dbus_assert (dbus_message_has_sender (message, "org.foo.bar"));
+  /* string length including nul byte not a multiple of 4 */
+  dbus_message_set_sender (message, "org.foo.bar1");
+  _dbus_assert (dbus_message_has_sender (message, "org.foo.bar1"));
+  dbus_message_set_reply_serial (message, 5678);
   dbus_message_set_sender (message, NULL);
-  _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar"));
+  _dbus_assert (!dbus_message_has_sender (message, "org.foo.bar1"));
   _dbus_assert (dbus_message_get_serial (message) == 1234);
-  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test"));
+  _dbus_assert (dbus_message_get_reply_serial (message) == 5678);
+  _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.TestService"));
 
-  _dbus_assert (dbus_message_get_is_error (message) == FALSE);
-  dbus_message_set_is_error (message, TRUE);
-  _dbus_assert (dbus_message_get_is_error (message) == TRUE);
-  dbus_message_set_is_error (message, FALSE);
-  _dbus_assert (dbus_message_get_is_error (message) == FALSE);
+  _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
+  dbus_message_set_no_reply (message, TRUE);
+  _dbus_assert (dbus_message_get_no_reply (message) == TRUE);
+  dbus_message_set_no_reply (message, FALSE);
+  _dbus_assert (dbus_message_get_no_reply (message) == FALSE);
   
   dbus_message_unref (message);
   
   /* Test the vararg functions */
-  message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test");
+  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
+                                          "/org/freedesktop/TestPath",
+                                          "Foo.TestInterface",
+                                          "TestMethod");
   _dbus_message_set_serial (message, 1);
   dbus_message_append_args (message,
 			    DBUS_TYPE_INT32, -0x12345678,
@@ -5855,10 +6563,12 @@
                             _DBUS_N_ELEMENTS (our_uint32_array),
                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT32, our_int32_array,
                             _DBUS_N_ELEMENTS (our_int32_array),
+#ifdef DBUS_HAVE_INT64
                             DBUS_TYPE_ARRAY, DBUS_TYPE_UINT64, our_uint64_array,
                             _DBUS_N_ELEMENTS (our_uint64_array),
                             DBUS_TYPE_ARRAY, DBUS_TYPE_INT64, our_int64_array,
                             _DBUS_N_ELEMENTS (our_int64_array),
+#endif
                             DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, our_string_array,
                             _DBUS_N_ELEMENTS (our_string_array),
                             DBUS_TYPE_ARRAY, DBUS_TYPE_DOUBLE, our_double_array,
@@ -5896,15 +6606,24 @@
 
   verify_test_message (copy);
 
-  name1 = dbus_message_get_name (message);
-  name2 = dbus_message_get_name (copy);
+  name1 = dbus_message_get_interface (message);
+  name2 = dbus_message_get_interface (copy);
+
+  _dbus_assert (strcmp (name1, name2) == 0);
+
+  name1 = dbus_message_get_member (message);
+  name2 = dbus_message_get_member (copy);
 
   _dbus_assert (strcmp (name1, name2) == 0);
   
   dbus_message_unref (message);
   dbus_message_unref (copy);
-  
-  message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test");
+
+  message = dbus_message_new_method_call ("org.freedesktop.DBus.TestService",
+                                          "/org/freedesktop/TestPath",
+                                          "Foo.TestInterface",
+                                          "TestMethod");
+
   _dbus_message_set_serial (message, 1);
   dbus_message_set_reply_serial (message, 0x12345678);
 

Index: dbus-message.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-message.h,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -d -r1.42 -r1.43
--- dbus-message.h	22 Jun 2003 20:46:17 -0000	1.42
+++ dbus-message.h	30 Sep 2003 02:32:53 -0000	1.43
@@ -31,6 +31,7 @@
 #include <dbus/dbus-types.h>
 #include <dbus/dbus-arch-deps.h>
 #include <dbus/dbus-memory.h>
+#include <dbus/dbus-errors.h>
 #include <stdarg.h>
 
 DBUS_BEGIN_DECLS;
@@ -38,45 +39,74 @@
 typedef struct DBusMessage DBusMessage;
 typedef struct DBusMessageIter DBusMessageIter;
 
+/**
+ * DBusMessageIter struct; contains no public fields 
+ */
 struct DBusMessageIter
-{
-  void *dummy1;
-  void *dummy2;
-  dbus_uint32_t dummy3;
-  int dummy4;
-  int dummy5;
-  int dummy6;
-  int dummy7;
-  int dummy8;
-  int dummy9;
-  int dummy10;
-  int dummy11;
-  int pad1;
-  int pad2;
-  void *pad3;
+{ 
+  void *dummy1;         /**< Don't use this */
+  void *dummy2;         /**< Don't use this */
+  dbus_uint32_t dummy3; /**< Don't use this */
+  int dummy4;           /**< Don't use this */
+  int dummy5;           /**< Don't use this */
+  int dummy6;           /**< Don't use this */
+  int dummy7;           /**< Don't use this */
+  int dummy8;           /**< Don't use this */
+  int dummy9;           /**< Don't use this */
+  int dummy10;          /**< Don't use this */
+  int dummy11;          /**< Don't use this */
+  int pad1;             /**< Don't use this */
+  int pad2;             /**< Don't use this */
+  void *pad3;           /**< Don't use this */
 };
 
+DBusMessage* dbus_message_new               (int          message_type);
+DBusMessage* dbus_message_new_method_call   (const char  *service,
+                                             const char  *path,
+                                             const char  *interface,
+                                             const char  *method);
+DBusMessage* dbus_message_new_method_return (DBusMessage *method_call);
+DBusMessage* dbus_message_new_signal        (const char  *path,
+                                             const char  *interface,
+                                             const char  *name);
+DBusMessage* dbus_message_new_error         (DBusMessage *reply_to,
+                                             const char  *error_name,
+                                             const char  *error_message);
 
-DBusMessage* dbus_message_new              (const char        *name,
-					    const char        *destination_service);
-DBusMessage* dbus_message_new_reply        (DBusMessage       *original_message);
-DBusMessage* dbus_message_new_error_reply  (DBusMessage       *original_message,
-					    const char        *error_name,
-					    const char        *error_message);
-DBusMessage *dbus_message_copy             (const DBusMessage *message);
+DBusMessage *dbus_message_copy              (const DBusMessage *message);
 
 void          dbus_message_ref              (DBusMessage   *message);
 void          dbus_message_unref            (DBusMessage   *message);
-const char*   dbus_message_get_name         (DBusMessage   *message);
+int           dbus_message_get_type         (DBusMessage   *message);
+dbus_bool_t   dbus_message_set_path         (DBusMessage   *message,
+                                             const char    *object_path);
+const char*   dbus_message_get_path         (DBusMessage   *message);
+dbus_bool_t   dbus_message_set_interface    (DBusMessage   *message,
+                                             const char    *interface);
+const char*   dbus_message_get_interface    (DBusMessage   *message);
+dbus_bool_t   dbus_message_set_member       (DBusMessage   *message,
+                                             const char    *member);
+const char*   dbus_message_get_member       (DBusMessage   *message);
+dbus_bool_t   dbus_message_set_error_name   (DBusMessage   *message,
+                                             const char    *name);
+const char*   dbus_message_get_error_name   (DBusMessage   *message);
+dbus_bool_t   dbus_message_set_destination  (DBusMessage   *message,
+                                             const char    *destination);
 const char*   dbus_message_get_destination  (DBusMessage   *message);
 dbus_bool_t   dbus_message_set_sender       (DBusMessage   *message,
                                              const char    *sender);
 const char*   dbus_message_get_sender       (DBusMessage   *message);
-void          dbus_message_set_is_error     (DBusMessage   *message,
-                                             dbus_bool_t    is_error_reply);
-dbus_bool_t   dbus_message_get_is_error     (DBusMessage   *message);
-dbus_bool_t   dbus_message_has_name         (DBusMessage   *message,
-                                             const char    *name);
+void          dbus_message_set_no_reply     (DBusMessage   *message,
+                                             dbus_bool_t    no_reply);
+dbus_bool_t   dbus_message_get_no_reply     (DBusMessage   *message);
+dbus_bool_t   dbus_message_is_method_call   (DBusMessage   *message,
+                                             const char    *interface,
+                                             const char    *method);
+dbus_bool_t   dbus_message_is_signal        (DBusMessage   *message,
+                                             const char    *interface,
+                                             const char    *signal_name);
+dbus_bool_t   dbus_message_is_error         (DBusMessage   *message,
+                                             const char    *error_name);
 dbus_bool_t   dbus_message_has_destination  (DBusMessage   *message,
                                              const char    *service);
 dbus_bool_t   dbus_message_has_sender       (DBusMessage   *message,
@@ -86,6 +116,9 @@
                                              dbus_uint32_t  reply_serial);
 dbus_uint32_t dbus_message_get_reply_serial (DBusMessage   *message);
 
+dbus_bool_t   dbus_message_get_path_decomposed (DBusMessage   *message,
+                                                char        ***path);
+
 dbus_bool_t dbus_message_append_args          (DBusMessage     *message,
 					       int              first_arg_type,
 					       ...);

Index: dbus-protocol.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-protocol.h,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- dbus-protocol.h	23 Apr 2003 03:33:52 -0000	1.20
+++ dbus-protocol.h	30 Sep 2003 02:32:53 -0000	1.21
@@ -53,25 +53,54 @@
 #define DBUS_TYPE_NAMED         10
 #define DBUS_TYPE_ARRAY         11
 #define DBUS_TYPE_DICT          12
+#define DBUS_TYPE_OBJECT_PATH   13
+  
+#define DBUS_TYPE_LAST DBUS_TYPE_OBJECT_PATH
 
-#define DBUS_TYPE_LAST DBUS_TYPE_DICT
-
-/* Max length in bytes of a service or message name */
+/* Max length in bytes of a service or interface or member name */
 #define DBUS_MAXIMUM_NAME_LENGTH 256
 
+/* Types of message */
+#define DBUS_MESSAGE_TYPE_INVALID       0
+#define DBUS_MESSAGE_TYPE_METHOD_CALL   1
+#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2
+#define DBUS_MESSAGE_TYPE_ERROR         3
+#define DBUS_MESSAGE_TYPE_SIGNAL        4
+  
 /* Header flags */
-#define DBUS_HEADER_FLAG_ERROR 0x1
+#define DBUS_HEADER_FLAG_NO_REPLY_EXPECTED 0x1
   
 /* Header fields */
-#define DBUS_HEADER_FIELD_NAME    "name"
-#define DBUS_HEADER_FIELD_SERVICE "srvc"
-#define DBUS_HEADER_FIELD_REPLY	  "rply"
-#define DBUS_HEADER_FIELD_SENDER  "sndr"
+#define DBUS_HEADER_FIELD_INVALID        0
+#define DBUS_HEADER_FIELD_PATH           1
+#define DBUS_HEADER_FIELD_INTERFACE      2
+#define DBUS_HEADER_FIELD_MEMBER         3
+#define DBUS_HEADER_FIELD_ERROR_NAME     4
+#define DBUS_HEADER_FIELD_REPLY_SERIAL   5
+#define DBUS_HEADER_FIELD_SERVICE        6
+#define DBUS_HEADER_FIELD_SENDER_SERVICE 7
 
+#define DBUS_HEADER_FIELD_LAST DBUS_HEADER_FIELD_SENDER_SERVICE
+  
 /* Services */
-#define DBUS_SERVICE_DBUS      "org.freedesktop.DBus"
-#define DBUS_SERVICE_BROADCAST "org.freedesktop.DBus.Broadcast"
+#define DBUS_SERVICE_ORG_FREEDESKTOP_DBUS      "org.freedesktop.DBus"
 
+/* Paths */
+#define DBUS_PATH_ORG_FREEDESKTOP_DBUS  "/org/freedesktop/DBus"
+#define DBUS_PATH_ORG_FREEDESKTOP_LOCAL "/org/freedesktop/Local"
+  
+/* Interfaces, these #define don't do much other than
+ * catch typos at compile time
+ */
+#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS  "org.freedesktop.DBus"
+#define DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE "org.freedesktop.Introspectable"
+  
+/* This is a special interface whose methods can only be invoked
+ * by the local implementation (messages from remote apps aren't
+ * allowed to specify this interface).
+ */
+#define DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL "org.freedesktop.Local"
+  
 /* Service owner flags */
 #define DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT 0x1
 #define DBUS_SERVICE_FLAG_REPLACE_EXISTING     0x2
@@ -86,24 +115,6 @@
 #define DBUS_ACTIVATION_REPLY_ACTIVATED      0x0
 #define DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE 0x1
   
-/* Messages */
-#define DBUS_MESSAGE_ACTIVATE_SERVICE      "org.freedesktop.DBus.ActivateService"  
-#define DBUS_MESSAGE_SERVICE_EXISTS        "org.freedesktop.DBus.ServiceExists"
-#define DBUS_MESSAGE_HELLO                 "org.freedesktop.DBus.Hello"
-#define DBUS_MESSAGE_LIST_SERVICES         "org.freedesktop.DBus.ListServices"
-#define DBUS_MESSAGE_ACQUIRE_SERVICE       "org.freedesktop.DBus.AcquireService"
-#define DBUS_MESSAGE_SERVICE_ACQUIRED      "org.freedesktop.DBus.ServiceAcquired"
-#define DBUS_MESSAGE_SERVICE_CREATED       "org.freedesktop.DBus.ServiceCreated"
-#define DBUS_MESSAGE_SERVICE_DELETED       "org.freedesktop.DBus.ServiceDeleted"
-#define DBUS_MESSAGE_SERVICE_LOST          "org.freedesktop.DBus.ServiceLost"
-
-
-/* This namespace is reserved for locally-synthesized messages, you can't
- * send messages that have this namespace.
- */
-#define DBUS_NAMESPACE_LOCAL_MESSAGE       "org.freedesktop.Local."
-#define DBUS_MESSAGE_LOCAL_DISCONNECT      DBUS_NAMESPACE_LOCAL_MESSAGE"Disconnect"
-  
 #ifdef __cplusplus
 }
 #endif

Index: dbus-server-debug-pipe.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-server-debug-pipe.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- dbus-server-debug-pipe.c	18 Apr 2003 04:18:57 -0000	1.12
+++ dbus-server-debug-pipe.c	30 Sep 2003 02:32:53 -0000	1.13
@@ -27,6 +27,7 @@
 #include "dbus-transport-unix.h"
 #include "dbus-connection-internal.h"
 #include "dbus-hash.h"
+#include "dbus-string.h"
 
 #ifdef DBUS_BUILD_TESTS
 

Index: dbus-server-protected.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-server-protected.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- dbus-server-protected.h	18 Apr 2003 04:18:57 -0000	1.10
+++ dbus-server-protected.h	30 Sep 2003 02:32:53 -0000	1.11
@@ -34,6 +34,9 @@
 
 typedef struct DBusServerVTable DBusServerVTable;
 
+/**
+ * Virtual table to be implemented by all server "subclasses"
+ */
 struct DBusServerVTable
 {
   void        (* finalize)      (DBusServer *server);
@@ -43,6 +46,9 @@
   /**< Disconnect this server. */
 };
 
+/**
+ * Internals of DBusServer object
+ */
 struct DBusServer
 {
   int refcount;                               /**< Reference count. */

Index: dbus-server-unix.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-server-unix.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- dbus-server-unix.c	4 Jun 2003 05:20:19 -0000	1.18
+++ dbus-server-unix.c	30 Sep 2003 02:32:53 -0000	1.19
@@ -25,6 +25,7 @@
 #include "dbus-server-unix.h"
 #include "dbus-transport-unix.h"
 #include "dbus-connection-internal.h"
+#include "dbus-string.h"
 #include <sys/types.h>
 #include <unistd.h>
 

Index: dbus-server.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-server.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- dbus-server.c	22 Jun 2003 19:39:47 -0000	1.29
+++ dbus-server.c	30 Sep 2003 02:32:53 -0000	1.30
@@ -23,6 +23,7 @@
 
 #include "dbus-server.h"
 #include "dbus-server-unix.h"
+#include "dbus-string.h"
 #ifdef DBUS_BUILD_TESTS
 #include "dbus-server-debug-pipe.h"
 #endif

Index: dbus-sha.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-sha.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- dbus-sha.h	22 Feb 2003 17:29:48 -0000	1.1
+++ dbus-sha.h	30 Sep 2003 02:32:53 -0000	1.2
@@ -31,11 +31,14 @@
 
 typedef struct DBusSHAContext DBusSHAContext;
 
+/**
+ * Struct storing state of the SHA algorithm
+ */
 struct DBusSHAContext
 {
   dbus_uint32_t  digest[5];         /**< Message digest */
   dbus_uint32_t  count_lo;          /**< 64-bit bit count */
-  dbus_uint32_t  count_hi;
+  dbus_uint32_t  count_hi;          /**< No clue */
   dbus_uint32_t  data[16];          /**< SHA data buffer */
 };
 

Index: dbus-spawn.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-spawn.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- dbus-spawn.c	11 May 2003 07:59:08 -0000	1.12
+++ dbus-spawn.c	30 Sep 2003 02:32:53 -0000	1.13
@@ -176,28 +176,31 @@
   CHILD_PID                /* Followed by pid_t */
 };
 
+/**
+ * Babysitter implementation details
+ */
 struct DBusBabysitter
 {
-  int refcount;
+  int refcount; /**< Reference count */
 
   char *executable; /**< executable name to use in error messages */
   
-  int socket_to_babysitter;
-  int error_pipe_from_child;
+  int socket_to_babysitter; /**< Connection to the babysitter process */
+  int error_pipe_from_child; /**< Connection to the process that does the exec() */
   
-  pid_t sitter_pid;
-  pid_t grandchild_pid;
+  pid_t sitter_pid;  /**< PID Of the babysitter */
+  pid_t grandchild_pid; /**< PID of the grandchild */
 
-  DBusWatchList *watches;
+  DBusWatchList *watches; /**< Watches */
 
-  DBusWatch *error_watch;
-  DBusWatch *sitter_watch;
+  DBusWatch *error_watch; /**< Error pipe watch */
+  DBusWatch *sitter_watch; /**< Sitter pipe watch */
 
-  int errnum;
-  int status;
-  unsigned int have_child_status : 1;
-  unsigned int have_fork_errnum : 1;
-  unsigned int have_exec_errnum : 1;
+  int errnum; /**< Error number */
+  int status; /**< Exit status code */
+  unsigned int have_child_status : 1; /**< True if child status has been reaped */
+  unsigned int have_fork_errnum : 1; /**< True if we have an error code from fork() */
+  unsigned int have_exec_errnum : 1; /**< True if we have an error code from exec() */
 };
 
 static DBusBabysitter*

Index: dbus-string.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-string.c,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -d -r1.41 -r1.42
--- dbus-string.c	12 May 2003 02:44:44 -0000	1.41
+++ dbus-string.c	30 Sep 2003 02:32:53 -0000	1.42
@@ -25,6 +25,8 @@
 #include "dbus-string.h"
 /* we allow a system header here, for speed/convenience */
 #include <string.h>
+/* for vsnprintf */
+#include <stdio.h>
 #include "dbus-marshal.h"
 #define DBUS_CAN_USE_DBUS_STRING_PRIVATE 1
 #include "dbus-string-private.h"
@@ -560,26 +562,30 @@
 }
 
 /**
- * Inserts the given byte at the given position.
+ * Inserts a number of bytes of a given value at the
+ * given position.
  *
  * @param str the string
  * @param i the position
+ * @param n_bytes number of bytes
  * @param byte the value to insert
  * @returns #TRUE on success
  */
 dbus_bool_t
-_dbus_string_insert_byte (DBusString   *str,
-                          int           i,
-                          unsigned char byte)
+_dbus_string_insert_bytes (DBusString   *str,
+			   int           i,
+			   int           n_bytes,
+			   unsigned char byte)
 {
   DBUS_STRING_PREAMBLE (str);
   _dbus_assert (i <= real->len);
   _dbus_assert (i >= 0);
+  _dbus_assert (n_bytes > 0);
   
-  if (!open_gap (1, real, i))
+  if (!open_gap (n_bytes, real, i))
     return FALSE;
   
-  real->str[i] = byte;
+  memset (real->str + i, byte, n_bytes);
 
   return TRUE;
 }
@@ -964,7 +970,7 @@
   p = (dbus_uint64_t*) (real->str + (real->len - 8));
   *p = *((dbus_uint64_t*)octets);
 #else
-  char *p;
+  unsigned char *p;
   DBUS_STRING_PREAMBLE (str);
   
   if (!align_length_then_lengthen (str, 8, 8))
@@ -987,6 +993,59 @@
 }
 
 /**
+ * Appends a printf-style formatted string
+ * to the #DBusString.
+ *
+ * @param str the string
+ * @param format printf format
+ * @param args variable argument list
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_string_append_printf_valist  (DBusString        *str,
+                                    const char        *format,
+                                    va_list            args)
+{
+  int len;
+  char c;
+  DBUS_STRING_PREAMBLE (str);
+  
+  /* Measure the message length without terminating nul */
+  len = vsnprintf (&c, 1, format, args);
+
+  if (!_dbus_string_lengthen (str, len))
+    return FALSE;
+
+  vsprintf (real->str + (real->len - len),
+            format, args);
+
+  return TRUE;
+}
+
+/**
+ * Appends a printf-style formatted string
+ * to the #DBusString.
+ *
+ * @param str the string
+ * @param format printf format
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_string_append_printf (DBusString        *str,
+                            const char        *format,
+                            ...)
+{
+  va_list args;
+  dbus_bool_t retval;
+  
+  va_start (args, format);
+  retval = _dbus_string_append_printf_valist (str, format, args);
+  va_end (args);
+
+  return retval;
+}
+
+/**
  * Appends block of bytes with the given length to a DBusString.
  *
  * @param str the DBusString
@@ -1752,7 +1811,7 @@
 }
 
 /**
- * Assigns a newline-terminated or \r\n-terminated line from the front
+ * Assigns a newline-terminated or \\r\\n-terminated line from the front
  * of the string to the given dest string. The dest string's previous
  * contents are deleted. If the source string contains no newline,
  * moves the entire source string to the dest string.
@@ -2791,13 +2850,84 @@
 }
 
 /**
- * Checks that the given range of the string is a valid message name
+ * Checks that the given range of the string is a valid object path
+ * name in the D-BUS protocol. This includes a length restriction,
+ * etc., see the specification. It does not validate UTF-8, that has
+ * to be done separately for now.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that isn't in the string.
+ *
+ * @todo change spec to disallow more things, such as spaces in the
+ * path name
+ * 
+ * @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_string_validate_path (const DBusString  *str,
+                            int                start,
+                            int                len)
+{
+  const unsigned char *s;
+  const unsigned char *end;
+  const unsigned char *last_slash;
+  
+  DBUS_CONST_STRING_PREAMBLE (str);
+  _dbus_assert (start >= 0);
+  _dbus_assert (len >= 0);
+  _dbus_assert (start <= real->len);
+  
+  if (len > real->len - start)
+    return FALSE;
+
+  if (len > DBUS_MAXIMUM_NAME_LENGTH)
+    return FALSE;
+
+  if (len == 0)
+    return FALSE;
+
+  s = real->str + start;
+  end = s + len;
+
+  if (*s != '/')
+    return FALSE;
+  last_slash = s;
+  ++s;
+  
+  while (s != end)
+    {
+      if (*s == '/')
+        {
+          if ((s - last_slash) < 2)
+            return FALSE; /* no empty path components allowed */
+
+          last_slash = s;
+        }
+      
+      ++s;
+    }
+
+  if ((end - last_slash) < 2 &&
+      len > 1)
+    return FALSE; /* trailing slash not allowed unless the string is "/" */
+  
+  return TRUE;
+}
+
+/**
+ * Checks that the given range of the string is a valid interface name
  * in the D-BUS protocol. This includes a length restriction, etc.,
  * see the specification. It does not validate UTF-8, that has to be
  * done separately for now.
  *
  * @todo this is inconsistent with most of DBusString in that
  * it allows a start,len range that isn't in the string.
+ *
+ * @todo change spec to disallow more things, such as spaces in the
+ * interface name
  * 
  * @param str the string
  * @param start first byte index to check
@@ -2805,9 +2935,9 @@
  * @returns #TRUE if the byte range exists and is a valid name
  */
 dbus_bool_t
-_dbus_string_validate_name (const DBusString  *str,
-                            int                start,
-                            int                len)
+_dbus_string_validate_interface (const DBusString  *str,
+                                 int                start,
+                                 int                len)
 {
   const unsigned char *s;
   const unsigned char *end;
@@ -2847,6 +2977,89 @@
   return TRUE;
 }
 
+/**
+ * Checks that the given range of the string is a valid member name
+ * in the D-BUS protocol. This includes a length restriction, etc.,
+ * see the specification. It does not validate UTF-8, that has to be
+ * done separately for now.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that isn't in the string.
+ * 
+ * @todo change spec to disallow more things, such as spaces in the
+ * member name
+ * 
+ * @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_string_validate_member (const DBusString  *str,
+                              int                start,
+                              int                len)
+{
+  const unsigned char *s;
+  const unsigned char *end;
+  dbus_bool_t saw_dot;
+  
+  DBUS_CONST_STRING_PREAMBLE (str);
+  _dbus_assert (start >= 0);
+  _dbus_assert (len >= 0);
+  _dbus_assert (start <= real->len);
+  
+  if (len > real->len - start)
+    return FALSE;
+
+  if (len > DBUS_MAXIMUM_NAME_LENGTH)
+    return FALSE;
+
+  if (len == 0)
+    return FALSE;
+
+  saw_dot = FALSE;
+  s = real->str + start;
+  end = s + len;
+  while (s != end)
+    {
+      if (*s == '.')
+        {
+          saw_dot = TRUE;
+          break;
+        }
+      
+      ++s;
+    }
+
+  /* No dot allowed in member names */
+  if (saw_dot)
+    return FALSE;
+  
+  return TRUE;
+}
+
+/**
+ * Checks that the given range of the string is a valid error name
+ * in the D-BUS protocol. This includes a length restriction, etc.,
+ * see the specification. It does not validate UTF-8, that has to be
+ * done separately for now.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that isn't in the string.
+ * 
+ * @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_string_validate_error_name (const DBusString  *str,
+                                  int                start,
+                                  int                len)
+{
+  /* Same restrictions as interface name at the moment */
+  return _dbus_string_validate_interface (str, start, len);
+}
 
 /**
  * Checks that the given range of the string is a valid service name
@@ -2856,6 +3069,9 @@
  *
  * @todo this is inconsistent with most of DBusString in that
  * it allows a start,len range that isn't in the string.
+ *
+ * @todo change spec to disallow more things, such as spaces in the
+ * service name
  * 
  * @param str the string
  * @param start first byte index to check
@@ -3107,6 +3323,24 @@
   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;
+  const char *valid_paths[] = {
+    "/",
+    "/foo/bar",
+    "/foo",
+    "/foo/bar/baz"
+  };
+  const char *invalid_paths[] = {
+    "bar",
+    "bar/baz",
+    "/foo/bar/",
+    "/foo/"
+    "foo/",
+    "boo//blah",
+    "//",
+    "///",
+    "foo///blah/",
+    "Hello World"
+  };
   
   i = 0;
   while (i < _DBUS_N_ELEMENTS (lens))
@@ -3342,23 +3576,26 @@
   _dbus_string_set_byte (&str, 1, 'q');
   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'q');
 
-  if (!_dbus_string_insert_byte (&str, 0, 255))
+  if (!_dbus_string_insert_bytes (&str, 0, 1, 255))
     _dbus_assert_not_reached ("can't insert byte");
 
-  if (!_dbus_string_insert_byte (&str, 2, 'Z'))
+  if (!_dbus_string_insert_bytes (&str, 2, 4, 'Z'))
     _dbus_assert_not_reached ("can't insert byte");
 
-  if (!_dbus_string_insert_byte (&str, _dbus_string_get_length (&str), 'W'))
+  if (!_dbus_string_insert_bytes (&str, _dbus_string_get_length (&str), 1, 'W'))
     _dbus_assert_not_reached ("can't insert byte");
   
   _dbus_assert (_dbus_string_get_byte (&str, 0) == 255);
   _dbus_assert (_dbus_string_get_byte (&str, 1) == 'H');
   _dbus_assert (_dbus_string_get_byte (&str, 2) == 'Z');
-  _dbus_assert (_dbus_string_get_byte (&str, 3) == 'q');
-  _dbus_assert (_dbus_string_get_byte (&str, 4) == 'l');
-  _dbus_assert (_dbus_string_get_byte (&str, 5) == 'l');
-  _dbus_assert (_dbus_string_get_byte (&str, 6) == 'o');
-  _dbus_assert (_dbus_string_get_byte (&str, 7) == 'W');
+  _dbus_assert (_dbus_string_get_byte (&str, 3) == 'Z');
+  _dbus_assert (_dbus_string_get_byte (&str, 4) == 'Z');
+  _dbus_assert (_dbus_string_get_byte (&str, 5) == 'Z');
+  _dbus_assert (_dbus_string_get_byte (&str, 6) == 'q');
+  _dbus_assert (_dbus_string_get_byte (&str, 7) == 'l');
+  _dbus_assert (_dbus_string_get_byte (&str, 8) == 'l');
+  _dbus_assert (_dbus_string_get_byte (&str, 9) == 'o');
+  _dbus_assert (_dbus_string_get_byte (&str, 10) == 'W');
 
   _dbus_string_free (&str);
   
@@ -3481,7 +3718,38 @@
   /* Base 64 and Hex encoding */
   test_roundtrips (test_base64_roundtrip);
   test_roundtrips (test_hex_roundtrip);
-  
+
+  /* Path validation */
+  i = 0;
+  while (i < (int) _DBUS_N_ELEMENTS (valid_paths))
+    {
+      _dbus_string_init_const (&str, valid_paths[i]);
+
+      if (!_dbus_string_validate_path (&str, 0,
+                                       _dbus_string_get_length (&str)))
+        {
+          _dbus_warn ("Path \"%s\" should have been valid\n", valid_paths[i]);
+          _dbus_assert_not_reached ("invalid path");
+        }
+      
+      ++i;
+    }
+
+  i = 0;
+  while (i < (int) _DBUS_N_ELEMENTS (invalid_paths))
+    {
+      _dbus_string_init_const (&str, invalid_paths[i]);
+      
+      if (_dbus_string_validate_path (&str, 0,
+                                      _dbus_string_get_length (&str)))
+        {
+          _dbus_warn ("Path \"%s\" should have been invalid\n", invalid_paths[i]);
+          _dbus_assert_not_reached ("valid path");
+        }
+      
+      ++i;
+    }
+         
   return TRUE;
 }
 

Index: dbus-string.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-string.h,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- dbus-string.h	12 May 2003 02:44:44 -0000	1.20
+++ dbus-string.h	30 Sep 2003 02:32:53 -0000	1.21
@@ -28,11 +28,15 @@
 
 #include <dbus/dbus-memory.h>
 #include <dbus/dbus-types.h>
+#include <dbus/dbus-sysdeps.h>
 
-DBUS_BEGIN_DECLS;
+#include <stdarg.h>
 
-typedef struct DBusString DBusString;
+DBUS_BEGIN_DECLS;
 
+/**
+ * DBusString object
+ */
 struct DBusString
 {
   void *dummy1; /**< placeholder */
@@ -68,8 +72,9 @@
                                                   unsigned char      byte);
 unsigned char _dbus_string_get_byte              (const DBusString  *str,
                                                   int                start);
-dbus_bool_t   _dbus_string_insert_byte           (DBusString        *str,
+dbus_bool_t   _dbus_string_insert_bytes          (DBusString        *str,
                                                   int                i,
+						  int                n_bytes,
                                                   unsigned char      byte);
 dbus_bool_t   _dbus_string_steal_data            (DBusString        *str,
                                                   char             **data_return);
@@ -111,6 +116,12 @@
                                                   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);
+dbus_bool_t   _dbus_string_append_printf_valist  (DBusString        *str,
+                                                  const char        *format,
+                                                  va_list            args);
 void          _dbus_string_delete                (DBusString        *str,
                                                   int                start,
                                                   int                len);
@@ -216,7 +227,16 @@
 dbus_bool_t   _dbus_string_validate_nul          (const DBusString  *str,
                                                   int                start,
                                                   int                len);
-dbus_bool_t   _dbus_string_validate_name         (const DBusString  *str,
+dbus_bool_t   _dbus_string_validate_path         (const DBusString  *str,
+                                                  int                start,
+                                                  int                len);
+dbus_bool_t   _dbus_string_validate_interface    (const DBusString  *str,
+                                                  int                start,
+                                                  int                len);
+dbus_bool_t   _dbus_string_validate_member       (const DBusString  *str,
+                                                  int                start,
+                                                  int                len);
+dbus_bool_t   _dbus_string_validate_error_name   (const DBusString  *str,
                                                   int                start,
                                                   int                len);
 dbus_bool_t   _dbus_string_validate_service      (const DBusString  *str,

Index: dbus-sysdeps.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-sysdeps.c,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -d -r1.64 -r1.65
--- dbus-sysdeps.c	15 Jun 2003 10:45:06 -0000	1.64
+++ dbus-sysdeps.c	30 Sep 2003 02:32:53 -0000	1.65
@@ -2515,9 +2515,12 @@
     return FALSE;
 }
 
+/**
+ * Internals of directory iterator
+ */
 struct DBusDirIter
 {
-  DIR *d;
+  DIR *d; /**< The DIR* from opendir() */
   
 };
 

Index: dbus-sysdeps.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-sysdeps.h,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -d -r1.35 -r1.36
--- dbus-sysdeps.h	4 Jun 2003 05:20:20 -0000	1.35
+++ dbus-sysdeps.h	30 Sep 2003 02:32:53 -0000	1.36
@@ -25,7 +25,6 @@
 #ifndef DBUS_SYSDEPS_H
 #define DBUS_SYSDEPS_H
 
-#include <dbus/dbus-string.h>
 #include <dbus/dbus-errors.h>
 
 /* this is perhaps bogus, but strcmp() etc. are faster if we use the
@@ -47,6 +46,8 @@
  * dbus-memory.c)
  */
 
+typedef struct DBusString DBusString;
+
 #if     __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
 #define _DBUS_GNUC_PRINTF( format_idx, arg_idx )    \
   __attribute__((__format__ (__printf__, format_idx, arg_idx)))
@@ -96,12 +97,14 @@
 #define DBUS_UID_FORMAT "%lu"
 #define DBUS_GID_FORMAT "%lu"
 
+/**
+ * Struct representing socket credentials
+ */
 typedef struct
 {
-  /* Set to DBUS_PID_UNSET etc. if not available */
-  dbus_pid_t pid;
-  dbus_uid_t uid;
-  dbus_gid_t gid;
+  dbus_pid_t pid; /**< process ID or DBUS_PID_UNSET */
+  dbus_uid_t uid; /**< user ID or DBUS_UID_UNSET */
+  dbus_gid_t gid; /**< group ID or DBUS_GID_UNSET */
 } DBusCredentials;
 
 int _dbus_connect_unix_socket (const char     *path,
@@ -134,6 +137,9 @@
 typedef struct DBusUserInfo  DBusUserInfo;
 typedef struct DBusGroupInfo DBusGroupInfo;
 
+/**
+ * Information about a UNIX user
+ */
 struct DBusUserInfo
 {
   dbus_uid_t  uid;            /**< UID */
@@ -144,6 +150,9 @@
   char       *homedir;        /**< Home directory */
 };
 
+/**
+ * Information about a UNIX group
+ */
 struct DBusGroupInfo
 {
   dbus_gid_t  gid;            /**< GID */
@@ -172,9 +181,13 @@
 dbus_gid_t    _dbus_getgid (void);
 
 typedef struct DBusAtomic DBusAtomic;
+
+/**
+ * An atomic integer.
+ */
 struct DBusAtomic
 {
-  volatile dbus_int32_t value;
+  volatile dbus_int32_t value; /**< Value of the atomic integer. */
 };
 
 dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic);
@@ -187,11 +200,14 @@
 #define _DBUS_POLLHUP     0x0010    /* Hung up */
 #define _DBUS_POLLNVAL    0x0020    /* Invalid request: fd not open */
 
+/**
+ * A portable struct pollfd wrapper. 
+ */
 typedef struct
 {
-  int fd;
-  short events;
-  short revents;
+  int fd;            /**< File descriptor */
+  short events;      /**< Events to poll for */
+  short revents;     /**< Events that occurred */
 } DBusPollFD;
 
 int _dbus_poll (DBusPollFD *fds,
@@ -248,16 +264,19 @@
 
 void _dbus_exit (int code) _DBUS_GNUC_NORETURN;
 
+/**
+ * Portable struct with stat() results
+ */
 typedef struct
 {
-  unsigned long mode;
-  unsigned long nlink;
-  dbus_uid_t    uid;
-  dbus_gid_t    gid;
-  unsigned long size;
-  unsigned long atime;
-  unsigned long mtime;
-  unsigned long ctime;
+  unsigned long mode;  /**< File mode */
+  unsigned long nlink; /**< Number of hard links */
+  dbus_uid_t    uid;   /**< User owning file */
+  dbus_gid_t    gid;   /**< Group owning file */
+  unsigned long size;  /**< Size of file */
+  unsigned long atime; /**< Access time */
+  unsigned long mtime; /**< Modify time */
+  unsigned long ctime; /**< Creation time */
 } DBusStat;
 
 dbus_bool_t _dbus_stat             (const DBusString *filename,

Index: dbus-test.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-test.c,v
retrieving revision 1.30
retrieving revision 1.31
diff -u -d -r1.30 -r1.31
--- dbus-test.c	28 Jun 2003 23:12:11 -0000	1.30
+++ dbus-test.c	30 Sep 2003 02:32:53 -0000	1.31
@@ -81,7 +81,7 @@
     die ("strings");
 
   check_memleaks ();
-
+  
   printf ("%s: running sysdeps tests\n", "dbus-test");
   if (!_dbus_sysdeps_test ())
     die ("sysdeps");
@@ -99,6 +99,12 @@
     die ("address parsing");
 
   check_memleaks ();
+
+  printf ("%s: running object tree tests\n", "dbus-test");
+  if (!_dbus_object_tree_test ())
+    die ("object tree");
+  
+  check_memleaks ();
   
   printf ("%s: running marshalling tests\n", "dbus-test");
   if (!_dbus_marshal_test ())
@@ -129,12 +135,6 @@
     die ("messages");
 
   check_memleaks ();
-
-  printf ("%s: running message handler tests\n", "dbus-test");
-  if (!_dbus_message_handler_test (test_data_dir))
-    die ("message handler");
-
-  check_memleaks ();
   
   printf ("%s: running hash table tests\n", "dbus-test");
   if (!_dbus_hash_test ())
@@ -179,6 +179,12 @@
     die ("auth");
 
   check_memleaks ();
+
+  printf ("%s: running pending call tests\n", "dbus-test");
+  if (!_dbus_pending_call_test (test_data_dir))
+    die ("auth");
+
+  check_memleaks ();
   
   printf ("%s: completed successfully\n", "dbus-test");
 #else

Index: dbus-test.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-test.h,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- dbus-test.h	28 Jun 2003 23:12:11 -0000	1.22
+++ dbus-test.h	30 Sep 2003 02:32:53 -0000	1.23
@@ -43,7 +43,6 @@
 dbus_bool_t _dbus_string_test          (void);
 dbus_bool_t _dbus_address_test         (void);
 dbus_bool_t _dbus_message_test         (const char *test_data_dir);
-dbus_bool_t _dbus_message_handler_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);
@@ -53,7 +52,8 @@
 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_memory_test	       (void);
-
+dbus_bool_t _dbus_object_tree_test     (void);
+dbus_bool_t _dbus_pending_call_test    (const char *test_data_dir);
 
 void        dbus_internal_do_not_use_run_tests         (const char          *test_data_dir);
 dbus_bool_t dbus_internal_do_not_use_try_message_file  (const DBusString    *filename,

Index: dbus-threads.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-threads.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- dbus-threads.c	23 Jun 2003 02:12:19 -0000	1.17
+++ dbus-threads.c	30 Sep 2003 02:32:53 -0000	1.18
@@ -223,10 +223,10 @@
 #define LOCK_ADDR(name) (& _dbus_lock_##name)
     LOCK_ADDR (list),
     LOCK_ADDR (connection_slots),
+    LOCK_ADDR (pending_call_slots),
     LOCK_ADDR (server_slots),
     LOCK_ADDR (message_slots),
     LOCK_ADDR (atomic),
-    LOCK_ADDR (message_handler),
     LOCK_ADDR (bus),
     LOCK_ADDR (shutdown_funcs),
     LOCK_ADDR (system_users)

Index: dbus-threads.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-threads.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- dbus-threads.h	15 Feb 2003 16:25:08 -0000	1.3
+++ dbus-threads.h	30 Sep 2003 02:32:53 -0000	1.4
@@ -66,30 +66,34 @@
   DBUS_THREAD_FUNCTIONS_ALL_MASK     = (1 << 10) - 1
 } DBusThreadFunctionsMask;
 
+/**
+ * Functions that must be implemented to make the D-BUS
+ * library thread-aware. 
+ */
 typedef struct
 {
-  unsigned int mask;
+  unsigned int mask; /**< Mask indicating which functions are present. */
 
-  DBusMutexNewFunction mutex_new;
-  DBusMutexFreeFunction mutex_free;
-  DBusMutexLockFunction mutex_lock;
-  DBusMutexUnlockFunction mutex_unlock;
+  DBusMutexNewFunction mutex_new; /**< Function to create a mutex */
+  DBusMutexFreeFunction mutex_free; /**< Function to free a mutex */
+  DBusMutexLockFunction mutex_lock; /**< Function to lock a mutex */
+  DBusMutexUnlockFunction mutex_unlock; /**< Function to unlock a mutex */
 
-  DBusCondVarNewFunction condvar_new;
-  DBusCondVarFreeFunction condvar_free;
-  DBusCondVarWaitFunction condvar_wait;
-  DBusCondVarWaitTimeoutFunction condvar_wait_timeout;
-  DBusCondVarWakeOneFunction condvar_wake_one;
-  DBusCondVarWakeAllFunction condvar_wake_all;
+  DBusCondVarNewFunction condvar_new; /**< Function to create a condition variable */
+  DBusCondVarFreeFunction condvar_free; /**< Function to free a condition variable */
+  DBusCondVarWaitFunction condvar_wait; /**< Function to wait on a condition */
+  DBusCondVarWaitTimeoutFunction condvar_wait_timeout; /**< Function to wait on a condition with a timeout */
+  DBusCondVarWakeOneFunction condvar_wake_one; /**< Function to wake one thread waiting on the condition */
+  DBusCondVarWakeAllFunction condvar_wake_all; /**< Function to wake all threads waiting on the condition */
   
-  void (* padding1) (void);
-  void (* padding2) (void);
-  void (* padding3) (void);
-  void (* padding4) (void);
-  void (* padding5) (void);
-  void (* padding6) (void);
-  void (* padding7) (void);
-  void (* padding8) (void);
+  void (* padding1) (void); /**< Reserved for future expansion */
+  void (* padding2) (void); /**< Reserved for future expansion */
+  void (* padding3) (void); /**< Reserved for future expansion */
+  void (* padding4) (void); /**< Reserved for future expansion */
+  void (* padding5) (void); /**< Reserved for future expansion */
+  void (* padding6) (void); /**< Reserved for future expansion */
+  void (* padding7) (void); /**< Reserved for future expansion */
+  void (* padding8) (void); /**< Reserved for future expansion */
   
 } DBusThreadFunctions;
 

Index: dbus-timeout.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-timeout.c,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- dbus-timeout.c	12 May 2003 02:44:44 -0000	1.10
+++ dbus-timeout.c	30 Sep 2003 02:32:53 -0000	1.11
@@ -33,6 +33,9 @@
  * @{
  */
 
+/**
+ * Internals of DBusTimeout
+ */
 struct DBusTimeout
 {
   int refcount;                                /**< Reference count */

Index: dbus-transport-protected.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-transport-protected.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- dbus-transport-protected.h	14 Apr 2003 02:29:21 -0000	1.9
+++ dbus-transport-protected.h	30 Sep 2003 02:32:53 -0000	1.10
@@ -34,6 +34,10 @@
 
 typedef struct DBusTransportVTable DBusTransportVTable;
 
+/**
+ * The virtual table that must be implemented to
+ * create a new kind of transport.
+ */
 struct DBusTransportVTable
 {
   void        (* finalize)              (DBusTransport *transport);
@@ -69,6 +73,12 @@
   /**< Outstanding messages counter changed */
 };
 
+/**
+ * Object representing a transport such as a socket.
+ * A transport can shuttle messages from point A to point B,
+ * and is the backend for a #DBusConnection.
+ *
+ */
 struct DBusTransport
 {
   int refcount;                               /**< Reference count. */

Index: dbus-transport.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-transport.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- dbus-transport.c	4 Jun 2003 05:20:20 -0000	1.33
+++ dbus-transport.c	30 Sep 2003 02:32:53 -0000	1.34
@@ -813,7 +813,9 @@
 {
   DBusDispatchStatus status;
 
+#if 0
   _dbus_verbose ("_dbus_transport_queue_messages()\n");
+#endif
   
   /* Queue any messages */
   while ((status = _dbus_transport_get_dispatch_status (transport)) == DBUS_DISPATCH_DATA_REMAINS)

Index: dbus-types.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-types.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- dbus-types.h	29 Apr 2003 22:57:13 -0000	1.7
+++ dbus-types.h	30 Sep 2003 02:32:53 -0000	1.8
@@ -83,6 +83,10 @@
  *
  * A 64-bit unsigned integer on all platforms that support it.
  * If supported, #DBUS_HAVE_INT64 will be defined.
+ *
+ * C99 requires a 64-bit type and most likely all interesting
+ * compilers support one. GLib for example flat-out requires
+ * a 64-bit type.
  */
 
 /**
@@ -90,6 +94,10 @@
  *
  * A 64-bit signed integer on all platforms that support it.
  * If supported, #DBUS_HAVE_INT64 will be defined.
+ *
+ * C99 requires a 64-bit type and most likely all interesting
+ * compilers support one. GLib for example flat-out requires
+ * a 64-bit type.
  */
 
 /**

Index: dbus-userdb.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-userdb.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbus-userdb.c	28 Apr 2003 19:29:42 -0000	1.4
+++ dbus-userdb.c	30 Sep 2003 02:32:53 -0000	1.5
@@ -26,14 +26,17 @@
 #include "dbus-internals.h"
 #include <string.h>
 
+/**
+ * Internals of DBusUserDatabase
+ */
 struct DBusUserDatabase
 {
-  int refcount;
+  int refcount; /**< Reference count */
 
-  DBusHashTable *users;
-  DBusHashTable *groups;
-  DBusHashTable *users_by_name;
-  DBusHashTable *groups_by_name;
+  DBusHashTable *users; /**< Users in the database by UID */
+  DBusHashTable *groups; /**< Groups in the database by GID */
+  DBusHashTable *users_by_name; /**< Users in the database by name */
+  DBusHashTable *groups_by_name; /**< Groups in the database by name */
 };
 
 static void

Index: dbus-watch.c
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus-watch.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- dbus-watch.c	16 May 2003 20:09:25 -0000	1.13
+++ dbus-watch.c	30 Sep 2003 02:32:53 -0000	1.14
@@ -33,6 +33,9 @@
  * @{
  */
 
+/**
+ * Implementation of DBusWatch
+ */
 struct DBusWatch
 {
   int refcount;                        /**< Reference count */

Index: dbus.h
===================================================================
RCS file: /cvs/dbus/dbus/dbus/dbus.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- dbus.h	29 Apr 2003 21:56:37 -0000	1.15
+++ dbus.h	30 Sep 2003 02:32:53 -0000	1.16
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus.h  Convenience header including all other headers
  *
- * Copyright (C) 2002  Red Hat Inc.
+ * Copyright (C) 2002, 2003  Red Hat Inc.
  *
  * Licensed under the Academic Free License version 1.2
  * 
@@ -37,7 +37,7 @@
 #include <dbus/dbus-errors.h>
 #include <dbus/dbus-macros.h>
 #include <dbus/dbus-message.h>
-#include <dbus/dbus-message-handler.h>
+#include <dbus/dbus-pending-call.h>
 #include <dbus/dbus-protocol.h>
 #include <dbus/dbus-server.h>
 #include <dbus/dbus-threads.h>