]> git.0d.be Git - empathy.git/commitdiff
Import tools from telepathy-glib 0.7.3 and build a static libemp-extensions.la.
authorXavier Claessens <xclaesse@src.gnome.org>
Tue, 26 Feb 2008 13:31:02 +0000 (13:31 +0000)
committerXavier Claessens <xclaesse@src.gnome.org>
Tue, 26 Feb 2008 13:31:02 +0000 (13:31 +0000)
Link that library into libempathy (it's not actually used for anything at this
point).

Extensions currently built: ChannelHandler and StreamEngine.

The namespacing convention used is emp_*, Emp*, EMP_* so it won't be included
in the library ABI.

svn path=/trunk/; revision=663

32 files changed:
Makefile.am
configure.ac
extensions/.gitignore [new file with mode: 0644]
extensions/Channel_Handler.xml [new file with mode: 0644]
extensions/Makefile.am [new file with mode: 0644]
extensions/Stream_Engine.xml [new file with mode: 0644]
extensions/all.xml [new file with mode: 0644]
extensions/extensions-cli.c [new file with mode: 0644]
extensions/extensions.c [new file with mode: 0644]
extensions/extensions.h [new file with mode: 0644]
extensions/misc.xml [new file with mode: 0644]
libempathy/Makefile.am
tools/.gitignore [new file with mode: 0644]
tools/Makefile.am [new file with mode: 0644]
tools/c-constants-generator.xsl [new file with mode: 0644]
tools/c-interfaces-generator.xsl [new file with mode: 0644]
tools/check-c-style.sh [new file with mode: 0644]
tools/check-coding-style.mk [new file with mode: 0644]
tools/check-misc.sh [new file with mode: 0644]
tools/check-whitespace.sh [new file with mode: 0644]
tools/doc-generator.xsl [new file with mode: 0644]
tools/glib-client-gen.py [new file with mode: 0644]
tools/glib-client-marshaller-gen.py [new file with mode: 0644]
tools/glib-errors-enum-body.xsl [new file with mode: 0644]
tools/glib-errors-enum-header.xsl [new file with mode: 0644]
tools/glib-ginterface-gen.py [new file with mode: 0644]
tools/glib-gtypes-generator.py [new file with mode: 0644]
tools/glib-interfaces-body-generator.xsl [new file with mode: 0644]
tools/glib-interfaces-generator.xsl [new file with mode: 0644]
tools/glib-signals-marshal-gen.py [new file with mode: 0644]
tools/identity.xsl [new file with mode: 0644]
tools/libglibcodegen.py [new file with mode: 0644]

index 2d0d907ff443415d925296b61e4533bba1072530..14aa451e5f96c81358756d56b1abc2947f094b72 100644 (file)
@@ -1,4 +1,4 @@
-SUBDIRS = po data libempathy libempathy-gtk src docs
+SUBDIRS = tools extensions po data libempathy libempathy-gtk src docs
 
 if HAVE_MEGAPHONE
 SUBDIRS += megaphone
 
 if HAVE_MEGAPHONE
 SUBDIRS += megaphone
index ac012243a068a5d5918dde7000ea4c4afcdf4527..4d26cae4efb63a10040efb34ef79fdea53c173d7 100644 (file)
@@ -31,7 +31,7 @@ GCONF_REQUIRED=1.2.0
 LIBGLADE_REQUIRED=2.0.0
 LIBPANELAPPLET_REQUIRED=2.10.0
 TELEPATHY_REQUIRED=0.3.1
 LIBGLADE_REQUIRED=2.0.0
 LIBPANELAPPLET_REQUIRED=2.10.0
 TELEPATHY_REQUIRED=0.3.1
-TELEPATHY_GLIB_REQUIRED=0.7.0
+TELEPATHY_GLIB_REQUIRED=0.7.3
 MISSION_CONTROL_REQUIRED=4.53
 
 # Uncomment that to build without deprecated symbols
 MISSION_CONTROL_REQUIRED=4.53
 
 # Uncomment that to build without deprecated symbols
@@ -52,6 +52,7 @@ AC_ISC_POSIX
 AC_PROG_CC
 AC_HEADER_STDC
 AM_PROG_LIBTOOL
 AC_PROG_CC
 AC_HEADER_STDC
 AM_PROG_LIBTOOL
+AM_PROG_MKDIR_P
 AM_PATH_GLIB_2_0
 AC_PATH_XTRA
 IT_PROG_INTLTOOL([0.35.0])
 AM_PATH_GLIB_2_0
 AC_PATH_XTRA
 IT_PROG_INTLTOOL([0.35.0])
@@ -63,6 +64,15 @@ AM_GCONF_SOURCE_2
 GLIB_GENMARSHAL=`$PKG_CONFIG glib-2.0 --variable=glib_genmarshal`
 AC_SUBST(GLIB_GENMARSHAL)
 
 GLIB_GENMARSHAL=`$PKG_CONFIG glib-2.0 --variable=glib_genmarshal`
 AC_SUBST(GLIB_GENMARSHAL)
 
+AC_CHECK_PROGS([XSLTPROC], [xsltproc])
+if test -z "$XSLTPROC"; then
+  AC_MSG_ERROR([xsltproc (from libxslt) is required])
+fi
+AC_CHECK_PROGS([PYTHON], [python2.3 python2.4 python2.5 python])
+if test -z "$PYTHON"; then
+  AC_MSG_ERROR([Python is required])
+fi
+
 EMPATHY_ARG_VALGRIND
 
 # -----------------------------------------------------------
 EMPATHY_ARG_VALGRIND
 
 # -----------------------------------------------------------
@@ -300,6 +310,7 @@ AC_OUTPUT([
    data/Makefile
    data/empathy.desktop.in
    data/icons/Makefile
    data/Makefile
    data/empathy.desktop.in
    data/icons/Makefile
+   extensions/Makefile
    po/Makefile.in
    libempathy/Makefile
    libempathy/libempathy.pc
    po/Makefile.in
    libempathy/Makefile
    libempathy/libempathy.pc
@@ -321,4 +332,5 @@ AC_OUTPUT([
    python/pyempathy/Makefile
    python/pyempathygtk/Makefile
    tests/Makefile
    python/pyempathy/Makefile
    python/pyempathygtk/Makefile
    tests/Makefile
+   tools/Makefile
 ])
 ])
diff --git a/extensions/.gitignore b/extensions/.gitignore
new file mode 100644 (file)
index 0000000..09d7dbf
--- /dev/null
@@ -0,0 +1,2 @@
+_gen
+extensions.html
diff --git a/extensions/Channel_Handler.xml b/extensions/Channel_Handler.xml
new file mode 100644 (file)
index 0000000..80233e9
--- /dev/null
@@ -0,0 +1,62 @@
+<?xml version="1.0" ?>
+<node name="/Channel_Handler" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+  <tp:copyright>Copyright (C) 2007 Collabora Limited</tp:copyright>
+  <tp:license xmlns="http://www.w3.org/1999/xhtml">
+    <p>This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.</p>
+
+<p>This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.</p>
+
+<p>You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</p>
+  </tp:license>
+  <interface name="org.freedesktop.Telepathy.ChannelHandler">
+
+    <method name="HandleChannel">
+      <arg direction="in" type="s" name="Bus_Name" tp:type="DBus_Bus_Name">
+        <tp:docstring>
+          The bus name of the connection and channel
+        </tp:docstring>
+      </arg>
+      <arg direction="in" type="o" name="Connection">
+        <tp:docstring>
+          The object-path of the connection that owns the channel
+        </tp:docstring>
+      </arg>
+      <arg direction="in" type="s" tp:type="DBus_Interface" name="Channel_Type">
+        <tp:docstring>
+          The channel type
+        </tp:docstring>
+      </arg>
+      <arg direction="in" type="o" name="Channel">
+        <tp:docstring>
+          The object-path of the channel
+        </tp:docstring>
+      </arg>
+      <arg direction="in" type="u" tp:type="Handle_Type" name="Handle_Type">
+        <tp:docstring>The type of the handle that the channel communicates
+          with, or 0 if there is no associated handle</tp:docstring>
+      </arg>
+      <arg direction="in" type="u" tp:type="Handle" name="Handle">
+        <tp:docstring>The handle that the channel communicates with,
+          or 0 if there is no associated handle</tp:docstring>
+      </arg>
+      <tp:docstring>
+        Called when a channel handler should handle a new channel.
+      </tp:docstring>
+      <!-- FIXME: possible errors? -->
+    </method>
+    <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+      <p>An interface exported by client applications which are able to
+        handle incoming channels.</p>
+    </tp:docstring>
+  </interface>
+</node>
+<!-- vim:set sw=2 sts=2 et ft=xml: -->
+
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
new file mode 100644 (file)
index 0000000..ccf7bb5
--- /dev/null
@@ -0,0 +1,130 @@
+tools_dir = $(top_srcdir)/tools
+
+AM_CFLAGS = \
+    -I$(top_srcdir) \
+    -I$(top_builddir) \
+    $(WARN_CFLAGS) \
+    $(LIBEMPATHY_CFLAGS)
+
+EXTRA_DIST = \
+    all.xml \
+    misc.xml \
+    Channel_Handler.xml \
+    Stream_Engine.xml
+
+noinst_LTLIBRARIES = libemp-extensions.la
+
+libemp_extensions_la_LIBADD = \
+    $(TELEPATHY_GLIB_LIBS)
+
+# The client-specific parts are built into a separate .o file, so the linker
+# can discard them when linking services. The service-specific parts are
+# in svc-*.c, so we don't need an extensions-svc.c.
+libemp_extensions_la_SOURCES = \
+    extensions.c \
+    extensions-cli.c \
+    extensions.h
+
+nodist_libemp_extensions_la_SOURCES = \
+    _gen/signals-marshal.c \
+    _gen/signals-marshal.h \
+    _gen/signals-marshal.list \
+    _gen/register-dbus-glib-marshallers-body.h \
+    _gen/enums.h \
+    _gen/gtypes.h \
+    _gen/gtypes-body.h \
+    _gen/interfaces.h \
+    _gen/interfaces-body.h \
+    _gen/cli-misc.h \
+    _gen/cli-misc-body.h \
+    _gen/svc-misc.h \
+    _gen/svc-misc.c
+
+BUILT_SOURCES = \
+    _gen/all.xml \
+    _gen/misc.xml \
+    $(nodist_libemp_extensions_la_SOURCES) \
+    extensions.html
+
+CLEANFILES = $(BUILT_SOURCES)
+
+XSLTPROCFLAGS = --nonet --novalid
+
+# Generated files which can be generated for all categories simultaneously
+
+_gen/%.xml: %.xml $(wildcard *.xml)
+       $(mkdir_p) _gen
+       $(XSLTPROC) $(XSLTPROCFLAGS) --xinclude $(tools_dir)/identity.xsl \
+               $< > $@
+
+extensions.html: _gen/all.xml $(tools_dir)/doc-generator.xsl
+       $(XSLTPROC) $(XSLTPROCFLAGS) \
+               $(tools_dir)/doc-generator.xsl \
+               $< > $@
+
+_gen/gtypes.h _gen/gtypes-body.h: _gen/all.xml \
+       $(top_srcdir)/tools/glib-gtypes-generator.py
+       $(PYTHON) $(top_srcdir)/tools/glib-gtypes-generator.py \
+               $< _gen/gtypes Emp
+
+_gen/signals-marshal.list: _gen/all.xml \
+       $(tools_dir)/glib-signals-marshal-gen.py
+       $(PYTHON) $(tools_dir)/glib-signals-marshal-gen.py $< > $@
+
+_gen/signals-marshal.h: _gen/signals-marshal.list
+       $(GLIB_GENMARSHAL) --header --prefix=_emp_ext_marshal $< > $@
+
+_gen/signals-marshal.c: _gen/signals-marshal.list
+       ( \
+       echo '#include "signals-marshal.h"' && \
+       $(GLIB_GENMARSHAL) --body --prefix=_emp_ext_marshal $< \
+       ) >> $@
+
+_gen/register-dbus-glib-marshallers-body.h: _gen/all.xml \
+       $(tools_dir)/glib-client-marshaller-gen.py
+       $(PYTHON) $(tools_dir)/glib-client-marshaller-gen.py $< \
+               _emp_ext > $@
+
+_gen/enums.h: _gen/all.xml $(tools_dir)/c-constants-generator.xsl
+       $(XSLTPROC) $(XSLTPROCFLAGS) \
+               --stringparam mixed-case-prefix Emp \
+               $(tools_dir)/c-constants-generator.xsl \
+               $< > $@
+
+_gen/interfaces.h: _gen/all.xml \
+       $(tools_dir)/glib-interfaces-generator.xsl \
+       $(tools_dir)/c-interfaces-generator.xsl
+       $(XSLTPROC) $(XSLTPROCFLAGS) \
+               --stringparam mixed-case-prefix Emp \
+               $(tools_dir)/glib-interfaces-generator.xsl \
+               $< > $@
+
+_gen/interfaces-body.h: _gen/all.xml \
+       $(tools_dir)/glib-interfaces-body-generator.xsl \
+       $(tools_dir)/c-interfaces-generator.xsl
+       $(XSLTPROC) $(XSLTPROCFLAGS) \
+               --stringparam mixed-case-prefix Emp \
+               $(tools_dir)/glib-interfaces-body-generator.xsl \
+               $< > $@
+
+# Generated files which must be generated per "category". Each TpProxy
+# subclass you want to use with --subclass will need to have its own category,
+# although you can subdivide further if you want.
+
+_gen/cli-misc-body.h _gen/cli-misc.h: _gen/misc.xml \
+       $(tools_dir)/glib-client-gen.py
+       $(PYTHON) $(tools_dir)/glib-client-gen.py \
+               --group=misc \
+               --iface-quark-prefix=EMP_IFACE_QUARK \
+               $< Emp_Cli _gen/cli-misc
+
+_gen/svc-misc.c _gen/svc-misc.h: _gen/misc.xml \
+       $(tools_dir)/glib-ginterface-gen.py
+       $(PYTHON) $(tools_dir)/glib-ginterface-gen.py \
+               --filename=_gen/svc-misc \
+               --signal-marshal-prefix=_emp_ext \
+               --include='<telepathy-glib/dbus.h>' \
+               --include='"_gen/signals-marshal.h"' \
+               --not-implemented-func='tp_dbus_g_method_return_not_implemented' \
+               --allow-unstable \
+               $< Emp_Svc_
diff --git a/extensions/Stream_Engine.xml b/extensions/Stream_Engine.xml
new file mode 100644 (file)
index 0000000..0303a51
--- /dev/null
@@ -0,0 +1,44 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node name="/Stream_Engine">
+  <interface name="org.freedesktop.Telepathy.StreamEngine">
+    <method name="SetOutputVolume">
+      <arg direction="in" type="o" name="channel_path" />
+      <arg direction="in" type="u" name="stream_id" />
+      <arg direction="in" type="u" name="volume" />
+    </method>
+    <method name="MuteInput">
+      <arg direction="in" type="o" name="channel_path" />
+      <arg direction="in" type="u" name="stream_id" />
+      <arg direction="in" type="b" name="mute_state" />
+    </method>
+    <method name="MuteOutput">
+      <arg direction="in" type="o" name="channel_path" />
+      <arg direction="in" type="u" name="stream_id" />
+      <arg direction="in" type="b" name="mute_state" />
+    </method>
+    <method name="SetOutputWindow">
+      <arg direction="in" type="o" name="channel_path" />
+      <arg direction="in" type="u" name="stream_id" />
+      <arg direction="in" type="u" name="window" />
+    </method>
+    <method name="AddPreviewWindow">
+      <arg direction="in" type="u" name="window" />
+    </method>
+    <method name="RemovePreviewWindow">
+      <arg direction="in" type="u" name="window" />
+    </method>
+    <signal name="Receiving">
+      <arg type="o" name="channel_path" />
+      <arg type="u" name="stream_id" />
+      <arg type="b" name="state" />
+    </signal>
+    <signal name="StreamStateChanged">
+      <arg type="o" name="channel_path" />
+      <arg type="u" name="stream_id" />
+      <arg type="u" name="state" />
+      <arg type="u" name="direction" />
+    </signal>
+    <method name="Shutdown">
+    </method>
+  </interface>
+</node>
diff --git a/extensions/all.xml b/extensions/all.xml
new file mode 100644 (file)
index 0000000..2a0e109
--- /dev/null
@@ -0,0 +1,14 @@
+<tp:spec
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<tp:title>Extensions for Empathy</tp:title>
+
+<xi:include href="misc.xml"/>
+
+<tp:generic-types>
+  <tp:external-type name="Contact_Handle" type="u"
+    from="Telepathy specification"/>
+</tp:generic-types>
+
+</tp:spec>
diff --git a/extensions/extensions-cli.c b/extensions/extensions-cli.c
new file mode 100644 (file)
index 0000000..98a1744
--- /dev/null
@@ -0,0 +1,19 @@
+#include "extensions.h"
+
+#include <telepathy-glib/proxy-subclass.h>
+
+static void _emp_ext_register_dbus_glib_marshallers (void);
+
+/* include auto-generated stubs for client-specific code */
+#include "_gen/signals-marshal.h"
+#include "_gen/cli-misc-body.h"
+#include "_gen/register-dbus-glib-marshallers-body.h"
+
+void
+emp_cli_init (void)
+{
+  _emp_ext_register_dbus_glib_marshallers ();
+
+  tp_proxy_or_subclass_hook_on_interface_add (TP_TYPE_PROXY,
+      emp_cli_misc_add_signals);
+}
diff --git a/extensions/extensions.c b/extensions/extensions.c
new file mode 100644 (file)
index 0000000..eeda462
--- /dev/null
@@ -0,0 +1,6 @@
+#include "extensions.h"
+
+/* include auto-generated stubs for things common to service and client */
+#include "_gen/gtypes-body.h"
+#include "_gen/interfaces-body.h"
+#include "_gen/signals-marshal.h"
diff --git a/extensions/extensions.h b/extensions/extensions.h
new file mode 100644 (file)
index 0000000..d97dc83
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __EMP_EXTENSIONS_H__
+#define __EMP_EXTENSIONS_H__
+
+#include <glib-object.h>
+#include <telepathy-glib/channel.h>
+
+#include "extensions/_gen/enums.h"
+#include "extensions/_gen/cli-misc.h"
+#include "extensions/_gen/svc-misc.h"
+
+G_BEGIN_DECLS
+
+#include "extensions/_gen/gtypes.h"
+#include "extensions/_gen/interfaces.h"
+
+void emp_cli_init (void);
+
+G_END_DECLS
+
+#endif
diff --git a/extensions/misc.xml b/extensions/misc.xml
new file mode 100644 (file)
index 0000000..070ae85
--- /dev/null
@@ -0,0 +1,10 @@
+<tp:spec
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  xmlns:xi="http://www.w3.org/2001/XInclude">
+
+<tp:title>Channel extensions for Empathy</tp:title>
+
+<xi:include href="Stream_Engine.xml"/>
+<xi:include href="Channel_Handler.xml"/>
+
+</tp:spec>
index 90b3aa891c8fa3cefee2e8be5d224dd5c113bcdd..adf9b7d5b276ddc8197144378bb3192c28d7bca7 100644 (file)
@@ -1,6 +1,7 @@
 AM_CPPFLAGS =                                           \
        -I.                                             \
        -I$(top_srcdir)                                 \
 AM_CPPFLAGS =                                           \
        -I.                                             \
        -I$(top_srcdir)                                 \
