2003-09-21 Seth Nickell <seth@gnome.org>
authorSeth Nickell <seth@gnome.org>
Mon, 22 Sep 2003 05:45:59 +0000 (05:45 +0000)
committerSeth Nickell <seth@gnome.org>
Mon, 22 Sep 2003 05:45:59 +0000 (05:45 +0000)
        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.

ChangeLog
Makefile.am
acinclude.m4
configure.in
python/.cvsignore [new file with mode: 0644]
python/Makefile.am [new file with mode: 0644]
python/dbus.py [new file with mode: 0644]
python/dbus_bindings.pyx.in [new file with mode: 0644]
python/dbus_h_wrapper.h [new file with mode: 0644]
python/extract.py [new file with mode: 0644]
test/test-service.c

index d0c88df..530c47c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+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
index 5bb5ae6..4732997 100644 (file)
@@ -16,8 +16,11 @@ if DBUS_USE_MCS
    MONO_SUBDIR=mono
 endif
 
+if HAVE_PYTHON
+   PYTHON_SUBDIR=python
+endif
 
-SUBDIRS=dbus bus doc $(GLIB_SUBDIR) $(GCJ_SUBDIR) $(MONO_SUBDIR) $(QT_SUBDIR) test 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)
index c80e0ac..27da0a4 100644 (file)
@@ -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"
+])
+
index e81a8d6..6cf4acc 100644 (file)
@@ -35,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])
@@ -834,6 +836,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([
@@ -846,6 +884,7 @@ bus/dbus-daemon-1.1
 Makefile
 dbus/Makefile
 glib/Makefile
+python/Makefile
 qt/Makefile
 gcj/Makefile
 gcj/org/Makefile
@@ -914,6 +953,7 @@ 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}
diff --git a/python/.cvsignore b/python/.cvsignore
new file mode 100644 (file)
index 0000000..8902bbe
--- /dev/null
@@ -0,0 +1,8 @@
+*.pyc
+*.pyo
+Makefile
+Makefile.in
+build
+*.la
+*.lo
+*.o
\ No newline at end of file
diff --git a/python/Makefile.am b/python/Makefile.am
new file mode 100644 (file)
index 0000000..792dc47
--- /dev/null
@@ -0,0 +1,28 @@
+INCLUDES=-I$(top_builddir) -I$(top_builddir)/glib $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) $(PYTHON_INCLUDES)
+
+dbusdir = $(pythondir)
+dbus_PYTHON = dbus.py
+
+dbusbindingsdir = $(pythondir)
+dbusbindings_LTLIBRARIES = dbus_bindings.la
+
+dbus_bindings_la_LDFLAGS = -module -avoid-version -fPIC -export-symbols-regex initdbus_bindings
+dbus_bindings_la_LIBADD = $(top_builddir)/dbus/libdbus-1.la $(top_builddir)/glib/libdbus-glib-1.la
+dbus_bindings_la_SOURCES = dbus_bindings.c
+
+EXTRA_DIST =                   \
+       dbus_bindings.pyx.in    \
+       extract.py              \
+       setup.py                \
+       test.py
+
+CLEANFILES =                   \
+       dbus_bindings.pyx       \
+       dbus_bindings.c
+
+
+dbus_bindings.pyx: dbus_bindings.pyx.in extract.py
+       -$(PYTHON) extract.py dbus_bindings.pyx.in -I$(top_builddir)  > dbus_bindings.pyx
+
+dbus_bindings.c: dbus_bindings.pyx
+       -pyrexc dbus_bindings.pyx
diff --git a/python/dbus.py b/python/dbus.py
new file mode 100644 (file)
index 0000000..a7cca56
--- /dev/null
@@ -0,0 +1,196 @@
+
+"""Module for high-level communication over the FreeDesktop.org Bus (DBus)
+
+DBus allows you to share and access remote objects between processes
+running on the desktop, and also to access system services (such as
+the print spool).
+
+To use DBus, first get a Bus object, which provides a connection to one
+of a few standard dbus-daemon instances that might be running. From the
+Bus you can get a RemoteService. A service is provided by an application or
+process connected to the Bus, and represents a set of objects. Once you
+have a RemoteService you can get a RemoteObject that implements a specific interface
+(an interface is just a standard group of member functions). Then you can call
+those member functions directly.
+
+You can think of a complete method call as looking something like:
+
+Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org')
+
+This communicates over the SESSION Bus to the org.gnome.Evolution process to call the
+Forward method of the /org/gnome/Evolution/Inbox object (which provides the
+org.gnome.Evolution.MailFolder interface) with two string arguments.
+
+For example, the dbus-daemon itself provides a service and some objects:
+
+# Get a connection to the desktop-wide SESSION bus
+bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
+
+# Get the service provided by the dbus-daemon named org.freedesktop.DBus
+dbus_service = bus.get_service('org.freedesktop.DBus')
+
+# Get a reference to the desktop bus' standard object, denoted
+# by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus
+# implements the 'org.freedesktop.DBus' interface
+dbus_object = dbus_service.get_object('/org/freedesktop/DBus',
+                                       'org.freedesktop.DBus')
+
+# One of the member functions in the org.freedesktop.DBus interface
+# is ListServices(), which provides a list of all the other services
+# registered on this bus. Call it, and print the list.
+print(dbus_object.ListServices())
+"""
+
+import dbus_bindings
+
+class Bus:
+    """A connection to a DBus daemon.
+
+    One of three possible standard buses, the SESSION, SYSTEM,
+    or ACTIVATION bus
+    """
+    TYPE_SESSION    = dbus_bindings.BUS_SESSION
+    TYPE_SYSTEM     = dbus_bindings.BUS_SYSTEM
+    TYPE_ACTIVATION = dbus_bindings.BUS_ACTIVATION
+
+    def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True):
+        self._connection = dbus_bindings.bus_get(bus_type)
+
+        if (glib_mainloop):
+            self._connection.setup_with_g_main()
+
+    def get_service(self, service_name="org.freedesktop.Broadcast"):
+        """Get one of the RemoteServices connected to this Bus. service_name
+        is just a string of the form 'com.widgetcorp.MyService'
+        """
+        return RemoteService(self._connection, service_name)
+
+    def get_connection(self):
+        """Get the dbus_bindings.Connection object associated with this Bus"""
+        return self._connection
+
+
+class RemoteObject:
+    """A remote Object.
+
+    A RemoteObject is provided by a RemoteService on a particular Bus. RemoteObjects
+    have member functions, and can be called like normal Python objects.
+    """
+    def __init__(self, connection, service_name, object_path, interface):
+        self._connection   = connection
+        self._service_name = service_name
+        self._object_path  = object_path
+        self._interface    = interface
+
+    def __getattr__(self, member):
+        if member == '__call__':
+            return object.__call__
+        else:
+            return RemoteMethod(self._connection, self._service_name,
+                                self._object_path, self._interface, member)
+
+
+class RemoteMethod:
+    """A remote Method.
+
+    Typically a member of a RemoteObject. Calls to the
+    method produce messages that travel over the Bus and are routed
+    to a specific Service.
+    """
+    def __init__(self, connection, service_name, object_path, interface, method_name):
+        self._connection   = connection
+        self._service_name = service_name
+        self._object_path  = object_path
+        self._interface    = interface
+        self._method_name  = method_name
+
+    def __call__(self, *args):
+        print ("Going to call object(%s).interface(%s).method(%s)"
+               % (self._object_path, self._interface, self._method_name))
+
+        message = dbus_bindings.MethodCall(self._object_path, self._interface, self._method_name)
+        message.set_destination(self._service_name)
+        
+        # Add the arguments to the function
+        iter = message.get_iter()
+        for arg in args:
+            print ("Adding arg %s" % (arg))
+            print ("Append success is %d" % (iter.append(arg)))
+            print ("Args now %s" % (message.get_args_list()))            
+
+        reply_message = self._connection.send_with_reply_and_block(message, 5000)
+
+        args_tuple = reply_message.get_args_list()
+        if (len(args_tuple) == 0):
+            return
+        elif (len(args_tuple) == 1):
+            return args_tuple[0]
+        else:
+            return args_tuple
+
+class Service:
+    """A base class for exporting your own Services across the Bus
+
+    Just inherit from Service, providing the name of your service
+    (e.g. org.designfu.SampleService).
+    """
+    def __init__(self, service_name, bus=None):
+        self._service_name = service_name
+                             
+        if bus == None:
+            # Get the default bus
+            self._bus = Bus()
+        else:
+            self._bus = bus
+
+        dbus_bindings.bus_acquire_service(self._bus.get_connection(), service_name)
+
+    def get_bus(self):
+        """Get the Bus this Service is on"""
+        return self._bus
+
+class Object:
+    """A base class for exporting your own Objects across the Bus.
+
+    Just inherit from Object and provide a list of methods to share
+    across the Bus. These will appear as member functions of your
+    ServiceObject.
+    """
+    def __init__(self, object_path, methods_to_share, service):
+        self._object_path = object_path
+        self._service = service
+        self._object_methods = methods_to_share
+        self._bus = service.get_bus()
+        self._connection = self._bus.get_connection()
+        
+        self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb)
+
+    def _unregister_cb(self, connection):
+        print ("Unregister")
+        
+    def message_cb(self, connection, message):
+        print ("Message %s received" % (message))
+        print ("MethodCall %s" % (message.get_member()))
+        
+class RemoteService:
+    """A remote service providing objects.
+
+    A service is typically a process or application that provides
+    remote objects, but can also be the broadcast service that
+    receives signals from all applications on the Bus.
+    """
+    
+    def __init__(self, connection, service_name):
+        self._connection     = connection
+        self._service_name   = service_name
+
+    def get_object(self, object_path, interface):
+        """Get an object provided by this Service that implements a
+        particular interface. object_path is a string of the form
+        '/com/widgetcorp/MyService/MyObject1'. interface looks a lot
+        like a service_name (they're often the same) and is of the form,
+        'com.widgetcorp.MyInterface', and mostly just defines the
+        set of member functions that will be present in the object.
+        """
+        return RemoteObject(self._connection, self._service_name, object_path, interface)
+                             
diff --git a/python/dbus_bindings.pyx.in b/python/dbus_bindings.pyx.in
new file mode 100644 (file)
index 0000000..2e575ed
--- /dev/null
@@ -0,0 +1,900 @@
+# -*- Mode: Python -*-
+
+#include "dbus_h_wrapper.h"
+
+cdef extern from "stdlib.h":
+    cdef void *malloc(size_t size)
+    cdef void free(void *ptr)
+
+cdef extern from "dbus-glib.h":
+    ctypedef struct GMainContext
+    cdef void dbus_connection_setup_with_g_main (DBusConnection *connection,
+                                                 GMainContext   *context)
+    cdef void dbus_server_setup_with_g_main     (DBusServer     *server,
+                                                 GMainContext   *context)
+
+cdef extern from "Python.h":
+    void Py_XINCREF (object)
+    void Py_XDECREF (object)
+
+
+ctypedef struct DBusError:
+    char *name
+    char *message
+    unsigned int dummy1 
+    unsigned int dummy2
+    unsigned int dummy3
+    unsigned int dummy4
+    unsigned int dummy5
+    void *padding1
+    
+ctypedef 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
+
+ctypedef struct DBusObjectPathVTable:
+  DBusObjectPathUnregisterFunction   unregister_function
+  DBusObjectPathMessageFunction      message_function
+  void (* dbus_internal_pad1) (void *)
+  void (* dbus_internal_pad2) (void *)
+  void (* dbus_internal_pad3) (void *)
+  void (* dbus_internal_pad4) (void *)
+
+
+class DBusException(Exception):
+    pass
+
+class ConnectionError(Exception):
+    pass
+
+cdef void cunregister_function_handler (DBusConnection *connection,
+                                        void *user_data):
+    print ("cunregister_function_handler() called")
+    tup = <object>user_data
+    function = tup[0]
+    args = [Connection(_conn=<object>connection)]
+    function(*args)
+
+cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection,
+                                                  DBusMessage *msg,
+                                                  void *user_data):
+    print ("cmessage_function_handler() called")
+    tup = <object>user_data
+    print (tup)
+    function = tup[1]
+    message = Message(_create=0)
+    message._set_msg(<object>msg)
+    args = [Connection(_conn=<object>connection),
+            message]
+    retval = function(*args)
+    if (retval == None):
+        retval = DBUS_HANDLER_RESULT_HANDLED
+    return retval
+
+cdef DBusHandlerResult chandle_message_function_handler (DBusConnection *connection,
+                                                        DBusMessage *msg,
+                                                        void *user_data):
+    function = <object>user_data
+    messagein = Message(_create=0)
+    messagein._set_msg(<object>msg)
+    args = [Connection(_conn=<object>connection),
+            messagein]
+    retval = function(*args)
+    if (retval == None):
+        retval = DBUS_HANDLER_RESULT_HANDLED
+    return retval    
+
+cdef class Connection:
+    cdef DBusConnection *conn
+    
+    # FIXME: this is a major major hack. We use this because casting values to
+    # python objects and returning seemed to be corrupting them. This is a "global variable" :-(
+    cdef char **_parsed_path
+    
+    def __init__(self, address=None, _conn=None):
+        cdef DBusError error
+        dbus_error_init(&error)
+        if <DBusConnection*>_conn != NULL:
+            self.conn = <DBusConnection*>_conn
+            dbus_connection_ref(self.conn)
+        else:
+            self.conn = dbus_connection_open(address,
+                                             &error)
+            if dbus_error_is_set(&error):
+                raise DBusException, error.message
+            
+        dbus_connection_ref(self.conn)
+
+    def _set_conn(self, conn):
+        self.conn = <DBusConnection*>conn
+        
+    def _get_conn(self):
+        return <object>self.conn
+    
+    #FIXME: this is totally busted, don't use a class shared member like parsed_path
+    def _build_parsed_path(self, path_element_list):
+        cdef char **cpatharray        
+        size = len(path_element_list)
+        cpatharray = <char **>malloc(sizeof(char*) * (size + 1))
+
+        for i in range(size):
+            path_element = path_element_list[i]
+            cpatharray[i] = path_element
+            
+        cpatharray[size] = NULL
+
+        self._parsed_path = cpatharray
+
+    def get_base_service(self):
+        return bus_get_base_service(self)
+
+    def setup_with_g_main(self):
+        dbus_connection_setup_with_g_main(self.conn, NULL)
+
+    def disconnect(self):
+        dbus_connection_disconnect(self.conn)
+
+    def get_is_connected(self):
+        return dbus_connection_get_is_connected(self.conn)
+    
+    def get_is_authenticated(self):
+        return dbus_connection_get_is_authenticated(self.conn)
+
+    def flush(self):
+        dbus_connection_flush(self.conn)
+
+    def borrow_message(self):
+        m = Message(_create=0)
+        m._set_msg(<object>dbus_connection_borrow_message(self.conn))
+        return m
+    
+    def return_message(self, message):
+        msg = message._get_msg()
+        dbus_connection_return_message(self.conn, <DBusMessage*>msg)
+
+    def steal_borrowed_message(self, message):
+        msg = message._get_msg()
+        dbus_connection_steal_borrowed_message(self.conn,
+                                               <DBusMessage*>msg)
+    
+    def pop_message(self):
+        cdef DBusMessage *msg
+        msg = dbus_connection_pop_message(self.conn)
+        if msg != NULL:
+            m = Message(_create=0)
+            m._set_msg(<object>msg)
+        else:
+            m = None
+        return m        
+
+    def get_dispatch_status(self):
+        return dbus_connection_get_dispatch_status(self.conn)
+    
+    def dispatch(self):
+        return dbus_connection_dispatch(self.conn)
+
+    def send(self, message):
+        #cdef dbus_uint32_t client_serial
+        #if type(message) != Message:
+        #    raise TypeError
+        
+        msg = message._get_msg()
+        retval = dbus_connection_send(self.conn,
+                                      <DBusMessage*>msg,
+                                      NULL)
+        return retval
+
+    def send_with_reply(self, message, timeout_milliseconds):
+        cdef dbus_bool_t retval
+        cdef DBusPendingCall *cpending_call
+        cdef DBusError error
+        dbus_error_init(&error)
+
+        cpending_call = NULL
+        
+        msg = message._get_msg()
+
+        retval = dbus_connection_send_with_reply(self.conn,
+                                                 <DBusMessage*>msg,
+                                                 &cpending_call,
+                                                 timeout_milliseconds)
+
+        if dbus_error_is_set(&error):
+            raise DBusException, error.message
+
+        if (cpending_call != NULL):
+            pending_call = PendingCall(<object>cpending_call)
+        else:
+            pending_call = None
+
+        return (retval, pending_call)
+                                
+    def send_with_reply_and_block(self, message,
+                                  timeout_milliseconds=0):
+        cdef DBusMessage * retval
+        cdef DBusError error
+        dbus_error_init(&error)
+
+        msg = message._get_msg()
+
+        print ("About to block")
+
+        retval = dbus_connection_send_with_reply_and_block(
+            <DBusConnection*>self.conn,
+            <DBusMessage*>msg,
+            <int>timeout_milliseconds,
+            &error)
+
+        print ("done")
+
+        if dbus_error_is_set(&error):
+            raise DBusException, error.message
+
+        if retval == NULL:
+            raise AssertionError
+        
+        m = Message(_create=0)
+        m._set_msg(<object>retval)
+        return m
+
+    def set_watch_functions(self, add_function, remove_function, data):
+        pass
+
+    def set_timeout_functions(self, add_function, remove_function, data):
+        pass
+
+    def set_wakeup_main_function(self, wakeup_main_function, data):
+        pass
+
+    # FIXME: set_dispatch_status_function, get_unix_user, set_unix_user_function
+
+    def add_filter(self, function):
+        return dbus_connection_add_filter(self.conn,
+                                          chandle_message_function_handler,
+                                          <void*>function,
+                                          NULL)
+
+
+    #FIXME: remove_filter
+    #       this is pretty tricky, we want to only remove the filter
+    #       if we truly have no more calls to our message_function_handler...ugh
+
+    def set_data(self, slot, data):
+        pass
+
+    def get_data(self, slot):
+        pass
+
+    def set_max_message_size(self, size):
+        dbus_connection_set_max_message_size(self.conn, size)
+
+    def get_max_message_size(self):
+        return dbus_connection_get_max_message_size(self.conn)
+
+    def set_max_received_size(self, size):
+        dbus_connection_set_max_received_size(self.conn, size)
+
+    def get_max_received_size(self):
+        return dbus_connection_get_max_received_size(self.conn)
+
+    def get_outgoing_size(self):
+        return dbus_connection_get_outgoing_size(self.conn)    
+
+    # preallocate_send, free_preallocated_send, send_preallocated
+
+    def register_object_path(self, path, unregister_cb, message_cb):
+        cdef DBusObjectPathVTable cvtable
+        
+        cvtable.unregister_function = cunregister_function_handler 
+        cvtable.message_function    = cmessage_function_handler
+
+        user_data = [unregister_cb, message_cb]
+        #Py_XINCREF(user_data)
+        
+        path_element_list = path[1:].split('/')
+        self._build_parsed_path(path_element_list)
+        
+        return dbus_connection_register_object_path(self.conn, self._parsed_path, &cvtable,
+                                                    <void*>user_data) 
+
+    def register_fallback(self, path, unregister_cb, message_cb):
+        cdef DBusObjectPathVTable cvtable
+
+        cvtable.unregister_function = cunregister_function_handler 
+        cvtable.message_function    = cmessage_function_handler
+
+        user_data = [unregister_cb, message_cb]
+        Py_XINCREF(user_data)
+
+        print ("Ref inced")
+        
+        path_element_list = path[1:].split('/')
+        self._build_parsed_path(path_element_list)
+        
+        return dbus_connection_register_fallback(self.conn, self._parsed_path, &cvtable,
+                                                 <void*>user_data) 
+
+    #FIXME: unregister_object_path , see problems with remove_filter
+
+    def list_registered (self, parent_path):
+        cdef char **cchild_entries
+        cdef dbus_bool_t retval
+        
+        path_element_list = parent_path[1:].split('/')
+        self._build_parsed_path(path_element_list)
+        
+        retval = dbus_connection_list_registered(self.conn, self._parsed_path, &cchild_entries)
+
+        if (not retval):
+            #FIXME: raise out of memory exception?
+            return None
+
+        i = 0
+        child_entries = []
+        print ("cchild_entries[0] is %d" % (<int>cchild_entries[0]))
+        while (cchild_entries[i] != NULL):
+            child_entries.append(cchild_entries[i])
+            i = i + 1
+
+        dbus_free_string_array(cchild_entries)
+
+        return child_entries
+
+    
+cdef class PendingCall:
+    cdef DBusPendingCall *pending_call
+
+    def __init__(self, _pending_call):
+        self.pending_call = <DBusPendingCall*>_pending_call
+        dbus_pending_call_ref(self.pending_call)
+        
+    def _get_pending_call(self):
+        return <object>self.pending_call
+
+    def cancel(self):
+        dbus_pending_call_cancel(self.pending_call)
+
+    def get_completed(self):
+        return dbus_pending_call_get_completed(self.pending_call)
+
+    def get_reply(self):
+        message = Message(_create=0)
+        message._set_msg(<object>dbus_pending_call_get_reply(self.pending_call))
+        return message
+
+    def block(self):
+        dbus_pending_call_block(self.pending_call)
+
+cdef class Watch:
+    cdef DBusWatch* watch
+    def __init__(self, cwatch):
+        self.watch = <DBusWatch*>cwatch
+
+    def get_fd(self):
+        return dbus_watch_get_fd(self.watch)
+
+    # FIXME: not picked up correctly by extract.py
+    #def get_flags(self):
+    #    return dbus_watch_get_flags(self.watch)
+
+    def handle(self, flags):
+        return dbus_watch_handle(self.watch, flags)
+
+    def get_enabled(self):
+        return dbus_watch_get_enabled(self.watch)
+    
+cdef class MessageIter:
+    cdef DBusMessageIter *iter
+    cdef DBusMessageIter real_iter
+
+
+    def __init__(self, message):
+        self.iter = &self.real_iter
+        msg = message._get_msg()
+        dbus_message_iter_init(<DBusMessage*>msg, self.iter)
+    
+    def get_iter(self):
+        return <object>self.iter
+
+    def has_next(self):
+        return dbus_message_iter_has_next(self.iter)
+    
+    def next(self):
+        return dbus_message_iter_next(self.iter)
+
+    def get(self):
+        arg_type = self.get_arg_type()
+
+        if arg_type == TYPE_INVALID:
+            raise TypeError, 'Invalid arg type in MessageIter'
+        elif arg_type == TYPE_STRING:
+            retval = self.get_string()
+        elif arg_type == TYPE_INT32:
+            retval = self.get_int32()
+        elif arg_type == TYPE_UINT32:
+            retval = self.get_uint32()
+        elif arg_type == TYPE_DOUBLE:
+            retval = self.get_double()
+        elif arg_type == TYPE_BYTE:
+            retval = self.get_byte()
+        elif arg_type == TYPE_BOOLEAN:
+            retval = self.get_boolean()
+        elif arg_type == TYPE_ARRAY:
+            array_type = self.get_array_type()
+
+            if array_type == TYPE_STRING:
+                retval = self.get_string_array()
+            elif array_type == TYPE_BOOLEAN:
+                retval = self.get_boolean_array()
+            else:
+                raise TypeError, "Unknown array type %d in MessageIter" % (array_type)
+        else:
+            raise TypeError, 'Unknown arg type %d in MessageIter' % (argtype)
+
+        return retval
+    
+    def get_arg_type(self):
+        return dbus_message_iter_get_arg_type(self.iter)
+
+    def get_array_type(self):
+        return dbus_message_iter_get_array_type(self.iter)
+
+    #FIXME: implement get_byte
+    #def get_byte(self):
+    #    return dbus_message_iter_get_byte(self.iter)
+
+    def get_boolean(self):
+        return dbus_message_iter_get_boolean(self.iter)
+    
+    def get_int32(self):
+        return dbus_message_iter_get_int32(self.iter)
+
+    def get_uint32(self):
+        return dbus_message_iter_get_uint32(self.iter)
+
+    def get_double(self):
+        return dbus_message_iter_get_double(self.iter)
+
+    def get_string(self):
+        return dbus_message_iter_get_string(self.iter)
+
+    def get_dict_key(self):
+        return dbus_message_iter_get_dict_key(self.iter)
+
+    # FIXME: implement dbus_message_iter_get_named
+    #                  dbus_message_iter_init_array_iterator
+    
+    def get_byte_array(self):
+        cdef int len
+        cdef unsigned char *retval
+        dbus_message_iter_get_byte_array(self.iter, &retval, <int*>&len)
+        list = []
+        for i from 0 <= i < len:
+            list.append(chr(retval[i]))
+        return list
+
+    # FIXME: implement dbus_message_iter_get_boolean_array
+    #                  dbus_message_iter_get_int32_array
+    #                  dbus_message_iter_get_uint32_array
+    #                  dbus_message_iter_get_double_array
+
+    def get_string_array(self):
+        cdef int len
+        cdef char **retval
+        
+        dbus_message_iter_get_string_array(self.iter, &retval, <int*>&len)
+        list = []
+        for i from 0 <= i < len:
+            list.append(retval[i])
+        return list
+
+    # dbus_message_append_iter_init included in class Message
+
+    #FIXME: handle all the different types?
+    def append(self, value):
+        value_type = type(value)
+
+        if value_type == bool:
+            retval = self.append_boolean(value)
+        elif value_type == int:
+            retval = self.append_int32(value)
+        elif value_type == float:
+            retval = self.append_double(value)
+        elif value_type == str:
+            retval = self.append_string(value)
+        elif value_type == list:
+            if (len(list) == 1):
+                raise TypeError, "Empty list"
+            list_type = type(list[0])
+            if list_type == str:
+                self.append_string_array(list)
+            else:
+                raise TypeError, "List of unknown type '%s'" % (list_type)
+        else:
+            raise TypeError, "Argument of unknown type '%s'" % (value_type)
+
+        return retval
+
+    def append_nil(self):
+        return dbus_message_iter_append_nil(self.iter)
+    
+    def append_boolean(self, value):
+        return dbus_message_iter_append_boolean(self.iter, value)
+
+    def append_byte(self, value):
+        return dbus_message_iter_append_byte(self.iter, value)
+    
+    def append_int32(self, value):
+        return dbus_message_iter_append_int32(self.iter, value)
+
+    def append_uint32(self, value):
+        return dbus_message_iter_append_uint32(self.iter, value)
+
+    def append_double(self, value):
+        return dbus_message_iter_append_double(self.iter, value)
+
+    def append_string(self, value):
+        return dbus_message_iter_append_string(self.iter, value)    
+
+    # FIXME: dbus_message_iter_append_named
+
+    def append_dict_key(self, value):
+        return dbus_message_iter_append_dict_key(self.iter, value)
+
+    # FIXME: append_array, append_dict_array, append_boolean_array, append_int32_array, append_uint32_array, append_double_array
+
+    def append_byte_array(self, list):
+        cdef unsigned char * value
+        cdef int length
+        length = len(list)
+        value = <unsigned char*>malloc(length)
+        for i from 0 <= i < length:
+            item = list[i]
+            if type(item) != str or len(item) != 1:
+                raise TypeError
+            value[i] = ord(item)
+        return dbus_message_iter_append_byte_array(self.iter, value, length)
+    
+    def append_string_array(self, list):
+        cdef char **value
+        cdef int length
+        length = len(list)
+        value = <char**>malloc(length)
+        for i from 0 <= i < length:
+            item = list[i]
+            if type(item) != str:
+                raise TypeError
+            value[i] = item
+        return dbus_message_iter_append_string_array(self.iter, value, length)
+
+    
+(MESSAGE_TYPE_INVALID, MESSAGE_TYPE_METHOD_CALL, MESSAGE_TYPE_METHOD_RETURN, MESSAGE_TYPE_ERROR, MESSAGE_TYPE_SIGNAL) = range(5)
+(TYPE_INVALID, TYPE_NIL, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_NAMED, TYPE_ARRAY, TYPE_DICT, TYPE_OBJECT_PATH) = range(14)
+    
+cdef class Message:
+    cdef DBusMessage *msg
+
+    def __init__(self, message_type=MESSAGE_TYPE_INVALID, service=None, path=None, interface=None,
+                 method=None, name=None, reply_to=None, error_name=None, error_message=None,
+                 _create=1):
+        cdef char *cservice
+        if (service == None):
+            cservice = NULL
+        else:
+            cservice = service
+            
+        if not _create:
+            return 0
+
+        if message_type == MESSAGE_TYPE_METHOD_CALL:
+            self.msg = dbus_message_new_method_call(cservice, path, interface, method)
+        elif message_type == MESSAGE_TYPE_METHOD_RETURN:
+            msg = method_call._get_msg()
+            self.msg = dbus_message_new_method_return(<DBusMessage*>msg)
+        elif message_type == MESSAGE_TYPE_SIGNAL:
+            self.msg = dbus_message_new_signal(path, interface, name)
+        elif message_type == MESSAGE_TYPE_ERROR:
+            msg = reply_to._get_msg()
+            self.msg = dbus_message_new_error(<DBusMessage*>msg, error_name, error_message)
+            
+    def type_to_name(self, type):
+        if type == MESSAGE_TYPE_SIGNAL:
+            return "signal"
+        elif type == MESSAGE_TYPE_METHOD_CALL:
+            return "method call"
+        elif type == MESSAGE_TYPE_METHOD_RETURN:
+            return "method return"
+        elif type == MESSAGE_TYPE_ERROR:
+            return "error"
+        else:
+            return "(unknown message type)"
+        
+    def __str__(self):
+        message_type = self.get_type()
+        sender = self.get_sender()
+
+        if sender == None:
+            sender = "(no sender)"
+
+        if (message_type == MESSAGE_TYPE_METHOD_CALL) or (message_type == MESSAGE_TYPE_SIGNAL):
+            retval = '%s interface=%s; member=%s; sender=%s' % (self.type_to_name(message_type),
+                                                                self.get_interface(),
+                                                                self.get_member(),
+                                                                sender)
+        elif message_type == MESSAGE_TYPE_METHOD_RETURN:
+            retval = '%s sender=%s' % (self.type_to_name(message_type),
+                                        sender)
+        elif message_type == MESSAGE_TYPE_ERROR:
+            retval = '%s name=%s; sender=%s' % (self.type_to_name(message_type),
+                                                self.get_error_name(),
+                                                sender)
+        else:
+            retval = "Message of unknown type %d" % (message_type)
+
+
+        # FIXME: should really use self.convert_to_tuple() here
+        
+        iter = self.get_iter()
+        value_at_iter = True
+        
+        while (value_at_iter):
+            type = iter.get_arg_type()
+
+            if type == TYPE_INVALID:
+                break
+            elif type == TYPE_STRING:
+                str = iter.get_string()
+                arg = 'string:%s\n' % (str)
+            elif type == TYPE_INT32:
+                num = iter.get_int32()
+                arg = 'int32:%d\n' % (num)
+            elif type == TYPE_UINT32:
+                num = iter.get_uint32()
+                arg = 'uint32:%u\n' % (num)
+            elif type == TYPE_DOUBLE:
+                num = iter.get_double()
+                arg = 'double:%f\n' % (num)
+            elif type == TYPE_BYTE:
+                num = iter.get_byte()
+                arg = 'byte:%d\n' % (num)
+            elif type == TYPE_BOOLEAN:
+                bool = iter.get_boolean()
+                if (bool):
+                    str = "true"
+                else:
+                    str = "false"
+                arg = 'boolean:%s\n' % (str)
+            else:
+                arg = '(unknown arg type %d)\n' % type
+
+            retval = retval + arg
+            value_at_iter = iter.next()
+
+        return retval
+    
+    def _set_msg(self, msg):
+        self.msg = <DBusMessage*>msg
+
+    def _get_msg(self):
+        return <object>self.msg
+
+    def get_iter(self):
+        return MessageIter(self)
+
+    def get_args_list(self):
+        retval = [ ]
+
+        iter = self.get_iter()
+        try:
+            retval.append(iter.get())
+        except TypeError, e:
+            return [ ]
+            
+        value_at_iter = iter.next()
+        while (value_at_iter):
+            retval.append(iter.get())
+            value_at_iter = iter.next()        
+
+        return retval
+            
+    # FIXME: implement dbus_message_copy?
+
+    def get_type(self):
+        return dbus_message_get_type(self.msg)
+
+    def set_path(self, object_path):
+        return dbus_message_set_path(self.msg, object_path)
+    
+    def get_path(self):
+        return dbus_message_get_path(self.msg)
+    
+    def set_interface(self, interface):
+        return dbus_message_set_interface(self.msg, interface)
+
+    def get_interface(self):
+        return dbus_message_get_interface(self.msg)    
+
+    def set_member(self, member):
+        return dbus_message_set_member(self.msg, member)
+
+    def get_member(self):
+        return dbus_message_get_member(self.msg)
+
+    def set_error_name(self, name):
+        return dbus_message_set_error_name(self.msg, name)
+
+    def get_error_name(self):
+        return dbus_message_get_error_name(self.msg)
+
+    def set_destination(self, destination):
+        return dbus_message_set_destination(self.msg, destination)
+
+    def get_destination(self):
+        return dbus_message_get_destination(self.msg)
+
+    def set_sender(self, sender):
+        return dbus_message_set_sender(self.msg, sender)
+    
+    def get_sender(self):
+        cdef char *sender
+        sender = dbus_message_get_sender(self.msg)
+        if (sender == NULL):
+            return None
+        else:
+            return sender
+
+    def set_no_reply(self, no_reply):
+        dbus_message_set_no_reply(self.msg, no_reply)
+
+    def get_no_reply(self):
+        return dbus_message_get_no_reply(self.msg)
+
+    def is_method_call(self, interface, method):
+        return dbus_message_is_method_call(self.msg, interface, method)
+
+    def is_signal(self, interface, signal_name):
+        return dbus_message_is_signal(self.msg, interface, signal_name)
+
+    def is_error(self, error_name):
+        return dbus_message_is_error(self.msg, error_name)
+
+    def has_destination(self, service):
+        return dbus_message_has_destination(self.msg, service)
+
+    def has_sender(self, service):
+        return dbus_message_has_sender(self.msg, service)
+
+    def get_serial(self):
+        return dbus_message_get_serial(self.msg)
+
+    def set_reply_serial(self, reply_serial):
+        return dbus_message_set_reply_serial(self.msg, reply_serial)
+
+    def get_reply_serial(self):
+        return dbus_message_get_reply_serial(self.msg)    
+
+    #FIXME: dbus_message_get_path_decomposed
+    
+    # FIXME: all the different dbus_message_*args* methods
+
+class Signal(Message):
+    def __init__(self, spath, sinterface, sname):
+        Message.__init__(self, MESSAGE_TYPE_SIGNAL, path=spath, interface=sinterface, name=sname)
+
+class MethodCall(Message):
+    def __init__(self, mpath, minterface, mmethod):
+        Message.__init__(self, MESSAGE_TYPE_METHOD_CALL, path=mpath, interface=minterface, method=mmethod)
+
+cdef class Server:
+    cdef DBusServer *server
+    def __init__(self, address):
+        cdef DBusError error
+        dbus_error_init(&error)
+        self.server = dbus_server_listen(address,
+                                         &error)
+        if dbus_error_is_set(&error):
+            raise DBusException, error.message
+
+    def setup_with_g_main (self):
+        dbus_server_setup_with_g_main(self.server, NULL)
+
+    def disconnect(self):
+        dbus_server_disconnect(self.server)
+
+    def get_is_connected(self):
+        return dbus_server_get_is_connected(self.server)
+
+#    def set_new_connection_function(self, function, data):
+#        dbus_server_set_new_connection_function(self.conn, function,
+#                                                data, NULL)
+        
+#    def set_watch_functions(self, add_function, remove_function, data):
+#        dbus_server_set_watch_functions(self.server,
+#                                        add_function, remove_function,
+#                                        data, NULL)
+        
+#    def set_timeout_functions(self, add_function, remove_function, data):
+#        dbus_server_set_timeout_functions(self.server,
+#                                          add_function, remove_function,
+#                                          data, NULL)
+        
+#    def handle_watch(self, watch, condition):
+#        dbus_server_handle_watch(self.conn, watch, condition)
+
+BUS_SESSION = DBUS_BUS_SESSION
+BUS_SYSTEM = DBUS_BUS_SYSTEM
+BUS_ACTIVATION = DBUS_BUS_ACTIVATION
+
+def bus_get (bus_type):
+    cdef DBusError error
+    dbus_error_init(&error)
+    cdef DBusConnection *connection
+
+    connection = dbus_bus_get(bus_type,
+                              &error)
+
+    if dbus_error_is_set(&error):
+        raise DBusException, error.message
+
+    return Connection(_conn=<object>connection)
+
+def bus_get_base_service(connection):
+    conn = connection._get_conn()
+    return dbus_bus_get_base_service(<DBusConnection*>conn)
+
+def bus_register(connection):
+    cdef DBusError error
+    dbus_error_init(&error)
+    cdef dbus_bool_t retval
+
+    conn = connection._get_conn()
+    retval = dbus_bus_register(<DBusConnection*>conn,
+                               &error)
+    if dbus_error_is_set(&error):
+        raise DBusException, error.message
+
+    return retval
+
+SERVICE_FLAG_PROHIBIT_REPLACEMENT = 0x1
+SERVICE_FLAG_REPLACE_EXISTING     = 0x2
+
+def bus_acquire_service(connection, service_name, flags=0):
+    cdef DBusError error
+    dbus_error_init(&error)
+    cdef int retval
+
+    conn = connection._get_conn()
+    retval = dbus_bus_acquire_service(<DBusConnection*>conn,
+                                      service_name,
+                                      flags,
+                                      &error)
+    if dbus_error_is_set(&error):
+        raise DBusException, error.message
+    return retval
+    
+def bus_service_exists(connection, service_name):
+    cdef DBusError error
+    dbus_error_init(&error)
+    cdef dbus_bool_t retval
+
+    conn = connection._get_conn()
+    retval = dbus_bus_service_exists(<DBusConnection*>conn,
+                                     service_name,
+                                     &error)
+    if dbus_error_is_set(&error):
+        raise DBusException, error.message
+    return retval
+
+
diff --git a/python/dbus_h_wrapper.h b/python/dbus_h_wrapper.h
new file mode 100644 (file)
index 0000000..2e218c8
--- /dev/null
@@ -0,0 +1,3 @@
+#define DBUS_API_SUBJECT_TO_CHANGE 1
+#include <dbus/dbus.h>
+
diff --git a/python/extract.py b/python/extract.py
new file mode 100644 (file)
index 0000000..460af5a
--- /dev/null
@@ -0,0 +1,237 @@
+import commands
+import glob
+import re
+import os
+import string
+import sys
+
+def clean_func(buf):
+    buf = strip_comments(buf)
+    pat = re.compile(r"""\\\n""", re.MULTILINE) 
+    buf = pat.sub('',buf)
+    pat = re.compile(r"""^[#].*?$""", re.MULTILINE) 
+    buf = pat.sub('',buf)
+    pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE) 
+    buf = pat.sub('',buf)
+    pat = re.compile(r"""\s+""", re.MULTILINE) 
+    buf = pat.sub(' ',buf)
+    pat = re.compile(r""";\s*""", re.MULTILINE) 
+    buf = pat.sub('\n',buf)
+    buf = buf.lstrip()
+    #pat=re.compile(r'\s+([*|&]+)\s*(\w+)')
+    pat = re.compile(r' \s+ ([*|&]+) \s* (\w+)',re.VERBOSE)
+    buf = pat.sub(r'\1 \2', buf)
+    pat = re.compile(r'\s+ (\w+) \[ \s* \]',re.VERBOSE)
+    buf = pat.sub(r'[] \1', buf)
+#    buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
+    buf = string.replace(buf, 'const ', '')
+    return buf
+
+def strip_comments(buf):
+    parts = []
+    lastpos = 0
+    while 1:
+        pos = string.find(buf, '/*', lastpos)
+        if pos >= 0:
+            parts.append(buf[lastpos:pos])
+            pos = string.find(buf, '*/', pos)
+            if pos >= 0:
+                lastpos = pos + 2
+            else:
+                break
+        else:
+            parts.append(buf[lastpos:])
+            break
+    return string.join(parts, '')
+
+def find_enums(buf):
+    enums = []    
+    buf = strip_comments(buf)
+    buf = re.sub('\n', ' ', buf)
+    
+    enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
+    splitter = re.compile(r'\s*,\s', re.MULTILINE)
+    pos = 0
+    while pos < len(buf):
+        m = enum_pat.search(buf, pos)
+        if not m: break
+
+        name = m.group(2)
+        vals = m.group(1)
+        isflags = string.find(vals, '<<') >= 0
+        entries = []
+        for val in splitter.split(vals):
+            if not string.strip(val): continue
+            entries.append(string.split(val)[0])
+        enums.append((name, isflags, entries))
+        
+        pos = m.end()
+    return enums
+
+#typedef unsigned int   dbus_bool_t;
+#typedef struct {
+#
+# }
+#typedef struct FooStruct FooStruct;
+# typedef void (* DBusAddWatchFunction)      (DBusWatch      *watch,
+#                                          void           *data);
+
+def find_typedefs(buf):
+    typedefs = []
+    buf = re.sub('\n', ' ', strip_comments(buf))
+    typedef_pat = re.compile(
+        r"""typedef\s*(?P<type>\w*)
+            \s*
+            ([(]\s*\*\s*(?P<callback>[\w* ]*)[)]|{([^}]*)}|)
+            \s*
+            (?P<args1>[(](?P<args2>[\s\w*,_]*)[)]|[\w ]*)""",
+        re.MULTILINE | re.VERBOSE)
+    pat = re.compile(r"""\s+""", re.MULTILINE) 
+    pos = 0
+    while pos < len(buf):
+        m = typedef_pat.search(buf, pos)
+        if not m:
+            break
+        if m.group('type') == 'enum':
+            pos = m.end()
+            continue
+        if m.group('args2') != None:
+            args = pat.sub(' ', m.group('args2'))
+            
+            current = '%s (* %s) (%s)' % (m.group('type'),
+                                          m.group('callback'),
+                                          args)
+        else:
+            current = '%s %s' % (m.group('type'), m.group('args1'))
+        typedefs.append(current)
+        pos = m.end()
+    return typedefs
+
+proto_pat = re.compile(r"""
+(?P<ret>(-|\w|\&|\*)+\s*)      # return type
+\s+                            # skip whitespace
+(?P<func>\w+)\s*[(]  # match the function name until the opening (
+(?P<args>.*?)[)]               # group the function arguments
+""", re.IGNORECASE|re.VERBOSE)
+arg_split_pat = re.compile("\s*,\s*")
+
+
+def find_functions(buf):
+    functions = []
+    buf = clean_func(buf)
+    buf = string.split(buf,'\n')
+    for p in buf:
+        if len(p) == 0:
+            continue
+        
+        m = proto_pat.match(p)
+        if m == None:
+            continue
+        
+        func = m.group('func')
+        ret = m.group('ret')
+        args = m.group('args')
+        args = arg_split_pat.split(args)
+#        for i in range(len(args)):
+#            spaces = string.count(args[i], ' ')
+#            if spaces > 1:
+#                args[i] = string.replace(args[i], ' ', '-', spaces - 1)
+
+        functions.append((func, ret, args))
+    return functions
+
+class Writer:
+    def __init__(self, filename, enums, typedefs, functions):
+        if not (enums or typedefs or functions):
+            return
+        print 'cdef extern from "%s":' % filename
+
+        self.output_enums(enums)
+        self.output_typedefs(typedefs)
+        self.output_functions(functions)        
+        
+        print '    pass'
+        print
+        
+    def output_enums(self, enums):
+        for enum in enums:
+            print '    ctypedef enum %s:' % enum[0]
+            if enum[1] == 0:
+                for item in enum[2]:
+                    print '        %s' % item
+            else:
+                i = 0
+                for item in enum[2]:
+                    print '        %s' % item                    
+#                    print '        %s = 1 << %d' % (item, i)
+                    i += 1
+            print
+    def output_typedefs(self, typedefs):
+        for typedef in typedefs:
+            if typedef.find('va_list') != -1:
+                continue
+            
+            parts = typedef.split()
+            if parts[0] == 'struct':
+                if parts[-2] == parts[-1]:
+                    parts = parts[:-1]
+                print '    ctypedef %s' % ' '.join(parts)
+            else:
+                print '    ctypedef %s' % typedef
+
+    def output_functions(self, functions):
+        for func, ret, args in functions:
+            if func[0] == '_':
+                continue
+
+            str = ', '.join(args)
+            if str.find('...') != -1:
+                continue
+            if str.find('va_list') != -1:
+                continue
+            if str.strip() == 'void':
+                continue
+            print '    %-20s %s (%s)' % (ret, func, str)
+
+def do_buffer(name, buffer):
+    functions = find_functions(buffer)
+    typedefs = find_typedefs(buffer)
+    enums = find_enums(buffer)
+
+    Writer(name, enums, typedefs, functions)
+    
+def do_header(filename, name=None):
+    if name == None:
+        name = filename
+        
+    buffer = ""
+    for line in open(filename).readlines():
+        if line[0] == '#':
+            continue
+        buffer += line
+
+    print '# -- %s -- ' % filename
+    do_buffer(name, buffer)
+    
+filename = sys.argv[1]
+
+if filename.endswith('.h'):
+    do_header(filename)
+    raise SystemExit
+
+cppflags = ""
+
+for flag in sys.argv[2:]:
+    cppflags = cppflags + " " + flag
+
+fd = open(filename)
+
+for line in fd.readlines():
+    if line.startswith('#include'):
+        filename = line.split(' ')[1][1:-2]
+        command = "echo '%s'|cpp %s" % (line, cppflags)
+        sys.stderr.write('running %s' % (command))
+        output = commands.getoutput(command)
+        do_buffer(filename, output)
+    else:
+        print line[:-1]
index f22b175..d07575e 100644 (file)
@@ -106,7 +106,7 @@ main (int    argc,
   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",
@@ -126,10 +126,13 @@ main (int    argc,
                                    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);