summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-09-30 02:33:11 +0000
committerHavoc Pennington <hp@redhat.com>2003-09-30 02:33:11 +0000
commitdfd1292d525d01914141cc86013589c6e0ea9d5c (patch)
treefd0c5dd4296d970abcd70f16dd39cca711177df0
parentc30e28fdae3863651cfd7b5d3d0721a1b21a6919 (diff)
parent626db3fc5c36879186315fcc6de78824a7b75e9b (diff)
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
-rw-r--r--ChangeLog1986
-rw-r--r--Doxyfile.in2
-rw-r--r--HACKING9
-rw-r--r--Makefile.am5
-rw-r--r--acinclude.m426
-rw-r--r--bus/Makefile.am2
-rw-r--r--bus/activation.c4
-rw-r--r--bus/bus.c97
-rw-r--r--bus/bus.h71
-rw-r--r--bus/config-parser.c310
-rw-r--r--bus/connection.c169
-rw-r--r--bus/connection.h13
-rw-r--r--bus/dbus-daemon-1.1.in90
-rw-r--r--bus/desktop-file.c14
-rw-r--r--bus/dispatch.c647
-rw-r--r--bus/dispatch.h3
-rw-r--r--bus/driver.c250
-rw-r--r--bus/policy.c178
-rw-r--r--bus/policy.h21
-rw-r--r--bus/services.c8
-rw-r--r--bus/session.conf.in11
-rw-r--r--bus/signals.c778
-rw-r--r--bus/signals.h83
-rw-r--r--bus/system.conf.in8
-rw-r--r--bus/test-main.c6
-rw-r--r--bus/test.c61
-rw-r--r--bus/test.h1
-rw-r--r--configure.in81
-rw-r--r--dbus/Makefile.am6
-rw-r--r--dbus/dbus-address.c28
-rw-r--r--dbus/dbus-auth.c44
-rw-r--r--dbus/dbus-bus.c159
-rw-r--r--dbus/dbus-bus.h7
-rw-r--r--dbus/dbus-connection-internal.h58
-rw-r--r--dbus/dbus-connection.c1248
-rw-r--r--dbus/dbus-connection.h94
-rw-r--r--dbus/dbus-dataslot.h10
-rw-r--r--dbus/dbus-errors.c144
-rw-r--r--dbus/dbus-errors.h18
-rw-r--r--dbus/dbus-hash.c386
-rw-r--r--dbus/dbus-hash.h131
-rw-r--r--dbus/dbus-internals.c58
-rw-r--r--dbus/dbus-internals.h7
-rw-r--r--dbus/dbus-keyring.c3
-rw-r--r--dbus/dbus-mainloop.c5
-rw-r--r--dbus/dbus-mainloop.h5
-rw-r--r--dbus/dbus-marshal.c249
-rw-r--r--dbus/dbus-marshal.h30
-rw-r--r--dbus/dbus-md5.h9
-rw-r--r--dbus/dbus-message-builder.c193
-rw-r--r--dbus/dbus-message.c1605
-rw-r--r--dbus/dbus-message.h89
-rw-r--r--dbus/dbus-object-tree.c1481
-rw-r--r--dbus/dbus-object-tree.h52
-rw-r--r--dbus/dbus-pending-call.c429
-rw-r--r--dbus/dbus-pending-call.h58
-rw-r--r--dbus/dbus-protocol.h69
-rw-r--r--dbus/dbus-server-debug-pipe.c1
-rw-r--r--dbus/dbus-server-protected.h6
-rw-r--r--dbus/dbus-server-unix.c1
-rw-r--r--dbus/dbus-server.c1
-rw-r--r--dbus/dbus-sha.h5
-rw-r--r--dbus/dbus-spawn.c29
-rw-r--r--dbus/dbus-string.c310
-rw-r--r--dbus/dbus-string.h28
-rw-r--r--dbus/dbus-sysdeps.c5
-rw-r--r--dbus/dbus-sysdeps.h53
-rw-r--r--dbus/dbus-test.c20
-rw-r--r--dbus/dbus-test.h4
-rw-r--r--dbus/dbus-threads.c2
-rw-r--r--dbus/dbus-threads.h46
-rw-r--r--dbus/dbus-timeout.c3
-rw-r--r--dbus/dbus-transport-protected.h10
-rw-r--r--dbus/dbus-transport.c2
-rw-r--r--dbus/dbus-types.h8
-rw-r--r--dbus/dbus-userdb.c13
-rw-r--r--dbus/dbus-watch.c3
-rw-r--r--dbus/dbus.h4
-rw-r--r--doc/TODO30
-rw-r--r--doc/dbus-specification.sgml624
-rw-r--r--glib/.cvsignore6
-rw-r--r--glib/Makefile.am70
-rw-r--r--glib/dbus-gidl.c524
-rw-r--r--glib/dbus-gidl.h120
-rw-r--r--glib/dbus-glib-tool.c77
-rw-r--r--glib/dbus-glib.h121
-rw-r--r--glib/dbus-gloader-expat.c262
-rw-r--r--glib/dbus-gmain.c100
-rw-r--r--glib/dbus-gobject.c790
-rw-r--r--glib/dbus-gparser.c670
-rw-r--r--glib/dbus-gparser.h65
-rw-r--r--glib/dbus-gproxy.c1249
-rw-r--r--glib/dbus-gtest-main.c46
-rw-r--r--glib/dbus-gtest.c77
-rw-r--r--glib/dbus-gtest.h35
-rw-r--r--glib/dbus-gthread.c2
-rw-r--r--glib/dbus-gtool-test.h31
-rw-r--r--glib/dbus-gutils.c96
-rw-r--r--glib/dbus-gutils.h40
-rw-r--r--test/Makefile.am9
-rw-r--r--test/break-loader.c4
-rw-r--r--test/data/incomplete-messages/missing-body.message9
-rw-r--r--test/data/invalid-messages/array-of-nil.message12
-rw-r--r--test/data/invalid-messages/array-with-mixed-types.message12
-rw-r--r--test/data/invalid-messages/bad-boolean-array.message10
-rw-r--r--test/data/invalid-messages/bad-boolean.message10
-rw-r--r--test/data/invalid-messages/bad-endian.message15
-rw-r--r--test/data/invalid-messages/bad-header-field-alignment.message34
-rw-r--r--test/data/invalid-messages/local-namespace.message12
-rw-r--r--test/data/invalid-messages/no-dot-in-name.message13
-rw-r--r--test/data/invalid-messages/not-nul-header-padding.message12
-rw-r--r--test/data/invalid-messages/overlong-name.message9
-rw-r--r--test/data/invalid-messages/too-little-header-padding.message12
-rw-r--r--test/data/invalid-messages/too-much-header-padding-by-far.message12
-rw-r--r--test/data/invalid-messages/too-much-header-padding.message12
-rw-r--r--test/data/invalid-messages/too-short-dict.message13
-rw-r--r--test/data/valid-config-files/debug-allow-all-sha1.conf.in4
-rw-r--r--test/data/valid-config-files/debug-allow-all.conf.in4
-rw-r--r--test/data/valid-config-files/many-rules.conf57
-rw-r--r--test/data/valid-config-files/system.d/test.conf8
-rw-r--r--test/data/valid-messages/array-of-array-of-uint32.message8
-rw-r--r--test/data/valid-messages/dict-simple.message8
-rw-r--r--test/data/valid-messages/dict.message6
-rw-r--r--test/data/valid-messages/emptiness.message8
-rw-r--r--test/data/valid-messages/lots-of-arguments.message8
-rw-r--r--test/data/valid-messages/no-padding.message8
-rw-r--r--test/data/valid-messages/opposite-endian.message12
-rw-r--r--test/data/valid-messages/recursive-types.message7
-rw-r--r--test/data/valid-messages/simplest-manual.message12
-rw-r--r--test/data/valid-messages/simplest.message7
-rw-r--r--test/data/valid-messages/standard-acquire-service.message14
-rw-r--r--test/data/valid-messages/standard-hello.message14
-rw-r--r--test/data/valid-messages/standard-list-services.message14
-rw-r--r--test/data/valid-messages/standard-service-exists.message14
-rw-r--r--test/data/valid-messages/unknown-header-field.message17
-rw-r--r--test/decode-gcov.c4
-rw-r--r--test/test-service.c54
-rw-r--r--tools/Makefile.am18
-rw-r--r--tools/dbus-monitor.c17
-rw-r--r--tools/dbus-print-message.c56
-rw-r--r--tools/dbus-send.129
-rw-r--r--tools/dbus-send.c82
-rw-r--r--tools/dbus-tree-view.c373
-rw-r--r--tools/dbus-tree-view.h36
-rw-r--r--tools/dbus-viewer.c320
145 files changed, 15613 insertions, 3014 deletions
diff --git a/ChangeLog b/ChangeLog
index 8ceaa693..30b1dd7f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,745 @@
+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
@@ -93,7 +835,7 @@
2003-07-01 Havoc Pennington <hp@redhat.com>
- * doc/dbus-specification.sgml: clarify the format of a type code,
+ * doc/dbus-specification.sgml: clarify the format of a type code,
change suggested by Jim Blandy
2003-06-29 Miloslav Trmac <mitr@volny.cz>
@@ -111,7 +853,7 @@
of %c%c%c%c.
(dbus_message_new): Remove obsolete @todo.
- * dbus/dbus-marshal.c (_dbus_marshal_set_int64)
+ * dbus/dbus-marshal.c (_dbus_marshal_set_int64)
(_dbus_marshal_set_uint64): Fix comment.
* dbus/dbus-message.c (append_int_field, append_uint_field): Don't
@@ -144,7 +886,7 @@
(Message.Message):
* gcj/org/freedesktop/dbus/natMessage.cc:
Fix the build system.
-
+
2003-06-22 Havoc Pennington <hp@pobox.com>
* mono/Connection.cs: add more bindings
@@ -154,13 +896,13 @@
2003-06-22 Havoc Pennington <hp@pobox.com>
- * mono/Connection.cs, mono/DBus.cs, mono/Error.cs:
+ * mono/Connection.cs, mono/DBus.cs, mono/Error.cs:
Start wrapping more stuff.
2003-06-22 Havoc Pennington <hp@pobox.com>
* mono/Message.cs: implement Message.Wrap() that ensures we only
- have a single C# wrapper per DBusMessage, assuming it works which
+ have a single C# wrapper per DBusMessage, assuming it works which
it probably doesn't.
* dbus/dbus-message.c (dbus_message_allocate_data_slot): new
@@ -172,9 +914,9 @@
* dbus/dbus-dataslot.c (_dbus_data_slot_allocator_unref)
(_dbus_data_slot_allocator_alloc): rework these to keep a
- reference count on each slot and automatically manage a global
+ reference count on each slot and automatically manage a global
slot ID variable passed in by address
-
+
* bus/bus.c: convert to new dataslot API
* dbus/dbus-bus.c: convert to new dataslot API
@@ -200,9 +942,9 @@
2003-06-22 Havoc Pennington <hp@pobox.com>
- * mono/*, gcj/*, configure.in, Makefile.am:
- Check in makefiles and subdirs for mono and gcj bindings.
- Neither binding actually exists, just trying to get through
+ * mono/*, gcj/*, configure.in, Makefile.am:
+ Check in makefiles and subdirs for mono and gcj bindings.
+ Neither binding actually exists, just trying to get through
all the build and other boring bits.
2003-06-21 Philip Blundell <philb@gnu.org>
@@ -213,7 +955,7 @@
2003-06-20 Anders Carlsson <andersca@codefactory.se>
- * dbus/dbus-transport-unix.c (unix_handle_watch): Check
+ * dbus/dbus-transport-unix.c (unix_handle_watch): Check
for hangup and error after checking read so we won't discard
pending data if both hangup and read are set.
@@ -222,9 +964,9 @@
* tools/dbus-print-message.c (print_message): Handle BOOLEAN.
* tools/dbus-send.c: Accept both --system and --session.
-
+
* tools/dbus-monitor.c: Same here.
-
+
2003-06-19 Anders Carlsson <andersca@codefactory.se>
* glib/dbus-glib.h: Fix so that dbus-glib.h can be used
@@ -268,13 +1010,13 @@
toggle as an argument, implement abstract namespace support
(_dbus_listen_unix_socket): ditto
- * configure.in: add --enable-abstract-sockets and implement
+ * configure.in: add --enable-abstract-sockets and implement
a configure check for autodetection of the right value.
2003-06-01 Havoc Pennington <hp@pobox.com>
- * tools/dbus-cleanup-sockets.c: add utility to clean up sockets
- in /tmp (though on Linux this will end up being useless,
+ * tools/dbus-cleanup-sockets.c: add utility to clean up sockets
+ in /tmp (though on Linux this will end up being useless,
when we add abstract namespace support)
* configure.in: define DBUS_SESSION_SOCKET_DIR in addition to
@@ -293,29 +1035,29 @@
* tools/dbus-send.c: Don't exit with an error code if --help was
passed. Default to using the session bus instead of the system
one.
-
- * tools/dbus-launch.c: Ditto.
+
+ * tools/dbus-launch.c: Ditto.
* tools/dbus-monitor.c: Ditto.
* tools/dbus-send.1: Update with new arguments.
-
+
* tools/dbus-launch.c: Emit code to export variables. New
arguments -s and -c to specify shell syntax, and a bit of code to
autodetect syntax. Also, allow specifying a program to run.
-
+
* tools/dbus-launch.1: Update with new arguments.
-
+
* tools/dbus-send.1: Ditto.
* tools/dbus-monitor.1: Ditto.
-
+
2003-05-17 Havoc Pennington <hp@pobox.com>
* bus/config-parser.c (merge_included): merge in policies from
child configuration file.
- * bus/policy.c (bus_policy_merge): function to merge two policies
+ * bus/policy.c (bus_policy_merge): function to merge two policies
together
2003-05-16 Havoc Pennington <hp@redhat.com>
@@ -324,12 +1066,12 @@
* tools/dbus-send.c: add --print-reply command line option
- * tools/dbus-print-message.h (print_message): new util function
+ * tools/dbus-print-message.h (print_message): new util function
shared by dbus-send and dbus-monitor
* tools/dbus-monitor.c (handler_func): exit on disconnect
- * dbus/dbus-transport-unix.c (do_reading): if the transport is
+ * dbus/dbus-transport-unix.c (do_reading): if the transport is
disconnected, don't try to use the read_watch
* dbus/dbus-watch.c (dbus_watch_get_enabled): assert watch != NULL
@@ -368,7 +1110,7 @@
check" as it broke distcheck
* bus/Makefile.am (install-data-hook): create /etc/dbus-1/system.d
-
+
2003-05-13 James Willcox <jwillcox@gnome.org>
* configure.in:
@@ -390,18 +1132,18 @@
2003-05-11 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid
+ * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid
calling _dbus_marshal_validate_arg() for every byte in a byte
array, etc.
- * dbus/dbus-message-handler.c: use atomic reference counting to
+ * dbus/dbus-message-handler.c: use atomic reference counting to
reduce number of locks slightly; the global lock in here sucks
* dbus/dbus-connection.c
(_dbus_connection_update_dispatch_status_and_unlock): variant of
update_dispatch_status that can be called with lock held; then use
in a couple places to reduce locking/unlocking
- (dbus_connection_send): hold the lock over the whole function
+ (dbus_connection_send): hold the lock over the whole function
instead of acquiring it twice.
* dbus/dbus-timeout.c (_dbus_timeout_new): handle OOM
@@ -417,7 +1159,7 @@
* dbus/dbus-list.c (_dbus_list_find_last): new function
* dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec):
- change to use a struct for the atomic type; fix docs,
+ change to use a struct for the atomic type; fix docs,
they return value before increment, not after increment.
* dbus/dbus-string.c (_dbus_string_append_4_aligned)
@@ -434,8 +1176,8 @@
* dbus/dbus-string.c (_dbus_string_move): just call
_dbus_string_move_len
- (_dbus_string_move_len): add a special case for moving
- an entire string into an empty string; we can just
+ (_dbus_string_move_len): add a special case for moving
+ an entire string into an empty string; we can just
swap the string data instead of doing any reallocs.
(_dbus_string_init_preallocated): new function
@@ -446,14 +1188,14 @@
UTF-8 validation as hot spots. 20% of lock contention eliminated
with dbus_atomic_inc/dec implementation on x86. Much remaining
contention is global mempool locks for GList and DBusList.
-
+
* dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): add
x86 implementation
* dbus/dbus-connection.c (struct DBusConnection): use
- dbus_atomic_t for the reference count
+ dbus_atomic_t for the reference count
- * dbus/dbus-message.c (struct DBusMessage): declare
+ * dbus/dbus-message.c (struct DBusMessage): declare
dbus_atomic_t values as volatile
* configure.in: code to detect ability to use atomic integer
@@ -462,22 +1204,22 @@
* dbus/dbus-internals.c (_dbus_verbose_real): call getpid every
time, tired of it being wrong in threads and forked processes
- * glib/test-profile.c: a little program to bounce messages back
+ * glib/test-profile.c: a little program to bounce messages back
and forth between threads and eat CPU
* dbus/dbus-connection.c: add debug spew macros for debugging
- thread locks; include config.h at top; fix deadlock in
+ thread locks; include config.h at top; fix deadlock in
dbus_connection_flush()
2003-05-08 Havoc Pennington <hp@pobox.com>
* dbus/dbus-spawn.c: s/_exit/exit/ because it was keeping gcov
- data from getting written, and there wasn't a good reason to
+ data from getting written, and there wasn't a good reason to
use _exit really.
* test/decode-gcov.c (mark_inside_dbus_build_tests): don't count
dbus_verbose lines in test coverage
- (main): add list of functions sorted by # of untested blocks
+ (main): add list of functions sorted by # of untested blocks
to the coverage report
* dbus/dbus-mempool.c: put some test-only code in DBUS_BUILD_TESTS
@@ -518,14 +1260,14 @@
2003-05-04 Havoc Pennington <hp@pobox.com>
- * dbus-glib-1.pc.in (Requires): fix dependencies, from
+ * dbus-glib-1.pc.in (Requires): fix dependencies, from
Anders Gustafsson
2003-05-04 Havoc Pennington <hp@pobox.com>
* tools/dbus-launch.c: implement
- * bus/main.c (main), bus/bus.c (bus_context_new):
+ * bus/main.c (main), bus/bus.c (bus_context_new):
implement --print-pid and --fork
2003-05-03 Havoc Pennington <hp@redhat.com>
@@ -542,7 +1284,7 @@
* tools/Makefile.am, tools/dbus-launch.c, tools/dbus-launch.1: add
dbus-launch utility to launch the bus from a shell script. Didn't
actually implement dbus-launch yet, it's just a placeholder still.
-
+
2003-05-03 Havoc Pennington <hp@pobox.com>
* bus/Makefile.am, bus/dbus-daemon-1.1.in: man page for the
@@ -552,7 +1294,7 @@
2003-05-03 Havoc Pennington <hp@pobox.com>
- * tools/Makefile.am, tools/dbus-send.1, tools/dbus-monitor.1:
+ * tools/Makefile.am, tools/dbus-send.1, tools/dbus-monitor.1:
add some man pages
2003-05-03 Colin Walters <walters@verbum.org>
@@ -603,7 +1345,7 @@
* dbus/dbus.h: add "you have to define DBUS_API_SUBJECT_TO_CHANGE
to use this library" to be sure people have the right
expectations.
-
+
2003-04-28 Havoc Pennington <hp@redhat.com>
* configure.in: add --enable-docs which by default is auto yes if
@@ -619,14 +1361,14 @@
* NEWS: update
* bus/system.conf.in: add <includedir>system.d</includedir>
-
+
* dbus/dbus-userdb.c (_dbus_user_database_lookup): fix bug when
username was provided but not uid
* bus/config-parser.c (struct BusConfigParser): keep track of
- whether the parser is toplevel or was included; change some
+ whether the parser is toplevel or was included; change some
of the error handling if it's included.
-
+
2003-04-27 Havoc Pennington <hp@pobox.com>
Unbreak my code...
@@ -634,7 +1376,7 @@
* dbus/dbus-transport.c (_dbus_transport_get_dispatch_status):
report correct status if we finish processing authentication
inside this function.
-
+
* bus/activation.c (try_send_activation_failure): use
bus_transaction_send_error_reply
@@ -643,7 +1385,7 @@
* bus/bus.c (bus_context_check_security_policy): implement
restriction here that inactive connections can only send the
- hello message. Also, allow bus driver to send anything to
+ hello message. Also, allow bus driver to send anything to
any recipient.
* bus/connection.c (bus_connection_complete): create the
@@ -662,7 +1404,7 @@
2003-04-25 Havoc Pennington <hp@redhat.com>
test suite is slightly hosed at the moment, will fix soon
-
+
* bus/connection.c (bus_connections_expire_incomplete): fix to
properly disable the timeout when required
(bus_connection_set_name): check whether we can remove incomplete
@@ -672,7 +1414,7 @@
probably still broken.
* bus/services.c (bus_registry_acquire_service): implement max
- number of services owned, and honor allow/deny rules on which
+ number of services owned, and honor allow/deny rules on which
services a connection can own.
* bus/connection.c (bus_connection_get_policy): report errors here
@@ -694,19 +1436,19 @@
* test/data/valid-config-files/basic.conf: add <limit> tags to
this test
-
+
* bus/config-parser.h, bus/config-parser.c, bus/bus.c: Implement
<limit> tag in configuration file.
-
+
2003-04-24 Havoc Pennington <hp@redhat.com>
* bus/dispatch.c: somehow missed some name_is
- * dbus/dbus-timeout.c (_dbus_timeout_set_enabled)
+ * dbus/dbus-timeout.c (_dbus_timeout_set_enabled)
(_dbus_timeout_set_interval): new
* bus/connection.c (bus_connections_setup_connection): record time
- when each connection is first set up, and expire them after the
+ when each connection is first set up, and expire them after the
auth timeout passes.
2003-04-24 Havoc Pennington <hp@redhat.com>
@@ -754,7 +1496,7 @@
2003-04-22 Havoc Pennington <hp@redhat.com>
* dbus/dbus-message.c, dbus/dbus-marshal.c: add 64-bit integer
- support, and do some code cleanups to share more code and
+ support, and do some code cleanups to share more code and
speed up array marshal/demarshal.
* dbus-1.0.pc.in (Cflags): put libdir include file in cflags
@@ -770,7 +1512,7 @@
to use proper type for rply field
* test/data/invalid-messages: add tests for below validation
-
+
* dbus/dbus-message.c (decode_header_data): validate field types,
and validate that named fields are valid names
(decode_name_field): consider messages in the
@@ -780,7 +1522,7 @@
2003-04-19 Havoc Pennington <hp@pobox.com>
- * bus/driver.c (bus_driver_handle_hello): check limits and
+ * bus/driver.c (bus_driver_handle_hello): check limits and
return an error if they are exceeded.
* bus/connection.c: maintain separate lists of active and inactive
@@ -799,7 +1541,7 @@
* dbus/dbus-sysdeps.c (_dbus_string_save_to_file): fix some
memleaks
- * dbus/dbus-keyring.c (add_new_key): fix a memleak, and
+ * dbus/dbus-keyring.c (add_new_key): fix a memleak, and
on realloc be sure to update the pointer in the keyring
* dbus/dbus-string.c (_dbus_string_zero): compensate for align
@@ -823,7 +1565,7 @@
server.
2003-04-18 Havoc Pennington <hp@pobox.com>
-
+
* dbus/dbus-mainloop.c (_dbus_loop_iterate): fix UMR in verbose
debug spew
@@ -835,7 +1577,7 @@
* bus/Makefile.am (TESTS_ENVIRONMENT): put DBUS_TEST_HOMEDIR in
the environment
-
+
* bus/dispatch.c (bus_dispatch_sha1_test): actually load sha1
config file so we test the right thing
@@ -878,14 +1620,14 @@
* dbus/dbus-message.h: change message serials to unsigned
* dbus/dbus-connection.c: adapt to message serials being unsigned
-
+
2003-04-15 Havoc Pennington <hp@pobox.com>
- * bus/bus.c: create and keep around a shared DBusUserDatabase
+ * bus/bus.c: create and keep around a shared DBusUserDatabase
object.
* bus/connection.c (bus_connection_get_groups): don't cache
- groups for user in the connection object, since user database
+ groups for user in the connection object, since user database
object now does that.
2003-04-16 Havoc Pennington <hp@redhat.com>
@@ -895,12 +1637,12 @@
(_dbus_message_loader_putback_message_link): put back a popped link
* dbus/dbus-connection.c
- (dbus_connection_set_max_live_messages_size): rename
+ (dbus_connection_set_max_live_messages_size): rename
max_received_size
- (dbus_connection_get_outgoing_size): get size of outgoing
+ (dbus_connection_get_outgoing_size): get size of outgoing
queue
(_dbus_connection_set_connection_counter): remove this cruft
-
+
2003-04-14 Havoc Pennington <hp@redhat.com>
* dbus/dbus-userdb.c: user database abstraction, mostly to get
@@ -912,17 +1654,17 @@
test always uses EXTERNAL when available.
* configure.in,
- test/data/valid-config-files/debug-allow-all-sha1.conf.in:
+ test/data/valid-config-files/debug-allow-all-sha1.conf.in:
add conf file that requires use of sha1 auth
2003-04-13 Havoc Pennington <hp@pobox.com>
-
+
* tools/dbus-send.c, tools/dbus-monitor.c: two utility programs
from Philip Blundell to send messages and monitor them.
-
+
2003-04-13 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-mainloop.c: fix some reentrancy issues by refcounting
+ * dbus/dbus-mainloop.c: fix some reentrancy issues by refcounting
callbacks
* test/data/valid-config-files/debug-allow-all.conf.in: allow all
@@ -930,11 +1672,11 @@
* dbus/dbus-transport.c (_dbus_transport_get_dispatch_status):
fix to only recover unused bytes if we're already authenticated
- (_dbus_transport_get_is_authenticated): fix to still mark us
+ (_dbus_transport_get_is_authenticated): fix to still mark us
authenticated if there are unused bytes.
* bus/dispatch.c: implement security policy checking
-
+
* bus/connection.c (bus_transaction_send_from_driver): new
* bus/bus.c (bus_context_check_security_policy): new
@@ -952,7 +1694,7 @@
2003-04-13 Havoc Pennington <hp@pobox.com>
* bus/config-parser.c: Load up the BusPolicy and BusPolicyRules
-
+
* dbus/dbus-sysdeps.c (_dbus_get_user_id): new function
* bus/policy.c (bus_policy_append_mandatory_rule)
@@ -967,7 +1709,7 @@
the pid/gid/uid, just for paranoia.
* test/break-loader.c (randomly_do_n_things): find a byte
- containing a type code, and randomly change it to a different
+ containing a type code, and randomly change it to a different
type code.
2003-04-12 Havoc Pennington <hp@pobox.com>
@@ -975,7 +1717,7 @@
* bus/policy.h: change BusPolicy to be the thing from the config
file, and rename old BusPolicy to BusClientPolicy
- * bus/bus.c, bus/connection.c, bus/config-parser.c: change to
+ * bus/bus.c, bus/connection.c, bus/config-parser.c: change to
match change in how policy works
* dbus/dbus-internals.h: mark assert_not_reached as
@@ -983,7 +1725,7 @@
2003-04-11 Havoc Pennington <hp@redhat.com>
- * doc/dbus-specification.sgml: fix a spot with the wrong name for
+ * doc/dbus-specification.sgml: fix a spot with the wrong name for
the broadcast service. Use boolean return for ServiceExists.
2003-04-11 Havoc Pennington <hp@redhat.com>
@@ -1058,7 +1800,7 @@
we don't successfully create the service after all. Don't remove
pending activation if the function fails.
- * dbus/dbus-list.c (_dbus_list_insert_before_link)
+ * dbus/dbus-list.c (_dbus_list_insert_before_link)
(_dbus_list_insert_after_link): new code to facilitate
services.c fixes
@@ -1067,30 +1809,30 @@
into a hash table.
* bus/connection.c (bus_transaction_add_cancel_hook): new function
- allowing us to put custom hooks in a transaction to be used for
+ allowing us to put custom hooks in a transaction to be used for
cancelling said transaction
* doc/dbus-specification.sgml: add some discussion of secondary
service owners, and disallow zero-length service names
* bus/services.c (bus_registry_acquire_service): new function,
- splits out part of bus_driver_handle_acquire_service() and fixes
- a bug where we didn't remove the service doing the acquiring
+ splits out part of bus_driver_handle_acquire_service() and fixes
+ a bug where we didn't remove the service doing the acquiring
from the secondary queue if we failed to remove the current owner
from the front of the queue.
-
+
2003-04-10 Alexander Larsson <alexl@redhat.com>
* doc/dbus-specification.sgml:
s/org.freedesktop.Broadcast/org.freedesktop.DBus.Broadcast/
-
+
2003-04-10 Alexander Larsson <alexl@redhat.com>
* bus/.cvsignore:
* glib/.cvsignore:
* test/.cvsignore:
Added files to cvsignore
-
+
* dbus/dbus-message.h:
* dbus/dbus-message.c: (dbus_message_iter_get_named):
Make get_named() take two out argument and return a boolean.
@@ -1108,38 +1850,38 @@
* dbus/dbus-marshal.[ch]:
Add array_type_pos argument to _dbus_marshal_validate_arg.
Let you pass a NULL end_pos to _dbus_marshal_validate_type.
-
+
* dbus/dbus-message.[ch]:
Multi-dimensional arrays have full type specification in the
outermost array. Iter code re-arranged to handle this.
Added some more iter tests.
-
+
* doc/dbus-specification.sgml:
Add me to authors.
Remove old FIXME.
Update new array encoding description.
Correct DBUS_SERVICE_FLAGS_REPLACE_EXISTING description.
-
+
* test/data/invalid-messages/array-with-mixed-types.message:
* test/data/valid-messages/array-of-array-of-uint32.message:
Change to the new array format.
-
+
* test/data/invalid-messages/too-short-dict.message:
Fix bug in test.
-
+
* test/data/valid-messages/recursive-types.message:
Fix up and extend test.
2003-04-10 Havoc Pennington <hp@pobox.com>
* bus/dispatch.c: lots of fixes
-
+
* dbus/dbus-mainloop.c (_dbus_loop_dispatch): export
(_dbus_loop_iterate): remove old "quit if no callbacks" code,
that was crack, broke the test service.
* dbus/dbus-transport.c (_dbus_transport_open): fix error
- handling to avoid piling up errors if we get a failure on the
+ handling to avoid piling up errors if we get a failure on the
first address.
* dbus/dbus-internals.c (_dbus_real_assert_not_reached): include
@@ -1180,7 +1922,7 @@
allowing us to fix up main loop usage
(_dbus_connection_last_unref): free all the various function
user data
- (dbus_connection_dispatch): call the DispatchStatusFunction
+ (dbus_connection_dispatch): call the DispatchStatusFunction
whenever this function returns
(dbus_connection_handle_watch): call DispatchStatusFunction
(dbus_connection_send_with_reply_and_block): call DispatchStatusFunction
@@ -1189,7 +1931,7 @@
2003-04-09 Havoc Pennington <hp@redhat.com>
- * dbus/dbus-bus.c (dbus_bus_register): fix up error handling and
+ * dbus/dbus-bus.c (dbus_bus_register): fix up error handling and
a memory leak
* bus/dispatch.c (check_service_activated): fix bug in test
@@ -1201,12 +1943,12 @@
e.g. in the activation case.
2003-04-08 Colin Walters <walters@gnu.org>
-
+
* bus/bus.c (struct BusContext) [pidfile]: New member, to store
the pid file.
(bus_context_new): Set it.
(bus_context_unref): Use it to delete the pid file.
-
+
2003-04-08 Havoc Pennington <hp@redhat.com>
* test/data/invalid-messages/array-with-mixed-types.message:
@@ -1222,7 +1964,7 @@
* test/data/valid-messages/array-of-array-of-uint32.message:
happened to write this so added it to suite
-
+
2003-04-08 Havoc Pennington <hp@redhat.com>
* bus/driver.c (bus_driver_handle_acquire_service): init
@@ -1251,7 +1993,7 @@
* glib/test-thread-server.c: (handle_test_message):
* test/test-service.c: (handle_echo):
Update to new api
-
+
* dbus/Makefile.am:
* dbus/dbus-dict.c:
* dbus/dbus-dict.h:
@@ -1260,16 +2002,16 @@
* dbus/dbus-internals.c: (_dbus_type_to_string):
Update for new types.
-
+
* dbus/dbus-marshal.[ch]:
Implement recursive types and the new marshalling format.
Remove hardcoded dict marshalling.
Marshal named types.
-
+
* dbus/dbus-message-builder.c:
Add BYTE_ARRAY.
Remove references to old types
-
+
* dbus/dbus-message.[ch]:
New non-refcounted iter API that supports recursive iters.
Use iters for appending, including support for recursive
@@ -1277,24 +2019,24 @@
Add byte and named type support.
Update everything to new marshalling formats.
Add tests for new API.
-
+
* dbus/dbus-protocol.h:
Remove old array types.
Add types: BYTE, ARRAY, DICT, NAMED
-
+
* dbus/dbus-string.c:
* dbus/dbus-sysdeps.c:
Make parse_double locale safe.
-
+
* dbus/dbus-test-main.c:
Call setlocale.
-
+
* dbus/dbus-test.c:
Kill dict test
-
+
* doc/dbus-specification.sgml:
Update spec
-
+
* test/data/incomplete-messages/missing-body.message:
* test/data/invalid-messages/bad-boolean.message:
* test/data/invalid-messages/bad-boolean-array.message:
@@ -1309,10 +2051,10 @@
* test/data/valid-messages/recursive-types.message:
Add missing NAME fields
Fix up dicts & arrays
-
+
* test/data/invalid-messages/dict-with-nil-value.message:
Removed, this is not invalid anymore.
-
+
* test/data/valid-messages/recursive-types.message:
Add new test for deeply recursive types.
@@ -1323,11 +2065,11 @@
2003-04-07 Havoc Pennington <hp@redhat.com>
- * doc/dbus-specification.sgml: require that base service names
- start with ':' and that the base service is created/deleted
+ * doc/dbus-specification.sgml: require that base service names
+ start with ':' and that the base service is created/deleted
as first and last things a connection does on the bus
- * bus/dispatch.c (check_existent_service_activation): lots more
+ * bus/dispatch.c (check_existent_service_activation): lots more
work on the activation test; it doesn't fully pass yet...
* test/test-service.c (main): fix so we don't memleak the
@@ -1336,7 +2078,7 @@
2003-04-06 Havoc Pennington <hp@pobox.com>
- * qt/Makefile.am (dbusinclude_HEADERS): install dbus-qt.h,
+ * qt/Makefile.am (dbusinclude_HEADERS): install dbus-qt.h,
from Colin Walters
* configure.in: fixes to Qt detection from Colin Walters
@@ -1345,7 +2087,7 @@
exist, from Colin Walters
* dbus/dbus-bus.c: change how we set well-known connections to
- NULL, so that it works if a single connection is stored in
+ NULL, so that it works if a single connection is stored in
two well-known array slots.
* test/Makefile.am: remove a lot of stuff that isn't immediately
@@ -1361,17 +2103,17 @@
elsewhere, and util functions that are used in tests/daemon but
don't go in the lib.
- * dbus/dbus-mainloop.h, dbus/dbus-mainloop.c: move bus/loop.[hc]
+ * dbus/dbus-mainloop.h, dbus/dbus-mainloop.c: move bus/loop.[hc]
here so it can be used in test binaries also
2003-04-06 Havoc Pennington <hp@pobox.com>
* dbus/dbus-sysdeps.c (_dbus_become_daemon): write the pidfile
here in the parent process, so we can return an error if it
- fails. Also, move some of the code into the child so the parent
+ fails. Also, move some of the code into the child so the parent
is less hosed if we fail midway through.
- * bus/bus.c (bus_context_new): move pidfile detection further up
+ * bus/bus.c (bus_context_new): move pidfile detection further up
in the function, before we start overwriting sockets and such.
* bus/messagebus.in: adjust this a bit, not sure if it will work.
@@ -1393,13 +2135,13 @@
(bus_config_parser_end_element, bus_config_parser_content): Handle it.
(bus_config_parser_unref): Free it.
(bus_config_parser_get_pidfile): New function.
-
+
* bus/config-parser.h (_dbus_write_pid_file): Prototype.
* dbus/dbus-errors.h (DBUS_ERROR_PIDFILE_EXISTS): New error.
* dbus/dbus-sysdeps.c (_dbus_write_pid_file): New function.
-
+
* dbus/dbus-sysdeps.h: Prototype it.
2003-04-06 Havoc Pennington <hp@pobox.com>
@@ -1407,7 +2149,7 @@
* bus/bus.c (bus_context_new): print the address in here, rather
than in main(), because we need to do it before forking the daemon
- * bus/dispatch.c (send_service_nonexistent_error): set the sender
+ * bus/dispatch.c (send_service_nonexistent_error): set the sender
on the service nonexistent error
* bus/driver.c (bus_driver_handle_acquire_service): set the
@@ -1418,8 +2160,8 @@
2003-04-06 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-threads.c: Redo how the fake debug mutexes are done
- so it detects deadlocks and also we actually init threads when
+ * dbus/dbus-threads.c: Redo how the fake debug mutexes are done
+ so it detects deadlocks and also we actually init threads when
debugging.
2003-04-06 Havoc Pennington <hp@pobox.com>
@@ -1437,7 +2179,7 @@
2003-04-06 Havoc Pennington <hp@pobox.com>
* bus/bus.c (bus_context_new): fix wrong handling of
- server_data_slot_unref() in the error case.
+ server_data_slot_unref() in the error case.
* dbus/dbus-internals.h (_dbus_assert): change so it passes
"(condition) != 0" to _dbus_real_assert so that
@@ -1451,10 +2193,10 @@
* dbus/dbus-transport.c (_dbus_transport_open): special error for
"tmpdir" option to unix: address on client side
- * dbus/dbus-server.c (dbus_server_listen): handle "tmpdir" option
+ * dbus/dbus-server.c (dbus_server_listen): handle "tmpdir" option
to unix: address
-
- * configure.in (TEST_SOCKET_DIR): locate a temporary directory
+
+ * configure.in (TEST_SOCKET_DIR): locate a temporary directory
we can use to create sockets in the test suite.
* bus/main.c (signal_handler): on SIGTERM, exit the daemon
@@ -1475,22 +2217,22 @@
2003-04-05 Havoc Pennington <hp@pobox.com>
- * bus/bus.c (setup_server): fix this so dbus-daemon-1 doesn't
- crash on startup. Need to get "try starting the daemon"
+ * bus/bus.c (setup_server): fix this so dbus-daemon-1 doesn't
+ crash on startup. Need to get "try starting the daemon"
in the test suite I guess. ;-)
* dbus/dbus-server.h, dbus/dbus-server.c: remove the stuff that
- tracked the number of open connections; it's better done in
+ tracked the number of open connections; it's better done in
application-specific code as you want it to span all servers etc.
2003-04-05 Havoc Pennington <hp@pobox.com>
- * bus/Makefile.am (install-data-hook): add missing DESTDIR,
+ * bus/Makefile.am (install-data-hook): add missing DESTDIR,
patch from Colin Walters
2003-04-05 Havoc Pennington <hp@pobox.com>
- * doc/config-file.txt (Elements): fix docs of <auth> to reflect
+ * doc/config-file.txt (Elements): fix docs of <auth> to reflect
reality; in fact multiple mechanisms are allowed.
* dbus/dbus-internals.c (_dbus_real_assert)
@@ -1507,21 +2249,21 @@
* NEWS: update
* configure.in: 0.7
-
+
2003-04-05 Havoc Pennington <hp@pobox.com>
* dbus/dbus-string.c: docs warning
-
+
* dbus/dbus-spawn.c: missing docs
* dbus/dbus-memory.c (struct ShutdownClosure): missing docs
2003-04-05 Havoc Pennington <hp@pobox.com>
- * bus/loop.c (bus_loop_iterate): fix the timeout code, using
+ * bus/loop.c (bus_loop_iterate): fix the timeout code, using
magic from GLib
- * dbus/dbus-spawn.c (_dbus_babysitter_unref): set sitter_pid
+ * dbus/dbus-spawn.c (_dbus_babysitter_unref): set sitter_pid
to -1 once we've reaped the babysitter
(_dbus_babysitter_handle_watch): do as much work as we can, not
just one go of it
@@ -1542,7 +2284,7 @@
* Makefile.am (coverage-report.txt): add target "coverage-report.txt"
- * test/decode-gcov.c: hack up a little program to suck data
+ * test/decode-gcov.c: hack up a little program to suck data
out of gcov files. Yes this is sort of silly.
* configure.in: define something in config.h and do an
@@ -1555,15 +2297,15 @@
the spawned process and reap it when required.
* test/test-segfault.c, test/test-exit.c,
- test/test-sleep-forever.c: binaries that do various lame things,
+ test/test-sleep-forever.c: binaries that do various lame things,
used in the test suite.
* dbus/dbus-sysdeps.c: kill _dbus_errno_to_string()
-
+
2003-04-03 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-spawn.c: Move dbus-spawn into a separate file
- in preparation for modifying it, dbus-sysdeps is getting
+ * dbus/dbus-spawn.c: Move dbus-spawn into a separate file
+ in preparation for modifying it, dbus-sysdeps is getting
a bit unmanageable.
2003-04-03 Havoc Pennington <hp@redhat.com>
@@ -1585,41 +2327,41 @@
2003-04-03 Havoc Pennington <hp@pobox.com>
- * bus/config-parser.c (bus_config_parser_unref): free
+ * bus/config-parser.c (bus_config_parser_unref): free
list of mechanisms, bug discovered by test suite enhancements
(putting system.conf and session.conf into suite)
* test/Makefile.am, test/test-service.c: add placeholder for a
- test service that we'll activate as part of test suite. Doesn't
+ test service that we'll activate as part of test suite. Doesn't
do anything yet.
- * dbus/dbus-sysdeps.c (_dbus_setenv): support unsetenv by
- setting NULL value, and use system malloc not dbus_malloc()
+ * dbus/dbus-sysdeps.c (_dbus_setenv): support unsetenv by
+ setting NULL value, and use system malloc not dbus_malloc()
when we have unavoidable memleakage.
* dbus/dbus-bus.c (dbus_bus_get): fix bug where bus type of 0
didn't work, and support DBUS_BUS_ACTIVATION.
-
+
* bus/activation.c (child_setup): pass our well-known bus type to
the child
* bus/config-parser.c: support <type> to specify well-known type
- * doc/dbus-specification.sgml: document the env variables to
+ * doc/dbus-specification.sgml: document the env variables to
locate well-known buses and find service activator
2003-04-02 Havoc Pennington <hp@redhat.com>
* test/Makefile.am (all-local): add a rule to copy tests to
builddir, so we can have generated tests. Use this to remove the
- silly hack for testing system.conf and session.conf. Will use this
+ silly hack for testing system.conf and session.conf. Will use this
shortly to generate .service files pointing to test binaries.
2003-04-02 Havoc Pennington <hp@redhat.com>
* dbus/dbus-string.c (set_length): fix a bug - we allocated max of
current alloc and needed new length, not max of the doubled
- allocation and needed new length. Also, when building tests,
+ allocation and needed new length. Also, when building tests,
don't do the double-allocation stuff, just realloc every time.
2003-04-02 Havoc Pennington <hp@redhat.com>
@@ -1666,13 +2408,13 @@
socket 0777, and unlink any existing socket.
* bus/bus.c (bus_context_new): change our UID/GID and fork if
- the configuration file so specifies; set up auth mechanism
+ the configuration file so specifies; set up auth mechanism
restrictions
* bus/config-parser.c (bus_config_parser_content): add support
- for <fork> option and fill in code for <auth>
+ for <fork> option and fill in code for <auth>
- * bus/system.conf.in: add <fork/> to default configuration,
+ * bus/system.conf.in: add <fork/> to default configuration,
and limit auth mechanisms to EXTERNAL
* doc/config-file.txt (Elements): add <fork>
@@ -1682,7 +2424,7 @@
2003-03-31 Havoc Pennington <hp@redhat.com>
- * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket)
+ * dbus/dbus-sysdeps.c (_dbus_connect_unix_socket)
(_dbus_listen_unix_socket): fix off-by-one error in null
termination spotted by Nalin
@@ -1704,10 +2446,10 @@
2003-03-31 Havoc Pennington <hp@redhat.com>
Fix some annoying DBusString API and fix all affected code.
-
+
* dbus/dbus-string.c (_dbus_string_init): get rid of annoying
max_length argument
- (_dbus_string_get_data): change to return string instead of using
+ (_dbus_string_get_data): change to return string instead of using
an out param
(_dbus_string_get_const_data): ditto
(_dbus_string_get_data_len): ditto
@@ -1720,7 +2462,7 @@
2003-03-31 Havoc Pennington <hp@redhat.com>
* dbus/Makefile.am (INCLUDES): use EXPANDED_LOCALSTATEDIR to
- define DBUS_SYSTEM_BUS_PATH as we want to compile in the same
+ define DBUS_SYSTEM_BUS_PATH as we want to compile in the same
final location that lands in the config file
* bus/config-loader-expat.c (bus_config_load): fix type of
@@ -1740,7 +2482,7 @@
* bus/main.c (main): take the configuration file as an argument.
- * test/data/valid-config-files/debug-allow-all.conf: new file to
+ * test/data/valid-config-files/debug-allow-all.conf: new file to
use with dispatch.c tests for example
* bus/test-main.c (main): require test data dir
@@ -1751,7 +2493,7 @@
* doc/config-file.txt (Elements): add <servicedir>
* bus/system.conf, bus/session.conf: new files
-
+
* dbus/dbus-bus.c (dbus_bus_get): look for system bus on
well-known socket if none set
@@ -1760,8 +2502,8 @@
2003-03-30 Havoc Pennington <hp@pobox.com>
* bus/config-parser.c: hacking
-
- * dbus/dbus-memory.c: don't use DBusList for the list of stuff
+
+ * dbus/dbus-memory.c: don't use DBusList for the list of stuff
to shut down, since it could cause weirdness with the DBusList
lock
@@ -1787,13 +2529,13 @@
* dbus/dbus-bus.c: (bus_data_free), (dbus_bus_get):
* dbus/dbus-bus.h:
Add dbus_bus_get.
-
+
* dbus/dbus-memory.c:
Fix a doc comment.
-
+
2003-03-28 Havoc Pennington <hp@pobox.com>
- * bus/test.c (bus_test_flush_bus): remove the sleep from here,
+ * bus/test.c (bus_test_flush_bus): remove the sleep from here,
I think it may have just been superstition. Not sure.
* dbus/dbus-string.c (_dbus_string_base64_decode): catch some OOM
@@ -1819,10 +2561,10 @@
* doc/TODO:
Add note about automatic service activation.
-
+
* doc/dbus-specification.sgml:
Rename the specification and clarify a few things.
-
+
2003-03-26 Anders Carlsson <andersca@codefactory.se>
* Doxyfile.in:
@@ -1832,7 +2574,7 @@
* dbus/dbus-server-debug-pipe.c:
* dbus/dbus-transport-unix.c:
Fix documentation warnings.
-
+
2003-03-26 Havoc Pennington <hp@pobox.com>
* bus/test-main.c, dbus/dbus-test.c (main): check memleaks
@@ -1851,11 +2593,11 @@
2003-03-25 Havoc Pennington <hp@redhat.com>
* throughout - add more _DBUS_ASSERT_ERROR_IS_CLEAR
-
+
* configure.in: add --with-xml option to specify XML library,
right now only libxml is supported.
- * bus/config-loader-libxml.c, config-parser.c: sync some minor
+ * bus/config-loader-libxml.c, config-parser.c: sync some minor
nonworking code between home and work, still just stubs
2003-03-24 Havoc Pennington <hp@redhat.com>
@@ -1863,8 +2605,8 @@
* dbus/dbus-sysdeps.c (_dbus_set_fd_nonblocking): move to this
file
- * dbus/dbus-errors.c (dbus_set_error, dbus_set_error_const): allow
- NULL argument for "message" if the error is a well-known one,
+ * dbus/dbus-errors.c (dbus_set_error, dbus_set_error_const): allow
+ NULL argument for "message" if the error is a well-known one,
fill in a generic message in this case.
* dbus/dbus-errors.h (DBusResultCode): Kill DBusResultCode in
@@ -1876,20 +2618,20 @@
2003-03-24 Havoc Pennington <hp@pobox.com>
- * bus/connection.c (bus_connections_setup_connection): set up
- the "can this user connect" function, but it always returns
+ * bus/connection.c (bus_connections_setup_connection): set up
+ the "can this user connect" function, but it always returns
TRUE until we have a config file parser so we can have a config
file that allows connections.
2003-03-23 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-threads.c (dbus_mutex_new, dbus_condvar_new): with
- DBUS_BUILD_TESTS, actually alloc/free a block of memory for
- the mutex, so we can check for proper memory management
+ * dbus/dbus-threads.c (dbus_mutex_new, dbus_condvar_new): with
+ DBUS_BUILD_TESTS, actually alloc/free a block of memory for
+ the mutex, so we can check for proper memory management
and OOM handling.
* dbus/dbus-dataslot.c: remove the mutex from
- DBusDataSlotAllocator and lock it manually when using it,
+ DBusDataSlotAllocator and lock it manually when using it,
to simplify fitting it into the global slots framework.
* dbus/dbus-threads.c (init_static_locks): rework how we're
@@ -1899,17 +2641,17 @@
* bus/test-main.c (main): check for memleaks
- * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): make
+ * dbus/dbus-test.c (dbus_internal_do_not_use_run_tests): make
test suite check for memleaks
- * dbus/dbus-memory.c: add support in test mode for tracking
+ * dbus/dbus-memory.c: add support in test mode for tracking
number of outstanding blocks
2003-03-23 Havoc Pennington <hp@pobox.com>
* bus/policy.c, bus/bus.c, bus/connection.c: implement allow/deny
policies code
-
+
* dbus/dbus-hash.h: add ULONG hash keys
* dbus/dbus-sysdeps.c (_dbus_get_groups): new
@@ -1936,7 +2678,7 @@
2003-03-19 Havoc Pennington <hp@redhat.com>
- * bus/policy.c: start sketching code for policy restrictions on
+ * bus/policy.c: start sketching code for policy restrictions on
what connections can do.
2003-03-18 Havoc Pennington <hp@redhat.com>
@@ -1951,14 +2693,14 @@
* configure.in: 0.6
* NEWS: Update.
-
+
2003-03-17 Havoc Pennington <hp@redhat.com>
- * dbus/dbus-internals.h: add gcc attributes so that
- our printf-style functions warn on bad arguments to
+ * dbus/dbus-internals.h: add gcc attributes so that
+ our printf-style functions warn on bad arguments to
format
-
- * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): fix printf
+
+ * dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): fix printf
format bug
* dbus/dbus-message.c (_dbus_message_loader_queue_messages): fix
@@ -1966,10 +2708,10 @@
2003-03-17 Havoc Pennington <hp@redhat.com>
- * bus/test-main.c (main): make it print something as it runs
+ * bus/test-main.c (main): make it print something as it runs
so make check doesn't look stuck
- * doc/negotiation.txt, doc/dbus-sasl-profile.txt: remove
+ * doc/negotiation.txt, doc/dbus-sasl-profile.txt: remove
from CVS, now obsolete
2003-03-17 Anders Carlsson <andersca@codefactory.se>
@@ -1977,15 +2719,15 @@
* bus/dispatch.c: (bus_dispatch):
Refetch the service name since it may have been reallocated
when dbus_message_set_sender was called.
-
+
* dbus/dbus-sysdeps.c: (_dbus_accept):
Add address and address length variables and use them to stop
valgrind from complaining.
-
+
2003-03-17 Havoc Pennington <hp@pobox.com>
All tests pass, no memleaks, no valgrind complaints.
-
+
* bus/test.c: refcount handler_slot
* bus/connection.c (bus_connections_new): refcount
@@ -2032,22 +2774,22 @@
* dbus/dbus-server-debug-pipe.c (_dbus_transport_debug_pipe_new):
add some missing dbus_set_result
- * bus/dispatch.c (bus_dispatch_add_connection): handle failure to
+ * bus/dispatch.c (bus_dispatch_add_connection): handle failure to
alloc the DBusMessageHandler
* dbus/dbus-transport.c (_dbus_transport_disconnect): don't ref
- the transport here, since we call this from the finalizer; it
+ the transport here, since we call this from the finalizer; it
resulted in a double-finalize.
- * dbus/dbus-transport.c (_dbus_transport_disconnect): fix a bug
- where we tried to use transport->connection that was NULL,
+ * dbus/dbus-transport.c (_dbus_transport_disconnect): fix a bug
+ where we tried to use transport->connection that was NULL,
happened when transport was disconnected early on due to OOM
* bus/*.c: adapt to handle OOM for watches/timeouts
- * dbus/dbus-transport-unix.c: port to handle OOM during
+ * dbus/dbus-transport-unix.c: port to handle OOM during
watch handling
-
+
* dbus/dbus-auth.c (_dbus_auth_get_unused_bytes): return a
reference to unused bytes instead of a copy
@@ -2064,7 +2806,7 @@
* doc/dbus-specification.sgml:
Document reply message for ActivateService.
-
+
2003-03-16 Anders Carlsson <andersca@codefactory.se>
* bus/activation.c: (bus_pending_activation_entry_free),
@@ -2084,7 +2826,7 @@
* dbus/dbus-protocol.h:
Make activation work better. Now pending activations will be queued
and the daemon won't try to activate services that are already registered.
-
+
2003-03-16 Havoc Pennington <hp@pobox.com>
* dbus/dbus-bus.c (ensure_bus_data): handle failure to set
@@ -2100,8 +2842,8 @@
* bus/*: adapt to DBusConnection API changes
- * glib/dbus-gmain.c: adapt to DBusConnection API changes,
- requires renaming stuff to avoid dbus_connection_dispatch name
+ * glib/dbus-gmain.c: adapt to DBusConnection API changes,
+ requires renaming stuff to avoid dbus_connection_dispatch name
conflict.
* dbus/dbus-transport.c (_dbus_transport_queue_messages): new
@@ -2127,7 +2869,7 @@
* dbus/dbus-connection.c:
(dbus_connection_send_with_reply_and_block):
- Decrease connection->n_incoming when removing an entry
+ Decrease connection->n_incoming when removing an entry
from the list.
* dbus/dbus-dict.c: (dbus_dict_entry_free),
(dbus_dict_set_boolean_array), (dbus_dict_set_int32_array),
@@ -2136,7 +2878,7 @@
(dbus_dict_get_boolean_array), (dbus_dict_get_double_array),
(dbus_dict_get_byte_array):
Handle NULL arrays and strings. Also add support for byte arrays.
-
+
* dbus/dbus-marshal.c: (_dbus_marshal_byte_array),
(_dbus_marshal_dict), (_dbus_demarshal_byte_array),
(_dbus_demarshal_int32_array), (_dbus_demarshal_uint32_array),
@@ -2145,7 +2887,7 @@
(_dbus_marshal_validate_arg), (_dbus_marshal_test):
* dbus/dbus-marshal.h:
Add support for marshalling and demarshalling empty arrays and strings.
-
+
* dbus/dbus-message.c: (dbus_message_append_args_valist),
(dbus_message_append_string_array),
(dbus_message_iter_get_boolean),
@@ -2157,14 +2899,14 @@
(dbus_message_iter_get_string_array), (dbus_message_iter_get_dict),
(check_message_handling):
Add support for getting empty arrays and dicts.
-
+
* dbus/dbus-string.c: (_dbus_string_validate_utf8):
Don't do any validation at all for now, that's better than just checking
for ASCII.
-
+
* test/data/valid-messages/emptiness.message:
New test message with lots of empty arrays.
-
+
2003-03-16 Havoc Pennington <hp@pobox.com>
* dbus/dbus-connection.c
@@ -2172,7 +2914,7 @@
can't fail due to OOM
* dbus/dbus-message.c (_dbus_message_loader_pop_message_link):
- new function pops a message together with a list link
+ new function pops a message together with a list link
containing it.
* dbus/dbus-transport-unix.c (queue_messages): use new link-based
@@ -2187,20 +2929,20 @@
in the shared lib, and only daemon mallocs were tested. In any
case, the test case now tests all 500+ mallocs, and doesn't pass
yet, though there are lots of fixes in this patch.
-
+
* dbus/dbus-connection.c (dbus_connection_dispatch_message): fix
- this so that it doesn't need to allocate memory, since it
- has no way of indicating failure due to OOM (and would be
+ this so that it doesn't need to allocate memory, since it
+ has no way of indicating failure due to OOM (and would be
annoying if it did).
* dbus/dbus-list.c (_dbus_list_pop_first_link): new function
* bus/Makefile.am: rearrange to create two self-contained
- libraries, to avoid having libraries with overlapping symbols.
- that was resulting in weirdness, e.g. I'm pretty sure there
+ libraries, to avoid having libraries with overlapping symbols.
+ that was resulting in weirdness, e.g. I'm pretty sure there
were two copies of global static variables.
- * dbus/dbus-internals.c: move the malloc debug stuff to
+ * dbus/dbus-internals.c: move the malloc debug stuff to
dbus-memory.c
* dbus/dbus-list.c (free_link): free list mempool if it becomes
@@ -2212,15 +2954,15 @@
on failure.
* bus/dispatch.c (bus_dispatch_add_connection): free
- message_handler_slot when no longer using it, so
+ message_handler_slot when no longer using it, so
memory leak checkers are happy for the test suite.
* dbus/dbus-server-debug-pipe.c (debug_finalize): free server name
- * bus/bus.c (new_connection_callback): disconnect in here if
+ * bus/bus.c (new_connection_callback): disconnect in here if
bus_connections_setup_connection fails.
- * bus/connection.c (bus_connections_unref): fix to free the
+ * bus/connection.c (bus_connections_unref): fix to free the
connections
(bus_connections_setup_connection): if this fails, don't
disconnect the connection, just be sure there are no side
@@ -2230,11 +2972,11 @@
* dbus/dbus-auth.c (_dbus_auth_unref): free some stuff we were
leaking
- (_dbus_auth_new): fix the order in which we free strings
+ (_dbus_auth_new): fix the order in which we free strings
on OOM failure
- * bus/connection.c (bus_connection_disconnected): fix to
- not send ServiceDeleted multiple times in case of memory
+ * bus/connection.c (bus_connection_disconnected): fix to
+ not send ServiceDeleted multiple times in case of memory
allocation failure
* dbus/dbus-bus.c (dbus_bus_get_base_service): new function to
@@ -2244,18 +2986,18 @@
function for it.
(dbus_bus_register_client): rename dbus_bus_register()
- * bus/dispatch.c (check_hello_message): verify that other
- connections on the bus also got the correct results, not
+ * bus/dispatch.c (check_hello_message): verify that other
+ connections on the bus also got the correct results, not
just the one sending hello
2003-03-15 Havoc Pennington <hp@pobox.com>
Make it pass the Hello handling test including all OOM codepaths.
Now to do other messages...
-
+
* bus/services.c (bus_service_remove_owner): fix crash when
removing owner from an empty list of owners
- (bus_registry_ensure): don't leave service in the list of
+ (bus_registry_ensure): don't leave service in the list of
a connection's owned services if we fail to put the service
in the hash table.
@@ -2270,7 +3012,7 @@
needed.
(unix_connection_set): this can now fail on OOM
- * dbus/dbus-timeout.c, dbus/dbus-watch.c: add concept
+ * dbus/dbus-timeout.c, dbus/dbus-watch.c: add concept
of enabling/disabling a watch or timeout.
* bus/loop.c (bus_loop_iterate): don't touch disabled
@@ -2289,69 +3031,69 @@
watch). To fix this, I think we need to add new stuff to
set_watch_functions, namely a SetEnabled function so we can alloc
the watch earlier, then enable it later.
-
+
* dbus/Makefile.am (libdbus_convenience_la_SOURCES): move
dbus-memory.c to the convenience lib
- * bus/test.c: rename some static functions to keep them clearly
+ * bus/test.c: rename some static functions to keep them clearly
distinct from stuff in connection.c. Handle client disconnection.
2003-03-14 Havoc Pennington <hp@pobox.com>
- * bus/dispatch.c (bus_dispatch_test): do test using debug-pipe
- transport, tests more of the real codepath. Set up clients
+ * bus/dispatch.c (bus_dispatch_test): do test using debug-pipe
+ transport, tests more of the real codepath. Set up clients
with bus_setup_debug_client.
- * bus/test.c (bus_setup_debug_client): function to set up debug
+ * bus/test.c (bus_setup_debug_client): function to set up debug
"clients" on the main loop
- * dbus/dbus-transport.c (_dbus_transport_open): add debug-pipe
+ * dbus/dbus-transport.c (_dbus_transport_open): add debug-pipe
support
- * dbus/dbus-server.c (dbus_server_listen): add debug-pipe
+ * dbus/dbus-server.c (dbus_server_listen): add debug-pipe
server type
* dbus/dbus-server-debug.c: support a debug server based on pipes
* dbus/dbus-sysdeps.c (_dbus_full_duplex_pipe): new function
(_dbus_close): new function
-
+
* configure.in: check for socketpair
2003-03-14 Havoc Pennington <hp@redhat.com>
- * dbus/dbus-memory.c: add a "detect buffer overwrites on free"
+ * dbus/dbus-memory.c: add a "detect buffer overwrites on free"
cheesy hack
- * dbus/dbus-transport-debug.c: rework this a good bit to be
+ * dbus/dbus-transport-debug.c: rework this a good bit to be
less complicated. hopefully still works.
* dbus/dbus-server-debug.c (handle_new_client): remove timeout
manually
- * glib/dbus-gmain.c (timeout_handler): don't remove timeout
+ * glib/dbus-gmain.c (timeout_handler): don't remove timeout
after running it
- * dbus/dbus-message.c (dbus_message_copy): rename from
- dbus_message_new_from_message, fix it up to copy
+ * dbus/dbus-message.c (dbus_message_copy): rename from
+ dbus_message_new_from_message, fix it up to copy
all the message fields, add test case
- * bus/dispatch.c (bus_dispatch_test): add some more test code,
+ * bus/dispatch.c (bus_dispatch_test): add some more test code,
not quite passing yet
2003-03-14 Havoc Pennington <hp@pobox.com>
* bus/loop.c (bus_loop_iterate): add this so we can "run loop
- until no work remains" in test code. (the large diff here
+ until no work remains" in test code. (the large diff here
is just code movement, no actual changes)
* dbus/dbus-server-debug.c (DEFAULT_INTERVAL): change interval to
1, no point waiting around for test code.
- (_dbus_server_debug_accept_transport): unref the timeout
+ (_dbus_server_debug_accept_transport): unref the timeout
after adding it (right?)
* dbus/dbus-transport-debug.c (DEFAULT_INTERVAL): ditto
-
+
2003-03-13 Havoc Pennington <hp@redhat.com>
* dbus/dbus-timeout.c (_dbus_timeout_list_set_functions): handle
@@ -2379,33 +3121,33 @@
* bus/dispatch.c (bus_dispatch_test): started adding this but
didn't finish
-
+
2003-03-14 Anders Carlsson <andersca@codefactory.se>
* bus/dispatch.c (send_service_nonexistent_error): Fix typo.
2003-03-13 Havoc Pennington <hp@pobox.com>
- * bus/test.c, bus/test.h, bus/Makefile.am, bus/test-main.c:
+ * bus/test.c, bus/test.h, bus/Makefile.am, bus/test-main.c:
set up a test framework as for the library
2003-03-12 Havoc Pennington <hp@pobox.com>
- Throughout: purge global variables, introduce BusActivation,
+ Throughout: purge global variables, introduce BusActivation,
BusConnections, BusRegistry, etc. objects instead.
-
- * bus/bus.h, bus/bus.c: introduce BusContext as a global
+
+ * bus/bus.h, bus/bus.c: introduce BusContext as a global
message bus object
- * test/Makefile.am (TEST_BINARIES): disable bus-test for now,
+ * test/Makefile.am (TEST_BINARIES): disable bus-test for now,
going to redo this a bit differently I think
-
+
2003-03-12 Havoc Pennington <hp@redhat.com>
- Mega-patch that gets the message bus daemon initially handling
- out-of-memory. Work still needed. Also lots of random
+ Mega-patch that gets the message bus daemon initially handling
+ out-of-memory. Work still needed. Also lots of random
moving stuff to DBusError instead of ResultCode.
-
+
* dbus/dbus-list.c (_dbus_list_length_is_one): new function
* dbus/dbus-connection.c
@@ -2421,7 +3163,7 @@
rename bus_connection_disconnected as it's a notification only
* bus/driver.c (bus_driver_handle_acquire_service): don't free
- "name" on get_args failure, should be done by get_args;
+ "name" on get_args failure, should be done by get_args;
don't disconnect client for bad args, just return an error.
(bus_driver_handle_service_exists): ditto
@@ -2443,8 +3185,8 @@
* bus/connection.c (bus_connection_foreach): allow stopping
iteration by returning FALSE from foreach function.
- * dbus/dbus-connection.c (dbus_connection_send_preallocated)
- (dbus_connection_free_preallocated_send)
+ * dbus/dbus-connection.c (dbus_connection_send_preallocated)
+ (dbus_connection_free_preallocated_send)
(dbus_connection_preallocate_send): new API for sending a message
without possibility of malloc failure.
(dbus_connection_send_message): rename to just
@@ -2464,23 +3206,23 @@
2003-03-10 Anders Carlsson <andersca@codefactory.se>
- * dbus/dbus-marshal.c:
+ * dbus/dbus-marshal.c:
(_dbus_marshal_set_string):
Take a length argument so we can marshal the correct string
length.
-
+
(_dbus_marshal_dict), (_dbus_demarshal_dict),
(_dbus_marshal_get_arg_end_pos), (_dbus_marshal_validate_arg),
(_dbus_marshal_test):
- * dbus/dbus-marshal.h:
+ * dbus/dbus-marshal.h:
Add support for marshalling and demarshalling dicts.
-
+
* dbus/dbus-message-builder.c: (_dbus_message_data_load):
Add support for TYPE DICT.
-
+
* dbus/dbus-message.c: (set_string_field):
Adjust header padding.
-
+
(dbus_message_append_args_valist), (dbus_message_append_dict),
(dbus_message_get_args_valist), (dbus_message_iter_get_arg_type),
(dbus_message_iter_get_dict), (_dbus_message_loader_return_buffer),
@@ -2490,13 +3232,13 @@
* dbus/dbus-protocol.h:
Add DBUS_TYPE_DICT.
-
+
* dbus/dbus.h:
Add dbus-dict.h
-
+
* doc/dbus-specification.sgml:
Add information about how dicts are marshalled.
-
+
* test/data/invalid-messages/dict-with-nil-value.message:
* test/data/invalid-messages/too-short-dict.message:
* test/data/valid-messages/dict-simple.message:
@@ -2519,7 +3261,7 @@
(dbus_dict_set_string_array), (_dbus_dict_test):
* dbus/dbus-dict.h:
Fix according to comments from Havoc.
-
+
2003-03-06 Michael Meeks <michael@server.home>
* configure.in: if we don't have kde-config, disable have_qt.
@@ -2528,7 +3270,7 @@
* dbus/Makefile.am:
Add dbus-dict.[ch]
-
+
* dbus/dbus-dict.c: (dbus_dict_entry_free), (dbus_dict_new),
(dbus_dict_ref), (dbus_dict_unref), (dbus_dict_contains),
(dbus_dict_remove), (dbus_dict_get_value_type),
@@ -2545,11 +3287,11 @@
(dbus_dict_get_string_array), (_dbus_dict_test):
* dbus/dbus-dict.h:
Add DBusDict implementation
-
+
* dbus/dbus-test.c: (dbus_internal_do_not_use_run_tests):
* dbus/dbus-test.h:
Add _dbus_dict_test
-
+
2003-03-04 Havoc Pennington <hp@pobox.com>
* test/data/auth/*: adapt to changes
@@ -2559,15 +3301,15 @@
userid
* dbus/dbus-keyring.c (_dbus_keyring_validate_context): prevent
- more stuff from being in a context name, to make the protocol
+ more stuff from being in a context name, to make the protocol
simpler to deal with
* dbus/dbus-errors.c (dbus_error_has_name): new function
(dbus_error_is_set): new function
- * dbus/dbus-auth.c: replace DBUS_STUPID_TEST_MECH auth
+ * dbus/dbus-auth.c: replace DBUS_STUPID_TEST_MECH auth
with DBUS_COOKIE_SHA1, implement DBUS_COOKIE_SHA1
-
+
* dbus/dbus-connection.c (dbus_connection_flush): also read
messages during a flush operation
@@ -2579,10 +3321,10 @@
* dbus/dbus-transport.c: (_dbus_transport_open):
Remove duplicate "tcp" entry.
-
+
* doc/dbus-specification.sgml:
Clarify some things.
-
+
2003-03-05 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-auth.c: (send_rejected), (process_test_subdir):
@@ -2607,7 +3349,7 @@
sets really huge and small integers
* dbus/dbus-marshal.c (_dbus_marshal_validate_arg): add check
- that length of boolean array fits in the string, and that
+ that length of boolean array fits in the string, and that
string has room for boolean value in single-bool case.
* dbus/dbus-message-builder.c (_dbus_message_data_load): add
@@ -2641,7 +3383,7 @@
2003-02-27 Alexander Larsson <alexl@redhat.com>
- * glib/Makefile.am:
+ * glib/Makefile.am:
* configure.in:
Make gthreads-2.0 dependency optional. Don't build thread test if
its not found.
@@ -2652,14 +3394,14 @@
(dbus_connection_send_message_with_reply_and_block): fix doh!
doh! doh! bug that resulted in never removing a reply from the
queue, no wonder we called get_reply_serial so much ;-)
-
+
* dbus/dbus-message.c (struct DBusMessage): cache reply serial
and client serial instead of demarshaling them every time
2003-02-27 Havoc Pennington <hp@pobox.com>
* dbus/dbus-marshal.c (_dbus_demarshal_int32): rewrite to be much
- more inlined, using dbus-string-private.h, speeds things up
+ more inlined, using dbus-string-private.h, speeds things up
substantially
* dbus/dbus-string.c (_dbus_string_free): apply align offset
@@ -2669,17 +3411,17 @@
2003-02-26 Havoc Pennington <hp@redhat.com>
- All kinds of audit fixes from Owen, plus initial attempt to
+ All kinds of audit fixes from Owen, plus initial attempt to
handle unaligned memory returned from malloc.
-
- * dbus/dbus-string.c (_dbus_string_init): clamp max length to
+
+ * dbus/dbus-string.c (_dbus_string_init): clamp max length to
leave room for align_offset and nul byte
- (fixup_alignment): function to track an align_offset and
+ (fixup_alignment): function to track an align_offset and
ensure real->str is aligned
- (DBUS_GENERIC_STRING_PREAMBLE): len must be less than allocated,
+ (DBUS_GENERIC_STRING_PREAMBLE): len must be less than allocated,
to allow a nul byte plus align offset
(_dbus_string_lock): fix overflow issue
- (_dbus_string_init_const_len): add assertions on sanity of len,
+ (_dbus_string_init_const_len): add assertions on sanity of len,
assign allocated to be ALLOCATION_PADDING larger than len
(set_length): fixup the overflow handling
(_dbus_string_get_data_len): fix overflow in assertion
@@ -2691,16 +3433,16 @@
(_dbus_string_delete): fix overflow in assertion
(_dbus_string_copy_len): overflow in assertion
(_dbus_string_replace_len): overflows in assertions
- (_dbus_string_find): change to implement in terms of
+ (_dbus_string_find): change to implement in terms of
_dbus_string_find_to
(_dbus_string_find_to): assorted fixage
- (_dbus_string_equal_c_str): assert c_str != NULL,
+ (_dbus_string_equal_c_str): assert c_str != NULL,
fix logic so the function works
(_dbus_string_ends_with_c_str): fix overflow thingy
(_dbus_string_base64_encode): overflow fix
(_dbus_string_validate_ascii): overflow
(_dbus_string_validate_nul): overflow
-
+
2003-02-26 Havoc Pennington <hp@redhat.com>
* dbus/dbus-marshal.c (_dbus_marshal_test): fix to work with DISABLE_ASSERTS
@@ -2709,29 +3451,29 @@
* configure.in:
Set DBUS_GLIB_THREADS_LIBS for apps using gthread-2.0
-
+
* dbus/dbus-connection.c:
* dbus/dbus-connection.h:
Fix _dbus_connection_acquire_io_path and _dbus_connection_acquire_dispatch.
Add dbus_connection_set_wakeup_main_function and use it when queueing
incoming and outgoing messages.
-
-
+
+
* dbus/dbus-dataslot.c:
Threadsafe usage of DBusDataSlotAllocator
-
+
* dbus/dbus-message.c: (dbus_message_get_args_iter):
dbus_new can fail.
-
+
* dbus/dbus-server-unix.c:
Add todo comment
-
+
* glib/dbus-gmain.c:
Implement the new wakeup functions for glib.
-
+
* glib/Makefile.am:
- * glib/test-thread-client.c:
- * glib/test-thread-server.c:
+ * glib/test-thread-client.c:
+ * glib/test-thread-server.c:
* glib/test-thread.h:
Initial cut at some thread test code. Not really done yet.
@@ -2745,7 +3487,7 @@
at the end of this function, so if we didn't need to read for
authentication, we reinstall it for receiving messages
- * dbus/dbus-message.c (dbus_message_new_reply): allow replies to
+ * dbus/dbus-message.c (dbus_message_new_reply): allow replies to
a NULL sender for peer-to-peer case
* dbus/dbus-transport-unix.c (check_read_watch): handle
@@ -2763,9 +3505,9 @@
* Doxyfile.in (INPUT): add glib subdir
- * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): rename
+ * glib/dbus-gmain.c (dbus_connection_setup_with_g_main): rename
setup_with_g_main instead of hookup_with_g_main; write docs
-
+
2003-02-24 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-marshal.c: (_dbus_marshal_validate_arg):
@@ -2776,11 +3518,11 @@
* dbus/dbus-message.h:
* doc/dbus-specification.sgml:
Various fixes as pointed out by Havoc.
-
+
* test/data/invalid-messages/bad-boolean-array.message:
* test/data/invalid-messages/bad-boolean.message:
Add invalid boolean value test cases.
-
+
2003-02-24 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-internals.c: (_dbus_type_to_string):
@@ -2798,10 +3540,10 @@
* doc/dbus-specification.sgml:
* test/data/valid-messages/lots-of-arguments.message:
Add support for boolean and boolean array types.
-
+
2003-02-23 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-keyring.c: finish most of this implementation and
+ * dbus/dbus-keyring.c: finish most of this implementation and
simple unit test
* dbus/dbus-errors.c (dbus_set_error_const, dbus_set_error): make
@@ -2820,7 +3562,7 @@
* dbus/dbus-md5.c (_dbus_md5_compute): use dbus_string_hex_encode
- * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): make this use
+ * dbus/dbus-sysdeps.c (_dbus_string_save_to_file): make this use
the save-to-temp/rename trick to atomically write the new file
(_dbus_string_parse_uint): new function
@@ -2841,25 +3583,25 @@
* dbus/dbus-marshal.c: (_dbus_demarshal_string_array):
Make string arrays NULL-terminated.
-
+
* dbus/dbus-memory.c: (dbus_free_string_array):
* dbus/dbus-memory.h:
New function for freeing NULL-terminated string arrays.
-
+
* dbus/dbus-message-builder.c: (append_quoted_string),
(_dbus_message_data_load):
Add support for array types.
-
+
* dbus/dbus-message.c: (check_message_handling):
Add more types as test cases.
-
+
* dbus/dbus-sysdeps.c: (_dbus_string_parse_int),
(_dbus_string_parse_double):
Add the start offset to the end offset.
-
+
* test/data/valid-messages/lots-of-arguments.message:
New test message with lots of arguments.
-
+
2003-02-21 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-message.c: (dbus_message_append_nil),
@@ -2876,7 +3618,7 @@
* dbus/dbus-message.c: (dbus_message_append_nil):
Fix a silly.
-
+
2003-02-21 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-message.c: (dbus_message_append_args_valist),
@@ -2893,7 +3635,7 @@
* dbus/dbus-message.h:
Add functions for appending and getting arrays.
-
+
2003-02-21 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-mempool.c (_dbus_mem_pool_new): Make the
@@ -2906,7 +3648,7 @@
Unlock the connection mutex during a blocking select call.
Add todo about how we need a way to wake up the select.
- * dbus/dbus-connection-internal.h:
+ * dbus/dbus-connection-internal.h:
* dbus/dbus-connection.c:
Add _dbus_connection_lock and _dbus_connection_unlock.
@@ -2922,7 +3664,7 @@
* dbus/dbus-errors.c (dbus_set_error_const): do not call
dbus_error_init
(dbus_set_error): remove dbus_error_init, check for message ==
- NULL *before* we sprintf into it, and add @todo about including
+ NULL *before* we sprintf into it, and add @todo about including
system headers in this file
* dbus/dbus-sysdeps.c (_dbus_create_file_exclusively): new
@@ -2930,7 +3672,7 @@
* dbus/dbus-errors.h (DBUS_ERROR_FAILED): add
* dbus/dbus-sysdeps.c (get_user_info): break this function out to
- get various bits of user information based on either username
+ get various bits of user information based on either username
or user ID
(_dbus_homedir_from_username): new function
@@ -2938,22 +3680,22 @@
* configure.in:
Add check for nonposix getpwnam_r
-
+
* dbus/dbus-mempool.c: (_dbus_mem_pool_new):
Align the pool element size to a sizeof (void *) boundary.
-
+
* dbus/dbus-sysdeps.c: (_dbus_setenv), (_dbus_connect_unix_socket),
(_dbus_listen_unix_socket), (_dbus_credentials_from_username):
General Solaris fixes.
-
+
* test/data/valid-messages/simplest-manual.message:
Explicitly state that we want little-endian packing.
-
+
2003-02-19 Mikael Hallendal <micke@codefactory.se>
* dbus/dbus-server.c (dbus_server_listen): Support tcp: addresses.
- * dbus/dbus-transport-unix.c (_dbus_transport_new_for_tcp_socket):
+ * dbus/dbus-transport-unix.c (_dbus_transport_new_for_tcp_socket):
Added to create a transport connecting using a tcp/ip socket.
* dbus/dbus-sysdeps.c (_dbus_connect_tcp_socket): Added to connect
@@ -2963,14 +3705,14 @@
* dbus/dbus-server.c (dbus_server_listen): Support tcp: addresses.
- * dbus/dbus-server-unix.c (_dbus_server_new_for_tcp_socket):
+ * dbus/dbus-server-unix.c (_dbus_server_new_for_tcp_socket):
Added to create a server listening on a TCP/IP socket.
2003-02-19 Havoc Pennington <hp@pobox.com>
Throughout: mop up all the Doxygen warnings and undocumented
stuff.
-
+
* dbus/dbus-sysdeps.c (do_exec): do not use execvp, we don't want
to search any paths.
@@ -2979,10 +3721,10 @@
besides being kind of ugly
* Doxyfile (PREDEFINED): have Doxygen define
- DOXYGEN_SHOULD_SKIP_THIS so we can exclude things from
+ DOXYGEN_SHOULD_SKIP_THIS so we can exclude things from
docs with #ifndef DOXYGEN_SHOULD_SKIP_THIS
- (do not abuse the feature! it's for stuff like the autogenerated
- macros in dbus-md5.c, not just for things you don't feel like
+ (do not abuse the feature! it's for stuff like the autogenerated
+ macros in dbus-md5.c, not just for things you don't feel like
documenting...)
2003-02-18 Havoc Pennington <hp@pobox.com>
@@ -3031,14 +3773,14 @@
2003-02-17 Anders Carlsson <andersca@codefactory.se.>
Release 0.4
-
+
* NEWS: Update
2003-02-17 Anders Carlsson <andersca@codefactory.se>
* doc/dbus-specification.sgml:
Specification updates.
-
+
2003-02-17 Anders Carlsson <andersca@codefactory.se>
* bus/activation.c: (bus_activation_init), (child_setup),
@@ -3046,21 +3788,21 @@
* bus/activation.h:
* bus/main.c: (main):
Set DBUS_ADDRESS environment variable.
-
+
* dbus/dbus-errors.c: (dbus_set_error):
Don't use va_copy since that's a C99 feature.
-
+
* dbus/dbus-sysdeps.c: (_dbus_setenv), (do_exec),
(_dbus_spawn_async):
* dbus/dbus-sysdeps.h:
Add child_setup_func to _dbus_spawn_async.
-
+
* doc/dbus-specification.sgml:
Update specification.
-
+
* test/spawn-test.c: (setup_func), (main):
Fix test.
-
+
2003-02-17 Alexander Larsson <alexl@redhat.com>
* dbus/dbus-connection.c (_dbus_connection_handler_destroyed_locked):
@@ -3072,10 +3814,10 @@
* doc/Makefile.am:
* doc/dbus-test-plan.sgml:
Add test plan document.
-
+
* test/Makefile.am:
Fix distcheck.
-
+
2003-02-17 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-message.c: (decode_header_data),
@@ -3086,11 +3828,11 @@
* bus/dispatch.c: (send_one_message):
Only send broadcast messages to registered connections.
-
+
* dbus/dbus-message.c: (dbus_message_name_is):
* dbus/dbus-message.h:
New convenience function.
-
+
* dbus/dbus-transport-debug.c: (do_reading):
Only dispatch one message per run.
@@ -3101,7 +3843,7 @@
* test/bus-test-loop.[ch]:
Add these.
-
+
2003-02-16 Havoc Pennington <hp@pobox.com>
* dbus/dbus-connection.c (dbus_connection_dispatch_message): fix
@@ -3113,7 +3855,7 @@
Implement sent_message_with_reply. (with_reply_and block is still
busted).
Made dispatch_message not lose message if OOM.
-
+
* dbus/dbus-errors.h:
Add NoReply error (for reply timeouts).
@@ -3126,51 +3868,51 @@
* dbus/dbus-auth.c: (client_try_next_mechanism):
Plug a leak.
-
+
* dbus/dbus-threads.c: (dbus_condvar_wait_timeout):
Return TRUE if there's no thread implementation around.
-
+
* glib/dbus-gmain.c: (free_source),
(dbus_connection_hookup_with_g_main):
Make sure to remove the GSource when the connection is finalized.
-
+
2003-02-16 Anders Carlsson <andersca@codefactory.se>
* bus/dispatch.c: (bus_dispatch_message_handler):
* dbus/dbus-errors.h:
Return an error if someone tries to send a message to a service
that doesn't exist.
-
+
2003-02-16 Anders Carlsson <andersca@codefactory.se>
* bus/activation.c: (load_directory), (bus_activation_init),
(bus_activation_activate_service):
* bus/activation.h:
- * bus/driver.c:
+ * bus/driver.c:
(bus_driver_handle_activate_service), (bus_driver_handle_message):
More work on the activation handling.
-
+
* dbus/dbus-errors.h:
Add some error messages
-
+
* dbus/dbus-message.c: (dbus_message_new_error_reply):
* dbus/dbus-message.h:
New function that creates an error message.
-
+
* dbus/dbus-protocol.h:
Add ACTIVATE_SERVER message.
-
+
* dbus/dbus-server-unix.c: (unix_handle_watch),
(_dbus_server_new_for_domain_socket):
Call _dbus_fd_set_close_on_exec.
-
+
* dbus/dbus-sysdeps.c: (make_pipe), (do_exec),
(_dbus_spawn_async), (_dbus_disable_sigpipe),
(_dbus_fd_set_close_on_exec):
* dbus/dbus-sysdeps.h:
Add _dbus_fd_set_close_on exec function. Also add function that checks
that all open fds are set to close-on-exec and warns otherwise.
-
+
* dbus/dbus-transport-unix.c:
(_dbus_transport_new_for_domain_socket):
Call _dbus_fd_set_close_on_exec.
@@ -3179,7 +3921,7 @@
* dbus/dbus-connection.c (dbus_connection_set_change_sigpipe):
allow people to avoid setting SIGPIPE to SIG_IGN
- (_dbus_connection_new_for_transport): disable SIGPIPE unless
+ (_dbus_connection_new_for_transport): disable SIGPIPE unless
we've been asked not to
2003-02-15 Anders Carlsson <andersca@codefactory.se>
@@ -3208,24 +3950,24 @@
* dbus/dbus-errors.c: (dbus_set_error):
* dbus/dbus-errors.h:
Add a few errors and make dbus_set_error void.
-
- * dbus/dbus-sysdeps.c:
+
+ * dbus/dbus-sysdeps.c:
(_dbus_errno_to_string), (close_and_invalidate), (make_pipe),
(write_err_and_exit), (read_ints), (do_exec), (_dbus_spawn_async):
* dbus/dbus-sysdeps.h:
Add _dbus_spawn_async.
-
+
* test/spawn-test.c: (main):
Test for _dbus_spawn_async.
-
+
2003-02-15 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-internals.h:
Fix build without tests.
-
+
* dbus/dbus-list.c: (alloc_link):
Fix a segfault when a malloc fails.
-
+
* dbus/dbus-memory.c: (initialize_malloc_debug), (dbus_malloc),
(dbus_malloc0), (dbus_realloc):
Add support for malloc debugging.
@@ -3236,12 +3978,12 @@
* dbus/dbus-threads.h:
Add condvars. Remove static mutext from API.
Implement static mutexes by initializing them from threads_init.
-
+
* glib/dbus-gthread.c:
* qt/dbus-qthread.cpp:
Update with the thread api changes.
-
+
* dbus/dbus-list.c:
* dbus/dbus-list.h:
Turn StaticMutex into normal mutex + init function.
@@ -3249,18 +3991,18 @@
_dbus_list_append_link, _dbus_list_prepend_link
- * dbus/dbus-sysdeps.c:
+ * dbus/dbus-sysdeps.c:
* dbus/dbus-sysdeps.h:
New type dbus_atomic_t, and new functions _dbus_atomic_inc,
_dbus_atomic_dec. Only slow fallback implementation at the moment.
-
+
* dbus/dbus-protocol.h:
Add DBUS_MESSAGE_LOCAL_DISCONNECT define
-
+
* dbus/dbus-message.c:
Make ref/unref atomic.
Fix some docs.
-
+
* dbus/dbus-connection-internal.h:
* dbus/dbus-connection.c:
* dbus/dbus-connection.h:
@@ -3268,23 +4010,23 @@
Change _peek to _borrow,_return & _steal_borrowed.
Change disconnect callback to event.
Make dbus_connection_dispatch_messages reentrant.
-
+
* dbus/dbus-transport.c:
Don't ref the connection on calls to the transport
implementation.
-
+
* dbus/dbus-message-handler.c:
Make threadsafe.
-
+
* glib/dbus-gmain.c:
Don't use peek_message anymore
-
+
* test/Makefile.am:
* test/debug-thread.c:
* test/debug-thread.h:
Simple thread implementation that asserts() on deadlocks in
single-threaded code.
-
+
* test/bus-test.c:
(main) Call debug_threads_init.
@@ -3295,10 +4037,10 @@
* bus/connection.h:
Don't call dbus_connection_set_disconnect_function. Instead export
bus_connection_disconnect.
-
+
* bus/dispatch.c:
Call bus_connection_disconnect when we get a disconnected message.
-
+
2003-02-15 Havoc Pennington <hp@pobox.com>
* dbus/dbus-message.c (dbus_message_new): fool around with the
@@ -3312,12 +4054,12 @@
should
* dbus/dbus-internals.c (_dbus_set_fail_alloc_counter)
- (_dbus_decrement_fail_alloc_counter): debug functions to
+ (_dbus_decrement_fail_alloc_counter): debug functions to
simulate memory allocation failures
2003-02-14 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-errors.h (struct DBusError): add a word of padding
+ * dbus/dbus-errors.h (struct DBusError): add a word of padding
to DBusError
2003-02-13 Anders Carlsson <andersca@codefactory.se>
@@ -3326,10 +4068,10 @@
* bus/driver.h:
* bus/services.c: (bus_service_lookup):
Reorder message sending so we get a more sane order.
-
+
* test/bus-test.c: (message_handler):
Fix tyop.
-
+
2003-02-13 Anders Carlsson <andersca@codefactory.se>
* bus/driver.c: (bus_driver_send_service_deleted),
@@ -3354,10 +4096,10 @@
* test/bus-test.c: (main):
Change fields to arguments in messages, so that they won't be
confused with header fields.
-
+
* glib/test-dbus-glib.c: (main):
Remove append_fields from hello message.
-
+
2003-02-13 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-errors.c:
@@ -3370,36 +4112,36 @@
* glib/dbus-gmain.c: (timeout_handler), (add_timeout),
(remove_timeout):
Implement support for timeouts in dbus-glib.
-
+
2003-02-13 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-message-builder.c: (_dbus_message_data_load):
* dbus/dbus-message.c: (process_test_subdir):
* test/break-loader.c: (find_breaks_based_on):
Plug some memory leaks.
-
+
2003-02-13 Richard Hult <rhult@codefactory.se>
* bus/main.c: Fix build.
- * dbus/dbus-errors.h:
+ * dbus/dbus-errors.h:
* dbus/dbus-errors.c: Fix copyright for Anders.
2003-02-13 Anders Carlsson <andersca@codefactory.se>
* bus/Makefile.am:
Add utils.[ch]
-
+
* bus/connection.c: (bus_connection_foreach):
Fix a warning.
-
+
* bus/desktop-file.c: (grow_lines_in_section), (grow_sections),
(unescape_string), (new_section), (parse_section_start),
(parse_key_value), (report_error), (bus_desktop_file_load),
(bus_desktop_file_get_string):
* bus/desktop-file.h:
Use DBusError for error reporting.
-
+
* bus/dispatch.c: (send_one_message),
(bus_dispatch_message_handler):
* bus/driver.c: (bus_driver_send_service_deleted),
@@ -3412,21 +4154,21 @@
* bus/loop.c: (bus_loop_run):
* bus/main.c:
Use BUS_HANDLE_OOM instead of _DBUS_HANDLE_OOM.
-
+
* bus/utils.c: (bus_wait_for_memory):
* bus/utils.h:
New files with general utility functions.
-
+
* dbus/dbus-internals.h:
Remove _DBUS_HANDLE_OOM.
-
+
2003-02-13 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-errors.c: (dbus_result_to_string), (dbus_error_init),
(dbus_error_free), (dbus_set_error_const), (dbus_set_error):
* dbus/dbus-errors.h:
Add DBusError structure.
-
+
2003-02-13 Anders Carlsson <andersca@codefactory.se>
* test/data/valid-messages/standard-acquire-service.message:
@@ -3434,7 +4176,7 @@
* test/data/valid-messages/standard-list-services.message:
* test/data/valid-messages/standard-service-exists.message:
Add some standard messages.
-
+
2003-02-13 Anders Carlsson <andersca@codefactory.se>
* bus/driver.c: (bus_driver_send_welcome_message),
@@ -3442,7 +4184,7 @@
(bus_driver_handle_acquire_service),
(bus_driver_handle_service_exists), (bus_driver_handle_message):
Update for API changes in libdbus.
-
+
* dbus/dbus-message.c: (dbus_message_new_reply):
* dbus/dbus-message.h:
Remove the name argument. The spec states that replies shouldn't
@@ -3456,7 +4198,7 @@
(bus_desktop_file_get_string):
* bus/desktop-file.h:
Some fixes, and new functions for getting a key value from a section.
-
+
2003-02-13 Havoc Pennington <hp@pobox.com>
* test/data/auth/fail-after-n-attempts.auth-script: new test
@@ -3472,12 +4214,12 @@
* dbus/dbus-auth-script.c (_dbus_auth_script_run): support
NO_CREDENTIALS and ROOT_CREDENTIALS
- * dbus/dbus-auth.c (_dbus_auth_do_work): move get_state() routine
- into here. Never process more commands after we've reached an
+ * dbus/dbus-auth.c (_dbus_auth_do_work): move get_state() routine
+ into here. Never process more commands after we've reached an
end state; store further data as unused bytes.
* test/data/auth/*: add more auth tests
-
+
* dbus/dbus-auth-script.c (_dbus_auth_script_run): support EXPECT
command to match exact string and EXPECT_UNUSED to match unused
bytes
@@ -3505,11 +4247,11 @@
2003-02-10 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-auth-script.c, dbus/dbus-auth-script.h: sync
+ * dbus/dbus-auth-script.c, dbus/dbus-auth-script.h: sync
initial cut at test framework for DBusAuth from laptop.
- Doesn't quite work yet but it compiles and I need to get
+ Doesn't quite work yet but it compiles and I need to get
it off the 266mhz laptop. ;-)
-
+
* dbus/dbus-server-debug.c (_dbus_server_debug_accept_transport):
fix a memleak in error case
@@ -3533,7 +4275,7 @@
2003-02-06 Anders Carlsson <andersca@codefactory.se>
Release 0.3
-
+
* NEWS: Update
2003-02-06 Anders Carlsson <andersca@codefactory.se>
@@ -3546,7 +4288,7 @@
2003-02-02 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-keyring.c, dbus/dbus-keyring.h: template files
+ * dbus/dbus-keyring.c, dbus/dbus-keyring.h: template files
for code to manage cookies in your home directory
* dbus/dbus-sysdeps.c (_dbus_generate_random_bytes): new function
@@ -3563,7 +4305,7 @@
* doc/dbus-specification.sgml:
Update address format section.
-
+
2003-02-02 Anders Carlsson <andersca@codefactory.se>
* test/Makefile.am:
@@ -3571,15 +4313,15 @@
(message_handler), (new_connection_callback), (loop_quit),
(loop_run), (main):
Add bus test.
-
+
2003-02-02 Anders Carlsson <andersca@codefactory.se>
* bus/driver.c: (bus_driver_handle_service_exists):
Simplify the code a bit.
-
+
* dbus/dbus-bus.c: (dbus_bus_service_exists):
- Fix a silly.
-
+ Fix a silly.
+
2003-02-02 Anders Carlsson <andersca@codefactory.se>
* bus/Makefile.am:
@@ -3594,7 +4336,7 @@
* bus/driver.c: (bus_driver_handle_service_exists):
Don't unref the incoming message.
-
+
2003-02-02 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus.h: Add dbus-address.h and dbus-bus.h
@@ -3604,7 +4346,7 @@
* dbus/dbus-server.c: (dbus_server_listen):
* dbus/dbus-transport.c: (_dbus_transport_open):
ifdef out the calls to the debug transport and server.
-
+
2003-02-02 Alexander Larsson <alexl@redhat.com>
* dbus/dbus-watch.c (dbus_watch_get_flags):
@@ -3624,18 +4366,18 @@
(bus_driver_handle_hello):
Don't take a name, just use a numeric id to identify
each client.
-
+
* dbus/Makefile.am:
* dbus/dbus-bus.c: (dbus_bus_register_client),
(dbus_bus_acquire_service), (dbus_bus_service_exists):
* dbus/dbus-bus.h:
Add new convenience functions for communicating with the bus.
-
+
* dbus/dbus-message.h:
-
+
* dbus/dbus-protocol.h:
Fix a typo.
-
+
2003-02-01 Alexander Larsson <alexl@redhat.com>
* dbus/dbus-message.c (dbus_message_append_fields):
@@ -3643,7 +4385,7 @@
2003-02-01 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-break-loader.c (randomly_modify_length): change
+ * dbus/dbus-break-loader.c (randomly_modify_length): change
a 4-byte value in the message as if it were a length
* dbus/dbus-sysdeps.c (_dbus_string_save_to_file): don't set
@@ -3658,23 +4400,23 @@
* dbus/dbus-sysdeps.c (_dbus_string_save_to_file): new function
* dbus/dbus-string.c (_dbus_string_set_byte): new
-
+
2003-01-31 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-message.c: refactor the test code to be more general,
- in preparation for writing a "randomly permute test cases to
+ * dbus/dbus-message.c: refactor the test code to be more general,
+ in preparation for writing a "randomly permute test cases to
try to break the loader" program.
2003-01-31 Havoc Pennington <hp@pobox.com>
-
+
* doc/dbus-specification.sgml: work on the specification
- * dbus/dbus-message.c (_dbus_message_loader_return_buffer): check
+ * dbus/dbus-message.c (_dbus_message_loader_return_buffer): check
the protocol version of the message.
- * dbus/dbus-protocol.h: drop special _REPLY names, the spec
+ * dbus/dbus-protocol.h: drop special _REPLY names, the spec
no longer specifies that.
- (DBUS_SERVICE_REPLY_SERVICE_EXISTS): fix flags (1/2/4/8 not
+ (DBUS_SERVICE_REPLY_SERVICE_EXISTS): fix flags (1/2/4/8 not
1/2/3/4)
* dbus/dbus-marshal.c (_dbus_marshal_get_arg_end_pos): add missing
@@ -3682,7 +4424,7 @@
2003-01-31 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-message.c (dbus_message_set_is_error_reply): rename
+ * dbus/dbus-message.c (dbus_message_set_is_error_reply): rename
just set_is_error/get_is_error as this is a commonly-used
function, and write docs.
@@ -3690,28 +4432,28 @@
* dbus/dbus-address.c: (dbus_address_entry_free):
Free key and value lists.
-
+
* dbus/dbus-internals.c: (_dbus_type_to_string):
Add the types we didn't have.
-
+
* dbus/dbus-marshal.c: (_dbus_marshal_get_arg_end_pos),
(_dbus_marshal_validate_arg):
Add NIL types.
-
+
* dbus/dbus-message.c: (dbus_message_set_sender):
Remove todo about being able to set sender to NULL.
-
+
(dbus_message_set_is_error_reply),
(dbus_message_get_is_error_reply):
* dbus/dbus-message.h:
New functions.
-
+
* dbus/dbus-protocol.h:
Add error reply flag.
-
+
* test/data/valid-messages/opposite-endian.message:
Add NIL type to test.
-
+
2003-01-31 Havoc Pennington <hp@pobox.com>
* doc/dbus-specification.sgml: fully specify the header. Add
@@ -3728,10 +4470,10 @@
2003-01-30 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-auth.c: rework to use only REJECTED, no
+ * dbus/dbus-auth.c: rework to use only REJECTED, no
MECHANISMS
- * doc/dbus-sasl-profile.txt: drop MECHANISMS and just
+ * doc/dbus-sasl-profile.txt: drop MECHANISMS and just
use REJECTED, suggested by Mark McLoughlin
2003-01-30 Havoc Pennington <hp@pobox.com>
@@ -3743,55 +4485,55 @@
* dbus/dbus-address.c (dbus_address_entries_free): add @todo about
leaking list nodes
- (dbus_parse_address): add @todo about documenting address format,
+ (dbus_parse_address): add @todo about documenting address format,
and allowing , and ; to be escaped
2003-01-30 Anders Carlsson <andersca@codefactory.se>
* dbus/Makefile.am:
Add dbus-address.[ch]
-
+
* dbus/dbus-address.c: (dbus_address_entry_free),
(dbus_address_entries_free), (create_entry),
(dbus_address_entry_get_method), (dbus_address_entry_get_value),
(dbus_parse_address), (_dbus_address_test):
* dbus/dbus-address.h:
New files for dealing with address parsing.
-
+
* dbus/dbus-connection.c:
Document timeout functions.
-
+
* dbus/dbus-message.c:
Document dbus_message_new_from_message.
-
+
* dbus/dbus-server-debug.c:
Document.
-
+
* dbus/dbus-server.c: (dbus_server_listen):
Parse address and use correct server implementation.
-
+
* dbus/dbus-string.c: (_dbus_string_find_to), (_dbus_string_test):
* dbus/dbus-string.h:
New function with test.
-
+
* dbus/dbus-test.c: (dbus_internal_symbol_do_not_use_run_tests):
* dbus/dbus-test.h:
Add address tests.
-
+
* dbus/dbus-transport-debug.c:
Document.
-
+
* dbus/dbus-transport.c: (_dbus_transport_open):
- Parse address and use correct transport implementation.
+ Parse address and use correct transport implementation.
2003-01-30 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-message.c: use message->byte_order instead of
+ * dbus/dbus-message.c: use message->byte_order instead of
DBUS_COMPILER_BYTE_ORDER throughout.
- (dbus_message_create_header): pad header to align the
+ (dbus_message_create_header): pad header to align the
start of the body of the message to 8-byte boundary
- * dbus/dbus-marshal.h: make all the demarshalers take const
+ * dbus/dbus-marshal.h: make all the demarshalers take const
DBusString arguments.
* dbus/dbus-message.c (_dbus_message_loader_return_buffer):
@@ -3804,7 +4546,7 @@
implemented properly)
(_dbus_string_validate_nul): new function to check all-nul
- * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): rename
+ * dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): rename
get_arg_end_pos and remove all validation
(_dbus_marshal_validate_arg): actually do validation here.
@@ -3816,9 +4558,9 @@
2003-01-28 Havoc Pennington <hp@pobox.com>
* dbus/dbus-server-debug.c: Add doc section comments
-
+
* dbus/dbus-transport-debug.c: add doc section comments
-
+
2003-01-28 Havoc Pennington <hp@redhat.com>
* dbus/dbus-string.c (_dbus_string_base64_decode): append bytes in
@@ -3832,13 +4574,13 @@
* dbus/dbus-connection.c: (_dbus_connection_add_timeout),
(_dbus_connection_remove_timeout):
Add functions for adding and removing timeouts.
-
+
* dbus/dbus-message.c: (dbus_message_new_from_message):
Add new function that takes a message and creates an exact
copy of it, but with the refcount set to 1.
(check_message_handling):
Fix build error.
-
+
* dbus/dbus-server-protected.h:
* dbus/dbus-server.c: (_dbus_server_init_base),
(_dbus_server_finalize_base), (_dbus_server_add_timeout),
@@ -3851,16 +4593,16 @@
* dbus/dbus-timeout.c: (_dbus_timeout_new):
Actually set the handler, doh.
-
+
* dbus/dbus-transport.c: (_dbus_transport_open):
Add commented out call to dbus_transport_debug_client_new.
-
+
* dbus/Makefile.am:
Add dbus-transport-debug.[ch] and dbus-server-debug.[ch]
-
+
2003-01-28 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-message.c (check_message_handling): function to check
+ * dbus/dbus-message.c (check_message_handling): function to check
on the loaded message, iterates over it etc.
2003-01-28 Havoc Pennington <hp@pobox.com>
@@ -3871,14 +4613,14 @@
2003-01-27 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-mempool.c (time_for_size): replace printf with
+ * dbus/dbus-mempool.c (time_for_size): replace printf with
_dbus_verbose
* dbus/dbus-message-builder.c (_dbus_message_data_load): allow
empty lines; fix the SAVE_LENGTH stuff to be
- START_LENGTH/END_LENGTH so it actually works; couple other
+ START_LENGTH/END_LENGTH so it actually works; couple other
bugfixes
-
+
* test/Makefile.am (dist-hook): add dist-hook for .message files
* dbus/dbus-string.c (DBUS_STRING_COPY_PREAMBLE): source of a copy
@@ -3888,7 +4630,7 @@
* dbus/dbus-sysdeps.c (_dbus_concat_dir_and_file): utility
- * dbus/dbus-test-main.c (main): take an argument which is the
+ * dbus/dbus-test-main.c (main): take an argument which is the
directory containing test data
* dbus/dbus-message.c (_dbus_message_test): pass a test_data_dir
@@ -3899,7 +4641,7 @@
* bus/dispatch.c: (bus_dispatch_message_handler):
Dispatch messages sent to services.
-
+
* bus/driver.c: (bus_driver_send_service_deleted),
(bus_driver_send_service_created), (bus_driver_send_service_lost),
(bus_driver_send_service_acquired):
@@ -3907,56 +4649,56 @@
(bus_driver_send_welcome_message):
Send HELLO_REPLY instead of WELCOME.
-
+
(bus_driver_handle_list_services):
Send LIST_SERVICES_REPLY instead of SERVICES.
-
+
(bus_driver_handle_own_service),
(bus_driver_handle_service_exists):
New message handlers.
-
+
(bus_driver_handle_message):
Invoke new message handlers.
-
+
(bus_driver_remove_connection):
Don't remove any services here since that's done automatically
by bus_service_remove_owner now.
-
+
* bus/driver.h:
New function signatures.
-
+
* bus/services.c: (bus_service_add_owner):
Send ServiceAcquired message if we're the only primary owner.
-
+
(bus_service_remove_owner):
Send ServiceAcquired/ServiceLost messages.
-
+
(bus_service_set_prohibit_replacement),
(bus_service_get_prohibit_replacement):
Functions for setting prohibit replacement.
-
+
(bus_service_has_owner):
- New function that checks if a connection is in the owner queue of
+ New function that checks if a connection is in the owner queue of
a certain service.
-
+
* bus/services.h:
Add new function signatures.
-
+
* dbus/dbus-list.c: (_dbus_list_test):
Add tests for _dbus_list_remove_last and traversing the list backwards.
-
+
* dbus/dbus-list.h:
Fix a typo in _dbus_list_get_prev_link, if we're at the first element we can't
go any further, so return NULL then.
-
+
* dbus/dbus-protocol.h:
Add new messages, service flags and service replies.
-
+
2003-01-26 Havoc Pennington <hp@pobox.com>
* dbus/dbus-message-builder.c: implement, completely untested.
- * test/data/*: add data to be used in testing.
+ * test/data/*: add data to be used in testing.
".message" files are our simple loadable text format.
".message-raw" will be binary dumps of messages.
@@ -3981,21 +4723,21 @@
The unit tests pass, but otherwise untested. If it breaks, the
tests should have been better. ;-)
-
+
* bus/driver.c (bus_driver_handle_hello): return if we disconnect
the connection.
- * dbus/dbus-message.c: redo everything so we maintain
+ * dbus/dbus-message.c: redo everything so we maintain
message->header as the only copy of the various fields.
This avoids the possibility of out-of-memory in some cases,
for example dbus_message_lock() can't run out of memory anymore,
- and avoids extra copying. Figured I may as well go ahead and do
- this since it was busted for dbus_message_lock to not return
+ and avoids extra copying. Figured I may as well go ahead and do
+ this since it was busted for dbus_message_lock to not return
failure on OOM, and dbus_message_write_header was totally
unchecked for OOM. Also fixed some random other bugs.
* dbus/dbus-marshal.c (_dbus_marshal_get_field_end_pos): verify
- that strings are nul-terminated. Also, end_pos can be equal
+ that strings are nul-terminated. Also, end_pos can be equal
to string length just not greater than, I think.
(_dbus_marshal_set_int32): new function
(_dbus_marshal_set_uint32): new function
@@ -4013,7 +4755,7 @@
* bus/driver.c: (bus_driver_handle_hello),
(bus_driver_send_welcome_message):
Plug leaks
-
+
2003-01-26 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-auth.c: (process_auth), (_dbus_auth_unref):
@@ -4022,13 +4764,13 @@
* dbus/dbus-marshal.c: (_dbus_marshal_test):
* dbus/dbus-message.c: (dbus_message_unref),
Plug memory leaks.
-
- (dbus_message_get_fields):
+
+ (dbus_message_get_fields):
Remove debugging printout.
(_dbus_message_loader_return_buffer):
Don't store the header string.
-
+
(_dbus_message_test):
Plug leaks.
@@ -4042,10 +4784,10 @@
* glib/dbus-gmain.c: (dbus_connection_prepare),
(dbus_connection_check), (dbus_connection_dispatch), (add_watch),
(remove_watch), (dbus_connection_hookup_with_g_main):
- Rewrite the glib handling to use its own GSource instead of a
+ Rewrite the glib handling to use its own GSource instead of a
GIOChannel so we can catch messages put in the queue while waiting
for a reply.
-
+
2003-01-25 Anders Carlsson <andersca@codefactory.se>
* bus/Makefile.am:
@@ -4061,105 +4803,105 @@
(bus_driver_handle_list_services), (bus_driver_remove_connection),
(bus_driver_handle_message):
* bus/driver.h:
- Refactor code, put the message dispatching in its own file. Use
+ Refactor code, put the message dispatching in its own file. Use
_DBUS_HANDLE_OOM. Also send ServiceDeleted messages when a client
is disconnected.
-
+
2003-01-25 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-internals.h:
Add _DBUS_HANDLE_OOM macro, it doesn't do anything currently.
-
+
* dbus/dbus-message.c: (dbus_message_get_sender):
* dbus/dbus-message.h:
Implement dbus_message_get_sender.
-
+
* dbus/dbus-protocol.h:
Add message and service defines.
-
+
2003-01-25 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-connection.c: (dbus_connection_send_message):
* dbus/dbus-message-internal.h:
* dbus/dbus-message.c: (_dbus_message_get_client_serial),
(dbus_message_write_header):
- Remove _dbus_messag_unlock and don't set the client serial on a
+ Remove _dbus_messag_unlock and don't set the client serial on a
message if one already exists.
-
+
2003-01-24 Havoc Pennington <hp@pobox.com>
* dbus/dbus-list.c (alloc_link): put a thread lock on the global
list_pool
- * bus/driver.c (bus_driver_handle_list_services): fix a leak
+ * bus/driver.c (bus_driver_handle_list_services): fix a leak
on OOM
2003-01-25 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-list.c: (alloc_link), (free_link):
Use a memory pool for the links.
-
+
2003-01-25 Anders Carlsson <andersca@codefactory.se>
* bus/connection.c: (bus_connection_foreach):
* bus/connection.h:
Add new bus_connection_foreach function.
-
+
* bus/driver.c: (send_one_message), (bus_driver_broadcast_message):
Add function that broadcasts a message to all clients.
-
+
(bus_driver_send_service_created), (bus_driver_handle_hello),
(bus_driver_send_welcome_message),
(bus_driver_handle_list_services), (bus_driver_message_handler):
Implement functions that take care of listing services, and notifying
clients when new services are created.
-
+
* bus/services.c: (bus_services_list):
* bus/services.h:
Add new function that returns an array of strings with the currently
registered services.
-
+
* glib/dbus-glib.h:
* glib/dbus-gmain.c:
Update copyright year.
-
+
2003-01-25 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-connection.c: (dbus_connection_send_message):
Unlock the message in case it was sent earlier.
-
+
(dbus_connection_send_message_with_reply_and_block):
Remove the reply message from the list.
-
+
* dbus/dbus-marshal.c: (_dbus_demarshal_string_array):
Set array_len and new_pos correctly.
-
+
(_dbus_marshal_test):
Remove debug output.
-
+
* dbus/dbus-message-internal.h:
* dbus/dbus-message.c: (_dbus_message_get_reply_serial):
New function that returns the reply serial.
-
+
(_dbus_message_unlock):
New function that unlocks a message and resets its header.
- (dbus_message_append_string_array),
+ (dbus_message_append_string_array),
(dbus_message_get_fields_valist),
(dbus_message_iter_get_field_type),
- (dbus_message_iter_get_string_array),
- (dbus_message_get_fields),
+ (dbus_message_iter_get_string_array),
+ (dbus_message_get_fields),
(dbus_message_append_fields_valist):
Handle string arrays.
-
+
(dbus_message_set_sender):
Make this function public since the bus daemon needs it.
-
+
(decode_header_data):
Set the reply serial to -1 initially.
* dbus/dbus-message.h:
- Add dbus_message_set_sender.
+ Add dbus_message_set_sender.
2003-01-24 Havoc Pennington <hp@pobox.com>
@@ -4179,9 +4921,9 @@
2003-01-21 Havoc Pennington <hp@pobox.com>
(patch untested because can't compile)
-
+
* bus/driver.c (create_unique_client_name): make this function
- never recycle client names. Also, caller should initialize
+ never recycle client names. Also, caller should initialize
the DBusString.
* dbus/dbus-sysdeps.c (_dbus_get_current_time): new function
@@ -4199,27 +4941,27 @@
* dbus/dbus-protocol.h:
Add support for marshalling and demarshalling integer, double
and string arrays.
-
+
2003-01-21 Anders Carlsson <andersca@codefactory.se>
* bus/Makefile.am:
Add driver.[ch]
-
+
* bus/connection.c: (connection_disconnect_handler):
Remove the connection from the bus driver's list.
-
+
(connection_watch_callback): Dispatch messages.
(free_connection_data): Free connection name.
-
+
(bus_connection_setup): Add connection to the bus driver's list.
- (bus_connection_remove_owned_service):
+ (bus_connection_remove_owned_service):
(bus_connection_set_name), (bus_connection_get_name):
Add functions for setting and getting the connection's name.
-
+
* bus/connection.h:
Add function headers.
-
+
* bus/driver.c: (create_unique_client_name),
(bus_driver_handle_hello_message),
(bus_driver_send_welcome_message), (bus_driver_message_handler),
@@ -4229,27 +4971,27 @@
* bus/services.c: (bus_service_free):
* bus/services.h:
New file that handles communication and registreation with the bus
- itself.
-
+ itself.
+
2003-01-21 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-connection.c: (dbus_connection_send_message):
Add a new client_serial parameter.
-
+
(dbus_connection_send_message_with_reply):
Remove a @todo since we've implemented the blocking function.
-
+
(dbus_connection_send_message_with_reply_and_block):
New function that sends a message and waits for a reply and
then returns the reply.
-
+
* dbus/dbus-connection.h:
Add new functions.
-
+
* dbus/dbus-errors.c: (dbus_result_to_string):
* dbus/dbus-errors.h:
Add new DBUS_RESULT.
-
+
* dbus/dbus-message-internal.h:
* dbus/dbus-message.c: (_dbus_message_get_reply_serial),
(_dbus_message_set_sender), (dbus_message_write_header),
@@ -4258,37 +5000,37 @@
* dbus/dbus-message.h:
Add new functions that set the reply serial and sender.
Also marshal and demarshal them correctly and add test.
-
+
* dbus/dbus-protocol.h:
Add new DBUS_MESSAGE_TYPE_SENDER.
-
+
* glib/dbus-glib.h:
* glib/dbus-gmain.c: (watch_callback), (free_callback_data),
(add_watch), (remove_watch), (add_timeout), (remove_timeout),
(dbus_connection_hookup_with_g_main):
* glib/test-dbus-glib.c: (main):
Rewrite to use GIOChannel and remove the GSource crack.
-
+
* test/echo-client.c: (main):
* test/watch.c: (check_messages):
Update for changed APIs
-
+
2003-01-19 Anders Carlsson <andersca@codefactory.se>
* dbus/Makefile.am: Add dbus-timeout.[cħ]
-
+
* dbus/dbus-connection.c: (_dbus_connection_new_for_transport):
- Create a DBusTimeoutList.
+ Create a DBusTimeoutList.
(dbus_connection_set_timeout_functions): Add new function to
set timeout callbacks
-
+
* dbus/dbus-connection.h: Add public DBusTimeout API.
-
+
* dbus/dbus-message.c: (dbus_message_get_service):
* dbus/dbus-message.h: New function.
* dbus/dbus-server.c: Fix small doc typo.
-
+
* dbus/dbus-timeout.[ch]: New files for mainloop timeouts.
2003-01-19 Anders Carlsson <andersca@codefactory.se>
@@ -4318,9 +5060,9 @@
* dbus/dbus-transport-unix.c (check_write_watch): fix a mem leak
in OOM case
- * dbus/dbus-connection.c (dbus_connection_set_max_message_size)
- (dbus_connection_get_max_message_size)
- (dbus_connection_set_max_live_messages_size)
+ * dbus/dbus-connection.c (dbus_connection_set_max_message_size)
+ (dbus_connection_get_max_message_size)
+ (dbus_connection_set_max_live_messages_size)
(dbus_connection_get_max_live_messages_size): implement some
resource limitation functions
@@ -4332,10 +5074,10 @@
* dbus/dbus-marshal.c (_dbus_demarshal_byte_array): add missing
docs
-
+
2003-01-18 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-connection.c (dbus_connection_unref): disconnect the
+ * dbus/dbus-connection.c (dbus_connection_unref): disconnect the
connection if it hasn't been already.
* dbus/dbus-connection.h: kill off the idea of an ErrorFunction,
@@ -4345,9 +5087,9 @@
Building --disable-verbose-mode --disable-asserts --disable-tests
cuts the library from 112K to 45K or so
-
- * configure.in: check for varargs macro support,
- add --enable-verbose-mode, --enable-asserts.
+
+ * configure.in: check for varargs macro support,
+ add --enable-verbose-mode, --enable-asserts.
* dbus/dbus-internals.h (_dbus_assert): support
DBUS_DISABLE_ASSERT
@@ -4374,7 +5116,7 @@
2003-01-15 Havoc Pennington <hp@redhat.com>
Release 0.2
-
+
* NEWS: update
2003-01-15 Havoc Pennington <hp@redhat.com>
@@ -4385,8 +5127,8 @@
2003-01-15 Havoc Pennington <hp@redhat.com>
Release 0.1.
-
- * NEWS: update
+
+ * NEWS: update
2003-01-15 Havoc Pennington <hp@redhat.com>
@@ -4404,7 +5146,7 @@
* bus/main.c: (main):
Make sure that the DBusConnectionData struct is NULLed
out to prevent a segfault.
-
+
* dbus/dbus-errors.c: (dbus_result_to_string):
* dbus/dbus-errors.h:
* dbus/dbus-message.c: (dbus_message_get_fields),
@@ -4412,7 +5154,7 @@
* dbus/dbus-message.h:
Make dbus_message_get_fields return a result code so we can
track invalid fields as well as oom.
-
+
2003-01-11 Havoc Pennington <hp@pobox.com>
* configure.in: change --enable-test/--enable-ansi action-if-given
@@ -4425,11 +5167,11 @@
* dbus/dbus-test-main.c: move main() for test app here
* dbus/dbus-test.c
(dbus_internal_symbol_do_not_use_run_tests): we have to export a
- symbol to run tests, because dbus-test isn't in the main
+ symbol to run tests, because dbus-test isn't in the main
library
Code review nitpicks.
-
+
* dbus/dbus-message.c (dbus_message_write_header): add newlines
for people with narrow emacs ;-). Assert client_serial was filled
in. Assert message->name != NULL.
@@ -4466,7 +5208,7 @@
2003-01-08 Havoc Pennington <hp@redhat.com>
- * dbus/dbus-transport-unix.c (unix_do_iteration): add read/write
+ * dbus/dbus-transport-unix.c (unix_do_iteration): add read/write
to the select() as needed for authentication. (should be using
_dbus_poll() not select, but for another day)
@@ -4481,7 +5223,7 @@
* dbus/dbus-internals.c: (_dbus_type_to_string):
New function that returns a string describing a type.
-
+
* dbus/dbus-marshal.c: (_dbus_demarshal_byte_array):
* dbus/dbus-marshal.h:
* dbus/dbus-message.c: (dbus_message_get_fields_valist),
@@ -4527,7 +5269,7 @@
* test/echo-client.c: (main):
* test/watch.c: (check_messages):
Make messages sendable and receivable for real.
-
+
2003-01-07 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-marshal.c: (_dbus_marshal_double),
@@ -4536,7 +5278,7 @@
(dbus_message_append_uint32), (dbus_message_append_double),
(dbus_message_append_string), (dbus_message_append_byte_array):
Handle OOM restoration.
-
+
2003-01-07 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-marshal.c: (_dbus_marshal_string),
@@ -4544,13 +5286,13 @@
* dbus/dbus-marshal.h:
* dbus/dbus-message.c: (dbus_message_get_name),
Document these functions.
-
+
(dbus_message_append_int32), (dbus_message_append_uint32),
(dbus_message_append_double), (dbus_message_append_string),
(dbus_message_append_byte_array):
* dbus/dbus-message.h:
Add functions for adding message fields of different types.
-
+
* dbus/dbus-protocol.h:
Add the different types.
@@ -4584,13 +5326,13 @@
2003-01-04 Havoc Pennington <hp@pobox.com>
- * test/watch.c (error_handler): make it safe if the error handler
+ * test/watch.c (error_handler): make it safe if the error handler
is called multiple times (if we s/error handler/disconnect
handler/ we should just guarantee it's called only once)
* dbus/dbus-transport.c (_dbus_transport_disconnect): call the
error handler on disconnect (it's quite possible we should
- just change the error handler to a "disconnect handler," I'm
+ just change the error handler to a "disconnect handler," I'm
not sure we have any other meaningful errors)
* configure.in: check for getpwnam_r
@@ -4615,7 +5357,7 @@
* dbus/dbus-marshal.h:
Add _dbus_marshal_byte_array and rename _dbus_marshal_string
to _dbus_marshal_utf8_string. Also fix some tests.
-
+
2002-12-28 Harri Porten <porten@kde.org>
* configure.in: added check for C++ compiler and a very cheesy
@@ -4623,9 +5365,9 @@
* Makefile.am (SUBDIRS): compile qt subdir if support is enabled
- * qt/Makefile.am: added
+ * qt/Makefile.am: added
- * qt/.cvsignore: added
+ * qt/.cvsignore: added
* qt/dbus-qthread.cc, qt/dbus-qthread.cpp: renamed former to
latter, added #ifdef QT_THREAD_SUPPORT guard.
@@ -4638,7 +5380,7 @@
2002-12-27 Anders Carlsson <andersca@codefactory.se>
- * acinclude.m4: Add this file and put the
+ * acinclude.m4: Add this file and put the
PKG_CHECK_MODULE macro in it.
2002-12-27 Anders Carlsson <andersca@codefactory.se>
@@ -4648,9 +5390,9 @@
(_dbus_demarshal_uint32), (_dbus_demarshal_string),
(_dbus_marshal_test):
Make the demarshalling routines align the pos argument.
- Add string marshalling tests and fix the obvious bugs
+ Add string marshalling tests and fix the obvious bugs
discovered.
-
+
2002-12-26 Havoc Pennington <hp@pobox.com>
* dbus/dbus-auth.c: fixes fixes fixes
@@ -4658,8 +5400,8 @@
* dbus/dbus-transport-unix.c: wire up support for
encoding/decoding data on the wire
- * dbus/dbus-auth.c (_dbus_auth_encode_data)
- (_dbus_auth_decode_data): append to target string
+ * dbus/dbus-auth.c (_dbus_auth_encode_data)
+ (_dbus_auth_decode_data): append to target string
instead of nuking it.
2002-12-26 Havoc Pennington <hp@pobox.com>
@@ -4669,7 +5411,7 @@
doh
* dbus/dbus-marshal.c: Add macros to do int swapping in-place and
- avoid swap_bytes() overhead (ignoring possible assembly stuff for
+ avoid swap_bytes() overhead (ignoring possible assembly stuff for
now). Main point is because I wanted unpack_uint32 to implement
_dbus_verbose_bytes
(_dbus_verbose_bytes): new function
@@ -4678,14 +5420,14 @@
* dbus/dbus-message.c (_dbus_message_loader_get_is_corrupted): add
mechanism to handle a corrupt message stream
- (_dbus_message_loader_new): fix preallocation to only prealloc,
+ (_dbus_message_loader_new): fix preallocation to only prealloc,
not prelengthen
-
+
* dbus/dbus-string.c (_dbus_string_skip_blank): fix this function
(_dbus_string_test): enhance tests for copy/move and fix the
functions
- * dbus/dbus-transport-unix.c: Hold references in more places to
+ * dbus/dbus-transport-unix.c: Hold references in more places to
avoid reentrancy problems
* dbus/dbus-transport.c: ditto
@@ -4705,7 +5447,7 @@
(_dbus_auth_get_unused_bytes): append the unused bytes
to the passed in string, rather than prepend
- * dbus/dbus-transport.c (_dbus_transport_init_base): create
+ * dbus/dbus-transport.c (_dbus_transport_init_base): create
the auth conversation DBusAuth
* dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd)
@@ -4720,14 +5462,14 @@
(unix_connection_set): unref watch if we fail to add it
* dbus/dbus-connection.c (dbus_connection_unref): delete the
- transport first, so that the connection owned by the
+ transport first, so that the connection owned by the
transport will be valid as the transport finalizes.
* dbus/dbus-transport-unix.c (unix_finalize): free the write_watch
if necessary, and remove watches from the connection.
-
+
* dbus/dbus-watch.c (_dbus_watch_list_free): improve a comment
-
+
2002-12-26 Anders Carlsson <andersca@codefactory.se>
* dbus/dbus-marshal.c: (_dbus_marshal_string),
@@ -4737,15 +5479,15 @@
* dbus/dbus-marshal.h:
Add string marshal functions and have the demarshal functions
return the new position.
-
+
2002-12-25 Havoc Pennington <hp@pobox.com>
- * doc/dbus-sasl-profile.txt: docs on the authentication protocol,
+ * doc/dbus-sasl-profile.txt: docs on the authentication protocol,
it is a simple protocol that just maps directly to SASL.
* dbus/dbus-auth.h, dbus/dbus-auth.c: authentication protocol
initial implementation, not actually used yet.
-
+
* dbus/dbus-string.c (_dbus_string_find): new function
(_dbus_string_equal): new function
(_dbus_string_base64_encode): new function
@@ -4763,7 +5505,7 @@
* dbus/dbus-test.c: (main):
* dbus/dbus-test.h:
Add un-optimized marshalling/demarshalling routines.
-
+
2002-12-25 Harri Porten <porten@kde.org>
* qt/dbus-qt.h: adjusted ctor and getter to KDE/Qt conventions
@@ -4778,17 +5520,17 @@
* glib/dbus-gthread.c: fix include
- * glib/dbus-glib.h: rename DBusMessageHandler for now.
- I think glib API needs to change, though, as you don't
- want to use DBusMessageFunction, you want to use the
- DBusMessageHandler object. Probably
+ * glib/dbus-glib.h: rename DBusMessageHandler for now.
+ I think glib API needs to change, though, as you don't
+ want to use DBusMessageFunction, you want to use the
+ DBusMessageHandler object. Probably
dbus_connection_open_with_g_main_loop()
and dbus_connection_setup_g_main_loop() or something like that
- (but think of better names...) that just create a connection
+ (but think of better names...) that just create a connection
that has watch/timeout functions etc. already set up.
* dbus/dbus-connection.c
- (dbus_connection_send_message_with_reply): new function just to
+ (dbus_connection_send_message_with_reply): new function just to
show how the message handler helps us deal with replies.
* dbus/dbus-list.c (_dbus_list_remove_last): new function
@@ -4797,15 +5539,15 @@
wasn't
* dbus/dbus-hash.c: use memory pools for the hash entries
- (rebuild_table): be more paranoid about overflow, and
+ (rebuild_table): be more paranoid about overflow, and
shrink table when we can
(_dbus_hash_test): reduce number of sprintfs and write
- valid C89. Add tests for case where we grow and then
+ valid C89. Add tests for case where we grow and then
shrink the hash table.
* dbus/dbus-mempool.h, dbus/dbus-mempool.c: memory pools
- * dbus/dbus-connection.c (dbus_connection_register_handler)
+ * dbus/dbus-connection.c (dbus_connection_register_handler)
(dbus_connection_unregister_handler): new functions
* dbus/dbus-message.c (dbus_message_get_name): new
@@ -4820,13 +5562,13 @@
* glib/dbus-glib.h:
* glib/dbus-gthread.c: (dbus_gthread_init):
Don't use the gdbus prefix for public functions.
-
+
2002-12-16 Anders Carlsson <andersca@codefactory.se>
* Makefile.am:
* configure.in:
Add GLib checks and fixup .pc files
-
+
* glib/Makefile.am:
* glib/dbus-glib.h:
* glib/dbus-gmain.c: (gdbus_connection_prepare),
@@ -4837,14 +5579,14 @@
(dbus_gmutex_lock), (dbus_gmutex_unlock), (dbus_gthread_init):
* glib/test-dbus-glib.c: (message_handler), (main):
Add GLib support.
-
+
2002-12-15 Harri Porten <porten@kde.org>
- * autogen.sh: check for libtoolize before attempting to use it
-
+ * autogen.sh: check for libtoolize before attempting to use it
+
* dbus/dbus-transport-unix.c: include <sys/time.h> for timeval
struct.
-
+
* .cvsignore: ignore more stamp files
* dbus/dbus-watch.c (_dbus_watch_list_new): fixed doc error
@@ -4882,7 +5624,7 @@
* dbus/dbus-connection.c (dbus_connection_send_message): return
TRUE on success
- * dbus/dbus-transport.c: include dbus-watch.h
+ * dbus/dbus-transport.c: include dbus-watch.h
* dbus/dbus-connection.c: include dbus-message-internal.h
@@ -4896,17 +5638,17 @@
system/libc usage here, as in vsftpd, for ease of auditing (and
should also simplify portability). Haven't actually moved all the
system/libc usage into here yet.
-
+
2002-11-25 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-internals.c (_dbus_verbose): fix to not
+ * dbus/dbus-internals.c (_dbus_verbose): fix to not
always print the first verbose message.
2002-11-24 Havoc Pennington <hp@pobox.com>
- * test/echo-client.c, test/echo-server.c: cheesy test
+ * test/echo-client.c, test/echo-server.c: cheesy test
clients.
-
+
* configure.in (AC_CHECK_FUNCS): check for writev
* dbus/dbus-message.c (_dbus_message_get_network_data): new
@@ -4925,8 +5667,8 @@
public API for reporting errors
* dbus/dbus-connection.h, dbus/dbus-connection.c:
- public object representing a connection that
- sends/receives messages. (Same object used for
+ public object representing a connection that
+ sends/receives messages. (Same object used for
both client and server.)
* dbus/dbus-transport.h, dbus/dbus-transport.c:
@@ -4935,20 +5677,20 @@
2002-11-23 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-internals.h (_DBUS_INT_MAX): add _DBUS_INT_MIN
+ * dbus/dbus-internals.h (_DBUS_INT_MAX): add _DBUS_INT_MIN
_DBUS_INT_MAX
- * dbus/dbus-test.c (main): add list test, and include
+ * dbus/dbus-test.c (main): add list test, and include
dbus-test.h as intended
- * dbus/dbus-hash.c (_dbus_hash_table_remove_string)
- (_dbus_hash_table_remove_int): return value indicates
+ * dbus/dbus-hash.c (_dbus_hash_table_remove_string)
+ (_dbus_hash_table_remove_int): return value indicates
whether the entry existed to remove
- * dbus/dbus-list.c: add linked list utility class,
+ * dbus/dbus-list.c: add linked list utility class,
with docs and tests
- * dbus/dbus-hash.c: add TODO item about shrinking the hash bucket
+ * dbus/dbus-hash.c: add TODO item about shrinking the hash bucket
array sometimes.
2002-11-23 Havoc Pennington <hp@pobox.com>
@@ -4958,43 +5700,43 @@
* Doxyfile.in (JAVADOC_AUTOBRIEF): set to YES
- * dbus/dbus-message.c, dbus/dbus-hash.c:
+ * dbus/dbus-message.c, dbus/dbus-hash.c:
add some missing @brief
2002-11-23 Havoc Pennington <hp@pobox.com>
- * dbus/dbus-message.h: put semicolons after DEBUG_BEGIN_DECLS
+ * dbus/dbus-message.h: put semicolons after DEBUG_BEGIN_DECLS
to avoid confusing Doxygen
* dbus/dbus-hash.c: @} not }@
- * dbus/dbus-message.c (struct DBusMessage): split out
+ * dbus/dbus-message.c (struct DBusMessage): split out
internals docs
2002-11-23 Havoc Pennington <hp@pobox.com>
* configure.in: pile on more warning flags if using gcc
- * Doxyfile.in (EXTRACT_STATIC): set to NO, so we don't have
+ * Doxyfile.in (EXTRACT_STATIC): set to NO, so we don't have
to document static functions
- * configure.in: add summary to end of configure so it
+ * configure.in: add summary to end of configure so it
looks nice and attractive
- * dbus/dbus-hash.c: finish implementation and write unit
+ * dbus/dbus-hash.c: finish implementation and write unit
tests and docs
* configure.in: add --enable-tests to enable unit tests
- * dbus/dbus-test.c: test program to run unit tests
- for all files in dbus/*, initially runs a test for
+ * dbus/dbus-test.c: test program to run unit tests
+ for all files in dbus/*, initially runs a test for
dbus-hash.c
-
+
* dbus/dbus-internals.h: file to hold some internal utility stuff
2002-11-22 Havoc Pennington <hp@redhat.com>
- * dbus/dbus-hash.c: copy in Tcl hash table, not yet
+ * dbus/dbus-hash.c: copy in Tcl hash table, not yet
"ported" away from Tcl
* dbus/dbus-types.h: header for types such as dbus_bool_t
@@ -5003,7 +5745,7 @@
* dbus/dbus.h: fixups for doc warnings
- * Doxyfile.in (FILE_PATTERNS): we need to scan .h to pick up
+ * Doxyfile.in (FILE_PATTERNS): we need to scan .h to pick up
macros
(QUIET): make it quiet so we can see warnings
@@ -5015,8 +5757,8 @@
* configure.in: generate the Doxyfile
- * Doxyfile.in: move Doxyfile here, so we can use
- configure to generate a Doxyfile with the right
+ * Doxyfile.in: move Doxyfile here, so we can use
+ configure to generate a Doxyfile with the right
version number etc.
2002-11-22 Havoc Pennington <hp@redhat.com>
@@ -5025,16 +5767,16 @@
* Doxyfile (OUTPUT_DIRECTORY): move output to doc/api
so all docs are under doc/
- (MAN_EXTENSION): generate man pages. Use extension
- ".3dbus" which matches ".3qt" on my system,
+ (MAN_EXTENSION): generate man pages. Use extension
+ ".3dbus" which matches ".3qt" on my system,
I guess this is OK, I don't know really.
(FILE_PATTERNS): look for .c files not .h, makes sense
for plain C I think
2002-11-22 Havoc Pennington <hp@pobox.com>
- * Makefile.am (SUBDIRS): rename subdir "server" to "bus"
- because any app can be a server, and any app can be a client,
+ * Makefile.am (SUBDIRS): rename subdir "server" to "bus"
+ because any app can be a server, and any app can be a client,
the bus is a special kind of server.
Thu Nov 21 23:35:31 2002 Zack Rusin <zack@kde.org>
@@ -5042,7 +5784,7 @@ Thu Nov 21 23:35:31 2002 Zack Rusin <zack@kde.org>
* Doxyfile : adding. Still needs Makefile rules to be generated
automatically (just run "doxygen" in the toplevel dir for now to
generate docs)
-
+
* dbus/dbus-message.h : Adding sample docs (javadoc since
resembles gtk-doc a little more)
@@ -5050,17 +5792,17 @@ Thu Nov 21 23:35:31 2002 Zack Rusin <zack@kde.org>
2002-11-21 Havoc Pennington <hp@redhat.com>
- * dbus/Makefile.am (INCLUDES): define DBUS_COMPILATION
- so we can allow ourselves to include files directly,
+ * dbus/Makefile.am (INCLUDES): define DBUS_COMPILATION
+ so we can allow ourselves to include files directly,
instead of having to use dbus.h
* dbus/dbus.h: fill in
* dbus/dbus-message.h: sketch out a sample header file.
- Include griping if you include it directly instead of
+ Include griping if you include it directly instead of
via dbus.h
- * dbus/dbus-macros.h: new file with macros for extern "C",
+ * dbus/dbus-macros.h: new file with macros for extern "C",
TRUE/FALSE, NULL, etc.
* doc/file-boilerplate.c: put include guards in here
@@ -5069,7 +5811,7 @@ Thu Nov 21 23:35:31 2002 Zack Rusin <zack@kde.org>
* doc/file-boilerplate.c: include both AFL and GPL boilerplate.
- * COPYING: include the GPL as well, and license code
+ * COPYING: include the GPL as well, and license code
under both AFL and GPL.
2002-11-21 Havoc Pennington <hp@redhat.com>
@@ -5079,9 +5821,9 @@ Thu Nov 21 23:35:31 2002 Zack Rusin <zack@kde.org>
* autogen.sh (run_configure): add --no-configure option
* configure.in: remove AC_ARG_PROGRAM to make
- autoconf complain less. add AC_PREREQ.
+ autoconf complain less. add AC_PREREQ.
add AC_DEFINE third arg.
-
+
2002-11-21 Anders Carlsson <andersca@codefactory.se>
* doc/Makefile.am:
diff --git a/Doxyfile.in b/Doxyfile.in
index b2ac9587..9648449a 100644
--- a/Doxyfile.in
+++ b/Doxyfile.in
@@ -49,7 +49,7 @@ WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
-INPUT = dbus bus glib
+INPUT = dbus glib
FILE_PATTERNS = *.c *.h
RECURSIVE = YES
#EXCLUDE = test
diff --git a/HACKING b/HACKING
index 3bd2e094..1faad127 100644
--- a/HACKING
+++ b/HACKING
@@ -90,11 +90,12 @@ To make a release of D-BUS, do the following:
- once the commit succeeds, "cvs tag DBUS_X_Y_Z" where
X_Y_Z map to version X.Y.Z
- - check out the "web" module, copy the tarball to
- web/content/software/dbus/releases, "cvs add -kb dbus-x.y.z.tar.gz"
+ - scp your tarball to freedesktop.org server and copy it
+ to /home/www/twiki/Software/dbus/releases. This should
+ be possible if you're in group "dbus"
- - update web/content/software/dbus/main.in with a pointer to the
- tarball
+ - update the wiki page http://pdx.freedesktop.org/Software/dbus
+ to list your new release
- post to message-bus-list@freedesktop.org announcing the release.
diff --git a/Makefile.am b/Makefile.am
index 7384af0d..47329972 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,8 +16,11 @@ if DBUS_USE_MCS
MONO_SUBDIR=mono
endif
+if HAVE_PYTHON
+ PYTHON_SUBDIR=python
+endif
-SUBDIRS=dbus bus test doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) tools
+SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) $(PYTHON_SUBDIR) test tools
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = dbus-1.pc $(GLIB_PC)
diff --git a/acinclude.m4 b/acinclude.m4
index c80e0acf..27da0a4c 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -55,3 +55,29 @@ AC_DEFUN(PKG_CHECK_MODULES, [
])
+
+dnl a macro to check for ability to create python extensions
+dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE])
+dnl function also defines PYTHON_INCLUDES
+AC_DEFUN([AM_CHECK_PYTHON_HEADERS],
+[AC_REQUIRE([AM_PATH_PYTHON])
+AC_MSG_CHECKING(for headers required to compile python extensions)
+dnl deduce PYTHON_INCLUDES
+py_prefix=`$PYTHON -c "import sys; print sys.prefix"`
+py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"`
+PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}"
+if test "$py_prefix" != "$py_exec_prefix"; then
+ PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}"
+fi
+AC_SUBST(PYTHON_INCLUDES)
+dnl check if the headers exist:
+save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES"
+AC_TRY_CPP([#include <Python.h>],dnl
+[AC_MSG_RESULT(found)
+$1],dnl
+[AC_MSG_RESULT(not found)
+$2])
+CPPFLAGS="$save_CPPFLAGS"
+])
+
diff --git a/bus/Makefile.am b/bus/Makefile.am
index 27735077..bc728801 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -44,6 +44,8 @@ BUS_SOURCES= \
policy.h \
services.c \
services.h \
+ signals.c \
+ signals.h \
test.c \
test.h \
utils.c \
diff --git a/bus/activation.c b/bus/activation.c
index a52fa4bc..91d3c116 100644
--- a/bus/activation.c
+++ b/bus/activation.c
@@ -586,7 +586,7 @@ bus_activation_service_created (BusActivation *activation,
if (dbus_connection_get_is_connected (entry->connection))
{
- message = dbus_message_new_reply (entry->activation_message);
+ message = dbus_message_new_method_return (entry->activation_message);
if (!message)
{
BUS_SET_OOM (error);
@@ -866,7 +866,7 @@ bus_activation_activate_service (BusActivation *activation,
{
_dbus_verbose ("Service \"%s\" is already active\n", service_name);
- message = dbus_message_new_reply (activation_message);
+ message = dbus_message_new_method_return (activation_message);
if (!message)
{
diff --git a/bus/bus.c b/bus/bus.c
index a5530974..4087334e 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -28,6 +28,7 @@
#include "utils.h"
#include "policy.h"
#include "config-parser.h"
+#include "signals.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-internals.h>
@@ -44,6 +45,7 @@ struct BusContext
BusActivation *activation;
BusRegistry *registry;
BusPolicy *policy;
+ BusMatchmaker *matchmaker;
DBusUserDatabase *user_database;
BusLimits limits;
};
@@ -505,6 +507,13 @@ bus_context_new (const DBusString *config_file,
goto failed;
}
+ context->matchmaker = bus_matchmaker_new ();
+ if (context->matchmaker == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto failed;
+ }
+
context->policy = bus_config_parser_steal_policy (parser);
_dbus_assert (context->policy != NULL);
@@ -715,6 +724,12 @@ bus_context_unref (BusContext *context)
_dbus_loop_unref (context->loop);
context->loop = NULL;
}
+
+ if (context->matchmaker)
+ {
+ bus_matchmaker_unref (context->matchmaker);
+ context->matchmaker = NULL;
+ }
dbus_free (context->type);
dbus_free (context->address);
@@ -771,6 +786,12 @@ bus_context_get_activation (BusContext *context)
return context->activation;
}
+BusMatchmaker*
+bus_context_get_matchmaker (BusContext *context)
+{
+ return context->matchmaker;
+}
+
DBusLoop*
bus_context_get_loop (BusContext *context)
{
@@ -845,18 +866,33 @@ bus_context_get_max_services_per_connection (BusContext *context)
return context->limits.max_services_per_connection;
}
+int
+bus_context_get_max_match_rules_per_connection (BusContext *context)
+{
+ return context->limits.max_match_rules_per_connection;
+}
+
dbus_bool_t
bus_context_check_security_policy (BusContext *context,
DBusConnection *sender,
- DBusConnection *recipient,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
DBusMessage *message,
DBusError *error)
{
BusClientPolicy *sender_policy;
BusClientPolicy *recipient_policy;
- /* NULL sender/receiver means the bus driver */
+ /* NULL sender, proposed_recipient means the bus driver. NULL
+ * addressed_recipient means the message didn't specify an explicit
+ * target. If proposed_recipient is NULL, then addressed_recipient
+ * is also NULL but is implicitly the bus driver.
+ */
+ _dbus_assert (proposed_recipient == NULL ||
+ (dbus_message_get_destination (message) == NULL ||
+ addressed_recipient != NULL));
+
if (sender != NULL)
{
if (bus_connection_is_active (sender))
@@ -869,21 +905,23 @@ bus_context_check_security_policy (BusContext *context,
/* Policy for inactive connections is that they can only send
* the hello message to the bus driver
*/
- if (recipient == NULL &&
- dbus_message_has_name (message, DBUS_MESSAGE_HELLO))
+ if (proposed_recipient == NULL &&
+ dbus_message_is_method_call (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "Hello"))
{
_dbus_verbose ("security check allowing %s message\n",
- DBUS_MESSAGE_HELLO);
+ "Hello");
return TRUE;
}
else
{
_dbus_verbose ("security check disallowing non-%s message\n",
- DBUS_MESSAGE_HELLO);
+ "Hello");
dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
"Client tried to send a message other than %s without being registered",
- DBUS_MESSAGE_HELLO);
+ "Hello");
return FALSE;
}
@@ -895,15 +933,15 @@ bus_context_check_security_policy (BusContext *context,
_dbus_assert ((sender != NULL && sender_policy != NULL) ||
(sender == NULL && sender_policy == NULL));
- if (recipient != NULL)
+ if (proposed_recipient != NULL)
{
/* only the bus driver can send to an inactive recipient (as it
* owns no services, so other apps can't address it). Inactive
* recipients can receive any message.
*/
- if (bus_connection_is_active (recipient))
+ if (bus_connection_is_active (proposed_recipient))
{
- recipient_policy = bus_connection_get_policy (recipient);
+ recipient_policy = bus_connection_get_policy (proposed_recipient);
_dbus_assert (recipient_policy != NULL);
}
else if (sender == NULL)
@@ -920,13 +958,13 @@ bus_context_check_security_policy (BusContext *context,
else
recipient_policy = NULL;
- _dbus_assert ((recipient != NULL && recipient_policy != NULL) ||
- (recipient != NULL && sender == NULL && recipient_policy == NULL) ||
- (recipient == NULL && recipient_policy == NULL));
+ _dbus_assert ((proposed_recipient != NULL && recipient_policy != NULL) ||
+ (proposed_recipient != NULL && sender == NULL && recipient_policy == NULL) ||
+ (proposed_recipient == NULL && recipient_policy == NULL));
if (sender_policy &&
!bus_client_policy_check_can_send (sender_policy,
- context->registry, recipient,
+ context->registry, proposed_recipient,
message))
{
const char *dest = dbus_message_get_destination (message);
@@ -934,9 +972,14 @@ bus_context_check_security_policy (BusContext *context,
"A security policy in place prevents this sender "
"from sending this message to this recipient, "
"see message bus configuration file (rejected message "
- "had name \"%s\" destination \"%s\")",
- dbus_message_get_name (message),
- dest ? dest : DBUS_SERVICE_DBUS);
+ "had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")",
+ dbus_message_get_interface (message) ?
+ dbus_message_get_interface (message) : "(unset)",
+ dbus_message_get_member (message) ?
+ dbus_message_get_member (message) : "(unset)",
+ dbus_message_get_error_name (message) ?
+ dbus_message_get_error_name (message) : "(unset)",
+ dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
_dbus_verbose ("security policy disallowing message due to sender policy\n");
return FALSE;
}
@@ -944,6 +987,7 @@ bus_context_check_security_policy (BusContext *context,
if (recipient_policy &&
!bus_client_policy_check_can_receive (recipient_policy,
context->registry, sender,
+ addressed_recipient, proposed_recipient,
message))
{
const char *dest = dbus_message_get_destination (message);
@@ -951,22 +995,29 @@ bus_context_check_security_policy (BusContext *context,
"A security policy in place prevents this recipient "
"from receiving this message from this sender, "
"see message bus configuration file (rejected message "
- "had name \"%s\" destination \"%s\")",
- dbus_message_get_name (message),
- dest ? dest : DBUS_SERVICE_DBUS);
+ "had interface \"%s\" member \"%s\" error name \"%s\" destination \"%s\")",
+ dbus_message_get_interface (message) ?
+ dbus_message_get_interface (message) : "(unset)",
+ dbus_message_get_member (message) ?
+ dbus_message_get_member (message) : "(unset)",
+ dbus_message_get_error_name (message) ?
+ dbus_message_get_error_name (message) : "(unset)",
+ dest ? dest : DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
_dbus_verbose ("security policy disallowing message due to recipient policy\n");
return FALSE;
}
/* See if limits on size have been exceeded */
- if (recipient &&
- dbus_connection_get_outgoing_size (recipient) >
+ if (proposed_recipient &&
+ dbus_connection_get_outgoing_size (proposed_recipient) >
context->limits.max_outgoing_bytes)
{
const char *dest = dbus_message_get_destination (message);
dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
"The destination service \"%s\" has a full message queue",
- dest ? dest : DBUS_SERVICE_DBUS);
+ dest ? dest : (proposed_recipient ?
+ bus_connection_get_name (proposed_recipient) :
+ DBUS_SERVICE_ORG_FREEDESKTOP_DBUS));
_dbus_verbose ("security policy disallowing message due to full message queue\n");
return FALSE;
}
diff --git a/bus/bus.h b/bus/bus.h
index 8f32d7a9..5809321a 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -40,7 +40,8 @@ typedef struct BusPolicyRule BusPolicyRule;
typedef struct BusRegistry BusRegistry;
typedef struct BusService BusService;
typedef struct BusTransaction BusTransaction;
-
+typedef struct BusMatchmaker BusMatchmaker;
+typedef struct BusMatchRule BusMatchRule;
typedef struct
{
@@ -54,40 +55,44 @@ typedef struct
int max_connections_per_user; /**< Max number of connections auth'd as same user */
int max_pending_activations; /**< Max number of pending activations for the entire bus */
int max_services_per_connection; /**< Max number of owned services for a single connection */
+ int max_match_rules_per_connection; /**< Max number of match rules for a single connection */
} BusLimits;
-BusContext* bus_context_new (const DBusString *config_file,
- dbus_bool_t force_fork,
- int print_addr_fd,
- int print_pid_fd,
- DBusError *error);
-void bus_context_shutdown (BusContext *context);
-void bus_context_ref (BusContext *context);
-void bus_context_unref (BusContext *context);
-const char* bus_context_get_type (BusContext *context);
-const char* bus_context_get_address (BusContext *context);
-BusRegistry* bus_context_get_registry (BusContext *context);
-BusConnections* bus_context_get_connections (BusContext *context);
-BusActivation* bus_context_get_activation (BusContext *context);
-DBusLoop* bus_context_get_loop (BusContext *context);
-DBusUserDatabase* bus_context_get_user_database (BusContext *context);
-dbus_bool_t bus_context_allow_user (BusContext *context,
- unsigned long uid);
-BusClientPolicy* bus_context_create_client_policy (BusContext *context,
- DBusConnection *connection,
- DBusError *error);
+BusContext* bus_context_new (const DBusString *config_file,
+ dbus_bool_t force_fork,
+ int print_addr_fd,
+ int print_pid_fd,
+ DBusError *error);
+void bus_context_shutdown (BusContext *context);
+void bus_context_ref (BusContext *context);
+void bus_context_unref (BusContext *context);
+const char* bus_context_get_type (BusContext *context);
+const char* bus_context_get_address (BusContext *context);
+BusRegistry* bus_context_get_registry (BusContext *context);
+BusConnections* bus_context_get_connections (BusContext *context);
+BusActivation* bus_context_get_activation (BusContext *context);
+BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
+DBusLoop* bus_context_get_loop (BusContext *context);
+DBusUserDatabase* bus_context_get_user_database (BusContext *context);
+dbus_bool_t bus_context_allow_user (BusContext *context,
+ unsigned long uid);
+BusClientPolicy* bus_context_create_client_policy (BusContext *context,
+ DBusConnection *connection,
+ DBusError *error);
+int bus_context_get_activation_timeout (BusContext *context);
+int bus_context_get_auth_timeout (BusContext *context);
+int bus_context_get_max_completed_connections (BusContext *context);
+int bus_context_get_max_incomplete_connections (BusContext *context);
+int bus_context_get_max_connections_per_user (BusContext *context);
+int bus_context_get_max_pending_activations (BusContext *context);
+int bus_context_get_max_services_per_connection (BusContext *context);
+int bus_context_get_max_match_rules_per_connection (BusContext *context);
+dbus_bool_t bus_context_check_security_policy (BusContext *context,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
+ DBusMessage *message,
+ DBusError *error);
-int bus_context_get_activation_timeout (BusContext *context);
-int bus_context_get_auth_timeout (BusContext *context);
-int bus_context_get_max_completed_connections (BusContext *context);
-int bus_context_get_max_incomplete_connections (BusContext *context);
-int bus_context_get_max_connections_per_user (BusContext *context);
-int bus_context_get_max_pending_activations (BusContext *context);
-int bus_context_get_max_services_per_connection (BusContext *context);
-dbus_bool_t bus_context_check_security_policy (BusContext *context,
- DBusConnection *sender,
- DBusConnection *recipient,
- DBusMessage *message,
- DBusError *error);
#endif /* BUS_BUS_H */
diff --git a/bus/config-parser.c b/bus/config-parser.c
index c42278e1..7b9b962d 100644
--- a/bus/config-parser.c
+++ b/bus/config-parser.c
@@ -88,9 +88,12 @@ typedef struct
} Element;
+/**
+ * Parser for bus configuration file.
+ */
struct BusConfigParser
{
- int refcount;
+ int refcount; /**< Reference count */
DBusString basedir; /**< Directory we resolve paths relative to */
@@ -331,6 +334,8 @@ bus_config_parser_new (const DBusString *basedir,
parser->limits.max_pending_activations = 256;
parser->limits.max_services_per_connection = 256;
+
+ parser->limits.max_match_rules_per_connection = 128;
parser->refcount = 1;
@@ -808,6 +813,21 @@ start_busconfig_child (BusConfigParser *parser,
}
}
+static int
+message_type_from_string (const char *type_str)
+{
+ if (strcmp (type_str, "method_call") == 0)
+ return DBUS_MESSAGE_TYPE_METHOD_CALL;
+ if (strcmp (type_str, "method_return") == 0)
+ return DBUS_MESSAGE_TYPE_METHOD_RETURN;
+ else if (strcmp (type_str, "signal") == 0)
+ return DBUS_MESSAGE_TYPE_SIGNAL;
+ else if (strcmp (type_str, "error") == 0)
+ return DBUS_MESSAGE_TYPE_ERROR;
+ else
+ return DBUS_MESSAGE_TYPE_INVALID;
+}
+
static dbus_bool_t
append_rule_from_element (BusConfigParser *parser,
const char *element_name,
@@ -816,11 +836,20 @@ append_rule_from_element (BusConfigParser *parser,
dbus_bool_t allow,
DBusError *error)
{
- const char *send;
- const char *receive;
+ const char *send_interface;
+ const char *send_member;
+ const char *send_error;
+ const char *send_destination;
+ const char *send_path;
+ const char *send_type;
+ const char *receive_interface;
+ const char *receive_member;
+ const char *receive_error;
+ const char *receive_sender;
+ const char *receive_path;
+ const char *receive_type;
+ const char *eavesdrop;
const char *own;
- const char *send_to;
- const char *receive_from;
const char *user;
const char *group;
BusPolicyRule *rule;
@@ -829,57 +858,147 @@ append_rule_from_element (BusConfigParser *parser,
attribute_names,
attribute_values,
error,
- "send", &send,
- "receive", &receive,
+ "send_interface", &send_interface,
+ "send_member", &send_member,
+ "send_error", &send_error,
+ "send_destination", &send_destination,
+ "send_path", &send_path,
+ "send_type", &send_type,
+ "receive_interface", &receive_interface,
+ "receive_member", &receive_member,
+ "receive_error", &receive_error,
+ "receive_sender", &receive_sender,
+ "receive_path", &receive_path,
+ "receive_type", &receive_type,
+ "eavesdrop", &eavesdrop,
"own", &own,
- "send_to", &send_to,
- "receive_from", &receive_from,
"user", &user,
"group", &group,
NULL))
return FALSE;
- if (!(send || receive || own || send_to || receive_from ||
- user || group))
+ if (!(send_interface || send_member || send_error || send_destination ||
+ send_type || send_path ||
+ receive_interface || receive_member || receive_error || receive_sender ||
+ receive_type || receive_path || eavesdrop ||
+ own || user || group))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
"Element <%s> must have one or more attributes",
element_name);
return FALSE;
}
+
+ if ((send_member && (send_interface == NULL && send_path == NULL)) ||
+ (receive_member && (receive_interface == NULL && receive_path == NULL)))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "On element <%s>, if you specify a member you must specify an interface or a path. Keep in mind that not all messages have an interface field.",
+ element_name);
+ return FALSE;
+ }
- if (((send && own) ||
- (send && receive) ||
- (send && receive_from) ||
- (send && user) ||
- (send && group)) ||
-
- ((receive && own) ||
- (receive && send_to) ||
- (receive && user) ||
- (receive && group)) ||
-
- ((own && send_to) ||
- (own && receive_from) ||
- (own && user) ||
- (own && group)) ||
+ /* Allowed combinations of elements are:
+ *
+ * base, must be all send or all receive:
+ * nothing
+ * interface
+ * interface + member
+ * error
+ *
+ * base send_ can combine with send_destination, send_path, send_type
+ * base receive_ with receive_sender, receive_path, receive_type, eavesdrop
+ *
+ * user, group, own must occur alone
+ *
+ * Pretty sure the below stuff is broken, FIXME think about it more.
+ */
- ((send_to && receive_from) ||
- (send_to && user) ||
- (send_to && group)) ||
+ if (((send_interface && send_error) ||
+ (send_interface && receive_interface) ||
+ (send_interface && receive_member) ||
+ (send_interface && receive_error) ||
+ (send_interface && receive_sender) ||
+ (send_interface && eavesdrop) ||
+ (send_interface && own) ||
+ (send_interface && user) ||
+ (send_interface && group)) ||
+
+ ((send_member && send_error) ||
+ (send_member && receive_interface) ||
+ (send_member && receive_member) ||
+ (send_member && receive_error) ||
+ (send_member && receive_sender) ||
+ (send_member && eavesdrop) ||
+ (send_member && own) ||
+ (send_member && user) ||
+ (send_member && group)) ||
+
+ ((send_error && receive_interface) ||
+ (send_error && receive_member) ||
+ (send_error && receive_error) ||
+ (send_error && receive_sender) ||
+ (send_error && eavesdrop) ||
+ (send_error && own) ||
+ (send_error && user) ||
+ (send_error && group)) ||
+
+ ((send_destination && receive_interface) ||
+ (send_destination && receive_member) ||
+ (send_destination && receive_error) ||
+ (send_destination && receive_sender) ||
+ (send_destination && eavesdrop) ||
+ (send_destination && own) ||
+ (send_destination && user) ||
+ (send_destination && group)) ||
+
+ ((send_type && receive_interface) ||
+ (send_type && receive_member) ||
+ (send_type && receive_error) ||
+ (send_type && receive_sender) ||
+ (send_type && eavesdrop) ||
+ (send_type && own) ||
+ (send_type && user) ||
+ (send_type && group)) ||
+
+ ((send_path && receive_interface) ||
+ (send_path && receive_member) ||
+ (send_path && receive_error) ||
+ (send_path && receive_sender) ||
+ (send_path && eavesdrop) ||
+ (send_path && own) ||
+ (send_path && user) ||
+ (send_path && group)) ||
+
+ ((receive_interface && receive_error) ||
+ (receive_interface && own) ||
+ (receive_interface && user) ||
+ (receive_interface && group)) ||
+
+ ((receive_member && receive_error) ||
+ (receive_member && own) ||
+ (receive_member && user) ||
+ (receive_member && group)) ||
+
+ ((receive_error && own) ||
+ (receive_error && user) ||
+ (receive_error && group)) ||
- ((receive_from && user) ||
- (receive_from && group)) ||
+ ((eavesdrop && own) ||
+ (eavesdrop && user) ||
+ (eavesdrop && group)) ||
+
+ ((own && user) ||
+ (own && group)) ||
- (user && group))
+ ((user && group)))
{
dbus_set_error (error, DBUS_ERROR_FAILED,
- "Invalid combination of attributes on element <%s>, "
- "only send/send_to or receive/receive_from may be paired",
+ "Invalid combination of attributes on element <%s>",
element_name);
return FALSE;
}
-
+
rule = NULL;
/* In BusPolicyRule, NULL represents wildcard.
@@ -887,41 +1006,122 @@ append_rule_from_element (BusConfigParser *parser,
*/
#define IS_WILDCARD(str) ((str) && ((str)[0]) == '*' && ((str)[1]) == '\0')
- if (send || send_to)
+ if (send_interface || send_member || send_error || send_destination ||
+ send_path || send_type)
{
+ int message_type;
+
+ if (IS_WILDCARD (send_interface))
+ send_interface = NULL;
+ if (IS_WILDCARD (send_member))
+ send_member = NULL;
+ if (IS_WILDCARD (send_error))
+ send_error = NULL;
+ if (IS_WILDCARD (send_destination))
+ send_destination = NULL;
+ if (IS_WILDCARD (send_path))
+ send_path = NULL;
+ if (IS_WILDCARD (send_type))
+ send_type = NULL;
+
+ message_type = DBUS_MESSAGE_TYPE_INVALID;
+ if (send_type != NULL)
+ {
+ message_type = message_type_from_string (send_type);
+ if (message_type == DBUS_MESSAGE_TYPE_INVALID)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Bad message type \"%s\"",
+ send_type);
+ return FALSE;
+ }
+ }
+
rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
if (rule == NULL)
goto nomem;
-
- if (IS_WILDCARD (send))
- send = NULL;
- if (IS_WILDCARD (send_to))
- send_to = NULL;
- rule->d.send.message_name = _dbus_strdup (send);
- rule->d.send.destination = _dbus_strdup (send_to);
- if (send && rule->d.send.message_name == NULL)
+ rule->d.send.message_type = message_type;
+ rule->d.send.path = _dbus_strdup (send_path);
+ rule->d.send.interface = _dbus_strdup (send_interface);
+ rule->d.send.member = _dbus_strdup (send_member);
+ rule->d.send.error = _dbus_strdup (send_error);
+ rule->d.send.destination = _dbus_strdup (send_destination);
+ if (send_path && rule->d.send.path == NULL)
+ goto nomem;
+ if (send_interface && rule->d.send.interface == NULL)
+ goto nomem;
+ if (send_member && rule->d.send.member == NULL)
+ goto nomem;
+ if (send_error && rule->d.send.error == NULL)
goto nomem;
- if (send_to && rule->d.send.destination == NULL)
+ if (send_destination && rule->d.send.destination == NULL)
goto nomem;
}
- else if (receive || receive_from)
+ else if (receive_interface || receive_member || receive_error || receive_sender ||
+ receive_path || receive_type || eavesdrop)
{
+ int message_type;
+
+ if (IS_WILDCARD (receive_interface))
+ receive_interface = NULL;
+ if (IS_WILDCARD (receive_member))
+ receive_member = NULL;
+ if (IS_WILDCARD (receive_error))
+ receive_error = NULL;
+ if (IS_WILDCARD (receive_sender))
+ receive_sender = NULL;
+ if (IS_WILDCARD (receive_path))
+ receive_path = NULL;
+ if (IS_WILDCARD (receive_type))
+ receive_type = NULL;
+
+ message_type = DBUS_MESSAGE_TYPE_INVALID;
+ if (receive_type != NULL)
+ {
+ message_type = message_type_from_string (receive_type);
+ if (message_type == DBUS_MESSAGE_TYPE_INVALID)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Bad message type \"%s\"",
+ receive_type);
+ return FALSE;
+ }
+ }
+
+
+ if (eavesdrop &&
+ !(strcmp (eavesdrop, "true") == 0 ||
+ strcmp (eavesdrop, "false") == 0))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Bad value \"%s\" for eavesdrop attribute, must be true or false",
+ eavesdrop);
+ return FALSE;
+ }
+
rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
if (rule == NULL)
goto nomem;
- if (IS_WILDCARD (receive))
- receive = NULL;
-
- if (IS_WILDCARD (receive_from))
- receive_from = NULL;
+ if (eavesdrop)
+ rule->d.receive.eavesdrop = (strcmp (eavesdrop, "true") == 0);
- rule->d.receive.message_name = _dbus_strdup (receive);
- rule->d.receive.origin = _dbus_strdup (receive_from);
- if (receive && rule->d.receive.message_name == NULL)
+ rule->d.receive.message_type = message_type;
+ rule->d.receive.path = _dbus_strdup (receive_path);
+ rule->d.receive.interface = _dbus_strdup (receive_interface);
+ rule->d.receive.member = _dbus_strdup (receive_member);
+ rule->d.receive.error = _dbus_strdup (receive_error);
+ rule->d.receive.origin = _dbus_strdup (receive_sender);
+ if (receive_path && rule->d.receive.path == NULL)
+ goto nomem;
+ if (receive_interface && rule->d.receive.interface == NULL)
+ goto nomem;
+ if (receive_member && rule->d.receive.member == NULL)
+ goto nomem;
+ if (receive_error && rule->d.receive.error == NULL)
goto nomem;
- if (receive_from && rule->d.receive.origin == NULL)
+ if (receive_sender && rule->d.receive.origin == NULL)
goto nomem;
}
else if (own)
diff --git a/bus/connection.c b/bus/connection.c
index 5121658d..a824576c 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -25,6 +25,7 @@
#include "policy.h"
#include "services.h"
#include "utils.h"
+#include "signals.h"
#include <dbus/dbus-list.h>
#include <dbus/dbus-hash.h>
#include <dbus/dbus-timeout.h>
@@ -41,6 +42,7 @@ struct BusConnections
BusContext *context;
DBusHashTable *completed_by_user; /**< Number of completed connections for each UID */
DBusTimeout *expire_timeout; /**< Timeout for expiring incomplete connections. */
+ int stamp; /**< Incrementing number */
};
static dbus_int32_t connection_data_slot = -1;
@@ -52,6 +54,8 @@ typedef struct
DBusConnection *connection;
DBusList *services_owned;
int n_services_owned;
+ DBusList *match_rules;
+ int n_match_rules;
char *name;
DBusList *transaction_messages; /**< Stuff we need to send as part of a transaction */
DBusMessage *oom_message;
@@ -60,6 +64,7 @@ typedef struct
long connection_tv_sec; /**< Time when we connected (seconds component) */
long connection_tv_usec; /**< Time when we connected (microsec component) */
+ int stamp; /**< connections->stamp last time we were traversed */
} BusConnectionData;
static dbus_bool_t expire_incomplete_timeout (void *data);
@@ -140,12 +145,20 @@ bus_connection_disconnected (DBusConnection *connection)
{
BusConnectionData *d;
BusService *service;
-
+ BusMatchmaker *matchmaker;
+
d = BUS_CONNECTION_DATA (connection);
_dbus_assert (d != NULL);
_dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
d->name ? d->name : "(inactive)");
+
+ /* Delete our match rules */
+ if (d->n_match_rules > 0)
+ {
+ matchmaker = bus_context_get_matchmaker (d->connections->context);
+ bus_matchmaker_disconnected (matchmaker, connection);
+ }
/* Drop any service ownership. FIXME Unfortunately, this requires
* memory allocation and there doesn't seem to be a good way to
@@ -881,6 +894,40 @@ bus_connections_get_context (BusConnections *connections)
return connections->context;
}
+/*
+ * This is used to avoid covering the same connection twice when
+ * traversing connections. Note that it assumes we will
+ * bus_connection_mark_stamp() each connection at least once per
+ * INT_MAX increments of the global stamp, or wraparound would break
+ * things.
+ */
+void
+bus_connections_increment_stamp (BusConnections *connections)
+{
+ connections->stamp += 1;
+}
+
+/* Mark connection with current stamp, return TRUE if it
+ * didn't already have that stamp
+ */
+dbus_bool_t
+bus_connection_mark_stamp (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+
+ _dbus_assert (d != NULL);
+
+ if (d->stamp == d->connections->stamp)
+ return FALSE;
+ else
+ {
+ d->stamp = d->connections->stamp;
+ return TRUE;
+ }
+}
+
BusContext*
bus_connection_get_context (DBusConnection *connection)
{
@@ -929,6 +976,18 @@ bus_connection_get_activation (DBusConnection *connection)
return bus_context_get_activation (d->connections->context);
}
+BusMatchmaker*
+bus_connection_get_matchmaker (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+
+ _dbus_assert (d != NULL);
+
+ return bus_context_get_matchmaker (d->connections->context);
+}
+
/**
* Checks whether the connection is registered with the message bus.
*
@@ -963,19 +1022,19 @@ bus_connection_preallocate_oom_error (DBusConnection *connection)
if (preallocated == NULL)
return FALSE;
- /* d->name may be NULL, but that is OK */
- message = dbus_message_new (DBUS_ERROR_NO_MEMORY,
- d->name);
+ message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR);
+
if (message == NULL)
{
dbus_connection_free_preallocated_send (connection, preallocated);
return FALSE;
}
- dbus_message_set_is_error (message, TRUE);
-
- if (!dbus_message_set_sender (message,
- DBUS_SERVICE_DBUS))
+ /* d->name may be NULL, but that is OK */
+ if (!dbus_message_set_error_name (message, DBUS_ERROR_NO_MEMORY) ||
+ !dbus_message_set_destination (message, d->name) ||
+ !dbus_message_set_sender (message,
+ DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
dbus_connection_free_preallocated_send (connection, preallocated);
dbus_message_unref (message);
@@ -1025,6 +1084,62 @@ bus_connection_send_oom_error (DBusConnection *connection,
}
void
+bus_connection_add_match_rule_link (DBusConnection *connection,
+ DBusList *link)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+
+ _dbus_list_append_link (&d->match_rules, link);
+
+ d->n_match_rules += 1;
+}
+
+dbus_bool_t
+bus_connection_add_match_rule (DBusConnection *connection,
+ BusMatchRule *rule)
+{
+ DBusList *link;
+
+ link = _dbus_list_alloc_link (rule);
+
+ if (link == NULL)
+ return FALSE;
+
+ bus_connection_add_match_rule_link (connection, link);
+
+ return TRUE;
+}
+
+void
+bus_connection_remove_match_rule (DBusConnection *connection,
+ BusMatchRule *rule)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+
+ _dbus_list_remove_last (&d->match_rules, rule);
+
+ d->n_match_rules -= 1;
+ _dbus_assert (d->n_match_rules >= 0);
+}
+
+int
+bus_connection_get_n_match_rules (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+
+ return d->n_match_rules;
+}
+
+void
bus_connection_add_owned_service_link (DBusConnection *connection,
DBusList *link)
{
@@ -1092,6 +1207,8 @@ bus_connection_complete (DBusConnection *connection,
_dbus_assert (d != NULL);
_dbus_assert (d->name == NULL);
_dbus_assert (d->policy == NULL);
+
+ _dbus_assert (!bus_connection_is_active (connection));
if (!_dbus_string_copy_data (name, &d->name))
{
@@ -1147,6 +1264,8 @@ bus_connection_complete (DBusConnection *connection,
/* See if we can remove the timeout */
bus_connections_expire_incomplete (d->connections);
+
+ _dbus_assert (bus_connection_is_active (connection));
return TRUE;
}
@@ -1312,17 +1431,22 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
* to check security policy since it was not done in
* dispatch.c
*/
- _dbus_verbose ("Sending %s from driver\n",
- dbus_message_get_name (message));
-
- if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+ _dbus_verbose ("Sending %s %s %s from driver\n",
+ dbus_message_get_interface (message) ?
+ dbus_message_get_interface (message) : "(no interface)",
+ dbus_message_get_member (message) ?
+ dbus_message_get_member (message) : "(no member)",
+ dbus_message_get_error_name (message) ?
+ dbus_message_get_error_name (message) : "(no error name)");
+
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
return FALSE;
/* If security policy doesn't allow the message, we silently
* eat it; the driver doesn't care about getting a reply.
*/
if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
- NULL, connection, message, NULL))
+ NULL, connection, connection, message, NULL))
return TRUE;
return bus_transaction_send (transaction, connection, message);
@@ -1337,11 +1461,16 @@ bus_transaction_send (BusTransaction *transaction,
BusConnectionData *d;
DBusList *link;
- _dbus_verbose (" trying to add %s %s to transaction%s\n",
- dbus_message_get_is_error (message) ? "error" :
+ _dbus_verbose (" trying to add %s interface=%s member=%s error=%s to transaction%s\n",
+ dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR ? "error" :
dbus_message_get_reply_serial (message) != 0 ? "reply" :
"message",
- dbus_message_get_name (message),
+ dbus_message_get_interface (message) ?
+ dbus_message_get_interface (message) : "(unset)",
+ dbus_message_get_member (message) ?
+ dbus_message_get_member (message) : "(unset)",
+ dbus_message_get_error_name (message) ?
+ dbus_message_get_error_name (message) : "(unset)",
dbus_connection_get_is_connected (connection) ?
"" : " (disconnected)");
@@ -1550,13 +1679,13 @@ bus_transaction_send_error_reply (BusTransaction *transaction,
_dbus_assert (error != NULL);
_DBUS_ASSERT_ERROR_IS_SET (error);
-
+
_dbus_verbose ("Sending error reply %s \"%s\"\n",
error->name, error->message);
- reply = dbus_message_new_error_reply (in_reply_to,
- error->name,
- error->message);
+ reply = dbus_message_new_error (in_reply_to,
+ error->name,
+ error->message);
if (reply == NULL)
return FALSE;
diff --git a/bus/connection.h b/bus/connection.h
index 92c93267..d9fd727e 100644
--- a/bus/connection.h
+++ b/bus/connection.h
@@ -44,16 +44,18 @@ void bus_connections_foreach_active (BusConnections
BusConnectionForeachFunction function,
void *data);
BusContext* bus_connections_get_context (BusConnections *connections);
+void bus_connections_increment_stamp (BusConnections *connections);
BusContext* bus_connection_get_context (DBusConnection *connection);
BusConnections* bus_connection_get_connections (DBusConnection *connection);
BusRegistry* bus_connection_get_registry (DBusConnection *connection);
BusActivation* bus_connection_get_activation (DBusConnection *connection);
+BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection);
dbus_bool_t bus_connections_check_limits (BusConnections *connections,
DBusConnection *requesting_completion,
DBusError *error);
void bus_connections_expire_incomplete (BusConnections *connections);
-
+dbus_bool_t bus_connection_mark_stamp (DBusConnection *connection);
dbus_bool_t bus_connection_is_active (DBusConnection *connection);
const char *bus_connection_get_name (DBusConnection *connection);
@@ -62,6 +64,15 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
void bus_connection_send_oom_error (DBusConnection *connection,
DBusMessage *in_reply_to);
+/* called by signals.c */
+dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
+ BusMatchRule *rule);
+void bus_connection_add_match_rule_link (DBusConnection *connection,
+ DBusList *link);
+void bus_connection_remove_match_rule (DBusConnection *connection,
+ BusMatchRule *rule);
+int bus_connection_get_n_match_rules (DBusConnection *connection);
+
/* called by services.c */
dbus_bool_t bus_connection_add_owned_service (DBusConnection *connection,
diff --git a/bus/dbus-daemon-1.1.in b/bus/dbus-daemon-1.1.in
index 73a88c90..b272a62e 100644
--- a/bus/dbus-daemon-1.1.in
+++ b/bus/dbus-daemon-1.1.in
@@ -328,16 +328,33 @@ in the config file.
.TP
.I "<deny>"
+.I "<allow>"
+
+.PP
+A <deny> element appears below a <policy> element and prohibits some
+action. The <allow> element makes an exception to previous <deny>
+statements, and works just like <deny> but with the inverse meaning.
.PP
-A <deny> element appears below a <policy> element and prohibits
-some action. The possible attributes of a <deny> element are:
+The possible attributes of these elements are:
.nf
- send="messagename"
- receive="messagename"
+ send_interface="interface_name"
+ send_member="method_or_signal_name"
+ send_error="error_name"
+ send_destination="service_name"
+ send_type="method_call" | "method_return" | "signal" | "error"
+ send_path="/path/name"
+
+ receive_interface="interface_name"
+ receive_member="method_or_signal_name"
+ receive_error="error_name"
+ receive_sender="service_name"
+ receive_type="method_call" | "method_return" | "signal" | "error"
+ receive_path="/path/name"
+
+ eavesdrop="true" | "false"
+
own="servicename"
- send_to="servicename"
- receive_from="servicename"
user="username"
group="groupname"
.fi
@@ -345,11 +362,11 @@ some action. The possible attributes of a <deny> element are:
.PP
Examples:
.nf
- <deny send="org.freedesktop.System.Reboot"/>
- <deny receive="org.freedesktop.System.Reboot"/>
+ <deny send_interface="org.freedesktop.System" send_member="Reboot"/>
+ <deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
<deny own="org.freedesktop.System"/>
- <deny send_to="org.freedesktop.System"/>
- <deny receive_from="org.freedesktop.System"/>
+ <deny send_destination="org.freedesktop.System"/>
+ <deny receive_sender="org.freedesktop.System"/>
<deny user="john"/>
<deny group="enemies"/>
.fi
@@ -360,18 +377,38 @@ particular action. If it matches, the action is denied (unless later
rules in the config file allow it).
.PP
-send_to and receive_from mean that messages may not be sent to or
-received from the *owner* of the given service, not that they may not
-be sent *to that service name*. That is, if a connection owns services
-A, B, C, and sending to A is denied, sending to B or C will not work
-either.
+send_destination and receive_sender rules mean that messages may not be
+sent to or received from the *owner* of the given service, not that
+they may not be sent *to that service name*. That is, if a connection
+owns services A, B, C, and sending to A is denied, sending to B or C
+will not work either.
+
+.PP
+The other send_* and receive_* attributes are purely textual/by-value
+matches against the given field in the message header.
+
+.PP
+"Eavesdropping" occurs when an application receives a message that
+was explicitly addressed to a service the application does not own.
+Eavesdropping thus only applies to messages that are addressed to
+services (i.e. it does not apply to signals).
+
+.PP
+For <allow>, eavesdrop="true" indicates that the rule matches even
+when eavesdropping. eavesdrop="false" is the default and means that
+the rule only allows messages to go to their specified recipient.
+For <deny>, eavesdrop="true" indicates that the rule matches
+only when eavesdropping. eavesdrop="false" is the default for <deny>
+also, but here it means that the rule applies always, even when
+not eavesdropping. The eavesdrop attribute can only be combined with
+receive rules (with receive_* attributes).
.PP
user and group denials mean that the given user or group may
not connect to the message bus.
.PP
-For "servicename" or "messagename" or "username" or "groupname"
+For "service_name", "username", "groupname", etc.
the character "*" can be substituted, meaning "any." Complex globs
like "foo.bar.*" aren't allowed for now because they'd be work to
implement and maybe encourage sloppy security anyway.
@@ -382,18 +419,21 @@ for a user or group; user/group denials can only be inside
context="default" or context="mandatory" policies.
.PP
-A single <deny> rule may specify both send and send_to, OR both
-receive and receive_from. In this case, the denial applies only if
-both attributes match the message being denied.
-e.g. <deny send="foo.bar" send_to="foo.blah"/> would deny
-messages of the given name AND to the given service.
+A single <deny> rule may specify combinations of attributes such as
+send_service and send_interface and send_type. In this case, the
+denial applies only if both attributes match the message being denied.
+e.g. <deny send_interface="foo.bar" send_service="foo.blah"/> would
+deny messages of the given interface AND to the given service.
+To get an OR effect you specify multiple <deny> rules.
-.TP
-.I "<allow>"
+.PP
+You can't include both send_ and receive_ attributes on the same
+rule, since "whether the message can be sent" and "whether it can be
+received" are evaluated separately.
.PP
-Makes an exception to previous <deny> statements. Works
-just like <deny> but with the inverse meaning.
+Be careful with send_interface/receive_interface, because the
+interface field in messages is optional.
.SH AUTHOR
See http://www.freedesktop.org/software/dbus/doc/AUTHORS
diff --git a/bus/desktop-file.c b/bus/desktop-file.c
index 08af768e..dd621214 100644
--- a/bus/desktop-file.c
+++ b/bus/desktop-file.c
@@ -48,15 +48,19 @@ struct BusDesktopFile
int n_allocated_sections;
};
+/**
+ * Parser for service files.
+ */
typedef struct
{
- DBusString data;
+ DBusString data; /**< The data from the file */
- BusDesktopFile *desktop_file;
- int current_section;
+ BusDesktopFile *desktop_file; /**< The resulting object */
+ int current_section; /**< The current section being parsed */
- int pos, len;
- int line_num;
+ int pos; /**< Current position */
+ int len; /**< Length */
+ int line_num; /**< Current line number */
} BusDesktopFileParser;
diff --git a/bus/dispatch.c b/bus/dispatch.c
index d43e8121..606c68ef 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -28,38 +28,33 @@
#include "services.h"
#include "utils.h"
#include "bus.h"
+#include "signals.h"
#include "test.h"
#include <dbus/dbus-internals.h>
#include <string.h>
-static dbus_int32_t message_handler_slot = -1;
-
-typedef struct
-{
- BusContext *context;
- DBusConnection *sender;
- DBusMessage *message;
- BusTransaction *transaction;
- DBusError *error;
-} SendMessageData;
-
static dbus_bool_t
-send_one_message (DBusConnection *connection, void *data)
+send_one_message (DBusConnection *connection,
+ BusContext *context,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusMessage *message,
+ BusTransaction *transaction,
+ DBusError *error)
{
- SendMessageData *d = data;
-
- if (!bus_context_check_security_policy (d->context,
- d->sender,
+ if (!bus_context_check_security_policy (context,
+ sender,
+ addressed_recipient,
connection,
- d->message,
+ message,
NULL))
return TRUE; /* silently don't send it */
- if (!bus_transaction_send (d->transaction,
+ if (!bus_transaction_send (transaction,
connection,
- d->message))
+ message))
{
- BUS_SET_OOM (d->error);
+ BUS_SET_OOM (error);
return FALSE;
}
@@ -67,30 +62,60 @@ send_one_message (DBusConnection *connection, void *data)
}
dbus_bool_t
-bus_dispatch_broadcast_message (BusTransaction *transaction,
- DBusConnection *sender,
- DBusMessage *message,
- DBusError *error)
+bus_dispatch_matches (BusTransaction *transaction,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusMessage *message,
+ DBusError *error)
{
DBusError tmp_error;
- SendMessageData d;
BusConnections *connections;
+ DBusList *recipients;
+ BusMatchmaker *matchmaker;
+ DBusList *link;
+ BusContext *context;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
-
+
+ /* sender and recipient can both be NULL for the bus driver,
+ * or for signals with no particular recipient
+ */
+
+ _dbus_assert (sender == NULL || bus_connection_is_active (sender));
_dbus_assert (dbus_message_get_sender (message) != NULL);
connections = bus_transaction_get_connections (transaction);
dbus_error_init (&tmp_error);
- d.sender = sender;
- d.context = bus_transaction_get_context (transaction);
- d.message = message;
- d.transaction = transaction;
- d.error = &tmp_error;
-
- bus_connections_foreach_active (connections, send_one_message, &d);
+ context = bus_transaction_get_context (transaction);
+ matchmaker = bus_context_get_matchmaker (context);
+ recipients = NULL;
+ if (!bus_matchmaker_get_recipients (matchmaker,
+ bus_context_get_connections (context),
+ sender, addressed_recipient, message,
+ &recipients))
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ link = _dbus_list_get_first_link (&recipients);
+ while (link != NULL)
+ {
+ DBusConnection *dest;
+
+ dest = link->data;
+
+ if (!send_one_message (dest, context, sender, addressed_recipient,
+ message, transaction, &tmp_error))
+ break;
+
+ link = _dbus_list_get_next_link (&recipients, link);
+ }
+
+ _dbus_list_clear (&recipients);
+
if (dbus_error_is_set (&tmp_error))
{
dbus_move_error (&tmp_error, error);
@@ -100,16 +125,21 @@ bus_dispatch_broadcast_message (BusTransaction *transaction,
return TRUE;
}
-static void
+static DBusHandlerResult
bus_dispatch (DBusConnection *connection,
DBusMessage *message)
{
- const char *sender, *service_name, *message_name;
+ const char *sender, *service_name;
DBusError error;
BusTransaction *transaction;
BusContext *context;
+ DBusHandlerResult result;
+ DBusConnection *addressed_recipient;
+
+ result = DBUS_HANDLER_RESULT_HANDLED;
transaction = NULL;
+ addressed_recipient = NULL;
dbus_error_init (&error);
context = bus_connection_get_context (connection);
@@ -123,32 +153,50 @@ bus_dispatch (DBusConnection *connection,
/* Ref connection in case we disconnect it at some point in here */
dbus_connection_ref (connection);
-
+
service_name = dbus_message_get_destination (message);
- message_name = dbus_message_get_name (message);
-
- _dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */
- _dbus_verbose ("DISPATCH: %s to %s\n",
- message_name, service_name ? service_name : "peer");
-
- /* If service_name is NULL, this is a message to the bus daemon, not
- * intended to actually go "on the bus"; e.g. a peer-to-peer
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ {
+ const char *interface_name, *member_name, *error_name;
+
+ interface_name = dbus_message_get_interface (message);
+ member_name = dbus_message_get_member (message);
+ error_name = dbus_message_get_error_name (message);
+
+ _dbus_verbose ("DISPATCH: %s %s %s to %s\n",
+ interface_name ? interface_name : "(no interface)",
+ member_name ? member_name : "(no member)",
+ error_name ? error_name : "(no error name)",
+ service_name ? service_name : "peer");
+ }
+#endif /* DBUS_ENABLE_VERBOSE_MODE */
+
+ /* If service_name is NULL, if it's a signal we send it to all
+ * connections with a match rule. If it's not a signal, it goes to
+ * the bus daemon but doesn't go "on the bus"; e.g. a peer-to-peer
* ping. Handle these immediately, especially disconnection
* messages. There are no security policy checks on these.
*/
if (service_name == NULL)
- {
- if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0)
- bus_connection_disconnected (connection);
+ {
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+ "Disconnected"))
+ {
+ bus_connection_disconnected (connection);
+ goto out;
+ }
- /* DBusConnection also handles some of these automatically, we leave
- * it to do so.
- */
- goto out;
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ {
+ /* DBusConnection also handles some of these automatically, we leave
+ * it to do so.
+ */
+ result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ goto out;
+ }
}
-
- _dbus_assert (service_name != NULL); /* this message is intended for bus routing */
/* Create our transaction */
transaction = bus_transaction_new (context);
@@ -177,17 +225,18 @@ bus_dispatch (DBusConnection *connection,
*/
service_name = dbus_message_get_destination (message);
}
-
- if (strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
+
+ if (service_name &&
+ strcmp (service_name, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) == 0) /* to bus driver */
{
if (!bus_context_check_security_policy (context,
- connection, NULL, message, &error))
+ connection, NULL, NULL, message, &error))
{
_dbus_verbose ("Security policy rejected message\n");
goto out;
}
- _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS);
+ _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
if (!bus_driver_handle_message (connection, transaction, message, &error))
goto out;
}
@@ -195,22 +244,16 @@ bus_dispatch (DBusConnection *connection,
{
_dbus_verbose ("Received message from non-registered client. Disconnecting.\n");
dbus_connection_disconnect (connection);
+ goto out;
}
- /* FIXME what if we un-special-case this service and just have a flag
- * on services that all service owners will get messages to it, not just
- * the primary owner.
- */
- else if (strcmp (service_name, DBUS_SERVICE_BROADCAST) == 0) /* spam! */
- {
- if (!bus_dispatch_broadcast_message (transaction, connection, message, &error))
- goto out;
- }
- else /* route to named service */
+ else if (service_name != NULL) /* route to named service */
{
DBusString service_string;
BusService *service;
BusRegistry *registry;
+ _dbus_assert (service_name != NULL);
+
registry = bus_connection_get_registry (connection);
_dbus_string_init_const (&service_string, service_name);
@@ -225,24 +268,30 @@ bus_dispatch (DBusConnection *connection,
goto out;
}
else
- {
- DBusConnection *recipient;
-
- recipient = bus_service_get_primary_owner (service);
- _dbus_assert (recipient != NULL);
+ {
+ addressed_recipient = bus_service_get_primary_owner (service);
+ _dbus_assert (addressed_recipient != NULL);
if (!bus_context_check_security_policy (context,
- connection, recipient, message, &error))
+ connection, addressed_recipient,
+ addressed_recipient,
+ message, &error))
goto out;
/* Dispatch the message */
- if (!bus_transaction_send (transaction, recipient, message))
+ if (!bus_transaction_send (transaction, addressed_recipient, message))
{
BUS_SET_OOM (&error);
goto out;
}
}
}
+
+ /* Now match the messages against any match rules, which will send
+ * out signals and such. addressed_recipient may == NULL.
+ */
+ if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error))
+ goto out;
out:
if (dbus_error_is_set (&error))
@@ -295,66 +344,26 @@ bus_dispatch (DBusConnection *connection,
}
dbus_connection_unref (connection);
-}
-static DBusHandlerResult
-bus_dispatch_message_handler (DBusMessageHandler *handler,
- DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
-{
- bus_dispatch (connection, message);
-
- return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ return result;
}
-static void
-free_message_handler (void *data)
+static DBusHandlerResult
+bus_dispatch_message_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
{
- DBusMessageHandler *handler = data;
-
- _dbus_assert (message_handler_slot >= 0);
-
- dbus_message_handler_unref (handler);
- dbus_connection_free_data_slot (&message_handler_slot);
+ return bus_dispatch (connection, message);
}
dbus_bool_t
bus_dispatch_add_connection (DBusConnection *connection)
-{
- DBusMessageHandler *handler;
-
- if (!dbus_connection_allocate_data_slot (&message_handler_slot))
+{
+ if (!dbus_connection_add_filter (connection,
+ bus_dispatch_message_filter,
+ NULL, NULL))
return FALSE;
- handler = dbus_message_handler_new (bus_dispatch_message_handler, NULL, NULL);
- if (handler == NULL)
- {
- dbus_connection_free_data_slot (&message_handler_slot);
- return FALSE;
- }
-
- if (!dbus_connection_add_filter (connection, handler))
- {
- dbus_message_handler_unref (handler);
- dbus_connection_free_data_slot (&message_handler_slot);
-
- return FALSE;
- }
-
- _dbus_assert (message_handler_slot >= 0);
-
- if (!dbus_connection_set_data (connection,
- message_handler_slot,
- handler,
- free_message_handler))
- {
- dbus_message_handler_unref (handler);
- dbus_connection_free_data_slot (&message_handler_slot);
-
- return FALSE;
- }
-
return TRUE;
}
@@ -364,9 +373,9 @@ bus_dispatch_remove_connection (DBusConnection *connection)
/* Here we tell the bus driver that we want to get off. */
bus_driver_remove_connection (connection);
- dbus_connection_set_data (connection,
- message_handler_slot,
- NULL, NULL);
+ dbus_connection_remove_filter (connection,
+ bus_dispatch_message_filter,
+ NULL);
}
#ifdef DBUS_BUILD_TESTS
@@ -401,6 +410,42 @@ pop_message_waiting_for_memory (DBusConnection *connection)
return dbus_connection_pop_message (connection);
}
+static void
+warn_unexpected_real (DBusConnection *connection,
+ DBusMessage *message,
+ const char *expected,
+ const char *function,
+ int line)
+{
+ _dbus_warn ("%s:%d received message interface \"%s\" member \"%s\" error name \"%s\" on %p, expecting %s\n",
+ function, line,
+ dbus_message_get_interface (message) ?
+ dbus_message_get_interface (message) : "(unset)",
+ dbus_message_get_member (message) ?
+ dbus_message_get_member (message) : "(unset)",
+ dbus_message_get_error_name (message) ?
+ dbus_message_get_error_name (message) : "(unset)",
+ connection,
+ expected);
+}
+
+#define warn_unexpected(connection, message, expected) \
+ warn_unexpected_real (connection, message, expected, _DBUS_FUNCTION_NAME, __LINE__)
+
+static void
+verbose_message_received (DBusConnection *connection,
+ DBusMessage *message)
+{
+ _dbus_verbose ("Received message interface \"%s\" member \"%s\" error name \"%s\" on %p\n",
+ dbus_message_get_interface (message) ?
+ dbus_message_get_interface (message) : "(unset)",
+ dbus_message_get_member (message) ?
+ dbus_message_get_member (message) : "(unset)",
+ dbus_message_get_error_name (message) ?
+ dbus_message_get_error_name (message) : "(unset)",
+ connection);
+}
+
typedef struct
{
const char *expected_service_name;
@@ -424,14 +469,15 @@ check_service_deleted_foreach (DBusConnection *connection,
if (message == NULL)
{
_dbus_warn ("Did not receive a message on %p, expecting %s\n",
- connection, DBUS_MESSAGE_SERVICE_DELETED);
+ connection, "ServiceDeleted");
goto out;
}
- else if (!dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED))
+ else if (!dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceDeleted"))
{
- _dbus_warn ("Received message %s on %p, expecting %s\n",
- dbus_message_get_name (message),
- connection, DBUS_MESSAGE_SERVICE_DELETED);
+ warn_unexpected (connection, message, "ServiceDeleted");
+
goto out;
}
else
@@ -554,8 +600,8 @@ check_no_messages_foreach (DBusConnection *connection,
message = pop_message_waiting_for_memory (connection);
if (message != NULL)
{
- _dbus_warn ("Received message %s on %p, expecting no messages\n",
- dbus_message_get_name (message), connection);
+ warn_unexpected (connection, message, "no messages");
+
d->failed = TRUE;
}
@@ -591,14 +637,14 @@ check_service_created_foreach (DBusConnection *connection,
if (message == NULL)
{
_dbus_warn ("Did not receive a message on %p, expecting %s\n",
- connection, DBUS_MESSAGE_SERVICE_CREATED);
+ connection, "ServiceCreated");
goto out;
}
- else if (!dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED))
+ else if (!dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceCreated"))
{
- _dbus_warn ("Received message %s on %p, expecting %s\n",
- dbus_message_get_name (message),
- connection, DBUS_MESSAGE_SERVICE_CREATED);
+ warn_unexpected (connection, message, "ServiceCreated");
goto out;
}
else
@@ -662,7 +708,7 @@ check_hello_message (BusContext *context,
DBusConnection *connection)
{
DBusMessage *message;
- dbus_int32_t serial;
+ dbus_uint32_t serial;
dbus_bool_t retval;
DBusError error;
char *name;
@@ -673,9 +719,13 @@ check_hello_message (BusContext *context,
name = NULL;
acquired = NULL;
message = NULL;
+
+ _dbus_verbose ("check_hello_message for %p\n", connection);
- 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 == NULL)
return TRUE;
@@ -710,14 +760,13 @@ check_hello_message (BusContext *context,
if (message == NULL)
{
_dbus_warn ("Did not receive a reply to %s %d on %p\n",
- DBUS_MESSAGE_HELLO, serial, connection);
+ "Hello", serial, connection);
goto out;
}
- _dbus_verbose ("Received %s on %p\n",
- dbus_message_get_name (message), connection);
+ verbose_message_received (connection, message);
- if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+ if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
_dbus_warn ("Message has wrong sender %s\n",
dbus_message_get_sender (message) ?
@@ -725,17 +774,17 @@ check_hello_message (BusContext *context,
goto out;
}
- if (dbus_message_get_is_error (message))
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
{
- if (dbus_message_has_name (message,
+ if (dbus_message_is_error (message,
DBUS_ERROR_NO_MEMORY))
{
; /* good, this is a valid response */
}
else
{
- _dbus_warn ("Did not expect error %s\n",
- dbus_message_get_name (message));
+ warn_unexpected (connection, message, "not this error");
+
goto out;
}
}
@@ -743,15 +792,14 @@ check_hello_message (BusContext *context,
{
CheckServiceCreatedData scd;
- if (dbus_message_has_name (message,
- DBUS_MESSAGE_HELLO))
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
{
; /* good, expected */
}
else
{
- _dbus_warn ("Did not expect reply %s\n",
- dbus_message_get_name (message));
+ warn_unexpected (connection, message, "method return for Hello");
+
goto out;
}
@@ -780,7 +828,7 @@ check_hello_message (BusContext *context,
while (!dbus_bus_set_base_service (connection, name))
_dbus_wait_for_memory ();
- scd.skip_connection = NULL;
+ scd.skip_connection = connection; /* we haven't done AddMatch so won't get it ourselves */
scd.failed = FALSE;
scd.expected_service_name = name;
bus_test_clients_foreach (check_service_created_foreach,
@@ -795,7 +843,7 @@ check_hello_message (BusContext *context,
if (message == NULL)
{
_dbus_warn ("Expecting %s, got nothing\n",
- DBUS_MESSAGE_SERVICE_ACQUIRED);
+ "ServiceAcquired");
goto out;
}
@@ -850,6 +898,126 @@ check_hello_message (BusContext *context,
* but the correct thing may include OOM errors.
*/
static dbus_bool_t
+check_add_match_all (BusContext *context,
+ DBusConnection *connection)
+{
+ DBusMessage *message;
+ dbus_bool_t retval;
+ dbus_uint32_t serial;
+ DBusError error;
+
+ retval = FALSE;
+ dbus_error_init (&error);
+ message = NULL;
+
+ _dbus_verbose ("check_add_match_all for %p\n", connection);
+
+ message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+ DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "AddMatch");
+
+ if (message == NULL)
+ return TRUE;
+
+ if (!dbus_message_append_args (message, DBUS_TYPE_STRING, "", /* FIXME */
+ DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (message);
+ return TRUE;
+ }
+
+ if (!dbus_connection_send (connection, message, &serial))
+ {
+ dbus_message_unref (message);
+ return TRUE;
+ }
+
+ dbus_message_unref (message);
+ message = NULL;
+
+ /* send our message */
+ bus_test_run_clients_loop (TRUE);
+
+ dbus_connection_ref (connection); /* because we may get disconnected */
+ block_connection_until_message_from_bus (context, connection);
+
+ if (!dbus_connection_get_is_connected (connection))
+ {
+ _dbus_verbose ("connection was disconnected\n");
+
+ dbus_connection_unref (connection);
+
+ return TRUE;
+ }
+
+ dbus_connection_unref (connection);
+
+ message = pop_message_waiting_for_memory (connection);
+ if (message == NULL)
+ {
+ _dbus_warn ("Did not receive a reply to %s %d on %p\n",
+ "AddMatch", serial, connection);
+ goto out;
+ }
+
+ verbose_message_received (connection, message);
+
+ if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
+ {
+ _dbus_warn ("Message has wrong sender %s\n",
+ dbus_message_get_sender (message) ?
+ dbus_message_get_sender (message) : "(none)");
+ goto out;
+ }
+
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ if (dbus_message_is_error (message,
+ DBUS_ERROR_NO_MEMORY))
+ {
+ ; /* good, this is a valid response */
+ }
+ else
+ {
+ warn_unexpected (connection, message, "not this error");
+
+ goto out;
+ }
+ }
+ else
+ {
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ {
+ ; /* good, expected */
+ _dbus_assert (dbus_message_get_reply_serial (message) == serial);
+ }
+ else
+ {
+ warn_unexpected (connection, message, "method return for AddMatch");
+
+ goto out;
+ }
+ }
+
+ if (!check_no_leftovers (context))
+ goto out;
+
+ retval = TRUE;
+
+ out:
+ dbus_error_free (&error);
+
+ if (message)
+ dbus_message_unref (message);
+
+ return retval;
+}
+
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
check_hello_connection (BusContext *context)
{
DBusConnection *connection;
@@ -874,7 +1042,7 @@ check_hello_connection (BusContext *context)
if (!check_hello_message (context, connection))
return FALSE;
-
+
if (dbus_bus_get_base_service (connection) == NULL)
{
/* We didn't successfully register, so we can't
@@ -884,6 +1052,9 @@ check_hello_connection (BusContext *context)
}
else
{
+ if (!check_add_match_all (context, connection))
+ return FALSE;
+
kill_client_connection (context, connection);
}
@@ -900,14 +1071,16 @@ check_nonexistent_service_activation (BusContext *context,
DBusConnection *connection)
{
DBusMessage *message;
- dbus_int32_t serial;
+ dbus_uint32_t serial;
dbus_bool_t retval;
DBusError error;
dbus_error_init (&error);
- message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_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,
+ "ActivateService");
if (message == NULL)
return TRUE;
@@ -946,16 +1119,15 @@ check_nonexistent_service_activation (BusContext *context,
if (message == NULL)
{
_dbus_warn ("Did not receive a reply to %s %d on %p\n",
- DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection);
+ "ActivateService", serial, connection);
goto out;
}
- _dbus_verbose ("Received %s on %p\n",
- dbus_message_get_name (message), connection);
+ verbose_message_received (connection, message);
- if (dbus_message_get_is_error (message))
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
{
- if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+ if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
_dbus_warn ("Message has wrong sender %s\n",
dbus_message_get_sender (message) ?
@@ -963,20 +1135,19 @@ check_nonexistent_service_activation (BusContext *context,
goto out;
}
- if (dbus_message_has_name (message,
+ if (dbus_message_is_error (message,
DBUS_ERROR_NO_MEMORY))
{
; /* good, this is a valid response */
}
- else if (dbus_message_has_name (message,
+ else if (dbus_message_is_error (message,
DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND))
{
; /* good, this is expected also */
}
else
{
- _dbus_warn ("Did not expect error %s\n",
- dbus_message_get_name (message));
+ warn_unexpected (connection, message, "not this error");
goto out;
}
}
@@ -1015,7 +1186,9 @@ check_base_service_activated (BusContext *context,
message = initial_message;
dbus_message_ref (message);
- if (dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED))
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceCreated"))
{
char *service_name;
CheckServiceCreatedData scd;
@@ -1034,7 +1207,7 @@ check_base_service_activated (BusContext *context,
else
{
_dbus_warn ("Message %s doesn't have a service name: %s\n",
- dbus_message_get_name (message),
+ "ServiceCreated",
error.message);
dbus_error_free (&error);
goto out;
@@ -1062,8 +1235,8 @@ check_base_service_activated (BusContext *context,
}
else
{
- _dbus_warn ("Expected to get base service ServiceCreated, instead got %s\n",
- dbus_message_get_name (message));
+ warn_unexpected (connection, message, "ServiceCreated for base service");
+
goto out;
}
@@ -1104,7 +1277,9 @@ check_service_activated (BusContext *context,
message = initial_message;
dbus_message_ref (message);
- if (dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_CREATED))
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceCreated"))
{
char *service_name;
CheckServiceCreatedData scd;
@@ -1123,7 +1298,7 @@ check_service_activated (BusContext *context,
else
{
_dbus_warn ("Message %s doesn't have a service name: %s\n",
- dbus_message_get_name (message),
+ "ServiceCreated",
error.message);
dbus_error_free (&error);
goto out;
@@ -1154,22 +1329,21 @@ check_service_activated (BusContext *context,
if (message == NULL)
{
_dbus_warn ("Expected a reply to %s, got nothing\n",
- DBUS_MESSAGE_ACTIVATE_SERVICE);
+ "ActivateService");
goto out;
}
}
else
{
- _dbus_warn ("Expected to get service %s ServiceCreated, instead got %s\n",
- activated_name, dbus_message_get_name (message));
+ warn_unexpected (connection, message, "ServiceCreated for the activated name");
+
goto out;
}
- if (!dbus_message_has_name (message, DBUS_MESSAGE_ACTIVATE_SERVICE))
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_RETURN)
{
- _dbus_warn ("Expected reply to %s, got message %s instead\n",
- DBUS_MESSAGE_ACTIVATE_SERVICE,
- dbus_message_get_name (message));
+ warn_unexpected (connection, message, "reply to ActivateService");
+
goto out;
}
@@ -1181,7 +1355,7 @@ check_service_activated (BusContext *context,
if (!dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
{
_dbus_warn ("Did not have activation result first argument to %s: %s\n",
- DBUS_MESSAGE_ACTIVATE_SERVICE, error.message);
+ "ActivateService", error.message);
dbus_error_free (&error);
goto out;
}
@@ -1279,7 +1453,7 @@ check_send_exit_to_service (BusContext *context,
{
dbus_bool_t got_error;
DBusMessage *message;
- dbus_int32_t serial;
+ dbus_uint32_t serial;
dbus_bool_t retval;
_dbus_verbose ("Sending exit message to the test service\n");
@@ -1287,8 +1461,10 @@ check_send_exit_to_service (BusContext *context,
retval = FALSE;
/* Kill off the test service by sending it a quit message */
- message = dbus_message_new ("org.freedesktop.DBus.TestSuiteExit",
- service_name);
+ message = dbus_message_new_method_call (service_name,
+ "/org/freedesktop/TestSuite",
+ "org.freedesktop.TestSuite",
+ "Exit");
if (message == NULL)
{
@@ -1324,7 +1500,7 @@ check_send_exit_to_service (BusContext *context,
/* see if we got an error during message bus dispatching */
bus_test_run_clients_loop (FALSE);
message = dbus_connection_borrow_message (connection);
- got_error = message != NULL && dbus_message_get_is_error (message);
+ got_error = message != NULL && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR;
if (message)
{
dbus_connection_return_message (connection, message);
@@ -1344,21 +1520,16 @@ check_send_exit_to_service (BusContext *context,
message = pop_message_waiting_for_memory (connection);
_dbus_assert (message != NULL);
- if (!dbus_message_get_is_error (message))
+ if (!dbus_message_is_error (message,
+ DBUS_ERROR_NO_MEMORY))
{
- _dbus_warn ("expecting an error reply to asking test service to exit, got %s\n",
- dbus_message_get_name (message));
- goto out;
- }
- else if (!dbus_message_has_name (message, DBUS_ERROR_NO_MEMORY))
- {
- _dbus_warn ("not expecting error %s when asking test service to exit\n",
- dbus_message_get_name (message));
+ warn_unexpected (connection, message,
+ "a no memory error from asking test service to exit");
goto out;
}
_dbus_verbose ("Got error %s when asking test service to exit\n",
- dbus_message_get_name (message));
+ dbus_message_get_error_name (message));
/* Do this again; we still need the service to exit... */
if (!check_send_exit_to_service (context, connection,
@@ -1402,10 +1573,10 @@ check_got_error (BusContext *context,
goto out;
}
- if (!dbus_message_get_is_error (message))
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
{
- _dbus_warn ("Expected an error, got %s\n",
- dbus_message_get_name (message));
+ warn_unexpected (connection, message, "an error");
+
goto out;
}
@@ -1415,7 +1586,7 @@ check_got_error (BusContext *context,
error_name = first_error_name;
while (error_name != NULL)
{
- if (dbus_message_has_name (message, error_name))
+ if (dbus_message_is_error (message, error_name))
{
error_found = TRUE;
break;
@@ -1428,7 +1599,7 @@ check_got_error (BusContext *context,
{
_dbus_warn ("Expected error %s or other, got %s instead\n",
first_error_name,
- dbus_message_get_name (message));
+ dbus_message_get_error_name (message));
goto out;
}
@@ -1451,7 +1622,7 @@ check_existent_service_activation (BusContext *context,
DBusConnection *connection)
{
DBusMessage *message;
- dbus_int32_t serial;
+ dbus_uint32_t serial;
dbus_bool_t retval;
DBusError error;
char *base_service;
@@ -1460,8 +1631,10 @@ check_existent_service_activation (BusContext *context,
dbus_error_init (&error);
- message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_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,
+ "ActivateService");
if (message == NULL)
return TRUE;
@@ -1505,17 +1678,16 @@ check_existent_service_activation (BusContext *context,
if (message == NULL)
{
_dbus_warn ("Did not receive any messages after %s %d on %p\n",
- DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection);
+ "ActivateService", serial, connection);
goto out;
}
- _dbus_verbose ("Received %s on %p after sending %s\n",
- dbus_message_get_name (message), connection,
- DBUS_MESSAGE_ACTIVATE_SERVICE);
+ verbose_message_received (connection, message);
+ _dbus_verbose (" (after sending %s)\n", "ActivateService");
- if (dbus_message_get_is_error (message))
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
{
- if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+ if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
_dbus_warn ("Message has wrong sender %s\n",
dbus_message_get_sender (message) ?
@@ -1523,12 +1695,12 @@ check_existent_service_activation (BusContext *context,
goto out;
}
- if (dbus_message_has_name (message,
+ if (dbus_message_is_error (message,
DBUS_ERROR_NO_MEMORY))
{
; /* good, this is a valid response */
}
- else if (dbus_message_has_name (message,
+ else if (dbus_message_is_error (message,
DBUS_ERROR_SPAWN_CHILD_EXITED))
{
; /* good, this is expected also */
@@ -1536,7 +1708,7 @@ check_existent_service_activation (BusContext *context,
else
{
_dbus_warn ("Did not expect error %s\n",
- dbus_message_get_name (message));
+ dbus_message_get_error_name (message));
goto out;
}
}
@@ -1562,8 +1734,10 @@ check_existent_service_activation (BusContext *context,
goto out;
}
- got_service_deleted = dbus_message_has_name (message, DBUS_MESSAGE_SERVICE_DELETED);
- got_error = dbus_message_get_is_error (message);
+ got_service_deleted = dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceDeleted");
+ got_error = dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR;
dbus_connection_return_message (connection, message);
message = NULL;
@@ -1662,14 +1836,16 @@ check_segfault_service_activation (BusContext *context,
DBusConnection *connection)
{
DBusMessage *message;
- dbus_int32_t serial;
+ dbus_uint32_t serial;
dbus_bool_t retval;
DBusError error;
dbus_error_init (&error);
- message = dbus_message_new (DBUS_MESSAGE_ACTIVATE_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,
+ "ActivateService");
if (message == NULL)
return TRUE;
@@ -1709,16 +1885,15 @@ check_segfault_service_activation (BusContext *context,
if (message == NULL)
{
_dbus_warn ("Did not receive a reply to %s %d on %p\n",
- DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection);
+ "ActivateService", serial, connection);
goto out;
}
- _dbus_verbose ("Received %s on %p\n",
- dbus_message_get_name (message), connection);
+ verbose_message_received (connection, message);
- if (dbus_message_get_is_error (message))
+ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
{
- if (!dbus_message_has_sender (message, DBUS_SERVICE_DBUS))
+ if (!dbus_message_has_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
_dbus_warn ("Message has wrong sender %s\n",
dbus_message_get_sender (message) ?
@@ -1726,20 +1901,20 @@ check_segfault_service_activation (BusContext *context,
goto out;
}
- if (dbus_message_has_name (message,
- DBUS_ERROR_NO_MEMORY))
+ if (dbus_message_is_error (message,
+ DBUS_ERROR_NO_MEMORY))
{
; /* good, this is a valid response */
}
- else if (dbus_message_has_name (message,
- DBUS_ERROR_SPAWN_CHILD_SIGNALED))
+ else if (dbus_message_is_error (message,
+ DBUS_ERROR_SPAWN_CHILD_SIGNALED))
{
; /* good, this is expected also */
}
else
{
- _dbus_warn ("Did not expect error %s\n",
- dbus_message_get_name (message));
+ warn_unexpected (connection, message, "not this error");
+
goto out;
}
}
@@ -1862,6 +2037,9 @@ bus_dispatch_test (const DBusString *test_data_dir)
if (!check_hello_message (context, foo))
_dbus_assert_not_reached ("hello message failed");
+
+ if (!check_add_match_all (context, foo))
+ _dbus_assert_not_reached ("AddMatch message failed");
bar = dbus_connection_open ("debug-pipe:name=test-server", &error);
if (bar == NULL)
@@ -1872,6 +2050,9 @@ bus_dispatch_test (const DBusString *test_data_dir)
if (!check_hello_message (context, bar))
_dbus_assert_not_reached ("hello message failed");
+
+ if (!check_add_match_all (context, bar))
+ _dbus_assert_not_reached ("AddMatch message failed");
baz = dbus_connection_open ("debug-pipe:name=test-server", &error);
if (baz == NULL)
@@ -1883,6 +2064,9 @@ bus_dispatch_test (const DBusString *test_data_dir)
if (!check_hello_message (context, baz))
_dbus_assert_not_reached ("hello message failed");
+ if (!check_add_match_all (context, baz))
+ _dbus_assert_not_reached ("AddMatch message failed");
+
if (!check_no_leftovers (context))
{
_dbus_warn ("Messages were left over after setting up initial connections");
@@ -1939,6 +2123,9 @@ bus_dispatch_sha1_test (const DBusString *test_data_dir)
if (!check_hello_message (context, foo))
_dbus_assert_not_reached ("hello message failed");
+ if (!check_add_match_all (context, foo))
+ _dbus_assert_not_reached ("addmatch message failed");
+
if (!check_no_leftovers (context))
{
_dbus_warn ("Messages were left over after setting up initial SHA-1 connection\n");
diff --git a/bus/dispatch.h b/bus/dispatch.h
index 18f74529..d8107b1a 100644
--- a/bus/dispatch.h
+++ b/bus/dispatch.h
@@ -29,8 +29,9 @@
dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
void bus_dispatch_remove_connection (DBusConnection *connection);
-dbus_bool_t bus_dispatch_broadcast_message (BusTransaction *transaction,
+dbus_bool_t bus_dispatch_matches (BusTransaction *transaction,
DBusConnection *sender,
+ DBusConnection *recipient,
DBusMessage *message,
DBusError *error);
diff --git a/bus/driver.c b/bus/driver.c
index e0afd8ef..791fcd69 100644
--- a/bus/driver.c
+++ b/bus/driver.c
@@ -27,6 +27,7 @@
#include "driver.h"
#include "dispatch.h"
#include "services.h"
+#include "signals.h"
#include "utils.h"
#include <dbus/dbus-string.h>
#include <dbus/dbus-internals.h>
@@ -49,15 +50,17 @@ bus_driver_send_service_deleted (const char *service_name,
_dbus_verbose ("sending service deleted: %s\n", service_name);
- message = dbus_message_new (DBUS_MESSAGE_SERVICE_DELETED,
- DBUS_SERVICE_BROADCAST);
+ message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceDeleted");
+
if (message == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
- if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS) ||
!dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
DBUS_TYPE_INVALID))
@@ -67,7 +70,7 @@ bus_driver_send_service_deleted (const char *service_name,
return FALSE;
}
- retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
+ retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
dbus_message_unref (message);
return retval;
@@ -83,15 +86,17 @@ bus_driver_send_service_created (const char *service_name,
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
- message = dbus_message_new (DBUS_MESSAGE_SERVICE_CREATED,
- DBUS_SERVICE_BROADCAST);
+ message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceCreated");
+
if (message == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
- if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_ORG_FREEDESKTOP_DBUS))
{
dbus_message_unref (message);
BUS_SET_OOM (error);
@@ -107,7 +112,7 @@ bus_driver_send_service_created (const char *service_name,
return FALSE;
}
- retval = bus_dispatch_broadcast_message (transaction, NULL, message, error);
+ retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
dbus_message_unref (message);
return retval;
@@ -123,15 +128,18 @@ bus_driver_send_service_lost (DBusConnection *connection,
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
- message = dbus_message_new (DBUS_MESSAGE_SERVICE_LOST,
- bus_connection_get_name (connection));
+ message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceLost");
+
if (message == NULL)
{
BUS_SET_OOM (error);
return FALSE;
}
- if (!dbus_message_append_args (message,
+ if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
+ !dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
DBUS_TYPE_INVALID))
{
@@ -163,8 +171,9 @@ bus_driver_send_service_acquired (DBusConnection *connection,
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
- message = dbus_message_new (DBUS_MESSAGE_SERVICE_ACQUIRED,
- bus_connection_get_name (connection));
+ message = dbus_message_new_signal (DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceAcquired");
if (message == NULL)
{
@@ -172,7 +181,8 @@ bus_driver_send_service_acquired (DBusConnection *connection,
return FALSE;
}
- if (!dbus_message_append_args (message,
+ if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
+ !dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
DBUS_TYPE_INVALID))
{
@@ -322,6 +332,7 @@ bus_driver_handle_hello (DBusConnection *connection,
bus_service_set_prohibit_replacement (service, TRUE);
+ _dbus_assert (bus_connection_is_active (connection));
retval = TRUE;
out_0:
@@ -343,7 +354,7 @@ bus_driver_send_welcome_message (DBusConnection *connection,
name = bus_connection_get_name (connection);
_dbus_assert (name != NULL);
- welcome = dbus_message_new_reply (hello_message);
+ welcome = dbus_message_new_method_return (hello_message);
if (welcome == NULL)
{
BUS_SET_OOM (error);
@@ -387,7 +398,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
registry = bus_connection_get_registry (connection);
- reply = dbus_message_new_reply (message);
+ reply = dbus_message_new_method_return (message);
if (reply == NULL)
{
BUS_SET_OOM (error);
@@ -463,7 +474,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
error))
goto out;
- reply = dbus_message_new_reply (message);
+ reply = dbus_message_new_method_return (message);
if (reply == NULL)
{
BUS_SET_OOM (error);
@@ -518,7 +529,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
_dbus_string_init_const (&service_name, name);
service = bus_registry_lookup (registry, &service_name);
- reply = dbus_message_new_reply (message);
+ reply = dbus_message_new_method_return (message);
if (reply == NULL)
{
BUS_SET_OOM (error);
@@ -591,6 +602,160 @@ bus_driver_handle_activate_service (DBusConnection *connection,
return retval;
}
+static dbus_bool_t
+send_ack_reply (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
+ {
+ BUS_SET_OOM (error);
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ dbus_message_unref (reply);
+
+ return TRUE;
+}
+
+static dbus_bool_t
+bus_driver_handle_add_match (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ BusMatchRule *rule;
+ char *text;
+ DBusString str;
+ BusMatchmaker *matchmaker;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ text = NULL;
+ rule = NULL;
+
+ if (bus_connection_get_n_match_rules (connection) >=
+ bus_context_get_max_match_rules_per_connection (bus_transaction_get_context (transaction)))
+ {
+ dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
+ "Connection \"%s\" is not allowed to add more match rules "
+ "(increase limits in configuration file if required)",
+ bus_connection_is_active (connection) ?
+ bus_connection_get_name (connection) :
+ "(inactive)");
+ goto failed;
+ }
+
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID))
+ {
+ _dbus_verbose ("No memory to get arguments to AddMatch\n");
+ goto failed;
+ }
+
+ _dbus_string_init_const (&str, text);
+
+ rule = bus_match_rule_parse (connection, &str, error);
+ if (rule == NULL)
+ goto failed;
+
+ matchmaker = bus_connection_get_matchmaker (connection);
+
+ if (!bus_matchmaker_add_rule (matchmaker, rule))
+ {
+ BUS_SET_OOM (error);
+ goto failed;
+ }
+
+ if (!send_ack_reply (connection, transaction,
+ message, error))
+ {
+ bus_matchmaker_remove_rule (matchmaker, rule);
+ goto failed;
+ }
+
+ bus_match_rule_unref (rule);
+ dbus_free (text);
+
+ return TRUE;
+
+ failed:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (rule)
+ bus_match_rule_unref (rule);
+ if (text)
+ dbus_free (text);
+ return FALSE;
+}
+
+static dbus_bool_t
+bus_driver_handle_remove_match (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ BusMatchRule *rule;
+ char *text;
+ DBusString str;
+ BusMatchmaker *matchmaker;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ text = NULL;
+ rule = NULL;
+
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID))
+ {
+ _dbus_verbose ("No memory to get arguments to RemoveMatch\n");
+ goto failed;
+ }
+
+ _dbus_string_init_const (&str, text);
+
+ rule = bus_match_rule_parse (connection, &str, error);
+ if (rule == NULL)
+ goto failed;
+
+ /* Send the ack before we remove the rule, since the ack is undone
+ * on transaction cancel, but rule removal isn't.
+ */
+ if (!send_ack_reply (connection, transaction,
+ message, error))
+ goto failed;
+
+ matchmaker = bus_connection_get_matchmaker (connection);
+
+ if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
+ goto failed;
+
+ bus_match_rule_unref (rule);
+ dbus_free (text);
+
+ return TRUE;
+
+ failed:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (rule)
+ bus_match_rule_unref (rule);
+ if (text)
+ dbus_free (text);
+ return FALSE;
+}
+
/* For speed it might be useful to sort this in order of
* frequency of use (but doesn't matter with only a few items
* anyhow)
@@ -603,11 +768,13 @@ struct
DBusMessage *message,
DBusError *error);
} message_handlers[] = {
- { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
- { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
- { DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
- { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
- { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
+ { "AcquireService", bus_driver_handle_acquire_service },
+ { "ActivateService", bus_driver_handle_activate_service },
+ { "Hello", bus_driver_handle_hello },
+ { "ServiceExists", bus_driver_handle_service_exists },
+ { "ListServices", bus_driver_handle_list_services },
+ { "AddMatch", bus_driver_handle_add_match },
+ { "RemoveMatch", bus_driver_handle_remove_match }
};
dbus_bool_t
@@ -620,15 +787,32 @@ bus_driver_handle_message (DBusConnection *connection,
int i;
_DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ _dbus_verbose ("Driver got a non-method-call message, ignoring\n");
+ return TRUE; /* we just ignore this */
+ }
+
+ _dbus_assert (dbus_message_get_interface (message) != NULL);
+ _dbus_assert (dbus_message_get_member (message) != NULL);
+
+ name = dbus_message_get_member (message);
+ sender = dbus_message_get_sender (message);
- _dbus_verbose ("Driver got a message: %s\n",
- dbus_message_get_name (message));
+ if (strcmp (dbus_message_get_interface (message),
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS) != 0)
+ {
+ _dbus_verbose ("Driver got message to unknown interface \"%s\"\n",
+ dbus_message_get_interface (message));
+ goto unknown;
+ }
+
+ _dbus_verbose ("Driver got a method call: %s\n",
+ dbus_message_get_member (message));
- name = dbus_message_get_name (message);
- sender = dbus_message_get_sender (message);
-
/* security checks should have kept this from getting here */
- _dbus_assert (sender != NULL || strcmp (name, DBUS_MESSAGE_HELLO) == 0);
+ _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
if (dbus_message_get_reply_serial (message) == 0)
{
@@ -659,11 +843,13 @@ bus_driver_handle_message (DBusConnection *connection,
++i;
}
- _dbus_verbose ("No driver handler for %s\n", name);
+ unknown:
+ _dbus_verbose ("No driver handler for message \"%s\"\n",
+ name);
- dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
+ dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD,
"%s does not understand message %s",
- DBUS_SERVICE_DBUS, name);
+ DBUS_SERVICE_ORG_FREEDESKTOP_DBUS, name);
return FALSE;
}
diff --git a/bus/policy.c b/bus/policy.c
index 2f8e2ca3..2d462fb6 100644
--- a/bus/policy.c
+++ b/bus/policy.c
@@ -52,7 +52,11 @@ bus_policy_rule_new (BusPolicyRuleType type,
rule->d.group.gid = DBUS_GID_UNSET;
break;
case BUS_POLICY_RULE_SEND:
+ rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
+ break;
case BUS_POLICY_RULE_RECEIVE:
+ rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
+ break;
case BUS_POLICY_RULE_OWN:
break;
}
@@ -80,11 +84,17 @@ bus_policy_rule_unref (BusPolicyRule *rule)
switch (rule->type)
{
case BUS_POLICY_RULE_SEND:
- dbus_free (rule->d.send.message_name);
+ dbus_free (rule->d.send.path);
+ dbus_free (rule->d.send.interface);
+ dbus_free (rule->d.send.member);
+ dbus_free (rule->d.send.error);
dbus_free (rule->d.send.destination);
break;
case BUS_POLICY_RULE_RECEIVE:
- dbus_free (rule->d.receive.message_name);
+ dbus_free (rule->d.receive.path);
+ dbus_free (rule->d.receive.interface);
+ dbus_free (rule->d.receive.member);
+ dbus_free (rule->d.receive.error);
dbus_free (rule->d.receive.origin);
break;
case BUS_POLICY_RULE_OWN:
@@ -680,8 +690,8 @@ bus_client_policy_optimize (BusClientPolicy *policy)
/* The idea here is that if we have:
*
- * <allow send="foo"/>
- * <deny send="*"/>
+ * <allow send_interface="foo.bar"/>
+ * <deny send_interface="*"/>
*
* (for example) the deny will always override the allow. So we
* delete the allow. Ditto for deny followed by allow, etc. This is
@@ -713,12 +723,20 @@ bus_client_policy_optimize (BusClientPolicy *policy)
{
case BUS_POLICY_RULE_SEND:
remove_preceding =
- rule->d.send.message_name == NULL &&
+ rule->d.send.message_type == DBUS_MESSAGE_TYPE_INVALID &&
+ rule->d.send.path == NULL &&
+ rule->d.send.interface == NULL &&
+ rule->d.send.member == NULL &&
+ rule->d.send.error == NULL &&
rule->d.send.destination == NULL;
break;
case BUS_POLICY_RULE_RECEIVE:
remove_preceding =
- rule->d.receive.message_name == NULL &&
+ rule->d.receive.message_type == DBUS_MESSAGE_TYPE_INVALID &&
+ rule->d.receive.path == NULL &&
+ rule->d.receive.interface == NULL &&
+ rule->d.receive.member == NULL &&
+ rule->d.receive.error == NULL &&
rule->d.receive.origin == NULL;
break;
case BUS_POLICY_RULE_OWN:
@@ -791,16 +809,59 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
continue;
}
- if (rule->d.send.message_name != NULL)
+ if (rule->d.send.message_type != DBUS_MESSAGE_TYPE_INVALID)
+ {
+ if (dbus_message_get_type (message) != rule->d.send.message_type)
+ {
+ _dbus_verbose (" (policy) skipping rule for different message type\n");
+ continue;
+ }
+ }
+
+ if (rule->d.send.path != NULL)
+ {
+ if (dbus_message_get_path (message) != NULL &&
+ strcmp (dbus_message_get_path (message),
+ rule->d.send.path) != 0)
+ {
+ _dbus_verbose (" (policy) skipping rule for different path\n");
+ continue;
+ }
+ }
+
+ if (rule->d.send.interface != NULL)
{
- if (!dbus_message_has_name (message,
- rule->d.send.message_name))
+ if (dbus_message_get_interface (message) != NULL &&
+ strcmp (dbus_message_get_interface (message),
+ rule->d.send.interface) != 0)
{
- _dbus_verbose (" (policy) skipping rule for different message name\n");
+ _dbus_verbose (" (policy) skipping rule for different interface\n");
continue;
}
}
+ if (rule->d.send.member != NULL)
+ {
+ if (dbus_message_get_member (message) != NULL &&
+ strcmp (dbus_message_get_member (message),
+ rule->d.send.member) != 0)
+ {
+ _dbus_verbose (" (policy) skipping rule for different member\n");
+ continue;
+ }
+ }
+
+ if (rule->d.send.error != NULL)
+ {
+ if (dbus_message_get_error_name (message) != NULL &&
+ strcmp (dbus_message_get_error_name (message),
+ rule->d.send.error) != 0)
+ {
+ _dbus_verbose (" (policy) skipping rule for different error name\n");
+ continue;
+ }
+ }
+
if (rule->d.send.destination != NULL)
{
/* receiver can be NULL for messages that are sent to the
@@ -856,16 +917,33 @@ dbus_bool_t
bus_client_policy_check_can_receive (BusClientPolicy *policy,
BusRegistry *registry,
DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
DBusMessage *message)
{
DBusList *link;
dbus_bool_t allowed;
+ dbus_bool_t eavesdropping;
+
+ /* NULL sender, proposed_recipient means the bus driver. NULL
+ * addressed_recipient means the message didn't specify an explicit
+ * target. If proposed_recipient is NULL, then addressed_recipient
+ * is also NULL but is implicitly the bus driver.
+ */
+
+ _dbus_assert (proposed_recipient == NULL ||
+ (dbus_message_get_destination (message) == NULL ||
+ addressed_recipient != NULL));
+
+ eavesdropping =
+ (proposed_recipient == NULL || /* explicitly to bus driver */
+ (addressed_recipient && addressed_recipient != proposed_recipient)); /* explicitly to a different recipient */
/* policy->rules is in the order the rules appeared
* in the config file, i.e. last rule that applies wins
*/
- _dbus_verbose (" (policy) checking receive rules\n");
+ _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
allowed = FALSE;
link = _dbus_list_get_first_link (&policy->rules);
@@ -873,12 +951,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
{
BusPolicyRule *rule = link->data;
- link = _dbus_list_get_next_link (&policy->rules, link);
-
- /* Rule is skipped if it specifies a different
- * message name from the message, or a different
- * origin from the message
- */
+ link = _dbus_list_get_next_link (&policy->rules, link);
if (rule->type != BUS_POLICY_RULE_RECEIVE)
{
@@ -886,16 +959,77 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
continue;
}
- if (rule->d.receive.message_name != NULL)
+ if (rule->d.receive.message_type != DBUS_MESSAGE_TYPE_INVALID)
{
- if (!dbus_message_has_name (message,
- rule->d.receive.message_name))
+ if (dbus_message_get_type (message) != rule->d.receive.message_type)
{
- _dbus_verbose (" (policy) skipping rule for different message name\n");
+ _dbus_verbose (" (policy) skipping rule for different message type\n");
continue;
}
}
+ /* for allow, eavesdrop=false means the rule doesn't apply when
+ * eavesdropping. eavesdrop=true means always allow.
+ */
+ if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
+ {
+ _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
+ continue;
+ }
+
+ /* for deny, eavesdrop=true means the rule applies only when
+ * eavesdropping; eavesdrop=false means always deny.
+ */
+ if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
+ {
+ _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n");
+ continue;
+ }
+
+ if (rule->d.receive.path != NULL)
+ {
+ if (dbus_message_get_path (message) != NULL &&
+ strcmp (dbus_message_get_path (message),
+ rule->d.receive.path) != 0)
+ {
+ _dbus_verbose (" (policy) skipping rule for different path\n");
+ continue;
+ }
+ }
+
+ if (rule->d.receive.interface != NULL)
+ {
+ if (dbus_message_get_interface (message) != NULL &&
+ strcmp (dbus_message_get_interface (message),
+ rule->d.receive.interface) != 0)
+ {
+ _dbus_verbose (" (policy) skipping rule for different interface\n");
+ continue;
+ }
+ }
+
+ if (rule->d.receive.member != NULL)
+ {
+ if (dbus_message_get_member (message) != NULL &&
+ strcmp (dbus_message_get_member (message),
+ rule->d.receive.member) != 0)
+ {
+ _dbus_verbose (" (policy) skipping rule for different member\n");
+ continue;
+ }
+ }
+
+ if (rule->d.receive.error != NULL)
+ {
+ if (dbus_message_get_error_name (message) != NULL &&
+ strcmp (dbus_message_get_error_name (message),
+ rule->d.receive.error) != 0)
+ {
+ _dbus_verbose (" (policy) skipping rule for different error name\n");
+ continue;
+ }
+ }
+
if (rule->d.receive.origin != NULL)
{
/* sender can be NULL for messages that originate from the
@@ -937,7 +1071,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
}
}
}
-
+
/* Use this rule */
allowed = rule->allow;
diff --git a/bus/policy.h b/bus/policy.h
index 940085ee..63981cc0 100644
--- a/bus/policy.h
+++ b/bus/policy.h
@@ -54,16 +54,27 @@ struct BusPolicyRule
{
struct
{
- /* either can be NULL meaning "any" */
- char *message_name;
+ /* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */
+ int message_type;
+ /* any of these can be NULL meaning "any" */
+ char *path;
+ char *interface;
+ char *member;
+ char *error;
char *destination;
} send;
struct
{
- /* either can be NULL meaning "any" */
- char *message_name;
+ /* message type can be DBUS_MESSAGE_TYPE_INVALID meaning "any" */
+ int message_type;
+ /* any of these can be NULL meaning "any" */
+ char *path;
+ char *interface;
+ char *member;
+ char *error;
char *origin;
+ unsigned int eavesdrop : 1;
} receive;
struct
@@ -124,6 +135,8 @@ dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy,
dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy,
BusRegistry *registry,
DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusConnection *proposed_recipient,
DBusMessage *message);
dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy,
DBusConnection *connection,
diff --git a/bus/services.c b/bus/services.c
index 5148f1f1..84cabe21 100644
--- a/bus/services.c
+++ b/bus/services.c
@@ -417,10 +417,14 @@ bus_service_relink (BusService *service,
bus_service_ref (service);
}
+/**
+ * Data used to represent an ownership cancellation in
+ * a bus transaction.
+ */
typedef struct
{
- DBusConnection *connection;
- BusService *service;
+ DBusConnection *connection; /**< the connection */
+ BusService *service; /**< service to cancel ownership of */
} OwnershipCancelData;
static void
diff --git a/bus/session.conf.in b/bus/session.conf.in
index 673d8739..34d2492c 100644
--- a/bus/session.conf.in
+++ b/bus/session.conf.in
@@ -13,11 +13,14 @@
<servicedir>@EXPANDED_LIBDIR@/dbus-1.0/services</servicedir>
<policy context="default">
- <!-- Allow everything -->
- <allow send="*"/>
- <allow receive="*"/>
+ <!-- Allow everything to be sent -->
+ <allow send_destination="*"/>
+ <!-- Allow everything to be received -->
+ <allow eavesdrop="true"/>
+ <!-- Allow anyone to own anything -->
<allow own="*"/>
- <allow user="*"/>
+ <!-- Allow any user to connect -->
+ <allow user="*"/>
</policy>
<!-- This is included last so local configuration can override what's
diff --git a/bus/signals.c b/bus/signals.c
new file mode 100644
index 00000000..30d977c3
--- /dev/null
+++ b/bus/signals.c
@@ -0,0 +1,778 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* signals.c Bus signal connection implementation
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "signals.h"
+#include "services.h"
+#include "utils.h"
+
+struct BusMatchRule
+{
+ int refcount; /**< reference count */
+
+ DBusConnection *matches_go_to; /**< Owner of the rule */
+
+ unsigned int flags; /**< BusMatchFlags */
+
+ int message_type;
+ char *interface;
+ char *member;
+ char *sender;
+ char *destination;
+ char *path;
+};
+
+BusMatchRule*
+bus_match_rule_new (DBusConnection *matches_go_to)
+{
+ BusMatchRule *rule;
+
+ rule = dbus_new0 (BusMatchRule, 1);
+ if (rule == NULL)
+ return NULL;
+
+ rule->refcount = 1;
+ rule->matches_go_to = matches_go_to;
+
+ return rule;
+}
+
+void
+bus_match_rule_ref (BusMatchRule *rule)
+{
+ _dbus_assert (rule->refcount > 0);
+
+ rule->refcount += 1;
+}
+
+void
+bus_match_rule_unref (BusMatchRule *rule)
+{
+ _dbus_assert (rule->refcount > 0);
+
+ rule->refcount -= 1;
+ if (rule->refcount == 0)
+ {
+ dbus_free (rule->interface);
+ dbus_free (rule->member);
+ dbus_free (rule->sender);
+ dbus_free (rule->destination);
+ dbus_free (rule->path);
+ dbus_free (rule);
+ }
+}
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+static char*
+match_rule_to_string (BusMatchRule *rule)
+{
+ DBusString str;
+ char *ret;
+
+ if (!_dbus_string_init (&str))
+ {
+ char *s;
+ while ((s = _dbus_strdup ("nomem")) == NULL)
+ ; /* only OK for debug spew... */
+ return s;
+ }
+
+ if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
+ {
+ /* FIXME make type readable */
+ if (!_dbus_string_append_printf (&str, "type='%d'", rule->message_type))
+ goto nomem;
+ }
+
+ if (rule->flags & BUS_MATCH_INTERFACE)
+ {
+ if (_dbus_string_get_length (&str) > 0)
+ {
+ if (!_dbus_string_append (&str, ","))
+ goto nomem;
+ }
+
+ if (!_dbus_string_append_printf (&str, "interface='%s'", rule->interface))
+ goto nomem;
+ }
+
+ if (rule->flags & BUS_MATCH_MEMBER)
+ {
+ if (_dbus_string_get_length (&str) > 0)
+ {
+ if (!_dbus_string_append (&str, ","))
+ goto nomem;
+ }
+
+ if (!_dbus_string_append_printf (&str, "member='%s'", rule->member))
+ goto nomem;
+ }
+
+ if (rule->flags & BUS_MATCH_PATH)
+ {
+ if (_dbus_string_get_length (&str) > 0)
+ {
+ if (!_dbus_string_append (&str, ","))
+ goto nomem;
+ }
+
+ if (!_dbus_string_append_printf (&str, "path='%s'", rule->path))
+ goto nomem;
+ }
+
+ if (rule->flags & BUS_MATCH_SENDER)
+ {
+ if (_dbus_string_get_length (&str) > 0)
+ {
+ if (!_dbus_string_append (&str, ","))
+ goto nomem;
+ }
+
+ if (!_dbus_string_append_printf (&str, "sender='%s'", rule->sender))
+ goto nomem;
+ }
+
+ if (rule->flags & BUS_MATCH_DESTINATION)
+ {
+ if (_dbus_string_get_length (&str) > 0)
+ {
+ if (!_dbus_string_append (&str, ","))
+ goto nomem;
+ }
+
+ if (!_dbus_string_append_printf (&str, "destination='%s'", rule->destination))
+ goto nomem;
+ }
+
+ if (!_dbus_string_steal_data (&str, &ret))
+ goto nomem;
+
+ _dbus_string_free (&str);
+ return ret;
+
+ nomem:
+ _dbus_string_free (&str);
+ {
+ char *s;
+ while ((s = _dbus_strdup ("nomem")) == NULL)
+ ; /* only OK for debug spew... */
+ return s;
+ }
+}
+#endif /* DBUS_ENABLE_VERBOSE_MODE */
+
+dbus_bool_t
+bus_match_rule_set_message_type (BusMatchRule *rule,
+ int type)
+{
+ rule->flags |= BUS_MATCH_MESSAGE_TYPE;
+
+ rule->message_type = type;
+
+ return TRUE;
+}
+
+dbus_bool_t
+bus_match_rule_set_interface (BusMatchRule *rule,
+ const char *interface)
+{
+ char *new;
+
+ _dbus_assert (interface != NULL);
+
+ new = _dbus_strdup (interface);
+ if (new == NULL)
+ return FALSE;
+
+ rule->flags |= BUS_MATCH_INTERFACE;
+ dbus_free (rule->interface);
+ rule->interface = new;
+
+ return TRUE;
+}
+
+dbus_bool_t
+bus_match_rule_set_member (BusMatchRule *rule,
+ const char *member)
+{
+ char *new;
+
+ _dbus_assert (member != NULL);
+
+ new = _dbus_strdup (member);
+ if (new == NULL)
+ return FALSE;
+
+ rule->flags |= BUS_MATCH_MEMBER;
+ dbus_free (rule->member);
+ rule->member = new;
+
+ return TRUE;
+}
+
+dbus_bool_t
+bus_match_rule_set_sender (BusMatchRule *rule,
+ const char *sender)
+{
+ char *new;
+
+ _dbus_assert (sender != NULL);
+
+ new = _dbus_strdup (sender);
+ if (new == NULL)
+ return FALSE;
+
+ rule->flags |= BUS_MATCH_SENDER;
+ dbus_free (rule->sender);
+ rule->sender = new;
+
+ return TRUE;
+}
+
+dbus_bool_t
+bus_match_rule_set_destination (BusMatchRule *rule,
+ const char *destination)
+{
+ char *new;
+
+ _dbus_assert (destination != NULL);
+
+ new = _dbus_strdup (destination);
+ if (new == NULL)
+ return FALSE;
+
+ rule->flags |= BUS_MATCH_DESTINATION;
+ dbus_free (rule->destination);
+ rule->destination = new;
+
+ return TRUE;
+}
+
+dbus_bool_t
+bus_match_rule_set_path (BusMatchRule *rule,
+ const char *path)
+{
+ char *new;
+
+ _dbus_assert (path != NULL);
+
+ new = _dbus_strdup (path);
+ if (new == NULL)
+ return FALSE;
+
+ rule->flags |= BUS_MATCH_PATH;
+ dbus_free (rule->path);
+ rule->path = new;
+
+ return TRUE;
+}
+
+/*
+ * The format is comma-separated with strings quoted with single quotes
+ * as for the shell (to escape a literal single quote, use '\'').
+ *
+ * type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='Foo',
+ * path='/bar/foo',destination=':452345-34'
+ *
+ */
+BusMatchRule*
+bus_match_rule_parse (DBusConnection *matches_go_to,
+ const DBusString *rule_text,
+ DBusError *error)
+{
+ BusMatchRule *rule;
+
+ rule = bus_match_rule_new (matches_go_to);
+ if (rule == NULL)
+ goto oom;
+
+ /* FIXME implement for real */
+
+ if (!bus_match_rule_set_message_type (rule,
+ DBUS_MESSAGE_TYPE_SIGNAL))
+ goto oom;
+
+ return rule;
+
+ oom:
+ if (rule)
+ bus_match_rule_unref (rule);
+ BUS_SET_OOM (error);
+ return NULL;
+}
+
+struct BusMatchmaker
+{
+ int refcount;
+
+ DBusList *all_rules;
+};
+
+BusMatchmaker*
+bus_matchmaker_new (void)
+{
+ BusMatchmaker *matchmaker;
+
+ matchmaker = dbus_new0 (BusMatchmaker, 1);
+ if (matchmaker == NULL)
+ return NULL;
+
+ matchmaker->refcount = 1;
+
+ return matchmaker;
+}
+
+void
+bus_matchmaker_ref (BusMatchmaker *matchmaker)
+{
+ _dbus_assert (matchmaker->refcount > 0);
+
+ matchmaker->refcount += 1;
+}
+
+void
+bus_matchmaker_unref (BusMatchmaker *matchmaker)
+{
+ _dbus_assert (matchmaker->refcount > 0);
+
+ matchmaker->refcount -= 1;
+ if (matchmaker->refcount == 0)
+ {
+ while (matchmaker->all_rules != NULL)
+ {
+ BusMatchRule *rule;
+
+ rule = matchmaker->all_rules->data;
+ bus_match_rule_unref (rule);
+ _dbus_list_remove_link (&matchmaker->all_rules,
+ matchmaker->all_rules);
+ }
+
+ dbus_free (matchmaker);
+ }
+}
+
+/* The rule can't be modified after it's added. */
+dbus_bool_t
+bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
+ BusMatchRule *rule)
+{
+ _dbus_assert (bus_connection_is_active (rule->matches_go_to));
+
+ if (!_dbus_list_append (&matchmaker->all_rules, rule))
+ return FALSE;
+
+ if (!bus_connection_add_match_rule (rule->matches_go_to, rule))
+ {
+ _dbus_list_remove_last (&matchmaker->all_rules, rule);
+ return FALSE;
+ }
+
+ bus_match_rule_ref (rule);
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ {
+ char *s = match_rule_to_string (rule);
+
+ _dbus_verbose ("Added match rule %s to connection %p\n",
+ s, rule->matches_go_to);
+ dbus_free (s);
+ }
+#endif
+
+ return TRUE;
+}
+
+static dbus_bool_t
+match_rule_equal (BusMatchRule *a,
+ BusMatchRule *b)
+{
+ if (a->flags != b->flags)
+ return FALSE;
+
+ if ((a->flags & BUS_MATCH_MESSAGE_TYPE) &&
+ a->message_type != b->message_type)
+ return FALSE;
+
+ if ((a->flags & BUS_MATCH_MEMBER) &&
+ strcmp (a->member, b->member) != 0)
+ return FALSE;
+
+ if ((a->flags & BUS_MATCH_PATH) &&
+ strcmp (a->path, b->path) != 0)
+ return FALSE;
+
+ if ((a->flags & BUS_MATCH_INTERFACE) &&
+ strcmp (a->interface, b->interface) != 0)
+ return FALSE;
+
+ if ((a->flags & BUS_MATCH_SENDER) &&
+ strcmp (a->sender, b->sender) != 0)
+ return FALSE;
+
+ if ((a->flags & BUS_MATCH_DESTINATION) &&
+ strcmp (a->destination, b->destination) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+bus_matchmaker_remove_rule_link (BusMatchmaker *matchmaker,
+ DBusList *link)
+{
+ BusMatchRule *rule = link->data;
+
+ bus_connection_remove_match_rule (rule->matches_go_to, rule);
+ _dbus_list_remove_link (&matchmaker->all_rules, link);
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ {
+ char *s = match_rule_to_string (rule);
+
+ _dbus_verbose ("Removed match rule %s for connection %p\n",
+ s, rule->matches_go_to);
+ dbus_free (s);
+ }
+#endif
+
+ bus_match_rule_unref (rule);
+}
+
+void
+bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
+ BusMatchRule *rule)
+{
+ bus_connection_remove_match_rule (rule->matches_go_to, rule);
+ _dbus_list_remove (&matchmaker->all_rules, rule);
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ {
+ char *s = match_rule_to_string (rule);
+
+ _dbus_verbose ("Removed match rule %s for connection %p\n",
+ s, rule->matches_go_to);
+ dbus_free (s);
+ }
+#endif
+
+ bus_match_rule_unref (rule);
+}
+
+/* Remove a single rule which is equal to the given rule by value */
+dbus_bool_t
+bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
+ BusMatchRule *value,
+ DBusError *error)
+{
+ /* FIXME this is an unoptimized linear scan */
+
+ DBusList *link;
+
+ /* we traverse backward because bus_connection_remove_match_rule()
+ * removes the most-recently-added rule
+ */
+ link = _dbus_list_get_last_link (&matchmaker->all_rules);
+ while (link != NULL)
+ {
+ BusMatchRule *rule;
+ DBusList *prev;
+
+ rule = link->data;
+ prev = _dbus_list_get_prev_link (&matchmaker->all_rules, link);
+
+ if (match_rule_equal (rule, value))
+ {
+ bus_matchmaker_remove_rule_link (matchmaker, link);
+ break;
+ }
+
+ link = prev;
+ }
+
+ if (link == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_MATCH_RULE_NOT_FOUND,
+ "The given match rule wasn't found and can't be removed");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void
+bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
+ DBusConnection *disconnected)
+{
+ DBusList *link;
+
+ /* FIXME
+ *
+ * This scans all match rules on the bus. We could avoid that
+ * for the rules belonging to the connection, since we keep
+ * a list of those; but for the rules that just refer to
+ * the connection we'd need to do something more elaborate.
+ *
+ */
+
+ _dbus_assert (bus_connection_is_active (disconnected));
+
+ link = _dbus_list_get_first_link (&matchmaker->all_rules);
+ while (link != NULL)
+ {
+ BusMatchRule *rule;
+ DBusList *next;
+
+ rule = link->data;
+ next = _dbus_list_get_next_link (&matchmaker->all_rules, link);
+
+ if (rule->matches_go_to == disconnected)
+ {
+ bus_matchmaker_remove_rule_link (matchmaker, link);
+ }
+ else if (((rule->flags & BUS_MATCH_SENDER) && *rule->sender == ':') ||
+ ((rule->flags & BUS_MATCH_DESTINATION) && *rule->destination == ':'))
+ {
+ /* The rule matches to/from a base service, see if it's the
+ * one being disconnected, since we know this service name
+ * will never be recycled.
+ */
+ const char *name;
+
+ name = bus_connection_get_name (disconnected);
+ _dbus_assert (name != NULL); /* because we're an active connection */
+
+ if (((rule->flags & BUS_MATCH_SENDER) &&
+ strcmp (rule->sender, name) == 0) ||
+ ((rule->flags & BUS_MATCH_DESTINATION) &&
+ strcmp (rule->destination, name) == 0))
+ {
+ bus_matchmaker_remove_rule_link (matchmaker, link);
+ }
+ }
+
+ link = next;
+ }
+}
+
+static dbus_bool_t
+connection_is_primary_owner (DBusConnection *connection,
+ const char *service_name)
+{
+ BusService *service;
+ DBusString str;
+ BusRegistry *registry;
+
+ registry = bus_connection_get_registry (connection);
+
+ _dbus_string_init_const (&str, service_name);
+ service = bus_registry_lookup (registry, &str);
+
+ if (service == NULL)
+ return FALSE; /* Service doesn't exist so connection can't own it. */
+
+ return bus_service_get_primary_owner (service) == connection;
+}
+
+static dbus_bool_t
+match_rule_matches (BusMatchRule *rule,
+ BusConnections *connections,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusMessage *message)
+{
+ /* All features of the match rule are AND'd together,
+ * so FALSE if any of them don't match.
+ */
+
+ if (rule->flags & BUS_MATCH_MESSAGE_TYPE)
+ {
+ _dbus_assert (rule->message_type != DBUS_MESSAGE_TYPE_INVALID);
+
+ if (rule->message_type != dbus_message_get_type (message))
+ return FALSE;
+ }
+
+ if (rule->flags & BUS_MATCH_INTERFACE)
+ {
+ const char *iface;
+
+ _dbus_assert (rule->interface != NULL);
+
+ iface = dbus_message_get_interface (message);
+ if (iface == NULL)
+ return FALSE;
+
+ if (strcmp (iface, rule->interface) != 0)
+ return FALSE;
+ }
+
+ if (rule->flags & BUS_MATCH_MEMBER)
+ {
+ const char *member;
+
+ _dbus_assert (rule->member != NULL);
+
+ member = dbus_message_get_member (message);
+ if (member == NULL)
+ return FALSE;
+
+ if (strcmp (member, rule->member) != 0)
+ return FALSE;
+ }
+
+ if (rule->flags & BUS_MATCH_SENDER)
+ {
+ _dbus_assert (rule->sender != NULL);
+
+ if (!connection_is_primary_owner (sender, rule->sender))
+ return FALSE;
+ }
+
+ if (rule->flags & BUS_MATCH_DESTINATION)
+ {
+ const char *destination;
+
+ _dbus_assert (rule->destination != NULL);
+
+ if (addressed_recipient == NULL)
+ return FALSE;
+
+ destination = dbus_message_get_destination (message);
+ if (destination == NULL)
+ return FALSE;
+
+ if (!connection_is_primary_owner (addressed_recipient, rule->destination))
+ return FALSE;
+ }
+
+ if (rule->flags & BUS_MATCH_PATH)
+ {
+ const char *path;
+
+ _dbus_assert (rule->path != NULL);
+
+ path = dbus_message_get_path (message);
+ if (path == NULL)
+ return FALSE;
+
+ if (strcmp (path, rule->path) != 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+dbus_bool_t
+bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
+ BusConnections *connections,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusMessage *message,
+ DBusList **recipients_p)
+{
+ /* FIXME for now this is a wholly unoptimized linear search */
+ /* Guessing the important optimization is to skip the signal-related
+ * match lists when processing method call and exception messages.
+ * So separate match rule lists for signals?
+ */
+
+ DBusList *link;
+
+ _dbus_assert (*recipients_p == NULL);
+
+ /* This avoids sending same message to the same connection twice.
+ * Purpose of the stamp instead of a bool is to avoid iterating over
+ * all connections resetting the bool each time.
+ */
+ bus_connections_increment_stamp (connections);
+
+ /* addressed_recipient is already receiving the message, don't add to list.
+ * NULL addressed_recipient means either bus driver, or this is a signal
+ * and thus lacks a specific addressed_recipient.
+ */
+ if (addressed_recipient != NULL)
+ bus_connection_mark_stamp (addressed_recipient);
+
+ link = _dbus_list_get_first_link (&matchmaker->all_rules);
+ while (link != NULL)
+ {
+ BusMatchRule *rule;
+
+ rule = link->data;
+
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ {
+ char *s = match_rule_to_string (rule);
+
+ _dbus_verbose ("Checking whether message matches rule %s for connection %p\n",
+ s, rule->matches_go_to);
+ dbus_free (s);
+ }
+#endif
+
+ if (match_rule_matches (rule, connections,
+ sender, addressed_recipient, message))
+ {
+ _dbus_verbose ("Rule matched\n");
+
+ /* Append to the list if we haven't already */
+ if (bus_connection_mark_stamp (rule->matches_go_to))
+ {
+ if (!_dbus_list_append (recipients_p, rule->matches_go_to))
+ goto nomem;
+ }
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+ else
+ {
+ _dbus_verbose ("Connection already receiving this message, so not adding again\n");
+ }
+#endif /* DBUS_ENABLE_VERBOSE_MODE */
+ }
+
+ link = _dbus_list_get_next_link (&matchmaker->all_rules, link);
+ }
+
+ return TRUE;
+
+ nomem:
+ _dbus_list_clear (recipients_p);
+ return FALSE;
+}
+
+#ifdef DBUS_BUILD_TESTS
+#include "test.h"
+
+dbus_bool_t
+bus_signals_test (const DBusString *test_data_dir)
+{
+ BusMatchmaker *matchmaker;
+
+ matchmaker = bus_matchmaker_new ();
+ bus_matchmaker_ref (matchmaker);
+ bus_matchmaker_unref (matchmaker);
+ bus_matchmaker_unref (matchmaker);
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
+
diff --git a/bus/signals.h b/bus/signals.h
new file mode 100644
index 00000000..fab018ae
--- /dev/null
+++ b/bus/signals.h
@@ -0,0 +1,83 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* signals.h Bus signal connection implementation
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef BUS_SIGNALS_H
+#define BUS_SIGNALS_H
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-string.h>
+#include <dbus/dbus-sysdeps.h>
+#include "connection.h"
+
+typedef enum
+{
+ BUS_MATCH_MESSAGE_TYPE = 1 << 0,
+ BUS_MATCH_INTERFACE = 1 << 1,
+ BUS_MATCH_MEMBER = 1 << 2,
+ BUS_MATCH_SENDER = 1 << 3,
+ BUS_MATCH_DESTINATION = 1 << 4,
+ BUS_MATCH_PATH = 1 << 5
+} BusMatchFlags;
+
+BusMatchRule* bus_match_rule_new (DBusConnection *matches_go_to);
+void bus_match_rule_ref (BusMatchRule *rule);
+void bus_match_rule_unref (BusMatchRule *rule);
+
+dbus_bool_t bus_match_rule_set_message_type (BusMatchRule *rule,
+ int type);
+dbus_bool_t bus_match_rule_set_interface (BusMatchRule *rule,
+ const char *interface);
+dbus_bool_t bus_match_rule_set_member (BusMatchRule *rule,
+ const char *member);
+dbus_bool_t bus_match_rule_set_sender (BusMatchRule *rule,
+ const char *sender);
+dbus_bool_t bus_match_rule_set_destination (BusMatchRule *rule,
+ const char *destination);
+dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule,
+ const char *path);
+
+BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to,
+ const DBusString *rule_text,
+ DBusError *error);
+
+BusMatchmaker* bus_matchmaker_new (void);
+void bus_matchmaker_ref (BusMatchmaker *matchmaker);
+void bus_matchmaker_unref (BusMatchmaker *matchmaker);
+
+dbus_bool_t bus_matchmaker_add_rule (BusMatchmaker *matchmaker,
+ BusMatchRule *rule);
+dbus_bool_t bus_matchmaker_remove_rule_by_value (BusMatchmaker *matchmaker,
+ BusMatchRule *value,
+ DBusError *error);
+void bus_matchmaker_remove_rule (BusMatchmaker *matchmaker,
+ BusMatchRule *rule);
+void bus_matchmaker_disconnected (BusMatchmaker *matchmaker,
+ DBusConnection *disconnected);
+dbus_bool_t bus_matchmaker_get_recipients (BusMatchmaker *matchmaker,
+ BusConnections *connections,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+ DBusMessage *message,
+ DBusList **recipients_p);
+
+#endif /* BUS_SIGNALS_H */
diff --git a/bus/system.conf.in b/bus/system.conf.in
index 476a87a6..8e2dbda9 100644
--- a/bus/system.conf.in
+++ b/bus/system.conf.in
@@ -34,16 +34,16 @@
<policy context="default">
<!-- Deny everything then punch holes -->
- <deny send="*"/>
- <deny receive="*"/>
+ <deny send_interface="*"/>
+ <deny receive_interface="*"/>
<deny own="*"/>
<!-- But allow all users to connect -->
<allow user="*"/>
<!-- Allow anyone to talk to the message bus -->
<!-- FIXME I think currently these allow rules are always implicit
even if they aren't in here -->
- <allow send_to="org.freedesktop.DBus"/>
- <allow receive_from="org.freedesktop.DBus"/>
+ <allow send_destination="org.freedesktop.DBus"/>
+ <allow receive_sender="org.freedesktop.DBus"/>
</policy>
<!-- Config files are placed here that among other things, punch
diff --git a/bus/test-main.c b/bus/test-main.c
index c433075f..3f280d4e 100644
--- a/bus/test-main.c
+++ b/bus/test-main.c
@@ -89,6 +89,12 @@ main (int argc, char **argv)
check_memleaks (argv[0]);
+ printf ("%s: Running signals test\n", argv[0]);
+ if (!bus_signals_test (&test_data_dir))
+ die ("signals");
+
+ check_memleaks (argv[0]);
+
printf ("%s: Running SHA1 connection test\n", argv[0]);
if (!bus_dispatch_sha1_test (&test_data_dir))
die ("sha1");
diff --git a/bus/test.c b/bus/test.c
index 30cbcd05..b48ba0fe 100644
--- a/bus/test.c
+++ b/bus/test.c
@@ -102,11 +102,15 @@ remove_client_timeout (DBusTimeout *timeout,
}
static DBusHandlerResult
-client_disconnect_handler (DBusMessageHandler *handler,
- DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
+client_disconnect_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
{
+ if (!dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+ "Disconnected"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
_dbus_verbose ("Removing client %p in disconnect handler\n",
connection);
@@ -120,42 +124,19 @@ client_disconnect_handler (DBusMessageHandler *handler,
client_loop = NULL;
}
- return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-}
-
-static dbus_int32_t handler_slot = -1;
-
-static void
-free_handler (void *data)
-{
- DBusMessageHandler *handler = data;
-
- dbus_message_handler_unref (handler);
- dbus_connection_free_data_slot (&handler_slot);
+ return DBUS_HANDLER_RESULT_HANDLED;
}
dbus_bool_t
bus_setup_debug_client (DBusConnection *connection)
{
- DBusMessageHandler *disconnect_handler;
- const char *to_handle[] = { DBUS_MESSAGE_LOCAL_DISCONNECT };
- dbus_bool_t retval;
-
- disconnect_handler = dbus_message_handler_new (client_disconnect_handler,
- NULL, NULL);
+ dbus_bool_t retval;
- if (disconnect_handler == NULL)
+ if (!dbus_connection_add_filter (connection,
+ client_disconnect_filter,
+ NULL, NULL))
return FALSE;
- if (!dbus_connection_register_handler (connection,
- disconnect_handler,
- to_handle,
- _DBUS_N_ELEMENTS (to_handle)))
- {
- dbus_message_handler_unref (disconnect_handler);
- return FALSE;
- }
-
retval = FALSE;
if (client_loop == NULL)
@@ -182,25 +163,15 @@ bus_setup_debug_client (DBusConnection *connection)
if (!_dbus_list_append (&clients, connection))
goto out;
-
- if (!dbus_connection_allocate_data_slot (&handler_slot))
- goto out;
-
- /* Set up handler to be destroyed */
- if (!dbus_connection_set_data (connection, handler_slot,
- disconnect_handler,
- free_handler))
- {
- dbus_connection_free_data_slot (&handler_slot);
- goto out;
- }
retval = TRUE;
out:
if (!retval)
{
- dbus_message_handler_unref (disconnect_handler); /* unregisters it */
+ dbus_connection_remove_filter (connection,
+ client_disconnect_filter,
+ NULL);
dbus_connection_set_watch_functions (connection,
NULL, NULL, NULL, NULL, NULL);
diff --git a/bus/test.h b/bus/test.h
index 36a69e6c..fc972fe3 100644
--- a/bus/test.h
+++ b/bus/test.h
@@ -36,6 +36,7 @@ dbus_bool_t bus_dispatch_test (const DBusString *test_data_d
dbus_bool_t bus_dispatch_sha1_test (const DBusString *test_data_dir);
dbus_bool_t bus_policy_test (const DBusString *test_data_dir);
dbus_bool_t bus_config_parser_test (const DBusString *test_data_dir);
+dbus_bool_t bus_signals_test (const DBusString *test_data_dir);
dbus_bool_t bus_setup_debug_client (DBusConnection *connection);
void bus_test_clients_foreach (BusConnectionForeachFunction function,
void *data);
diff --git a/configure.in b/configure.in
index 0a5928a2..9665cb03 100644
--- a/configure.in
+++ b/configure.in
@@ -24,6 +24,7 @@ AC_HEADER_STDC
AC_ARG_ENABLE(qt, [ --enable-qt enable Qt-friendly client library],enable_qt=$enableval,enable_qt=auto)
AC_ARG_ENABLE(glib, [ --enable-glib enable GLib-friendly client library],enable_glib=$enableval,enable_glib=auto)
+AC_ARG_ENABLE(gtk, [ --enable-gtk enable GTK-requiring executables],enable_gtk=$enableval,enable_gtk=auto)
AC_ARG_ENABLE(tests, [ --enable-tests enable unit test code],enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE)
AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no)
AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
@@ -34,6 +35,8 @@ AC_ARG_ENABLE(gcov, [ --enable-gcov compile with coverage p
AC_ARG_ENABLE(abstract-sockets, [ --enable-abstract-sockets use abstract socket namespace (linux only)],enable_abstract_sockets=$enableval,enable_abstract_sockets=auto)
AC_ARG_ENABLE(gcj, [ --enable-gcj build gcj bindings],enable_gcj=$enableval,enable_gcj=no)
AC_ARG_ENABLE(mono, [ --enable-mono build mono bindings],enable_mono=$enableval,enable_mono=no)
+AC_ARG_ENABLE(python, [ --enable-python build python bindings],enable_python=$enableval,enable_python=auto)
+
AC_ARG_WITH(xml, [ --with-xml=[libxml/expat] XML library to use])
AC_ARG_WITH(init-scripts, [ --with-init-scripts=[redhat] Style of init scripts to install])
@@ -54,9 +57,11 @@ if test x$enable_verbose_mode = xyes; then
fi
if test x$enable_asserts = xno; then
AC_DEFINE(DBUS_DISABLE_ASSERT,1,[Disable assertion checking])
+ AC_DEFINE(G_DISABLE_ASSERT,1,[Disable GLib assertion macros])
fi
if test x$enable_checks = xno; then
AC_DEFINE(DBUS_DISABLE_CHECKS,1,[Disable public API sanity checking])
+ AC_DEFINE(G_DISABLE_CHECKS,1,[Disable GLib public API sanity checking])
fi
#### gcc warning flags
@@ -545,7 +550,7 @@ AC_SUBST(DBUS_TEST_CFLAGS)
AC_SUBST(DBUS_TEST_LIBS)
# Glib detection
-PKG_CHECK_MODULES(DBUS_GLIB, glib-2.0, have_glib=yes, have_glib=no)
+PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0, have_glib=yes, have_glib=no)
PKG_CHECK_MODULES(DBUS_GLIB_THREADS, glib-2.0 gthread-2.0, have_glib_threads=yes, have_glib_threads=no)
if test x$have_glib = xno ; then
@@ -570,6 +575,39 @@ AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
AC_SUBST(DBUS_GLIB_THREADS_LIBS)
+DBUS_GLIB_TOOL_CFLAGS=$XML_CFLAGS
+DBUS_GLIB_TOOL_LIBS=$XML_LIBS
+AC_SUBST(DBUS_GLIB_TOOL_CFLAGS)
+AC_SUBST(DBUS_GLIB_TOOL_LIBS)
+
+# GTK detection
+if test x$have_glib = xno ; then
+ AC_MSG_WARN([Can't use GTK+ since GLib not enabled])
+ have_gtk=no
+else
+ PKG_CHECK_MODULES(DBUS_GTK, gtk+-2.0, have_gtk=yes, have_gtk=no)
+fi
+
+if test x$have_gtk = xno ; then
+ AC_MSG_WARN([GTK+ development libraries not found])
+fi
+
+if test x$enable_gtk = xyes; then
+ if test x$have_gtk = xno; then
+ AC_MSG_ERROR([GTK+ explicitly required, and GTK+ development libraries not found])
+ fi
+fi
+
+if test x$enable_gtk = xno; then
+ have_gtk=no;
+fi
+
+AM_CONDITIONAL(HAVE_GTK, test x$have_gtk = xyes)
+
+dnl Gtk flags
+AC_SUBST(DBUS_GTK_CFLAGS)
+AC_SUBST(DBUS_GTK_LIBS)
+
# Qt detection
have_qt=no
AC_MSG_CHECKING([for qglobal.h])
@@ -812,6 +850,42 @@ fi
AC_DEFINE_UNQUOTED(DBUS_SESSION_SOCKET_DIR, "$DBUS_SESSION_SOCKET_DIR", [Where per-session bus puts its sockets])
AC_SUBST(DBUS_SESSION_SOCKET_DIR)
+# Detect if we can build Python bindings (need python, python headers, and pyrex)
+if test x$enable_python = xno; then
+ have_python=no
+else
+ AC_MSG_NOTICE([Checking to see if we can build Python bindings])
+ have_python=no
+ AM_PATH_PYTHON(2.2)
+
+ if test -z "$PYTHON" ; then
+ AC_MSG_WARN([Python not found])
+ else
+ AC_CHECK_PROGS(PYREX, pyrexc)
+
+ if test -z "$PYREX" ; then
+ have_pyrex=no
+ else
+ have_pyrex=yes
+ fi
+
+ AM_CHECK_PYTHON_HEADERS(have_python_headers=yes,have_python_headers=no)
+
+ if test x$have_pyrex = xyes -a x$have_python_headers = xyes ; then
+ have_python=yes
+ fi
+ fi
+
+ if test x$have_python = xno ; then
+ if test x$enable_python = xyes ; then
+ AC_MSG_ERROR([Building python explicitly requested, but can't build python bindings])
+ else
+ AC_MSG_WARN([Couldn't find either Pyrex or the Python headers, not building Python bindings])
+ fi
+ fi
+fi
+
+AM_CONDITIONAL(HAVE_PYTHON, test x$have_python = xyes)
AC_OUTPUT([
@@ -824,6 +898,7 @@ bus/dbus-daemon-1.1
Makefile
dbus/Makefile
glib/Makefile
+python/Makefile
qt/Makefile
gcj/Makefile
gcj/org/Makefile
@@ -833,6 +908,7 @@ mono/Makefile
bus/Makefile
tools/Makefile
test/Makefile
+test/glib/Makefile
doc/Makefile
dbus-1.pc
dbus-glib-1.pc
@@ -863,6 +939,7 @@ echo "
cflags: ${CFLAGS}
cppflags: ${CPPFLAGS}
cxxflags: ${CXXFLAGS}
+ 64-bit int: ${DBUS_INT64_TYPE}
Doxygen: ${DOXYGEN}
db2html: ${DB2HTML}"
@@ -895,6 +972,8 @@ echo "
Building checks: ${enable_checks}
Building Qt bindings: ${have_qt}
Building GLib bindings: ${have_glib}
+ Building Python bindings: ${have_python}
+ Building GTK+ tools: ${have_gtk}
Building X11 code: ${enable_x11}
Building documentation: ${enable_docs}
Using XML parser: ${with_xml}
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
index b5fc26ff..dc49ec81 100644
--- a/dbus/Makefile.am
+++ b/dbus/Makefile.am
@@ -15,7 +15,7 @@ dbusinclude_HEADERS= \
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_LIB_SOURCES= \
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 \
diff --git a/dbus/dbus-address.c b/dbus/dbus-address.c
index bf9dbc3b..97af49fd 100644
--- a/dbus/dbus-address.c
+++ b/dbus/dbus-address.c
@@ -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_address_entry_free (DBusAddressEntry *entry)
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 @@ dbus_parse_address (const char *address,
}
-/** @} */
+/** @} */ /* End of public API */
#ifdef DBUS_BUILD_TESTS
#include "dbus-test.h"
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index b496dba0..cdfd3bb2 100644
--- a/dbus/dbus-auth.c
+++ b/dbus/dbus-auth.c
@@ -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 @@ typedef dbus_bool_t (* DBusProcessAuthCommandFunction) (DBusAuth *auth,
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 dbus_bool_t (* DBusAuthDecodeFunction) (DBusAuth *auth,
*/
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 @@ struct DBusAuth
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 @@ process_test_subdir (const DBusString *test_base_dir,
goto failed;
}
- printf ("Testing:\n");
+ printf ("Testing %s:\n", subdir);
next:
while (_dbus_directory_get_next_file (dir, &filename, &error))
diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c
index 865811fd..0c9f58e1 100644
--- a/dbus/dbus-bus.c
+++ b/dbus/dbus-bus.c
@@ -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_bus_get (DBusBusType type,
_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 @@ dbus_bus_register (DBusConnection *connection,
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_bus_acquire_service (DBusConnection *connection,
_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_bus_service_exists (DBusConnection *connection,
_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 @@ dbus_bus_activate_service (DBusConnection *connection,
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 @@ dbus_bus_activate_service (DBusConnection *connection,
}
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 @@ dbus_bus_activate_service (DBusConnection *connection,
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);
+}
/** @} */
diff --git a/dbus/dbus-bus.h b/dbus/dbus-bus.h
index a62a746b..072b0c8e 100644
--- a/dbus/dbus-bus.h
+++ b/dbus/dbus-bus.h
@@ -59,6 +59,13 @@ dbus_bool_t dbus_bus_activate_service (DBusConnection *connection,
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 */
diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h
index 5ddc0e0a..b19ab636 100644
--- a/dbus/dbus-connection-internal.h
+++ b/dbus/dbus-connection-internal.h
@@ -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 @@ typedef enum
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 @@ void _dbus_connection_do_iteration (DBusConnection
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 */
diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
index 01b2a7bf..ed7d57d0 100644
--- a/dbus/dbus-connection.c
+++ b/dbus/dbus-connection.c
@@ -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 @@ struct DBusConnection
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 @@ struct DBusConnection
DBusList *link_cache; /**< A cache of linked list links to prevent contention
* for the global linked list mempool lock
*/
-};
+ DBusObjectTree *objects; /**< Object path handlers registered with this connection */
-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;
-
-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 @@ void
_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 @@ _dbus_connection_queue_received_message_link (DBusConnection *connection,
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_queue_received_message_link (DBusConnection *connection,
_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 @@ _dbus_connection_message_sent (DBusConnection *connection,
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 @@ _dbus_connection_notify_disconnected (DBusConnection *connection)
}
}
+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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
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 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
if (outgoing_counter)
_dbus_counter_unref (outgoing_counter);
+
+ if (objects)
+ _dbus_object_tree_unref (objects);
return NULL;
}
@@ -825,6 +980,39 @@ _dbus_connection_ref_unlocked (DBusConnection *connection)
#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 @@ _dbus_connection_get_next_client_serial (DBusConnection *connection)
}
/**
- * 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 @@ free_outgoing_message (void *element,
static void
_dbus_connection_last_unref (DBusConnection *connection)
{
- DBusHashIter iter;
DBusList *link;
_dbus_verbose ("Finalizing connection %p\n", connection);
@@ -1032,6 +1175,8 @@ _dbus_connection_last_unref (DBusConnection *connection)
_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 @@ _dbus_connection_last_unref (DBusConnection *connection)
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 @@ dbus_connection_get_is_authenticated (DBusConnection *connection)
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_connection_send_preallocated_unlocked (DBusConnection *connection,
_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_connection_send_preallocated (DBusConnection *connection,
_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 @@ dbus_connection_send_preallocated (DBusConnection *connection,
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 @@ dbus_connection_send (DBusConnection *connection,
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 @@ reply_handler_timeout (void *data)
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.
- *
- * 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
+ * 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.
+ *
+ * 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 @@ reply_handler_data_free (ReplyHandlerData *data)
*
* @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 @@ reply_handler_data_free (ReplyHandlerData *data)
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_connection_send_with_reply (DBusConnection *connection,
_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 @@ dbus_connection_send_with_reply (DBusConnection *connection,
{
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 @@ check_for_reply_unlocked (DBusConnection *connection,
}
/**
- * 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 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
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 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
{
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_connection_send_with_reply_and_block (DBusConnection *connection,
_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 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
}
/**
+ * 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 @@ dbus_connection_borrow_message (DBusConnection *connection)
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_connection_return_message (DBusConnection *connection,
{
_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_connection_steal_borrowed_message (DBusConnection *connection,
_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 @@ _dbus_connection_pop_message_link_unlocked (DBusConnection *connection)
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 @@ _dbus_connection_pop_message_unlocked (DBusConnection *connection)
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 @@ dbus_connection_get_dispatch_status (DBusConnection *connection)
* 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 @@ dbus_connection_dispatch (DBusConnection *connection)
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_connection_dispatch (DBusConnection *connection)
}
_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 @@ dbus_connection_dispatch (DBusConnection *connection)
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 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
}
/**
- * 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;
diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h
index 9f4dd7ae..aa92b30a 100644
--- a/dbus/dbus-connection.h
+++ b/dbus/dbus-connection.h
@@ -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 @@ typedef enum
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 @@ typedef dbus_bool_t (* DBusAllowUnixUserFunction) (DBusConnection *connection,
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_unref (DBusConnection
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_bool_t dbus_connection_send (DBusConnection
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 @@ void dbus_timeout_set_data (DBusTimeout *timeout,
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 @@ void dbus_connection_send_preallocated (DBusConnection
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 */
diff --git a/dbus/dbus-dataslot.h b/dbus/dbus-dataslot.h
index 6f591eb5..c4a914b4 100644
--- a/dbus/dbus-dataslot.h
+++ b/dbus/dbus-dataslot.h
@@ -40,12 +40,18 @@ struct DBusDataSlot
};
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 @@ struct DBusDataSlotAllocator
DBusMutex *lock; /**< thread lock */
};
+/**
+ * Data structure that stores the actual user data set at a given
+ * slot.
+ */
struct DBusDataSlotList
{
DBusDataSlot *slots; /**< Data slots */
diff --git a/dbus/dbus-errors.c b/dbus/dbus-errors.c
index 3cf52363..f7b2f740 100644
--- a/dbus/dbus-errors.c
+++ b/dbus/dbus-errors.c
@@ -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 @@ message_from_error (const char *error)
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 @@ dbus_error_is_set (const DBusError *error)
*
* @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 @@ dbus_set_error (DBusError *error,
...)
{
DBusRealError *real;
+ DBusString str;
va_list args;
- int message_length;
- char *message;
- char c;
-
+
if (error == NULL)
return;
@@ -321,31 +328,46 @@ dbus_set_error (DBusError *error,
_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 */
diff --git a/dbus/dbus-errors.h b/dbus/dbus-errors.h
index 8d8e16ec..f229188a 100644
--- a/dbus/dbus-errors.h
+++ b/dbus/dbus-errors.h
@@ -35,6 +35,9 @@ DBUS_BEGIN_DECLS;
typedef struct DBusError DBusError;
+/**
+ * Object representing an exception.
+ */
struct DBusError
{
const char *name; /**< error name */
@@ -50,13 +53,8 @@ struct DBusError
};
#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 @@ struct DBusError
#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);
diff --git a/dbus/dbus-hash.c b/dbus/dbus-hash.c
index 2c410010..d35087b4 100644
--- a/dbus/dbus-hash.c
+++ b/dbus/dbus-hash.c
@@ -221,26 +221,32 @@ typedef struct
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 @@ _dbus_hash_table_new (DBusHashType type,
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 @@ _dbus_hash_iter_get_string_key (DBusHashIter *iter)
}
/**
+ * 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 @@ add_entry (DBusHashTable *table,
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 @@ find_string_function (DBusHashTable *table,
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 @@ rebuild_table (DBusHashTable *table)
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 @@ _dbus_hash_table_lookup_string (DBusHashTable *table,
}
/**
+ * 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 @@ _dbus_hash_table_remove_string (DBusHashTable *table,
* @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 @@ _dbus_hash_table_insert_string (DBusHashTable *table,
* @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 @@ count_entries (DBusHashTable *table)
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 @@ _dbus_hash_test (void)
DBusHashTable *table1;
DBusHashTable *table2;
DBusHashTable *table3;
+ DBusHashTable *table4;
DBusHashIter iter;
#define N_HASH_KEYS 5000
char **keys;
@@ -1569,7 +1741,16 @@ _dbus_hash_test (void)
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 @@ _dbus_hash_test (void)
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 @@ _dbus_hash_test (void)
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 @@ _dbus_hash_test (void)
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_test (void)
_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_test (void)
_dbus_hash_table_ref (table1);
_dbus_hash_table_ref (table2);
_dbus_hash_table_ref (table3);
+ _dbus_hash_table_ref (table4);
_dbus_hash_table_unref (table1);
_dbus_hash_table_unref (table2);
_dbus_hash_table_unref (table3);
+ _dbus_hash_table_unref (table4);
_dbus_hash_table_unref (table1);
_dbus_hash_table_unref (table2);
_dbus_hash_table_unref (table3);
+ _dbus_hash_table_unref (table4);
table3 = NULL;
/* Insert a bunch of stuff then check
diff --git a/dbus/dbus-hash.h b/dbus/dbus-hash.h
index 566d4021..5e7515f9 100644
--- a/dbus/dbus-hash.h
+++ b/dbus/dbus-hash.h
@@ -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 struct DBusHashIter DBusHashIter;
*/
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;
diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c
index 6e7f9e16..cf1cc391 100644
--- a/dbus/dbus-internals.c
+++ b/dbus/dbus-internals.c
@@ -248,7 +248,7 @@ _dbus_verbose_reset_real (void)
char*
_dbus_strdup (const char *str)
{
- int len;
+ size_t len;
char *copy;
if (str == NULL)
@@ -266,6 +266,29 @@ _dbus_strdup (const char *str)
}
/**
+ * 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 @@ _dbus_type_to_string (int type)
}
}
+/**
+ * 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";
diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h
index d84017d7..fa1ad19c 100644
--- a/dbus/dbus-internals.h
+++ b/dbus/dbus-internals.h
@@ -144,6 +144,8 @@ extern const char _dbus_return_if_fail_warning_format[];
((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 @@ void _dbus_verbose_bytes_of_string (const DBusString *str,
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 @@ extern int _dbus_current_generation;
_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);
diff --git a/dbus/dbus-keyring.c b/dbus/dbus-keyring.c
index b5974af0..e091d801 100644
--- a/dbus/dbus-keyring.c
+++ b/dbus/dbus-keyring.c
@@ -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 */
diff --git a/dbus/dbus-mainloop.c b/dbus/dbus-mainloop.c
index 51eb7b0d..6da5318c 100644
--- a/dbus/dbus-mainloop.c
+++ b/dbus/dbus-mainloop.c
@@ -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_wait_for_memory (void)
_dbus_sleep_milliseconds (_dbus_get_oom_wait ());
}
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/dbus/dbus-mainloop.h b/dbus/dbus-mainloop.h
index ac5731f5..8a3cde13 100644
--- a/dbus/dbus-mainloop.h
+++ b/dbus/dbus-mainloop.h
@@ -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 @@ dbus_bool_t _dbus_loop_dispatch (DBusLoop *loop);
int _dbus_get_oom_wait (void);
void _dbus_wait_for_memory (void);
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+
#endif /* DBUS_MAINLOOP_H */
+
diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c
index 5d7290e3..cb989891 100644
--- a/dbus/dbus-marshal.c
+++ b/dbus/dbus-marshal.c
@@ -73,13 +73,17 @@ swap_bytes (unsigned char *data,
}
#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 @@ unpack_8_octets (int byte_order,
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 @@ _dbus_marshal_set_uint64 (DBusString *str,
* 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 @@ _dbus_marshal_set_string (DBusString *str,
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 @@ marshal_8_octets_array (DBusString *str,
#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 @@ _dbus_marshal_string_array (DBusString *str,
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 @@ demarshal_8_octets_array (const DBusString *str,
#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 @@ _dbus_demarshal_string_array (const DBusString *str,
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 @@ _dbus_marshal_get_arg_end_pos (const DBusString *str,
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 @@ validate_array_data (const DBusString *str,
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 @@ validate_array_data (const DBusString *str,
* 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 @@ _dbus_marshal_validate_arg (const DBusString *str,
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 @@ _dbus_marshal_validate_arg (const DBusString *str,
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 @@ _dbus_marshal_validate_arg (const DBusString *str,
}
break;
+ case DBUS_TYPE_OBJECT_PATH:
case DBUS_TYPE_STRING:
{
int len;
@@ -1887,6 +2041,12 @@ _dbus_marshal_validate_arg (const DBusString *str,
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 @@ _dbus_marshal_test (void)
s = _dbus_demarshal_string (&str, DBUS_BIG_ENDIAN, 0, NULL);
_dbus_assert (strcmp (s, "Hello") == 0);
dbus_free (s);
-
_dbus_string_free (&str);
diff --git a/dbus/dbus-marshal.h b/dbus/dbus-marshal.h
index 1eff8995..27ded007 100644
--- a/dbus/dbus-marshal.h
+++ b/dbus/dbus-marshal.h
@@ -152,11 +152,17 @@ void _dbus_marshal_set_uint64 (DBusString *str,
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 @@ dbus_bool_t _dbus_marshal_string_array (DBusString *str,
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 @@ dbus_bool_t _dbus_demarshal_string_array (const DBusString *str,
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,
diff --git a/dbus/dbus-md5.h b/dbus/dbus-md5.h
index 63fc62e8..e31711dd 100644
--- a/dbus/dbus-md5.h
+++ b/dbus/dbus-md5.h
@@ -31,11 +31,14 @@ DBUS_BEGIN_DECLS;
typedef struct DBusMD5Context DBusMD5Context;
+/**
+ * A context used to store the state of the MD5 algorithm
+ */
struct DBusMD5Context
{
- dbus_uint32_t count[2]; /* message length in bits, lsw first */
- dbus_uint32_t abcd[4]; /* digest buffer */
- unsigned char buf[64]; /* accumulate block */
+ 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);
diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c
index 390dda75..c9dc8ca5 100644
--- a/dbus/dbus-message-builder.c
+++ b/dbus/dbus-message-builder.c
@@ -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 @@ append_saved_length (DBusString *dest,
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 @@ append_saved_length (DBusString *dest,
*
* 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 @@ append_saved_length (DBusString *dest,
* (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 @@ append_saved_length (DBusString *dest,
* 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 @@ _dbus_message_data_load (DBusString *dest,
{
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 @@ _dbus_message_data_load (DBusString *dest,
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 @@ _dbus_message_data_load (DBusString *dest,
}
}
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 @@ _dbus_message_data_load (DBusString *dest,
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 @@ _dbus_message_data_load (DBusString *dest,
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 @@ _dbus_message_data_load (DBusString *dest,
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;
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index e74191f8..19457468 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -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 @@ struct DBusMessage
* 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 @@ append_header_padding (DBusMessage *message)
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 @@ get_int_field (DBusMessage *message,
{
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 @@ get_uint_field (DBusMessage *message,
{
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 @@ get_string_field (DBusMessage *message,
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 @@ get_string_field (DBusMessage *message,
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 @@ append_int_field (DBusMessage *message,
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 @@ append_int_field (DBusMessage *message,
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 @@ append_int_field (DBusMessage *message,
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 @@ append_uint_field (DBusMessage *message,
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 @@ append_uint_field (DBusMessage *message,
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 @@ append_uint_field (DBusMessage *message,
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 @@ append_string_field (DBusMessage *message,
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 @@ append_string_field (DBusMessage *message,
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;
+
+ /* 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;
+ }
- append_header_padding (message);
+ 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);
+
+ 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;
- append_header_padding (message);
+ _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 @@ set_int_field (DBusMessage *message,
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 @@ set_uint_field (DBusMessage *message,
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 @@ set_uint_field (DBusMessage *message,
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 @@ set_string_field (DBusMessage *message,
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_message_set_serial (DBusMessage *message,
{
_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_message_set_reply_serial (DBusMessage *message,
{
_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 @@ _dbus_message_remove_size_counter (DBusMessage *message,
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 @@ dbus_message_create_header (DBusMessage *message,
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 @@ _dbus_message_lock (DBusMessage *message)
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_message_new_empty_header (void)
_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 @@ dbus_message_new_empty_header (void)
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 @@ dbus_message_new (const char *name,
}
/**
- * 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 @@ dbus_message_new_reply (DBusMessage *original_message)
}
/**
+ * 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 @@ dbus_message_new_error_reply (DBusMessage *original_message,
return NULL;
}
}
-
- dbus_message_set_is_error (message, TRUE);
return message;
}
@@ -1129,9 +1379,9 @@ dbus_message_copy (const DBusMessage *message)
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 @@ dbus_message_unref (DBusMessage *message)
}
/**
- * 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 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_path (DBusMessage *message)
+{
+ _dbus_return_val_if_fail (message != NULL, 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
- * @returns the message name (should not be freed)
+ * @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_name (DBusMessage *message)
+dbus_message_get_error_name (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_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_message_get_destination (DBusMessage *message)
{
_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 @@ dbus_message_set_sender (DBusMessage *message,
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_message_get_sender (DBusMessage *message)
{
_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 (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
+ return FALSE;
- if (n && strcmp (n, name) == 0)
+ n = dbus_message_get_error_name (message);
+
+ if (n && strcmp (n, error_name) == 0)
return TRUE;
else
return FALSE;
@@ -3833,7 +4429,7 @@ dbus_message_has_sender (DBusMessage *message,
/**
* 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_set_error_from_message (DBusError *error,
_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_set_error_from_message (DBusError *error,
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 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader,
*/
#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 @@ decode_string_field (const DBusString *data,
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 @@ static dbus_bool_t
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 @@ decode_header_data (const DBusString *data,
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.
+ */
+
+ if (fields[field].name_offset >= 0)
+ {
+ _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_AS_UINT32:
- if (fields[FIELD_REPLY_SERIAL].offset >= 0)
+ case DBUS_HEADER_FIELD_REPLY_SERIAL:
+ if (fields[field].name_offset >= 0)
{
- _dbus_verbose ("%s field provided twice\n",
- DBUS_HEADER_FIELD_REPLY);
+ _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 @@ decode_header_data (const DBusString *data,
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 @@ decode_header_data (const DBusString *data,
}
}
- /* 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 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader,
/**
* 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 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
{
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 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
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 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
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 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
/* 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 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader)
* 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 @@ check_message_handling (DBusMessage *message)
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 @@ process_test_subdir (const DBusString *test_base_dir,
goto failed;
}
- printf ("Testing:\n");
+ printf ("Testing %s:\n", subdir);
next:
while (_dbus_directory_get_next_file (dir, &filename, &error))
@@ -5499,10 +6195,11 @@ process_test_subdir (const DBusString *test_base_dir,
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_message_test (const char *test_data_dir)
_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_message_test (const char *test_data_dir)
_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 @@ _dbus_message_test (const char *test_data_dir)
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);
diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h
index 9f07565c..888fe862 100644
--- a/dbus/dbus-message.h
+++ b/dbus/dbus-message.h
@@ -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 @@ DBUS_BEGIN_DECLS;
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_bool_t dbus_message_set_reply_serial (DBusMessage *message,
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,
...);
diff --git a/dbus/dbus-object-tree.c b/dbus/dbus-object-tree.c
new file mode 100644
index 00000000..07d3ae59
--- /dev/null
+++ b/dbus/dbus-object-tree.c
@@ -0,0 +1,1481 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-object-tree.c DBusObjectTree (internals of DBusConnection)
+ *
+ * Copyright (C) 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "dbus-object-tree.h"
+#include "dbus-connection-internal.h"
+#include "dbus-internals.h"
+#include "dbus-hash.h"
+#include "dbus-protocol.h"
+#include "dbus-string.h"
+#include <string.h>
+#include <stdlib.h>
+
+/**
+ * @defgroup DBusObjectTree A hierarchy of objects with container-contained relationship
+ * @ingroup DBusInternals
+ * @brief DBusObjectTree is used by DBusConnection to track the object tree
+ *
+ * Types and functions related to DBusObjectTree. These
+ * are all library-internal.
+ *
+ * @{
+ */
+
+/** Subnode of the object hierarchy */
+typedef struct DBusObjectSubtree DBusObjectSubtree;
+
+static DBusObjectSubtree* _dbus_object_subtree_new (const char *name,
+ const DBusObjectPathVTable *vtable,
+ void *user_data);
+static void _dbus_object_subtree_ref (DBusObjectSubtree *subtree);
+static void _dbus_object_subtree_unref (DBusObjectSubtree *subtree);
+
+/**
+ * Internals of DBusObjectTree
+ */
+struct DBusObjectTree
+{
+ int refcount; /**< Reference count */
+ DBusConnection *connection; /**< Connection this tree belongs to */
+
+ DBusObjectSubtree *root; /**< Root of the tree ("/" node) */
+};
+
+/**
+ * Struct representing a single registered subtree handler, or node
+ * that's a parent of a registered subtree handler. If
+ * message_function != NULL there's actually a handler at this node.
+ */
+struct DBusObjectSubtree
+{
+ DBusAtomic refcount; /**< Reference count */
+ DBusObjectSubtree *parent; /**< Parent node */
+ DBusObjectPathUnregisterFunction unregister_function; /**< Function to call on unregister */
+ DBusObjectPathMessageFunction message_function; /**< Function to handle messages */
+ void *user_data; /**< Data for functions */
+ DBusObjectSubtree **subtrees; /**< Child nodes */
+ int n_subtrees; /**< Number of child nodes */
+ unsigned int subtrees_sorted : 1; /**< Whether children are sorted */
+ unsigned int invoke_as_fallback : 1; /**< Whether to invoke message_function when child nodes don't handle the message */
+ char name[1]; /**< Allocated as large as necessary */
+};
+
+/**
+ * Creates a new object tree, representing a mapping from paths
+ * to handler vtables.
+ *
+ * @param connection the connection this tree belongs to
+ * @returns the new tree or #NULL if no memory
+ */
+DBusObjectTree*
+_dbus_object_tree_new (DBusConnection *connection)
+{
+ DBusObjectTree *tree;
+
+ /* the connection passed in here isn't fully constructed,
+ * so don't do anything more than store a pointer to
+ * it
+ */
+
+ tree = dbus_new0 (DBusObjectTree, 1);
+ if (tree == NULL)
+ goto oom;
+
+ tree->refcount = 1;
+ tree->connection = connection;
+ tree->root = _dbus_object_subtree_new ("/", NULL, NULL);
+ if (tree->root == NULL)
+ goto oom;
+ tree->root->invoke_as_fallback = TRUE;
+
+ return tree;
+
+ oom:
+ if (tree)
+ {
+ dbus_free (tree);
+ }
+
+ return NULL;
+}
+
+/**
+ * Increment the reference count
+ * @param tree the object tree
+ */
+void
+_dbus_object_tree_ref (DBusObjectTree *tree)
+{
+ _dbus_assert (tree->refcount > 0);
+
+ tree->refcount += 1;
+}
+
+/**
+ * Decrement the reference count
+ * @param tree the object tree
+ */
+void
+_dbus_object_tree_unref (DBusObjectTree *tree)
+{
+ _dbus_assert (tree->refcount > 0);
+
+ tree->refcount -= 1;
+
+ if (tree->refcount == 0)
+ {
+ _dbus_object_tree_free_all_unlocked (tree);
+
+ dbus_free (tree);
+ }
+}
+
+static int
+subtree_cmp (DBusObjectSubtree *subtree_a,
+ DBusObjectSubtree *subtree_b)
+{
+ return strcmp (subtree_a->name, subtree_b->name);
+}
+
+static int
+subtree_qsort_cmp (const void *a,
+ const void *b)
+{
+ DBusObjectSubtree **subtree_a_p = (void*) a;
+ DBusObjectSubtree **subtree_b_p = (void*) b;
+
+ return subtree_cmp (*subtree_a_p, *subtree_b_p);
+}
+
+static void
+ensure_sorted (DBusObjectSubtree *subtree)
+{
+ if (subtree->subtrees && !subtree->subtrees_sorted)
+ {
+ qsort (subtree->subtrees,
+ subtree->n_subtrees,
+ sizeof (DBusObjectSubtree*),
+ subtree_qsort_cmp);
+ subtree->subtrees_sorted = TRUE;
+ }
+}
+
+/** Set to 1 to get a bunch of debug spew about finding the
+ * subtree nodes
+ */
+#define VERBOSE_FIND 0
+
+static DBusObjectSubtree*
+find_subtree_recurse (DBusObjectSubtree *subtree,
+ const char **path,
+ dbus_bool_t return_deepest_match,
+ dbus_bool_t create_if_not_found,
+ int *index_in_parent)
+{
+ int i;
+
+ _dbus_assert (!(return_deepest_match && create_if_not_found));
+
+ if (path[0] == NULL)
+ {
+#if VERBOSE_FIND
+ _dbus_verbose (" path exhausted, returning %s\n",
+ subtree->name);
+#endif
+ return subtree;
+ }
+
+#if VERBOSE_FIND
+ _dbus_verbose (" searching children of %s for %s\n",
+ subtree->name, path[0]);
+#endif
+
+ ensure_sorted (subtree);
+
+ /* FIXME we should do a binary search here instead
+ * of O(n)
+ */
+
+ i = 0;
+ while (i < subtree->n_subtrees)
+ {
+ int v;
+
+ v = strcmp (path[0], subtree->subtrees[i]->name);
+
+#if VERBOSE_FIND
+ _dbus_verbose (" %s cmp %s = %d\n",
+ path[0], subtree->subtrees[i]->name,
+ v);
+#endif
+
+ if (v == 0)
+ {
+ if (index_in_parent)
+ {
+#if VERBOSE_FIND
+ _dbus_verbose (" storing parent index %d\n", i);
+#endif
+ *index_in_parent = i;
+ }
+
+ if (return_deepest_match)
+ {
+ DBusObjectSubtree *next;
+
+ next = find_subtree_recurse (subtree->subtrees[i],
+ &path[1], return_deepest_match,
+ create_if_not_found, index_in_parent);
+ if (next == NULL &&
+ subtree->invoke_as_fallback)
+ {
+#if VERBOSE_FIND
+ _dbus_verbose (" no deeper match found, returning %s\n",
+ subtree->name);
+#endif
+ return subtree;
+ }
+ else
+ return next;
+ }
+ else
+ return find_subtree_recurse (subtree->subtrees[i],
+ &path[1], return_deepest_match,
+ create_if_not_found, index_in_parent);
+ }
+ else if (v < 0)
+ {
+ goto not_found;
+ }
+
+ ++i;
+ }
+
+ not_found:
+#if VERBOSE_FIND
+ _dbus_verbose (" no match found, current tree %s, create_if_not_found = %d\n",
+ subtree->name, create_if_not_found);
+#endif
+
+ if (create_if_not_found)
+ {
+ DBusObjectSubtree* child;
+ DBusObjectSubtree **new_subtrees;
+ int new_n_subtrees;
+
+#if VERBOSE_FIND
+ _dbus_verbose (" creating subtree %s\n",
+ path[0]);
+#endif
+
+ child = _dbus_object_subtree_new (path[0],
+ NULL, NULL);
+ if (child == NULL)
+ return NULL;
+
+ /* FIXME we should do the "double alloc each time" standard thing */
+ new_n_subtrees = subtree->n_subtrees + 1;
+ new_subtrees = dbus_realloc (subtree->subtrees,
+ new_n_subtrees * sizeof (DBusObjectSubtree*));
+ if (new_subtrees == NULL)
+ {
+ child->unregister_function = NULL;
+ child->message_function = NULL;
+ _dbus_object_subtree_unref (child);
+ return FALSE;
+ }
+
+ new_subtrees[subtree->n_subtrees] = child;
+ if (index_in_parent)
+ *index_in_parent = subtree->n_subtrees;
+ subtree->subtrees_sorted = FALSE;
+ subtree->n_subtrees = new_n_subtrees;
+ subtree->subtrees = new_subtrees;
+
+ child->parent = subtree;
+
+ return find_subtree_recurse (child,
+ &path[1], return_deepest_match,
+ create_if_not_found, index_in_parent);
+ }
+ else
+ return (return_deepest_match && subtree->invoke_as_fallback) ? subtree : NULL;
+}
+
+static DBusObjectSubtree*
+find_subtree (DBusObjectTree *tree,
+ const char **path,
+ int *index_in_parent)
+{
+ DBusObjectSubtree *subtree;
+
+#if VERBOSE_FIND
+ _dbus_verbose ("Looking for exact registered subtree\n");
+#endif
+
+ subtree = find_subtree_recurse (tree->root, path, FALSE, FALSE, index_in_parent);
+
+ if (subtree && subtree->message_function == NULL)
+ return NULL;
+ else
+ return subtree;
+}
+
+static DBusObjectSubtree*
+find_handler (DBusObjectTree *tree,
+ const char **path)
+{
+#if VERBOSE_FIND
+ _dbus_verbose ("Looking for deepest handler\n");
+#endif
+ return find_subtree_recurse (tree->root, path, TRUE, FALSE, NULL);
+}
+
+static DBusObjectSubtree*
+ensure_subtree (DBusObjectTree *tree,
+ const char **path)
+{
+#if VERBOSE_FIND
+ _dbus_verbose ("Ensuring subtree\n");
+#endif
+ return find_subtree_recurse (tree->root, path, FALSE, TRUE, NULL);
+}
+
+/**
+ * Registers a new subtree in the global object tree.
+ *
+ * @param tree the global object tree
+ * @param fallback #TRUE to handle messages to children of this path
+ * @param path NULL-terminated array of path elements giving path to subtree
+ * @param vtable the vtable used to traverse this subtree
+ * @param user_data user data to pass to methods in the vtable
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+_dbus_object_tree_register (DBusObjectTree *tree,
+ dbus_bool_t fallback,
+ const char **path,
+ const DBusObjectPathVTable *vtable,
+ void *user_data)
+{
+ DBusObjectSubtree *subtree;
+
+ _dbus_assert (tree != NULL);
+ _dbus_assert (vtable->message_function != NULL);
+ _dbus_assert (path != NULL);
+
+ subtree = ensure_subtree (tree, path);
+ if (subtree == NULL)
+ return FALSE;
+
+#ifndef DBUS_DISABLE_CHECKS
+ if (subtree->message_function != NULL)
+ {
+ _dbus_warn ("A handler is already registered for the path starting with path[0] = \"%s\"\n",
+ path[0] ? path[0] : "null");
+ return FALSE;
+ }
+#else
+ _dbus_assert (subtree->message_function == NULL);
+#endif
+
+ subtree->message_function = vtable->message_function;
+ subtree->unregister_function = vtable->unregister_function;
+ subtree->user_data = user_data;
+ subtree->invoke_as_fallback = fallback != FALSE;
+
+ return TRUE;
+}
+
+/**
+ * Unregisters an object subtree that was registered with the
+ * same path.
+ *
+ * @param tree the global object tree
+ * @param path path to the subtree (same as the one passed to _dbus_object_tree_register())
+ */
+void
+_dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree,
+ const char **path)
+{
+ int i;
+ DBusObjectSubtree *subtree;
+ DBusObjectPathUnregisterFunction unregister_function;
+ void *user_data;
+ DBusConnection *connection;
+
+ _dbus_assert (path != NULL);
+
+ subtree = find_subtree (tree, path, &i);
+
+#ifndef DBUS_DISABLE_CHECKS
+ if (subtree == NULL)
+ {
+ _dbus_warn ("Attempted to unregister path (path[0] = %s path[1] = %s) which isn't registered\n",
+ path[0] ? path[0] : "null",
+ path[1] ? path[1] : "null");
+ return;
+ }
+#else
+ _dbus_assert (subtree != NULL);
+#endif
+
+ _dbus_assert (subtree->parent == NULL ||
+ (i >= 0 && subtree->parent->subtrees[i] == subtree));
+
+ subtree->message_function = NULL;
+
+ unregister_function = subtree->unregister_function;
+ user_data = subtree->user_data;
+
+ subtree->unregister_function = NULL;
+ subtree->user_data = NULL;
+
+ /* If we have no subtrees of our own, remove from
+ * our parent (FIXME could also be more aggressive
+ * and remove our parent if it becomes empty)
+ */
+ if (subtree->parent && subtree->n_subtrees == 0)
+ {
+ /* assumes a 0-byte memmove is OK */
+ memmove (&subtree->parent->subtrees[i],
+ &subtree->parent->subtrees[i+1],
+ (subtree->parent->n_subtrees - i - 1) *
+ sizeof (subtree->parent->subtrees[0]));
+ subtree->parent->n_subtrees -= 1;
+
+ subtree->parent = NULL;
+
+ _dbus_object_subtree_unref (subtree);
+ }
+ subtree = NULL;
+
+ connection = tree->connection;
+
+ /* Unlock and call application code */
+#ifdef DBUS_BUILD_TESTS
+ if (connection)
+#endif
+ {
+ _dbus_connection_ref_unlocked (connection);
+ _dbus_connection_unlock (connection);
+ }
+
+ if (unregister_function)
+ (* unregister_function) (connection, user_data);
+
+#ifdef DBUS_BUILD_TESTS
+ if (connection)
+#endif
+ dbus_connection_unref (connection);
+}
+
+static void
+free_subtree_recurse (DBusConnection *connection,
+ DBusObjectSubtree *subtree)
+{
+ /* Delete them from the end, for slightly
+ * more robustness against odd reentrancy.
+ */
+ while (subtree->n_subtrees > 0)
+ {
+ DBusObjectSubtree *child;
+
+ child = subtree->subtrees[subtree->n_subtrees - 1];
+ subtree->subtrees[subtree->n_subtrees - 1] = NULL;
+ subtree->n_subtrees -= 1;
+ child->parent = NULL;
+
+ free_subtree_recurse (connection, child);
+ }
+
+ /* Call application code */
+ if (subtree->unregister_function)
+ {
+ (* subtree->unregister_function) (connection,
+ subtree->user_data);
+ subtree->message_function = NULL;
+ subtree->unregister_function = NULL;
+ subtree->user_data = NULL;
+ }
+
+ /* Now free ourselves */
+ _dbus_object_subtree_unref (subtree);
+}
+
+/**
+ * Free all the handlers in the tree. Lock on tree's connection
+ * must not be held.
+ *
+ * @param tree the object tree
+ */
+void
+_dbus_object_tree_free_all_unlocked (DBusObjectTree *tree)
+{
+ if (tree->root)
+ free_subtree_recurse (tree->connection,
+ tree->root);
+ tree->root = NULL;
+}
+
+static dbus_bool_t
+_dbus_object_tree_list_registered_unlocked (DBusObjectTree *tree,
+ const char **parent_path,
+ char ***child_entries)
+{
+ DBusObjectSubtree *subtree;
+ char **retval;
+
+ _dbus_assert (parent_path != NULL);
+ _dbus_assert (child_entries != NULL);
+
+ *child_entries = NULL;
+
+ subtree = find_subtree (tree, parent_path, NULL);
+ if (subtree == NULL)
+ {
+ retval = dbus_new0 (char *, 1);
+ if (retval == NULL)
+ goto out;
+ }
+ else
+ {
+ int i;
+ retval = dbus_new0 (char*, subtree->n_subtrees + 1);
+ if (retval == NULL)
+ goto out;
+ i = 0;
+ while (i < subtree->n_subtrees)
+ {
+ retval[i] = _dbus_strdup (subtree->subtrees[i]->name);
+ if (retval[i] == NULL)
+ {
+ dbus_free_string_array (retval);
+ retval = NULL;
+ goto out;
+ }
+ ++i;
+ }
+ }
+
+ out:
+
+ *child_entries = retval;
+ return retval != NULL;
+}
+
+static DBusHandlerResult
+handle_default_introspect_unlocked (DBusObjectTree *tree,
+ DBusMessage *message,
+ const char **path)
+{
+ DBusString xml;
+ DBusHandlerResult result;
+ char **children;
+ int i;
+
+ if (!dbus_message_is_method_call (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
+ "Introspect"))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!_dbus_string_init (&xml))
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ children = NULL;
+ if (!_dbus_object_tree_list_registered_unlocked (tree, path, &children))
+ goto out;
+
+ if (!_dbus_string_append (&xml, "<node>\n"))
+ goto out;
+
+ i = 0;
+ while (children[i] != NULL)
+ {
+ if (!_dbus_string_append_printf (&xml, " <node name=\"%s\"/>\n",
+ children[i]))
+ goto out;
+
+ ++i;
+ }
+
+ if (!_dbus_string_append (&xml, "</node>\n"))
+ goto out;
+
+ result = DBUS_HANDLER_RESULT_HANDLED;
+
+ out:
+ _dbus_string_free (&xml);
+ dbus_free_string_array (children);
+
+ return result;
+}
+
+/**
+ * Tries to dispatch a message by directing it to handler for the
+ * object path listed in the message header, if any. Messages are
+ * dispatched first to the registered handler that matches the largest
+ * number of path elements; that is, message to /foo/bar/baz would go
+ * to the handler for /foo/bar before the one for /foo.
+ *
+ * @todo thread problems
+ *
+ * @param tree the global object tree
+ * @param message the message to dispatch
+ * @returns whether message was handled successfully
+ */
+DBusHandlerResult
+_dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
+ DBusMessage *message)
+{
+ char **path;
+ DBusList *list;
+ DBusList *link;
+ DBusHandlerResult result;
+ DBusObjectSubtree *subtree;
+
+#if 0
+ _dbus_verbose ("Dispatch of message by object path\n");
+#endif
+
+ path = NULL;
+ if (!dbus_message_get_path_decomposed (message, &path))
+ {
+#ifdef DBUS_BUILD_TESTS
+ if (tree->connection)
+#endif
+ _dbus_connection_unlock (tree->connection);
+
+ _dbus_verbose ("No memory to get decomposed path\n");
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ if (path == NULL)
+ {
+#ifdef DBUS_BUILD_TESTS
+ if (tree->connection)
+#endif
+ _dbus_connection_unlock (tree->connection);
+
+ _dbus_verbose ("No path field in message\n");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ /* Find the deepest path that covers the path in the message */
+ subtree = find_handler (tree, (const char**) path);
+
+ /* Build a list of all paths that cover the path in the message */
+
+ list = NULL;
+
+ while (subtree != NULL)
+ {
+ if (subtree->message_function != NULL)
+ {
+ _dbus_object_subtree_ref (subtree);
+
+ /* run deepest paths first */
+ if (!_dbus_list_append (&list, subtree))
+ {
+ result = DBUS_HANDLER_RESULT_NEED_MEMORY;
+ _dbus_object_subtree_unref (subtree);
+ goto free_and_return;
+ }
+ }
+
+ subtree = subtree->parent;
+ }
+
+ _dbus_verbose ("%d handlers in the path tree for this message\n",
+ _dbus_list_get_length (&list));
+
+ /* Invoke each handler in the list */
+
+ result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ link = _dbus_list_get_first_link (&list);
+ while (link != NULL)
+ {
+ DBusList *next = _dbus_list_get_next_link (&list, link);
+ subtree = link->data;
+
+ /* message_function is NULL if we're unregistered
+ * due to reentrancy
+ */
+ if (subtree->message_function)
+ {
+ DBusObjectPathMessageFunction message_function;
+ void *user_data;
+
+ message_function = subtree->message_function;
+ user_data = subtree->user_data;
+
+#if 0
+ _dbus_verbose (" (invoking a handler)\n");
+#endif
+
+#ifdef DBUS_BUILD_TESTS
+ if (tree->connection)
+#endif
+ _dbus_connection_unlock (tree->connection);
+
+ /* FIXME you could unregister the subtree in another thread
+ * before we invoke the callback, and I can't figure out a
+ * good way to solve this.
+ */
+
+ result = (* message_function) (tree->connection,
+ message,
+ user_data);
+
+#ifdef DBUS_BUILD_TESTS
+ if (tree->connection)
+#endif
+ _dbus_connection_lock (tree->connection);
+
+ if (result != DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
+ goto free_and_return;
+ }
+
+ link = next;
+ }
+
+ free_and_return:
+
+ if (result == DBUS_HANDLER_RESULT_NOT_YET_HANDLED)
+ {
+ /* This hardcoded default handler does a minimal Introspect()
+ */
+ result = handle_default_introspect_unlocked (tree, message,
+ (const char**) path);
+ }
+
+#ifdef DBUS_BUILD_TESTS
+ if (tree->connection)
+#endif
+ _dbus_connection_unlock (tree->connection);
+
+ while (list != NULL)
+ {
+ link = _dbus_list_get_first_link (&list);
+ _dbus_object_subtree_unref (link->data);
+ _dbus_list_remove_link (&list, link);
+ }
+
+ dbus_free_string_array (path);
+
+ return result;
+}
+
+/**
+ * Allocates a subtree object.
+ *
+ * @param name name to duplicate.
+ * @returns newly-allocated subtree
+ */
+static DBusObjectSubtree*
+allocate_subtree_object (const char *name)
+{
+ int len;
+ DBusObjectSubtree *subtree;
+ const size_t front_padding = _DBUS_STRUCT_OFFSET (DBusObjectSubtree, name);
+
+ _dbus_assert (name != NULL);
+
+ len = strlen (name);
+
+ subtree = dbus_malloc (front_padding + (len + 1));
+
+ if (subtree == NULL)
+ return NULL;
+
+ memcpy (subtree->name, name, len + 1);
+
+ return subtree;
+}
+
+static DBusObjectSubtree*
+_dbus_object_subtree_new (const char *name,
+ const DBusObjectPathVTable *vtable,
+ void *user_data)
+{
+ DBusObjectSubtree *subtree;
+
+ subtree = allocate_subtree_object (name);
+ if (subtree == NULL)
+ goto oom;
+
+ _dbus_assert (name != NULL);
+
+ subtree->parent = NULL;
+
+ if (vtable)
+ {
+ subtree->message_function = vtable->message_function;
+ subtree->unregister_function = vtable->unregister_function;
+ }
+ else
+ {
+ subtree->message_function = NULL;
+ subtree->unregister_function = NULL;
+ }
+
+ subtree->user_data = user_data;
+ subtree->refcount.value = 1;
+ subtree->subtrees = NULL;
+ subtree->n_subtrees = 0;
+ subtree->subtrees_sorted = TRUE;
+
+ return subtree;
+
+ oom:
+ if (subtree)
+ {
+ dbus_free (subtree);
+ }
+
+ return NULL;
+}
+
+static void
+_dbus_object_subtree_ref (DBusObjectSubtree *subtree)
+{
+ _dbus_assert (subtree->refcount.value > 0);
+ _dbus_atomic_inc (&subtree->refcount);
+}
+
+static void
+_dbus_object_subtree_unref (DBusObjectSubtree *subtree)
+{
+ _dbus_assert (subtree->refcount.value > 0);
+
+ if (_dbus_atomic_dec (&subtree->refcount) == 1)
+ {
+ _dbus_assert (subtree->unregister_function == NULL);
+ _dbus_assert (subtree->message_function == NULL);
+
+ dbus_free (subtree->subtrees);
+ dbus_free (subtree);
+ }
+}
+
+/**
+ * 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_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
+ const char **parent_path,
+ char ***child_entries)
+{
+ dbus_bool_t result;
+
+ result = _dbus_object_tree_list_registered_unlocked (tree,
+ parent_path,
+ child_entries);
+
+#ifdef DBUS_BUILD_TESTS
+ if (tree->connection)
+#endif
+ _dbus_connection_unlock (tree->connection);
+
+ return result;
+}
+
+/** @} */
+
+#ifdef DBUS_BUILD_TESTS
+#include "dbus-test.h"
+#include <stdio.h>
+
+static char*
+flatten_path (const char **path)
+{
+ DBusString str;
+ int i;
+ char *s;
+
+ if (!_dbus_string_init (&str))
+ return NULL;
+
+ i = 0;
+ while (path[i])
+ {
+ if (!_dbus_string_append_byte (&str, '/'))
+ goto nomem;
+
+ if (!_dbus_string_append (&str, path[i]))
+ goto nomem;
+
+ ++i;
+ }
+
+ if (!_dbus_string_steal_data (&str, &s))
+ goto nomem;
+
+ _dbus_string_free (&str);
+
+ return s;
+
+ nomem:
+ _dbus_string_free (&str);
+ return NULL;
+}
+
+/* Returns TRUE if container is a parent of child
+ */
+static dbus_bool_t
+path_contains (const char **container,
+ const char **child)
+{
+ int i;
+
+ i = 0;
+ while (child[i] != NULL)
+ {
+ int v;
+
+ if (container[i] == NULL)
+ return TRUE; /* container ran out, child continues;
+ * thus the container is a parent of the
+ * child.
+ */
+
+ _dbus_assert (container[i] != NULL);
+ _dbus_assert (child[i] != NULL);
+
+ v = strcmp (container[i], child[i]);
+
+ if (v != 0)
+ return FALSE; /* they overlap until here and then are different,
+ * not overlapping
+ */
+
+ ++i;
+ }
+
+ /* Child ran out; if container also did, they are equal;
+ * otherwise, the child is a parent of the container.
+ */
+ if (container[i] == NULL)
+ return TRUE; /* equal is counted as containing */
+ else
+ return FALSE;
+}
+
+static void
+spew_subtree_recurse (DBusObjectSubtree *subtree,
+ int indent)
+{
+ int i;
+
+ i = 0;
+ while (i < indent)
+ {
+ _dbus_verbose (" ");
+ ++i;
+ }
+
+ _dbus_verbose ("%s (%d children)\n",
+ subtree->name, subtree->n_subtrees);
+
+ i = 0;
+ while (i < subtree->n_subtrees)
+ {
+ spew_subtree_recurse (subtree->subtrees[i], indent + 2);
+
+ ++i;
+ }
+}
+
+static void
+spew_tree (DBusObjectTree *tree)
+{
+ spew_subtree_recurse (tree->root, 0);
+}
+
+/**
+ * Callback data used in tests
+ */
+typedef struct
+{
+ const char **path; /**< Path */
+ dbus_bool_t message_handled; /**< Gets set to true if message handler called */
+ dbus_bool_t handler_unregistered; /**< gets set to true if handler is unregistered */
+
+} TreeTestData;
+
+
+static void
+test_unregister_function (DBusConnection *connection,
+ void *user_data)
+{
+ TreeTestData *ttd = user_data;
+
+ ttd->handler_unregistered = TRUE;
+}
+
+static DBusHandlerResult
+test_message_function (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ TreeTestData *ttd = user_data;
+
+ ttd->message_handled = TRUE;
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static dbus_bool_t
+do_register (DBusObjectTree *tree,
+ const char **path,
+ int i,
+ TreeTestData *tree_test_data)
+{
+ DBusObjectPathVTable vtable = { test_unregister_function,
+ test_message_function, NULL };
+
+ tree_test_data[i].message_handled = FALSE;
+ tree_test_data[i].handler_unregistered = FALSE;
+ tree_test_data[i].path = path;
+
+ if (!_dbus_object_tree_register (tree, TRUE, path,
+ &vtable,
+ &tree_test_data[i]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static dbus_bool_t
+do_test_dispatch (DBusObjectTree *tree,
+ const char **path,
+ int i,
+ TreeTestData *tree_test_data,
+ int n_test_data)
+{
+ DBusMessage *message;
+ int j;
+ DBusHandlerResult result;
+ char *flat;
+
+ message = NULL;
+
+ flat = flatten_path (path);
+ if (flat == NULL)
+ goto oom;
+
+ message = dbus_message_new_method_call (NULL,
+ flat,
+ "org.freedesktop.TestInterface",
+ "Foo");
+ dbus_free (flat);
+ if (message == NULL)
+ goto oom;
+
+ j = 0;
+ while (j < n_test_data)
+ {
+ tree_test_data[j].message_handled = FALSE;
+ ++j;
+ }
+
+ result = _dbus_object_tree_dispatch_and_unlock (tree, message);
+ if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
+ goto oom;
+
+ _dbus_assert (tree_test_data[i].message_handled);
+
+ j = 0;
+ while (j < n_test_data)
+ {
+ if (tree_test_data[j].message_handled)
+ _dbus_assert (path_contains (tree_test_data[j].path,
+ path));
+ else
+ _dbus_assert (!path_contains (tree_test_data[j].path,
+ path));
+
+ ++j;
+ }
+
+ dbus_message_unref (message);
+
+ return TRUE;
+
+ oom:
+ if (message)
+ dbus_message_unref (message);
+ return FALSE;
+}
+
+static dbus_bool_t
+object_tree_test_iteration (void *data)
+{
+ const char *path1[] = { "foo", NULL };
+ const char *path2[] = { "foo", "bar", NULL };
+ const char *path3[] = { "foo", "bar", "baz", NULL };
+ const char *path4[] = { "foo", "bar", "boo", NULL };
+ const char *path5[] = { "blah", NULL };
+ const char *path6[] = { "blah", "boof", NULL };
+ const char *path7[] = { "blah", "boof", "this", "is", "really", "long", NULL };
+ const char *path8[] = { "childless", NULL };
+ DBusObjectTree *tree;
+ TreeTestData tree_test_data[8];
+ int i;
+
+ tree = NULL;
+
+ tree = _dbus_object_tree_new (NULL);
+ if (tree == NULL)
+ goto out;
+
+ if (!do_register (tree, path1, 0, tree_test_data))
+ goto out;
+
+ _dbus_assert (find_subtree (tree, path1, NULL));
+ _dbus_assert (!find_subtree (tree, path2, NULL));
+ _dbus_assert (!find_subtree (tree, path3, NULL));
+ _dbus_assert (!find_subtree (tree, path4, NULL));
+ _dbus_assert (!find_subtree (tree, path5, NULL));
+ _dbus_assert (!find_subtree (tree, path6, NULL));
+ _dbus_assert (!find_subtree (tree, path7, NULL));
+ _dbus_assert (!find_subtree (tree, path8, NULL));
+
+ _dbus_assert (find_handler (tree, path1));
+ _dbus_assert (find_handler (tree, path2));
+ _dbus_assert (find_handler (tree, path3));
+ _dbus_assert (find_handler (tree, path4));
+ _dbus_assert (find_handler (tree, path5) == tree->root);
+ _dbus_assert (find_handler (tree, path6) == tree->root);
+ _dbus_assert (find_handler (tree, path7) == tree->root);
+ _dbus_assert (find_handler (tree, path8) == tree->root);
+
+ if (!do_register (tree, path2, 1, tree_test_data))
+ goto out;
+
+ _dbus_assert (find_subtree (tree, path1, NULL));
+ _dbus_assert (find_subtree (tree, path2, NULL));
+ _dbus_assert (!find_subtree (tree, path3, NULL));
+ _dbus_assert (!find_subtree (tree, path4, NULL));
+ _dbus_assert (!find_subtree (tree, path5, NULL));
+ _dbus_assert (!find_subtree (tree, path6, NULL));
+ _dbus_assert (!find_subtree (tree, path7, NULL));
+ _dbus_assert (!find_subtree (tree, path8, NULL));
+
+ if (!do_register (tree, path3, 2, tree_test_data))
+ goto out;
+
+ _dbus_assert (find_subtree (tree, path1, NULL));
+ _dbus_assert (find_subtree (tree, path2, NULL));
+ _dbus_assert (find_subtree (tree, path3, NULL));
+ _dbus_assert (!find_subtree (tree, path4, NULL));
+ _dbus_assert (!find_subtree (tree, path5, NULL));
+ _dbus_assert (!find_subtree (tree, path6, NULL));
+ _dbus_assert (!find_subtree (tree, path7, NULL));
+ _dbus_assert (!find_subtree (tree, path8, NULL));
+
+ if (!do_register (tree, path4, 3, tree_test_data))
+ goto out;
+
+ _dbus_assert (find_subtree (tree, path1, NULL));
+ _dbus_assert (find_subtree (tree, path2, NULL));
+ _dbus_assert (find_subtree (tree, path3, NULL));
+ _dbus_assert (find_subtree (tree, path4, NULL));
+ _dbus_assert (!find_subtree (tree, path5, NULL));
+ _dbus_assert (!find_subtree (tree, path6, NULL));
+ _dbus_assert (!find_subtree (tree, path7, NULL));
+ _dbus_assert (!find_subtree (tree, path8, NULL));
+
+ if (!do_register (tree, path5, 4, tree_test_data))
+ goto out;
+
+ _dbus_assert (find_subtree (tree, path1, NULL));
+ _dbus_assert (find_subtree (tree, path2, NULL));
+ _dbus_assert (find_subtree (tree, path3, NULL));
+ _dbus_assert (find_subtree (tree, path4, NULL));
+ _dbus_assert (find_subtree (tree, path5, NULL));
+ _dbus_assert (!find_subtree (tree, path6, NULL));
+ _dbus_assert (!find_subtree (tree, path7, NULL));
+ _dbus_assert (!find_subtree (tree, path8, NULL));
+
+ _dbus_assert (find_handler (tree, path1) != tree->root);
+ _dbus_assert (find_handler (tree, path2) != tree->root);
+ _dbus_assert (find_handler (tree, path3) != tree->root);
+ _dbus_assert (find_handler (tree, path4) != tree->root);
+ _dbus_assert (find_handler (tree, path5) != tree->root);
+ _dbus_assert (find_handler (tree, path6) != tree->root);
+ _dbus_assert (find_handler (tree, path7) != tree->root);
+ _dbus_assert (find_handler (tree, path8) == tree->root);
+
+ if (!do_register (tree, path6, 5, tree_test_data))
+ goto out;
+
+ _dbus_assert (find_subtree (tree, path1, NULL));
+ _dbus_assert (find_subtree (tree, path2, NULL));
+ _dbus_assert (find_subtree (tree, path3, NULL));
+ _dbus_assert (find_subtree (tree, path4, NULL));
+ _dbus_assert (find_subtree (tree, path5, NULL));
+ _dbus_assert (find_subtree (tree, path6, NULL));
+ _dbus_assert (!find_subtree (tree, path7, NULL));
+ _dbus_assert (!find_subtree (tree, path8, NULL));
+
+ if (!do_register (tree, path7, 6, tree_test_data))
+ goto out;
+
+ _dbus_assert (find_subtree (tree, path1, NULL));
+ _dbus_assert (find_subtree (tree, path2, NULL));
+ _dbus_assert (find_subtree (tree, path3, NULL));
+ _dbus_assert (find_subtree (tree, path4, NULL));
+ _dbus_assert (find_subtree (tree, path5, NULL));
+ _dbus_assert (find_subtree (tree, path6, NULL));
+ _dbus_assert (find_subtree (tree, path7, NULL));
+ _dbus_assert (!find_subtree (tree, path8, NULL));
+
+ if (!do_register (tree, path8, 7, tree_test_data))
+ goto out;
+
+ _dbus_assert (find_subtree (tree, path1, NULL));
+ _dbus_assert (find_subtree (tree, path2, NULL));
+ _dbus_assert (find_subtree (tree, path3, NULL));
+ _dbus_assert (find_subtree (tree, path4, NULL));
+ _dbus_assert (find_subtree (tree, path5, NULL));
+ _dbus_assert (find_subtree (tree, path6, NULL));
+ _dbus_assert (find_subtree (tree, path7, NULL));
+ _dbus_assert (find_subtree (tree, path8, NULL));
+
+ _dbus_assert (find_handler (tree, path1) != tree->root);
+ _dbus_assert (find_handler (tree, path2) != tree->root);
+ _dbus_assert (find_handler (tree, path3) != tree->root);
+ _dbus_assert (find_handler (tree, path4) != tree->root);
+ _dbus_assert (find_handler (tree, path5) != tree->root);
+ _dbus_assert (find_handler (tree, path6) != tree->root);
+ _dbus_assert (find_handler (tree, path7) != tree->root);
+ _dbus_assert (find_handler (tree, path8) != tree->root);
+
+ /* Check that destroying tree calls unregister funcs */
+ _dbus_object_tree_unref (tree);
+
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
+ {
+ _dbus_assert (tree_test_data[i].handler_unregistered);
+ _dbus_assert (!tree_test_data[i].message_handled);
+ ++i;
+ }
+
+ /* Now start again and try the individual unregister function */
+ tree = _dbus_object_tree_new (NULL);
+ if (tree == NULL)
+ goto out;
+
+ if (!do_register (tree, path1, 0, tree_test_data))
+ goto out;
+ if (!do_register (tree, path2, 1, tree_test_data))
+ goto out;
+ if (!do_register (tree, path3, 2, tree_test_data))
+ goto out;
+ if (!do_register (tree, path4, 3, tree_test_data))
+ goto out;
+ if (!do_register (tree, path5, 4, tree_test_data))
+ goto out;
+ if (!do_register (tree, path6, 5, tree_test_data))
+ goto out;
+ if (!do_register (tree, path7, 6, tree_test_data))
+ goto out;
+ if (!do_register (tree, path8, 7, tree_test_data))
+ goto out;
+
+ _dbus_object_tree_unregister_and_unlock (tree, path1);
+
+ _dbus_assert (!find_subtree (tree, path1, NULL));
+ _dbus_assert (find_subtree (tree, path2, NULL));
+ _dbus_assert (find_subtree (tree, path3, NULL));
+ _dbus_assert (find_subtree (tree, path4, NULL));
+ _dbus_assert (find_subtree (tree, path5, NULL));
+ _dbus_assert (find_subtree (tree, path6, NULL));
+ _dbus_assert (find_subtree (tree, path7, NULL));
+ _dbus_assert (find_subtree (tree, path8, NULL));
+
+ _dbus_object_tree_unregister_and_unlock (tree, path2);
+
+ _dbus_assert (!find_subtree (tree, path1, NULL));
+ _dbus_assert (!find_subtree (tree, path2, NULL));
+ _dbus_assert (find_subtree (tree, path3, NULL));
+ _dbus_assert (find_subtree (tree, path4, NULL));
+ _dbus_assert (find_subtree (tree, path5, NULL));
+ _dbus_assert (find_subtree (tree, path6, NULL));
+ _dbus_assert (find_subtree (tree, path7, NULL));
+ _dbus_assert (find_subtree (tree, path8, NULL));
+
+ _dbus_object_tree_unregister_and_unlock (tree, path3);
+
+ _dbus_assert (!find_subtree (tree, path1, NULL));
+ _dbus_assert (!find_subtree (tree, path2, NULL));
+ _dbus_assert (!find_subtree (tree, path3, NULL));
+ _dbus_assert (find_subtree (tree, path4, NULL));
+ _dbus_assert (find_subtree (tree, path5, NULL));
+ _dbus_assert (find_subtree (tree, path6, NULL));
+ _dbus_assert (find_subtree (tree, path7, NULL));
+ _dbus_assert (find_subtree (tree, path8, NULL));
+
+ _dbus_object_tree_unregister_and_unlock (tree, path4);
+
+ _dbus_assert (!find_subtree (tree, path1, NULL));
+ _dbus_assert (!find_subtree (tree, path2, NULL));
+ _dbus_assert (!find_subtree (tree, path3, NULL));
+ _dbus_assert (!find_subtree (tree, path4, NULL));
+ _dbus_assert (find_subtree (tree, path5, NULL));
+ _dbus_assert (find_subtree (tree, path6, NULL));
+ _dbus_assert (find_subtree (tree, path7, NULL));
+ _dbus_assert (find_subtree (tree, path8, NULL));
+
+ _dbus_object_tree_unregister_and_unlock (tree, path5);
+
+ _dbus_assert (!find_subtree (tree, path1, NULL));
+ _dbus_assert (!find_subtree (tree, path2, NULL));
+ _dbus_assert (!find_subtree (tree, path3, NULL));
+ _dbus_assert (!find_subtree (tree, path4, NULL));
+ _dbus_assert (!find_subtree (tree, path5, NULL));
+ _dbus_assert (find_subtree (tree, path6, NULL));
+ _dbus_assert (find_subtree (tree, path7, NULL));
+ _dbus_assert (find_subtree (tree, path8, NULL));
+
+ _dbus_object_tree_unregister_and_unlock (tree, path6);
+
+ _dbus_assert (!find_subtree (tree, path1, NULL));
+ _dbus_assert (!find_subtree (tree, path2, NULL));
+ _dbus_assert (!find_subtree (tree, path3, NULL));
+ _dbus_assert (!find_subtree (tree, path4, NULL));
+ _dbus_assert (!find_subtree (tree, path5, NULL));
+ _dbus_assert (!find_subtree (tree, path6, NULL));
+ _dbus_assert (find_subtree (tree, path7, NULL));
+ _dbus_assert (find_subtree (tree, path8, NULL));
+
+ _dbus_object_tree_unregister_and_unlock (tree, path7);
+
+ _dbus_assert (!find_subtree (tree, path1, NULL));
+ _dbus_assert (!find_subtree (tree, path2, NULL));
+ _dbus_assert (!find_subtree (tree, path3, NULL));
+ _dbus_assert (!find_subtree (tree, path4, NULL));
+ _dbus_assert (!find_subtree (tree, path5, NULL));
+ _dbus_assert (!find_subtree (tree, path6, NULL));
+ _dbus_assert (!find_subtree (tree, path7, NULL));
+ _dbus_assert (find_subtree (tree, path8, NULL));
+
+ _dbus_object_tree_unregister_and_unlock (tree, path8);
+
+ _dbus_assert (!find_subtree (tree, path1, NULL));
+ _dbus_assert (!find_subtree (tree, path2, NULL));
+ _dbus_assert (!find_subtree (tree, path3, NULL));
+ _dbus_assert (!find_subtree (tree, path4, NULL));
+ _dbus_assert (!find_subtree (tree, path5, NULL));
+ _dbus_assert (!find_subtree (tree, path6, NULL));
+ _dbus_assert (!find_subtree (tree, path7, NULL));
+ _dbus_assert (!find_subtree (tree, path8, NULL));
+
+ i = 0;
+ while (i < (int) _DBUS_N_ELEMENTS (tree_test_data))
+ {
+ _dbus_assert (tree_test_data[i].handler_unregistered);
+ _dbus_assert (!tree_test_data[i].message_handled);
+ ++i;
+ }
+
+ /* Register it all again, and test dispatch */
+
+ if (!do_register (tree, path1, 0, tree_test_data))
+ goto out;
+ if (!do_register (tree, path2, 1, tree_test_data))
+ goto out;
+ if (!do_register (tree, path3, 2, tree_test_data))
+ goto out;
+ if (!do_register (tree, path4, 3, tree_test_data))
+ goto out;
+ if (!do_register (tree, path5, 4, tree_test_data))
+ goto out;
+ if (!do_register (tree, path6, 5, tree_test_data))
+ goto out;
+ if (!do_register (tree, path7, 6, tree_test_data))
+ goto out;
+ if (!do_register (tree, path8, 7, tree_test_data))
+ goto out;
+
+#if 0
+ spew_tree (tree);
+#endif
+
+ if (!do_test_dispatch (tree, path1, 0, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
+ goto out;
+ if (!do_test_dispatch (tree, path2, 1, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
+ goto out;
+ if (!do_test_dispatch (tree, path3, 2, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
+ goto out;
+ if (!do_test_dispatch (tree, path4, 3, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
+ goto out;
+ if (!do_test_dispatch (tree, path5, 4, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
+ goto out;
+ if (!do_test_dispatch (tree, path6, 5, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
+ goto out;
+ if (!do_test_dispatch (tree, path7, 6, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
+ goto out;
+ if (!do_test_dispatch (tree, path8, 7, tree_test_data, _DBUS_N_ELEMENTS (tree_test_data)))
+ goto out;
+
+ out:
+ if (tree)
+ {
+ /* test ref */
+ _dbus_object_tree_ref (tree);
+ _dbus_object_tree_unref (tree);
+ _dbus_object_tree_unref (tree);
+ }
+
+ return TRUE;
+}
+
+/**
+ * @ingroup DBusObjectTree
+ * Unit test for DBusObjectTree
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_object_tree_test (void)
+{
+ _dbus_test_oom_handling ("object tree",
+ object_tree_test_iteration,
+ NULL);
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-object-tree.h b/dbus/dbus-object-tree.h
new file mode 100644
index 00000000..bf34d972
--- /dev/null
+++ b/dbus/dbus-object-tree.h
@@ -0,0 +1,52 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-object-tree.h DBusObjectTree (internals of DBusConnection)
+ *
+ * Copyright (C) 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef DBUS_OBJECT_TREE_H
+#define DBUS_OBJECT_TREE_H
+
+#include <dbus/dbus-connection.h>
+
+DBUS_BEGIN_DECLS;
+
+typedef struct DBusObjectTree DBusObjectTree;
+
+DBusObjectTree* _dbus_object_tree_new (DBusConnection *connection);
+void _dbus_object_tree_ref (DBusObjectTree *tree);
+void _dbus_object_tree_unref (DBusObjectTree *tree);
+
+dbus_bool_t _dbus_object_tree_register (DBusObjectTree *tree,
+ dbus_bool_t fallback,
+ const char **path,
+ const DBusObjectPathVTable *vtable,
+ void *user_data);
+void _dbus_object_tree_unregister_and_unlock (DBusObjectTree *tree,
+ const char **path);
+DBusHandlerResult _dbus_object_tree_dispatch_and_unlock (DBusObjectTree *tree,
+ DBusMessage *message);
+void _dbus_object_tree_free_all_unlocked (DBusObjectTree *tree);
+
+dbus_bool_t _dbus_object_tree_list_registered_and_unlock (DBusObjectTree *tree,
+ const char **parent_path,
+ char ***child_entries);
+DBUS_END_DECLS;
+
+#endif /* DBUS_OBJECT_TREE_H */
diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c
new file mode 100644
index 00000000..dad444e3
--- /dev/null
+++ b/dbus/dbus-pending-call.c
@@ -0,0 +1,429 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-pending-call.c Object representing a call in progress.
+ *
+ * Copyright (C) 2002, 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "dbus-internals.h"
+#include "dbus-connection-internal.h"
+#include "dbus-pending-call.h"
+#include "dbus-list.h"
+#include "dbus-threads.h"
+#include "dbus-test.h"
+
+/**
+ * @defgroup DBusPendingCallInternals DBusPendingCall implementation details
+ * @ingroup DBusInternals
+ * @brief DBusPendingCall private implementation details.
+ *
+ * The guts of DBusPendingCall and its methods.
+ *
+ * @{
+ */
+
+static dbus_int32_t notify_user_data_slot = -1;
+
+/**
+ * Creates a new pending reply object.
+ *
+ * @param connection connection where reply will arrive
+ * @param timeout_milliseconds length of timeout, -1 for default
+ * @param timeout_handler timeout handler, takes pending call as data
+ * @returns a new #DBusPendingCall or #NULL if no memory.
+ */
+DBusPendingCall*
+_dbus_pending_call_new (DBusConnection *connection,
+ int timeout_milliseconds,
+ DBusTimeoutHandler timeout_handler)
+{
+ DBusPendingCall *pending;
+ DBusTimeout *timeout;
+
+ _dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
+
+ if (timeout_milliseconds == -1)
+ timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
+
+ if (!dbus_pending_call_allocate_data_slot (&notify_user_data_slot))
+ return NULL;
+
+ pending = dbus_new (DBusPendingCall, 1);
+
+ if (pending == NULL)
+ {
+ dbus_pending_call_free_data_slot (&notify_user_data_slot);
+ return NULL;
+ }
+
+ timeout = _dbus_timeout_new (timeout_milliseconds,
+ timeout_handler,
+ pending, NULL);
+
+ if (timeout == NULL)
+ {
+ dbus_pending_call_free_data_slot (&notify_user_data_slot);
+ dbus_free (pending);
+ return NULL;
+ }
+
+ pending->refcount.value = 1;
+ pending->connection = connection;
+ pending->timeout = timeout;
+
+ _dbus_data_slot_list_init (&pending->slot_list);
+
+ return pending;
+}
+
+/**
+ * Calls notifier function for the pending call
+ * and sets the call to completed.
+ *
+ * @param pending the pending call
+ *
+ */
+void
+_dbus_pending_call_notify (DBusPendingCall *pending)
+{
+ pending->completed = TRUE;
+
+ if (pending->function)
+ {
+ void *user_data;
+ user_data = dbus_pending_call_get_data (pending,
+ notify_user_data_slot);
+
+ (* pending->function) (pending, user_data);
+ }
+}
+
+/** @} */
+
+/**
+ * @defgroup DBusPendingCall DBusPendingCall
+ * @ingroup DBus
+ * @brief Pending reply to a method call message
+ *
+ * A DBusPendingCall is an object representing an
+ * expected reply. A #DBusPendingCall can be created
+ * when you send a message that should have a reply.
+ *
+ * @{
+ */
+
+/**
+ * @typedef DBusPendingCall
+ *
+ * Opaque data type representing a message pending.
+ */
+
+/**
+ * Increments the reference count on a pending call.
+ *
+ * @param pending the pending call object
+ */
+void
+dbus_pending_call_ref (DBusPendingCall *pending)
+{
+ _dbus_return_if_fail (pending != NULL);
+
+ _dbus_atomic_inc (&pending->refcount);
+}
+
+/**
+ * Decrements the reference count on a pending call,
+ * freeing it if the count reaches 0.
+ *
+ * @param pending the pending call object
+ */
+void
+dbus_pending_call_unref (DBusPendingCall *pending)
+{
+ dbus_bool_t last_unref;
+
+ _dbus_return_if_fail (pending != NULL);
+
+ last_unref = (_dbus_atomic_dec (&pending->refcount) == 1);
+
+ if (last_unref)
+ {
+ /* If we get here, we should be already detached
+ * from the connection, or never attached.
+ */
+ _dbus_assert (pending->connection == NULL);
+ _dbus_assert (!pending->timeout_added);
+
+ /* this assumes we aren't holding connection lock... */
+ _dbus_data_slot_list_free (&pending->slot_list);
+
+ if (pending->timeout != NULL)
+ _dbus_timeout_unref (pending->timeout);
+
+ if (pending->timeout_link)
+ {
+ dbus_message_unref ((DBusMessage *)pending->timeout_link->data);
+ _dbus_list_free_link (pending->timeout_link);
+ pending->timeout_link = NULL;
+ }
+
+ if (pending->reply)
+ {
+ dbus_message_unref (pending->reply);
+ pending->reply = NULL;
+ }
+
+ dbus_free (pending);
+
+ dbus_pending_call_free_data_slot (&notify_user_data_slot);
+ }
+}
+
+/**
+ * Sets a notification function to be called when the reply is
+ * received or the pending call times out.
+ *
+ * @param pending the pending call
+ * @param function notifier function
+ * @param user_data data to pass to notifier function
+ * @param free_user_data function to free the user data
+ * @returns #FALSE if not enough memory
+ */
+dbus_bool_t
+dbus_pending_call_set_notify (DBusPendingCall *pending,
+ DBusPendingCallNotifyFunction function,
+ void *user_data,
+ DBusFreeFunction free_user_data)
+{
+ _dbus_return_val_if_fail (pending != NULL, FALSE);
+
+ /* could invoke application code! */
+ if (!dbus_pending_call_set_data (pending, notify_user_data_slot,
+ user_data, free_user_data))
+ return FALSE;
+
+ pending->function = function;
+
+ return TRUE;
+}
+
+/**
+ * Cancels the pending call, such that any reply
+ * or error received will just be ignored.
+ * Drops at least one reference to the #DBusPendingCall
+ * so will free the call if nobody else is holding
+ * a reference.
+ *
+ * @param pending the pending call
+ */
+void
+dbus_pending_call_cancel (DBusPendingCall *pending)
+{
+ if (pending->connection)
+ _dbus_connection_remove_pending_call (pending->connection,
+ pending);
+}
+
+/**
+ * Checks whether the pending call has received a reply
+ * yet, or not.
+ *
+ * @todo not thread safe? I guess it has to lock though it sucks
+ *
+ * @param pending the pending call
+ * @returns #TRUE if a reply has been received */
+dbus_bool_t
+dbus_pending_call_get_completed (DBusPendingCall *pending)
+{
+ return pending->completed;
+}
+
+/**
+ * Gets the reply, or returns #NULL if none has been received yet. The
+ * reference count is not incremented on the returned message, so you
+ * have to keep a reference count on the pending call (or add one
+ * to the message).
+ *
+ * @todo not thread safe? I guess it has to lock though it sucks
+ * @todo maybe to make this threadsafe, it should be steal_reply(), i.e. only one thread can ever get the message
+ *
+ * @param pending the pending call
+ * @returns the reply message or #NULL.
+ */
+DBusMessage*
+dbus_pending_call_get_reply (DBusPendingCall *pending)
+{
+ return pending->reply;
+}
+
+/**
+ * Block until the pending call is completed. The blocking is as with
+ * dbus_connection_send_with_reply_and_block(); it does not enter the
+ * main loop or process other messages, it simply waits for the reply
+ * in question.
+ *
+ * If the pending call is already completed, this function returns
+ * immediately.
+ *
+ * @todo when you start blocking, the timeout is reset, but it should
+ * really only use time remaining since the pending call was created.
+ *
+ * @param pending the pending call
+ */
+void
+dbus_pending_call_block (DBusPendingCall *pending)
+{
+ DBusMessage *message;
+
+ if (dbus_pending_call_get_completed (pending))
+ return;
+
+ message = _dbus_connection_block_for_reply (pending->connection,
+ pending->reply_serial,
+ dbus_timeout_get_interval (pending->timeout));
+
+ _dbus_connection_lock (pending->connection);
+ _dbus_pending_call_complete_and_unlock (pending, message);
+ dbus_message_unref (message);
+}
+
+static DBusDataSlotAllocator slot_allocator;
+_DBUS_DEFINE_GLOBAL_LOCK (pending_call_slots);
+
+/**
+ * Allocates an integer ID to be used for storing application-specific
+ * data on any DBusPendingCall. The allocated ID may then be used
+ * with dbus_pending_call_set_data() and dbus_pending_call_get_data().
+ * The passed-in slot must be initialized to -1, and is filled in
+ * with the slot ID. If the passed-in slot is not -1, it's assumed
+ * to be already allocated, and its refcount is incremented.
+ *
+ * The allocated slot is global, i.e. all DBusPendingCall objects will
+ * have a slot with the given integer ID reserved.
+ *
+ * @param slot_p address of a global variable storing the slot
+ * @returns #FALSE on failure (no memory)
+ */
+dbus_bool_t
+dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p)
+{
+ return _dbus_data_slot_allocator_alloc (&slot_allocator,
+ _DBUS_LOCK_NAME (pending_call_slots),
+ slot_p);
+}
+
+/**
+ * Deallocates a global ID for #DBusPendingCall data slots.
+ * dbus_pending_call_get_data() and dbus_pending_call_set_data() may
+ * no longer be used with this slot. Existing data stored on existing
+ * DBusPendingCall objects will be freed when the #DBusPendingCall is
+ * finalized, but may not be retrieved (and may only be replaced if
+ * someone else reallocates the slot). When the refcount on the
+ * passed-in slot reaches 0, it is set to -1.
+ *
+ * @param slot_p address storing the slot to deallocate
+ */
+void
+dbus_pending_call_free_data_slot (dbus_int32_t *slot_p)
+{
+ _dbus_return_if_fail (*slot_p >= 0);
+
+ _dbus_data_slot_allocator_free (&slot_allocator, slot_p);
+}
+
+/**
+ * Stores a pointer on a #DBusPendingCall, along
+ * with an optional function to be used for freeing
+ * the data when the data is set again, or when
+ * the pending call is finalized. The slot number
+ * must have been allocated with dbus_pending_call_allocate_data_slot().
+ *
+ * @param pending the pending_call
+ * @param slot the slot number
+ * @param data the data to store
+ * @param free_data_func finalizer function for the data
+ * @returns #TRUE if there was enough memory to store the data
+ */
+dbus_bool_t
+dbus_pending_call_set_data (DBusPendingCall *pending,
+ dbus_int32_t slot,
+ void *data,
+ DBusFreeFunction free_data_func)
+{
+ DBusFreeFunction old_free_func;
+ void *old_data;
+ dbus_bool_t retval;
+
+ _dbus_return_val_if_fail (pending != NULL, FALSE);
+ _dbus_return_val_if_fail (slot >= 0, FALSE);
+
+ retval = _dbus_data_slot_list_set (&slot_allocator,
+ &pending->slot_list,
+ slot, data, free_data_func,
+ &old_free_func, &old_data);
+
+ if (retval)
+ {
+ if (old_free_func)
+ (* old_free_func) (old_data);
+ }
+
+ return retval;
+}
+
+/**
+ * Retrieves data previously set with dbus_pending_call_set_data().
+ * The slot must still be allocated (must not have been freed).
+ *
+ * @param pending the pending_call
+ * @param slot the slot to get data from
+ * @returns the data, or #NULL if not found
+ */
+void*
+dbus_pending_call_get_data (DBusPendingCall *pending,
+ dbus_int32_t slot)
+{
+ void *res;
+
+ _dbus_return_val_if_fail (pending != NULL, NULL);
+
+ res = _dbus_data_slot_list_get (&slot_allocator,
+ &pending->slot_list,
+ slot);
+
+ return res;
+}
+
+/** @} */
+
+#ifdef DBUS_BUILD_TESTS
+
+/**
+ * @ingroup DBusPendingCallInternals
+ * Unit test for DBusPendingCall.
+ *
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_pending_call_test (const char *test_data_dir)
+{
+
+ return TRUE;
+}
+#endif /* DBUS_BUILD_TESTS */
diff --git a/dbus/dbus-pending-call.h b/dbus/dbus-pending-call.h
new file mode 100644
index 00000000..4f1e92c0
--- /dev/null
+++ b/dbus/dbus-pending-call.h
@@ -0,0 +1,58 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-pending-call.h Object representing a call in progress.
+ *
+ * Copyright (C) 2002, 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#if !defined (DBUS_INSIDE_DBUS_H) && !defined (DBUS_COMPILATION)
+#error "Only <dbus/dbus.h> can be included directly, this file may disappear or change contents."
+#endif
+
+#ifndef DBUS_PENDING_CALL_H
+#define DBUS_PENDING_CALL_H
+
+#include <dbus/dbus-macros.h>
+#include <dbus/dbus-types.h>
+#include <dbus/dbus-connection.h>
+
+DBUS_BEGIN_DECLS;
+
+void dbus_pending_call_ref (DBusPendingCall *pending);
+void dbus_pending_call_unref (DBusPendingCall *pending);
+dbus_bool_t dbus_pending_call_set_notify (DBusPendingCall *pending,
+ DBusPendingCallNotifyFunction function,
+ void *user_data,
+ DBusFreeFunction free_user_data);
+void dbus_pending_call_cancel (DBusPendingCall *pending);
+dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending);
+DBusMessage* dbus_pending_call_get_reply (DBusPendingCall *pending);
+void dbus_pending_call_block (DBusPendingCall *pending);
+
+dbus_bool_t dbus_pending_call_allocate_data_slot (dbus_int32_t *slot_p);
+void dbus_pending_call_free_data_slot (dbus_int32_t *slot_p);
+dbus_bool_t dbus_pending_call_set_data (DBusPendingCall *pending,
+ dbus_int32_t slot,
+ void *data,
+ DBusFreeFunction free_data_func);
+void* dbus_pending_call_get_data (DBusPendingCall *pending,
+ dbus_int32_t slot);
+
+DBUS_END_DECLS;
+
+#endif /* DBUS_PENDING_CALL_H */
diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
index fbdcb6dd..a0cf54ef 100644
--- a/dbus/dbus-protocol.h
+++ b/dbus/dbus-protocol.h
@@ -53,25 +53,54 @@ extern "C" {
#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 @@ extern "C" {
#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
diff --git a/dbus/dbus-server-debug-pipe.c b/dbus/dbus-server-debug-pipe.c
index 15b78608..6a66391e 100644
--- a/dbus/dbus-server-debug-pipe.c
+++ b/dbus/dbus-server-debug-pipe.c
@@ -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
diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h
index a3774c31..317805f5 100644
--- a/dbus/dbus-server-protected.h
+++ b/dbus/dbus-server-protected.h
@@ -34,6 +34,9 @@ DBUS_BEGIN_DECLS;
typedef struct DBusServerVTable DBusServerVTable;
+/**
+ * Virtual table to be implemented by all server "subclasses"
+ */
struct DBusServerVTable
{
void (* finalize) (DBusServer *server);
@@ -43,6 +46,9 @@ struct DBusServerVTable
/**< Disconnect this server. */
};
+/**
+ * Internals of DBusServer object
+ */
struct DBusServer
{
int refcount; /**< Reference count. */
diff --git a/dbus/dbus-server-unix.c b/dbus/dbus-server-unix.c
index 036446af..487d60ec 100644
--- a/dbus/dbus-server-unix.c
+++ b/dbus/dbus-server-unix.c
@@ -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>
diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c
index 1c9d53f0..29e20a55 100644
--- a/dbus/dbus-server.c
+++ b/dbus/dbus-server.c
@@ -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
diff --git a/dbus/dbus-sha.h b/dbus/dbus-sha.h
index 7f793844..0a48d197 100644
--- a/dbus/dbus-sha.h
+++ b/dbus/dbus-sha.h
@@ -31,11 +31,14 @@ DBUS_BEGIN_DECLS;
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 */
};
diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c
index d4015561..604b9e7c 100644
--- a/dbus/dbus-spawn.c
+++ b/dbus/dbus-spawn.c
@@ -176,28 +176,31 @@ enum
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*
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
index c6f929a8..628cf861 100644
--- a/dbus/dbus-string.c
+++ b/dbus/dbus-string.c
@@ -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 @@ _dbus_string_get_byte (const DBusString *str,
}
/**
- * 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 @@ _dbus_string_append_8_aligned (DBusString *str,
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 @@ _dbus_string_append_8_aligned (DBusString *str,
}
/**
+ * 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 @@ _dbus_string_skip_white (const DBusString *str,
}
/**
- * 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 @@ _dbus_string_validate_nul (const DBusString *str,
}
/**
- * 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 @@ _dbus_string_validate_nul (const DBusString *str,
* @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 @@ _dbus_string_validate_name (const DBusString *str,
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 @@ _dbus_string_validate_name (const DBusString *str,
*
* @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 @@ _dbus_string_test (void)
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_test (void)
_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 @@ _dbus_string_test (void)
/* 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;
}
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
index 8fa13805..0b7be8b0 100644
--- a/dbus/dbus-string.h
+++ b/dbus/dbus-string.h
@@ -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 @@ void _dbus_string_set_byte (DBusString *str,
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 @@ dbus_bool_t _dbus_string_append_4_aligned (DBusString *str,
const unsigned char octets[4]);
dbus_bool_t _dbus_string_append_8_aligned (DBusString *str,
const unsigned char octets[8]);
+dbus_bool_t _dbus_string_append_printf (DBusString *str,
+ const char *format,
+ ...) _DBUS_GNUC_PRINTF (2, 3);
+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_utf8 (const DBusString *str,
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,
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index 5311b202..c3ddf8cd 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -2515,9 +2515,12 @@ _dbus_path_is_absolute (const DBusString *filename)
return FALSE;
}
+/**
+ * Internals of directory iterator
+ */
struct DBusDirIter
{
- DIR *d;
+ DIR *d; /**< The DIR* from opendir() */
};
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index cfe0cd25..363f665d 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -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_BEGIN_DECLS;
* 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 @@ typedef unsigned long dbus_gid_t;
#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 @@ dbus_bool_t _dbus_credentials_match (const DBusCredentials *expec
typedef struct DBusUserInfo DBusUserInfo;
typedef struct DBusGroupInfo DBusGroupInfo;
+/**
+ * Information about a UNIX user
+ */
struct DBusUserInfo
{
dbus_uid_t uid; /**< UID */
@@ -144,6 +150,9 @@ struct DBusUserInfo
char *homedir; /**< Home directory */
};
+/**
+ * Information about a UNIX group
+ */
struct DBusGroupInfo
{
dbus_gid_t gid; /**< GID */
@@ -172,9 +181,13 @@ dbus_uid_t _dbus_getuid (void);
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 @@ dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic);
#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_fd_set_close_on_exec (int fd);
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,
diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c
index 2fbab5a4..b7a09a0e 100644
--- a/dbus/dbus-test.c
+++ b/dbus/dbus-test.c
@@ -81,7 +81,7 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
die ("strings");
check_memleaks ();
-
+
printf ("%s: running sysdeps tests\n", "dbus-test");
if (!_dbus_sysdeps_test ())
die ("sysdeps");
@@ -99,6 +99,12 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
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 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
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 @@ dbus_internal_do_not_use_run_tests (const char *test_data_dir)
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
diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h
index 22a43f79..02b2c279 100644
--- a/dbus/dbus-test.h
+++ b/dbus/dbus-test.h
@@ -43,7 +43,6 @@ dbus_bool_t _dbus_mem_pool_test (void);
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_sysdeps_test (void);
dbus_bool_t _dbus_spawn_test (const char *test_data_dir);
dbus_bool_t _dbus_userdb_test (const char *test_data_dir);
dbus_bool_t _dbus_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,
diff --git a/dbus/dbus-threads.c b/dbus/dbus-threads.c
index b604a397..2170c465 100644
--- a/dbus/dbus-threads.c
+++ b/dbus/dbus-threads.c
@@ -223,10 +223,10 @@ init_global_locks (void)
#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)
diff --git a/dbus/dbus-threads.h b/dbus/dbus-threads.h
index 0dcb1040..dea969a2 100644
--- a/dbus/dbus-threads.h
+++ b/dbus/dbus-threads.h
@@ -66,30 +66,34 @@ typedef enum
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;
-
- DBusMutexNewFunction mutex_new;
- DBusMutexFreeFunction mutex_free;
- DBusMutexLockFunction mutex_lock;
- DBusMutexUnlockFunction mutex_unlock;
-
- DBusCondVarNewFunction condvar_new;
- DBusCondVarFreeFunction condvar_free;
- DBusCondVarWaitFunction condvar_wait;
- DBusCondVarWaitTimeoutFunction condvar_wait_timeout;
- DBusCondVarWakeOneFunction condvar_wake_one;
- DBusCondVarWakeAllFunction condvar_wake_all;
+ unsigned int mask; /**< Mask indicating which functions are present. */
+
+ 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; /**< 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;
diff --git a/dbus/dbus-timeout.c b/dbus/dbus-timeout.c
index 289d6347..b15089db 100644
--- a/dbus/dbus-timeout.c
+++ b/dbus/dbus-timeout.c
@@ -33,6 +33,9 @@
* @{
*/
+/**
+ * Internals of DBusTimeout
+ */
struct DBusTimeout
{
int refcount; /**< Reference count */
diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h
index 1c5b4208..d4d20957 100644
--- a/dbus/dbus-transport-protected.h
+++ b/dbus/dbus-transport-protected.h
@@ -34,6 +34,10 @@ DBUS_BEGIN_DECLS;
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 @@ struct DBusTransportVTable
/**< 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. */
diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
index 59ec6ea1..4625cf25 100644
--- a/dbus/dbus-transport.c
+++ b/dbus/dbus-transport.c
@@ -813,7 +813,9 @@ _dbus_transport_queue_messages (DBusTransport *transport)
{
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)
diff --git a/dbus/dbus-types.h b/dbus/dbus-types.h
index 854b6526..99cb45f5 100644
--- a/dbus/dbus-types.h
+++ b/dbus/dbus-types.h
@@ -83,6 +83,10 @@ typedef dbus_uint32_t dbus_unichar_t;
*
* 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 @@ typedef dbus_uint32_t dbus_unichar_t;
*
* 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.
*/
/**
diff --git a/dbus/dbus-userdb.c b/dbus/dbus-userdb.c
index 4a7b7488..95f13981 100644
--- a/dbus/dbus-userdb.c
+++ b/dbus/dbus-userdb.c
@@ -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
diff --git a/dbus/dbus-watch.c b/dbus/dbus-watch.c
index 5b59e8c8..f212090a 100644
--- a/dbus/dbus-watch.c
+++ b/dbus/dbus-watch.c
@@ -33,6 +33,9 @@
* @{
*/
+/**
+ * Implementation of DBusWatch
+ */
struct DBusWatch
{
int refcount; /**< Reference count */
diff --git a/dbus/dbus.h b/dbus/dbus.h
index 0dd072ac..99eee18c 100644
--- a/dbus/dbus.h
+++ b/dbus/dbus.h
@@ -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>
diff --git a/doc/TODO b/doc/TODO
index 0e56e1e7..120d1eba 100644
--- a/doc/TODO
+++ b/doc/TODO
@@ -23,9 +23,6 @@
(changing get_string to have an error return, and allowing a type error
as a possible return)
- - We might consider returning a "no such operation" error in dbus-connection.c
- for unhandled messages.
-
- The convenience functions in dbus-bus.h should perhaps have
the signatures that they would have if they were autogenerated
stubs. e.g. the acquire service function. We should also evaluate
@@ -69,3 +66,30 @@
files; they have to be in the toplevel file. when loading
a child file, we could just init its DBusLimits from the parent,
then after parsing copy its DBusLimits back to the parent
+
+ - when making a method call, if the call serial were globally unique,
+ we could forward the call serial along with any method calls made
+ as a result of the first method call, and allow reentrancy that was
+ strictly part of the call stack of said method call. But I don't
+ really see how to do this without making the user pass around the
+ call serial to all method calls all the time, or disallowing
+ async calls.
+
+ - the invalid messages in the test suite are all useless because
+ they are invalid for the wrong reasons due to protocol changes
+
+ - I don't want to introduce DBusObject, but refcounting and object
+ data could still be factored out into an internal "base class"
+ perhaps.
+
+ - modify the auth protocol to also support other initial-handshake
+ type of information
+
+ - document the auth protocol as a set of states and transitions, and
+ then reimplement it in those terms
+
+ - dbus_gproxy or dbus_g_proxy?
+
+ - add dbus_message_has_path(), maybe has_member/interface
+
+ - The OBJECT_PATH type is not documented in the spec.
diff --git a/doc/dbus-specification.sgml b/doc/dbus-specification.sgml
index 4ab5291a..696c3f45 100644
--- a/doc/dbus-specification.sgml
+++ b/doc/dbus-specification.sgml
@@ -3,8 +3,8 @@
<article id="index">
<artheader>
<title>D-BUS Specification</title>
- <releaseinfo>Version 0.7</releaseinfo>
- <date>26 March 2003</date>
+ <releaseinfo>Version 0.8</releaseinfo>
+ <date>06 September 2003</date>
<authorgroup>
<author>
<firstname>Havoc</firstname>
@@ -65,10 +65,10 @@
<para>
D-BUS is <emphasis>easy to use</emphasis> because it works in terms
of <firstterm>messages</firstterm> rather than byte streams, and
- does not require users to understand any complex concepts such as a
- new type system or elaborate APIs. Libraries implementing D-BUS
- may choose to abstract messages as "method calls" (see
- <xref linkend="message-conventions-method">).
+ automatically handles a lot of the hard IPC issues. Also, the D-BUS
+ library is designed to be wrapped in a way that lets developers use
+ their framework's existing object/type system, rather than learning
+ a new one specifically for IPC.
</para>
</listitem>
</itemizedlist>
@@ -83,11 +83,10 @@
forwards messages among them.
</para>
<para>
- Things that D-BUS can be used for is for example notification of
- system changes (notification of when a camera is plugged in to a
- computer, or a new version of some software has been installed),
- or desktop interoperablity, for example a file monitoring
- service or a configuration service.
+ Uses of D-BUS include notification of system changes (notification of when
+ a camera is plugged in to a computer, or a new version of some software
+ has been installed), or desktop interoperablity, for example a file
+ monitoring service or a configuration service.
</para>
</sect1>
@@ -135,6 +134,12 @@
</row>
<row>
<entry>1 byte</entry>
+ <entry>Type of message. Unknown types MUST be ignored.
+ Currently-defined types are described below.
+ </entry>
+ </row>
+ <row>
+ <entry>1 byte</entry>
<entry>Bitwise OR of flags. Unknown flags
MUST be ignored. Currently-defined flags are described below.
</entry>
@@ -149,12 +154,6 @@
</entry>
</row>
<row>
- <entry>1 byte</entry>
- <entry>A nul byte, reserved for future use.
- Any value for this byte MUST be accepted.
- </entry>
- </row>
- <row>
<entry>4 bytes</entry>
<entry>An unsigned 32-bit integer in the
message's byte order, indicating the total length in bytes of
@@ -172,9 +171,11 @@
<row>
<entry>4 bytes</entry>
<entry>The message's serial number, an unsigned 32-bit integer in
- the message's byte order. Applications MUST NOT reuse the same
- serial number for different messages more often than 32-bit
- unsigned integer wraparound. Zero is not a valid serial number.
+ the message's byte order. The serial number is a cookie used to
+ identify message replies; thus all outstanding unreplied-to messages
+ from the same connection MUST have a different serial number.
+ Zero is not a valid serial number, but all other numbers are
+ allowed.
</entry>
</row>
</tbody>
@@ -182,19 +183,67 @@
</informaltable>
</para>
<para>
- Flags that can appear in the second byte of the header:
+ Types that can appear in the second byte of the header:
<informaltable>
- <tgroup cols=2>
+ <tgroup cols=3>
+ <thead>
+ <row>
+ <entry>Conventional name</entry>
+ <entry>Decimal value</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>INVALID</entry>
+ <entry>0</entry>
+ <entry>This is an invalid type, if seen in a message
+ the connection should be dropped immediately.</entry>
+ </row>
+ <row>
+ <entry>METHOD_CALL</entry>
+ <entry>1</entry>
+ <entry>Method call.</entry>
+ </row>
+ <row>
+ <entry>METHOD_RETURN</entry>
+ <entry>2</entry>
+ <entry>Method reply with returned data.</entry>
+ </row>
+ <row>
+ <entry>ERROR</entry>
+ <entry>3</entry>
+ <entry>Error reply. If the first argument exists and is a
+ string, it is an error message.</entry>
+ </row>
+ <row>
+ <entry>SIGNAL</entry>
+ <entry>4</entry>
+ <entry>Signal emission.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </para>
+ <para>
+ Flags that can appear in the third byte of the header:
+ <informaltable>
+ <tgroup cols=3>
<thead>
<row>
+ <entry>Conventional name</entry>
<entry>Hex value</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
+ <entry>NO_REPLY_EXPECTED</entry>
<entry>0x1</entry>
- <entry>This message is an error reply. If the first argument exists and is a string, it is an error message.</entry>
+ <entry>This message does not expect method return replies or
+ error replies; the reply can be omitted as an
+ optimization. However, it is compliant with this specification
+ to return the reply despite this flag.</entry>
</row>
</tbody>
</tgroup>
@@ -208,22 +257,21 @@
In addition to the required header information mentioned
in <xref linkend="message-protocol-header-encoding">,
the header may contain zero or more named
- header fields. These fields are named to allow
- future versions of this protocol specification to
- add new fields; implementations must ignore fields
- they do not understand. Implementations must not
- invent their own header fields; only changes to
+ header fields. Future versions of this protocol
+ specification may add new fields. Implementations must
+ ignore fields they do not understand. Implementations
+ must not invent their own header fields; only changes to
this specification may introduce new header fields.
</para>
<para>
- Header field names MUST consist of 4 non-nul bytes. The field name is
- NOT nul terminated; it occupies exactly 4 bytes. Following the name, the
- field MUST have a type code represented as a single unsigned byte, and
- then a properly-aligned value of that type. See <xref
- linkend="message-protocol-arguments"> for a description of how each type
- is encoded. If an implementation sees a header field name that it does
- not understand, it MUST ignore that field.
+ Header field names MUST consist of a single byte, possible values
+ of which are defined below. Following the name, the field MUST have
+ a type code represented as a single unsigned byte, and then a
+ properly-aligned value of that type. See <xref
+ linkend="message-protocol-arguments"> for a description of how each
+ type is encoded. If an implementation sees a header field name that
+ it does not understand, it MUST ignore that field.
</para>
<para>
@@ -232,36 +280,68 @@
<tgroup cols=3>
<thead>
<row>
- <entry>Name</entry>
+ <entry>Conventional Name</entry>
+ <entry>Decimal Value</entry>
<entry>Type</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
- <entry>name</entry>
+ <entry>INVALID</entry>
+ <entry>0</entry>
+ <entry>INVALID</entry>
+ <entry>Not a valid field name (error if it appears in a message)</entry>
+ </row>
+ <row>
+ <entry>PATH</entry>
+ <entry>1</entry>
+ <entry>STRING</entry>
+ <entry>The object to send the message to; objects are identified by
+ a path, "/foo/bar"</entry>
+ </row>
+ <row>
+ <entry>INTERFACE</entry>
+ <entry>2</entry>
+ <entry>STRING</entry>
+ <entry>The interface to invoke a method call on, or
+ that a signal is emitted from. e.g. "org.freedesktop.Introspectable"</entry>
+ </row>
+ <row>
+ <entry>MEMBER</entry>
+ <entry>3</entry>
+ <entry>STRING</entry>
+ <entry>The member, either the method name or signal name.
+ e.g. "Frobate"</entry>
+ </row>
+ <row>
+ <entry>ERROR_NAME</entry>
+ <entry>4</entry>
<entry>STRING</entry>
- <entry>The name of the message, such as org.freedesktop.Peer.Ping</entry>
+ <entry>The name of the error that occurred, for errors</entry>
</row>
<row>
- <entry>rply</entry>
+ <entry>REPLY_SERIAL</entry>
+ <entry>5</entry>
<entry>UINT32</entry>
<entry>The serial number of the message this message is a reply
to. (The serial number is one of the mandatory header fields,
see <xref linkend="message-protocol-header-encoding">.)</entry>
</row>
<row>
- <entry>srvc</entry>
+ <entry>SERVICE</entry>
+ <entry>6</entry>
<entry>STRING</entry>
<entry>The name of the service this message should be routed to.
Only used in combination with the message bus, see
<xref linkend="message-bus">.</entry>
</row>
<row>
- <entry>sndr</entry>
+ <entry>SENDER_SERVICE</entry>
+ <entry>7</entry>
<entry>STRING</entry>
- <entry>The name of the base service that sent this message.
- The message bus fills in this field; the field is
+ <entry>Sender service. The name of the base service that sent
+ this message. The message bus fills in this field; the field is
only meaningful in combination with the message bus.</entry>
</row>
</tbody>
@@ -277,10 +357,9 @@
buffer while keeping data types aligned, the total length of the header
must be a multiple of 8 bytes. To achieve this, the header MUST be padded
with nul bytes to align its total length on an 8-byte boundary.
- The minimum number of padding bytes MUST be used. Because all possible
- named fields use at least 8 bytes, implementations can distinguish
- padding (which must be less than 8 bytes) from additional named fields
- (which must be at least 8 bytes).
+ The minimum number of padding bytes MUST be used. Because zero is an
+ invalid field name, implementations can distinguish padding (which must be
+ zero initialized) from additional named fields.
</para>
</sect2>
@@ -440,19 +519,228 @@
<sect2 id="message-protocol-names">
<title>Valid names</title>
<para>
- Messages and services have names with type STRING, meaning that
- they must be valid UTF-8. However, there are also some
- additional restrictions that apply to message and service names
- specifically:
- <itemizedlist>
- <listitem><para>They must contain at least one '.' (period) character</para></listitem>
- <listitem><para>They must not begin with a '.' (period) character</para></listitem>
- <listitem><para>They must not exceed 256 bytes in length</para></listitem>
- <listitem><para>They must be at least 1 byte in length</para></listitem>
- </itemizedlist>
- As a special exception, base service names (those beginning with a colon (':') character)
- need not contain a period.
+ The various header fields of type STRING have some restrictions
+ on the string's format.
+ </para>
+ <sect3 id="message-protocol-names-service">
+ <title>Service names</title>
+ <para>
+ Services have names with type STRING, meaning that
+ they must be valid UTF-8. However, there are also some
+ additional restrictions that apply to service names
+ specifically:
+ <itemizedlist>
+ <listitem><para>They must contain at least one '.' (period) character</para></listitem>
+ <listitem><para>They must not begin with a '.' (period) character</para></listitem>
+ <listitem><para>They must not exceed 256 bytes in length</para></listitem>
+ <listitem><para>They must be at least 1 byte in length</para></listitem>
+ </itemizedlist>
+
+ As a special exception, base service names (those beginning with a colon
+ (':') character) need not contain a period.
+ </para>
+ <para>
+ FIXME really, shouldn't we ban basically everything non-alphanumeric
+ so the name will work in all programming languages?
+ </para>
+ </sect3>
+ <sect3 id="message-protocol-names-interface">
+ <title>Interface names</title>
+ <para>
+ Interface names have the same restrictions as service names,
+ but do not have the special exception for names beginning with
+ a colon.
+ </para>
+ <para>
+ FIXME really, shouldn't we ban basically everything non-alphanumeric
+ so the name will work in all programming languages?
+ </para>
+ </sect3>
+ <sect3 id="message-protocol-names-method">
+ <title>Method names</title>
+ <para>
+ Method names:
+ <itemizedlist>
+ <listitem><para>May not contain the '.' (period) character</para></listitem>
+ <listitem><para>Must not exceed 256 bytes in length</para></listitem>
+ <listitem><para>Must be at least 1 byte in length</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ FIXME really, shouldn't we ban basically everything non-alphanumeric
+ so the name will work in all programming languages?
+ </para>
+ </sect3>
+ <sect3 id="message-protocol-names-path">
+ <title>Path names</title>
+ <para>
+ A path must begin with an ASCII '/' (slash) character. Paths may not
+ end with a slash character unless the path is the one-byte string
+ "/". Two slash characters may not appear adjacent to one another (the
+ empty string is not a valid "subdirectory"). Paths may not exceed
+ 256 bytes in length.
+ </para>
+ </sect3>
+ <sect3 id="message-protocol-names-error">
+ <title>Error names</title>
+ <para>
+ Error names have the same restrictions as interface names.
+ </para>
+ <para>
+ FIXME really, shouldn't we ban basically everything non-alphanumeric
+ so the name will work in all programming languages?
+ </para>
+ </sect3>
+ </sect2>
+
+ <sect2 id="message-protocol-types">
+ <title>Message types</title>
+ <para>
+ Each of the message types (METHOD_CALL, METHOD_RETURN, ERROR, and
+ SIGNAL) has its own expected usage conventions and header fields.
</para>
+ <sect3 id="message-protocol-types-method">
+ <title>Method Calls, Returns, and Errors</title>
+ <para>
+ Some messages invoke an operation on a remote object. These are
+ called method call messages and have the type tag METHOD_CALL. Such
+ messages map naturally to methods on objects in a typical program.
+ </para>
+ <para>
+ A method call message is expected to have a MEMBER header field
+ indicating the name of the method. Optionally, the message has an
+ INTERFACE field giving the interface the method is a part of. In the
+ absence of an INTERFACE field, if two interfaces on the same object have
+ a method with the same name, it is undefined which of the two methods
+ will be invoked. Implementations may also choose to return an error in
+ this ambiguous case. However, if a method name is unique
+ implementations should not require an interface field.
+ </para>
+ <para>
+ Method call messages also include a PATH field indicating the
+ object to invoke the method on. If the call is passing through
+ a message bus, the message will also have a SERVICE field giving
+ the service to receive the message.
+ </para>
+ <para>
+ When an application handles a method call message, it is expected to
+ return a reply. The reply is identified by a REPLY_SERIAL header field
+ indicating the serial number of the METHOD_CALL being replied to. The
+ reply can have one of two types; either METHOD_RETURN or ERROR.
+ </para>
+ <para>
+ If the reply has type METHOD_RETURN, the arguments to the reply message
+ are the return value(s) or "out parameters" of the method call.
+ If the reply has type ERROR, then an "exception" has been thrown,
+ and the call fails; no return value will be provided. It makes
+ no sense to send multiple replies to the same method call.
+ </para>
+ <para>
+ Even if a method call has no return values, a METHOD_RETURN
+ reply is expected, so the caller will know the method
+ was successfully processed.
+ </para>
+ <para>
+ If a METHOD_CALL message has the flag NO_REPLY_EXPECTED,
+ then as an optimization the application receiving the method
+ call may choose to omit the reply message (regardless of
+ whether the reply would have been METHOD_RETURN or ERROR).
+ However, it is also acceptable to ignore the NO_REPLY_EXPECTED
+ flag and reply anyway.
+ </para>
+ <sect4 id="message-protocol-types-method-apis">
+ <title>Mapping method calls to native APIs</title>
+ <para>
+ APIs for D-BUS may map method calls to a method call in a specific
+ programming language, such as C++, or may map a method call written
+ in an IDL to a D-BUS message.
+ </para>
+ <para>
+ In APIs of this nature, arguments to a method are often termed "in"
+ (which implies sent in the METHOD_CALL), or "out" (which implies
+ returned in the METHOD_RETURN). Some APIs such as CORBA also have
+ "inout" arguments, which are both sent and received, i.e. the caller
+ passes in a value which is modified. Mapped to D-BUS, an "inout"
+ argument is equivalent to an "in" argument, followed by an "out"
+ argument. You can't pass things "by reference" over the wire, so
+ "inout" is purely an illusion of the in-process API.
+ </para>
+ <para>
+ Given a method with zero or one return values, followed by zero or more
+ arguments, where each argument may be "in", "out", or "inout", the
+ caller constructs a message by appending each "in" or "inout" argument,
+ in order. "out" arguments are not represented in the caller's message.
+ </para>
+ <para>
+ The recipient constructs a reply by appending first the return value
+ if any, then each "out" or "inout" argument, in order.
+ "in" arguments are not represented in the reply message.
+ </para>
+ </sect4>
+
+ </sect3>
+
+ <sect3 id="message-protocol-types-signal">
+ <title>Signal Emission</title>
+ <para>
+ Unlike method calls, signal emissions have no replies.
+ A signal emission is simply a single message of type SIGNAL.
+ It must have three header fields: PATH giving the object
+ the signal was emitted from, plus INTERFACE and MEMBER giving
+ the fully-qualified name of the signal.
+ </para>
+ </sect3>
+
+ <sect3 id="message-protocol-types-notation">
+ <title>Notation in this document</title>
+ <para>
+ This document uses a simple pseudo-IDL to describe particular method
+ calls and signals. Here is an example of a method call:
+ <programlisting>
+ org.freedesktop.DBus.ActivateService (in STRING service_name, in UINT32 flags,
+ out UINT32 resultcode)
+ </programlisting>
+ This means INTERFACE = org.freedesktop.DBus, MEMBER = ActivateService,
+ METHOD_CALL arguments are STRING and UINT32, METHOD_RETURN argument
+ is UINT32. Remember that the MEMBER field can't contain any '.' (period)
+ characters so it's known that the last part of the name in
+ the "IDL" is the member name.
+ </para>
+ <para>
+ In C++ that might end up looking like this:
+ <programlisting>
+ unsigned int org::freedesktop::DBus::ActivateService (const char *service_name,
+ unsigned int flags);
+ </programlisting>
+ or equally valid, the return value could be done as an argument:
+ <programlisting>
+ void org::freedesktop::DBus::ActivateService (const char *service_name,
+ unsigned int flags,
+ unsigned int *resultcode);
+ </programlisting>
+ It's really up to the API designer how they want to make
+ this look. You could design an API where the namespace wasn't used
+ in C++, using STL or Qt, using varargs, or whatever you wanted.
+ </para>
+ <para>
+ Signals are written as follows:
+ <programlisting>
+ org.freedesktop.DBus.ServiceLost (STRING service_name)
+ </programlisting>
+ Signals don't specify "in" vs. "out" because only
+ a single direction is possible.
+ </para>
+ <para>
+ In this ad hoc notation, the special type name ANY means any type
+ other than NIL, and the special type name ANY_OR_NIL means any valid
+ type.
+ </para>
+ <para>
+ It isn't especially encouraged to use this lame pseudo-IDL in actual
+ API implementations; you might use the native notation for the
+ language you're using, or you might use COM or CORBA IDL, for example.
+ </para>
+ </sect3>
</sect2>
</sect1>
@@ -730,6 +1018,13 @@
</figure>
</para>
</sect2>
+ <sect2 id="auth-states">
+ <title>Authentication state diagrams</title>
+
+ <para>
+ WRITEME
+ </para>
+ </sect2>
<sect2 id="auth-mechanisms">
<title>Authentication mechanisms</title>
<para>
@@ -905,161 +1200,35 @@
</para>
</sect1>
- <sect1 id="message-conventions">
- <title>Message Conventions</title>
- <para>
- This section documents conventions that are not essential to D-BUS
- functionality, but should generally be followed in order to simplify
- programmer's lives.
- </para>
- <sect2 id="message-conventions-naming">
- <title>Message Naming</title>
- <para>
- Messages are normally named in the form
- "org.freedesktop.Peer.Ping", which has three
- distinct components:
- <variablelist>
- <varlistentry>
- <term>Namespace e.g. <literal>org.freedesktop</literal></term>
- <listitem>
- <para>
- Message names have a Java-style namespace: a reversed domain
- name. The components of the domain are normally lowercase.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Package or object e.g. <literal>Peer</literal></term>
- <listitem>
- <para>
- The next part of the message name can be thought of as the name
- of a singleton object, or as the name of a package of related
- messages. More than one dot-separated component might be used
- here. (Note that D-BUS does not define any idea of object
- instances or object references.) The package or object name is
- capitalized LikeThis.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Method or operation e.g. <literal>Ping</literal></term>
- <listitem>
- <para>
- The final part of the message name is the most specific, and
- should be a verb indicating an operation to be performed on the
- object. The method or operation name is capitalized LikeThis.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
- <para>
- A reply to a message conventionally has the same name as the message
- being replied to. When following method call conventions (see <xref
- linkend="message-conventions-method">), this convention is mandatory,
- because a message with multiple possible replies can't be mapped
- to method call semantics without special-case code.
- </para>
- </sect2>
- <sect2 id="message-conventions-method">
- <title>Method Call Mapping</title>
- <para>
- Some implementations of D-BUS may present an API that translates object
- method calls into D-BUS messages. This document does not specify in
- detail how such an API should look or work. However, it does specify how
- message-based protocols should be designed to be friendly to such an
- API.
- </para>
- <para>
- Remember that D-BUS does not have object references or object instances.
- So when one application sends the message
- <literal>org.freedesktop.Peer.Ping</literal>, it sends it to another
- application, not to any kind of sub-portion of that application.
- However, a convenience API used within the recipient application may
- route all messages that start with
- <literal>org.freedesktop.Peer</literal> to a particular object instance,
- and may invoke the <literal>Ping()</literal> method on said instance in
- order to handle the message. This is a convenience API based on
- method calls.
- </para>
- <para>
- A "method call" consists of a message and, optionally, a reply to that
- message. The name of the "method" is the last component of the message,
- for example, <literal>org.freedesktop.Peer.Ping</literal> would map to
- the method <literal>Ping()</literal> on some object.
- </para>
- <para>
- Arguments to a method may be considered "in" (processed by the
- recipient of the message), or "out" (returned to the sender of the
- message in the reply). "inout" arguments are both sent and received,
- i.e. the caller passes in a value which is modified. An "inout" argument
- is equivalent to an "in" argument, followed by an "out" argument.
- </para>
- <para>
- Given a method with zero or one return values, followed by zero or more
- arguments, where each argument may be "in", "out", or "inout", the
- caller constructs a message by appending each "in" or "inout" argument,
- in order. "out" arguments are not represented in the caller's message.
- </para>
- <para>
- The recipient constructs a reply by appending first the return value
- if any, then each "out" or "inout" argument, in order.
- "in" arguments are not represented in the reply message.
- </para>
- <para>
- The standard reply message MUST have the same name as the message being
- replied to, and MUST set the "rply" header field to the serial
- number of the message being replied to.
- </para>
- <para>
- If an error occurs, an error reply may be sent in place of the standard
- reply. Error replies can be identified by a special header flag, see
- <xref linkend="message-protocol-header-encoding">. Error replies have a
- name which reflects the type of error that occurred. Error replies would
- generally be mapped to exceptions in a programming language. If an
- error reply has a first argument, and that argument has type STRING,
- then the argument must be an error message.
- </para>
- <para>
- [FIXME discuss mapping of broadcast messages + matching rules
- to signals and slots]
- </para>
- </sect2>
- </sect1>
-
<sect1 id="standard-messages">
<title>Standard Peer-to-Peer Messages</title>
<para>
- In the following message definitions, "method call notation" is presented
- in addition to simply listing the message names and arguments. The special
- type name ANY means any type other than NIL, and the special type name
- ANY_OR_NIL means any valid type.
- [FIXME the messages here are just made up to illustrate the
- format for defining them]
+ See <xref linkend="message-protocol-types-notation"> for details on
+ the notation used in this section.
</para>
<sect2 id="standard-messages-ping">
<title><literal>org.freedesktop.Peer.Ping</literal></title>
<para>
- As a method:
<programlisting>
- void Ping ()
+ org.freedesktop.Peer.Ping ()
</programlisting>
</para>
<para>
- On receipt of the message <literal>org.freedesktop.Peer.Ping</literal>,
- an application should reply with
- <literal>org.freedesktop.Peer.Ping</literal>. Neither the
- message nor its reply have any arguments.
- [FIXME the messages here are just made up to illustrate the
- format for defining them]
+ On receipt of the METHOD_CALL
+ message <literal>org.freedesktop.Peer.Ping</literal>, an application
+ should do nothing other than reply with a METHOD_RETURN as usual.
</para>
</sect2>
+
<sect2 id="standard-messages-get-props">
<title><literal>org.freedesktop.Props.Get</literal></title>
<para>
- As a method:
+ [FIXME this is just a bogus made-up method that isn't implemented
+ or thought through, to save an example of table formatting for the
+ argument descriptions]
<programlisting>
- ANY_OR_NIL Get (in STRING property_name)
+ org.freedesktop.Props.Get (in STRING property_name,
+ out ANY_OR_NIL property_value)
</programlisting>
Message arguments:
<informaltable>
@@ -1074,37 +1243,18 @@
<tbody>
<row>
<entry>0</entry>
- <entry>STRING</entry>
+ <entry>in STRING</entry>
<entry>Name of the property to get</entry>
</row>
- </tbody>
- </tgroup>
- </informaltable>
- Reply arguments:
- <informaltable>
- <tgroup cols=3>
- <thead>
- <row>
- <entry>Argument</entry>
- <entry>Type</entry>
- <entry>Description</entry>
- </row>
- </thead>
- <tbody>
<row>
- <entry>0</entry>
- <entry>ANY_OR_NIL</entry>
+ <entry>1</entry>
+ <entry>out ANY_OR_NIL</entry>
<entry>The value of the property. The type depends on the property.</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
- <para>
-
- [FIXME the messages here are just made up to illustrate the
- format for defining them]
- </para>
</sect2>
</sect1>
@@ -1132,18 +1282,18 @@
the new owner of the service.
</para>
<para>
- Messages may have a <literal>srvc</literal> field (see <xref
+ Messages may have a <literal>SERVICE</literal> field (see <xref
linkend="message-protocol-header-fields">). When the message bus
- receives a message, if the <literal>srvc</literal> field is absent, the
+ receives a message, if the <literal>SERVICE</literal> field is absent, the
message is taken to be a standard peer-to-peer message and interpreted
by the message bus itself. For example, sending
an <literal>org.freedesktop.Peer.Ping</literal> message with no
- <literal>srvc</literal> will cause the message bus itself to reply
+ <literal>SERVICE</literal> will cause the message bus itself to reply
to the ping immediately; the message bus would never make
this message visible to other applications.
</para>
<para>
- If the <literal>srvc</literal> field is present, then it indicates a
+ If the <literal>SERVICE</literal> field is present, then it indicates a
request for the message bus to route the message. In the usual case,
messages are routed to the owner of the named service.
Messages may also be <firstterm>broadcast</firstterm>
@@ -1154,7 +1304,7 @@
</para>
<para>
Continuing the <literal>org.freedesktop.Peer.Ping</literal> example, if
- the ping message were sent with a <literal>srvc</literal> name of
+ the ping message were sent with a <literal>SERVICE</literal> name of
<literal>com.yoyodyne.Screensaver</literal>, then the ping would be
forwarded, and the Yoyodyne Corporation screensaver application would be
expected to reply to the ping. If
@@ -1967,6 +2117,32 @@
</para>
</glossdef>
</glossentry>
+
+ <glossentry id="term-object"><glossterm>Object</glossterm>
+ <glossdef>
+ <para>
+ Each application contains <firstterm>objects</firstterm>,
+ which have <firstterm>interfaces</firstterm> and
+ <firstterm>methods</firstterm>. Objects are referred to
+ by a name, called a <firstterm>path</firstterm> or
+ <firstterm>object reference</firstterm>.
+ </para>
+ </glossdef>
+ </glossentry>
+
+ <glossentry id="term-path"><glossterm>Path</glossterm>
+ <glossdef>
+ <para>
+ Object references (object names) in D-BUS are
+ organized into a filesystem-style hierarchy, so
+ each object is named by a path. As in LDAP,
+ there's no difference between "files" and "directories";
+ a path can refer to an object, while still having
+ child objects below it.
+ </para>
+ </glossdef>
+ </glossentry>
+
<glossentry id="peer-to-peer"><glossterm>Peer-to-peer</glossterm>
<glossdef>
<para>
diff --git a/glib/.cvsignore b/glib/.cvsignore
index a6e3d2b5..881b4887 100644
--- a/glib/.cvsignore
+++ b/glib/.cvsignore
@@ -4,11 +4,9 @@ Makefile
Makefile.in
*.lo
*.la
-test-dbus-glib
+dbus-glib-test
+dbus-glib-tool
*.bb
*.bbg
*.da
*.gcov
-test-thread-client
-test-thread-server
-test-profile
diff --git a/glib/Makefile.am b/glib/Makefile.am
index ebdb932f..a45aa593 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -1,4 +1,4 @@
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS)
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) -DDBUS_COMPILATION=1
dbusincludedir=$(includedir)/dbus-1.0/dbus
@@ -9,47 +9,61 @@ dbusinclude_HEADERS= \
libdbus_glib_1_la_SOURCES = \
dbus-gmain.c \
- dbus-gthread.c
+ dbus-gobject.c \
+ dbus-gproxy.c \
+ dbus-gtest.c \
+ dbus-gtest.h \
+ dbus-gthread.c \
+ dbus-gutils.c \
+ dbus-gutils.h
libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la
+## don't export symbols that start with "_" (we use this
+## convention for internal symbols)
+libdbus_glib_1_la_LDFLAGS= -export-symbols-regex "^[^_].*"
-if DBUS_BUILD_TESTS
+# convenience lib used here and by dbus-viewer
+noinst_LTLIBRARIES=libdbus-gtool.la
-if HAVE_GLIB_THREADS
-THREAD_APPS=test-thread-server test-thread-client test-profile
+libdbus_gtool_la_SOURCES = \
+ dbus-gidl.c \
+ dbus-gidl.h \
+ dbus-gloader-expat.c \
+ dbus-gparser.c \
+ dbus-gparser.h \
+ dbus-gutils.c \
+ dbus-gutils.h
-test_thread_server_SOURCES= \
- test-thread-server.c \
- test-thread.h
+libdbus_gtool_la_LIBADD = libdbus-glib-1.la
-test_thread_server_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la
+bin_PROGRAMS=dbus-glib-tool
-test_thread_client_SOURCES= \
- test-thread-client.c \
- test-thread.h
+dbus_glib_tool_SOURCES = \
+ dbus-glib-tool.c \
+ dbus-gtool-test.h
-test_thread_client_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la
-endif
+dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-gtool.la
+
+if DBUS_BUILD_TESTS
-noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS)
+## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we
+## build even when not doing "make check"
+noinst_PROGRAMS= $(TESTS)
-test_dbus_glib_SOURCES= \
- test-dbus-glib.c
+## note that TESTS has special meaning (stuff to use in make check)
+## so if adding tests not to be run in make check, don't add them to
+## TESTS
+TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_builddir)/test/data DBUS_TEST_HOMEDIR=$(top_builddir)/dbus
+TESTS=dbus-glib-test
-test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
+dbus_glib_test_SOURCES= \
+ dbus-gtest-main.c
+
+dbus_glib_test_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
else
### not building tests
-
-if HAVE_GLIB_THREADS
-noinst_PROGRAMS=test-profile
-endif
+TESTS=
endif
-if HAVE_GLIB_THREADS
-test_profile_SOURCES= \
- test-profile.c
-
-test_profile_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la
-endif \ No newline at end of file
diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c
new file mode 100644
index 00000000..596b43ca
--- /dev/null
+++ b/glib/dbus-gidl.c
@@ -0,0 +1,524 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gidl.c data structure describing an interface, to be generated from IDL
+ * or something
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "dbus-gidl.h"
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+struct BaseInfo
+{
+ unsigned int refcount : 28;
+ unsigned int type : 4;
+ char *name;
+};
+
+struct NodeInfo
+{
+ BaseInfo base;
+ GSList *interfaces;
+ GSList *nodes;
+};
+
+struct InterfaceInfo
+{
+ BaseInfo base;
+ /* Since we have BaseInfo now these could be one list */
+ GSList *methods;
+ GSList *signals;
+};
+
+struct MethodInfo
+{
+ BaseInfo base;
+ GSList *args;
+};
+
+struct SignalInfo
+{
+ BaseInfo base;
+ GSList *args;
+};
+
+struct ArgInfo
+{
+ BaseInfo base;
+ int type;
+ ArgDirection direction;
+};
+
+void
+base_info_ref (BaseInfo *info)
+{
+ g_return_if_fail (info != NULL);
+ g_return_if_fail (info->refcount > 0);
+
+ info->refcount += 1;
+}
+
+static void
+base_info_free (void *ptr)
+{
+ BaseInfo *info;
+
+ info = ptr;
+
+ g_free (info->name);
+ g_free (info);
+}
+
+void
+base_info_unref (BaseInfo *info)
+{
+ g_return_if_fail (info != NULL);
+ g_return_if_fail (info->refcount > 0);
+
+ /* This is sort of bizarre, BaseInfo was tacked on later */
+
+ switch (info->type)
+ {
+ case INFO_TYPE_NODE:
+ node_info_unref ((NodeInfo*) info);
+ break;
+ case INFO_TYPE_INTERFACE:
+ interface_info_unref ((InterfaceInfo*) info);
+ break;
+ case INFO_TYPE_SIGNAL:
+ signal_info_unref ((SignalInfo*) info);
+ break;
+ case INFO_TYPE_METHOD:
+ method_info_unref ((MethodInfo*) info);
+ break;
+ case INFO_TYPE_ARG:
+ arg_info_unref ((ArgInfo*) info);
+ break;
+ }
+}
+
+InfoType
+base_info_get_type (BaseInfo *info)
+{
+ return info->type;
+}
+
+const char*
+base_info_get_name (BaseInfo *info)
+{
+ return info->name;
+}
+
+void
+base_info_set_name (BaseInfo *info,
+ const char *name)
+{
+ char *old;
+
+ old = info->name;
+ info->name = g_strdup (name);
+ g_free (old);
+}
+
+GType
+base_info_get_gtype (void)
+{
+ static GType our_type = 0;
+
+ if (our_type == 0)
+ our_type = g_boxed_type_register_static ("BaseInfo",
+ (GBoxedCopyFunc) base_info_ref,
+ (GBoxedFreeFunc) base_info_unref);
+
+ return our_type;
+}
+
+static void
+free_interface_list (GSList **interfaces_p)
+{
+ GSList *tmp;
+ tmp = *interfaces_p;
+ while (tmp != NULL)
+ {
+ interface_info_unref (tmp->data);
+ tmp = tmp->next;
+ }
+ g_slist_free (*interfaces_p);
+ *interfaces_p = NULL;
+}
+
+static void
+free_node_list (GSList **nodes_p)
+{
+ GSList *tmp;
+ tmp = *nodes_p;
+ while (tmp != NULL)
+ {
+ node_info_unref (tmp->data);
+ tmp = tmp->next;
+ }
+ g_slist_free (*nodes_p);
+ *nodes_p = NULL;
+}
+
+static void
+free_method_list (GSList **methods_p)
+{
+ GSList *tmp;
+ tmp = *methods_p;
+ while (tmp != NULL)
+ {
+ method_info_unref (tmp->data);
+ tmp = tmp->next;
+ }
+ g_slist_free (*methods_p);
+ *methods_p = NULL;
+}
+
+static void
+free_signal_list (GSList **signals_p)
+{
+ GSList *tmp;
+ tmp = *signals_p;
+ while (tmp != NULL)
+ {
+ signal_info_unref (tmp->data);
+ tmp = tmp->next;
+ }
+ g_slist_free (*signals_p);
+ *signals_p = NULL;
+}
+
+NodeInfo*
+node_info_new (const char *name)
+{
+ NodeInfo *info;
+
+ /* name can be NULL */
+
+ info = g_new0 (NodeInfo, 1);
+ info->base.refcount = 1;
+ info->base.name = g_strdup (name);
+ info->base.type = INFO_TYPE_NODE;
+
+ return info;
+}
+
+void
+node_info_ref (NodeInfo *info)
+{
+ info->base.refcount += 1;
+}
+
+void
+node_info_unref (NodeInfo *info)
+{
+ info->base.refcount -= 1;
+ if (info->base.refcount == 0)
+ {
+ free_interface_list (&info->interfaces);
+ free_node_list (&info->nodes);
+ base_info_free (info);
+ }
+}
+
+const char*
+node_info_get_name (NodeInfo *info)
+{
+ return info->base.name;
+}
+
+GSList*
+node_info_get_interfaces (NodeInfo *info)
+{
+ return info->interfaces;
+}
+
+void
+node_info_add_interface (NodeInfo *info,
+ InterfaceInfo *interface)
+{
+ interface_info_ref (interface);
+ info->interfaces = g_slist_append (info->interfaces, interface);
+}
+
+GSList*
+node_info_get_nodes (NodeInfo *info)
+{
+ return info->nodes;
+}
+
+void
+node_info_add_node (NodeInfo *info,
+ NodeInfo *node)
+{
+ node_info_ref (node);
+ info->nodes = g_slist_append (info->nodes, node);
+}
+
+InterfaceInfo*
+interface_info_new (const char *name)
+{
+ InterfaceInfo *info;
+
+ info = g_new0 (InterfaceInfo, 1);
+ info->base.refcount = 1;
+ info->base.name = g_strdup (name);
+ info->base.type = INFO_TYPE_INTERFACE;
+
+ return info;
+}
+
+void
+interface_info_ref (InterfaceInfo *info)
+{
+ info->base.refcount += 1;
+}
+
+void
+interface_info_unref (InterfaceInfo *info)
+{
+ info->base.refcount -= 1;
+ if (info->base.refcount == 0)
+ {
+ free_method_list (&info->methods);
+ free_signal_list (&info->signals);
+ base_info_free (info);
+ }
+}
+
+const char*
+interface_info_get_name (InterfaceInfo *info)
+{
+ return info->base.name;
+}
+
+GSList*
+interface_info_get_methods (InterfaceInfo *info)
+{
+ return info->methods;
+}
+
+GSList*
+interface_info_get_signals (InterfaceInfo *info)
+{
+ return info->signals;
+}
+
+void
+interface_info_add_method (InterfaceInfo *info,
+ MethodInfo *method)
+{
+ method_info_ref (method);
+ info->methods = g_slist_append (info->methods, method);
+}
+
+void
+interface_info_add_signal (InterfaceInfo *info,
+ SignalInfo *signal)
+{
+ signal_info_ref (signal);
+ info->signals = g_slist_append (info->signals, signal);
+}
+
+static void
+free_arg_list (GSList **args_p)
+{
+ GSList *tmp;
+ tmp = *args_p;
+ while (tmp != NULL)
+ {
+ arg_info_unref (tmp->data);
+ tmp = tmp->next;
+ }
+ g_slist_free (*args_p);
+ *args_p = NULL;
+}
+
+MethodInfo*
+method_info_new (const char *name)
+{
+ MethodInfo *info;
+
+ info = g_new0 (MethodInfo, 1);
+ info->base.refcount = 1;
+ info->base.name = g_strdup (name);
+ info->base.type = INFO_TYPE_METHOD;
+
+ return info;
+}
+
+void
+method_info_ref (MethodInfo *info)
+{
+ info->base.refcount += 1;
+}
+
+void
+method_info_unref (MethodInfo *info)
+{
+ info->base.refcount -= 1;
+ if (info->base.refcount == 0)
+ {
+ free_arg_list (&info->args);
+ base_info_free (info);
+ }
+}
+
+const char*
+method_info_get_name (MethodInfo *info)
+{
+ return info->base.name;
+}
+
+GSList*
+method_info_get_args (MethodInfo *info)
+{
+ return info->args;
+}
+
+void
+method_info_add_arg (MethodInfo *info,
+ ArgInfo *arg)
+{
+ arg_info_ref (arg);
+ info->args = g_slist_append (info->args, arg);
+}
+
+SignalInfo*
+signal_info_new (const char *name)
+{
+ SignalInfo *info;
+
+ info = g_new0 (SignalInfo, 1);
+ info->base.refcount = 1;
+ info->base.name = g_strdup (name);
+ info->base.type = INFO_TYPE_SIGNAL;
+
+ return info;
+}
+
+void
+signal_info_ref (SignalInfo *info)
+{
+ info->base.refcount += 1;
+}
+
+void
+signal_info_unref (SignalInfo *info)
+{
+ info->base.refcount -= 1;
+ if (info->base.refcount == 0)
+ {
+ free_arg_list (&info->args);
+ base_info_free (info);
+ }
+}
+
+const char*
+signal_info_get_name (SignalInfo *info)
+{
+ return info->base.name;
+}
+
+GSList*
+signal_info_get_args (SignalInfo *info)
+{
+ return info->args;
+}
+
+void
+signal_info_add_arg (SignalInfo *info,
+ ArgInfo *arg)
+{
+ arg_info_ref (arg);
+ info->args = g_slist_append (info->args, arg);
+}
+
+ArgInfo*
+arg_info_new (const char *name,
+ ArgDirection direction,
+ int type)
+{
+ ArgInfo *info;
+
+ info = g_new0 (ArgInfo, 1);
+ info->base.refcount = 1;
+ info->base.type = INFO_TYPE_ARG;
+
+ /* name can be NULL */
+ info->base.name = g_strdup (name);
+ info->direction = direction;
+ info->type = type;
+
+ return info;
+}
+
+void
+arg_info_ref (ArgInfo *info)
+{
+ info->base.refcount += 1;
+}
+
+void
+arg_info_unref (ArgInfo *info)
+{
+ info->base.refcount -= 1;
+ if (info->base.refcount == 0)
+ {
+ base_info_free (info);
+ }
+}
+const char*
+arg_info_get_name (ArgInfo *info)
+{
+ return info->base.name;
+}
+
+int
+arg_info_get_type (ArgInfo *info)
+{
+ return info->type;
+}
+
+ArgDirection
+arg_info_get_direction (ArgInfo *info)
+{
+ return info->direction;
+}
+
+#ifdef DBUS_BUILD_TESTS
+
+/**
+ * @ingroup DBusGIDL
+ * Unit test for GLib IDL internals
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_gidl_test (void)
+{
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h
new file mode 100644
index 00000000..f95abfbd
--- /dev/null
+++ b/glib/dbus-gidl.h
@@ -0,0 +1,120 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gidl.h data structure describing an interface, to be generated from IDL
+ * or something
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef DBUS_GLIB_IDL_H
+#define DBUS_GLIB_IDL_H
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+#include <dbus/dbus.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct BaseInfo BaseInfo;
+typedef struct NodeInfo NodeInfo;
+typedef struct InterfaceInfo InterfaceInfo;
+typedef struct MethodInfo MethodInfo;
+typedef struct SignalInfo SignalInfo;
+typedef struct ArgInfo ArgInfo;
+
+typedef enum
+{
+ ARG_IN,
+ ARG_OUT
+} ArgDirection;
+
+typedef enum
+{
+ INFO_TYPE_NODE,
+ INFO_TYPE_INTERFACE,
+ INFO_TYPE_METHOD,
+ INFO_TYPE_SIGNAL,
+ INFO_TYPE_ARG
+
+} InfoType;
+
+void base_info_ref (BaseInfo *info);
+void base_info_unref (BaseInfo *info);
+InfoType base_info_get_type (BaseInfo *info);
+const char* base_info_get_name (BaseInfo *info);
+void base_info_set_name (BaseInfo *info,
+ const char *name);
+GType base_info_get_gtype (void);
+#define BASE_INFO_TYPE (base_info_get_gtype ())
+
+
+NodeInfo* node_info_new (const char *name);
+void node_info_ref (NodeInfo *info);
+void node_info_unref (NodeInfo *info);
+const char* node_info_get_name (NodeInfo *info);
+GSList* node_info_get_interfaces (NodeInfo *info);
+GSList* node_info_get_nodes (NodeInfo *info);
+void node_info_add_interface (NodeInfo *info,
+ InterfaceInfo *interface);
+void node_info_add_node (NodeInfo *info,
+ NodeInfo *child);
+
+InterfaceInfo* interface_info_new (const char *name);
+void interface_info_ref (InterfaceInfo *info);
+void interface_info_unref (InterfaceInfo *info);
+const char* interface_info_get_name (InterfaceInfo *info);
+GSList* interface_info_get_methods (InterfaceInfo *info);
+GSList* interface_info_get_signals (InterfaceInfo *info);
+void interface_info_add_method (InterfaceInfo *info,
+ MethodInfo *method);
+void interface_info_add_signal (InterfaceInfo *info,
+ SignalInfo *signal);
+
+MethodInfo* method_info_new (const char *name);
+void method_info_ref (MethodInfo *info);
+void method_info_unref (MethodInfo *info);
+
+const char* method_info_get_name (MethodInfo *info);
+GSList* method_info_get_args (MethodInfo *info);
+void method_info_add_arg (MethodInfo *info,
+ ArgInfo *arg);
+
+SignalInfo* signal_info_new (const char *name);
+void signal_info_ref (SignalInfo *info);
+void signal_info_unref (SignalInfo *info);
+
+const char* signal_info_get_name (SignalInfo *info);
+GSList* signal_info_get_args (SignalInfo *info);
+void signal_info_add_arg (SignalInfo *info,
+ ArgInfo *arg);
+
+ArgInfo* arg_info_new (const char *name,
+ ArgDirection direction,
+ int type);
+void arg_info_ref (ArgInfo *info);
+void arg_info_unref (ArgInfo *info);
+const char* arg_info_get_name (ArgInfo *info);
+int arg_info_get_type (ArgInfo *info);
+ArgDirection arg_info_get_direction (ArgInfo *info);
+
+G_END_DECLS
+
+#endif /* DBUS_GLIB_IDL_H */
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/glib/dbus-glib-tool.c b/glib/dbus-glib-tool.c
new file mode 100644
index 00000000..aaf133d4
--- /dev/null
+++ b/glib/dbus-glib-tool.c
@@ -0,0 +1,77 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-compiler-main.c main() for GLib stubs/skels generator
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "dbus-gidl.h"
+#include <locale.h>
+
+#ifdef DBUS_BUILD_TESTS
+static void run_all_tests (const char *test_data_dir);
+#endif
+
+int
+main (int argc, char **argv)
+{
+ setlocale(LC_ALL, "");
+
+ return 0;
+}
+
+#ifdef DBUS_BUILD_TESTS
+static void
+test_die (const char *failure)
+{
+ fprintf (stderr, "Unit test failed: %s\n", failure);
+ exit (1);
+}
+
+static void
+run_all_tests (const char *test_data_dir)
+{
+ if (test_data_dir == NULL)
+ test_data_dir = _dbus_getenv ("DBUS_TEST_DATA");
+
+ if (test_data_dir != NULL)
+ printf ("Test data in %s\n", test_data_dir);
+ else
+ printf ("No test data!\n");
+
+ printf ("%s: running gtool tests\n", "dbus-glib-tool");
+ if (!_dbus_gtool_test (test_data_dir))
+ test_die ("gtool");
+
+ printf ("%s: completed successfully\n", "dbus-glib-test");
+}
+
+/**
+ * @ingroup DBusGTool
+ * Unit test for GLib utility tool
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_gtool_test (const char *test_data_dir)
+{
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h
index c6116c52..46f4555d 100644
--- a/glib/dbus-glib.h
+++ b/glib/dbus-glib.h
@@ -2,6 +2,7 @@
/* dbus-glib.h GLib integration
*
* Copyright (C) 2002, 2003 CodeFactory AB
+ * Copyright (C) 2003 Red Hat, Inc.
*
* Licensed under the Academic Free License version 1.2
*
@@ -24,16 +25,132 @@
#define DBUS_GLIB_H
#include <dbus/dbus.h>
-#include <glib.h>
+#include <glib-object.h>
G_BEGIN_DECLS
-void dbus_gthread_init (void);
+#define DBUS_INSIDE_DBUS_GLIB_H 1
+
+GQuark dbus_g_error_quark (void);
+#define DBUS_GERROR dbus_g_error_quark ()
+
+#define DBUS_TYPE_CONNECTION (dbus_connection_get_g_type ())
+#define DBUS_TYPE_MESSAGE (dbus_message_get_g_type ())
+GType dbus_connection_get_g_type (void) G_GNUC_CONST;
+GType dbus_message_get_g_type (void) G_GNUC_CONST;
+
+typedef enum
+{
+ /* FIXME map all the DBUS_ERROR to DBUS_GERROR, should
+ * probably be automated in some way, perhaps
+ * via lame perl script
+ */
+ DBUS_GERROR_FAILED
+} DBusGError;
+
+void dbus_set_g_error (GError **gerror,
+ DBusError *derror);
+
+void dbus_g_thread_init (void);
void dbus_connection_setup_with_g_main (DBusConnection *connection,
GMainContext *context);
void dbus_server_setup_with_g_main (DBusServer *server,
GMainContext *context);
+typedef struct DBusGObjectInfo DBusGObjectInfo;
+typedef struct DBusGMethodInfo DBusGMethodInfo;
+
+/**
+ * Object typically generated by dbus-glib-tool that
+ * stores a mapping from introspection data to a
+ * function pointer for a C method to be invoked.
+ */
+struct DBusGMethodInfo
+{
+ GCallback function; /**< C method to invoke */
+ DBusHandleMessageFunction marshaller; /**< Marshaller to go DBusMessage to C method */
+ int data_offset; /**< Offset into the introspection data */
+};
+
+/**
+ * Introspection data for a GObject, normally autogenerated by
+ * a tool such as dbus-glib-tool.
+ */
+struct DBusGObjectInfo
+{
+ const DBusGMethodInfo *infos; /**< Array of method pointers */
+ const unsigned char *data; /**< Introspection data */
+ void *dbus_internal_padding1; /**< Reserved for expansion */
+ void *dbus_internal_padding2; /**< Reserved for expansion */
+};
+
+void dbus_g_object_class_install_info (GObjectClass *object_class,
+ const DBusGObjectInfo *info);
+void dbus_connection_register_g_object (DBusConnection *connection,
+ const char *at_path,
+ GObject *object);
+
+
+typedef struct DBusGProxy DBusGProxy;
+typedef struct DBusGProxyClass DBusGProxyClass;
+
+typedef void (* DBusGProxySignalHandler) (DBusGProxy *proxy,
+ DBusMessage *signal,
+ void *user_data);
+
+#define DBUS_TYPE_GPROXY (dbus_gproxy_get_type ())
+#define DBUS_GPROXY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), DBUS_TYPE_GPROXY, DBusGProxy))
+#define DBUS_GPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DBUS_TYPE_GPROXY, DBusGProxyClass))
+#define DBUS_IS_GPROXY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), DBUS_TYPE_GPROXY))
+#define DBUS_IS_GPROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), DBUS_TYPE_GPROXY))
+#define DBUS_GPROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DBUS_TYPE_GPROXY, DBusGProxyClass))
+
+
+GType dbus_gproxy_get_type (void) G_GNUC_CONST;
+DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection,
+ const char *service_name,
+ const char *path_name,
+ const char *interface_name);
+DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection,
+ const char *service_name,
+ const char *path_name,
+ const char *interface_name,
+ GError **error);
+DBusGProxy* dbus_gproxy_new_for_peer (DBusConnection *connection,
+ const char *path_name,
+ const char *interface_name);
+void dbus_gproxy_connect_signal (DBusGProxy *proxy,
+ const char *signal_name,
+ DBusGProxySignalHandler handler,
+ void *data,
+ GClosureNotify free_data_func);
+void dbus_gproxy_disconnect_signal (DBusGProxy *proxy,
+ const char *signal_name,
+ DBusGProxySignalHandler handler,
+ void *data);
+DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy,
+ const char *method,
+ int first_arg_type,
+ ...);
+gboolean dbus_gproxy_end_call (DBusGProxy *proxy,
+ DBusPendingCall *pending,
+ GError **error,
+ int first_arg_type,
+ ...);
+void dbus_gproxy_oneway_call (DBusGProxy *proxy,
+ const char *method,
+ int first_arg_type,
+ ...);
+void dbus_gproxy_send (DBusGProxy *proxy,
+ DBusMessage *message,
+ dbus_uint32_t *client_serial);
+
+
+#undef DBUS_INSIDE_DBUS_GLIB_H
+
G_END_DECLS
#endif /* DBUS_GLIB_H */
+
+
+
diff --git a/glib/dbus-gloader-expat.c b/glib/dbus-gloader-expat.c
new file mode 100644
index 00000000..01587d21
--- /dev/null
+++ b/glib/dbus-gloader-expat.c
@@ -0,0 +1,262 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gloader-expat.c expat XML loader
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "dbus-gparser.h"
+#include <expat.h>
+
+static void*
+expat_g_malloc (size_t sz)
+{
+ return g_malloc (sz);
+}
+
+static void*
+expat_g_realloc (void *mem, size_t sz)
+{
+ return g_realloc (mem, sz);
+}
+
+static XML_Memory_Handling_Suite memsuite =
+{
+ expat_g_malloc,
+ expat_g_realloc,
+ g_free
+};
+
+/**
+ * Context for Expat parser for introspection data.
+ */
+typedef struct
+{
+ Parser *parser; /**< The parser for the introspection data */
+ const char *filename; /**< The filename being loaded */
+ GString *content; /**< The content of the current element */
+ GError **error; /**< Error return location */
+ gboolean failed; /**< True if parse has failed */
+} ExpatParseContext;
+
+static dbus_bool_t
+process_content (ExpatParseContext *context)
+{
+ if (context->failed)
+ return FALSE;
+
+ if (context->content->len > 0)
+ {
+ if (!parser_content (context->parser,
+ context->content->str,
+ context->content->len,
+ context->error))
+ {
+ context->failed = TRUE;
+ return FALSE;
+ }
+ g_string_set_size (context->content, 0);
+ }
+
+ return TRUE;
+}
+
+static void
+expat_StartElementHandler (void *userData,
+ const XML_Char *name,
+ const XML_Char **atts)
+{
+ ExpatParseContext *context = userData;
+ int i;
+ char **names;
+ char **values;
+
+ /* Expat seems to suck and can't abort the parse if we
+ * throw an error. Expat 2.0 is supposed to fix this.
+ */
+ if (context->failed)
+ return;
+
+ if (!process_content (context))
+ return;
+
+ /* "atts" is key, value, key, value, NULL */
+ for (i = 0; atts[i] != NULL; ++i)
+ ; /* nothing */
+
+ g_assert (i % 2 == 0);
+ names = g_new0 (char *, i / 2 + 1);
+ values = g_new0 (char *, i / 2 + 1);
+
+ i = 0;
+ while (atts[i] != NULL)
+ {
+ g_assert (i % 2 == 0);
+ names [i / 2] = (char*) atts[i];
+ values[i / 2] = (char*) atts[i+1];
+
+ i += 2;
+ }
+
+ if (!parser_start_element (context->parser,
+ name,
+ (const char **) names,
+ (const char **) values,
+ context->error))
+ {
+ g_free (names);
+ g_free (values);
+ context->failed = TRUE;
+ return;
+ }
+
+ g_free (names);
+ g_free (values);
+}
+
+static void
+expat_EndElementHandler (void *userData,
+ const XML_Char *name)
+{
+ ExpatParseContext *context = userData;
+
+ if (!process_content (context))
+ return;
+
+ if (!parser_end_element (context->parser,
+ name,
+ context->error))
+ {
+ context->failed = TRUE;
+ return;
+ }
+}
+
+/* s is not 0 terminated. */
+static void
+expat_CharacterDataHandler (void *userData,
+ const XML_Char *s,
+ int len)
+{
+ ExpatParseContext *context = userData;
+
+ if (context->failed)
+ return;
+
+ g_string_append_len (context->content,
+ s, len);
+}
+
+NodeInfo*
+description_load_from_file (const char *filename,
+ GError **error)
+{
+ char *contents;
+ gsize len;
+ NodeInfo *nodes;
+
+ contents = NULL;
+ if (!g_file_get_contents (filename, &contents, &len, error))
+ return NULL;
+
+ nodes = description_load_from_string (contents, len, error);
+ g_free (contents);
+
+ return nodes;
+}
+
+NodeInfo*
+description_load_from_string (const char *str,
+ int len,
+ GError **error)
+{
+ XML_Parser expat;
+ ExpatParseContext context;
+ NodeInfo *nodes;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ expat = NULL;
+ context.parser = NULL;
+ context.error = error;
+ context.failed = FALSE;
+
+ expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL);
+ if (expat == NULL)
+ g_error ("No memory to create XML parser\n");
+
+ context.parser = parser_new ();
+ context.content = g_string_new (NULL);
+
+ XML_SetUserData (expat, &context);
+ XML_SetElementHandler (expat,
+ expat_StartElementHandler,
+ expat_EndElementHandler);
+ XML_SetCharacterDataHandler (expat,
+ expat_CharacterDataHandler);
+
+ if (!XML_Parse (expat, str, len, TRUE))
+ {
+ if (context.error != NULL &&
+ *context.error == NULL)
+ {
+ enum XML_Error e;
+
+ e = XML_GetErrorCode (expat);
+ if (e == XML_ERROR_NO_MEMORY)
+ g_error ("Not enough memory to parse XML document");
+ else
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ "Error in D-BUS description XML, line %d, column %d: %s\n",
+ XML_GetCurrentLineNumber (expat),
+ XML_GetCurrentColumnNumber (expat),
+ XML_ErrorString (e));
+ }
+
+ goto failed;
+ }
+
+ if (context.failed)
+ goto failed;
+
+ if (!parser_finished (context.parser, error))
+ goto failed;
+
+ XML_ParserFree (expat);
+ g_string_free (context.content, TRUE);
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ nodes = parser_get_nodes (context.parser);
+ node_info_ref (nodes);
+ parser_unref (context.parser);
+ return nodes;
+
+ failed:
+ g_return_val_if_fail (error == NULL || *error != NULL, NULL);
+
+ g_string_free (context.content, TRUE);
+ if (expat)
+ XML_ParserFree (expat);
+ if (context.parser)
+ parser_unref (context.parser);
+ return NULL;
+}
+
diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c
index d948b431..68ba22d7 100644
--- a/glib/dbus-gmain.c
+++ b/glib/dbus-gmain.c
@@ -21,8 +21,13 @@
*
*/
+#include <config.h>
#include "dbus-glib.h"
-#include <glib.h>
+#include "dbus-gtest.h"
+
+#include <libintl.h>
+#define _(x) dgettext (GETTEXT_PACKAGE, x)
+#define N_(x) x
/**
* @defgroup DBusGLib GLib bindings
@@ -48,6 +53,9 @@
*/
typedef struct DBusGSource DBusGSource;
+/**
+ * A GSource subclass for a DBusConnection.
+ */
struct DBusGSource
{
GSource source; /**< the parent GSource */
@@ -530,4 +538,94 @@ dbus_server_setup_with_g_main (DBusServer *server,
g_error ("Not enough memory to set up DBusServer for use with GLib");
}
+/**
+ * The implementation of DBUS_GERROR error domain. See documentation
+ * for GError in GLib reference manual.
+ *
+ * @returns the error domain quark for use with GError
+ */
+GQuark
+dbus_g_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (quark == 0)
+ quark = g_quark_from_static_string ("g-exec-error-quark");
+ return quark;
+}
+
+
+/**
+ * Set a GError return location from a DBusError.
+ *
+ * @todo expand the DBUS_GERROR enum and take advantage of it here
+ *
+ * @param gerror location to store a GError, or #NULL
+ * @param derror the DBusError
+ */
+void
+dbus_set_g_error (GError **gerror,
+ DBusError *derror)
+{
+ g_return_if_fail (derror != NULL);
+ g_return_if_fail (dbus_error_is_set (derror));
+
+ g_set_error (gerror, DBUS_GERROR,
+ DBUS_GERROR_FAILED,
+ _("D-BUS error %s: %s"),
+ derror->name, derror->message);
+}
+
+/**
+ * Get the GLib type ID for a DBusConnection boxed type.
+ *
+ * @returns GLib type
+ */
+GType
+dbus_connection_get_g_type (void)
+{
+ static GType our_type = 0;
+
+ if (our_type == 0)
+ our_type = g_boxed_type_register_static ("DBusConnection",
+ (GBoxedCopyFunc) dbus_connection_ref,
+ (GBoxedFreeFunc) dbus_connection_unref);
+
+ return our_type;
+}
+
+/**
+ * Get the GLib type ID for a DBusMessage boxed type.
+ *
+ * @returns GLib type
+ */
+GType
+dbus_message_get_g_type (void)
+{
+ static GType our_type = 0;
+
+ if (our_type == 0)
+ our_type = g_boxed_type_register_static ("DBusMessage",
+ (GBoxedCopyFunc) dbus_message_ref,
+ (GBoxedFreeFunc) dbus_message_unref);
+
+ return our_type;
+}
+
+
/** @} */ /* end of public API */
+
+#ifdef DBUS_BUILD_TESTS
+
+/**
+ * @ingroup DBusGLibInternals
+ * Unit test for GLib main loop integration
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_gmain_test (const char *test_data_dir)
+{
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c
new file mode 100644
index 00000000..6e65770f
--- /dev/null
+++ b/glib/dbus-gobject.c
@@ -0,0 +1,790 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gobject.c Exporting a GObject remotely
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include "dbus-glib.h"
+#include "dbus-gtest.h"
+#include "dbus-gutils.h"
+#include <string.h>
+
+/**
+ * @addtogroup DBusGLibInternals
+ * @{
+ */
+
+static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT;
+static GHashTable *info_hash = NULL;
+
+static char*
+wincaps_to_uscore (const char *caps)
+{
+ const char *p;
+ GString *str;
+
+ str = g_string_new (NULL);
+ p = caps;
+ while (*p)
+ {
+ if (g_ascii_isupper (*p))
+ {
+ if (str->len > 0 &&
+ (str->len < 2 || str->str[str->len-2] != '_'))
+ g_string_append_c (str, '_');
+ g_string_append_c (str, g_ascii_tolower (*p));
+ }
+ else
+ {
+ g_string_append_c (str, *p);
+ }
+ ++p;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static char*
+uscore_to_wincaps (const char *uscore)
+{
+ const char *p;
+ GString *str;
+ gboolean last_was_uscore;
+
+ last_was_uscore = TRUE;
+
+ str = g_string_new (NULL);
+ p = uscore;
+ while (*p)
+ {
+ if (*p == '-' || *p == '_')
+ {
+ last_was_uscore = TRUE;
+ }
+ else
+ {
+ if (last_was_uscore)
+ {
+ g_string_append_c (str, g_ascii_toupper (*p));
+ last_was_uscore = FALSE;
+ }
+ else
+ g_string_append_c (str, *p);
+ }
+ ++p;
+ }
+
+ return g_string_free (str, FALSE);
+}
+
+static void
+gobject_unregister_function (DBusConnection *connection,
+ void *user_data)
+{
+ GObject *object;
+
+ object = G_OBJECT (user_data);
+
+ /* FIXME */
+
+}
+
+static int
+gtype_to_dbus_type (GType type)
+{
+ switch (type)
+ {
+ case G_TYPE_CHAR:
+ case G_TYPE_UCHAR:
+ return DBUS_TYPE_BYTE;
+
+ case G_TYPE_BOOLEAN:
+ return DBUS_TYPE_BOOLEAN;
+
+ /* long gets cut to 32 bits so the remote API is consistent
+ * on all architectures
+ */
+
+ case G_TYPE_LONG:
+ case G_TYPE_INT:
+ return DBUS_TYPE_INT32;
+ case G_TYPE_ULONG:
+ case G_TYPE_UINT:
+ return DBUS_TYPE_UINT32;
+
+ case G_TYPE_INT64:
+ return DBUS_TYPE_INT64;
+
+ case G_TYPE_UINT64:
+ return DBUS_TYPE_UINT64;
+
+ case G_TYPE_FLOAT:
+ case G_TYPE_DOUBLE:
+ return DBUS_TYPE_DOUBLE;
+
+ case G_TYPE_STRING:
+ return DBUS_TYPE_STRING;
+
+ default:
+ return DBUS_TYPE_INVALID;
+ }
+}
+
+static const char *
+dbus_type_to_string (int type)
+{
+ switch (type)
+ {
+ case DBUS_TYPE_INVALID:
+ return "invalid";
+ case DBUS_TYPE_NIL:
+ return "nil";
+ case DBUS_TYPE_BOOLEAN:
+ return "boolean";
+ case DBUS_TYPE_INT32:
+ return "int32";
+ case DBUS_TYPE_UINT32:
+ return "uint32";
+ case DBUS_TYPE_DOUBLE:
+ return "double";
+ case DBUS_TYPE_STRING:
+ return "string";
+ case DBUS_TYPE_NAMED:
+ return "named";
+ case DBUS_TYPE_ARRAY:
+ return "array";
+ case DBUS_TYPE_DICT:
+ return "dict";
+ default:
+ return "unknown";
+ }
+}
+
+static DBusHandlerResult
+handle_introspect (DBusConnection *connection,
+ DBusMessage *message,
+ GObject *object)
+{
+ GString *xml;
+ GParamSpec **specs;
+ unsigned int n_specs;
+ unsigned int i;
+ GType last_type;
+ DBusMessage *ret;
+ char **path;
+ char **children;
+
+ if (!dbus_message_get_path_decomposed (message, &path))
+ g_error ("Out of memory");
+
+ if (!dbus_connection_list_registered (connection, (const char**) path,
+ &children))
+ g_error ("Out of memory");
+
+ xml = g_string_new (NULL);
+
+ g_string_append (xml, "<node>\n");
+
+ last_type = G_TYPE_INVALID;
+
+ specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
+ &n_specs);
+
+ i = 0;
+ while (i < n_specs)
+ {
+ GParamSpec *spec = specs[i];
+ gboolean can_set;
+ gboolean can_get;
+ char *s;
+ int dbus_type;
+
+ dbus_type = gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec));
+ if (dbus_type == DBUS_TYPE_INVALID)
+ goto next;
+
+ if (spec->owner_type != last_type)
+ {
+ if (last_type != G_TYPE_INVALID)
+ g_string_append (xml, " </interface>\n");
+
+
+ /* FIXME what should the namespace on the interface be in
+ * general? should people be able to set it for their
+ * objects?
+ */
+
+ g_string_append (xml, " <interface name=\"org.gtk.objects.");
+ g_string_append (xml, g_type_name (spec->owner_type));
+ g_string_append (xml, "\">\n");
+
+ last_type = spec->owner_type;
+ }
+
+ can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
+ (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
+
+ can_get = (spec->flags & G_PARAM_READABLE) != 0;
+
+ s = uscore_to_wincaps (spec->name);
+
+ if (can_set)
+ {
+ g_string_append (xml, " <method name=\"set_");
+ g_string_append (xml, s);
+ g_string_append (xml, "\">\n");
+
+ g_string_append (xml, " <arg type=\"");
+ g_string_append (xml, dbus_type_to_string (dbus_type));
+ g_string_append (xml, "\"/>\n");
+ }
+
+ if (can_get)
+ {
+ g_string_append (xml, " <method name=\"get_");
+ g_string_append (xml, s);
+ g_string_append (xml, "\">\n");
+
+ g_string_append (xml, " <arg type=\"");
+ g_string_append (xml, dbus_type_to_string (dbus_type));
+ g_string_append (xml, "\" direction=\"out\"/>\n");
+ }
+
+ g_free (s);
+
+ next:
+ ++i;
+ }
+
+ if (last_type != G_TYPE_INVALID)
+ g_string_append (xml, " </interface>\n");
+
+ g_free (specs);
+
+ /* Append child nodes */
+
+ i = 0;
+ while (children[i])
+ {
+ g_string_append_printf (xml, " <node name=\"%s\"/>\n",
+ children[i]);
+ ++i;
+ }
+
+ /* Close the XML, and send it to the requesting app */
+
+ g_string_append (xml, "</node>\n");
+
+ ret = dbus_message_new_method_return (message);
+ if (ret == NULL)
+ g_error ("Out of memory");
+
+ dbus_message_append_args (message,
+ DBUS_TYPE_STRING, xml->str,
+ DBUS_TYPE_INVALID);
+
+ dbus_connection_send (connection, message, NULL);
+ dbus_message_unref (message);
+
+ g_string_free (xml, TRUE);
+
+ dbus_free_string_array (path);
+ dbus_free_string_array (children);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusMessage*
+set_object_property (DBusConnection *connection,
+ DBusMessage *message,
+ GObject *object,
+ GParamSpec *pspec)
+{
+ GValue value;
+ DBusMessageIter iter;
+ int type;
+ gboolean can_set;
+ DBusMessage *ret;
+
+ dbus_message_iter_init (message, &iter);
+ type = dbus_message_get_type (message);
+
+ can_set = TRUE;
+ switch (type)
+ {
+ case DBUS_TYPE_BYTE:
+ {
+ unsigned char b;
+
+ b = dbus_message_iter_get_byte (&iter);
+
+ g_value_init (&value, G_TYPE_UCHAR);
+
+ g_value_set_uchar (&value, b);
+ }
+ break;
+ case DBUS_TYPE_BOOLEAN:
+ {
+ gboolean b;
+
+ b = dbus_message_iter_get_boolean (&iter);
+
+ g_value_init (&value, G_TYPE_BOOLEAN);
+
+ g_value_set_boolean (&value, b);
+ }
+ break;
+ case DBUS_TYPE_INT32:
+ {
+ gint32 i;
+
+ i = dbus_message_iter_get_int32 (&iter);
+
+ g_value_init (&value, G_TYPE_INT);
+
+ g_value_set_int (&value, i);
+ }
+ break;
+ case DBUS_TYPE_UINT32:
+ {
+ guint32 i;
+
+ i = dbus_message_iter_get_uint32 (&iter);
+
+ g_value_init (&value, G_TYPE_UINT);
+
+ g_value_set_uint (&value, i);
+ }
+ break;
+ case DBUS_TYPE_INT64:
+ {
+ gint64 i;
+
+ i = dbus_message_iter_get_int64 (&iter);
+
+ g_value_init (&value, G_TYPE_INT64);
+
+ g_value_set_int64 (&value, i);
+ }
+ break;
+ case DBUS_TYPE_UINT64:
+ {
+ guint64 i;
+
+ i = dbus_message_iter_get_uint64 (&iter);
+
+ g_value_init (&value, G_TYPE_UINT64);
+
+ g_value_set_uint64 (&value, i);
+ }
+ break;
+ case DBUS_TYPE_DOUBLE:
+ {
+ double d;
+
+ d = dbus_message_iter_get_double (&iter);
+
+ g_value_init (&value, G_TYPE_DOUBLE);
+
+ g_value_set_double (&value, d);
+ }
+ break;
+ case DBUS_TYPE_STRING:
+ {
+ char *s;
+
+ /* FIXME use a const string accessor */
+
+ s = dbus_message_iter_get_string (&iter);
+
+ g_value_init (&value, G_TYPE_STRING);
+
+ g_value_set_string (&value, s);
+
+ g_free (s);
+ }
+ break;
+
+ /* FIXME array and other types, especially byte array
+ * converted to G_TYPE_STRING
+ */
+
+ default:
+ can_set = FALSE;
+ break;
+ }
+
+ /* The g_object_set_property() will transform some types, e.g. it
+ * will let you use a uchar to set an int property etc. Note that
+ * any error in value range or value conversion will just
+ * g_warning(). These GObject skels are not for secure applications.
+ */
+
+ if (can_set)
+ {
+ g_object_set_property (object,
+ pspec->name,
+ &value);
+
+ ret = dbus_message_new_method_return (message);
+ if (ret == NULL)
+ g_error ("out of memory");
+
+ g_value_unset (&value);
+ }
+ else
+ {
+ ret = dbus_message_new_error (message,
+ DBUS_ERROR_INVALID_ARGS,
+ "Argument's D-BUS type can't be converted to a GType");
+ if (ret == NULL)
+ g_error ("out of memory");
+ }
+
+ return ret;
+}
+
+static DBusMessage*
+get_object_property (DBusConnection *connection,
+ DBusMessage *message,
+ GObject *object,
+ GParamSpec *pspec)
+{
+ GType value_type;
+ gboolean can_get;
+ DBusMessage *ret;
+ GValue value;
+ DBusMessageIter iter;
+
+ value_type = G_PARAM_SPEC_VALUE_TYPE (pspec);
+
+ ret = dbus_message_new_method_return (message);
+ if (ret == NULL)
+ g_error ("out of memory");
+
+ can_get = TRUE;
+ g_value_init (&value, value_type);
+ g_object_get_property (object, pspec->name, &value);
+
+ value_type = G_VALUE_TYPE (&value);
+
+ dbus_message_append_iter_init (message, &iter);
+
+ switch (value_type)
+ {
+ case G_TYPE_CHAR:
+ dbus_message_iter_append_byte (&iter,
+ g_value_get_char (&value));
+ break;
+ case G_TYPE_UCHAR:
+ dbus_message_iter_append_byte (&iter,
+ g_value_get_uchar (&value));
+ break;
+ case G_TYPE_BOOLEAN:
+ dbus_message_iter_append_boolean (&iter,
+ g_value_get_boolean (&value));
+ break;
+ case G_TYPE_INT:
+ dbus_message_iter_append_int32 (&iter,
+ g_value_get_int (&value));
+ break;
+ case G_TYPE_UINT:
+ dbus_message_iter_append_uint32 (&iter,
+ g_value_get_uint (&value));
+ break;
+ /* long gets cut to 32 bits so the remote API is consistent
+ * on all architectures
+ */
+ case G_TYPE_LONG:
+ dbus_message_iter_append_int32 (&iter,
+ g_value_get_long (&value));
+ break;
+ case G_TYPE_ULONG:
+ dbus_message_iter_append_uint32 (&iter,
+ g_value_get_ulong (&value));
+ break;
+ case G_TYPE_INT64:
+ dbus_message_iter_append_int64 (&iter,
+ g_value_get_int64 (&value));
+ break;
+ case G_TYPE_UINT64:
+ dbus_message_iter_append_uint64 (&iter,
+ g_value_get_uint64 (&value));
+ break;
+ case G_TYPE_FLOAT:
+ dbus_message_iter_append_double (&iter,
+ g_value_get_float (&value));
+ break;
+ case G_TYPE_DOUBLE:
+ dbus_message_iter_append_double (&iter,
+ g_value_get_double (&value));
+ break;
+ case G_TYPE_STRING:
+ /* FIXME, the GValue string may not be valid UTF-8 */
+ dbus_message_iter_append_string (&iter,
+ g_value_get_string (&value));
+ break;
+ default:
+ can_get = FALSE;
+ break;
+ }
+
+ g_value_unset (&value);
+
+ if (!can_get)
+ {
+ dbus_message_unref (ret);
+ ret = dbus_message_new_error (message,
+ DBUS_ERROR_UNKNOWN_METHOD,
+ "Can't convert GType of object property to a D-BUS type");
+ }
+
+ return ret;
+}
+
+static DBusHandlerResult
+gobject_message_function (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ const DBusGObjectInfo *info;
+ GParamSpec *pspec;
+ GObject *object;
+ const char *member;
+ gboolean setter;
+ gboolean getter;
+ char *s;
+
+ object = G_OBJECT (user_data);
+
+ if (dbus_message_is_method_call (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE,
+ "Introspect"))
+ return handle_introspect (connection, message, object);
+
+ member = dbus_message_get_member (message);
+
+ /* Try the metainfo, which lets us invoke methods */
+
+ g_static_mutex_lock (&info_hash_mutex);
+ /* FIXME this needs to walk up the inheritance tree, not
+ * just look at the most-derived class
+ */
+ info = g_hash_table_lookup (info_hash,
+ G_OBJECT_GET_CLASS (object));
+ g_static_mutex_unlock (&info_hash_mutex);
+
+ if (info != NULL)
+ {
+
+
+
+ }
+
+ /* If no metainfo, we can still do properties and signals
+ * via standard GLib introspection
+ */
+ setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
+ getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't' && member[3] == '_');
+
+ if (!(setter || getter))
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ s = wincaps_to_uscore (&member[4]);
+
+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
+ s);
+
+ g_free (s);
+
+ if (pspec != NULL)
+ {
+ DBusMessage *ret;
+
+ if (setter)
+ {
+ ret = set_object_property (connection, message,
+ object, pspec);
+ }
+ else if (getter)
+ {
+ ret = get_object_property (connection, message,
+ object, pspec);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ ret = NULL;
+ }
+
+ g_assert (ret != NULL);
+
+ dbus_connection_send (connection, ret, NULL);
+ dbus_message_unref (ret);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable gobject_dbus_vtable = {
+ gobject_unregister_function,
+ gobject_message_function,
+ NULL
+};
+
+/** @} */ /* end of internals */
+
+/**
+ * @addtogroup DBusGLib
+ * @{
+ */
+
+/**
+ * Install introspection information about the given object class
+ * sufficient to allow methods on the object to be invoked by name.
+ * The introspection information is normally generated by
+ * dbus-glib-tool, then this function is called in the
+ * class_init() for the object class.
+ *
+ * Once introspection information has been installed, instances of the
+ * object registered with dbus_connection_register_g_object() can have
+ * their methods invoked remotely.
+ *
+ * @param object_class class struct of the object
+ * @param info introspection data generated by dbus-glib-tool
+ */
+void
+dbus_g_object_class_install_info (GObjectClass *object_class,
+ const DBusGObjectInfo *info)
+{
+ g_return_if_fail (G_IS_OBJECT_CLASS (object_class));
+
+ g_static_mutex_lock (&info_hash_mutex);
+
+ if (info_hash == NULL)
+ {
+ info_hash = g_hash_table_new (NULL, NULL); /* direct hash */
+ }
+
+ g_hash_table_replace (info_hash, object_class, (void*) info);
+
+ g_static_mutex_unlock (&info_hash_mutex);
+}
+
+/**
+ * Registers a GObject at the given path. Properties, methods, and signals
+ * of the object can then be accessed remotely. Methods are only available
+ * if method introspection data has been added to the object's class
+ * with g_object_class_install_info().
+ *
+ * The registration will be cancelled if either the DBusConnection or
+ * the GObject gets finalized.
+ *
+ * @param connection the D-BUS connection
+ * @param at_path the path where the object will live (the object's name)
+ * @param object the object
+ */
+void
+dbus_connection_register_g_object (DBusConnection *connection,
+ const char *at_path,
+ GObject *object)
+{
+ char **split;
+
+ g_return_if_fail (connection != NULL);
+ g_return_if_fail (at_path != NULL);
+ g_return_if_fail (G_IS_OBJECT (object));
+
+ split = _dbus_gutils_split_path (at_path);
+
+ if (!dbus_connection_register_object_path (connection,
+ (const char**) split,
+ &gobject_dbus_vtable,
+ object))
+ g_error ("Failed to register GObject with DBusConnection");
+
+ g_strfreev (split);
+
+ /* FIXME set up memory management (so we break the
+ * registration if object or connection vanishes)
+ */
+}
+
+/** @} */ /* end of public API */
+
+#ifdef DBUS_BUILD_TESTS
+#include <stdlib.h>
+
+/**
+ * @ingroup DBusGLibInternals
+ * Unit test for GLib GObject integration ("skeletons")
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_gobject_test (const char *test_data_dir)
+{
+ int i;
+ static struct { const char *wincaps; const char *uscore; } name_pairs[] = {
+ { "SetFoo", "set_foo" },
+ { "Foo", "foo" },
+ { "GetFooBar", "get_foo_bar" },
+ { "Hello", "hello" }
+
+ /* Impossible-to-handle cases */
+ /* { "FrobateUIHandler", "frobate_ui_handler" } */
+ };
+
+ i = 0;
+ while (i < (int) G_N_ELEMENTS (name_pairs))
+ {
+ char *uscore;
+ char *wincaps;
+
+ uscore = wincaps_to_uscore (name_pairs[i].wincaps);
+ wincaps = uscore_to_wincaps (name_pairs[i].uscore);
+
+ if (strcmp (uscore, name_pairs[i].uscore) != 0)
+ {
+ g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
+ name_pairs[i].wincaps, name_pairs[i].uscore,
+ uscore);
+ exit (1);
+ }
+
+ if (strcmp (wincaps, name_pairs[i].wincaps) != 0)
+ {
+ g_printerr ("\"%s\" should have been converted to \"%s\" not \"%s\"\n",
+ name_pairs[i].uscore, name_pairs[i].wincaps,
+ wincaps);
+ exit (1);
+ }
+
+ g_free (uscore);
+ g_free (wincaps);
+
+ ++i;
+ }
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c
new file mode 100644
index 00000000..16d17f3d
--- /dev/null
+++ b/glib/dbus-gparser.c
@@ -0,0 +1,670 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gparser.c parse DBus description files
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "dbus-gparser.h"
+#include "dbus-gidl.h"
+#include <string.h>
+
+#include <libintl.h>
+#define _(x) gettext ((x))
+#define N_(x) x
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
+
+typedef struct
+{
+ const char *name;
+ const char **retloc;
+} LocateAttr;
+
+static gboolean
+locate_attributes (const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error,
+ const char *first_attribute_name,
+ const char **first_attribute_retloc,
+ ...)
+{
+ va_list args;
+ const char *name;
+ const char **retloc;
+ int n_attrs;
+#define MAX_ATTRS 24
+ LocateAttr attrs[MAX_ATTRS];
+ gboolean retval;
+ int i;
+
+ g_return_val_if_fail (first_attribute_name != NULL, FALSE);
+ g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
+
+ retval = TRUE;
+
+ n_attrs = 1;
+ attrs[0].name = first_attribute_name;
+ attrs[0].retloc = first_attribute_retloc;
+ *first_attribute_retloc = NULL;
+
+ va_start (args, first_attribute_retloc);
+
+ name = va_arg (args, const char*);
+ retloc = va_arg (args, const char**);
+
+ while (name != NULL)
+ {
+ g_return_val_if_fail (retloc != NULL, FALSE);
+
+ g_assert (n_attrs < MAX_ATTRS);
+
+ attrs[n_attrs].name = name;
+ attrs[n_attrs].retloc = retloc;
+ n_attrs += 1;
+ *retloc = NULL;
+
+ name = va_arg (args, const char*);
+ retloc = va_arg (args, const char**);
+ }
+
+ va_end (args);
+
+ if (!retval)
+ return retval;
+
+ i = 0;
+ while (attribute_names[i])
+ {
+ int j;
+ gboolean found;
+
+ found = FALSE;
+ j = 0;
+ while (j < n_attrs)
+ {
+ if (strcmp (attrs[j].name, attribute_names[i]) == 0)
+ {
+ retloc = attrs[j].retloc;
+
+ if (*retloc != NULL)
+ {
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Attribute \"%s\" repeated twice on the same <%s> element"),
+ attrs[j].name, element_name);
+ retval = FALSE;
+ goto out;
+ }
+
+ *retloc = attribute_values[i];
+ found = TRUE;
+ }
+
+ ++j;
+ }
+
+ if (!found)
+ {
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Attribute \"%s\" is invalid on <%s> element in this context"),
+ attribute_names[i], element_name);
+ retval = FALSE;
+ goto out;
+ }
+
+ ++i;
+ }
+
+ out:
+ return retval;
+}
+
+static gboolean
+check_no_attributes (const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ if (attribute_names[0] != NULL)
+ {
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Attribute \"%s\" is invalid on <%s> element in this context"),
+ attribute_names[0], element_name);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+struct Parser
+{
+ int refcount;
+
+ NodeInfo *result; /* Filled in when we pop the last node */
+ GSList *node_stack;
+ InterfaceInfo *interface;
+ MethodInfo *method;
+ SignalInfo *signal;
+ ArgInfo *arg;
+};
+
+Parser*
+parser_new (void)
+{
+ Parser *parser;
+
+ parser = g_new0 (Parser, 1);
+
+ parser->refcount = 1;
+
+ return parser;
+}
+
+void
+parser_ref (Parser *parser)
+{
+ parser->refcount += 1;
+}
+
+void
+parser_unref (Parser *parser)
+{
+ parser->refcount -= 1;
+ if (parser->refcount == 0)
+ {
+ if (parser->result)
+ node_info_unref (parser->result);
+
+ g_free (parser);
+ }
+}
+
+gboolean
+parser_check_doctype (Parser *parser,
+ const char *doctype,
+ GError **error)
+{
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ if (strcmp (doctype, "dbus_description") != 0)
+ {
+ g_set_error (error,
+ G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ "D-BUS description file has the wrong document type %s, use dbus_description",
+ doctype);
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+static gboolean
+parse_node (Parser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ const char *name;
+ NodeInfo *node;
+
+ if (parser->interface ||
+ parser->method ||
+ parser->signal ||
+ parser->arg)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Can't put a <%s> element here"),
+ element_name);
+ return FALSE;
+ }
+
+ name = NULL;
+ if (!locate_attributes (element_name, attribute_names,
+ attribute_values, error,
+ "name", &name,
+ NULL))
+ return FALSE;
+
+ /* Only the root node can have no name */
+ if (parser->node_stack != NULL && name == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute required on <%s> element "),
+ "name", element_name);
+ return FALSE;
+ }
+
+
+ node = node_info_new (name);
+
+ if (parser->node_stack != NULL)
+ {
+ node_info_add_node (parser->node_stack->data,
+ node);
+ }
+
+ parser->node_stack = g_slist_prepend (parser->node_stack,
+ node);
+
+ return TRUE;
+}
+
+static gboolean
+parse_interface (Parser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ const char *name;
+ InterfaceInfo *iface;
+ NodeInfo *top;
+
+ if (parser->interface ||
+ parser->method ||
+ parser->signal ||
+ parser->arg ||
+ (parser->node_stack == NULL))
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Can't put a <%s> element here"),
+ element_name);
+ return FALSE;
+ }
+
+ name = NULL;
+ if (!locate_attributes (element_name, attribute_names,
+ attribute_values, error,
+ "name", &name,
+ NULL))
+ return FALSE;
+
+ if (name == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute required on <%s> element "),
+ "name", element_name);
+ return FALSE;
+ }
+
+ top = parser->node_stack->data;
+
+ iface = interface_info_new (name);
+ node_info_add_interface (top, iface);
+ interface_info_unref (iface);
+
+ parser->interface = iface;
+
+ return TRUE;
+}
+
+static gboolean
+parse_method (Parser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ const char *name;
+ MethodInfo *method;
+ NodeInfo *top;
+
+ if (parser->interface == NULL ||
+ parser->node_stack == NULL ||
+ parser->method ||
+ parser->signal ||
+ parser->arg)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Can't put a <%s> element here"),
+ element_name);
+ return FALSE;
+ }
+
+ name = NULL;
+ if (!locate_attributes (element_name, attribute_names,
+ attribute_values, error,
+ "name", &name,
+ NULL))
+ return FALSE;
+
+ if (name == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute required on <%s> element "),
+ "name", element_name);
+ return FALSE;
+ }
+
+ top = parser->node_stack->data;
+
+ method = method_info_new (name);
+ interface_info_add_method (parser->interface, method);
+ method_info_unref (method);
+
+ parser->method = method;
+
+ return TRUE;
+}
+
+static gboolean
+parse_signal (Parser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ const char *name;
+ SignalInfo *signal;
+ NodeInfo *top;
+
+ if (parser->interface == NULL ||
+ parser->node_stack == NULL ||
+ parser->signal ||
+ parser->signal ||
+ parser->arg)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Can't put a <%s> element here"),
+ element_name);
+ return FALSE;
+ }
+
+ name = NULL;
+ if (!locate_attributes (element_name, attribute_names,
+ attribute_values, error,
+ "name", &name,
+ NULL))
+ return FALSE;
+
+ if (name == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute required on <%s> element "),
+ "name", element_name);
+ return FALSE;
+ }
+
+ top = parser->node_stack->data;
+
+ signal = signal_info_new (name);
+ interface_info_add_signal (parser->interface, signal);
+ signal_info_unref (signal);
+
+ parser->signal = signal;
+
+ return TRUE;
+}
+
+static int
+basic_type_from_string (const char *str)
+{
+ if (strcmp (str, "string") == 0)
+ return DBUS_TYPE_STRING;
+ else if (strcmp (str, "int32") == 0)
+ return DBUS_TYPE_INT32;
+ else if (strcmp (str, "uint32") == 0)
+ return DBUS_TYPE_UINT32;
+ else if (strcmp (str, "int64") == 0)
+ return DBUS_TYPE_INT64;
+ else if (strcmp (str, "uint64") == 0)
+ return DBUS_TYPE_UINT64;
+ else if (strcmp (str, "double") == 0)
+ return DBUS_TYPE_DOUBLE;
+ else if (strcmp (str, "byte") == 0)
+ return DBUS_TYPE_BYTE;
+ else if (strcmp (str, "boolean") == 0)
+ return DBUS_TYPE_BOOLEAN;
+ else if (strcmp (str, "byte") == 0)
+ return DBUS_TYPE_BYTE;
+ else if (strcmp (str, "object") == 0)
+ return DBUS_TYPE_OBJECT_PATH;
+ else
+ return DBUS_TYPE_INVALID;
+}
+
+static int
+type_from_string (const char *str)
+{
+ return basic_type_from_string (str);
+}
+
+static gboolean
+parse_arg (Parser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ const char *name;
+ const char *type;
+ const char *direction;
+ ArgDirection dir;
+ int t;
+ ArgInfo *arg;
+
+ if (!(parser->method || parser->signal) ||
+ parser->node_stack == NULL ||
+ parser->arg)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Can't put a <%s> element here"),
+ element_name);
+ return FALSE;
+ }
+
+ name = NULL;
+ if (!locate_attributes (element_name, attribute_names,
+ attribute_values, error,
+ "name", &name,
+ "type", &type,
+ "direction", &direction,
+ NULL))
+ return FALSE;
+
+ /* name can be null for args */
+
+ if (type == NULL)
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute required on <%s> element "),
+ "type", element_name);
+ return FALSE;
+ }
+
+ if (direction == NULL)
+ {
+ /* methods default to in, signal to out */
+ if (parser->method)
+ direction = "in";
+ else if (parser->signal)
+ direction = "out";
+ else
+ g_assert_not_reached ();
+ }
+
+ if (strcmp (direction, "in") == 0)
+ dir = ARG_IN;
+ else if (strcmp (direction, "out") == 0)
+ dir = ARG_OUT;
+ else
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
+ "direction", element_name);
+ return FALSE;
+ }
+
+ t = type_from_string (type);
+
+ arg = arg_info_new (name, dir, t);
+ if (parser->method)
+ method_info_add_arg (parser->method, arg);
+ else if (parser->signal)
+ signal_info_add_arg (parser->signal, arg);
+ else
+ g_assert_not_reached ();
+
+ arg_info_unref (arg);
+
+ parser->arg = arg;
+
+ return TRUE;
+}
+
+gboolean
+parser_start_element (Parser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error)
+{
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ if (ELEMENT_IS ("node"))
+ {
+ if (!parse_node (parser, element_name, attribute_names,
+ attribute_values, error))
+ return FALSE;
+ }
+ else if (ELEMENT_IS ("interface"))
+ {
+ if (!parse_interface (parser, element_name, attribute_names,
+ attribute_values, error))
+ return FALSE;
+ }
+ else if (ELEMENT_IS ("method"))
+ {
+ if (!parse_method (parser, element_name, attribute_names,
+ attribute_values, error))
+ return FALSE;
+ }
+ else if (ELEMENT_IS ("signal"))
+ {
+ if (!parse_signal (parser, element_name, attribute_names,
+ attribute_values, error))
+ return FALSE;
+ }
+ else if (ELEMENT_IS ("arg"))
+ {
+ if (!parse_arg (parser, element_name, attribute_names,
+ attribute_values, error))
+ return FALSE;
+ }
+ else
+ {
+ g_set_error (error, G_MARKUP_ERROR,
+ G_MARKUP_ERROR_PARSE,
+ _("Element <%s> not recognized"),
+ element_name);
+ }
+
+ return TRUE;
+}
+
+gboolean
+parser_end_element (Parser *parser,
+ const char *element_name,
+ GError **error)
+{
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ if (ELEMENT_IS ("interface"))
+ {
+ parser->interface = NULL;
+ }
+ else if (ELEMENT_IS ("method"))
+ {
+ parser->method = NULL;
+ }
+ else if (ELEMENT_IS ("signal"))
+ {
+ parser->signal = NULL;
+ }
+ else if (ELEMENT_IS ("arg"))
+ {
+ parser->arg = NULL;
+ }
+ else if (ELEMENT_IS ("node"))
+ {
+ NodeInfo *top;
+
+ g_assert (parser->node_stack != NULL);
+ top = parser->node_stack->data;
+
+ parser->node_stack = g_slist_remove (parser->node_stack,
+ top);
+
+ if (parser->node_stack == NULL)
+ parser->result = top; /* We are done, store the result */
+ }
+ else
+ g_assert_not_reached (); /* should have had an error on start_element */
+
+ return TRUE;
+}
+
+gboolean
+parser_content (Parser *parser,
+ const char *content,
+ int len,
+ GError **error)
+{
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ return TRUE;
+}
+
+gboolean
+parser_finished (Parser *parser,
+ GError **error)
+{
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ return TRUE;
+}
+
+NodeInfo*
+parser_get_nodes (Parser *parser)
+{
+ return parser->result;
+}
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/glib/dbus-gparser.h b/glib/dbus-gparser.h
new file mode 100644
index 00000000..cc58e5e0
--- /dev/null
+++ b/glib/dbus-gparser.h
@@ -0,0 +1,65 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gparser.h parse DBus description files
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef DBUS_GLIB_PARSER_H
+#define DBUS_GLIB_PARSER_H
+
+#include <dbus/dbus.h>
+#include <glib.h>
+#include "dbus-gidl.h"
+
+G_BEGIN_DECLS
+
+typedef struct Parser Parser;
+
+Parser* parser_new (void);
+void parser_ref (Parser *parser);
+void parser_unref (Parser *parser);
+gboolean parser_check_doctype (Parser *parser,
+ const char *doctype,
+ GError **error);
+gboolean parser_start_element (Parser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+ GError **error);
+gboolean parser_end_element (Parser *parser,
+ const char *element_name,
+ GError **error);
+gboolean parser_content (Parser *parser,
+ const char *content,
+ int len,
+ GError **error);
+gboolean parser_finished (Parser *parser,
+ GError **error);
+
+NodeInfo* description_load_from_file (const char *filename,
+ GError **error);
+NodeInfo* description_load_from_string (const char *str,
+ int len,
+ GError **error);
+
+NodeInfo* parser_get_nodes (Parser *parser);
+
+G_END_DECLS
+
+#endif /* DBUS_GLIB_GPARSER_H */
diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c
new file mode 100644
index 00000000..99900e4c
--- /dev/null
+++ b/glib/dbus-gproxy.c
@@ -0,0 +1,1249 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gcall.c convenience routines for calling methods, etc.
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include "dbus-glib.h"
+#include <string.h>
+
+/**
+ * @addtogroup DBusGLibInternals
+ *
+ * @{
+ */
+
+typedef struct DBusGProxyManager DBusGProxyManager;
+
+/**
+ * Internals of DBusGProxy
+ */
+struct DBusGProxy
+{
+ GObject parent; /**< Parent instance */
+
+ DBusGProxyManager *manager; /**< Proxy manager */
+ char *service; /**< Service messages go to or NULL */
+ char *path; /**< Path messages go to or NULL */
+ char *interface; /**< Interface messages go to or NULL */
+};
+
+/**
+ * Class struct for DBusGProxy
+ */
+struct DBusGProxyClass
+{
+ GObjectClass parent_class;
+};
+
+static void dbus_gproxy_init (DBusGProxy *proxy);
+static void dbus_gproxy_class_init (DBusGProxyClass *klass);
+static void dbus_gproxy_finalize (GObject *object);
+static void dbus_gproxy_dispose (GObject *object);
+static void dbus_gproxy_destroy (DBusGProxy *proxy);
+static void dbus_gproxy_emit_received (DBusGProxy *proxy,
+ DBusMessage *message);
+
+
+/**
+ * A list of proxies with a given service+path+interface, used to route incoming
+ * signals.
+ */
+typedef struct
+{
+ GSList *proxies;
+
+ char name[4]; /**< service (empty string for none), nul byte,
+ * path, nul byte,
+ * interface, nul byte
+ */
+
+} DBusGProxyList;
+
+/**
+ * DBusGProxyManager's primary task is to route signals to the proxies
+ * those signals are emitted on. In order to do this it also has to
+ * track the owners of the services proxies are bound to.
+ */
+struct DBusGProxyManager
+{
+ GStaticMutex lock; /**< Thread lock */
+ int refcount; /**< Reference count */
+ DBusConnection *connection; /**< Connection we're associated with. */
+
+ GHashTable *proxy_lists; /**< Hash used to route incoming signals
+ * and iterate over proxies
+ */
+
+};
+
+static void dbus_gproxy_manager_ref (DBusGProxyManager *manager);
+static DBusHandlerResult dbus_gproxy_manager_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data);
+
+/** Lock the DBusGProxyManager */
+#define LOCK_MANAGER(mgr) (g_static_mutex_lock (&(mgr)->lock))
+/** Unlock the DBusGProxyManager */
+#define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
+
+static int gproxy_manager_slot = -1;
+
+/* Lock controlling get/set manager as data on each connection */
+static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT;
+
+static DBusGProxyManager*
+dbus_gproxy_manager_get (DBusConnection *connection)
+{
+ DBusGProxyManager *manager;
+
+ dbus_connection_allocate_data_slot (&gproxy_manager_slot);
+ if (gproxy_manager_slot < 0)
+ g_error ("out of memory");
+
+ g_static_mutex_lock (&connection_gproxy_lock);
+
+ manager = dbus_connection_get_data (connection, gproxy_manager_slot);
+ if (manager != NULL)
+ {
+ dbus_connection_free_data_slot (&gproxy_manager_slot);
+ dbus_gproxy_manager_ref (manager);
+ g_static_mutex_unlock (&connection_gproxy_lock);
+ return manager;
+ }
+
+ manager = g_new0 (DBusGProxyManager, 1);
+
+ manager->refcount = 1;
+ manager->connection = connection;
+
+ g_static_mutex_init (&manager->lock);
+
+ /* Proxy managers keep the connection alive, which means that
+ * DBusGProxy indirectly does. To free a connection you have to free
+ * all the proxies referring to it.
+ */
+ dbus_connection_ref (manager->connection);
+
+ dbus_connection_set_data (connection, gproxy_manager_slot,
+ manager, NULL);
+
+ dbus_connection_add_filter (connection, dbus_gproxy_manager_filter,
+ manager, NULL);
+
+ g_static_mutex_unlock (&connection_gproxy_lock);
+
+ return manager;
+}
+
+static void
+dbus_gproxy_manager_ref (DBusGProxyManager *manager)
+{
+ g_assert (manager != NULL);
+ g_assert (manager->refcount > 0);
+
+ LOCK_MANAGER (manager);
+
+ manager->refcount += 1;
+
+ UNLOCK_MANAGER (manager);
+}
+
+static void
+dbus_gproxy_manager_unref (DBusGProxyManager *manager)
+{
+ g_assert (manager != NULL);
+ g_assert (manager->refcount > 0);
+
+ LOCK_MANAGER (manager);
+ manager->refcount -= 1;
+ if (manager->refcount == 0)
+ {
+ UNLOCK_MANAGER (manager);
+
+ if (manager->proxy_lists)
+ {
+ /* can't have any proxies left since they hold
+ * a reference to the proxy manager.
+ */
+ g_assert (g_hash_table_size (manager->proxy_lists) == 0);
+
+ g_hash_table_destroy (manager->proxy_lists);
+ manager->proxy_lists = NULL;
+ }
+
+ g_static_mutex_free (&manager->lock);
+
+ g_static_mutex_lock (&connection_gproxy_lock);
+
+ dbus_connection_remove_filter (manager->connection, dbus_gproxy_manager_filter,
+ manager);
+
+ dbus_connection_set_data (manager->connection,
+ gproxy_manager_slot,
+ NULL, NULL);
+
+ g_static_mutex_unlock (&connection_gproxy_lock);
+
+ dbus_connection_unref (manager->connection);
+ g_free (manager);
+
+ dbus_connection_free_data_slot (&gproxy_manager_slot);
+ }
+ else
+ {
+ UNLOCK_MANAGER (manager);
+ }
+}
+
+static guint
+tristring_hash (gconstpointer key)
+{
+ const char *p = key;
+ guint h = *p;
+
+ if (h)
+ {
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + *p;
+ }
+
+ /* skip nul and do the next substring */
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + *p;
+
+ /* skip nul again and another substring */
+ for (p += 1; *p != '\0'; p++)
+ h = (h << 5) - h + *p;
+
+ return h;
+}
+
+static gboolean
+strequal_len (const char *a,
+ const char *b,
+ size_t *lenp)
+{
+ size_t a_len;
+ size_t b_len;
+
+ a_len = strlen (a);
+ b_len = strlen (b);
+
+ if (a_len != b_len)
+ return FALSE;
+
+ if (memcmp (a, b, a_len) != 0)
+ return FALSE;
+
+ *lenp = a_len;
+
+ return TRUE;
+}
+
+static gboolean
+tristring_equal (gconstpointer a,
+ gconstpointer b)
+{
+ const char *ap = a;
+ const char *bp = b;
+ size_t len;
+
+ if (!strequal_len (ap, bp, &len))
+ return FALSE;
+
+ ap += len + 1;
+ bp += len + 1;
+
+ if (!strequal_len (ap, bp, &len))
+ return FALSE;
+
+ ap += len + 1;
+ bp += len + 1;
+
+ if (strcmp (ap, bp) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static char*
+tristring_alloc_from_strings (size_t padding_before,
+ const char *service,
+ const char *path,
+ const char *interface)
+{
+ size_t service_len, iface_len, path_len, len;
+ char *tri;
+
+ if (service)
+ service_len = strlen (service);
+ else
+ service_len = 0;
+
+ path_len = strlen (path);
+
+ iface_len = strlen (interface);
+
+ tri = g_malloc (padding_before + service_len + path_len + iface_len + 3);
+
+ len = padding_before;
+
+ if (service)
+ memcpy (&tri[len], service, service_len);
+
+ len += service_len;
+ tri[len] = '\0';
+ len += 1;
+
+ g_assert (len == (padding_before + service_len + 1));
+
+ memcpy (&tri[len], path, path_len);
+ len += path_len;
+ tri[len] = '\0';
+ len += 1;
+
+ g_assert (len == (padding_before + service_len + path_len + 2));
+
+ memcpy (&tri[len], interface, iface_len);
+ len += iface_len;
+ tri[len] = '\0';
+ len += 1;
+
+ g_assert (len == (padding_before + service_len + path_len + iface_len + 3));
+
+ return tri;
+}
+
+static char*
+tristring_from_proxy (DBusGProxy *proxy)
+{
+ return tristring_alloc_from_strings (0,
+ proxy->service,
+ proxy->path,
+ proxy->interface);
+}
+
+static char*
+tristring_from_message (DBusMessage *message)
+{
+ return tristring_alloc_from_strings (0,
+ dbus_message_get_sender (message),
+ dbus_message_get_path (message),
+ dbus_message_get_interface (message));
+}
+
+static DBusGProxyList*
+gproxy_list_new (DBusGProxy *first_proxy)
+{
+ DBusGProxyList *list;
+
+ list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
+ first_proxy->service,
+ first_proxy->path,
+ first_proxy->interface);
+ list->proxies = NULL;
+
+ return list;
+}
+
+static void
+gproxy_list_free (DBusGProxyList *list)
+{
+ /* we don't hold a reference to the proxies in the list,
+ * as they ref the GProxyManager
+ */
+ g_slist_free (list->proxies);
+
+ g_free (list);
+}
+
+static char*
+gproxy_get_match_rule (DBusGProxy *proxy)
+{
+ /* FIXME Some sort of escaping is required here I think */
+
+ if (proxy->service)
+ return g_strdup_printf ("type='signal',service='%s',path='%s',interface='%s'",
+ proxy->service, proxy->path, proxy->interface);
+ else
+ return g_strdup_printf ("type='signal',path='%s',interface='%s'",
+ proxy->path, proxy->interface);
+}
+
+static void
+dbus_gproxy_manager_register (DBusGProxyManager *manager,
+ DBusGProxy *proxy)
+{
+ DBusGProxyList *list;
+
+ LOCK_MANAGER (manager);
+
+ if (manager->proxy_lists == NULL)
+ {
+ list = NULL;
+ manager->proxy_lists = g_hash_table_new_full (tristring_hash,
+ tristring_equal,
+ NULL,
+ (GFreeFunc) gproxy_list_free);
+ }
+ else
+ {
+ char *tri;
+
+ tri = tristring_from_proxy (proxy);
+
+ list = g_hash_table_lookup (manager->proxy_lists, tri);
+
+ g_free (tri);
+ }
+
+ if (list == NULL)
+ {
+ list = gproxy_list_new (proxy);
+
+ g_hash_table_replace (manager->proxy_lists,
+ list->name, list);
+ }
+
+ if (list->proxies == NULL)
+ {
+ /* We have to add the match rule to the server,
+ * but FIXME only if the server is a message bus,
+ * not if it's a peer.
+ */
+ char *rule;
+
+ rule = gproxy_get_match_rule (proxy);
+
+ /* We don't check for errors; it's not like anyone would handle them,
+ * and we don't want a round trip here.
+ */
+ dbus_bus_add_match (manager->connection,
+ rule, NULL);
+
+ g_free (rule);
+ }
+
+ g_assert (g_slist_find (list->proxies, proxy) == NULL);
+
+ list->proxies = g_slist_prepend (list->proxies, proxy);
+
+ UNLOCK_MANAGER (manager);
+}
+
+static void
+dbus_gproxy_manager_unregister (DBusGProxyManager *manager,
+ DBusGProxy *proxy)
+{
+ DBusGProxyList *list;
+ char *tri;
+
+ LOCK_MANAGER (manager);
+
+#ifndef G_DISABLE_CHECKS
+ if (manager->proxy_lists == NULL)
+ {
+ g_warning ("Trying to disconnect a signal on a proxy but none are connected\n");
+ return;
+ }
+#endif
+
+ tri = tristring_from_proxy (proxy);
+
+ list = g_hash_table_lookup (manager->proxy_lists, tri);
+
+ g_free (tri);
+
+#ifndef G_DISABLE_CHECKS
+ if (list == NULL)
+ {
+ g_warning ("Trying to disconnect a signal on a proxy but none are connected\n");
+ return;
+ }
+#endif
+
+ g_assert (g_slist_find (list->proxies, proxy) != NULL);
+
+ list->proxies = g_slist_remove (list->proxies, proxy);
+
+ g_assert (g_slist_find (list->proxies, proxy) == NULL);
+
+ if (g_hash_table_size (manager->proxy_lists) == 0)
+ {
+ g_hash_table_destroy (manager->proxy_lists);
+ manager->proxy_lists = NULL;
+ }
+
+ UNLOCK_MANAGER (manager);
+}
+
+static void
+list_proxies_foreach (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ DBusGProxyList *list;
+ GSList **ret;
+ GSList *tmp;
+
+ list = value;
+ ret = user_data;
+
+ tmp = list->proxies;
+ while (tmp != NULL)
+ {
+ DBusGProxy *proxy = DBUS_GPROXY (tmp->data);
+
+ g_object_ref (proxy);
+ *ret = g_slist_prepend (*ret, proxy);
+
+ tmp = tmp->next;
+ }
+}
+
+static GSList*
+dbus_gproxy_manager_list_all (DBusGProxyManager *manager)
+{
+ GSList *ret;
+
+ ret = NULL;
+
+ if (manager->proxy_lists)
+ {
+ g_hash_table_foreach (manager->proxy_lists,
+ list_proxies_foreach,
+ &ret);
+ }
+
+ return ret;
+}
+
+static DBusHandlerResult
+dbus_gproxy_manager_filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ DBusGProxyManager *manager;
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ manager = user_data;
+
+ dbus_gproxy_manager_ref (manager);
+
+ LOCK_MANAGER (manager);
+
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+ "Disconnected"))
+ {
+ /* Destroy all the proxies, quite possibly resulting in unreferencing
+ * the proxy manager and the connection as well.
+ */
+ GSList *all;
+ GSList *tmp;
+
+ all = dbus_gproxy_manager_list_all (manager);
+
+ tmp = all;
+ while (tmp != NULL)
+ {
+ DBusGProxy *proxy;
+
+ proxy = DBUS_GPROXY (tmp->data);
+
+ UNLOCK_MANAGER (manager);
+ dbus_gproxy_destroy (proxy);
+ g_object_unref (G_OBJECT (proxy));
+ LOCK_MANAGER (manager);
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (all);
+
+#ifndef G_DISABLE_CHECKS
+ if (manager->proxy_lists != NULL)
+ g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak.");
+#endif
+ }
+ else
+ {
+ char *tri;
+ DBusGProxyList *list;
+
+ tri = tristring_from_message (message);
+
+ if (manager->proxy_lists)
+ list = g_hash_table_lookup (manager->proxy_lists, tri);
+ else
+ list = NULL;
+
+ g_free (tri);
+
+ /* Emit the signal */
+
+ if (list != NULL)
+ {
+ GSList *tmp;
+ GSList *copy;
+
+ copy = g_slist_copy (list->proxies);
+ g_slist_foreach (copy, (GFunc) g_object_ref, NULL);
+
+ tmp = copy;
+ while (tmp != NULL)
+ {
+ DBusGProxy *proxy;
+
+ proxy = DBUS_GPROXY (tmp->data);
+
+ UNLOCK_MANAGER (manager);
+ dbus_gproxy_emit_received (proxy, message);
+ g_object_unref (G_OBJECT (proxy));
+ LOCK_MANAGER (manager);
+
+ tmp = tmp->next;
+ }
+
+ g_slist_free (copy);
+ }
+ }
+
+ UNLOCK_MANAGER (manager);
+ dbus_gproxy_manager_unref (manager);
+
+ /* "Handling" signals doesn't make sense, they are for everyone
+ * who cares
+ */
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+
+/* ---------- DBusGProxy -------------- */
+
+
+
+enum
+{
+ DESTROY,
+ RECEIVED,
+ LAST_SIGNAL
+};
+
+static void *parent_class;
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+dbus_gproxy_init (DBusGProxy *proxy)
+{
+ /* Nothing */
+}
+
+static void
+dbus_gproxy_class_init (DBusGProxyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = dbus_gproxy_finalize;
+ object_class->dispose = dbus_gproxy_dispose;
+
+ signals[DESTROY] =
+ g_signal_new ("destroy",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[RECEIVED] =
+ g_signal_new ("received",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOXED,
+ G_TYPE_NONE, 1,
+ DBUS_TYPE_MESSAGE);
+}
+
+
+static void
+dbus_gproxy_dispose (GObject *object)
+{
+ DBusGProxy *proxy;
+
+ proxy = DBUS_GPROXY (object);
+
+ g_signal_emit (object, signals[DESTROY], 0);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+dbus_gproxy_finalize (GObject *object)
+{
+ DBusGProxy *proxy;
+
+ proxy = DBUS_GPROXY (object);
+
+ if (proxy->manager)
+ {
+ dbus_gproxy_manager_unregister (proxy->manager, proxy);
+ dbus_gproxy_manager_unref (proxy->manager);
+ }
+
+ g_free (proxy->service);
+ g_free (proxy->path);
+ g_free (proxy->interface);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+dbus_gproxy_destroy (DBusGProxy *proxy)
+{
+ /* FIXME do we need the GTK_IN_DESTRUCTION style flag
+ * from GtkObject?
+ */
+ g_object_run_dispose (G_OBJECT (proxy));
+}
+
+static char*
+create_signal_detail (const char *interface,
+ const char *signal)
+{
+ GString *str;
+
+ str = g_string_new (interface);
+
+ g_string_append (str, ".");
+
+ g_string_append (str, signal);
+
+ return g_string_free (str, FALSE);
+}
+
+static void
+dbus_gproxy_emit_received (DBusGProxy *proxy,
+ DBusMessage *message)
+{
+ const char *interface;
+ const char *signal;
+ char *detail;
+ GQuark q;
+
+ interface = dbus_message_get_interface (message);
+ signal = dbus_message_get_member (message);
+
+ g_assert (interface != NULL);
+ g_assert (signal != NULL);
+
+ detail = create_signal_detail (interface, signal);
+
+ /* If the quark isn't preexisting, there's no way there
+ * are any handlers connected. We don't want to create
+ * extra quarks for every possible signal.
+ */
+ q = g_quark_try_string (detail);
+
+ if (q != 0)
+ g_signal_emit (G_OBJECT (proxy),
+ signals[RECEIVED],
+ q,
+ message);
+
+ g_free (detail);
+}
+
+/** @} End of DBusGLibInternals */
+
+/** @addtogroup DBusGLib
+ * @{
+ */
+
+/**
+ * Standard GObject get_type() function for DBusGProxy.
+ *
+ * @returns type ID for DBusGProxy class
+ */
+GType
+dbus_gproxy_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (!object_type)
+ {
+ static const GTypeInfo object_info =
+ {
+ sizeof (DBusGProxyClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) dbus_gproxy_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (DBusGProxy),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) dbus_gproxy_init,
+ };
+
+ object_type = g_type_register_static (G_TYPE_OBJECT,
+ "DBusGProxy",
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+static DBusGProxy*
+dbus_gproxy_new (DBusConnection *connection,
+ const char *service_name,
+ const char *path_name,
+ const char *interface_name)
+{
+ DBusGProxy *proxy;
+
+ g_assert (connection != NULL);
+
+ proxy = g_object_new (DBUS_TYPE_GPROXY, NULL);
+
+ /* These should all be construct-only mandatory properties,
+ * for now we just don't let people use g_object_new().
+ */
+
+ proxy->manager = dbus_gproxy_manager_get (connection);
+
+ proxy->service = g_strdup (service_name);
+ proxy->path = g_strdup (path_name);
+ proxy->interface = g_strdup (interface_name);
+
+ dbus_gproxy_manager_register (proxy->manager, proxy);
+
+ return proxy;
+}
+
+/**
+ * Creates a new proxy for a remote interface exported by a service on
+ * a message bus. Method calls and signal connections over this proxy
+ * will go to the service owner; the service owner is expected to
+ * support the given interface name. THE SERVICE OWNER MAY CHANGE OVER
+ * TIME, for example between two different method calls. If you need a
+ * fixed owner, you need to request the current owner and bind a proxy
+ * to that rather than to the generic service name; see
+ * dbus_gproxy_new_for_service_owner().
+ *
+ * A service-associated proxy only makes sense with a message bus,
+ * not for app-to-app direct dbus connections.
+ *
+ * This proxy will only emit the "destroy" signal if the #DBusConnection
+ * is disconnected or the proxy is has no remaining references.
+ *
+ * @param connection the connection to the remote bus
+ * @param service_name name of the service on the message bus
+ * @param path_name name of the object inside the service to call methods on
+ * @param interface_name name of the interface to call methods on
+ * @returns new proxy object
+ */
+DBusGProxy*
+dbus_gproxy_new_for_service (DBusConnection *connection,
+ const char *service_name,
+ const char *path_name,
+ const char *interface_name)
+{
+ DBusGProxy *proxy;
+
+ g_return_val_if_fail (connection != NULL, NULL);
+ g_return_val_if_fail (service_name != NULL, NULL);
+ g_return_val_if_fail (path_name != NULL, NULL);
+ g_return_val_if_fail (interface_name != NULL, NULL);
+
+ proxy = dbus_gproxy_new (connection, service_name,
+ path_name, interface_name);
+
+ return proxy;
+}
+
+/**
+ * Similar to dbus_gproxy_new_for_service(), but makes a round-trip
+ * request to the message bus to get the current service owner, then
+ * binds the proxy specifically to the current owner. As a result, the
+ * service owner will not change over time, and the proxy will emit
+ * the "destroy" signal when the owner disappears from the message
+ * bus.
+ *
+ * An example of the difference between dbus_gproxy_new_for_service()
+ * and dbus_gproxy_new_for_service_owner(): if you pass the service name
+ * "org.freedesktop.Database" dbus_gproxy_new_for_service() remains bound
+ * to that name as it changes owner. dbus_gproxy_new_for_service_owner()
+ * will fail if the service has no owner. If the service has an owner,
+ * dbus_gproxy_new_for_service_owner() will bind to the unique name
+ * of that owner rather than the generic service name.
+ *
+ * @param connection the connection to the remote bus
+ * @param service_name name of the service on the message bus
+ * @param path_name name of the object inside the service to call methods on
+ * @param interface_name name of the interface to call methods on
+ * @param error return location for an error
+ * @returns new proxy object, or #NULL on error
+ */
+DBusGProxy*
+dbus_gproxy_new_for_service_owner (DBusConnection *connection,
+ const char *service_name,
+ const char *path_name,
+ const char *interface_name,
+ GError **error)
+{
+ g_return_val_if_fail (connection != NULL, NULL);
+ g_return_val_if_fail (service_name != NULL, NULL);
+ g_return_val_if_fail (path_name != NULL, NULL);
+ g_return_val_if_fail (interface_name != NULL, NULL);
+
+
+}
+
+/**
+ * Creates a proxy for an object in peer application (one
+ * we're directly connected to). That is, this function is
+ * intended for use when there's no message bus involved,
+ * we're doing a simple 1-to-1 communication between two
+ * applications.
+ *
+ *
+ * @param connection the connection to the peer
+ * @param path_name name of the object inside the peer to call methods on
+ * @param interface_name name of the interface to call methods on
+ * @returns new proxy object
+ *
+ */
+DBusGProxy*
+dbus_gproxy_new_for_peer (DBusConnection *connection,
+ const char *path_name,
+ const char *interface_name)
+{
+ DBusGProxy *proxy;
+
+ g_return_val_if_fail (connection != NULL, NULL);
+ g_return_val_if_fail (path_name != NULL, NULL);
+ g_return_val_if_fail (interface_name != NULL, NULL);
+
+ proxy = dbus_gproxy_new (connection, NULL,
+ path_name, interface_name);
+
+ return proxy;
+}
+
+/**
+ * Invokes a method on a remote interface. This function does not
+ * block; instead it returns an opaque #DBusPendingCall object that
+ * tracks the pending call. The method call will not be sent over the
+ * wire until the application returns to the main loop, or blocks in
+ * dbus_connection_flush() to write out pending data. The call will
+ * be completed after a timeout, or when a reply is received.
+ * To collect the results of the call (which may be an error,
+ * or a reply), use dbus_gproxy_end_call().
+ *
+ * @todo this particular function shouldn't die on out of memory,
+ * since you should be able to do a call with large arguments.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param method the name of the method to invoke
+ * @param first_arg_type type of the first argument
+ *
+ * @returns opaque pending call object
+ * */
+DBusPendingCall*
+dbus_gproxy_begin_call (DBusGProxy *proxy,
+ const char *method,
+ int first_arg_type,
+ ...)
+{
+ DBusPendingCall *pending;
+ DBusMessage *message;
+ va_list args;
+
+ g_return_val_if_fail (DBUS_IS_GPROXY (proxy), NULL);
+
+ message = dbus_message_new_method_call (proxy->service,
+ proxy->path,
+ proxy->interface,
+ method);
+ if (message == NULL)
+ goto oom;
+
+ va_start (args, first_arg_type);
+ if (!dbus_message_append_args_valist (message, first_arg_type,
+ args))
+ goto oom;
+ va_end (args);
+
+ if (!dbus_connection_send_with_reply (proxy->manager->connection,
+ message,
+ &pending,
+ -1))
+ goto oom;
+
+ return pending;
+
+ oom:
+ /* FIXME we should create a pending call that's
+ * immediately completed with an error status without
+ * ever going on the wire.
+ */
+
+ g_error ("Out of memory");
+ return NULL;
+}
+
+/**
+ * Collects the results of a method call. The method call was normally
+ * initiated with dbus_gproxy_end_call(). This function will block if
+ * the results haven't yet been received; use
+ * dbus_pending_call_set_notify() to be notified asynchronously that a
+ * pending call has been completed. Use
+ * dbus_pending_call_get_completed() to check whether a call has been
+ * completed. If it's completed, it will not block.
+ *
+ * If the call results in an error, the error is set as normal for
+ * GError and the function returns #FALSE.
+ *
+ * Otherwise, the "out" parameters and return value of the
+ * method are stored in the provided varargs list.
+ * The list should be terminated with DBUS_TYPE_INVALID.
+ *
+ * This function doesn't affect the reference count of the
+ * #DBusPendingCall, the caller of dbus_gproxy_begin_call() still owns
+ * a reference.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param pending the pending call from dbus_gproxy_begin_call()
+ * @param error return location for an error
+ * @param first_arg_type type of first "out" argument
+ * @returns #FALSE if an error is set */
+gboolean
+dbus_gproxy_end_call (DBusGProxy *proxy,
+ DBusPendingCall *pending,
+ GError **error,
+ int first_arg_type,
+ ...)
+{
+ DBusMessage *message;
+ va_list args;
+ DBusError derror;
+
+ g_return_val_if_fail (DBUS_IS_GPROXY (proxy), FALSE);
+ g_return_val_if_fail (pending != NULL, FALSE);
+
+ dbus_pending_call_block (pending);
+ message = dbus_pending_call_get_reply (pending);
+
+ g_assert (message != NULL);
+
+ dbus_error_init (&derror);
+ va_start (args, first_arg_type);
+ if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
+ {
+ va_end (args);
+ goto error;
+ }
+ va_end (args);
+
+ return TRUE;
+
+ error:
+ dbus_set_g_error (error, &derror);
+ dbus_error_free (&derror);
+ return FALSE;
+}
+
+/**
+ * Sends a method call message as with dbus_gproxy_begin_call(), but
+ * does not ask for a reply or allow you to receive one.
+ *
+ * @todo this particular function shouldn't die on out of memory,
+ * since you should be able to do a call with large arguments.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param method the name of the method to invoke
+ * @param first_arg_type type of the first argument
+ */
+void
+dbus_gproxy_oneway_call (DBusGProxy *proxy,
+ const char *method,
+ int first_arg_type,
+ ...)
+{
+ DBusMessage *message;
+ va_list args;
+
+ g_return_if_fail (DBUS_IS_GPROXY (proxy));
+
+ message = dbus_message_new_method_call (proxy->service,
+ proxy->path,
+ proxy->interface,
+ method);
+ if (message == NULL)
+ goto oom;
+
+ dbus_message_set_no_reply (message, TRUE);
+
+ va_start (args, first_arg_type);
+ if (!dbus_message_append_args_valist (message, first_arg_type,
+ args))
+ goto oom;
+ va_end (args);
+
+ if (!dbus_connection_send (proxy->manager->connection,
+ message,
+ NULL))
+ goto oom;
+
+ oom:
+ g_error ("Out of memory");
+}
+
+/**
+ * Sends a message to the interface we're proxying for. Does not
+ * block or wait for a reply. The message is only actually written out
+ * when you return to the main loop or block in
+ * dbus_connection_flush().
+ *
+ * The message is modified to be addressed to the target interface.
+ * That is, a destination service field or whatever is needed will be
+ * added to the message. The basic point of this function is to add
+ * the necessary header fields, otherwise it's equivalent to
+ * dbus_connection_send().
+ *
+ * This function adds a reference to the message, so the caller
+ * still owns its original reference.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param message the message to address and send
+ * @param client_serial return location for message's serial, or #NULL */
+void
+dbus_gproxy_send (DBusGProxy *proxy,
+ DBusMessage *message,
+ dbus_uint32_t *client_serial)
+{
+ g_return_if_fail (DBUS_IS_GPROXY (proxy));
+
+ if (proxy->service)
+ {
+ if (!dbus_message_set_destination (message, proxy->service))
+ g_error ("Out of memory");
+ }
+ if (proxy->path)
+ {
+ if (!dbus_message_set_path (message, proxy->path))
+ g_error ("Out of memory");
+ }
+ if (proxy->interface)
+ {
+ if (!dbus_message_set_interface (message, proxy->interface))
+ g_error ("Out of memory");
+ }
+
+ if (!dbus_connection_send (proxy->manager->connection, message, client_serial))
+ g_error ("Out of memory\n");
+}
+
+void
+dbus_gproxy_connect_signal (DBusGProxy *proxy,
+ const char *signal_name,
+ DBusGProxySignalHandler handler,
+ void *data,
+ GClosureNotify free_data_func)
+{
+ GClosure *closure;
+ char *detail;
+
+ g_return_if_fail (DBUS_IS_GPROXY (proxy));
+ g_return_if_fail (signal_name != NULL);
+ g_return_if_fail (handler != NULL);
+
+ detail = create_signal_detail (proxy->interface, signal_name);
+
+ closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
+ g_signal_connect_closure_by_id (G_OBJECT (proxy),
+ signals[RECEIVED],
+ g_quark_from_string (detail),
+ closure, FALSE);
+
+ g_free (detail);
+}
+
+void
+dbus_gproxy_disconnect_signal (DBusGProxy *proxy,
+ const char *signal_name,
+ DBusGProxySignalHandler handler,
+ void *data)
+{
+ char *detail;
+ GQuark q;
+
+ g_return_if_fail (DBUS_IS_GPROXY (proxy));
+ g_return_if_fail (signal_name != NULL);
+ g_return_if_fail (handler != NULL);
+
+ detail = create_signal_detail (proxy->interface, signal_name);
+ q = g_quark_try_string (detail);
+ g_free (detail);
+
+#ifndef G_DISABLE_CHECKS
+ if (q == 0)
+ {
+ g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
+ G_GNUC_FUNCTION, signal_name);
+ return;
+ }
+#endif
+
+ g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
+ G_SIGNAL_MATCH_DETAIL |
+ G_SIGNAL_MATCH_FUNC |
+ G_SIGNAL_MATCH_DATA,
+ signals[RECEIVED],
+ q,
+ NULL,
+ G_CALLBACK (handler), data);
+}
+
+/** @} End of DBusGLib public */
+
+#ifdef DBUS_BUILD_TESTS
+
+/**
+ * @ingroup DBusGLibInternals
+ * Unit test for GLib proxy functions
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_gproxy_test (void)
+{
+
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
diff --git a/glib/dbus-gtest-main.c b/glib/dbus-gtest-main.c
new file mode 100644
index 00000000..5cc6cb78
--- /dev/null
+++ b/glib/dbus-gtest-main.c
@@ -0,0 +1,46 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gtest-main.c Program to run all libdbus-glib tests
+ *
+ * Copyright (C) 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "dbus-gtest.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+
+int
+main (int argc,
+ char **argv)
+{
+ const char *test_data_dir;
+
+ setlocale(LC_ALL, "");
+
+
+ if (argc > 1)
+ test_data_dir = argv[1];
+ else
+ test_data_dir = NULL;
+
+ dbus_glib_internal_do_not_use_run_tests (test_data_dir);
+
+ return 0;
+}
diff --git a/glib/dbus-gtest.c b/glib/dbus-gtest.c
new file mode 100644
index 00000000..48cd13f0
--- /dev/null
+++ b/glib/dbus-gtest.c
@@ -0,0 +1,77 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-test.c Program to run all tests
+ *
+ * Copyright (C) 2002, 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include "dbus-gtest.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef DBUS_BUILD_TESTS
+static void
+die (const char *failure)
+{
+ fprintf (stderr, "Unit test failed: %s\n", failure);
+ exit (1);
+}
+#endif /* DBUS_BUILD_TESTS */
+
+/**
+ * An exported symbol to be run in order to execute
+ * unit tests. Should not be used by
+ * any app other than our test app, this symbol
+ * won't exist in some builds of the library.
+ * (with --enable-tests=no)
+ *
+ * @param test_data_dir the directory with test data (test/data normally)
+ */
+void
+dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir)
+{
+#ifdef DBUS_BUILD_TESTS
+ if (test_data_dir == NULL)
+ test_data_dir = g_getenv ("DBUS_TEST_DATA");
+
+ if (test_data_dir != NULL)
+ printf ("Test data in %s\n", test_data_dir);
+ else
+ printf ("No test data!\n");
+
+ printf ("%s: running utils tests\n", "dbus-glib-test");
+ if (!_dbus_gutils_test (test_data_dir))
+ die ("gutils");
+
+ printf ("%s: running mainloop integration tests\n", "dbus-glib-test");
+ if (!_dbus_gmain_test (test_data_dir))
+ die ("gmain");
+
+ printf ("%s: running GObject tests\n", "dbus-glib-test");
+ if (!_dbus_gobject_test (test_data_dir))
+ die ("gobject");
+
+ printf ("%s: completed successfully\n", "dbus-glib-test");
+#else
+ printf ("Not compiled with unit tests, not running any\n");
+#endif
+}
+
+
diff --git a/glib/dbus-gtest.h b/glib/dbus-gtest.h
new file mode 100644
index 00000000..1174eb0a
--- /dev/null
+++ b/glib/dbus-gtest.h
@@ -0,0 +1,35 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gtest.h Declarations of test functions.
+ *
+ * Copyright (C) 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef DBUS_GLIB_TEST_H
+#define DBUS_GLIB_TEST_H
+
+#include "dbus-glib.h"
+
+dbus_bool_t _dbus_gmain_test (const char *test_data_dir);
+dbus_bool_t _dbus_gobject_test (const char *test_data_dir);
+dbus_bool_t _dbus_gutils_test (const char *test_data_dir);
+
+void dbus_glib_internal_do_not_use_run_tests (const char *test_data_dir);
+
+#endif /* DBUS_GLIB_TEST_H */
diff --git a/glib/dbus-gthread.c b/glib/dbus-gthread.c
index 71a3c1f5..eb3e5572 100644
--- a/glib/dbus-gthread.c
+++ b/glib/dbus-gthread.c
@@ -165,7 +165,7 @@ dbus_gcondvar_wake_all (DBusCondVar *cond)
* other function in the D-BUS API.
*/
void
-dbus_gthread_init (void)
+dbus_g_thread_init (void)
{
if (!g_thread_supported ())
g_error ("g_thread_init() must be called before dbus_threads_init()");
diff --git a/glib/dbus-gtool-test.h b/glib/dbus-gtool-test.h
new file mode 100644
index 00000000..74a7649f
--- /dev/null
+++ b/glib/dbus-gtool-test.h
@@ -0,0 +1,31 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gtool-test.h Declarations of test functions for dbus-glib-tool.
+ *
+ * Copyright (C) 2003 Red Hat Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef DBUS_GLIB_TOOL_TEST_H
+#define DBUS_GLIB_TOOL_TEST_H
+
+#include "dbus-glib.h"
+
+dbus_bool_t _dbus_gtool_test (const char *test_data_dir);
+
+#endif /* DBUS_GLIB_TEST_H */
diff --git a/glib/dbus-gutils.c b/glib/dbus-gutils.c
new file mode 100644
index 00000000..e99286f8
--- /dev/null
+++ b/glib/dbus-gutils.c
@@ -0,0 +1,96 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gutils.c Utils shared between convenience lib and installed lib
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include "dbus-gutils.h"
+#include "dbus-gtest.h"
+#include <string.h>
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+char**
+_dbus_gutils_split_path (const char *path)
+{
+ int len;
+ char **split;
+ int n_components;
+ int i, j, comp;
+
+ len = strlen (path);
+
+ n_components = 0;
+ i = 0;
+ while (i < len)
+ {
+ if (path[i] == '/')
+ n_components += 1;
+ ++i;
+ }
+
+ split = g_new0 (char*, n_components + 1);
+
+ comp = 0;
+ i = 0;
+ while (i < len)
+ {
+ if (path[i] == '/')
+ ++i;
+ j = i;
+
+ while (j < len && path[j] != '/')
+ ++j;
+
+ /* Now [i, j) is the path component */
+ g_assert (i < j);
+ g_assert (path[i] != '/');
+ g_assert (j == len || path[j] == '/');
+
+ split[comp] = g_strndup (&path[i], j - i + 1);
+
+ split[comp][j-i] = '\0';
+
+ ++comp;
+ i = j;
+ }
+ g_assert (i == len);
+
+ return split;
+}
+
+#ifdef DBUS_BUILD_TESTS
+
+/**
+ * @ingroup DBusGLibInternals
+ * Unit test for GLib utils internals
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_gutils_test (const char *test_data_dir)
+{
+
+ return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/glib/dbus-gutils.h b/glib/dbus-gutils.h
new file mode 100644
index 00000000..af7cee45
--- /dev/null
+++ b/glib/dbus-gutils.h
@@ -0,0 +1,40 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-gutils.h Utils shared between convenience lib and installed lib
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef DBUS_GLIB_UTILS_H
+#define DBUS_GLIB_UTILS_H
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+#include <dbus/dbus.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+char** _dbus_gutils_split_path (const char *path);
+
+G_END_DECLS
+
+#endif /* DBUS_GLIB_UTILS_H */
+
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
diff --git a/test/Makefile.am b/test/Makefile.am
index 04df3510..84089517 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,6 +1,13 @@
+if HAVE_GLIB
+ GLIB_SUBDIR=glib
+endif
+
+SUBDIRS=$(GLIB_SUBDIR)
+
INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS)
+
if DBUS_BUILD_TESTS
TEST_BINARIES=test-service unbase64 break-loader spawn-test test-segfault test-exit test-sleep-forever
else
@@ -82,7 +89,7 @@ all-local:
for D in $(TESTDIRS); do \
test -d $(top_builddir)/test/$$D || mkdir $(top_builddir)/test/$$D || exit 1 ; \
done ; \
- if test $(srcdir) != . ; then \
+ if ! (test $(srcdir) = . || test $(srcdir) -ef .) ; then \
FILES=`(cd $(srcdir) && $(FIND_TESTS))` ; \
for F in $$FILES; do \
SRC=$(srcdir)/$$F ; \
diff --git a/test/break-loader.c b/test/break-loader.c
index ebe2606b..3771d7cc 100644
--- a/test/break-loader.c
+++ b/test/break-loader.c
@@ -287,8 +287,8 @@ randomly_add_one_byte (const DBusString *orig_data,
i = random_int_in_range (0, _dbus_string_get_length (mutated));
- _dbus_string_insert_byte (mutated, i,
- random_int_in_range (0, 256));
+ _dbus_string_insert_bytes (mutated, i, 1,
+ random_int_in_range (0, 256));
}
static void
diff --git a/test/data/incomplete-messages/missing-body.message b/test/data/incomplete-messages/missing-body.message
index 71ac5abc..138e9ea5 100644
--- a/test/data/incomplete-messages/missing-body.message
+++ b/test/data/incomplete-messages/missing-body.message
@@ -1,11 +1,14 @@
## message that's missing an expected body
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+HEADER_FIELD INTERFACE
TYPE STRING
STRING 'org.freedesktop.Foo'
-END_LENGTH Header
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
ALIGN 8
+END_LENGTH Header
## create the body, then chop it off
START_LENGTH Body
diff --git a/test/data/invalid-messages/array-of-nil.message b/test/data/invalid-messages/array-of-nil.message
index e86e6a10..7f0ac718 100644
--- a/test/data/invalid-messages/array-of-nil.message
+++ b/test/data/invalid-messages/array-of-nil.message
@@ -1,11 +1,17 @@
# Message with an array of NIL (not allowed)
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
TYPE STRING
STRING 'org.freedesktop.Foo'
-END_LENGTH Header
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
ALIGN 8
+END_LENGTH Header
+
START_LENGTH Body
TYPE ARRAY
TYPE NIL
diff --git a/test/data/invalid-messages/array-with-mixed-types.message b/test/data/invalid-messages/array-with-mixed-types.message
index 763a6c29..4455c898 100644
--- a/test/data/invalid-messages/array-with-mixed-types.message
+++ b/test/data/invalid-messages/array-with-mixed-types.message
@@ -1,12 +1,18 @@
# Message with an array of array where the child arrays are of
# different types
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
TYPE STRING
STRING 'org.freedesktop.Foo'
-END_LENGTH Header
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
ALIGN 8
+END_LENGTH Header
+
START_LENGTH Body
TYPE ARRAY
diff --git a/test/data/invalid-messages/bad-boolean-array.message b/test/data/invalid-messages/bad-boolean-array.message
index c045b978..91ad5ef1 100644
--- a/test/data/invalid-messages/bad-boolean-array.message
+++ b/test/data/invalid-messages/bad-boolean-array.message
@@ -1,12 +1,18 @@
## a message with an invalid boolean array
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
TYPE STRING
STRING 'org.freedesktop.Foo'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
ALIGN 8
END_LENGTH Header
+
START_LENGTH Body
TYPE ARRAY
TYPE BOOLEAN
diff --git a/test/data/invalid-messages/bad-boolean.message b/test/data/invalid-messages/bad-boolean.message
index 00a29626..cd588ad8 100644
--- a/test/data/invalid-messages/bad-boolean.message
+++ b/test/data/invalid-messages/bad-boolean.message
@@ -1,12 +1,18 @@
## a message with an invalid boolean value
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
TYPE STRING
STRING 'org.freedesktop.Foo'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
ALIGN 8
END_LENGTH Header
+
START_LENGTH Body
TYPE BOOLEAN
BYTE 3
diff --git a/test/data/invalid-messages/bad-endian.message b/test/data/invalid-messages/bad-endian.message
index 7a7b75d1..8d609244 100644
--- a/test/data/invalid-messages/bad-endian.message
+++ b/test/data/invalid-messages/bad-endian.message
@@ -1,13 +1,22 @@
## message with invalid endianness tag
BYTE 'i'
+BYTE 1
BYTE 0
BYTE 0
-BYTE 0
+
LENGTH Header
LENGTH Body
-## client serial
-INT32 7
+
+HEADER_FIELD INTERFACE
+TYPE STRING
+STRING 'org.freedesktop.Foo'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
+ALIGN 8
END_LENGTH Header
+
START_LENGTH Body
END_LENGTH Body
diff --git a/test/data/invalid-messages/bad-header-field-alignment.message b/test/data/invalid-messages/bad-header-field-alignment.message
new file mode 100644
index 00000000..75776a37
--- /dev/null
+++ b/test/data/invalid-messages/bad-header-field-alignment.message
@@ -0,0 +1,34 @@
+## last field incorrectly aligned to 4 bytes
+
+## VALID_HEADER includes a LENGTH Header and LENGTH Body
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
+TYPE STRING
+STRING 'org.freedesktop.Foo'
+
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
+HEADER_FIELD UNKNOWN
+TYPE STRING
+STRING 'a'
+
+ALIGN 4
+
+HEADER_FIELD UNKNOWN
+TYPE ARRAY
+TYPE BYTE
+ALIGN 4
+LENGTH ThisByteArray
+START_LENGTH ThisByteArray
+BYTE 1
+BYTE 2
+END_LENGTH ThisByteArray
+
+
+ALIGN 8
+END_LENGTH Header
+START_LENGTH Body
+END_LENGTH Body
diff --git a/test/data/invalid-messages/local-namespace.message b/test/data/invalid-messages/local-namespace.message
index ceb3053d..dad98a77 100644
--- a/test/data/invalid-messages/local-namespace.message
+++ b/test/data/invalid-messages/local-namespace.message
@@ -2,11 +2,17 @@
## invalid
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
+TYPE STRING
+STRING 'org.freedesktop.Local'
+HEADER_FIELD MEMBER
TYPE STRING
-STRING 'org.freedesktop.Local.Disconnect'
+STRING 'Disconnected'
+
ALIGN 8
END_LENGTH Header
+
START_LENGTH Body
END_LENGTH Body
diff --git a/test/data/invalid-messages/no-dot-in-name.message b/test/data/invalid-messages/no-dot-in-name.message
index 4cde0d1f..131be05d 100644
--- a/test/data/invalid-messages/no-dot-in-name.message
+++ b/test/data/invalid-messages/no-dot-in-name.message
@@ -1,10 +1,15 @@
-## a message with dotless name
+## a message with dotless interface
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
+TYPE STRING
+STRING 'NoDotInHere'
+HEADER_FIELD MEMBER
TYPE STRING
-STRING 'NoNamespaceHere'
+STRING 'Bar'
+
ALIGN 8
END_LENGTH Header
START_LENGTH Body
diff --git a/test/data/invalid-messages/not-nul-header-padding.message b/test/data/invalid-messages/not-nul-header-padding.message
index 1172af4b..a12c0fa7 100644
--- a/test/data/invalid-messages/not-nul-header-padding.message
+++ b/test/data/invalid-messages/not-nul-header-padding.message
@@ -1,8 +1,16 @@
## has one non-nul byte in header padding
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME unkn
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
+TYPE STRING
+STRING 'org.freedesktop.Foo'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
+HEADER_FIELD UNKNOWN
TYPE STRING
STRING 'a'
ALIGN 8
diff --git a/test/data/invalid-messages/overlong-name.message b/test/data/invalid-messages/overlong-name.message
index 0fdc7bc9..4fd7025e 100644
--- a/test/data/invalid-messages/overlong-name.message
+++ b/test/data/invalid-messages/overlong-name.message
@@ -1,10 +1,15 @@
## a message with too-long name field
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+HEADER_FIELD INTERFACE
TYPE STRING
STRING 'org.foo.bar.this.is.really.long 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200'
+
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
ALIGN 8
END_LENGTH Header
START_LENGTH Body
diff --git a/test/data/invalid-messages/too-little-header-padding.message b/test/data/invalid-messages/too-little-header-padding.message
index cf73be68..894e4c3e 100644
--- a/test/data/invalid-messages/too-little-header-padding.message
+++ b/test/data/invalid-messages/too-little-header-padding.message
@@ -1,8 +1,16 @@
## has one byte missing from header padding
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME unkn
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
+TYPE STRING
+STRING 'org.freedesktop.Foo'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
+HEADER_FIELD UNKNOWN
TYPE STRING
STRING 'a'
ALIGN 8
diff --git a/test/data/invalid-messages/too-much-header-padding-by-far.message b/test/data/invalid-messages/too-much-header-padding-by-far.message
index a60aca88..b74f559b 100644
--- a/test/data/invalid-messages/too-much-header-padding-by-far.message
+++ b/test/data/invalid-messages/too-much-header-padding-by-far.message
@@ -1,8 +1,16 @@
## has one byte extra header padding
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME unkn
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
+TYPE STRING
+STRING 'org.freedesktop.Foo'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
+HEADER_FIELD UNKNOWN
TYPE STRING
STRING 'a'
ALIGN 8
diff --git a/test/data/invalid-messages/too-much-header-padding.message b/test/data/invalid-messages/too-much-header-padding.message
index ebf154eb..01111b63 100644
--- a/test/data/invalid-messages/too-much-header-padding.message
+++ b/test/data/invalid-messages/too-much-header-padding.message
@@ -1,8 +1,16 @@
## has one byte extra header padding
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME unkn
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
+TYPE STRING
+STRING 'org.freedesktop.Foo'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
+HEADER_FIELD UNKNOWN
TYPE STRING
STRING 'a'
ALIGN 8
diff --git a/test/data/invalid-messages/too-short-dict.message b/test/data/invalid-messages/too-short-dict.message
index ba200461..fde88850 100644
--- a/test/data/invalid-messages/too-short-dict.message
+++ b/test/data/invalid-messages/too-short-dict.message
@@ -1,11 +1,18 @@
# Message with lots of different argument types
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+
+HEADER_FIELD INTERFACE
TYPE STRING
STRING 'org.freedesktop.Foo'
-END_LENGTH Header
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
ALIGN 8
+
+END_LENGTH Header
+
START_LENGTH Body
TYPE DICT
LENGTH Dict
diff --git a/test/data/valid-config-files/debug-allow-all-sha1.conf.in b/test/data/valid-config-files/debug-allow-all-sha1.conf.in
index 6db93f0c..7fb76c55 100644
--- a/test/data/valid-config-files/debug-allow-all-sha1.conf.in
+++ b/test/data/valid-config-files/debug-allow-all-sha1.conf.in
@@ -8,8 +8,8 @@
<servicedir>@TEST_SERVICE_DIR@</servicedir>
<auth>DBUS_COOKIE_SHA1</auth>
<policy context="default">
- <allow send="*"/>
- <allow receive="*"/>
+ <allow send_interface="*"/>
+ <allow receive_interface="*"/>
<allow own="*"/>
<allow user="*"/>
</policy>
diff --git a/test/data/valid-config-files/debug-allow-all.conf.in b/test/data/valid-config-files/debug-allow-all.conf.in
index 0dd8ed4a..ea1aec8c 100644
--- a/test/data/valid-config-files/debug-allow-all.conf.in
+++ b/test/data/valid-config-files/debug-allow-all.conf.in
@@ -7,8 +7,8 @@
<listen>unix:tmpdir=@TEST_SOCKET_DIR@</listen>
<servicedir>@TEST_SERVICE_DIR@</servicedir>
<policy context="default">
- <allow send="*"/>
- <allow receive="*"/>
+ <allow send_interface="*"/>
+ <allow receive_interface="*"/>
<allow own="*"/>
<allow user="*"/>
</policy>
diff --git a/test/data/valid-config-files/many-rules.conf b/test/data/valid-config-files/many-rules.conf
new file mode 100644
index 00000000..f68430e5
--- /dev/null
+++ b/test/data/valid-config-files/many-rules.conf
@@ -0,0 +1,57 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <user>mybususer</user>
+ <listen>unix:path=/foo/bar</listen>
+ <listen>tcp:port=1234</listen>
+ <includedir>basic.d</includedir>
+ <servicedir>/usr/share/foo</servicedir>
+ <include ignore_missing="yes">nonexistent.conf</include>
+ <policy context="default">
+ <allow user="*"/>
+ <deny send_interface="org.freedesktop.System" send_member="Reboot"/>
+ <deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
+ <deny send_path="/foo/bar/SystemObjectThing" send_member="Reboot"/>
+ <deny own="org.freedesktop.System"/>
+ <deny send_destination="org.freedesktop.System"/>
+ <deny receive_sender="org.freedesktop.System"/>
+ <deny user="root"/>
+ <deny group="root"/>
+ <allow send_type="error"/>
+ <allow send_type="method_call"/>
+ <allow send_type="method_return"/>
+ <allow send_type="signal"/>
+ <deny send_destination="org.freedesktop.Bar" send_interface="org.freedesktop.Foo"/>
+ <deny send_destination="org.freedesktop.Bar" send_interface="org.freedesktop.Foo" send_type="method_call"/>
+ </policy>
+
+ <policy context="mandatory">
+ <allow user="*"/>
+ <deny send_interface="org.freedesktop.System" send_member="Reboot"/>
+ <deny receive_interface="org.freedesktop.System" receive_member="Reboot"/>
+ <deny send_path="/foo/bar/SystemObjectThing" send_member="Reboot"/>
+ <deny own="org.freedesktop.System"/>
+ <deny send_destination="org.freedesktop.System"/>
+ <deny receive_sender="org.freedesktop.System"/>
+ <deny user="root"/>
+ <deny group="root"/>
+ <allow send_type="error"/>
+ <allow send_type="method_call"/>
+ <allow send_type="method_return"/>
+ <allow send_type="signal"/>
+ <deny send_destination="org.freedesktop.Bar" send_interface="org.freedesktop.Foo"/>
+ <deny send_destination="org.freedesktop.Bar" send_interface="org.freedesktop.Foo" send_type="method_call"/>
+ </policy>
+
+ <limit name="max_incoming_bytes">5000</limit>
+ <limit name="max_outgoing_bytes">5000</limit>
+ <limit name="max_message_size">300</limit>
+ <limit name="activation_timeout">5000</limit>
+ <limit name="auth_timeout">6000</limit>
+ <limit name="max_completed_connections">50</limit>
+ <limit name="max_incomplete_connections">80</limit>
+ <limit name="max_connections_per_user">64</limit>
+ <limit name="max_pending_activations">64</limit>
+ <limit name="max_services_per_connection">256</limit>
+
+</busconfig>
diff --git a/test/data/valid-config-files/system.d/test.conf b/test/data/valid-config-files/system.d/test.conf
index a683679e..5b60a1fc 100644
--- a/test/data/valid-config-files/system.d/test.conf
+++ b/test/data/valid-config-files/system.d/test.conf
@@ -5,16 +5,16 @@
policy so that a particular user can own a service, and other
connections can get messages from it -->
- <!-- Only fooserviceuser can own the FooService service, and
+ <!-- Only root can own the FooService service, and
this user can only send the one kind of message -->
- <policy user="fooserviceuser">
+ <policy user="root">
<allow own="org.foo.FooService"/>
- <allow send="org.foo.FooBroadcastMessage"/>
+ <allow send_interface="org.foo.FooBroadcastInterface"/>
</policy>
<!-- Allow any connection to receive the message, but
only if the message is sent by the owner of FooService -->
<policy context="default">
- <allow receive="org.foo.FooBroadcastMessage" receive_from="org.foo.FooService"/>
+ <allow receive_interface="org.foo.FooBroadcastInterface" receive_sender="org.foo.FooService"/>
</policy>
</busconfig>
diff --git a/test/data/valid-messages/array-of-array-of-uint32.message b/test/data/valid-messages/array-of-array-of-uint32.message
index 82b8273d..e12186b1 100644
--- a/test/data/valid-messages/array-of-array-of-uint32.message
+++ b/test/data/valid-messages/array-of-array-of-uint32.message
@@ -1,11 +1,9 @@
# Message with an array of array of uint32
-VALID_HEADER
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
-END_LENGTH Header
+VALID_HEADER method_call
+REQUIRED_FIELDS
ALIGN 8
+END_LENGTH Header
START_LENGTH Body
TYPE ARRAY
diff --git a/test/data/valid-messages/dict-simple.message b/test/data/valid-messages/dict-simple.message
index 34fb47d9..fa6927df 100644
--- a/test/data/valid-messages/dict-simple.message
+++ b/test/data/valid-messages/dict-simple.message
@@ -1,11 +1,9 @@
# A simple dict
-VALID_HEADER
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
-END_LENGTH Header
+VALID_HEADER method_call
+REQUIRED_FIELDS
ALIGN 8
+END_LENGTH Header
START_LENGTH Body
TYPE DICT
LENGTH Dict
diff --git a/test/data/valid-messages/dict.message b/test/data/valid-messages/dict.message
index 6b9d004e..0f997b1f 100644
--- a/test/data/valid-messages/dict.message
+++ b/test/data/valid-messages/dict.message
@@ -1,9 +1,7 @@
# Dict with different values
-VALID_HEADER
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
+VALID_HEADER method_call
+REQUIRED_FIELDS
ALIGN 8
END_LENGTH Header
START_LENGTH Body
diff --git a/test/data/valid-messages/emptiness.message b/test/data/valid-messages/emptiness.message
index 87196b16..32042c01 100644
--- a/test/data/valid-messages/emptiness.message
+++ b/test/data/valid-messages/emptiness.message
@@ -1,11 +1,9 @@
# Empty arrays and strings
-VALID_HEADER
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
-END_LENGTH Header
+VALID_HEADER method_call
+REQUIRED_FIELDS
ALIGN 8
+END_LENGTH Header
START_LENGTH Body
TYPE STRING
INT32 0
diff --git a/test/data/valid-messages/lots-of-arguments.message b/test/data/valid-messages/lots-of-arguments.message
index 6549646e..d3f6a4ee 100644
--- a/test/data/valid-messages/lots-of-arguments.message
+++ b/test/data/valid-messages/lots-of-arguments.message
@@ -1,11 +1,9 @@
# Message with lots of different argument types
-VALID_HEADER
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
-END_LENGTH Header
+VALID_HEADER method_call
+REQUIRED_FIELDS
ALIGN 8
+END_LENGTH Header
START_LENGTH Body
TYPE NIL
TYPE BYTE
diff --git a/test/data/valid-messages/no-padding.message b/test/data/valid-messages/no-padding.message
index b47dca78..94df4d45 100644
--- a/test/data/valid-messages/no-padding.message
+++ b/test/data/valid-messages/no-padding.message
@@ -1,15 +1,13 @@
## Message with no header padding
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
+VALID_HEADER method_call
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
+REQUIRED_FIELDS
## this byte array is filled with zeros to the natural length
## of the header
-FIELD_NAME unkn
+HEADER_FIELD UNKNOWN
TYPE ARRAY
TYPE BYTE
ALIGN 4
diff --git a/test/data/valid-messages/opposite-endian.message b/test/data/valid-messages/opposite-endian.message
index f8975b8b..90949dd2 100644
--- a/test/data/valid-messages/opposite-endian.message
+++ b/test/data/valid-messages/opposite-endian.message
@@ -3,17 +3,11 @@
OPPOSITE_ENDIAN
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
+VALID_HEADER method_call
-FIELD_NAME rply
-TYPE UINT32
-UINT32 10000
-
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
+REQUIRED_FIELDS
-FIELD_NAME unkn
+HEADER_FIELD UNKNOWN
TYPE INT32
INT32 0xfeeb
diff --git a/test/data/valid-messages/recursive-types.message b/test/data/valid-messages/recursive-types.message
index 2ac6ad13..e306fd1f 100644
--- a/test/data/valid-messages/recursive-types.message
+++ b/test/data/valid-messages/recursive-types.message
@@ -1,12 +1,11 @@
## Message with recursive types
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
+VALID_HEADER method_call
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
+REQUIRED_FIELDS
+ALIGN 8
END_LENGTH Header
START_LENGTH Body
diff --git a/test/data/valid-messages/simplest-manual.message b/test/data/valid-messages/simplest-manual.message
index 8eed1e5f..5a5b4105 100644
--- a/test/data/valid-messages/simplest-manual.message
+++ b/test/data/valid-messages/simplest-manual.message
@@ -3,16 +3,24 @@
LITTLE_ENDIAN
BYTE 'l'
-BYTE 0
+BYTE 1
BYTE 0
BYTE 0
LENGTH Header
LENGTH Body
## client serial
INT32 7
-FIELD_NAME name
+
+HEADER_FIELD PATH
+TYPE OBJECT_PATH
+OBJECT_PATH '/foo'
+HEADER_FIELD INTERFACE
TYPE STRING
STRING 'org.freedesktop.Foo'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Bar'
+
ALIGN 8
END_LENGTH Header
START_LENGTH Body
diff --git a/test/data/valid-messages/simplest.message b/test/data/valid-messages/simplest.message
index 7bb1872d..b9ddaf6b 100644
--- a/test/data/valid-messages/simplest.message
+++ b/test/data/valid-messages/simplest.message
@@ -1,10 +1,9 @@
## simplest possible valid message
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
+VALID_HEADER method_call
+REQUIRED_FIELDS
+
ALIGN 8
END_LENGTH Header
START_LENGTH Body
diff --git a/test/data/valid-messages/standard-acquire-service.message b/test/data/valid-messages/standard-acquire-service.message
index 5056d8df..a42a639c 100644
--- a/test/data/valid-messages/standard-acquire-service.message
+++ b/test/data/valid-messages/standard-acquire-service.message
@@ -1,10 +1,16 @@
# Standard org.freedesktop.DBus.AcquireService message
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+HEADER_FIELD PATH
+TYPE OBJECT_PATH
+OBJECT_PATH '/org/freedesktop/DBus'
+HEADER_FIELD INTERFACE
TYPE STRING
-STRING 'org.freedesktop.DBus.AcquireService'
-FIELD_NAME srvc
+STRING 'org.freedesktop.DBus'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'AcquireService'
+HEADER_FIELD SERVICE
TYPE STRING
STRING 'org.freedesktop.DBus'
ALIGN 8
diff --git a/test/data/valid-messages/standard-hello.message b/test/data/valid-messages/standard-hello.message
index f3f65961..50d4e0ff 100644
--- a/test/data/valid-messages/standard-hello.message
+++ b/test/data/valid-messages/standard-hello.message
@@ -1,10 +1,16 @@
# Standard org.freedesktop.DBus.Hello message
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+HEADER_FIELD PATH
+TYPE OBJECT_PATH
+OBJECT_PATH '/org/freedesktop/DBus'
+HEADER_FIELD INTERFACE
TYPE STRING
-STRING 'org.freedesktop.DBus.Hello'
-FIELD_NAME srvc
+STRING 'org.freedesktop.DBus'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'Hello'
+HEADER_FIELD SERVICE
TYPE STRING
STRING 'org.freedesktop.DBus'
ALIGN 8
diff --git a/test/data/valid-messages/standard-list-services.message b/test/data/valid-messages/standard-list-services.message
index 9dfb72e3..10c9a2f7 100644
--- a/test/data/valid-messages/standard-list-services.message
+++ b/test/data/valid-messages/standard-list-services.message
@@ -1,10 +1,16 @@
# Standard org.freedesktop.DBus.ListServices message
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+HEADER_FIELD PATH
+TYPE OBJECT_PATH
+OBJECT_PATH '/org/freedesktop/DBus'
+HEADER_FIELD INTERFACE
TYPE STRING
-STRING 'org.freedesktop.DBus.ListServices'
-FIELD_NAME srvc
+STRING 'org.freedesktop.DBus'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'ListServices'
+HEADER_FIELD SERVICES
TYPE STRING
STRING 'org.freedesktop.DBus'
ALIGN 8
diff --git a/test/data/valid-messages/standard-service-exists.message b/test/data/valid-messages/standard-service-exists.message
index 6755fea6..c3b715bc 100644
--- a/test/data/valid-messages/standard-service-exists.message
+++ b/test/data/valid-messages/standard-service-exists.message
@@ -1,10 +1,16 @@
# Standard org.freedesktop.DBus.ServiceExists message
-VALID_HEADER
-FIELD_NAME name
+VALID_HEADER method_call
+HEADER_FIELD PATH
+TYPE OBJECT_PATH
+OBJECT_PATH '/org/freedesktop/DBus'
+HEADER_FIELD INTERFACE
TYPE STRING
-STRING 'org.freedesktop.DBus.ServiceExists'
-FIELD_NAME srvc
+STRING 'org.freedesktop.DBus'
+HEADER_FIELD MEMBER
+TYPE STRING
+STRING 'ServiceExists'
+HEADER_FIELD SERVICE
TYPE STRING
STRING 'org.freedesktop.DBus'
ALIGN 8
diff --git a/test/data/valid-messages/unknown-header-field.message b/test/data/valid-messages/unknown-header-field.message
index 18ab379c..ac7d624c 100644
--- a/test/data/valid-messages/unknown-header-field.message
+++ b/test/data/valid-messages/unknown-header-field.message
@@ -1,13 +1,18 @@
## message with a 'name' header field and unknown 'unkn' field
## VALID_HEADER includes a LENGTH Header and LENGTH Body
-VALID_HEADER
-FIELD_NAME name
-TYPE STRING
-STRING 'org.freedesktop.Foo'
-FIELD_NAME unkn
+VALID_HEADER method_call
+REQUIRED_FIELDS
+
+HEADER_FIELD UNKNOWN
+TYPE DICT
+LENGTH Dict
+START_LENGTH Dict
+STRING 'int32'
TYPE INT32
-INT32 0xfeeb
+INT32 0x12345678
+END_LENGTH Dict
+
ALIGN 8
END_LENGTH Header
START_LENGTH Body
diff --git a/test/decode-gcov.c b/test/decode-gcov.c
index d13340e3..a7a4478b 100644
--- a/test/decode-gcov.c
+++ b/test/decode-gcov.c
@@ -38,6 +38,10 @@
#include <stdlib.h>
#include <string.h>
+#ifndef DBUS_HAVE_INT64
+#error "gcov support can't be built without 64-bit integer support"
+#endif
+
static void
die (const char *message)
{
diff --git a/test/test-service.c b/test/test-service.c
index c2757acc..d07575e2 100644
--- a/test/test-service.c
+++ b/test/test-service.c
@@ -37,9 +37,9 @@ handle_echo (DBusConnection *connection,
DBUS_TYPE_STRING, &s,
DBUS_TYPE_INVALID))
{
- reply = dbus_message_new_error_reply (message,
- error.name,
- error.message);
+ reply = dbus_message_new_error (message,
+ error.name,
+ error.message);
if (reply == NULL)
die ("No memory\n");
@@ -49,10 +49,10 @@ handle_echo (DBusConnection *connection,
dbus_message_unref (reply);
- return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
- reply = dbus_message_new_reply (message);
+ reply = dbus_message_new_method_return (message);
if (reply == NULL)
die ("No memory\n");
@@ -68,27 +68,32 @@ handle_echo (DBusConnection *connection,
dbus_message_unref (reply);
- return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static DBusHandlerResult
-filter_func (DBusMessageHandler *handler,
- DBusConnection *connection,
+filter_func (DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
- if (dbus_message_has_name (message, "org.freedesktop.DBus.TestSuiteEcho"))
+ if (dbus_message_is_method_call (message,
+ "org.freedesktop.TestSuite",
+ "Echo"))
return handle_echo (connection, message);
- else if (dbus_message_has_name (message, "org.freedesktop.DBus.TestSuiteExit") ||
- dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT))
+ else if (dbus_message_is_method_call (message,
+ "org.freedesktop.TestSuite",
+ "Exit") ||
+ dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+ "Disconnected"))
{
dbus_connection_disconnect (connection);
quit ();
- return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ return DBUS_HANDLER_RESULT_HANDLED;
}
else
{
- return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
}
@@ -98,16 +103,10 @@ main (int argc,
{
DBusConnection *connection;
DBusError error;
- DBusMessageHandler *handler;
- const char *to_handle[] = {
- "org.freedesktop.DBus.TestSuiteEcho",
- "org.freedesktop.DBus.TestSuiteExit",
- DBUS_MESSAGE_LOCAL_DISCONNECT,
- };
int result;
dbus_error_init (&error);
- connection = dbus_bus_get (DBUS_BUS_ACTIVATION, &error);
+ connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
if (connection == NULL)
{
_dbus_verbose ("*** Failed to open connection to activating message bus: %s\n",
@@ -123,18 +122,17 @@ main (int argc,
if (!test_connection_setup (loop, connection))
die ("No memory\n");
- handler = dbus_message_handler_new (filter_func, NULL, NULL);
- if (handler == NULL)
- die ("No memory");
-
- if (!dbus_connection_register_handler (connection, handler, to_handle,
- _DBUS_N_ELEMENTS (to_handle)))
+ if (!dbus_connection_add_filter (connection,
+ filter_func, NULL, NULL))
die ("No memory");
+ printf ("Acquiring service\n");
+
result = dbus_bus_acquire_service (connection, "org.freedesktop.DBus.TestSuiteEchoService",
0, &error);
if (dbus_error_is_set (&error))
{
+ printf ("Error %s", error.message);
_dbus_verbose ("*** Failed to acquire service: %s\n",
error.message);
dbus_error_free (&error);
@@ -145,10 +143,10 @@ main (int argc,
_dbus_loop_run (loop);
test_connection_shutdown (loop, connection);
+
+ dbus_connection_remove_filter (connection, filter_func, NULL);
dbus_connection_unref (connection);
-
- dbus_message_handler_unref (handler);
_dbus_loop_unref (loop);
loop = NULL;
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 80957854..a6a38a97 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -1,4 +1,4 @@
-INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS)
+INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_X_CFLAGS) $(DBUS_GTK_CFLAGS) -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\"
if HAVE_GLIB
GLIB_TOOLS=dbus-monitor
@@ -6,7 +6,13 @@ else
GLIB_TOOLS=
endif
-bin_PROGRAMS=dbus-send $(GLIB_TOOLS) dbus-launch dbus-cleanup-sockets
+if HAVE_GTK
+GTK_TOOLS=dbus-viewer
+else
+GTK_TOOLS=
+endif
+
+bin_PROGRAMS=dbus-send $(GLIB_TOOLS) dbus-launch dbus-cleanup-sockets $(GTK_TOOLS)
dbus_send_SOURCES= \
dbus-print-message.c \
@@ -24,9 +30,17 @@ dbus_launch_SOURCES= \
dbus_cleanup_sockets_SOURCES= \
dbus-cleanup-sockets.c
+dbus_viewer_SOURCES= \
+ dbus-tree-view.c \
+ dbus-tree-view.h \
+ dbus-viewer.c
+
dbus_send_LDADD= $(top_builddir)/dbus/libdbus-1.la
dbus_monitor_LDADD= $(top_builddir)/glib/libdbus-glib-1.la
dbus_launch_LDADD= $(DBUS_X_LIBS)
+dbus_viewer_LDADD= $(top_builddir)/glib/libdbus-gtool.la $(DBUS_GTK_LIBS)
man_MANS = dbus-send.1 dbus-monitor.1 dbus-launch.1 dbus-cleanup-sockets.1
EXTRA_DIST = $(man_MANS)
+
+
diff --git a/tools/dbus-monitor.c b/tools/dbus-monitor.c
index dac15292..23ee346a 100644
--- a/tools/dbus-monitor.c
+++ b/tools/dbus-monitor.c
@@ -30,17 +30,18 @@
#include "dbus-print-message.h"
static DBusHandlerResult
-handler_func (DBusMessageHandler *handler,
- DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
+filter_func (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
{
print_message (message);
- if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT))
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
+ "Disconnected"))
exit (0);
- return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void
@@ -56,7 +57,6 @@ main (int argc, char *argv[])
DBusConnection *connection;
DBusError error;
DBusBusType type = DBUS_BUS_SESSION;
- DBusMessageHandler *handler;
GMainLoop *loop;
int i;
@@ -94,8 +94,7 @@ main (int argc, char *argv[])
dbus_connection_setup_with_g_main (connection, NULL);
- handler = dbus_message_handler_new (handler_func, NULL, NULL);
- dbus_connection_add_filter (connection, handler);
+ dbus_connection_add_filter (connection, filter_func, NULL, NULL);
g_main_loop_run (loop);
diff --git a/tools/dbus-print-message.c b/tools/dbus-print-message.c
index bb380ce5..43c41c73 100644
--- a/tools/dbus-print-message.c
+++ b/tools/dbus-print-message.c
@@ -21,18 +21,64 @@
*/
#include "dbus-print-message.h"
+static const char*
+type_to_name (int message_type)
+{
+ switch (message_type)
+ {
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ return "signal";
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ return "method call";
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ return "method return";
+ case DBUS_MESSAGE_TYPE_ERROR:
+ return "error";
+ default:
+ return "(unknown message type)";
+ }
+}
+
void
print_message (DBusMessage *message)
{
DBusMessageIter iter;
const char *sender;
+ int message_type;
+ message_type = dbus_message_get_type (message);
sender = dbus_message_get_sender (message);
-
- printf ("message name=%s; sender=%s\n",
- dbus_message_get_name (message),
- sender ? sender : "(no sender)");
-
+
+ switch (message_type)
+ {
+ case DBUS_MESSAGE_TYPE_METHOD_CALL:
+ case DBUS_MESSAGE_TYPE_SIGNAL:
+ printf ("%s interface=%s; member=%s; sender=%s\n",
+ type_to_name (message_type),
+ dbus_message_get_interface (message),
+ dbus_message_get_member (message),
+ sender ? sender : "(no sender)");
+ break;
+
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+ printf ("%s; sender=%s\n",
+ type_to_name (message_type),
+ sender ? sender : "(no sender)");
+ break;
+
+ case DBUS_MESSAGE_TYPE_ERROR:
+ printf ("%s name=%s; sender=%s\n",
+ type_to_name (message_type),
+ dbus_message_get_error_name (message),
+ sender ? sender : "(no sender)");
+ break;
+
+ default:
+ printf ("Message of unknown type %d received\n",
+ message_type);
+ break;
+ }
+
dbus_message_iter_init (message, &iter);
do
diff --git a/tools/dbus-send.1 b/tools/dbus-send.1
index 08ea1335..725507c0 100644
--- a/tools/dbus-send.1
+++ b/tools/dbus-send.1
@@ -8,7 +8,8 @@ dbus-send \- Send a message to a message bus
.SH SYNOPSIS
.PP
.B dbus-send
-[\-\-system | \-\-session] [\-\-dest=SERVICE] [\-\-print-reply] <message name> [contents ...]
+[\-\-system | \-\-session] [\-\-dest=SERVICE] [\-\-print-reply]
+[\-\-type=TYPE] <destination object path> <message name> [contents ...]
.SH DESCRIPTION
@@ -28,26 +29,31 @@ specified, \fIdbus-send\fP sends to the session bus.
Nearly all uses of \fIdbus-send\fP must provide the \-\-dest argument
which is the name of a service on the bus to send the message to. If
\-\-dest is omitted, a default service name of
-"org.freedesktop.DBus.Broadcast" is used.
+"org.freedesktop.Broadcast" is used.
.PP
-The name of the message to send must always be specified. Following
-arguments, if any, are the message contents (message arguments).
-These are given as a type name, a colon, and then the value of the
-argument. The possible type names are: string, int32, uint32, double,
-byte, boolean. (D-BUS supports more types than these, but
-\fIdbus-send\fP currently does not.)
+The object path and the name of the message to send must always be
+specified. Following arguments, if any, are the message contents
+(message arguments). These are given as a type name, a colon, and
+then the value of the argument. The possible type names are: string,
+int32, uint32, double, byte, boolean. (D-BUS supports more types than
+these, but \fIdbus-send\fP currently does not.)
.PP
Here is an example invocation:
.nf
- dbus-send \-\-dest='org.freedesktop.ExampleService' \\
- org.freedesktop.ExampleMessage \\
+ dbus-send \-\-dest='org.freedesktop.ExampleService' \\
+ /org/freedesktop/sample/object/name \\
+ org.freedesktop.ExampleInterface.ExampleMethod \\
int32:47 string:'hello world' double:65.32
.fi
+Note that the interface is separated from a method or signal
+name by a dot, though in the actual protocol the interface
+and the interface member are separate fields.
+
.SH OPTIONS
The following options are supported:
.TP
@@ -62,6 +68,9 @@ Send to the system message bus.
.TP
.I "--session"
Send to the session message bus. (This is the default.)
+.TP
+.I "--type=TYPE"
+Specify "method_call" or "signal" (defaults to "signal").
.SH AUTHOR
dbus-send was written by Philip Blundell.
diff --git a/tools/dbus-send.c b/tools/dbus-send.c
index 12ad5c8c..06a87adb 100644
--- a/tools/dbus-send.c
+++ b/tools/dbus-send.c
@@ -30,7 +30,7 @@
static void
usage (char *name, int ecode)
{
- fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=SERVICE] [--print-reply] <message type> [contents ...]\n", name);
+ fprintf (stderr, "Usage: %s [--help] [--system | --session] [--dest=SERVICE] [--type=TYPE] [--print-reply] <destination object path> <message name> [contents ...]\n", name);
exit (ecode);
}
@@ -44,10 +44,13 @@ main (int argc, char *argv[])
DBusMessageIter iter;
int i;
DBusBusType type = DBUS_BUS_SESSION;
- char *dest = DBUS_SERVICE_BROADCAST;
- char *name = NULL;
-
- if (argc < 2)
+ const char *dest = NULL;
+ const char *name = NULL;
+ const char *path = NULL;
+ int message_type = DBUS_MESSAGE_TYPE_SIGNAL;
+ const char *type_str = NULL;
+
+ if (argc < 3)
usage (argv[0], 1);
print_reply = FALSE;
@@ -64,17 +67,37 @@ main (int argc, char *argv[])
print_reply = TRUE;
else if (strstr (arg, "--dest=") == arg)
dest = strchr (arg, '=') + 1;
+ else if (strstr (arg, "--type=") == arg)
+ type_str = strchr (arg, '=') + 1;
else if (!strcmp(arg, "--help"))
usage (argv[0], 0);
else if (arg[0] == '-')
usage (argv[0], 1);
+ else if (path == NULL)
+ path = arg;
+ else if (name == NULL)
+ name = arg;
else
- name = arg;
+ usage (argv[0], 1);
}
if (name == NULL)
usage (argv[0], 1);
+ if (type_str != NULL)
+ {
+ if (strcmp (type_str, "method_call") == 0)
+ message_type = DBUS_MESSAGE_TYPE_METHOD_CALL;
+ else if (strcmp (type_str, "signal") == 0)
+ message_type = DBUS_MESSAGE_TYPE_SIGNAL;
+ else
+ {
+ fprintf (stderr, "Message type \"%s\" is not supported\n",
+ type_str);
+ exit (1);
+ }
+ }
+
dbus_error_init (&error);
connection = dbus_bus_get (type, &error);
if (connection == NULL)
@@ -86,13 +109,57 @@ main (int argc, char *argv[])
exit (1);
}
- message = dbus_message_new (name, dest);
+ if (message_type == DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ char *last_dot;
+
+ last_dot = strrchr (name, '.');
+ if (last_dot == NULL)
+ {
+ fprintf (stderr, "Must use org.mydomain.Interface.Method notation, no dot in \"%s\"\n",
+ name);
+ exit (1);
+ }
+ *last_dot = '\0';
+
+ message = dbus_message_new_method_call (NULL,
+ path,
+ name,
+ last_dot + 1);
+ }
+ else if (message_type == DBUS_MESSAGE_TYPE_SIGNAL)
+ {
+ char *last_dot;
+
+ last_dot = strrchr (name, '.');
+ if (last_dot == NULL)
+ {
+ fprintf (stderr, "Must use org.mydomain.Interface.Signal notation, no dot in \"%s\"\n",
+ name);
+ exit (1);
+ }
+ *last_dot = '\0';
+
+ message = dbus_message_new_signal (path, name, last_dot + 1);
+ }
+ else
+ {
+ fprintf (stderr, "Internal error, unknown message type\n");
+ exit (1);
+ }
+
if (message == NULL)
{
fprintf (stderr, "Couldn't allocate D-BUS message\n");
exit (1);
}
+ if (dest && !dbus_message_set_destination (message, dest))
+ {
+ fprintf (stderr, "Not enough memory\n");
+ exit (1);
+ }
+
dbus_message_append_iter_init (message, &iter);
while (i < argc)
@@ -135,6 +202,7 @@ main (int argc, char *argv[])
exit (1);
}
+ /* FIXME - we are ignoring OOM returns on all these functions */
switch (type)
{
case DBUS_TYPE_BYTE:
diff --git a/tools/dbus-tree-view.c b/tools/dbus-tree-view.c
new file mode 100644
index 00000000..863ad1e0
--- /dev/null
+++ b/tools/dbus-tree-view.c
@@ -0,0 +1,373 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-tree-view.c GtkTreeView for a D-BUS interface description
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <string.h>
+#include <config.h>
+#include "dbus-tree-view.h"
+
+#include <libintl.h>
+#define _(x) dgettext (GETTEXT_PACKAGE, x)
+#define N_(x) x
+
+enum
+{
+ MODEL_COLUMN_INFO,
+
+ MODEL_COLUMN_LAST
+};
+
+enum
+{
+ VIEW_COLUMN_NAME,
+
+ VIEW_COLUMN_LAST
+};
+
+/* We stuff the node tree into a GtkTreeStore, rather
+ * than bothering to write a custom model
+ */
+static GtkTreeModel*
+model_new (void)
+{
+ GtkTreeModel *model;
+ GtkTreeStore *store;
+
+ store = gtk_tree_store_new (MODEL_COLUMN_LAST,
+ G_TYPE_POINTER);
+ /* FIXME, BASE_INFO_TYPE doesn't work right (crashes),
+ * G_TYPE_POINTER has a memleak. BASE_INFO_TYPE problem maybe just a
+ * bad GTK build on my laptop.
+ */
+ /* BASE_INFO_TYPE); */
+
+ model = GTK_TREE_MODEL (store);
+
+ return model;
+}
+
+static void set_info (GtkTreeModel *model,
+ GtkTreeIter *root,
+ BaseInfo *info);
+
+static void
+append_child_list (GtkTreeModel *model,
+ GtkTreeIter *parent,
+ GSList *children)
+{
+ GSList *tmp;
+ GtkTreeStore *store;
+
+ store = GTK_TREE_STORE (model);
+
+ /* parent may be NULL for root */
+
+ tmp = children;
+ while (tmp != NULL)
+ {
+ GtkTreeIter iter;
+
+ gtk_tree_store_append (store, &iter, parent);
+
+ set_info (model, &iter, tmp->data);
+
+ tmp = tmp->next;
+ }
+}
+
+static void
+set_info (GtkTreeModel *model,
+ GtkTreeIter *root,
+ BaseInfo *info)
+{
+ GtkTreeStore *store;
+ GtkTreeIter child;
+
+ store = GTK_TREE_STORE (model);
+
+ /* Remeber that root is NULL for "/" path */
+
+ /* Clear existing children */
+ while (gtk_tree_model_iter_children (model, &child, root))
+ gtk_tree_store_remove (store, &child);
+
+ /* Set our new value; we simply discard NodeInfo for "/" at the
+ * moment.
+ */
+ if (root != NULL)
+ {
+ base_info_ref (info); /* FIXME once boxed types are working */
+ gtk_tree_store_set (store, root,
+ MODEL_COLUMN_INFO, info,
+ -1);
+ }
+
+ /* Fill in new children */
+ switch (base_info_get_type (info))
+ {
+ case INFO_TYPE_NODE:
+ append_child_list (model, root,
+ node_info_get_interfaces ((NodeInfo*)info));
+ append_child_list (model, root,
+ node_info_get_nodes ((NodeInfo*)info));
+ break;
+ case INFO_TYPE_INTERFACE:
+ append_child_list (model, root,
+ interface_info_get_methods ((InterfaceInfo*)info));
+ append_child_list (model, root,
+ interface_info_get_signals ((InterfaceInfo*)info));
+ break;
+ case INFO_TYPE_METHOD:
+ append_child_list (model, root,
+ method_info_get_args ((MethodInfo*)info));
+ break;
+ case INFO_TYPE_SIGNAL:
+ append_child_list (model, root,
+ signal_info_get_args ((SignalInfo*)info));
+ break;
+ case INFO_TYPE_ARG:
+ /* no children */
+ break;
+ }
+}
+
+static void
+ensure_tree_node (GtkTreeModel *model,
+ const char **path,
+ GtkTreeIter *iter)
+{
+ GtkTreeStore *store;
+ int i;
+ GtkTreeIter child;
+ GtkTreeIter *parent;
+ GtkTreeIter prev;
+
+ store = GTK_TREE_STORE (model);
+
+ /* The path[0] == NULL case for path "/" can't happen since no tree
+ * node is created for that
+ */
+ g_assert (path[0] != NULL);
+
+ parent = NULL;
+
+ i = 0;
+ while (path[i] != NULL)
+ {
+ gboolean found;
+
+ found = FALSE;
+
+ if (gtk_tree_model_iter_children (model, &child, parent))
+ {
+ /* Scan for the right path */
+ do
+ {
+ BaseInfo *info;
+
+ info = NULL;
+ gtk_tree_model_get (model, &child,
+ MODEL_COLUMN_INFO, &info,
+ -1);
+
+ if (info != NULL &&
+ base_info_get_type (info) == INFO_TYPE_NODE &&
+ strcmp (base_info_get_name (info), path[i]) == 0)
+ {
+ /* Found it */
+ found = TRUE;
+ break;
+ }
+ }
+ while (gtk_tree_model_iter_next (model, &child));
+ }
+
+ if (!found)
+ {
+ NodeInfo *node;
+
+ node = node_info_new (path[i]);
+
+ gtk_tree_store_append (store, &child, parent);
+ gtk_tree_store_set (store, &child,
+ MODEL_COLUMN_INFO, node,
+ -1);
+ }
+
+ prev = child;
+ parent = &prev;
+
+ ++i;
+ }
+
+ g_assert (parent == &prev);
+ *iter = prev;
+}
+
+static void
+model_update (GtkTreeModel *model,
+ const char **path,
+ NodeInfo *node)
+{
+ GtkTreeStore *store;
+
+ store = GTK_TREE_STORE (model);
+
+ if (path[0] == NULL)
+ {
+ /* Setting '/' */
+
+ set_info (model, NULL, (BaseInfo*) node);
+ }
+ else
+ {
+ GtkTreeIter iter;
+ BaseInfo *old;
+
+ /* Be sure we have the parent node */
+ ensure_tree_node (model, path, &iter);
+
+ /* Force the canonical relative path name on the node */
+ old = NULL;
+ gtk_tree_model_get (model, &iter,
+ MODEL_COLUMN_INFO, &old,
+ -1);
+ base_info_set_name ((BaseInfo*) node,
+ base_info_get_name (old));
+
+ /* Fill in the new children */
+ set_info (model, &iter, (BaseInfo*) node);
+ }
+}
+
+static void
+info_set_func_text (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ BaseInfo *info;
+ GString *str;
+
+ info = NULL;
+ gtk_tree_model_get (model, iter,
+ MODEL_COLUMN_INFO, &info,
+ -1);
+
+ if (info == NULL)
+ return;
+
+ str = g_string_new (NULL);
+
+ switch (base_info_get_type (info))
+ {
+ case INFO_TYPE_NODE:
+ g_string_append (str, "<i>path</i>");
+ break;
+ case INFO_TYPE_INTERFACE:
+ g_string_append (str, "<i>interface</i>");
+ break;
+ case INFO_TYPE_METHOD:
+ g_string_append (str, "<i>method</i>");
+ break;
+ case INFO_TYPE_SIGNAL:
+ g_string_append (str, "<i>signal</i>");
+ break;
+ case INFO_TYPE_ARG:
+ g_string_append (str, "<i>arg</i>");
+ break;
+ }
+
+ g_string_append (str, " ");
+ g_string_append (str, base_info_get_name (info));
+
+ g_object_set (GTK_CELL_RENDERER (cell),
+ "markup", str->str,
+ NULL);
+
+ g_string_free (str, TRUE);
+
+ /* base_info_unref (info); */
+}
+
+GtkWidget*
+dbus_tree_view_new (void)
+{
+ GtkWidget *treeview;
+ GtkCellRenderer *cell_renderer;
+ GtkTreeViewColumn *column;
+
+ treeview = gtk_tree_view_new ();
+
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_title (column, _("Name"));
+
+ cell_renderer = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (column,
+ cell_renderer,
+ TRUE);
+ gtk_tree_view_column_set_cell_data_func (column, cell_renderer,
+ info_set_func_text, NULL, NULL);
+
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview),
+ column);
+
+ return treeview;
+}
+
+void
+dbus_tree_view_update (GtkTreeView *view,
+ const char **path,
+ NodeInfo *node)
+{
+ GtkTreeModel *model;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (view));
+
+ model = gtk_tree_view_get_model (view);
+
+ if (model == NULL)
+ {
+ model = model_new ();
+ model_update (model, path, node);
+ gtk_tree_view_set_model (view, model);
+ g_object_unref (G_OBJECT (model));
+ }
+ else
+ {
+ model_update (model, path, node);
+ }
+}
+
+void
+dbus_tree_view_clear (GtkTreeView *view)
+{
+ GtkTreeModel *model;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (view));
+
+ model = gtk_tree_view_get_model (view);
+
+ if (model != NULL)
+ gtk_tree_store_clear (GTK_TREE_STORE (model));
+}
+
diff --git a/tools/dbus-tree-view.h b/tools/dbus-tree-view.h
new file mode 100644
index 00000000..3377ac88
--- /dev/null
+++ b/tools/dbus-tree-view.h
@@ -0,0 +1,36 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-tree-view.h GtkTreeView for a D-BUS interface description
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef DBUS_TREE_VIEW_H
+#define DBUS_TREE_VIEW_H
+
+#include <gtk/gtk.h>
+#include <glib/dbus-glib.h>
+#include <glib/dbus-gidl.h>
+
+GtkWidget* dbus_tree_view_new (void);
+void dbus_tree_view_update (GtkTreeView *view,
+ const char **path,
+ NodeInfo *info);
+void dbus_tree_view_clear (GtkTreeView *view);
+
+#endif /* DBUS_TREE_VIEW_H */
diff --git a/tools/dbus-viewer.c b/tools/dbus-viewer.c
new file mode 100644
index 00000000..561a65af
--- /dev/null
+++ b/tools/dbus-viewer.c
@@ -0,0 +1,320 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* dbus-viewer.c Graphical D-BUS frontend utility
+ *
+ * Copyright (C) 2003 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 1.2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <config.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include "dbus-tree-view.h"
+#include <glib/dbus-gparser.h>
+#include <glib/dbus-gutils.h>
+
+#include <libintl.h>
+#define _(x) dgettext (GETTEXT_PACKAGE, x)
+#define N_(x) x
+
+typedef struct
+{
+ int refcount;
+ char *name;
+
+} ServiceData;
+
+static ServiceData*
+service_data_new (const char *name)
+{
+ ServiceData *sd;
+
+ sd = g_new0 (ServiceData, 1);
+
+ sd->refcount = 1;
+ sd->name = g_strdup (name);
+
+ return sd;
+}
+
+static void
+service_data_ref (ServiceData *sd)
+{
+ sd->refcount += 1;
+}
+
+static void
+service_data_unref (ServiceData *sd)
+{
+ sd->refcount -= 1;
+ if (sd->refcount == 0)
+ {
+ g_free (sd->name);
+ g_free (sd);
+ }
+}
+
+typedef struct
+{
+ GtkWidget *window;
+ GtkWidget *treeview;
+ GtkWidget *service_menu;
+
+ GSList *services;
+
+} TreeWindow;
+
+static void
+window_closed_callback (GtkWidget *window,
+ TreeWindow *w)
+{
+ g_assert (window == w->window);
+ w->window = NULL;
+ gtk_main_quit ();
+}
+
+static TreeWindow*
+tree_window_new (void)
+{
+ TreeWindow *w;
+ GtkWidget *sw;
+ GtkWidget *vbox;
+ GtkWidget *hbox;
+
+ /* Should use glade, blah */
+
+ w = g_new0 (TreeWindow, 1);
+ w->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_title (GTK_WINDOW (w->window), "D-BUS Viewer");
+ gtk_window_set_default_size (GTK_WINDOW (w->window), 400, 500);
+
+ g_signal_connect (w->window, "destroy", G_CALLBACK (window_closed_callback),
+ w);
+ gtk_container_set_border_width (GTK_CONTAINER (w->window), 6);
+
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (w->window), vbox);
+
+ hbox = gtk_hbox_new (FALSE, 6);
+ gtk_container_add (GTK_CONTAINER (vbox), hbox);
+
+ /* Create tree view */
+
+ sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+
+ gtk_box_pack_start (GTK_BOX (hbox), sw, TRUE, TRUE, 0);
+
+ w->treeview = dbus_tree_view_new ();
+
+ gtk_container_add (GTK_CONTAINER (sw), w->treeview);
+
+ /* Create services option menu */
+
+
+
+ /* Show everything */
+ gtk_widget_show_all (w->window);
+
+ return w;
+}
+
+static void
+show_error_dialog (GtkWindow *transient_parent,
+ GtkWidget **weak_ptr,
+ const char *message_format,
+ ...)
+{
+ char *message;
+ va_list args;
+
+ if (message_format)
+ {
+ va_start (args, message_format);
+ message = g_strdup_vprintf (message_format, args);
+ va_end (args);
+ }
+ else
+ message = NULL;
+
+ if (weak_ptr == NULL || *weak_ptr == NULL)
+ {
+ GtkWidget *dialog;
+ dialog = gtk_message_dialog_new (transient_parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ message);
+
+ g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), NULL);
+
+ if (weak_ptr != NULL)
+ {
+ *weak_ptr = dialog;
+ g_object_add_weak_pointer (G_OBJECT (dialog), (void**)weak_ptr);
+ }
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+ gtk_widget_show_all (dialog);
+ }
+ else
+ {
+ g_return_if_fail (GTK_IS_MESSAGE_DIALOG (*weak_ptr));
+
+ gtk_label_set_text (GTK_LABEL (GTK_MESSAGE_DIALOG (*weak_ptr)->label), message);
+
+ gtk_window_present (GTK_WINDOW (*weak_ptr));
+ }
+}
+
+static void
+usage (int ecode)
+{
+ fprintf (stderr, "dbus-viewer [--version] [--help]\n");
+ exit (ecode);
+}
+
+static void
+version (void)
+{
+ printf ("D-BUS Message Bus Viewer %s\n"
+ "Copyright (C) 2003 Red Hat, Inc.\n"
+ "This is free software; see the source for copying conditions.\n"
+ "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
+ VERSION);
+ exit (0);
+}
+
+int
+main (int argc, char **argv)
+{
+ const char *prev_arg;
+ int i;
+ GSList *files;
+ gboolean end_of_args;
+ GSList *tmp;
+
+ bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ end_of_args = FALSE;
+ files = NULL;
+ prev_arg = NULL;
+ i = 1;
+ while (i < argc)
+ {
+ const char *arg = argv[i];
+
+ if (!end_of_args)
+ {
+ if (strcmp (arg, "--help") == 0 ||
+ strcmp (arg, "-h") == 0 ||
+ strcmp (arg, "-?") == 0)
+ usage (0);
+ else if (strcmp (arg, "--version") == 0)
+ version ();
+ else if (arg[0] == '-' &&
+ arg[1] == '-' &&
+ arg[2] == '\0')
+ end_of_args = TRUE;
+ else if (arg[0] == '-')
+ {
+ usage (1);
+ }
+ else
+ {
+ files = g_slist_prepend (files, (char*) arg);
+ }
+ }
+ else
+ files = g_slist_prepend (files, (char*) arg);
+
+ prev_arg = arg;
+
+ ++i;
+ }
+
+ files = g_slist_reverse (files);
+
+ tmp = files;
+ while (tmp != NULL)
+ {
+ NodeInfo *node;
+ GError *error;
+ const char *filename;
+
+ filename = tmp->data;
+
+ error = NULL;
+ node = description_load_from_file (filename,
+ &error);
+ if (node == NULL)
+ {
+ g_assert (error != NULL);
+ show_error_dialog (NULL, NULL,
+ _("Unable to load \"%s\": %s\n"),
+ filename, error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ TreeWindow *w;
+ char **path;
+ const char *name;
+
+ name = node_info_get_name (node);
+ if (name == NULL ||
+ name[0] != '/')
+ {
+ g_printerr (_("Assuming root node of \"%s\" is at path /, since no absolute path is specified"), filename);
+ name = "/";
+ }
+
+ path = _dbus_gutils_split_path (name);
+
+ w = tree_window_new ();
+ dbus_tree_view_update (GTK_TREE_VIEW (w->treeview),
+ (const char**) path,
+ node);
+ node_info_unref (node);
+
+ g_strfreev (path);
+ }
+
+ tmp = tmp->next;
+ }
+
+ gtk_main ();
+
+ return 0;
+}
+
+
+
+
+
+