+       -I$(top_builddir)                               \
        -DDATADIR=\""$(datadir)"\"                      \
        $(LIBEMPATHY_CFLAGS)                            \
        $(WARN_CFLAGS)
        -DDATADIR=\""$(datadir)"\"                      \
        $(LIBEMPATHY_CFLAGS)                            \
        $(WARN_CFLAGS)
@@ -51,6 +52,7 @@ nodist_libempathy_la_SOURCES =\
        $(BUILT_SOURCES)
 
 libempathy_la_LIBADD =         \
        $(BUILT_SOURCES)
 
 libempathy_la_LIBADD =         \
+       $(top_builddir)/extensions/libemp-extensions.la \
        $(LIBEMPATHY_LIBS)
 
 libempathy_la_LDFLAGS =                \
        $(LIBEMPATHY_LIBS)
 
 libempathy_la_LDFLAGS =                \
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644 (file)
index 0000000..48bd3a8
--- /dev/null
@@ -0,0 +1 @@
+.py[co]
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644 (file)
index 0000000..4bf514f
--- /dev/null
@@ -0,0 +1,41 @@
+EXTRA_DIST = \
+    c-constants-generator.xsl \
+    check-coding-style.mk \
+    check-c-style.sh \
+    check-misc.sh \
+    check-whitespace.sh \
+    c-interfaces-generator.xsl \
+    doc-generator.xsl \
+    glib-client-gen.py \
+    glib-client-marshaller-gen.py \
+    glib-errors-enum-body.xsl \
+    glib-errors-enum-header.xsl \
+    glib-interfaces-generator.xsl \
+    glib-interfaces-body-generator.xsl \
+    glib-ginterface-gen.py \
+    glib-gtypes-generator.py \
+    glib-signals-marshal-gen.py \
+    identity.xsl \
+    libglibcodegen.py
+
+CLEANFILES = libglibcodegen.pyc libglibcodegen.pyo $(noinst_SCRIPTS)
+
+all: $(EXTRA_DIST)
+
+glib-client-marshaller-gen.py: libglibcodegen.py
+       touch $@
+glib-ginterface-gen.py: libglibcodegen.py
+       touch $@
+glib-gtypes-generator.py: libglibcodegen.py
+       touch $@
+glib-signals-marshal-gen.py: libglibcodegen.py
+       touch $@
+
+TELEPATHY_GLIB_SRCDIR = $(top_srcdir)/../telepathy-glib
+maintainer-update-from-telepathy-glib:
+       set -e && cd $(srcdir) && \
+       for x in $(EXTRA_DIST); do \
+               if test -f $(TELEPATHY_GLIB_SRCDIR)/tools/$$x; then \
+                       cp $(TELEPATHY_GLIB_SRCDIR)/tools/$$x $$x; \
+               fi; \
+       done
diff --git a/tools/c-constants-generator.xsl b/tools/c-constants-generator.xsl
new file mode 100644 (file)
index 0000000..18b2e49
--- /dev/null
@@ -0,0 +1,299 @@
+<!-- Stylesheet to extract C enumerations from the Telepathy spec.
+The master copy of this stylesheet is in telepathy-glib - please make any
+changes there.
+
+Copyright (C) 2006, 2007 Collabora Limited
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  exclude-result-prefixes="tp">
+
+  <xsl:output method="text" indent="no" encoding="ascii"/>
+
+  <xsl:param name="mixed-case-prefix" select="''"/>
+
+  <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
+  <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
+
+  <xsl:variable name="upper-case-prefix" select="concat(translate($mixed-case-prefix, $lower, $upper), '_')"/>
+  <xsl:variable name="lower-case-prefix" select="concat(translate($mixed-case-prefix, $upper, $lower), '_')"/>
+
+
+  <xsl:template match="tp:flags">
+    <xsl:variable name="name">
+      <xsl:choose>
+        <xsl:when test="@plural">
+          <xsl:value-of select="@plural"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@name"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="value-prefix">
+      <xsl:choose>
+        <xsl:when test="@singular">
+          <xsl:value-of select="@singular"/>
+        </xsl:when>
+        <xsl:when test="@value-prefix">
+          <xsl:value-of select="@value-prefix"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@name"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:text>/**&#10;</xsl:text>
+    <xsl:text> *&#10;</xsl:text>
+    <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>
+    <xsl:text>:&#10;</xsl:text>
+    <xsl:apply-templates mode="flag-or-enumvalue-gtkdoc">
+      <xsl:with-param name="value-prefix" select="$value-prefix"/>
+    </xsl:apply-templates>
+    <xsl:text> *&#10;</xsl:text>
+    <xsl:if test="tp:docstring">
+      <xsl:text> * &lt;![CDATA[</xsl:text>
+      <xsl:value-of select="translate(string (tp:docstring), '&#13;&#10;', '  ')"/>
+      <xsl:text>]]&gt;&#10;</xsl:text>
+      <xsl:text> *&#10;</xsl:text>
+    </xsl:if>
+    <xsl:text> * Bitfield/set of flags generated from the Telepathy specification.&#10;</xsl:text>
+    <xsl:text> */&#10;</xsl:text>
+    <xsl:text>typedef enum {&#10;</xsl:text>
+    <xsl:apply-templates>
+      <xsl:with-param name="value-prefix" select="$value-prefix"/>
+    </xsl:apply-templates>
+    <xsl:text>} </xsl:text>
+    <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>
+    <xsl:text>;&#10;</xsl:text>
+    <xsl:text>&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="text()" mode="flag-or-enumvalue-gtkdoc"/>
+
+  <xsl:template match="tp:enumvalue" mode="flag-or-enumvalue-gtkdoc">
+    <xsl:param name="value-prefix"/>
+    <xsl:text> * @</xsl:text>
+    <xsl:value-of select="translate(concat($upper-case-prefix, $value-prefix, '_', @suffix), $lower, $upper)"/>
+    <xsl:text>: &lt;![CDATA[</xsl:text>
+    <xsl:value-of select="translate(string(tp:docstring), '&#13;&#10;', '  ')"/>
+    <xsl:text>]]&gt;&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="tp:flag" mode="flag-or-enumvalue-gtkdoc">
+    <xsl:param name="value-prefix"/>
+    <xsl:text> * @</xsl:text>
+    <xsl:value-of select="translate(concat($upper-case-prefix, $value-prefix, '_', @suffix), $lower, $upper)"/>
+    <xsl:text>: &lt;![CDATA[</xsl:text>
+    <xsl:value-of select="translate(string(tp:docstring), '&#13;&#10;', '  ')"/>
+    <xsl:text>]]&gt;&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="tp:enum">
+    <xsl:variable name="name">
+      <xsl:choose>
+        <xsl:when test="@singular">
+          <xsl:value-of select="@singular"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@name"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="value-prefix">
+      <xsl:choose>
+        <xsl:when test="@singular">
+          <xsl:value-of select="@singular"/>
+        </xsl:when>
+        <xsl:when test="@value-prefix">
+          <xsl:value-of select="@value-prefix"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@name"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="name-plural">
+      <xsl:choose>
+        <xsl:when test="@plural">
+          <xsl:value-of select="@plural"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@name"/><xsl:text>s</xsl:text>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:text>/**&#10;</xsl:text>
+    <xsl:text> *&#10;</xsl:text>
+    <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>
+    <xsl:text>:&#10;</xsl:text>
+    <xsl:apply-templates mode="flag-or-enumvalue-gtkdoc">
+      <xsl:with-param name="value-prefix" select="$value-prefix"/>
+    </xsl:apply-templates>
+    <xsl:text> *&#10;</xsl:text>
+    <xsl:if test="tp:docstring">
+      <xsl:text> * &lt;![CDATA[</xsl:text>
+      <xsl:value-of select="translate(string (tp:docstring), '&#13;&#10;', '  ')"/>
+      <xsl:text>]]&gt;&#10;</xsl:text>
+      <xsl:text> *&#10;</xsl:text>
+    </xsl:if>
+    <xsl:text> * Bitfield/set of flags generated from the Telepathy specification.&#10;</xsl:text>
+    <xsl:text> */&#10;</xsl:text>
+    <xsl:text>typedef enum {&#10;</xsl:text>
+    <xsl:apply-templates>
+      <xsl:with-param name="value-prefix" select="$value-prefix"/>
+    </xsl:apply-templates>
+    <xsl:text>} </xsl:text>
+    <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>
+    <xsl:text>;&#10;</xsl:text>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:text>/**&#10;</xsl:text>
+    <xsl:text> * NUM_</xsl:text>
+    <xsl:value-of select="translate(concat($upper-case-prefix, $name-plural), $lower, $upper)"/>
+    <xsl:text>:&#10;</xsl:text>
+    <xsl:text> *&#10;</xsl:text>
+    <xsl:text> * 1 higher than the highest valid value of #</xsl:text>
+    <xsl:value-of select="translate(concat($mixed-case-prefix, $name), '_', '')"/>
+    <xsl:text>.&#10;</xsl:text>
+    <xsl:text> */&#10;</xsl:text>
+    <xsl:text>#define NUM_</xsl:text>
+    <xsl:value-of select="translate(concat($upper-case-prefix, $name-plural), $lower, $upper)"/>
+    <xsl:text> (</xsl:text>
+    <xsl:value-of select="tp:enumvalue[position() = last()]/@value"/>
+    <xsl:text>+1)&#10;</xsl:text>
+    <xsl:text>&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="tp:flags/tp:flag">
+    <xsl:param name="value-prefix"/>
+    <xsl:variable name="suffix">
+      <xsl:choose>
+        <xsl:when test="@suffix">
+          <xsl:value-of select="@suffix"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@name"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="name" select="translate(concat($upper-case-prefix, $value-prefix, '_', $suffix), $lower, $upper)"/>
+
+    <xsl:if test="@name and @suffix and @name != @suffix">
+      <xsl:message terminate="yes">
+        <xsl:text>Flag name </xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text> != suffix </xsl:text>
+        <xsl:value-of select="@suffix"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+    <xsl:text>    </xsl:text>
+    <xsl:value-of select="$name"/>
+    <xsl:text> = </xsl:text>
+    <xsl:value-of select="@value"/>
+    <xsl:text>,&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="tp:enum/tp:enumvalue">
+    <xsl:param name="value-prefix"/>
+    <xsl:variable name="suffix">
+      <xsl:choose>
+        <xsl:when test="@suffix">
+          <xsl:value-of select="@suffix"/>
+        </xsl:when>
+        <xsl:otherwise>
+          <xsl:value-of select="@name"/>
+        </xsl:otherwise>
+      </xsl:choose>
+    </xsl:variable>
+    <xsl:variable name="name" select="translate(concat($upper-case-prefix, $value-prefix, '_', $suffix), $lower, $upper)"/>
+
+    <xsl:if test="@name and @suffix and @name != @suffix">
+      <xsl:message terminate="yes">
+        <xsl:text>Enumvalue name </xsl:text>
+        <xsl:value-of select="@name"/>
+        <xsl:text> != suffix </xsl:text>
+        <xsl:value-of select="@suffix"/>
+        <xsl:text>&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:if test="preceding-sibling::tp:enumvalue and number(preceding-sibling::tp:enumvalue[1]/@value) > number(@value)">
+      <xsl:message terminate="yes">
+        <xsl:text>Enum values must be in ascending numeric order, but </xsl:text>
+        <xsl:value-of select="$name"/>
+        <xsl:text> is less than the previous value</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:text>    </xsl:text>
+    <xsl:value-of select="$name"/>
+    <xsl:text> = </xsl:text>
+    <xsl:value-of select="@value"/>
+    <xsl:text>,&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="tp:flag">
+    <xsl:message terminate="yes">tp:flag found outside tp:flags&#10;</xsl:message>
+  </xsl:template>
+
+  <xsl:template match="tp:enumvalue">
+    <xsl:message terminate="yes">tp:enumvalue found outside tp:enum&#10;</xsl:message>
+  </xsl:template>
+
+  <xsl:template match="text()"/>
+
+  <xsl:template match="/tp:spec">
+    <xsl:if test="$mixed-case-prefix = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>mixed-case-prefix param must be set&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:text>/* Generated from </xsl:text>
+    <xsl:value-of select="tp:title"/>
+    <xsl:if test="tp:version">
+      <xsl:text>, version </xsl:text>
+      <xsl:value-of select="tp:version"/>
+    </xsl:if>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:for-each select="tp:copyright">
+      <xsl:value-of select="."/>
+      <xsl:text>&#10;</xsl:text>
+    </xsl:for-each>
+    <xsl:value-of select="tp:license"/>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:value-of select="tp:docstring"/>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:text> */&#10;</xsl:text>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:text>#ifdef __cplusplus&#10;</xsl:text>
+    <xsl:text>extern "C" {&#10;</xsl:text>
+    <xsl:text>#endif&#10;</xsl:text>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:apply-templates/>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:text>#ifdef __cplusplus&#10;</xsl:text>
+    <xsl:text>}&#10;</xsl:text>
+    <xsl:text>#endif&#10;</xsl:text>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et noai noci: -->
diff --git a/tools/c-interfaces-generator.xsl b/tools/c-interfaces-generator.xsl
new file mode 100644 (file)
index 0000000..f965a70
--- /dev/null
@@ -0,0 +1,84 @@
+<!-- Stylesheet to extract C enumerations from the Telepathy spec.
+The master copy of this stylesheet is in telepathy-glib - please make any
+changes there.
+
+Copyright (C) 2006, 2007 Collabora Limited
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  exclude-result-prefixes="tp">
+
+  <xsl:param name="mixed-case-prefix" select="''"/>
+
+  <xsl:variable name="PREFIX"
+    select="translate($mixed-case-prefix, $lower, $upper)"/>
+  <xsl:variable name="Prefix" select="$mixed-case-prefix"/>
+  <xsl:variable name="prefix"
+    select="translate($mixed-case-prefix, $upper, $lower)"/>
+
+  <xsl:output method="text" indent="no" encoding="ascii"/>
+
+  <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
+  <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
+
+  <xsl:template match="interface">
+    <xsl:text>/**&#10; * </xsl:text>
+    <xsl:value-of select="$PREFIX"/>
+    <xsl:text>_IFACE_</xsl:text>
+    <xsl:value-of select="translate(../@name, concat($lower, '/'), $upper)"/>
+    <xsl:text>:&#10; * &#10; * The interface name "</xsl:text>
+    <xsl:value-of select="@name"/>
+    <xsl:text>"&#10; */&#10;#define </xsl:text>
+    <xsl:value-of select="$PREFIX"/>
+    <xsl:text>_IFACE_</xsl:text>
+    <xsl:value-of select="translate(../@name, concat($lower, '/'), $upper)"/>
+    <xsl:text> \&#10;"</xsl:text>
+    <xsl:value-of select="@name"/>
+    <xsl:text>"&#10;&#10;</xsl:text>
+  </xsl:template>
+
+  <xsl:template match="text()"/>
+
+  <xsl:template match="/tp:spec">
+    <xsl:if test="$mixed-case-prefix = ''">
+      <xsl:message terminate="yes">
+        <xsl:text>mixed-case-prefix param must be set&#10;</xsl:text>
+      </xsl:message>
+    </xsl:if>
+
+    <xsl:text>/* Generated from: </xsl:text>
+    <xsl:value-of select="tp:title"/>
+    <xsl:if test="tp:version">
+      <xsl:text> version </xsl:text>
+      <xsl:value-of select="tp:version"/>
+    </xsl:if>
+    <xsl:text>&#10;&#10;</xsl:text>
+    <xsl:for-each select="tp:copyright">
+      <xsl:value-of select="."/>
+      <xsl:text>&#10;</xsl:text>
+    </xsl:for-each>
+    <xsl:text>&#10;</xsl:text>
+    <xsl:value-of select="tp:license"/>
+    <xsl:value-of select="tp:docstring"/>
+    <xsl:text>&#10; */&#10;&#10;</xsl:text>
+    <xsl:apply-templates/>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et noai noci: -->
diff --git a/tools/check-c-style.sh b/tools/check-c-style.sh
new file mode 100644 (file)
index 0000000..357fdb3
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh
+fail=0
+
+( . "${tools_dir}"/check-misc.sh ) || fail=$?
+
+if grep -n '^ *GError *\*[[:alpha:]_][[:alnum:]_]* *;' "$@"
+then
+  echo "^^^ The above files contain uninitialized GError*s - they should be"
+  echo "    initialized to NULL"
+  fail=1
+fi
+
+# The first regex finds function calls like foo() (as opposed to foo ()).
+#   It attempts to ignore string constants (may cause false negatives).
+# The second and third ignore block comments (gtkdoc uses foo() as markup).
+# The fourth ignores cpp so you can
+#   #define foo(bar) (_real_foo (__FUNC__, bar)) (cpp insists on foo() style).
+if grep -n '^[^"]*[[:lower:]](' "$@" \
+  | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: *\*' \
+  | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: */\*' \
+  | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: *#'
+then
+  echo "^^^ Our coding style is to use function calls like foo (), not foo()"
+  fail=1
+fi
+
+if test -n "$CHECK_FOR_LONG_LINES"
+then
+  if egrep -n '.{80,}' "$@"
+  then
+    echo "^^^ The above files contain long lines"
+    fail=1
+  fi
+fi
+
+exit $fail
diff --git a/tools/check-coding-style.mk b/tools/check-coding-style.mk
new file mode 100644 (file)
index 0000000..1499f2f
--- /dev/null
@@ -0,0 +1,17 @@
+check-local::
+       @fail=0; \
+       if test -n "$(check_misc_sources)"; then \
+               tools_dir=$(top_srcdir)/tools \
+               sh $(top_srcdir)/tools/check-misc.sh \
+                       $(check_misc_sources) || fail=1; \
+       fi; \
+       if test -n "$(check_c_sources)"; then \
+               tools_dir=$(top_srcdir)/tools \
+               sh $(top_srcdir)/tools/check-c-style.sh \
+                       $(check_c_sources) || fail=1; \
+       fi;\
+       if test yes = "$(ENABLE_CODING_STYLE_CHECKS)"; then \
+               exit "$$fail";\
+       else \
+               exit 0;\
+       fi
diff --git a/tools/check-misc.sh b/tools/check-misc.sh
new file mode 100644 (file)
index 0000000..89e8e87
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+fail=0
+
+( . "${tools_dir}"/check-whitespace.sh ) || fail=$?
+
+if egrep '(Free\s*Software\s*Foundation.*02139|02111-1307)' "$@"
+then
+  echo "^^^ The above files contain the FSF's old address in GPL headers"
+  fail=1
+fi
+
+exit $fail
diff --git a/tools/check-whitespace.sh b/tools/check-whitespace.sh
new file mode 100644 (file)
index 0000000..5348331
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+fail=0
+
+if grep -n ' $' "$@"
+then
+  echo "^^^ The above files contain unwanted trailing spaces"
+  fail=1
+fi
+
+if grep -n '   ' "$@"
+then
+  echo "^^^ The above files contain tabs"
+  fail=1
+fi
+
+exit $fail
diff --git a/tools/doc-generator.xsl b/tools/doc-generator.xsl
new file mode 100644 (file)
index 0000000..83b42dc
--- /dev/null
@@ -0,0 +1,689 @@
+<!-- Generate HTML documentation from the Telepathy specification.
+The master copy of this stylesheet is in the Telepathy spec repository -
+please make any changes there.
+
+Copyright (C) 2006, 2007 Collabora Limited
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  exclude-result-prefixes="tp">
+  <!--Don't move the declaration of the HTML namespace up here - XMLNSs
+  don't work ideally in the presence of two things that want to use the
+  absence of a prefix, sadly. -->
+
+  <xsl:template match="*" mode="identity">
+    <xsl:copy>
+      <xsl:apply-templates mode="identity"/>
+    </xsl:copy>
+  </xsl:template>
+
+  <xsl:template match="tp:docstring">
+    <xsl:apply-templates select="node()" mode="identity"/>
+  </xsl:template>
+
+  <xsl:template match="tp:errors">
+    <h1 xmlns="http://www.w3.org/1999/xhtml">Errors</h1>
+    <xsl:apply-templates/>
+  </xsl:template>
+
+  <xsl:template match="tp:generic-types">
+    <h1 xmlns="http://www.w3.org/1999/xhtml">Generic types</h1>
+    <xsl:call-template name="do-types"/>
+  </xsl:template>
+
+  <xsl:template name="do-types">
+    <xsl:if test="tp:simple-type">
+      <h2 xmlns="http://www.w3.org/1999/xhtml">Simple types</h2>
+      <xsl:apply-templates select="tp:simple-type"/>
+    </xsl:if>
+
+    <xsl:if test="tp:enum">
+      <h2 xmlns="http://www.w3.org/1999/xhtml">Enumerated types:</h2>
+      <xsl:apply-templates select="tp:enum"/>
+    </xsl:if>
+
+    <xsl:if test="tp:flags">
+      <h2 xmlns="http://www.w3.org/1999/xhtml">Sets of flags:</h2>
+      <xsl:apply-templates select="tp:flags"/>
+    </xsl:if>
+
+    <xsl:if test="tp:struct">
+      <h2 xmlns="http://www.w3.org/1999/xhtml">Structure types</h2>
+      <xsl:apply-templates select="tp:struct"/>
+    </xsl:if>
+
+    <xsl:if test="tp:mapping">
+      <h2 xmlns="http://www.w3.org/1999/xhtml">Mapping types</h2>
+      <xsl:apply-templates select="tp:mapping"/>
+    </xsl:if>
+
+    <xsl:if test="tp:external-type">
+      <h2 xmlns="http://www.w3.org/1999/xhtml">Types defined elsewhere</h2>
+      <dl><xsl:apply-templates select="tp:external-type"/></dl>
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="tp:error">
+    <h2 xmlns="http://www.w3.org/1999/xhtml"><a name="{concat(../@namespace, '.', translate(@name, ' ', ''))}"></a><xsl:value-of select="concat(../@namespace, '.', translate(@name, ' ', ''))"/></h2>
+    <xsl:apply-templates select="tp:docstring"/>
+  </xsl:template>
+
+  <xsl:template match="/tp:spec/tp:copyright">
+    <div xmlns="http://www.w3.org/1999/xhtml">
+      <xsl:apply-templates/>
+    </div>
+  </xsl:template>
+  <xsl:template match="/tp:spec/tp:license">
+    <div xmlns="http://www.w3.org/1999/xhtml" class="license">
+      <xsl:apply-templates mode="identity"/>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="tp:copyright"/>
+  <xsl:template match="tp:license"/>
+
+  <xsl:template match="interface">
+    <h1 xmlns="http://www.w3.org/1999/xhtml"><a name="{@name}"></a><xsl:value-of select="@name"/></h1>
+
+    <xsl:if test="@tp:causes-havoc">
+      <p xmlns="http://www.w3.org/1999/xhtml" class="causes-havoc">
+        This interface is <xsl:value-of select="@tp:causes-havoc"/>
+        and is likely to cause havoc to your API/ABI if bindings are generated.
+        Don't include it in libraries that care about compatibility.
+      </p>
+    </xsl:if>
+
+    <xsl:if test="tp:requires">
+      <p>Implementations of this interface must also implement:</p>
+      <ul xmlns="http://www.w3.org/1999/xhtml">
+        <xsl:for-each select="tp:requires">
+          <li><code><a href="#{@interface}"><xsl:value-of select="@interface"/></a></code></li>
+        </xsl:for-each>
+      </ul>
+    </xsl:if>
+
+    <xsl:apply-templates select="tp:docstring" />
+
+    <xsl:choose>
+      <xsl:when test="method">
+        <h2 xmlns="http://www.w3.org/1999/xhtml">Methods:</h2>
+        <xsl:apply-templates select="method"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <p xmlns="http://www.w3.org/1999/xhtml">Interface has no methods.</p>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:choose>
+      <xsl:when test="signal">
+        <h2 xmlns="http://www.w3.org/1999/xhtml">Signals:</h2>
+        <xsl:apply-templates select="signal"/>
+      </xsl:when>
+      <xsl:otherwise>
+        <p xmlns="http://www.w3.org/1999/xhtml">Interface has no signals.</p>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:choose>
+      <xsl:when test="tp:property">
+        <h2 xmlns="http://www.w3.org/1999/xhtml">Properties:</h2>
+        <dl xmlns="http://www.w3.org/1999/xhtml">
+          <xsl:apply-templates select="tp:property"/>
+        </dl>
+      </xsl:when>
+      <xsl:otherwise>
+        <p xmlns="http://www.w3.org/1999/xhtml">Interface has no properties.</p>
+      </xsl:otherwise>
+    </xsl:choose>
+
+    <xsl:call-template name="do-types"/>
+
+  </xsl:template>
+
+  <xsl:template match="tp:flags">
+    <h3>
+      <a name="type-{@name}">
+        <xsl:value-of select="@name"/>
+      </a>
+    </h3>
+    <xsl:apply-templates select="tp:docstring" />
+    <dl xmlns="http://www.w3.org/1999/xhtml">
+        <xsl:variable name="value-prefix">
+          <xsl:choose>
+            <xsl:when test="@value-prefix">
+              <xsl:value-of select="@value-prefix"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@name"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+      <xsl:for-each select="tp:flag">
+        <dt xmlns="http://www.w3.org/1999/xhtml"><code><xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/></code></dt>
+        <xsl:choose>
+          <xsl:when test="tp:docstring">
+            <dd xmlns="http://www.w3.org/1999/xhtml"><xsl:apply-templates select="tp:docstring" /></dd>
+          </xsl:when>
+          <xsl:otherwise>
+            <dd xmlns="http://www.w3.org/1999/xhtml">(Undocumented)</dd>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:for-each>
+    </dl>
+  </xsl:template>
+
+  <xsl:template match="tp:enum">
+    <h3 xmlns="http://www.w3.org/1999/xhtml">
+      <a name="type-{@name}">
+        <xsl:value-of select="@name"/>
+      </a>
+    </h3>
+    <xsl:apply-templates select="tp:docstring" />
+    <dl xmlns="http://www.w3.org/1999/xhtml">
+        <xsl:variable name="value-prefix">
+          <xsl:choose>
+            <xsl:when test="@value-prefix">
+              <xsl:value-of select="@value-prefix"/>
+            </xsl:when>
+            <xsl:otherwise>
+              <xsl:value-of select="@name"/>
+            </xsl:otherwise>
+          </xsl:choose>
+        </xsl:variable>
+      <xsl:for-each select="tp:enumvalue">
+        <dt xmlns="http://www.w3.org/1999/xhtml"><code><xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/></code></dt>
+        <xsl:choose>
+          <xsl:when test="tp:docstring">
+            <dd xmlns="http://www.w3.org/1999/xhtml"><xsl:apply-templates select="tp:docstring" /></dd>
+          </xsl:when>
+          <xsl:otherwise>
+            <dd xmlns="http://www.w3.org/1999/xhtml">(Undocumented)</dd>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:for-each>
+    </dl>
+  </xsl:template>
+
+  <xsl:template match="tp:property">
+    <dt xmlns="http://www.w3.org/1999/xhtml">
+      <xsl:if test="@name">
+        <code><xsl:value-of select="@name"/></code> -
+      </xsl:if>
+      <code><xsl:value-of select="@type"/></code>
+    </dt>
+    <dd xmlns="http://www.w3.org/1999/xhtml">
+      <xsl:apply-templates select="tp:docstring"/>
+    </dd>
+  </xsl:template>
+
+  <xsl:template match="tp:mapping">
+    <div xmlns="http://www.w3.org/1999/xhtml" class="struct">
+      <h3>
+        <a name="type-{@name}">
+          <xsl:value-of select="@name"/>
+        </a> - a{
+        <xsl:for-each select="tp:member">
+          <xsl:value-of select="@type"/>
+          <xsl:text>: </xsl:text>
+          <xsl:value-of select="@name"/>
+          <xsl:if test="position() != last()"> &#x2192; </xsl:if>
+        </xsl:for-each>
+        }
+      </h3>
+      <div class="docstring">
+        <xsl:apply-templates select="tp:docstring"/>
+      </div>
+      <div>
+        <h4>Members</h4>
+        <dl>
+          <xsl:apply-templates select="tp:member" mode="members-in-docstring"/>
+        </dl>
+      </div>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="tp:docstring" mode="in-index"/>
+
+  <xsl:template match="tp:simple-type | tp:enum | tp:flags | tp:external-type"
+    mode="in-index">
+    - <xsl:value-of select="@type"/>
+  </xsl:template>
+
+  <xsl:template match="tp:simple-type">
+    <div xmlns="http://www.w3.org/1999/xhtml" class="simple-type">
+      <h3>
+        <a name="type-{@name}">
+          <xsl:value-of select="@name"/>
+        </a> - <xsl:value-of select="@type"/>
+      </h3>
+      <div class="docstring">
+        <xsl:apply-templates select="tp:docstring"/>
+      </div>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="tp:external-type">
+    <div xmlns="http://www.w3.org/1999/xhtml" class="external-type">
+      <dt>
+        <a name="type-{@name}">
+          <xsl:value-of select="@name"/>
+        </a> - <xsl:value-of select="@type"/>
+      </dt>
+      <dd>Defined by: <xsl:value-of select="@from"/></dd>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="tp:struct" mode="in-index">
+    - ( <xsl:for-each select="tp:member">
+          <xsl:value-of select="@type"/>
+          <xsl:if test="position() != last()">, </xsl:if>
+        </xsl:for-each> )
+  </xsl:template>
+
+  <xsl:template match="tp:mapping" mode="in-index">
+    - a{ <xsl:for-each select="tp:member">
+          <xsl:value-of select="@type"/>
+          <xsl:if test="position() != last()"> &#x2192; </xsl:if>
+        </xsl:for-each> }
+  </xsl:template>
+
+  <xsl:template match="tp:struct">
+    <div xmlns="http://www.w3.org/1999/xhtml" class="struct">
+      <h3>
+        <a name="type-{@name}">
+          <xsl:value-of select="@name"/>
+        </a> - (
+        <xsl:for-each select="tp:member">
+          <xsl:value-of select="@type"/>
+          <xsl:text>: </xsl:text>
+          <xsl:value-of select="@name"/>
+          <xsl:if test="position() != last()">, </xsl:if>
+        </xsl:for-each>
+        )
+      </h3>
+      <div class="docstring">
+        <xsl:apply-templates select="tp:docstring"/>
+      </div>
+      <xsl:choose>
+        <xsl:when test="string(@array-name) != ''">
+          <p>In bindings that need a separate name, arrays of
+            <xsl:value-of select="@name"/> should be called
+            <xsl:value-of select="@array-name"/>.</p>
+        </xsl:when>
+        <xsl:otherwise>
+          <p>Arrays of <xsl:value-of select="@name"/> don't generally
+            make sense.</p>
+        </xsl:otherwise>
+      </xsl:choose>
+      <div>
+        <h4>Members</h4>
+        <dl>
+          <xsl:apply-templates select="tp:member" mode="members-in-docstring"/>
+        </dl>
+      </div>
+    </div>
+  </xsl:template>
+
+  <xsl:template match="method">
+    <div xmlns="http://www.w3.org/1999/xhtml" class="method">
+      <h3 xmlns="http://www.w3.org/1999/xhtml">
+        <a name="{concat(../@name, concat('.', @name))}">
+          <xsl:value-of select="@name"/>
+        </a> (
+        <xsl:for-each xmlns="" select="arg[@direction='in']">
+          <xsl:value-of select="@type"/>: <xsl:value-of select="@name"/>
+          <xsl:if test="position() != last()">, </xsl:if>
+        </xsl:for-each>
+        ) &#x2192;
+        <xsl:choose>
+          <xsl:when test="arg[@direction='out']">
+            <xsl:for-each xmlns="" select="arg[@direction='out']">
+              <xsl:value-of select="@type"/>
+              <xsl:if test="position() != last()">, </xsl:if>
+            </xsl:for-each>
+          </xsl:when>
+          <xsl:otherwise>nothing</xsl:otherwise>
+        </xsl:choose>
+      </h3>
+      <div xmlns="http://www.w3.org/1999/xhtml" class="docstring">
+        <xsl:apply-templates select="tp:docstring" />
+      </div>
+
+      <xsl:if test="arg[@direction='in']">
+        <div xmlns="http://www.w3.org/1999/xhtml">
+          <h4>Parameters</h4>
+          <dl xmlns="http://www.w3.org/1999/xhtml">
+            <xsl:apply-templates select="arg[@direction='in']"
+              mode="parameters-in-docstring"/>
+          </dl>
+        </div>
+      </xsl:if>
+
+      <xsl:if test="arg[@direction='out']">
+        <div xmlns="http://www.w3.org/1999/xhtml">
+          <h4>Returns</h4>
+          <dl xmlns="http://www.w3.org/1999/xhtml">
+            <xsl:apply-templates select="arg[@direction='out']"
+              mode="returns-in-docstring"/>
+          </dl>
+        </div>
+      </xsl:if>
+
+      <xsl:if test="tp:possible-errors">
+        <div xmlns="http://www.w3.org/1999/xhtml">
+          <h4>Possible errors</h4>
+          <dl xmlns="http://www.w3.org/1999/xhtml">
+            <xsl:apply-templates select="tp:possible-errors/tp:error"/>
+          </dl>
+        </div>
+      </xsl:if>
+
+    </div>
+  </xsl:template>
+
+  <xsl:template name="parenthesized-tp-type">
+    <xsl:if test="@tp:type">
+      <xsl:variable name="tp-type" select="@tp:type"/>
+      <xsl:variable name="single-type">
+        <xsl:choose>
+          <xsl:when test="contains($tp-type, '[]')">
+            <xsl:value-of select="substring-before($tp-type, '[]')"/>
+          </xsl:when>
+          <xsl:otherwise>
+            <xsl:value-of select="$tp-type"/>
+          </xsl:otherwise>
+        </xsl:choose>
+      </xsl:variable>
+      <xsl:choose>
+        <xsl:when test="//tp:simple-type[@name=$tp-type]" />
+        <xsl:when test="//tp:simple-type[concat(@name, '[]')=$tp-type]" />
+        <xsl:when test="//tp:struct[concat(@name, '[]')=$tp-type][string(@array-name) != '']" />
+        <xsl:when test="//tp:struct[@name=$tp-type]" />
+        <xsl:when test="//tp:enum[@name=$tp-type]" />
+        <xsl:when test="//tp:enum[concat(@name, '[]')=$tp-type]" />
+        <xsl:when test="//tp:flags[@name=$tp-type]" />
+        <xsl:when test="//tp:flags[concat(@name, '[]')=$tp-type]" />
+        <xsl:when test="//tp:mapping[@name=$tp-type]" />
+        <xsl:when test="//tp:external-type[concat(@name, '[]')=$tp-type]" />
+        <xsl:when test="//tp:external-type[@name=$tp-type]" />
+        <xsl:otherwise>
+          <xsl:message terminate="yes">
+            <xsl:text>ERR: Unable to find type '</xsl:text>
+            <xsl:value-of select="$tp-type"/>
+            <xsl:text>'&#10;</xsl:text>
+          </xsl:message>
+        </xsl:otherwise>
+      </xsl:choose>
+      (<a href="#type-{$single-type}"><xsl:value-of select="$tp-type"/></a>)
+    </xsl:if>
+  </xsl:template>
+
+  <xsl:template match="tp:member" mode="members-in-docstring">
+    <dt xmlns="http://www.w3.org/1999/xhtml">
+      <code><xsl:value-of select="@name"/></code> -
+      <code><xsl:value-of select="@type"/></code>
+      <xsl:call-template name="parenthesized-tp-type"/>
+    </dt>
+    <dd xmlns="http://www.w3.org/1999/xhtml">
+      <xsl:choose>
+        <xsl:when test="tp:docstring">
+          <xsl:apply-templates select="tp:docstring" />
+        </xsl:when>
+        <xsl:otherwise>
+          <em>(undocumented)</em>
+        </xsl:otherwise>
+      </xsl:choose>
+    </dd>
+  </xsl:template>
+
+  <xsl:template match="arg" mode="parameters-in-docstring">
+    <dt xmlns="http://www.w3.org/1999/xhtml">
+      <code><xsl:value-of select="@name"/></code> -
+      <code><xsl:value-of select="@type"/></code>
+      <xsl:call-template name="parenthesized-tp-type"/>
+    </dt>
+    <dd xmlns="http://www.w3.org/1999/xhtml">
+      <xsl:apply-templates select="tp:docstring" />
+    </dd>
+  </xsl:template>
+
+  <xsl:template match="arg" mode="returns-in-docstring">
+    <dt xmlns="http://www.w3.org/1999/xhtml">
+      <xsl:if test="@name">
+        <code><xsl:value-of select="@name"/></code> -
+      </xsl:if>
+      <code><xsl:value-of select="@type"/></code>
+      <xsl:call-template name="parenthesized-tp-type"/>
+    </dt>
+    <dd xmlns="http://www.w3.org/1999/xhtml">
+      <xsl:apply-templates select="tp:docstring"/>
+    </dd>
+  </xsl:template>
+
+  <xsl:template match="tp:possible-errors/tp:error">
+    <dt xmlns="http://www.w3.org/1999/xhtml">
+      <code><xsl:value-of select="@name"/></code>
+    </dt>
+    <dd xmlns="http://www.w3.org/1999/xhtml">
+        <xsl:variable name="name" select="@name"/>
+        <xsl:choose>
+          <xsl:when test="tp:docstring">
+            <xsl:apply-templates select="tp:docstring"/>
+          </xsl:when>
+          <xsl:when test="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring">
+            <xsl:apply-templates select="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring"/> <em xmlns="http://www.w3.org/1999/xhtml">(generic description)</em>
+          </xsl:when>
+          <xsl:otherwise>
+            (Undocumented.)
+          </xsl:otherwise>
+        </xsl:choose>
+    </dd>
+  </xsl:template>
+
+  <xsl:template match="signal">
+    <div xmlns="http://www.w3.org/1999/xhtml" class="signal">
+      <h3 xmlns="http://www.w3.org/1999/xhtml">
+        <a name="{concat(../@name, concat('.', @name))}">
+          <xsl:value-of select="@name"/>
+        </a> (
+        <xsl:for-each xmlns="" select="arg">
+          <xsl:value-of select="@type"/>: <xsl:value-of select="@name"/>
+          <xsl:if test="position() != last()">, </xsl:if>
+        </xsl:for-each>
+        )</h3>
+      <div xmlns="http://www.w3.org/1999/xhtml" class="docstring">
+        <xsl:apply-templates select="tp:docstring"/>
+      </div>
+
+      <xsl:if test="arg">
+        <div xmlns="http://www.w3.org/1999/xhtml">
+          <h4>Parameters</h4>
+          <dl xmlns="http://www.w3.org/1999/xhtml">
+            <xsl:apply-templates select="arg" mode="parameters-in-docstring"/>
+          </dl>
+        </div>
+      </xsl:if>
+    </div>
+  </xsl:template>
+
+  <xsl:output method="xml" indent="no" encoding="ascii"
+    omit-xml-declaration="yes"
+    doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" />
+
+  <xsl:template match="/tp:spec">
+    <html xmlns="http://www.w3.org/1999/xhtml">
+      <head>
+        <title>
+          <xsl:value-of select="tp:title"/>
+          <xsl:if test="tp:version">
+            <xsl:text> version </xsl:text>
+            <xsl:value-of select="tp:version"/>
+          </xsl:if>
+        </title>
+        <style type="text/css">
+
+          body {
+            font-family: sans-serif;
+            margin: 2em;
+            height: 100%;
+            font-size: 1.2em;
+          }
+          h1 {
+            padding-top: 5px;
+            padding-bottom: 5px;
+            font-size: 1.6em;
+            background: #dadae2;
+          }
+          h2 {
+            font-size: 1.3em;
+          }
+          h3 {
+            font-size: 1.2em;
+          }
+          a:link, a:visited, a:link:hover, a:visited:hover {
+            font-weight: bold;
+          }
+          .topbox {
+            padding-top: 10px;
+            padding-left: 10px;
+            border-bottom: black solid 1px;
+            padding-bottom: 10px;
+            background: #dadae2;
+            font-size: 2em;
+            font-weight: bold;
+            color: #5c5c5c;
+          }
+          .topnavbox {
+            padding-left: 10px;
+            padding-top: 5px;
+            padding-bottom: 5px;
+            background: #abacba;
+            border-bottom: black solid 1px;
+            font-size: 1.2em;
+          }
+          .topnavbox a{
+            color: black;
+            font-weight: normal;
+          }
+          .sidebar {
+            float: left;
+            /* width:9em;
+            border-right:#abacba solid 1px;
+            border-left: #abacba solid 1px;
+            height:100%; */
+            border: #abacba solid 1px;
+            padding-left: 10px;
+            margin-left: 10px;
+            padding-right: 10px;
+            margin-right: 10px;
+            color: #5d5d5d;
+            background: #dadae2;
+          }
+          .sidebar a {
+            text-decoration: none;
+            border-bottom: #e29625 dotted 1px;
+            color: #e29625;
+            font-weight: normal;
+          }
+          .sidebar h1 {
+            font-size: 1.2em;
+            color: black;
+          }
+          .sidebar ul {
+            padding-left: 25px;
+            padding-bottom: 10px;
+            border-bottom: #abacba solid 1px;
+          }
+          .sidebar li {
+            padding-top: 2px;
+            padding-bottom: 2px;
+          }
+          .sidebar h2 {
+            font-style:italic;
+            font-size: 0.81em;
+            padding-left: 5px;
+            padding-right: 5px;
+            font-weight: normal;
+          }
+          .date {
+            font-size: 0.6em;
+            float: right;
+            font-style: italic;
+          }
+          .method {
+            margin-left: 1em;
+            margin-right: 4em;
+          }
+          .signal {
+            margin-left: 1em;
+            margin-right: 4em;
+          }
+
+        </style>
+      </head>
+      <body>
+        <h1 class="topbox">
+          <xsl:value-of select="tp:title" />
+        </h1>
+        <xsl:if test="tp:version">
+          <h2>Version <xsl:apply-templates select="tp:version"/></h2>
+        </xsl:if>
+        <xsl:apply-templates select="tp:copyright"/>
+        <xsl:apply-templates select="tp:license"/>
+        <xsl:apply-templates select="tp:docstring"/>
+
+        <h2>Interfaces</h2>
+        <ul>
+        <xsl:for-each select="node/interface">
+            <li><code><a href="#{@name}"><xsl:value-of select="@name"/></a></code></li>
+          </xsl:for-each>
+        </ul>
+
+        <xsl:apply-templates select="node"/>
+        <xsl:apply-templates select="tp:generic-types"/>
+        <xsl:apply-templates select="tp:errors"/>
+
+        <h1>Index</h1>
+        <h2>Index of interfaces</h2>
+        <ul>
+        <xsl:for-each select="node/interface">
+            <li><code><a href="#{@name}"><xsl:value-of select="@name"/></a></code></li>
+          </xsl:for-each>
+        </ul>
+        <h2>Index of types</h2>
+        <ul>
+          <xsl:for-each select="//tp:simple-type | //tp:enum | //tp:flags | //tp:mapping | //tp:struct | //tp:external-type">
+            <xsl:sort select="@name"/>
+            <li>
+              <code>
+                <a href="#type-{@name}">
+                  <xsl:value-of select="@name"/>
+                </a>
+              </code>
+              <xsl:apply-templates mode="in-index" select="."/>
+            </li>
+          </xsl:for-each>
+        </ul>
+      </body>
+    </html>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et: -->
diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py
new file mode 100644 (file)
index 0000000..4ff78cd
--- /dev/null
@@ -0,0 +1,1126 @@
+#!/usr/bin/python
+
+# glib-client-gen.py: "I Can't Believe It's Not dbus-binding-tool"
+#
+# Generate GLib client wrappers from the Telepathy specification.
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2006-2008 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+import sys
+import os.path
+import xml.dom.minidom
+from getopt import gnu_getopt
+
+from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
+        camelcase_to_lower, get_docstring, xml_escape
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+class Generator(object):
+
+    def __init__(self, dom, prefix, basename, opts):
+        self.dom = dom
+        self.__header = []
+        self.__body = []
+
+        self.prefix_lc = prefix.lower()
+        self.prefix_uc = prefix.upper()
+        self.prefix_mc = prefix.replace('_', '')
+        self.basename = basename
+        self.group = opts.get('--group', None)
+        self.iface_quark_prefix = opts.get('--iface-quark-prefix', None)
+        self.proxy_cls = opts.get('--subclass', 'TpProxy') + ' *'
+        self.proxy_arg = opts.get('--subclass', 'void') + ' *'
+        self.proxy_assert = opts.get('--subclass-assert', 'TP_IS_PROXY')
+        self.proxy_doc = ('A #%s or subclass'
+            % opts.get('--subclass', 'TpProxy'))
+        if self.proxy_arg == 'void *':
+            self.proxy_arg = 'gpointer '
+
+    def h(self, s):
+        self.__header.append(s)
+
+    def b(self, s):
+        self.__body.append(s)
+
+    def get_iface_quark(self):
+        assert self.iface_dbus is not None
+        assert self.iface_uc is not None
+        if self.iface_quark_prefix is None:
+            return 'g_quark_from_static_string (\"%s\")' % self.iface_dbus
+        else:
+            return '%s_%s' % (self.iface_quark_prefix, self.iface_uc)
+
+    def do_signal(self, iface, signal):
+        iface_lc = iface.lower()
+
+        member = signal.getAttribute('name')
+        member_lc = camelcase_to_lower(member)
+        member_uc = member_lc.upper()
+
+        arg_count = 0
+        args = []
+        out_args = []
+
+        for arg in signal.getElementsByTagName('arg'):
+            name = arg.getAttribute('name')
+            type = arg.getAttribute('type')
+            tp_type = arg.getAttribute('tp:type')
+
+            if not name:
+                name = 'arg%u' % arg_count
+                arg_count += 1
+            else:
+                name = 'arg_%s' % name
+
+            info = type_to_gtype(type)
+            args.append((name, info, tp_type, arg))
+
+        callback_name = ('%s_%s_signal_callback_%s'
+                         % (self.prefix_lc, iface_lc, member_lc))
+        collect_name = ('_%s_%s_collect_args_of_%s'
+                        % (self.prefix_lc, iface_lc, member_lc))
+        invoke_name = ('_%s_%s_invoke_callback_for_%s'
+                       % (self.prefix_lc, iface_lc, member_lc))
+
+        # Example:
+        #
+        # typedef void (*tp_cli_connection_signal_callback_new_channel)
+        #   (TpConnection *proxy, const gchar *arg_object_path,
+        #   const gchar *arg_channel_type, guint arg_handle_type,
+        #   guint arg_handle, gboolean arg_suppress_handler,
+        #   gpointer user_data, GObject *weak_object);
+
+        self.b('/**')
+        self.b(' * %s:' % callback_name)
+        self.b(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
+               % (self.prefix_lc, iface_lc, member_lc))
+        self.b(' *  was called')
+
+        for arg in args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b(' * @%s: %s' % (name,
+                xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+        self.b(' * @user_data: User-supplied data')
+        self.b(' * @weak_object: User-supplied weakly referenced object')
+        self.b(' *')
+        self.b(' * Represents the signature of a callback for the signal %s.'
+               % member)
+        self.b(' */')
+        self.h('typedef void (*%s) (%sproxy,'
+               % (callback_name, self.proxy_cls))
+
+        for arg in args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            const = pointer and 'const ' or ''
+
+            self.h('    %s%s%s,' % (const, ctype, name))
+
+        self.h('    gpointer user_data, GObject *weak_object);')
+
+        if args:
+            self.b('static void')
+            self.b('%s (DBusGProxy *proxy,' % collect_name)
+
+            for arg in args:
+                name, info, tp_type, elt = arg
+                ctype, gtype, marshaller, pointer = info
+
+                const = pointer and 'const ' or ''
+
+                self.b('    %s%s%s,' % (const, ctype, name))
+
+            self.b('    TpProxySignalConnection *sc)')
+            self.b('{')
+            self.b('  GValueArray *args = g_value_array_new (%d);' % len(args))
+            self.b('  GValue blank = { 0 };')
+            self.b('  guint i;')
+            self.b('')
+            self.b('  g_value_init (&blank, G_TYPE_INT);')
+            self.b('')
+            self.b('  for (i = 0; i < %d; i++)' % len(args))
+            self.b('    g_value_array_append (args, &blank);')
+            self.b('')
+
+            for i, arg in enumerate(args):
+                name, info, tp_type, elt = arg
+                ctype, gtype, marshaller, pointer = info
+
+                self.b('  g_value_unset (args->values + %d);' % i)
+                self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))
+
+                if gtype == 'G_TYPE_STRING':
+                    self.b('  g_value_set_string (args->values + %d, %s);'
+                           % (i, name))
+                elif marshaller == 'BOXED':
+                    self.b('  g_value_set_boxed (args->values + %d, %s);'
+                           % (i, name))
+                elif gtype == 'G_TYPE_UCHAR':
+                    self.b('  g_value_set_uchar (args->values + %d, %s);'
+                           % (i, name))
+                elif gtype == 'G_TYPE_BOOLEAN':
+                    self.b('  g_value_set_boolean (args->values + %d, %s);'
+                           % (i, name))
+                elif gtype == 'G_TYPE_INT':
+                    self.b('  g_value_set_int (args->values + %d, %s);'
+                           % (i, name))
+                elif gtype == 'G_TYPE_UINT':
+                    self.b('  g_value_set_uint (args->values + %d, %s);'
+                           % (i, name))
+                elif gtype == 'G_TYPE_INT64':
+                    self.b('  g_value_set_int (args->values + %d, %s);'
+                           % (i, name))
+                elif gtype == 'G_TYPE_UINT64':
+                    self.b('  g_value_set_uint (args->values + %d, %s);'
+                           % (i, name))
+                elif gtype == 'G_TYPE_DOUBLE':
+                    self.b('  g_value_set_double (args->values + %d, %s);'
+                           % (i, name))
+                else:
+                    assert False, ("Don't know how to put %s in a GValue"
+                                   % gtype)
+                self.b('')
+
+            self.b('  tp_proxy_signal_connection_v0_take_results (sc, args);')
+            self.b('}')
+
+        self.b('static void')
+        self.b('%s (TpProxy *tpproxy,' % invoke_name)
+        self.b('    GError *error,')
+        self.b('    GValueArray *args,')
+        self.b('    GCallback generic_callback,')
+        self.b('    gpointer user_data,')
+        self.b('    GObject *weak_object)')
+        self.b('{')
+        self.b('  %s callback =' % callback_name)
+        self.b('      (%s) generic_callback;' % callback_name)
+        self.b('')
+        self.b('  if (callback != NULL)')
+        self.b('    callback (g_object_ref (tpproxy),')
+
+        # FIXME: factor out into a function
+        for i, arg in enumerate(args):
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            if marshaller == 'BOXED':
+                self.b('      g_value_get_boxed (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_STRING':
+                self.b('      g_value_get_string (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_UCHAR':
+                self.b('      g_value_get_uchar (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_BOOLEAN':
+                self.b('      g_value_get_boolean (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_UINT':
+                self.b('      g_value_get_uint (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_INT':
+                self.b('      g_value_get_int (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_UINT64':
+                self.b('      g_value_get_uint64 (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_INT64':
+                self.b('      g_value_get_int64 (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_DOUBLE':
+                self.b('      g_value_get_double (args->values + %d),' % i)
+            else:
+                assert False, "Don't know how to get %s from a GValue" % gtype
+
+        self.b('      user_data,')
+        self.b('      weak_object);')
+        self.b('')
+
+        if len(args) > 0:
+            self.b('  g_value_array_free (args);')
+        else:
+            self.b('  if (args != NULL)')
+            self.b('    g_value_array_free (args);')
+            self.b('')
+
+        self.b('  g_object_unref (tpproxy);')
+        self.b('}')
+
+        # Example:
+        #
+        # TpProxySignalConnection *
+        #   tp_cli_connection_connect_to_new_channel
+        #   (TpConnection *proxy,
+        #   tp_cli_connection_signal_callback_new_channel callback,
+        #   gpointer user_data,
+        #   GDestroyNotify destroy);
+        #
+        # destroy is invoked when the signal becomes disconnected. This
+        # is either because the signal has been disconnected explicitly
+        # by the user, because the TpProxy has become invalid and
+        # emitted the 'invalidated' signal, or because the weakly referenced
+        # object has gone away.
+
+        self.b('/**')
+        self.b(' * %s_%s_connect_to_%s:'
+               % (self.prefix_lc, iface_lc, member_lc))
+        self.b(' * @proxy: %s' % self.proxy_doc)
+        self.b(' * @callback: Callback to be called when the signal is')
+        self.b(' *   received')
+        self.b(' * @user_data: User-supplied data for the callback')
+        self.b(' * @destroy: Destructor for the user-supplied data, which')
+        self.b(' *   will be called when this signal is disconnected, or')
+        self.b(' *   before this function returns %NULL')
+        self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
+        self.b(' *   if it is destroyed, this callback will automatically be')
+        self.b(' *   disconnected')
+        self.b(' * @error: If not %NULL, used to raise an error if %NULL is')
+        self.b(' *   returned')
+        self.b(' *')
+        self.b(' * Connect a handler to the signal %s.' % member)
+        self.b(' *')
+        self.b(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
+        self.b(' *')
+        self.b(' * Returns: a #TpProxySignalConnection containing all of the')
+        self.b(' * above, which can be used to disconnect the signal; or')
+        self.b(' * %NULL if the proxy does not have the desired interface')
+        self.b(' * or has become invalid.')
+        self.b(' */')
+        self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,'
+               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+        self.h('    %s callback,' % callback_name)
+        self.h('    gpointer user_data,')
+        self.h('    GDestroyNotify destroy,')
+        self.h('    GObject *weak_object,')
+        self.h('    GError **error);')
+
+        self.b('TpProxySignalConnection *')
+        self.b('%s_%s_connect_to_%s (%sproxy,'
+               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+        self.b('    %s callback,' % callback_name)
+        self.b('    gpointer user_data,')
+        self.b('    GDestroyNotify destroy,')
+        self.b('    GObject *weak_object,')
+        self.b('    GError **error)')
+        self.b('{')
+        self.b('  GType expected_types[%d] = {' % (len(args) + 1))
+
+        for arg in args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b('      %s,' % gtype)
+
+        self.b('      G_TYPE_INVALID };')
+        self.b('')
+        self.b('  g_return_val_if_fail (%s (proxy), NULL);'
+               % self.proxy_assert)
+        self.b('  g_return_val_if_fail (callback != NULL, NULL);')
+        self.b('')
+        self.b('  return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,')
+        self.b('      %s, \"%s\",' % (self.get_iface_quark(), member))
+        self.b('      expected_types,')
+
+        if args:
+            self.b('      G_CALLBACK (%s),' % collect_name)
+        else:
+            self.b('      NULL, /* no args => no collector function */')
+
+        self.b('      %s,' % invoke_name)
+        self.b('      G_CALLBACK (callback), user_data, destroy,')
+        self.b('      weak_object, error);')
+        self.b('}')
+        self.b('')
+
+        self.h('')
+
+    def do_method(self, iface, method):
+        iface_lc = iface.lower()
+
+        member = method.getAttribute('name')
+        member_lc = camelcase_to_lower(member)
+        member_uc = member_lc.upper()
+
+        in_count = 0
+        ret_count = 0
+        in_args = []
+        out_args = []
+
+        for arg in method.getElementsByTagName('arg'):
+            name = arg.getAttribute('name')
+            direction = arg.getAttribute('direction')
+            type = arg.getAttribute('type')
+            tp_type = arg.getAttribute('tp:type')
+
+            if direction != 'out':
+                if not name:
+                    name = 'in%u' % in_count
+                    in_count += 1
+                else:
+                    name = 'in_%s' % name
+            else:
+                if not name:
+                    name = 'out%u' % ret_count
+                    ret_count += 1
+                else:
+                    name = 'out_%s' % name
+
+            info = type_to_gtype(type)
+            if direction != 'out':
+                in_args.append((name, info, tp_type, arg))
+            else:
+                out_args.append((name, info, tp_type, arg))
+
+        # Async reply callback type
+
+        # Example:
+        # void (*tp_cli_properties_interface_callback_for_get_properties)
+        #   (TpProxy *proxy,
+        #       const GPtrArray *out0,
+        #       const GError *error,
+        #       gpointer user_data,
+        #       GObject *weak_object);
+
+        self.b('/**')
+        self.b(' * %s_%s_callback_for_%s:'
+               % (self.prefix_lc, iface_lc, member_lc))
+        self.b(' * @proxy: the proxy on which the call was made')
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b(' * @%s: Used to return an \'out\' argument if @error is '
+                   '%%NULL: %s'
+                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+        self.b(' * @error: %NULL on success, or an error on failure')
+        self.b(' * @user_data: user-supplied data')
+        self.b(' * @weak_object: user-supplied object')
+        self.b(' *')
+        self.b(' * Signature of the callback called when a %s method call'
+               % member)
+        self.b(' * succeeds or fails.')
+        self.b(' */')
+
+        callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
+                                                   member_lc)
+
+        self.h('typedef void (*%s) (%sproxy,'
+               % (callback_name, self.proxy_cls))
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+            const = pointer and 'const ' or ''
+
+            self.h('    %s%s%s,' % (const, ctype, name))
+
+        self.h('    const GError *error, gpointer user_data,')
+        self.h('    GObject *weak_object);')
+        self.h('')
+
+        # Async callback implementation
+
+        invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc,
+                                                         iface_lc,
+                                                         member_lc)
+
+        collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc,
+                                                           iface_lc,
+                                                           member_lc)
+
+        # The callback called by dbus-glib; this ends the call and collects
+        # the results into a GValueArray.
+        self.b('static void')
+        self.b('%s (DBusGProxy *proxy,' % collect_callback)
+        self.b('    DBusGProxyCall *call,')
+        self.b('    gpointer user_data)')
+        self.b('{')
+        self.b('  GError *error = NULL;')
+
+        if len(out_args) > 0:
+            self.b('  GValueArray *args;')
+            self.b('  GValue blank = { 0 };')
+            self.b('  guint i;')
+
+            for arg in out_args:
+                name, info, tp_type, elt = arg
+                ctype, gtype, marshaller, pointer = info
+
+                # "We handle variants specially; the caller is expected to
+                # have already allocated storage for them". Thanks,
+                # dbus-glib...
+                if gtype == 'G_TYPE_VALUE':
+                    self.b('  GValue *%s = g_new0 (GValue, 1);' % name)
+                else:
+                    self.b('  %s%s;' % (ctype, name))
+
+        self.b('')
+        self.b('  dbus_g_proxy_end_call (proxy, call, &error,')
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            if gtype == 'G_TYPE_VALUE':
+                self.b('      %s, %s,' % (gtype, name))
+            else:
+                self.b('      %s, &%s,' % (gtype, name))
+
+        self.b('      G_TYPE_INVALID);')
+
+        if len(out_args) == 0:
+            self.b('  tp_proxy_pending_call_v0_take_results (user_data, error,'
+                   'NULL);')
+        else:
+            self.b('')
+            self.b('  if (error != NULL)')
+            self.b('    {')
+            self.b('      tp_proxy_pending_call_v0_take_results (user_data, error,')
+            self.b('          NULL);')
+
+            for arg in out_args:
+                name, info, tp_type, elt = arg
+                ctype, gtype, marshaller, pointer = info
+                if gtype == 'G_TYPE_VALUE':
+                    self.b('      g_free (%s);' % name)
+
+            self.b('      return;')
+            self.b('    }')
+            self.b('')
+            self.b('  args = g_value_array_new (%d);' % len(out_args))
+            self.b('  g_value_init (&blank, G_TYPE_INT);')
+            self.b('')
+            self.b('  for (i = 0; i < %d; i++)' % len(out_args))
+            self.b('    g_value_array_append (args, &blank);')
+
+            for i, arg in enumerate(out_args):
+                name, info, tp_type, elt = arg
+                ctype, gtype, marshaller, pointer = info
+
+                self.b('')
+                self.b('  g_value_unset (args->values + %d);' % i)
+                self.b('  g_value_init (args->values + %d, %s);' % (i, gtype))
+
+                if gtype == 'G_TYPE_STRING':
+                    self.b('  g_value_take_string (args->values + %d, %s);'
+                           % (i, name))
+                elif marshaller == 'BOXED':
+                    self.b('  g_value_take_boxed (args->values + %d, %s);'
+                            % (i, name))
+                elif gtype == 'G_TYPE_UCHAR':
+                    self.b('  g_value_set_uchar (args->values + %d, %s);'
+                            % (i, name))
+                elif gtype == 'G_TYPE_BOOLEAN':
+                    self.b('  g_value_set_boolean (args->values + %d, %s);'
+                            % (i, name))
+                elif gtype == 'G_TYPE_INT':
+                    self.b('  g_value_set_int (args->values + %d, %s);'
+                            % (i, name))
+                elif gtype == 'G_TYPE_UINT':
+                    self.b('  g_value_set_uint (args->values + %d, %s);'
+                            % (i, name))
+                elif gtype == 'G_TYPE_INT64':
+                    self.b('  g_value_set_int (args->values + %d, %s);'
+                            % (i, name))
+                elif gtype == 'G_TYPE_UINT64':
+                    self.b('  g_value_set_uint (args->values + %d, %s);'
+                            % (i, name))
+                elif gtype == 'G_TYPE_DOUBLE':
+                    self.b('  g_value_set_double (args->values + %d, %s);'
+                            % (i, name))
+                else:
+                    assert False, ("Don't know how to put %s in a GValue"
+                                   % gtype)
+
+            self.b('  tp_proxy_pending_call_v0_take_results (user_data, '
+                   'NULL, args);')
+
+        self.b('}')
+
+        self.b('static void')
+        self.b('%s (TpProxy *self,' % invoke_callback)
+        self.b('    GError *error,')
+        self.b('    GValueArray *args,')
+        self.b('    GCallback generic_callback,')
+        self.b('    gpointer user_data,')
+        self.b('    GObject *weak_object)')
+        self.b('{')
+        self.b('  %s callback = (%s) generic_callback;'
+               % (callback_name, callback_name))
+        self.b('')
+        self.b('  if (error != NULL)')
+        self.b('    {')
+        self.b('      callback ((%s) self,' % self.proxy_cls)
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            if marshaller == 'BOXED' or pointer:
+                self.b('          NULL,')
+            elif gtype == 'G_TYPE_DOUBLE':
+                self.b('          0.0,')
+            else:
+                self.b('          0,')
+
+        self.b('          error, user_data, weak_object);')
+        self.b('      g_error_free (error);')
+        self.b('      return;')
+        self.b('    }')
+
+        self.b('  callback ((%s) self,' % self.proxy_cls)
+
+        # FIXME: factor out into a function
+        for i, arg in enumerate(out_args):
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            if marshaller == 'BOXED':
+                self.b('      g_value_get_boxed (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_STRING':
+                self.b('      g_value_get_string (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_UCHAR':
+                self.b('      g_value_get_uchar (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_BOOLEAN':
+                self.b('      g_value_get_boolean (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_UINT':
+                self.b('      g_value_get_uint (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_INT':
+                self.b('      g_value_get_int (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_UINT64':
+                self.b('      g_value_get_uint64 (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_INT64':
+                self.b('      g_value_get_int64 (args->values + %d),' % i)
+            elif gtype == 'G_TYPE_DOUBLE':
+                self.b('      g_value_get_double (args->values + %d),' % i)
+            else:
+                assert False, "Don't know how to get %s from a GValue" % gtype
+
+        self.b('      error, user_data, weak_object);')
+        self.b('')
+
+        if len(out_args) > 0:
+            self.b('  g_value_array_free (args);')
+        else:
+            self.b('  if (args != NULL)')
+            self.b('    g_value_array_free (args);')
+
+        self.b('}')
+        self.b('')
+
+        # Async stub
+
+        # Example:
+        # TpProxyPendingCall *
+        #   tp_cli_properties_interface_call_get_properties
+        #   (gpointer proxy,
+        #   gint timeout_ms,
+        #   const GArray *in_properties,
+        #   tp_cli_properties_interface_callback_for_get_properties callback,
+        #   gpointer user_data,
+        #   GDestroyNotify *destructor);
+
+        self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,'
+               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+        self.h('    gint timeout_ms,')
+
+        self.b('/**')
+        self.b(' * %s_%s_call_%s:'
+               % (self.prefix_lc, iface_lc, member_lc))
+        self.b(' * @proxy: the #TpProxy')
+        self.b(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
+        self.b(' *   default')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b(' * @%s: Used to pass an \'in\' argument: %s'
+                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+        self.b(' * @callback: called when the method call succeeds or fails')
+        self.b(' * @user_data: user-supplied data passed to the callback')
+        self.b(' * @destroy: called with the user_data as argument, after the')
+        self.b(' *   call has succeeded, failed or been cancelled')
+        self.b(' * @weak_object: A #GObject which will be weakly referenced; ')
+        self.b(' *   if it is destroyed, this callback will automatically be')
+        self.b(' *   disconnected')
+        self.b(' *')
+        self.b(' * Start a %s method call.' % member)
+        self.b(' *')
+        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
+        self.b(' *')
+        self.b(' * Returns: a #TpProxyPendingCall representing the call in')
+        self.b(' *  progress. It is borrowed from the object, and will become')
+        self.b(' *  invalid when the callback is called, the call is')
+        self.b(' *  cancelled or the #TpProxy becomes invalid.')
+        self.b(' */')
+        self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
+               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+        self.b('    gint timeout_ms,')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            const = pointer and 'const ' or ''
+
+            self.h('    %s%s%s,' % (const, ctype, name))
+            self.b('    %s%s%s,' % (const, ctype, name))
+
+        self.h('    %s callback,' % callback_name)
+        self.h('    gpointer user_data,')
+        self.h('    GDestroyNotify destroy,')
+        self.h('    GObject *weak_object);')
+        self.h('')
+
+        self.b('    %s callback,' % callback_name)
+        self.b('    gpointer user_data,')
+        self.b('    GDestroyNotify destroy,')
+        self.b('    GObject *weak_object)')
+        self.b('{')
+        self.b('  GError *error = NULL;')
+        self.b('  GQuark interface = %s;' % self.get_iface_quark())
+        self.b('  DBusGProxy *iface;')
+        self.b('')
+        self.b('  g_return_val_if_fail (%s (proxy), NULL);'
+               % self.proxy_assert)
+        self.b('')
+        self.b('  iface = tp_proxy_borrow_interface_by_id (')
+        self.b('      (TpProxy *) proxy,')
+        self.b('      interface, &error);')
+        self.b('')
+        self.b('  if (iface == NULL)')
+        self.b('    {')
+        self.b('      if (callback != NULL)')
+        self.b('        callback (proxy,')
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            if pointer:
+                self.b('            NULL,')
+            else:
+                self.b('            0,')
+
+        self.b('            error, user_data, weak_object);')
+        self.b('      return NULL;')
+        self.b('    }')
+        self.b('')
+        self.b('  if (callback == NULL)')
+        self.b('    {')
+        self.b('      dbus_g_proxy_call_no_reply (iface, "%s",' % member)
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            const = pointer and 'const ' or ''
+
+            self.b('          %s, %s,' % (gtype, name))
+
+        self.b('          G_TYPE_INVALID);')
+        self.b('      return NULL;')
+        self.b('    }')
+        self.b('  else')
+        self.b('    {')
+        self.b('      TpProxyPendingCall *data;')
+        self.b('')
+        self.b('      data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
+        self.b('          interface, "%s", iface,' % member)
+        self.b('          %s,' % invoke_callback)
+        self.b('          G_CALLBACK (callback), user_data, destroy,')
+        self.b('          weak_object, FALSE);')
+        self.b('      tp_proxy_pending_call_v0_take_pending_call (data,')
+        self.b('          dbus_g_proxy_begin_call_with_timeout (iface,')
+        self.b('              "%s",' % member)
+        self.b('              %s,' % collect_callback)
+        self.b('              data,')
+        self.b('              tp_proxy_pending_call_v0_completed,')
+        self.b('              timeout_ms,')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            const = pointer and 'const ' or ''
+
+            self.b('              %s, %s,' % (gtype, name))
+
+        self.b('              G_TYPE_INVALID));')
+        self.b('')
+        self.b('      return data;')
+        self.b('    }')
+        self.b('}')
+        self.b('')
+
+        # Reentrant blocking calls
+        # Example:
+        # gboolean tp_cli_properties_interface_run_get_properties
+        #   (gpointer proxy,
+        #       gint timeout_ms,
+        #       const GArray *in_properties,
+        #       GPtrArray **out0,
+        #       GError **error,
+        #       GMainLoop **loop);
+
+        self.b('typedef struct {')
+        self.b('    GMainLoop *loop;')
+        self.b('    GError **error;')
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b('    %s*%s;' % (ctype, name))
+
+        self.b('    gboolean success:1;')
+        self.b('    gboolean completed:1;')
+        self.b('} _%s_%s_run_state_%s;'
+               % (self.prefix_lc, iface_lc, member_lc))
+
+        reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc,
+                                                         iface_lc,
+                                                         member_lc)
+
+        self.b('static void')
+        self.b('%s (TpProxy *self,' % reentrant_invoke)
+        self.b('    GError *error,')
+        self.b('    GValueArray *args,')
+        self.b('    GCallback unused,')
+        self.b('    gpointer user_data,')
+        self.b('    GObject *unused2)')
+        self.b('{')
+        self.b('  _%s_%s_run_state_%s *state = user_data;'
+               % (self.prefix_lc, iface_lc, member_lc))
+        self.b('')
+        self.b('  state->success = (error == NULL);')
+        self.b('  state->completed = TRUE;')
+        self.b('  g_main_loop_quit (state->loop);')
+        self.b('')
+        self.b('  if (error != NULL)')
+        self.b('    {')
+        self.b('      if (state->error != NULL)')
+        self.b('        *state->error = error;')
+        self.b('      else')
+        self.b('        g_error_free (error);')
+        self.b('')
+        self.b('      return;')
+        self.b('    }')
+        self.b('')
+
+        for i, arg in enumerate(out_args):
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b('  if (state->%s != NULL)' % name)
+            if marshaller == 'BOXED':
+                self.b('    *state->%s = g_value_dup_boxed ('
+                       'args->values + %d);' % (name, i))
+            elif marshaller == 'STRING':
+                self.b('    *state->%s = g_value_dup_string '
+                       '(args->values + %d);' % (name, i))
+            elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT',
+                    'INT64', 'UINT64', 'DOUBLE'):
+                self.b('    *state->%s = g_value_get_%s (args->values + %d);'
+                       % (name, marshaller.lower(), i))
+            else:
+                assert False, "Don't know how to copy %s" % gtype
+
+            self.b('')
+
+        if len(out_args) > 0:
+            self.b('  g_value_array_free (args);')
+        else:
+            self.b('  if (args != NULL)')
+            self.b('    g_value_array_free (args);')
+
+        self.b('}')
+        self.b('')
+
+        self.h('gboolean %s_%s_run_%s (%sproxy,'
+               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+        self.h('    gint timeout_ms,')
+
+        self.b('/**')
+        self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
+        self.b(' * @proxy: %s' % self.proxy_doc)
+        self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b(' * @%s: Used to pass an \'in\' argument: %s'
+                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is '
+                   'returned: %s'
+                   % (name, xml_escape(get_docstring(elt) or '(Undocumented)')))
+
+        self.b(' * @error: If not %NULL, used to return errors if %FALSE ')
+        self.b(' *  is returned')
+        self.b(' * @loop: If not %NULL, set before re-entering ')
+        self.b(' *  the main loop, to point to a #GMainLoop ')
+        self.b(' *  which can be used to cancel this call with ')
+        self.b(' *  g_main_loop_quit(), causing a return of ')
+        self.b(' *  %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
+        self.b(' *')
+        self.b(' * Call the method %s and run the main loop' % member)
+        self.b(' * until it returns. Before calling this method, you must')
+        self.b(' * add a reference to any borrowed objects you need to keep,')
+        self.b(' * and generally ensure that everything is in a consistent')
+        self.b(' * state.')
+        self.b(' *')
+        self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
+        self.b(' *')
+        self.b(' * Returns: TRUE on success, FALSE and sets @error on error')
+        self.b(' */')
+        self.b('gboolean\n%s_%s_run_%s (%sproxy,'
+               % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
+        self.b('    gint timeout_ms,')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            const = pointer and 'const ' or ''
+
+            self.h('    %s%s%s,' % (const, ctype, name))
+            self.b('    %s%s%s,' % (const, ctype, name))
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            self.h('    %s*%s,' % (ctype, name))
+            self.b('    %s*%s,' % (ctype, name))
+
+        self.h('    GError **error,')
+        self.h('    GMainLoop **loop);')
+        self.h('')
+
+        self.b('    GError **error,')
+        self.b('    GMainLoop **loop)')
+        self.b('{')
+        self.b('  DBusGProxy *iface;')
+        self.b('  GQuark interface = %s;' % self.get_iface_quark())
+        self.b('  TpProxyPendingCall *pc;')
+        self.b('  _%s_%s_run_state_%s state = {'
+               % (self.prefix_lc, iface_lc, member_lc))
+        self.b('      NULL /* loop */, error,')
+
+        for arg in out_args:
+            name, info, tp_type, elt = arg
+
+            self.b('    %s,' % name)
+
+        self.b('      FALSE /* completed */, FALSE /* success */ };')
+        self.b('')
+        self.b('  g_return_val_if_fail (%s (proxy), FALSE);'
+               % self.proxy_assert)
+        self.b('')
+        self.b('  iface = tp_proxy_borrow_interface_by_id')
+        self.b('       ((TpProxy *) proxy, interface, error);')
+        self.b('')
+        self.b('  if (iface == NULL)')
+        self.b('    return FALSE;')
+        self.b('')
+        self.b('  state.loop = g_main_loop_new (NULL, FALSE);')
+        self.b('')
+        self.b('  pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,')
+        self.b('      interface, "%s", iface,' % member)
+        self.b('      %s,' % reentrant_invoke)
+        self.b('      NULL, &state, NULL, NULL, TRUE);')
+        self.b('')
+        self.b('  if (loop != NULL)')
+        self.b('    *loop = state.loop;')
+        self.b('')
+        self.b('  tp_proxy_pending_call_v0_take_pending_call (pc,')
+        self.b('      dbus_g_proxy_begin_call_with_timeout (iface,')
+        self.b('          "%s",' % member)
+        self.b('          %s,' % collect_callback)
+        self.b('          pc,')
+        self.b('          tp_proxy_pending_call_v0_completed,')
+        self.b('          timeout_ms,')
+
+        for arg in in_args:
+            name, info, tp_type, elt = arg
+            ctype, gtype, marshaller, pointer = info
+
+            const = pointer and 'const ' or ''
+
+            self.b('              %s, %s,' % (gtype, name))
+
+        self.b('          G_TYPE_INVALID));')
+        self.b('')
+        self.b('  if (!state.completed)')
+        self.b('    g_main_loop_run (state.loop);')
+        self.b('')
+        self.b('  if (!state.completed)')
+        self.b('    tp_proxy_pending_call_cancel (pc);')
+        self.b('')
+        self.b('  if (loop != NULL)')
+        self.b('    *loop = NULL;')
+        self.b('')
+        self.b('  g_main_loop_unref (state.loop);')
+        self.b('')
+        self.b('  return state.success;')
+        self.b('}')
+        self.b('')
+
+        # leave a gap for the end of the method
+        self.b('')
+        self.h('')
+
+    def do_signal_add(self, signal):
+        marshaller_items = []
+        gtypes = []
+
+        for i in signal.getElementsByTagName('arg'):
+            name = i.getAttribute('name')
+            type = i.getAttribute('type')
+            info = type_to_gtype(type)
+            # type, GType, STRING, is a pointer
+            gtypes.append(info[1])
+
+        self.b('  dbus_g_proxy_add_signal (proxy, "%s",'
+               % signal.getAttribute('name'))
+        for gtype in gtypes:
+            self.b('      %s,' % gtype)
+        self.b('      G_TYPE_INVALID);')
+
+    def do_interface(self, node):
+        ifaces = node.getElementsByTagName('interface')
+        assert len(ifaces) == 1
+        iface = ifaces[0]
+        name = node.getAttribute('name').replace('/', '')
+
+        self.iface = name
+        self.iface_lc = name.lower()
+        self.iface_uc = name.upper()
+        self.iface_mc = name.replace('_', '')
+        self.iface_dbus = iface.getAttribute('name')
+
+        signals = node.getElementsByTagName('signal')
+        methods = node.getElementsByTagName('method')
+
+        self.b('static inline void')
+        self.b('%s_add_signals_for_%s (DBusGProxy *proxy)'
+                % (self.prefix_lc, name.lower()))
+        self.b('{')
+
+        for signal in signals:
+            self.do_signal_add(signal)
+
+        self.b('}')
+        self.b('')
+        self.b('')
+
+        for signal in signals:
+            self.do_signal(name, signal)
+
+        for method in methods:
+            self.do_method(name, method)
+
+        self.iface_dbus = None
+
+    def __call__(self):
+
+        self.h('G_BEGIN_DECLS')
+        self.h('')
+
+        self.b('/* We don\'t want gtkdoc scanning this file, it\'ll get')
+        self.b(' * confused by seeing function definitions, so mark it as: */')
+        self.b('/*<private_header>*/')
+        self.b('')
+
+        nodes = self.dom.getElementsByTagName('node')
+        nodes.sort(cmp_by_name)
+
+        for node in nodes:
+            self.do_interface(node)
+
+        if self.group is not None:
+
+            self.b('/*')
+            self.b(' * %s_%s_add_signals:' % (self.prefix_lc, self.group))
+            self.b(' * @self: the #TpProxy')
+            self.b(' * @quark: a quark whose string value is the interface')
+            self.b(' *   name whose signals should be added')
+            self.b(' * @proxy: the D-Bus proxy to which to add the signals')
+            self.b(' * @unused: not used for anything')
+            self.b(' *')
+            self.b(' * Tell dbus-glib that @proxy has the signatures of all')
+            self.b(' * signals on the given interface, if it\'s one we')
+            self.b(' * support.')
+            self.b(' *')
+            self.b(' * This function should be used as a signal handler for')
+            self.b(' * #TpProxy::interface-added.')
+            self.b(' */')
+            self.b('static void')
+            self.b('%s_%s_add_signals (TpProxy *self,'
+                    % (self.prefix_lc, self.group))
+            self.b('    guint quark,')
+            self.b('    DBusGProxy *proxy,')
+            self.b('    gpointer unused)')
+
+            self.b('{')
+
+            for node in nodes:
+                iface = node.getElementsByTagName('interface')[0]
+                self.iface_dbus = iface.getAttribute('name')
+                name = node.getAttribute('name').replace('/', '').lower()
+                self.iface_uc = name.upper()
+                self.b('  if (quark == %s)' % self.get_iface_quark())
+                self.b('    %s_add_signals_for_%s (proxy);'
+                       % (self.prefix_lc, name))
+
+            self.b('}')
+            self.b('')
+
+        self.h('G_END_DECLS')
+        self.h('')
+
+        open(self.basename + '.h', 'w').write('\n'.join(self.__header))
+        open(self.basename + '-body.h', 'w').write('\n'.join(self.__body))
+
+
+def types_to_gtypes(types):
+    return [type_to_gtype(t)[1] for t in types]
+
+
+if __name__ == '__main__':
+    options, argv = gnu_getopt(sys.argv[1:], '',
+                               ['group=', 'subclass=', 'subclass-assert=',
+                                'iface-quark-prefix='])
+
+    opts = {}
+
+    for option, value in options:
+        opts[option] = value
+
+    dom = xml.dom.minidom.parse(argv[0])
+
+    Generator(dom, argv[1], argv[2], opts)()
diff --git a/tools/glib-client-marshaller-gen.py b/tools/glib-client-marshaller-gen.py
new file mode 100644 (file)
index 0000000..5444725
--- /dev/null
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+from string import ascii_letters, digits
+
+
+from libglibcodegen import signal_to_marshal_name
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+class Generator(object):
+
+    def __init__(self, dom, prefix):
+        self.dom = dom
+        self.marshallers = {}
+        self.prefix = prefix
+
+    def do_signal(self, signal):
+        marshaller = signal_to_marshal_name(signal, self.prefix)
+
+        assert '__' in marshaller
+        rhs = marshaller.split('__', 1)[1].split('_')
+
+        self.marshallers[marshaller] = rhs
+
+    def __call__(self):
+        signals = self.dom.getElementsByTagName('signal')
+
+        for signal in signals:
+            self.do_signal(signal)
+
+        print 'void'
+        print '%s_register_dbus_glib_marshallers (void)' % self.prefix
+        print '{'
+
+        all = self.marshallers.keys()
+        all.sort()
+        for marshaller in all:
+            rhs = self.marshallers[marshaller]
+
+            print '  dbus_g_object_register_marshaller (%s,' % marshaller
+            print '      G_TYPE_NONE,       /* return */'
+            for type in rhs:
+                print '      G_TYPE_%s,' % type.replace('VOID', 'NONE')
+            print '      G_TYPE_INVALID);'
+
+        print '}'
+
+
+def types_to_gtypes(types):
+    return [type_to_gtype(t)[1] for t in types]
+
+if __name__ == '__main__':
+    argv = sys.argv[1:]
+    dom = xml.dom.minidom.parse(argv[0])
+
+    Generator(dom, argv[1])()
diff --git a/tools/glib-errors-enum-body.xsl b/tools/glib-errors-enum-body.xsl
new file mode 100644 (file)
index 0000000..17054b7
--- /dev/null
@@ -0,0 +1,72 @@
+<!-- Stylesheet to extract GLib error enumerations from the Telepathy spec.
+The master copy of this stylesheet is in telepathy-glib - please make any
+changes there.
+
+Copyright (C) 2006, 2007 Collabora Limited
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  exclude-result-prefixes="tp">
+
+  <xsl:output method="text" indent="no" encoding="ascii"/>
+
+  <xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
+  <xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'"/>
+
+  <xsl:template match="tp:error" mode="values">
+    <!-- CHANNEL_BANNED -->
+    <xsl:variable name="name" select="translate(@name, concat($lower, '. '),
+                                                concat($upper, '__'))"/>
+    <!-- Channel.Banned -->
+    <xsl:variable name="nick" select="translate(@name, ' ', '')"/>
+        /* <xsl:value-of select="concat(../@namespace, '.', $name)"/>
+    <xsl:value-of select="tp:docstring"/> */
+        { TP_ERROR_<xsl:value-of select="$name"/>, "TP_ERROR_<xsl:value-of select="$name"/>", "<xsl:value-of select="$nick"/>" },
+</xsl:template>
+
+  <xsl:template match="text()"/>
+
+  <xsl:template match="//tp:errors">/* Generated from the Telepathy spec
+
+<xsl:for-each select="tp:copyright">
+<xsl:value-of select="."/><xsl:text>
+</xsl:text></xsl:for-each><xsl:text>
+</xsl:text><xsl:value-of select="tp:license"/>
+*/
+
+#include &lt;_gen/telepathy-errors.h&gt;
+
+GType
+tp_error_get_type (void)
+{
+  static GType etype = 0;
+  if (G_UNLIKELY (etype == 0))
+    {
+      static const GEnumValue values[] = {
+<xsl:apply-templates select="tp:error" mode="values"/>      };
+
+      etype = g_enum_register_static ("TpError", values);
+    }
+  return etype;
+}
+
+</xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et noai noci: -->
diff --git a/tools/glib-errors-enum-header.xsl b/tools/glib-errors-enum-header.xsl
new file mode 100644 (file)
index 0000000..5275041
--- /dev/null
@@ -0,0 +1,73 @@
+<!-- Stylesheet to extract GLib error enumerations from the Telepathy spec.
+The master copy of this stylesheet is in telepathy-glib - please make any
+changes there.
+
+Copyright (C) 2006, 2007 Collabora Limited
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  exclude-result-prefixes="tp">
+
+  <xsl:output method="text" indent="no" encoding="ascii"/>
+
+  <xsl:template match="tp:error" mode="gtkdoc">
+ * @TP_ERROR_<xsl:value-of select="translate(@name, 'abcdefghijklmnopqrstuvwxyz .', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ__')"/>: <xsl:value-of select="concat(../@namespace, '.', translate(@name, ' ', ''))"/>:
+ * <xsl:value-of select="translate(tp:docstring, '&#13;&#10;', '')"/>
+  </xsl:template>
+
+  <xsl:template match="tp:error" mode="enum">
+<xsl:text>    TP_ERROR_</xsl:text><xsl:value-of select="translate(@name, 'abcdefghijklmnopqrstuvwxyz .', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ__')"/>,
+</xsl:template>
+
+  <xsl:template match="text()"/>
+
+  <xsl:template match="//tp:errors">/* Generated from the Telepathy spec
+
+<xsl:for-each select="tp:copyright">
+<xsl:value-of select="."/><xsl:text>
+</xsl:text></xsl:for-each><xsl:text>
+</xsl:text><xsl:value-of select="tp:license"/>
+*/
+
+#include &lt;glib-object.h&gt;
+
+G_BEGIN_DECLS
+
+GType tp_error_get_type (void);
+
+/**
+ * TP_TYPE_ERROR:
+ *
+ * The GType of the Telepathy error enumeration.
+ */
+#define TP_TYPE_ERROR (tp_error_get_type())
+
+/**
+ * TpError:<xsl:apply-templates select="tp:error" mode="gtkdoc"/>
+ *
+ * Enumerated type representing the Telepathy D-Bus errors.
+ */
+typedef enum {
+<xsl:apply-templates select="tp:error" mode="enum"/>} TpError;
+
+G_END_DECLS
+</xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et noai noci: -->
diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py
new file mode 100644 (file)
index 0000000..0c7c419
--- /dev/null
@@ -0,0 +1,711 @@
+#!/usr/bin/python
+
+# glib-ginterface-gen.py: service-side interface generator
+#
+# Generate dbus-glib 0.x service GInterfaces from the Telepathy specification.
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2006, 2007 Collabora Limited
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+import sys
+import os.path
+import xml.dom.minidom
+
+from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \
+        camelcase_to_lower, NS_TP, dbus_gutils_wincaps_to_uscore, \
+        signal_to_marshal_name, method_to_glue_marshal_name
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+class Generator(object):
+
+    def __init__(self, dom, prefix, basename, signal_marshal_prefix,
+                 headers, end_headers, not_implemented_func,
+                 allow_havoc):
+        self.dom = dom
+        self.__header = []
+        self.__body = []
+
+        assert prefix.endswith('_')
+        assert not signal_marshal_prefix.endswith('_')
+
+        # The main_prefix, sub_prefix thing is to get:
+        # FOO_ -> (FOO_, _)
+        # FOO_SVC_ -> (FOO_, _SVC_)
+        # but
+        # FOO_BAR/ -> (FOO_BAR_, _)
+        # FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_)
+
+        if '/' in prefix:
+            main_prefix, sub_prefix = prefix.upper().split('/', 1)
+            prefix = prefix.replace('/', '_')
+        else:
+            main_prefix, sub_prefix = prefix.upper().split('_', 1)
+
+        self.MAIN_PREFIX_ = main_prefix + '_'
+        self._SUB_PREFIX_ = '_' + sub_prefix
+
+        self.Prefix_ = prefix
+        self.Prefix = prefix.replace('_', '')
+        self.prefix_ = prefix.lower()
+        self.PREFIX_ = prefix.upper()
+
+        self.signal_marshal_prefix = signal_marshal_prefix
+        self.headers = headers
+        self.end_headers = end_headers
+        self.not_implemented_func = not_implemented_func
+        self.allow_havoc = allow_havoc
+
+    def h(self, s):
+        self.__header.append(s)
+
+    def b(self, s):
+        self.__body.append(s)
+
+    def do_node(self, node):
+        node_name = node.getAttribute('name').replace('/', '')
+        node_name_mixed = self.node_name_mixed = node_name.replace('_', '')
+        node_name_lc = self.node_name_lc = node_name.lower()
+        node_name_uc = self.node_name_uc = node_name.upper()
+
+        interfaces = node.getElementsByTagName('interface')
+        assert len(interfaces) == 1, interfaces
+        interface = interfaces[0]
+        self.iface_name = interface.getAttribute('name')
+
+        tmp = interface.getAttribute('tp:implement-service')
+        if tmp == "no":
+            return
+
+        tmp = interface.getAttribute('tp:causes-havoc')
+        if tmp and not self.allow_havoc:
+            raise AssertionError('%s is %s' % (self.iface_name, tmp))
+
+        self.b('static const DBusGObjectInfo _%s%s_object_info;'
+               % (self.prefix_, node_name_lc))
+        self.b('')
+
+        methods = interface.getElementsByTagName('method')
+        signals = interface.getElementsByTagName('signal')
+        properties = interface.getElementsByTagName('property')
+        # Don't put properties in dbus-glib glue
+        glue_properties = []
+
+        self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed))
+        self.b('    GTypeInterface parent_class;')
+        for method in methods:
+            self.b('    %s %s;' % self.get_method_impl_names(method))
+        self.b('};')
+        self.b('')
+
+        if signals:
+            self.b('enum {')
+            for signal in signals:
+                self.b('    %s,' % self.get_signal_const_entry(signal))
+            self.b('    N_%s_SIGNALS' % node_name_uc)
+            self.b('};')
+            self.b('static guint %s_signals[N_%s_SIGNALS] = {0};'
+                   % (node_name_lc, node_name_uc))
+            self.b('')
+
+        self.b('static void %s%s_base_init (gpointer klass);'
+               % (self.prefix_, node_name_lc))
+        self.b('')
+
+        self.b('GType')
+        self.b('%s%s_get_type (void)'
+               % (self.prefix_, node_name_lc))
+        self.b('{')
+        self.b('  static GType type = 0;')
+        self.b('')
+        self.b('  if (G_UNLIKELY (type == 0))')
+        self.b('    {')
+        self.b('      static const GTypeInfo info = {')
+        self.b('        sizeof (%s%sClass),' % (self.Prefix, node_name_mixed))
+        self.b('        %s%s_base_init, /* base_init */'
+               % (self.prefix_, node_name_lc))
+        self.b('        NULL, /* base_finalize */')
+        self.b('        NULL, /* class_init */')
+        self.b('        NULL, /* class_finalize */')
+        self.b('        NULL, /* class_data */')
+        self.b('        0,')
+        self.b('        0, /* n_preallocs */')
+        self.b('        NULL /* instance_init */')
+        self.b('      };')
+        self.b('')
+        self.b('      type = g_type_register_static (G_TYPE_INTERFACE,')
+        self.b('          "%s%s", &info, 0);' % (self.Prefix, node_name_mixed))
+        self.b('    }')
+        self.b('')
+        self.b('  return type;')
+        self.b('}')
+        self.b('')
+
+        self.h('/**')
+        self.h(' * %s%s:' % (self.Prefix, node_name_mixed))
+        self.h(' *')
+        self.h(' * Dummy typedef representing any implementation of this '
+               'interface.')
+        self.h(' */')
+        self.h('typedef struct _%s%s %s%s;'
+               % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
+        self.h('')
+        self.h('/**')
+        self.h(' * %s%sClass:' % (self.Prefix, node_name_mixed))
+        self.h(' *')
+        self.h(' * The class of %s%s.' % (self.Prefix, node_name_mixed))
+        self.h(' */')
+        self.h('typedef struct _%s%sClass %s%sClass;'
+               % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
+        self.h('')
+        self.h('GType %s%s_get_type (void);'
+               % (self.prefix_, node_name_lc))
+
+        gtype = self.current_gtype = \
+                self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc
+        classname = self.Prefix + node_name_mixed
+
+        self.h('#define %s \\\n  (%s%s_get_type ())'
+               % (gtype, self.prefix_, node_name_lc))
+        self.h('#define %s%s(obj) \\\n'
+               '  (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))'
+               % (self.PREFIX_, node_name_uc, gtype, classname))
+        self.h('#define %sIS%s%s(obj) \\\n'
+               '  (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))'
+               % (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype))
+        self.h('#define %s%s_GET_CLASS(obj) \\\n'
+               '  (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))'
+               % (self.PREFIX_, node_name_uc, gtype, classname))
+        self.h('')
+        self.h('')
+
+        base_init_code = []
+
+        for method in methods:
+            self.do_method(method)
+
+        for signal in signals:
+            base_init_code.extend(self.do_signal(signal))
+
+        self.b('static inline void')
+        self.b('%s%s_base_init_once (gpointer klass)'
+               % (self.prefix_, node_name_lc))
+        self.b('{')
+        self.b('  static TpDBusPropertiesMixinPropInfo properties[%d] = {'
+               % (len(properties) + 1))
+
+        for m in properties:
+            access = m.getAttribute('access')
+            assert access in ('read', 'write', 'readwrite')
+
+            if access == 'read':
+                flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ'
+            elif access == 'write':
+                flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE'
+            else:
+                flags = ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | '
+                         'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE')
+
+            self.b('      { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
+                   % (flags, m.getAttribute('type'), m.getAttribute('name')))
+
+        self.b('      { 0, 0, NULL, 0, NULL, NULL }')
+        self.b('  };')
+        self.b('  static TpDBusPropertiesMixinIfaceInfo interface =')
+        self.b('      { 0, properties, NULL, NULL };')
+        self.b('')
+        self.b('  interface.dbus_interface = g_quark_from_static_string '
+               '("%s");' % self.iface_name)
+
+        for i, m in enumerate(properties):
+            self.b('  properties[%d].name = g_quark_from_static_string ("%s");'
+                   % (i, m.getAttribute('name')))
+            self.b('  properties[%d].type = %s;'
+                   % (i, type_to_gtype(m.getAttribute('type'))[1]))
+
+        self.b('  tp_svc_interface_set_dbus_properties_info (%s, &interface);'
+               % self.current_gtype)
+
+        self.b('')
+        for s in base_init_code:
+            self.b(s)
+        self.b('  dbus_g_object_type_install_info (%s%s_get_type (),'
+               % (self.prefix_, node_name_lc))
+        self.b('      &_%s%s_object_info);'
+               % (self.prefix_, node_name_lc))
+        self.b('}')
+
+        self.b('static void')
+        self.b('%s%s_base_init (gpointer klass)'
+               % (self.prefix_, node_name_lc))
+        self.b('{')
+        self.b('  static gboolean initialized = FALSE;')
+        self.b('')
+        self.b('  if (!initialized)')
+        self.b('    {')
+        self.b('      initialized = TRUE;')
+        self.b('      %s%s_base_init_once (klass);'
+               % (self.prefix_, node_name_lc))
+        self.b('    }')
+        # insert anything we need to do per implementation here
+        self.b('}')
+
+        self.h('')
+
+        self.b('static const DBusGMethodInfo _%s%s_methods[] = {'
+               % (self.prefix_, node_name_lc))
+
+        method_blob, offsets = self.get_method_glue(methods)
+
+        for method, offset in zip(methods, offsets):
+            self.do_method_glue(method, offset)
+
+        self.b('};')
+        self.b('')
+
+        self.b('static const DBusGObjectInfo _%s%s_object_info = {'
+               % (self.prefix_, node_name_lc))
+        self.b('  0,')  # version
+        self.b('  _%s%s_methods,' % (self.prefix_, node_name_lc))
+        self.b('  %d,' % len(methods))
+        self.b('"' + method_blob.replace('\0', '\\0') + '",')
+        self.b('"' + self.get_signal_glue(signals).replace('\0', '\\0') + '",')
+        self.b('"' +
+               self.get_property_glue(glue_properties).replace('\0', '\\0') +
+               '",')
+        self.b('};')
+        self.b('')
+
+        self.node_name_mixed = None
+        self.node_name_lc = None
+        self.node_name_uc = None
+
+    def get_method_glue(self, methods):
+        info = []
+        offsets = []
+
+        for method in methods:
+            offsets.append(len(''.join(info)))
+
+            info.append(self.iface_name + '\0')
+            info.append(method.getAttribute('name') + '\0')
+
+            info.append('A\0')    # async
+
+            counter = 0
+            for arg in method.getElementsByTagName('arg'):
+                out = arg.getAttribute('direction') == 'out'
+
+                name = arg.getAttribute('name')
+                if not name:
+                    assert out
+                    name = 'arg%u' % counter
+                counter += 1
+
+                info.append(name + '\0')
+
+                if out:
+                    info.append('O\0')
+                else:
+                    info.append('I\0')
+
+                if out:
+                    info.append('F\0')    # not const
+                    info.append('N\0')    # not error or return
+                info.append(arg.getAttribute('type') + '\0')
+
+            info.append('\0')
+
+        return ''.join(info) + '\0', offsets
+
+    def do_method_glue(self, method, offset):
+        lc_name = camelcase_to_lower(method.getAttribute('name'))
+
+        marshaller = method_to_glue_marshal_name(method,
+                self.signal_marshal_prefix)
+        wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name
+
+        self.b("  { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset))
+
+    def get_signal_glue(self, signals):
+        info = []
+
+        for signal in signals:
+            info.append(self.iface_name)
+            info.append(signal.getAttribute('name'))
+
+        return '\0'.join(info) + '\0\0'
+
+    # the implementation can be the same
+    get_property_glue = get_signal_glue
+
+    def get_method_impl_names(self, method):
+        dbus_method_name = method.getAttribute('name')
+        class_member_name = camelcase_to_lower(dbus_method_name)
+        stub_name = (self.prefix_ + self.node_name_lc + '_' +
+                     class_member_name)
+        return (stub_name + '_impl', class_member_name)
+
+    def do_method(self, method):
+        assert self.node_name_mixed is not None
+
+        in_class = []
+
+        # Examples refer to Thing.DoStuff (su) -> ii
+
+        # DoStuff
+        dbus_method_name = method.getAttribute('name')
+        # do_stuff
+        class_member_name = camelcase_to_lower(dbus_method_name)
+        # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
+        #   DBusGMethodInvocation *);
+        stub_name = (self.prefix_ + self.node_name_lc + '_' +
+                     class_member_name)
+        # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *,
+        #   const char *, guint, DBusGMethodInvocation);
+        impl_name = stub_name + '_impl'
+        # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *,
+        #   gint, gint);
+        ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' +
+                    class_member_name)
+
+        # Gather arguments
+        in_args = []
+        out_args = []
+        for i in method.getElementsByTagName('arg'):
+            name = i.getAttribute('name')
+            direction = i.getAttribute('direction') or 'in'
+            dtype = i.getAttribute('type')
+
+            assert direction in ('in', 'out')
+
+            if name:
+                name = direction + '_' + name
+            elif direction == 'in':
+                name = direction + str(len(in_args))
+            else:
+                name = direction + str(len(out_args))
+
+            ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
+
+            if pointer:
+                ctype = 'const ' + ctype
+
+            struct = (ctype, name)
+
+            if direction == 'in':
+                in_args.append(struct)
+            else:
+                out_args.append(struct)
+
+        # Implementation type declaration (in header, docs in body)
+        self.b('/**')
+        self.b(' * %s:' % impl_name)
+        self.b(' * @self: The object implementing this interface')
+        for (ctype, name) in in_args:
+            self.b(' * @%s: %s (FIXME, generate documentation)'
+                   % (name, ctype))
+        self.b(' * @context: Used to return values or throw an error')
+        self.b(' *')
+        self.b(' * The signature of an implementation of the D-Bus method')
+        self.b(' * %s on interface %s.' % (dbus_method_name, self.iface_name))
+        self.b(' */')
+        self.h('typedef void (*%s) (%s%s *self,'
+          % (impl_name, self.Prefix, self.node_name_mixed))
+        for (ctype, name) in in_args:
+            self.h('    %s%s,' % (ctype, name))
+        self.h('    DBusGMethodInvocation *context);')
+
+        # Class member (in class definition)
+        in_class.append('    %s %s;' % (impl_name, class_member_name))
+
+        # Stub definition (in body only - it's static)
+        self.b('static void')
+        self.b('%s (%s%s *self,'
+           % (stub_name, self.Prefix, self.node_name_mixed))
+        for (ctype, name) in in_args:
+            self.b('    %s%s,' % (ctype, name))
+        self.b('    DBusGMethodInvocation *context)')
+        self.b('{')
+        self.b('  %s impl = (%s%s_GET_CLASS (self)->%s);'
+          % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name))
+        self.b('')
+        self.b('  if (impl != NULL)')
+        tmp = ['self'] + [name for (ctype, name) in in_args] + ['context']
+        self.b('    {')
+        self.b('      (impl) (%s);' % ',\n        '.join(tmp))
+        self.b('    }')
+        self.b('  else')
+        self.b('    {')
+        if self.not_implemented_func:
+            self.b('      %s (context);' % self.not_implemented_func)
+        else:
+            self.b('      GError e = { DBUS_GERROR, ')
+            self.b('           DBUS_GERROR_UNKNOWN_METHOD,')
+            self.b('           "Method not implemented" };')
+            self.b('')
+            self.b('      dbus_g_method_return_error (context, &e);')
+        self.b('    }')
+        self.b('}')
+        self.b('')
+
+        # Implementation registration (in both header and body)
+        self.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);'
+               % (self.prefix_, self.node_name_lc, class_member_name,
+                  self.Prefix, self.node_name_mixed, impl_name))
+
+        self.b('/**')
+        self.b(' * %s%s_implement_%s:'
+               % (self.prefix_, self.node_name_lc, class_member_name))
+        self.b(' * @klass: A class whose instances implement this interface')
+        self.b(' * @impl: A callback used to implement the %s D-Bus method'
+               % dbus_method_name)
+        self.b(' *')
+        self.b(' * Register an implementation for the %s method in the vtable'
+               % dbus_method_name)
+        self.b(' * of an implementation of this interface. To be called from')
+        self.b(' * the interface init function.')
+        self.b(' */')
+        self.b('void')
+        self.b('%s%s_implement_%s (%s%sClass *klass, %s impl)'
+               % (self.prefix_, self.node_name_lc, class_member_name,
+                  self.Prefix, self.node_name_mixed, impl_name))
+        self.b('{')
+        self.b('  klass->%s = impl;' % class_member_name)
+        self.b('}')
+        self.b('')
+
+        # Return convenience function (static inline, in header)
+        self.h('/**')
+        self.h(' * %s:' % ret_name)
+        self.h(' * @context: The D-Bus method invocation context')
+        for (ctype, name) in out_args:
+            self.h(' * @%s: %s (FIXME, generate documentation)'
+                   % (name, ctype))
+        self.h(' *')
+        self.h(' * Return successfully by calling dbus_g_method_return().')
+        self.h(' * This inline function exists only to provide type-safety.')
+        self.h(' */')
+        tmp = (['DBusGMethodInvocation *context'] +
+               [ctype + name for (ctype, name) in out_args])
+        self.h('static inline')
+        self.h('/* this comment is to stop gtkdoc realising this is static */')
+        self.h(('void %s (' % ret_name) + (',\n    '.join(tmp)) + ');')
+        self.h('static inline void')
+        self.h(('%s (' % ret_name) + (',\n    '.join(tmp)) + ')')
+        self.h('{')
+        tmp = ['context'] + [name for (ctype, name) in out_args]
+        self.h('  dbus_g_method_return (' + ',\n      '.join(tmp) + ');')
+        self.h('}')
+        self.h('')
+
+        return in_class
+
+    def get_signal_const_entry(self, signal):
+        assert self.node_name_uc is not None
+        return ('SIGNAL_%s_%s'
+                % (self.node_name_uc, signal.getAttribute('name')))
+
+    def do_signal(self, signal):
+        assert self.node_name_mixed is not None
+
+        in_base_init = []
+
+        # for signal: Thing::StuffHappened (s, u)
+        # we want to emit:
+        # void tp_svc_thing_emit_stuff_happened (gpointer instance,
+        #    const char *arg0, guint arg1);
+
+        dbus_name = signal.getAttribute('name')
+        stub_name = (self.prefix_ + self.node_name_lc + '_emit_' +
+                     camelcase_to_lower(dbus_name))
+        const_name = self.get_signal_const_entry(signal)
+
+        # Gather arguments
+        args = []
+        for i in signal.getElementsByTagName('arg'):
+            name = i.getAttribute('name')
+            dtype = i.getAttribute('type')
+            tp_type = i.getAttribute('tp:type')
+
+            if name:
+                name = 'arg_' + name
+            else:
+                name = 'arg' + str(len(args))
+
+            ctype, gtype, marshaller, pointer = type_to_gtype(dtype)
+
+            if pointer:
+                ctype = 'const ' + ctype
+
+            struct = (ctype, name, gtype)
+            args.append(struct)
+
+        tmp = (['gpointer instance'] +
+               [ctype + name for (ctype, name, gtype) in args])
+
+        self.h(('void %s (' % stub_name) + (',\n    '.join(tmp)) + ');')
+
+        # FIXME: emit docs
+
+        self.b('/**')
+        self.b(' * %s:' % stub_name)
+        self.b(' * @instance: The object implementing this interface')
+        for (ctype, name, gtype) in args:
+            self.b(' * @%s: %s (FIXME, generate documentation)'
+                   % (name, ctype))
+        self.b(' *')
+        self.b(' * Type-safe wrapper around g_signal_emit to emit the')
+        self.b(' * %s signal on interface %s.'
+               % (dbus_name, self.iface_name))
+        self.b(' */')
+
+        self.b('void')
+        self.b(('%s (' % stub_name) + (',\n    '.join(tmp)) + ')')
+        self.b('{')
+        self.b('  g_assert (instance != NULL);')
+        self.b('  g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));'
+               % (self.current_gtype))
+        tmp = (['instance', '%s_signals[%s]' % (self.node_name_lc, const_name),
+                '0'] + [name for (ctype, name, gtype) in args])
+        self.b('  g_signal_emit (' + ',\n      '.join(tmp) + ');')
+        self.b('}')
+        self.b('')
+
+        in_base_init.append('  %s_signals[%s] ='
+                            % (self.node_name_lc, const_name))
+        in_base_init.append('  g_signal_new ("%s",'
+                % (dbus_gutils_wincaps_to_uscore(dbus_name).replace('_', '-')))
+        in_base_init.append('      G_OBJECT_CLASS_TYPE (klass),')
+        in_base_init.append('      G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,')
+        in_base_init.append('      0,')
+        in_base_init.append('      NULL, NULL,')
+        in_base_init.append('      %s,'
+                % signal_to_marshal_name(signal, self.signal_marshal_prefix))
+        in_base_init.append('      G_TYPE_NONE,')
+        tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args]
+        in_base_init.append('      %s);' % ',\n      '.join(tmp))
+        in_base_init.append('')
+
+        return in_base_init
+
+    def __call__(self):
+        self.h('#include <glib-object.h>')
+        self.h('#include <dbus/dbus-glib.h>')
+        self.h('#include <telepathy-glib/dbus-properties-mixin.h>')
+        self.h('')
+        self.h('G_BEGIN_DECLS')
+        self.h('')
+
+        self.b('#include "%s.h"' % basename)
+        self.b('')
+        for header in self.headers:
+            self.b('#include %s' % header)
+        self.b('')
+
+        nodes = self.dom.getElementsByTagName('node')
+        nodes.sort(cmp_by_name)
+
+        for node in nodes:
+            self.do_node(node)
+
+        self.h('')
+        self.h('G_END_DECLS')
+
+        self.b('')
+        for header in self.end_headers:
+            self.b('#include %s' % header)
+
+        self.h('')
+        self.b('')
+        open(basename + '.h', 'w').write('\n'.join(self.__header))
+        open(basename + '.c', 'w').write('\n'.join(self.__body))
+
+
+def cmdline_error():
+    print """\
+usage:
+    gen-ginterface [OPTIONS] xmlfile Prefix_
+options:
+    --include='<header.h>' (may be repeated)
+    --include='"header.h"' (ditto)
+    --include-end='"header.h"' (ditto)
+        Include extra headers in the generated .c file
+    --signal-marshal-prefix='prefix'
+        Use the given prefix on generated signal marshallers (default is
+        prefix.lower()).
+    --filename='BASENAME'
+        Set the basename for the output files (default is prefix.lower()
+        + 'ginterfaces')
+    --not-implemented-func='symbol'
+        Set action when methods not implemented in the interface vtable are
+        called. symbol must have signature
+            void symbol (DBusGMethodInvocation *context)
+        and return some sort of "not implemented" error via
+            dbus_g_method_return_error (context, ...)
+"""
+    sys.exit(1)
+
+
+if __name__ == '__main__':
+    from getopt import gnu_getopt
+
+    options, argv = gnu_getopt(sys.argv[1:], '',
+                               ['filename=', 'signal-marshal-prefix=',
+                                'include=', 'include-end=',
+                                'allow-unstable',
+                                'not-implemented-func='])
+
+    try:
+        prefix = argv[1]
+    except IndexError:
+        cmdline_error()
+
+    basename = prefix.lower() + 'ginterfaces'
+    signal_marshal_prefix = prefix.lower().rstrip('_')
+    headers = []
+    end_headers = []
+    not_implemented_func = ''
+    allow_havoc = False
+
+    for option, value in options:
+        if option == '--filename':
+            basename = value
+        elif option == '--signal-marshal-prefix':
+            signal_marshal_prefix = value
+        elif option == '--include':
+            if value[0] not in '<"':
+                value = '"%s"' % value
+            headers.append(value)
+        elif option == '--include-end':
+            if value[0] not in '<"':
+                value = '"%s"' % value
+            end_headers.append(value)
+        elif option == '--not-implemented-func':
+            not_implemented_func = value
+        elif option == '--allow-unstable':
+            allow_havoc = True
+
+    try:
+        dom = xml.dom.minidom.parse(argv[0])
+    except IndexError:
+        cmdline_error()
+
+    Generator(dom, prefix, basename, signal_marshal_prefix, headers,
+              end_headers, not_implemented_func, allow_havoc)()
diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py
new file mode 100644 (file)
index 0000000..fcb46e8
--- /dev/null
@@ -0,0 +1,230 @@
+#!/usr/bin/python
+
+# Generate GLib GInterfaces from the Telepathy specification.
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (C) 2006, 2007 Collabora Limited
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+import sys
+import xml.dom.minidom
+
+from libglibcodegen import escape_as_identifier, \
+                           get_docstring, \
+                           NS_TP, \
+                           Signature, \
+                           type_to_gtype, \
+                           xml_escape
+
+
+def types_to_gtypes(types):
+    return [type_to_gtype(t)[1] for t in types]
+
+
+class GTypesGenerator(object):
+    def __init__(self, dom, output, mixed_case_prefix):
+        self.dom = dom
+        self.Prefix = mixed_case_prefix
+        self.PREFIX_ = self.Prefix.upper() + '_'
+        self.prefix_ = self.Prefix.lower() + '_'
+
+        self.header = open(output + '.h', 'w')
+        self.body = open(output + '-body.h', 'w')
+
+        for f in (self.header, self.body):
+            f.write('/* Auto-generated, do not edit.\n *\n'
+                    ' * This file may be distributed under the same terms\n'
+                    ' * as the specification from which it was generated.\n'
+                    ' */\n\n')
+
+        self.need_mappings = {}
+        self.need_structs = {}
+        self.need_arrays = {}
+
+    def do_mapping_header(self, mapping):
+        members = mapping.getElementsByTagNameNS(NS_TP, 'member')
+        assert len(members) == 2
+
+        impl_sig = ''.join([elt.getAttribute('type')
+                            for elt in members])
+
+        esc_impl_sig = escape_as_identifier(impl_sig)
+
+        name = (self.PREFIX_ + 'HASH_TYPE_' +
+                mapping.getAttribute('name').upper())
+        impl = self.prefix_ + 'type_dbus_hash_' + esc_impl_sig
+
+        docstring = get_docstring(mapping) or '(Undocumented)'
+
+        self.header.write('/**\n * %s:\n *\n' % name)
+        self.header.write(' * %s\n' % xml_escape(docstring))
+        self.header.write(' *\n')
+        self.header.write(' * This macro expands to a call to a function\n')
+        self.header.write(' * that returns the #GType of a #GHashTable\n')
+        self.header.write(' * appropriate for representing a D-Bus\n')
+        self.header.write(' * dictionary of signature\n')
+        self.header.write(' * <literal>a{%s}</literal>.\n' % impl_sig)
+        self.header.write(' *\n')
+
+        key, value = members
+
+        self.header.write(' * Keys (D-Bus type <literal>%s</literal>,\n'
+                          % key.getAttribute('type'))
+        tp_type = key.getAttributeNS(NS_TP, 'type')
+        if tp_type:
+            self.header.write(' * type <literal>%s</literal>,\n' % tp_type)
+        self.header.write(' * named <literal>%s</literal>):\n'
+                          % key.getAttribute('name'))
+        docstring = get_docstring(key) or '(Undocumented)'
+        self.header.write(' * %s\n' % xml_escape(docstring))
+        self.header.write(' *\n')
+
+        self.header.write(' * Values (D-Bus type <literal>%s</literal>,\n'
+                          % value.getAttribute('type'))
+        tp_type = value.getAttributeNS(NS_TP, 'type')
+        if tp_type:
+            self.header.write(' * type <literal>%s</literal>,\n' % tp_type)
+        self.header.write(' * named <literal>%s</literal>):\n'
+                          % value.getAttribute('name'))
+        docstring = get_docstring(value) or '(Undocumented)'
+        self.header.write(' * %s\n' % xml_escape(docstring))
+        self.header.write(' *\n')
+
+        self.header.write(' */\n')
+
+        self.header.write('#define %s (%s ())\n\n' % (name, impl))
+        self.need_mappings[impl_sig] = esc_impl_sig
+
+    def do_struct_header(self, struct):
+        members = struct.getElementsByTagNameNS(NS_TP, 'member')
+        impl_sig = ''.join([elt.getAttribute('type') for elt in members])
+        esc_impl_sig = escape_as_identifier(impl_sig)
+
+        name = (self.PREFIX_ + 'STRUCT_TYPE_' +
+                struct.getAttribute('name').upper())
+        impl = self.prefix_ + 'type_dbus_struct_' + esc_impl_sig
+        docstring = struct.getElementsByTagNameNS(NS_TP, 'docstring')
+        if docstring:
+            docstring = docstring[0].toprettyxml()
+            if docstring.startswith('<tp:docstring>'):
+                docstring = docstring[14:]
+            if docstring.endswith('</tp:docstring>\n'):
+                docstring = docstring[:-16]
+            if docstring.strip() in ('<tp:docstring/>', ''):
+                docstring = '(Undocumented)'
+        else:
+            docstring = '(Undocumented)'
+        self.header.write('/**\n * %s:\n\n' % name)
+        self.header.write(' * %s\n' % xml_escape(docstring))
+        self.header.write(' *\n')
+        self.header.write(' * This macro expands to a call to a function\n')
+        self.header.write(' * that returns the #GType of a #GValueArray\n')
+        self.header.write(' * appropriate for representing a D-Bus struct\n')
+        self.header.write(' * with signature <literal>(%s)</literal>.\n'
+                          % impl_sig)
+        self.header.write(' *\n')
+
+        for i, member in enumerate(members):
+            self.header.write(' * Member %d (D-Bus type '
+                              '<literal>%s</literal>,\n'
+                              % (i, member.getAttribute('type')))
+            tp_type = member.getAttributeNS(NS_TP, 'type')
+            if tp_type:
+                self.header.write(' * type <literal>%s</literal>,\n' % tp_type)
+            self.header.write(' * named <literal>%s</literal>):\n'
+                              % member.getAttribute('name'))
+            docstring = get_docstring(member) or '(Undocumented)'
+            self.header.write(' * %s\n' % xml_escape(docstring))
+            self.header.write(' *\n')
+
+        self.header.write(' */\n')
+        self.header.write('#define %s (%s ())\n\n' % (name, impl))
+
+        array_name = struct.getAttribute('array-name')
+        if array_name != '':
+            array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper())
+            impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig
+            self.header.write('/**\n * %s:\n\n' % array_name)
+            self.header.write(' * Expands to a call to a function\n')
+            self.header.write(' * that returns the #GType of a #GPtrArray\n')
+            self.header.write(' * of #%s.\n' % name)
+            self.header.write(' */\n')
+            self.header.write('#define %s (%s ())\n\n' % (array_name, impl))
+            self.need_arrays[impl_sig] = esc_impl_sig
+
+        self.need_structs[impl_sig] = esc_impl_sig
+
+    def __call__(self):
+        mappings = self.dom.getElementsByTagNameNS(NS_TP, 'mapping')
+        structs = self.dom.getElementsByTagNameNS(NS_TP, 'struct')
+
+        for mapping in mappings:
+            self.do_mapping_header(mapping)
+
+        for sig in self.need_mappings:
+            self.header.write('GType %stype_dbus_hash_%s (void);\n\n' %
+                              (self.prefix_, self.need_mappings[sig]))
+            self.body.write('GType\n%stype_dbus_hash_%s (void)\n{\n' %
+                              (self.prefix_, self.need_mappings[sig]))
+            self.body.write('  static GType t = 0;\n\n')
+            self.body.write('  if (G_UNLIKELY (t == 0))\n')
+            # FIXME: translate sig into two GTypes
+            items = tuple(Signature(sig))
+            gtypes = types_to_gtypes(items)
+            self.body.write('    t = dbus_g_type_get_map ("GHashTable", '
+                            '%s, %s);\n' % (gtypes[0], gtypes[1]))
+            self.body.write('  return t;\n')
+            self.body.write('}\n\n')
+
+        for struct in structs:
+            self.do_struct_header(struct)
+
+        for sig in self.need_structs:
+            self.header.write('GType %stype_dbus_struct_%s (void);\n\n' %
+                              (self.prefix_, self.need_structs[sig]))
+            self.body.write('GType\n%stype_dbus_struct_%s (void)\n{\n' %
+                              (self.prefix_, self.need_structs[sig]))
+            self.body.write('  static GType t = 0;\n\n')
+            self.body.write('  if (G_UNLIKELY (t == 0))\n')
+            self.body.write('    t = dbus_g_type_get_struct ("GValueArray",\n')
+            items = tuple(Signature(sig))
+            gtypes = types_to_gtypes(items)
+            for gtype in gtypes:
+                self.body.write('        %s,\n' % gtype)
+            self.body.write('        G_TYPE_INVALID);\n')
+            self.body.write('  return t;\n')
+            self.body.write('}\n\n')
+
+        for sig in self.need_arrays:
+            self.header.write('GType %stype_dbus_array_%s (void);\n\n' %
+                              (self.prefix_, self.need_structs[sig]))
+            self.body.write('GType\n%stype_dbus_array_%s (void)\n{\n' %
+                              (self.prefix_, self.need_structs[sig]))
+            self.body.write('  static GType t = 0;\n\n')
+            self.body.write('  if (G_UNLIKELY (t == 0))\n')
+            self.body.write('    t = dbus_g_type_get_collection ("GPtrArray", '
+                            '%stype_dbus_struct_%s ());\n' %
+                            (self.prefix_, self.need_structs[sig]))
+            self.body.write('  return t;\n')
+            self.body.write('}\n\n')
+
+if __name__ == '__main__':
+    argv = sys.argv[1:]
+
+    dom = xml.dom.minidom.parse(argv[0])
+
+    GTypesGenerator(dom, argv[1], argv[2])()
diff --git a/tools/glib-interfaces-body-generator.xsl b/tools/glib-interfaces-body-generator.xsl
new file mode 100644 (file)
index 0000000..caff891
--- /dev/null
@@ -0,0 +1,47 @@
+<!-- Stylesheet to extract C interface names from the Telepathy spec.
+The master copy of this stylesheet is in telepathy-glib - please make any
+changes there.
+
+Copyright (C) 2006, 2007 Collabora Limited
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  exclude-result-prefixes="tp">
+
+  <xsl:import href="c-interfaces-generator.xsl"/>
+
+  <xsl:template match="interface">
+    <xsl:text>GQuark&#10;</xsl:text>
+    <xsl:value-of select="$prefix"/>
+    <xsl:text>_iface_quark_</xsl:text>
+    <xsl:value-of select="translate(../@name, concat($upper, '/'), $lower)"/>
+    <xsl:text> (void)&#10;{&#10;</xsl:text>
+    <xsl:text>  static GQuark quark = 0;&#10;&#10;</xsl:text>
+    <xsl:text>  if (G_UNLIKELY (quark == 0))&#10;</xsl:text>
+    <xsl:text>    {&#10;</xsl:text>
+    <xsl:text>      quark = g_quark_from_static_string ("</xsl:text>
+    <xsl:value-of select="@name"/>
+    <xsl:text>");&#10;</xsl:text>
+    <xsl:text>    }&#10;&#10;</xsl:text>
+    <xsl:text>  return quark;&#10;</xsl:text>
+    <xsl:text>}&#10;&#10;</xsl:text>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et noai noci: -->
diff --git a/tools/glib-interfaces-generator.xsl b/tools/glib-interfaces-generator.xsl
new file mode 100644 (file)
index 0000000..e703c40
--- /dev/null
@@ -0,0 +1,55 @@
+<!-- Stylesheet to extract C interface names from the Telepathy spec.
+The master copy of this stylesheet is in telepathy-glib - please make any
+changes there.
+
+Copyright (C) 2006, 2007 Collabora Limited
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+-->
+
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+  exclude-result-prefixes="tp">
+
+  <xsl:import href="c-interfaces-generator.xsl"/>
+
+  <xsl:template match="interface">
+    <xsl:apply-imports/>
+
+    <xsl:text>/**&#10; * </xsl:text>
+    <xsl:value-of select="$PREFIX"/>
+    <xsl:text>_IFACE_QUARK_</xsl:text>
+    <xsl:value-of select="translate(../@name, concat($lower, '/'), $upper)"/>
+    <xsl:text>:&#10; * &#10; * Expands to a call to a function that </xsl:text>
+    <xsl:text>returns a quark for the interface name "</xsl:text>
+    <xsl:value-of select="@name"/>
+    <xsl:text>"&#10; */&#10;#define </xsl:text>
+    <xsl:value-of select="$PREFIX"/>
+    <xsl:text>_IFACE_QUARK_</xsl:text>
+    <xsl:value-of select="translate(../@name, concat($lower, '/'), $upper)"/>
+    <xsl:text> \&#10;  (</xsl:text>
+    <xsl:value-of select="$prefix"/>
+    <xsl:text>_iface_quark_</xsl:text>
+    <xsl:value-of select="translate(../@name, concat($upper, '/'), $lower)"/>
+    <xsl:text> ())&#10;&#10;GQuark </xsl:text>
+    <xsl:value-of select="$prefix"/>
+    <xsl:text>_iface_quark_</xsl:text>
+    <xsl:value-of select="translate(../@name, concat($upper, '/'), $lower)"/>
+    <xsl:text> (void);&#10;&#10;</xsl:text>
+  </xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim:set sw=2 sts=2 et noai noci: -->
diff --git a/tools/glib-signals-marshal-gen.py b/tools/glib-signals-marshal-gen.py
new file mode 100644 (file)
index 0000000..0d02c13
--- /dev/null
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+from string import ascii_letters, digits
+
+
+from libglibcodegen import signal_to_marshal_name, method_to_glue_marshal_name
+
+
+class Generator(object):
+
+    def __init__(self, dom):
+        self.dom = dom
+        self.marshallers = {}
+
+    def do_method(self, method):
+        marshaller = method_to_glue_marshal_name(method, 'PREFIX')
+
+        assert '__' in marshaller
+        rhs = marshaller.split('__', 1)[1].split('_')
+
+        self.marshallers[marshaller] = rhs
+
+    def do_signal(self, signal):
+        marshaller = signal_to_marshal_name(signal, 'PREFIX')
+
+        assert '__' in marshaller
+        rhs = marshaller.split('__', 1)[1].split('_')
+
+        self.marshallers[marshaller] = rhs
+
+    def __call__(self):
+        methods = self.dom.getElementsByTagName('method')
+
+        for method in methods:
+            self.do_method(method)
+
+        signals = self.dom.getElementsByTagName('signal')
+
+        for signal in signals:
+            self.do_signal(signal)
+
+        all = self.marshallers.keys()
+        all.sort()
+        for marshaller in all:
+            rhs = self.marshallers[marshaller]
+            if not marshaller.startswith('g_cclosure'):
+                print 'VOID:' + ','.join(rhs)
+
+if __name__ == '__main__':
+    argv = sys.argv[1:]
+    dom = xml.dom.minidom.parse(argv[0])
+
+    Generator(dom)()
diff --git a/tools/identity.xsl b/tools/identity.xsl
new file mode 100644 (file)
index 0000000..6630f84
--- /dev/null
@@ -0,0 +1,7 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+       <xsl:template match="@*|node()">
+               <xsl:copy>
+                       <xsl:apply-templates select="@*|node()"/>
+               </xsl:copy>
+       </xsl:template>
+</xsl:stylesheet>
diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py
new file mode 100644 (file)
index 0000000..090e8de
--- /dev/null
@@ -0,0 +1,320 @@
+"""Library code for GLib/D-Bus-related code generation.
+
+The master copy of this library is in the telepathy-glib repository -
+please make any changes there.
+"""
+
+# Copyright (C) 2006, 2007 Collabora Limited
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+from string import ascii_letters, digits
+
+
+NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"
+
+_ASCII_ALNUM = ascii_letters + digits
+
+
+def camelcase_to_lower(s):
+    out ="";
+    out += s[0].lower()
+    last_upper=False
+    if s[0].isupper():
+        last_upper=True
+    for i in range(1,len(s)):
+        if s[i].isupper():
+            if last_upper:
+                if (i+1) < len(s) and  s[i+1].islower():
+                    out += "_" + s[i].lower()
+                else:
+                    out += s[i].lower()
+            else:
+                out += "_" + s[i].lower()
+            last_upper=True
+        else:
+            out += s[i]
+            last_upper=False
+    return out
+
+
+def camelcase_to_upper(s):
+    return camelcase_to_lower(s).upper()
+
+
+def cmp_by_name(node1, node2):
+    return cmp(node1.getAttributeNode("name").nodeValue,
+               node2.getAttributeNode("name").nodeValue)
+
+
+def dbus_gutils_wincaps_to_uscore(s):
+    """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore
+    which gets sequences of capital letters wrong in the same way.
+    (e.g. in Telepathy, SendDTMF -> send_dt_mf)
+    """
+    ret = ''
+    for c in s:
+        if c >= 'A' and c <= 'Z':
+            length = len(ret)
+            if length > 0 and (length < 2 or ret[length-2] != '_'):
+                ret += '_'
+            ret += c.lower()
+        else:
+            ret += c
+    return ret
+
+
+def escape_as_identifier(identifier):
+    """Escape the given string to be a valid D-Bus object path or service
+    name component, using a reversible encoding to ensure uniqueness.
+
+    The reversible encoding is as follows:
+
+    * The empty string becomes '_'
+    * Otherwise, each non-alphanumeric character is replaced by '_' plus
+      two lower-case hex digits; the same replacement is carried out on
+      the first character, if it's a digit
+    """
+    # '' -> '_'
+    if not identifier:
+        return '_'
+
+    # A bit of a fast path for strings which are already OK.
+    # We deliberately omit '_' because, for reversibility, that must also
+    # be escaped.
+    if (identifier.strip(_ASCII_ALNUM) == '' and
+        identifier[0] in ascii_letters):
+        return identifier
+
+    # The first character may not be a digit
+    if identifier[0] not in ascii_letters:
+        ret = ['_%02x' % ord(identifier[0])]
+    else:
+        ret = [identifier[0]]
+
+    # Subsequent characters may be digits or ASCII letters
+    for c in identifier[1:]:
+        if c in _ASCII_ALNUM:
+            ret.append(c)
+        else:
+            ret.append('_%02x' % ord(c))
+
+    return ''.join(ret)
+
+
+def get_docstring(element):
+    docstring = None
+    for x in element.childNodes:
+        if x.namespaceURI == NS_TP and x.localName == 'docstring':
+            docstring = x
+    if docstring is not None:
+        docstring = docstring.toxml().replace('\n', ' ').strip()
+        if docstring.startswith('<tp:docstring>'):
+            docstring = docstring[14:].lstrip()
+        if docstring.endswith('</tp:docstring>'):
+            docstring = docstring[:-15].rstrip()
+        if docstring in ('<tp:docstring/>', ''):
+            docstring = ''
+    return docstring
+
+
+def signal_to_marshal_type(signal):
+    """
+    return a list of strings indicating the marshalling type for this signal.
+    """
+
+    mtype=[]
+    for i in signal.getElementsByTagName("arg"):
+        name =i.getAttribute("name")
+        type = i.getAttribute("type")
+        mtype.append(type_to_gtype(type)[2])
+
+    return mtype
+
+
+_glib_marshallers = ['VOID', 'BOOLEAN', 'CHAR', 'UCHAR', 'INT',
+        'STRING', 'UINT', 'LONG', 'ULONG', 'ENUM', 'FLAGS', 'FLOAT',
+        'DOUBLE', 'STRING', 'PARAM', 'BOXED', 'POINTER', 'OBJECT',
+        'UINT_POINTER']
+
+
+def signal_to_marshal_name(signal, prefix):
+
+    mtype = signal_to_marshal_type(signal)
+    if len(mtype):
+        name = '_'.join(mtype)
+    else:
+        name = 'VOID'
+
+    if name in _glib_marshallers:
+        return 'g_cclosure_marshal_VOID__' + name
+    else:
+        return prefix + '_marshal_VOID__' + name
+
+
+def method_to_glue_marshal_name(method, prefix):
+
+    mtype = []
+    for i in method.getElementsByTagName("arg"):
+        if i.getAttribute("direction") != "out":
+            type = i.getAttribute("type")
+            mtype.append(type_to_gtype(type)[2])
+
+    mtype.append('POINTER')
+
+    name = '_'.join(mtype)
+
+    if name in _glib_marshallers:
+        return 'g_cclosure_marshal_VOID__' + name
+    else:
+        return prefix + '_marshal_VOID__' + name
+
+
+class _SignatureIter:
+    """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we
+    can run genginterface in a limited environment with only Python
+    (like Scratchbox).
+    """
+    def __init__(self, string):
+        self.remaining = string
+
+    def next(self):
+        if self.remaining == '':
+            raise StopIteration
+
+        signature = self.remaining
+        block_depth = 0
+        block_type = None
+        end = len(signature)
+
+        for marker in range(0, end):
+            cur_sig = signature[marker]
+
+            if cur_sig == 'a':
+                pass
+            elif cur_sig == '{' or cur_sig == '(':
+                if block_type == None:
+                    block_type = cur_sig
+
+                if block_type == cur_sig:
+                    block_depth = block_depth + 1
+
+            elif cur_sig == '}':
+                if block_type == '{':
+                    block_depth = block_depth - 1
+
+                if block_depth == 0:
+                    end = marker
+                    break
+
+            elif cur_sig == ')':
+                if block_type == '(':
+                    block_depth = block_depth - 1
+
+                if block_depth == 0:
+                    end = marker
+                    break
+
+            else:
+                if block_depth == 0:
+                    end = marker
+                    break
+
+        end = end + 1
+        self.remaining = signature[end:]
+        return Signature(signature[0:end])
+
+
+class Signature(str):
+    """A string, iteration over which is by D-Bus single complete types
+    rather than characters.
+    """
+    def __iter__(self):
+        return _SignatureIter(self)
+
+
+def type_to_gtype(s):
+    if s == 'y': #byte
+        return ("guchar ", "G_TYPE_UCHAR","UCHAR", False)
+    elif s == 'b': #boolean
+        return ("gboolean ", "G_TYPE_BOOLEAN","BOOLEAN", False)
+    elif s == 'n': #int16
+        return ("gint ", "G_TYPE_INT","INT", False)
+    elif s == 'q': #uint16
+        return ("guint ", "G_TYPE_UINT","UINT", False)
+    elif s == 'i': #int32
+        return ("gint ", "G_TYPE_INT","INT", False)
+    elif s == 'u': #uint32
+        return ("guint ", "G_TYPE_UINT","UINT", False)
+    elif s == 'x': #int64
+        return ("gint64 ", "G_TYPE_INT64","INT64", False)
+    elif s == 't': #uint64
+        return ("guint64 ", "G_TYPE_UINT64","UINT64", False)
+    elif s == 'd': #double
+        return ("gdouble ", "G_TYPE_DOUBLE","DOUBLE", False)
+    elif s == 's': #string
+        return ("gchar *", "G_TYPE_STRING", "STRING", True)
+    elif s == 'g': #signature - FIXME
+        return ("gchar *", "DBUS_TYPE_G_SIGNATURE", "STRING", True)
+    elif s == 'o': #object path
+        return ("gchar *", "DBUS_TYPE_G_OBJECT_PATH", "BOXED", True)
+    elif s == 'v':  #variant
+        return ("GValue *", "G_TYPE_VALUE", "BOXED", True)
+    elif s == 'as':  #array of strings
+        return ("gchar **", "G_TYPE_STRV", "BOXED", True)
+    elif s == 'ay': #byte array
+        return ("GArray *",
+            "dbus_g_type_get_collection (\"GArray\", G_TYPE_UCHAR)", "BOXED",
+            True)
+    elif s == 'au': #uint array
+        return ("GArray *", "DBUS_TYPE_G_UINT_ARRAY", "BOXED", True)
+    elif s == 'ai': #int array
+        return ("GArray *", "DBUS_TYPE_G_INT_ARRAY", "BOXED", True)
+    elif s == 'ax': #int64 array
+        return ("GArray *", "DBUS_TYPE_G_INT64_ARRAY", "BOXED", True)
+    elif s == 'at': #uint64 array
+        return ("GArray *", "DBUS_TYPE_G_UINT64_ARRAY", "BOXED", True)
+    elif s == 'ad': #double array
+        return ("GArray *", "DBUS_TYPE_G_DOUBLE_ARRAY", "BOXED", True)
+    elif s == 'ab': #boolean array
+        return ("GArray *", "DBUS_TYPE_G_BOOLEAN_ARRAY", "BOXED", True)
+    elif s == 'ao': #object path array
+        return ("GArray *", "DBUS_TYPE_G_OBJECT_ARRAY", "BOXED", True)
+    elif s == 'a{ss}': #hash table of string to string
+        return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False)
+    elif s[:2] == 'a{':  #some arbitrary hash tables
+        if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'):
+            raise Exception, "can't index a hashtable off non-basic type " + s
+        first = type_to_gtype(s[2])
+        second = type_to_gtype(s[3:-1])
+        return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False)
+    elif s[:2] in ('a(', 'aa'): # array of structs or arrays, recurse
+        gtype = type_to_gtype(s[1:])[1]
+        return ("GPtrArray *", "(dbus_g_type_get_collection (\"GPtrArray\", "+gtype+"))", "BOXED", True)
+    elif s[:1] == '(': #struct
+        gtype = "(dbus_g_type_get_struct (\"GValueArray\", "
+        for subsig in Signature(s[1:-1]):
+            gtype = gtype + type_to_gtype(subsig)[1] + ", "
+        gtype = gtype + "G_TYPE_INVALID))"
+        return ("GValueArray *", gtype, "BOXED", True)
+
+    # we just don't know ..
+    raise Exception, "don't know the GType for " + s
+
+
+def xml_escape(s):
+    s = s.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;')
+    return s.replace('<', '&lt;').replace('>', '&gt;')