[empathy] Update tools from telepathy-glib



commit 621bbbb8631f4b149d0478a3423687e4e973b04f
Author: Emilio Pozuelo Monfort <emilio pozuelo collabora co uk>
Date:   Tue Feb 1 13:47:58 2011 +0000

    Update tools from telepathy-glib

 extensions/Makefile.am               |   12 +-
 tools/Makefile.am                    |   14 +-
 tools/c-constants-gen.py             |   84 +++++---
 tools/check-coding-style.mk          |    4 +-
 tools/git-which-branch.sh            |   25 +++
 tools/glib-client-gen.py             |  283 +++++++++++++++----------
 tools/glib-errors-check-gen.py       |   58 +++++
 tools/glib-errors-enum-body-gen.py   |   62 ------
 tools/glib-errors-enum-header-gen.py |   75 -------
 tools/glib-errors-str-gen.py         |   82 +++++++
 tools/glib-ginterface-gen.py         |  293 +++++++++++++++++---------
 tools/glib-gtypes-generator.py       |  214 ++++++++++++-------
 tools/glib-interfaces-gen.py         |  138 +++++++++++--
 tools/gobject-foo.py                 |   23 ++-
 tools/identity.xsl                   |    7 -
 tools/libglibcodegen.py              |    5 +-
 tools/libtpcodegen.py                |   36 +---
 tools/make-release-mail.py           |   76 +++++++
 tools/manager-file.py                |  175 +++++++++++++++
 tools/shave.mk                       |    1 +
 tools/telepathy-glib.supp            |  390 ++++++++++++++++++++++++++++++++++
 tools/test-wrapper.sh                |   30 +++
 tools/valgrind.mk                    |   13 ++
 tools/with-session-bus.sh            |   10 +-
 tools/xincludator.py                 |   39 ++++
 25 files changed, 1623 insertions(+), 526 deletions(-)
---
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index ef8b751..0d540f5 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -59,10 +59,9 @@ XSLTPROCFLAGS = --nonet --novalid
 
 # Generated files which can be generated for all categories simultaneously
 
-_gen/all.xml: all.xml $(wildcard *.xml)
+_gen/all.xml: all.xml $(wildcard *.xml) $(tools_dir)/xincludator.py
 	@$(mkdir_p) _gen
-	$(AM_V_GEN)$(XSLTPROC) $(XSLTPROCFLAGS) --xinclude $(tools_dir)/identity.xsl \
-		$< > $@
+	$(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
 
 extensions.html: _gen/all.xml $(tools_dir)/doc-generator.xsl
 	$(AM_V_GEN)$(XSLTPROC) $(XSLTPROCFLAGS) \
@@ -95,7 +94,7 @@ _gen/enums.h: _gen/all.xml \
 	$(tools_dir)/c-constants-gen.py
 	$(AM_V_GEN)$(PYTHON) $(tools_dir)/c-constants-gen.py \
 		Emp \
-		$< > $@
+		$< _gen/enums
 
 _gen/interfaces-body.h _gen/interfaces.h: _gen/all.xml \
 	$(tools_dir)/glib-interfaces-gen.py
@@ -106,10 +105,9 @@ _gen/interfaces-body.h _gen/interfaces.h: _gen/all.xml \
 # subclass you want to use with --subclass will need to have its own category,
 # although you can subdivide further if you want.
 
-_gen/misc.xml: misc.xml $(wildcard *.xml)
+_gen/misc.xml: misc.xml $(wildcard *.xml) $(tools_dir)/xincludator.py
 	@$(mkdir_p) _gen
-	$(AM_V_GEN)$(XSLTPROC) $(XSLTPROCFLAGS) --xinclude $(tools_dir)/identity.xsl \
-		$< > $@
+	$(AM_V_GEN)$(PYTHON) $(tools_dir)/xincludator.py $< > $@
 
 _gen/cli-misc-body.h _gen/cli-misc.h: _gen/misc.xml \
 	$(tools_dir)/glib-client-gen.py
diff --git a/tools/Makefile.am b/tools/Makefile.am
index c9ac350..96cc60f 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -14,23 +14,29 @@ EXTRA_DIST = \
     check-whitespace.sh \
     doc-generator.xsl \
     flymake.mk \
+    git-which-branch.sh \
     glib-client-gen.py \
     glib-client-marshaller-gen.py \
-    glib-errors-enum-body-gen.py \
-    glib-errors-enum-header-gen.py \
+    glib-errors-check-gen.py \
+    glib-errors-str-gen.py \
     glib-ginterface-gen.py \
     glib-gtypes-generator.py \
     glib-interfaces-gen.py \
     glib-signals-marshal-gen.py \
     gobject-foo.py \
-    identity.xsl \
     lcov.am \
     libtpcodegen.py \
     libglibcodegen.py \
+    make-release-mail.py \
     make-version-script.py \
+    manager-file.py \
+    shave.mk \
     telepathy.am \
+    telepathy-glib.supp \
     telepathy-glib-env.in \
-    with-session-bus.sh
+    test-wrapper.sh \
+    with-session-bus.sh \
+    xincludator.py
 
 CLEANFILES = libtpcodegen.pyc libtpcodegen.pyo libglibcodegen.pyc libglibcodegen.pyo $(noinst_SCRIPTS)
 
diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py
index f338257..188ab82 100644
--- a/tools/c-constants-gen.py
+++ b/tools/c-constants-gen.py
@@ -3,34 +3,43 @@
 from sys import argv, stdout, stderr
 import xml.dom.minidom
 
-from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \
+from libglibcodegen import NS_TP, get_docstring, \
         get_descendant_text, get_by_path
 
 class Generator(object):
-    def __init__(self, prefix, dom):
+    def __init__(self, prefix, dom, output_base):
         self.prefix = prefix + '_'
         self.spec = get_by_path(dom, "spec")[0]
 
+        self.__header = open(output_base + '.h', 'w')
+        self.__docs = open(output_base + '-gtk-doc.h', 'w')
+
     def __call__(self):
         self.do_header()
         self.do_body()
         self.do_footer()
 
+    def write(self, code):
+        self.__header.write(code.encode('utf-8'))
+
+    def d(self, code):
+        self.__docs.write(code.encode('utf-8'))
+
     # Header
     def do_header(self):
-        stdout.write('/* Generated from ')
-        stdout.write(get_descendant_text(get_by_path(self.spec, 'title')))
+        self.write('/* Generated from ')
+        self.write(get_descendant_text(get_by_path(self.spec, 'title')))
         version = get_by_path(self.spec, "version")
         if version:
-            stdout.write(', version ' + get_descendant_text(version))
-        stdout.write('\n\n')
+            self.write(', version ' + get_descendant_text(version))
+        self.write('\n\n')
         for copyright in get_by_path(self.spec, 'copyright'):
-            stdout.write(get_descendant_text(copyright))
-            stdout.write('\n')
-        stdout.write(get_descendant_text(get_by_path(self.spec, 'license')))
-        stdout.write('\n')
-        stdout.write(get_descendant_text(get_by_path(self.spec, 'docstring')))
-        stdout.write("""
+            self.write(get_descendant_text(copyright))
+            self.write('\n')
+        self.write(get_descendant_text(get_by_path(self.spec, 'license')))
+        self.write('\n')
+        self.write(get_descendant_text(get_by_path(self.spec, 'docstring')))
+        self.write("""
  */
 
 #ifdef __cplusplus
@@ -51,28 +60,30 @@ extern "C" {
         value_prefix = flags.getAttribute('singular') or \
                        flags.getAttribute('value-prefix') or \
                        flags.getAttribute('name')
-        stdout.write("""\
+        self.d("""\
 /**
  *
 %s:
 """ % (self.prefix + name).replace('_', ''))
         for flag in get_by_path(flags, 'flag'):
             self.do_gtkdoc(flag, value_prefix)
-        stdout.write(' *\n')
+        self.d(' *\n')
         docstrings = get_by_path(flags, 'docstring')
         if docstrings:
-            stdout.write("""\
+            self.d("""\
  * <![CDATA[%s]]>
  *
 """ % get_descendant_text(docstrings).replace('\n', ' '))
-        stdout.write("""\
+        self.d("""\
  * Bitfield/set of flags generated from the Telepathy specification.
  */
-typedef enum {
 """)
+
+        self.write("typedef enum /*< flags >*/ {\n")
+
         for flag in get_by_path(flags, 'flag'):
             self.do_val(flag, value_prefix)
-        stdout.write("""\
+        self.write("""\
 } %s;
 
 """ % (self.prefix + name).replace('_', ''))
@@ -84,7 +95,7 @@ typedef enum {
                        enum.getAttribute('name')
         name_plural = enum.getAttribute('plural') or \
                       enum.getAttribute('name') + 's'
-        stdout.write("""\
+        self.d("""\
 /**
  *
 %s:
@@ -92,28 +103,35 @@ typedef enum {
         vals = get_by_path(enum, 'enumvalue')
         for val in vals:
             self.do_gtkdoc(val, value_prefix)
-        stdout.write(' *\n')
+        self.d(' *\n')
         docstrings = get_by_path(enum, 'docstring')
         if docstrings:
-            stdout.write("""\
+            self.d("""\
  * <![CDATA[%s]]>
  *
 """ % get_descendant_text(docstrings).replace('\n', ' '))
-        stdout.write("""\
+        self.d("""\
  * Bitfield/set of flags generated from the Telepathy specification.
  */
-typedef enum {
 """)
+
+        self.write("typedef enum {\n")
+
         for val in vals:
             self.do_val(val, value_prefix)
-        stdout.write("""\
-} %(mixed-name)s;
+        self.write("} %s;\n" % (self.prefix + name).replace('_', ''))
 
+        self.d("""\
 /**
  * NUM_%(upper-plural)s:
  *
  * 1 higher than the highest valid value of #%(mixed-name)s.
  */
+""" % {'mixed-name' : (self.prefix + name).replace('_', ''),
+       'upper-plural' : (self.prefix + name_plural).upper(),
+       'last-val' : vals[-1].getAttribute('value')})
+
+        self.write("""\
 #define NUM_%(upper-plural)s (%(last-val)s+1)
 
 """ % {'mixed-name' : (self.prefix + name).replace('_', ''),
@@ -127,20 +145,20 @@ typedef enum {
                 (suffix or name)).upper()
         assert not (name and suffix) or name == suffix, \
                 'Flag/enumvalue name %s != suffix %s' % (name, suffix)
-        stdout.write('    %s = %s,\n' % (use_name, val.getAttribute('value')))
+        self.write('    %s = %s,\n' % (use_name, val.getAttribute('value')))
 
     def do_gtkdoc(self, node, value_prefix):
-        stdout.write(' * @')
-        stdout.write((self.prefix + value_prefix + '_' +
+        self.d(' * @')
+        self.d((self.prefix + value_prefix + '_' +
             node.getAttribute('suffix')).upper())
-        stdout.write(': <![CDATA[')
+        self.d(': <![CDATA[')
         docstring = get_by_path(node, 'docstring')
-        stdout.write(get_descendant_text(docstring).replace('\n', ' '))
-        stdout.write(']]>\n')
+        self.d(get_descendant_text(docstring).replace('\n', ' '))
+        self.d(']]>\n')
 
     # Footer
     def do_footer(self):
-        stdout.write("""
+        self.write("""
 #ifdef __cplusplus
 }
 #endif
@@ -148,4 +166,4 @@ typedef enum {
 
 if __name__ == '__main__':
     argv = argv[1:]
-    Generator(argv[0], xml.dom.minidom.parse(argv[1]))()
+    Generator(argv[0], xml.dom.minidom.parse(argv[1]), argv[2])()
diff --git a/tools/check-coding-style.mk b/tools/check-coding-style.mk
index 3fc92fc..1c0a60f 100644
--- a/tools/check-coding-style.mk
+++ b/tools/check-coding-style.mk
@@ -3,12 +3,12 @@ check-coding-style:
 	if test -n "$(check_misc_sources)"; then \
 		tools_dir=$(top_srcdir)/tools \
 		sh $(top_srcdir)/tools/check-misc.sh \
-			$(check_misc_sources) || fail=1; \
+			$(addprefix $(srcdir)/,$(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; \
+			$(addprefix $(srcdir)/,$(check_c_sources)) || fail=1; \
 	fi;\
 	if test yes = "$(ENABLE_CODING_STYLE_CHECKS)"; then \
 		exit "$$fail";\
diff --git a/tools/git-which-branch.sh b/tools/git-which-branch.sh
new file mode 100644
index 0000000..b96b5d5
--- /dev/null
+++ b/tools/git-which-branch.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+# git-which-branch.sh - output the name of the current git branch
+#
+# The canonical location of this program is the telepathy-spec tools/
+# directory, please synchronize any changes with that copy.
+#
+# Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/>
+#
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.
+
+default="$1"
+if { ref="`git symbolic-ref HEAD 2>/dev/null`"; }; then
+    echo ${ref#refs/heads/}
+    exit 0
+fi
+
+if test -n "$default"; then
+    echo "$default" >/dev/null
+    exit 0
+fi
+
+echo "no git branch found" >&2
+exit 1
diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py
index 701fcaf..6b0bdeb 100644
--- a/tools/glib-client-gen.py
+++ b/tools/glib-client-gen.py
@@ -28,7 +28,7 @@ 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
+        get_docstring, xml_escape, get_deprecated
 
 
 NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0";
@@ -39,6 +39,7 @@ class Generator(object):
         self.dom = dom
         self.__header = []
         self.__body = []
+        self.__docs = []
 
         self.prefix_lc = prefix.lower()
         self.prefix_uc = prefix.upper()
@@ -55,6 +56,11 @@ class Generator(object):
             % opts.get('--subclass', 'TpProxy'))
         if self.proxy_arg == 'void *':
             self.proxy_arg = 'gpointer '
+        self.generate_reentrant = ('--generate-reentrant' in opts or
+                '--deprecate-reentrant' in opts)
+        self.deprecate_reentrant = opts.get('--deprecate-reentrant', None)
+        self.deprecation_attribute = opts.get('--deprecation-attribute',
+                'G_GNUC_DEPRECATED')
 
     def h(self, s):
         if isinstance(s, unicode):
@@ -66,6 +72,11 @@ class Generator(object):
             s = s.encode('utf-8')
         self.__body.append(s)
 
+    def d(self, s):
+        if isinstance(s, unicode):
+            s = s.encode('utf-8')
+        self.__docs.append(s)
+
     def get_iface_quark(self):
         assert self.iface_dbus is not None
         assert self.iface_uc is not None
@@ -78,7 +89,11 @@ class Generator(object):
         iface_lc = iface.lower()
 
         member = signal.getAttribute('name')
-        member_lc = camelcase_to_lower(member)
+        member_lc = signal.getAttribute('tp:name-for-bindings')
+        if member != member_lc.replace('_', ''):
+            raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
+                    'not match' % (member, member_lc))
+        member_lc = member_lc.lower()
         member_uc = member_lc.upper()
 
         arg_count = 0
@@ -114,25 +129,27 @@ class Generator(object):
         #   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.d('/**')
+        self.d(' * %s:' % callback_name)
+        self.d(' * @proxy: The proxy on which %s_%s_connect_to_%s ()'
                % (self.prefix_lc, iface_lc, member_lc))
-        self.b(' *  was called')
+        self.d(' *  was called')
 
         for arg in args:
             name, info, tp_type, elt = arg
             ctype, gtype, marshaller, pointer = info
 
-            self.b(' * @%s: %s' % (name,
+            self.d(' * @%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.'
+        self.d(' * @user_data: User-supplied data')
+        self.d(' * @weak_object: User-supplied weakly referenced object')
+        self.d(' *')
+        self.d(' * Represents the signature of a callback for the signal %s.'
                % member)
-        self.b(' */')
+        self.d(' */')
+        self.d('')
+
         self.h('typedef void (*%s) (%sproxy,'
                % (callback_name, self.proxy_cls))
 
@@ -281,31 +298,33 @@ class Generator(object):
         # emitted the 'invalidated' signal, or because the weakly referenced
         # object has gone away.
 
-        self.b('/**')
-        self.b(' * %s_%s_connect_to_%s:'
+        self.d('/**')
+        self.d(' * %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.d(' * @proxy: %s' % self.proxy_doc)
+        self.d(' * @callback: Callback to be called when the signal is')
+        self.d(' *   received')
+        self.d(' * @user_data: User-supplied data for the callback')
+        self.d(' * @destroy: Destructor for the user-supplied data, which')
+        self.d(' *   will be called when this signal is disconnected, or')
+        self.d(' *   before this function returns %NULL')
+        self.d(' * @weak_object: A #GObject which will be weakly referenced; ')
+        self.d(' *   if it is destroyed, this callback will automatically be')
+        self.d(' *   disconnected')
+        self.d(' * @error: If not %NULL, used to raise an error if %NULL is')
+        self.d(' *   returned')
+        self.d(' *')
+        self.d(' * Connect a handler to the signal %s.' % member)
+        self.d(' *')
+        self.d(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)'))
+        self.d(' *')
+        self.d(' * Returns: a #TpProxySignalConnection containing all of the')
+        self.d(' * above, which can be used to disconnect the signal; or')
+        self.d(' * %NULL if the proxy does not have the desired interface')
+        self.d(' * or has become invalid.')
+        self.d(' */')
+        self.d('')
+
         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)
@@ -313,6 +332,7 @@ class Generator(object):
         self.h('    GDestroyNotify destroy,')
         self.h('    GObject *weak_object,')
         self.h('    GError **error);')
+        self.h('')
 
         self.b('TpProxySignalConnection *')
         self.b('%s_%s_connect_to_%s (%sproxy,'
@@ -352,13 +372,15 @@ class Generator(object):
         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_lc = method.getAttribute('tp:name-for-bindings')
+        if member != member_lc.replace('_', ''):
+            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+                    'not match' % (member, member_lc))
+        member_lc = member_lc.lower()
         member_uc = member_lc.upper()
 
         in_count = 0
@@ -401,27 +423,35 @@ class Generator(object):
         #       gpointer user_data,
         #       GObject *weak_object);
 
-        self.b('/**')
-        self.b(' * %s_%s_callback_for_%s:'
+        self.d('/**')
+        self.d(' * %s_%s_callback_for_%s:'
                % (self.prefix_lc, iface_lc, member_lc))
-        self.b(' * @proxy: the proxy on which the call was made')
+        self.d(' * @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 '
+            self.d(' * @%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'
+        self.d(' * @error: %NULL on success, or an error on failure')
+        self.d(' * @user_data: user-supplied data')
+        self.d(' * @weak_object: user-supplied object')
+        self.d(' *')
+        self.d(' * Signature of the callback called when a %s method call'
                % member)
-        self.b(' * succeeds or fails.')
-        self.b(' */')
+        self.d(' * succeeds or fails.')
+
+        deprecated = method.getElementsByTagName('tp:deprecated')
+        if deprecated:
+            d = deprecated[0]
+            self.d(' *')
+            self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
+
+        self.d(' */')
+        self.d('')
 
         callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc,
                                                    member_lc)
@@ -646,42 +676,51 @@ class Generator(object):
                % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
         self.h('    gint timeout_ms,')
 
-        self.b('/**')
-        self.b(' * %s_%s_call_%s:'
+        self.d('/**')
+        self.d(' * %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')
+        self.d(' * @proxy: the #TpProxy')
+        self.d(' * @timeout_ms: the timeout in milliseconds, or -1 to use the')
+        self.d(' *   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'
+            self.d(' * @%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(' *   may be %NULL to make a "fire and forget" call with no ')
-        self.b(' *   reply tracking')
-        self.b(' * @user_data: user-supplied data passed to the callback;')
-        self.b(' *   must be %NULL if @callback is %NULL')
-        self.b(' * @destroy: called with the user_data as argument, after the')
-        self.b(' *   call has succeeded, failed or been cancelled;')
-        self.b(' *   must be %NULL if @callback is %NULL')
-        self.b(' * @weak_object: If not %NULL, a #GObject which will be ')
-        self.b(' *   weakly referenced; if it is destroyed, this call ')
-        self.b(' *   will automatically be cancelled. Must be %NULL if ')
-        self.b(' *   @callback is %NULL')
-        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.d(' * @callback: called when the method call succeeds or fails;')
+        self.d(' *   may be %NULL to make a "fire and forget" call with no ')
+        self.d(' *   reply tracking')
+        self.d(' * @user_data: user-supplied data passed to the callback;')
+        self.d(' *   must be %NULL if @callback is %NULL')
+        self.d(' * @destroy: called with the user_data as argument, after the')
+        self.d(' *   call has succeeded, failed or been cancelled;')
+        self.d(' *   must be %NULL if @callback is %NULL')
+        self.d(' * @weak_object: If not %NULL, a #GObject which will be ')
+        self.d(' *   weakly referenced; if it is destroyed, this call ')
+        self.d(' *   will automatically be cancelled. Must be %NULL if ')
+        self.d(' *   @callback is %NULL')
+        self.d(' *')
+        self.d(' * Start a %s method call.' % member)
+        self.d(' *')
+        self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
+        self.d(' *')
+        self.d(' * Returns: a #TpProxyPendingCall representing the call in')
+        self.d(' *  progress. It is borrowed from the object, and will become')
+        self.d(' *  invalid when the callback is called, the call is')
+        self.d(' *  cancelled or the #TpProxy becomes invalid.')
+
+        deprecated = method.getElementsByTagName('tp:deprecated')
+        if deprecated:
+            d = deprecated[0]
+            self.d(' *')
+            self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
+
+        self.d(' */')
+        self.d('')
+
         self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,'
                % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
         self.b('    gint timeout_ms,')
@@ -793,6 +832,17 @@ class Generator(object):
         self.b('}')
         self.b('')
 
+        if self.generate_reentrant:
+            self.do_method_reentrant(method, iface_lc, member, member_lc,
+                                     in_args, out_args, collect_callback)
+
+        # leave a gap for the end of the method
+        self.d('')
+        self.b('')
+        self.h('')
+
+    def do_method_reentrant(self, method, iface_lc, member, member_lc, in_args,
+            out_args, collect_callback):
         # Reentrant blocking calls
         # Example:
         # gboolean tp_cli_properties_interface_run_get_properties
@@ -877,48 +927,60 @@ class Generator(object):
         self.b('}')
         self.b('')
 
+        if self.deprecate_reentrant:
+            self.h('#ifndef %s' % self.deprecate_reentrant)
+
         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')
+        self.d('/**')
+        self.d(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc))
+        self.d(' * @proxy: %s' % self.proxy_doc)
+        self.d(' * @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'
+            self.d(' * @%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 '
+            self.d(' * @%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.d(' * @error: If not %NULL, used to return errors if %FALSE ')
+        self.d(' *  is returned')
+        self.d(' * @loop: If not %NULL, set before re-entering ')
+        self.d(' *  the main loop, to point to a #GMainLoop ')
+        self.d(' *  which can be used to cancel this call with ')
+        self.d(' *  g_main_loop_quit(), causing a return of ')
+        self.d(' *  %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED')
+        self.d(' *')
+        self.d(' * Call the method %s and run the main loop' % member)
+        self.d(' * until it returns. Before calling this method, you must')
+        self.d(' * add a reference to any borrowed objects you need to keep,')
+        self.d(' * and generally ensure that everything is in a consistent')
+        self.d(' * state.')
+        self.d(' *')
+        self.d(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)'))
+        self.d(' *')
+        self.d(' * Returns: TRUE on success, FALSE and sets @error on error')
+
+        deprecated = method.getElementsByTagName('tp:deprecated')
+        if deprecated:
+            d = deprecated[0]
+            self.d(' *')
+            self.d(' * Deprecated: %s' % xml_escape(get_deprecated(d)))
+
+        self.d(' */')
+        self.d('')
+
         self.b('gboolean\n%s_%s_run_%s (%sproxy,'
                % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg))
         self.b('    gint timeout_ms,')
@@ -940,7 +1002,13 @@ class Generator(object):
             self.b('    %s*%s,' % (ctype, name))
 
         self.h('    GError **error,')
-        self.h('    GMainLoop **loop);')
+
+        if self.deprecate_reentrant:
+            self.h('    GMainLoop **loop) %s;' % self.deprecation_attribute)
+            self.h('#endif /* not %s */' % self.deprecate_reentrant)
+        else:
+            self.h('    GMainLoop **loop);')
+
         self.h('')
 
         self.b('    GError **error,')
@@ -1012,10 +1080,6 @@ class Generator(object):
         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 = []
@@ -1136,6 +1200,7 @@ class Generator(object):
 
         open(self.basename + '.h', 'w').write('\n'.join(self.__header))
         open(self.basename + '-body.h', 'w').write('\n'.join(self.__body))
+        open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs))
 
 
 def types_to_gtypes(types):
@@ -1145,7 +1210,9 @@ def types_to_gtypes(types):
 if __name__ == '__main__':
     options, argv = gnu_getopt(sys.argv[1:], '',
                                ['group=', 'subclass=', 'subclass-assert=',
-                                'iface-quark-prefix=', 'tp-proxy-api='])
+                                'iface-quark-prefix=', 'tp-proxy-api=',
+                                'generate-reentrant', 'deprecate-reentrant=',
+                                'deprecation-attribute='])
 
     opts = {}
 
diff --git a/tools/glib-errors-check-gen.py b/tools/glib-errors-check-gen.py
new file mode 100644
index 0000000..553fc9c
--- /dev/null
+++ b/tools/glib-errors-check-gen.py
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, get_docstring, get_descendant_text
+
+class Generator(object):
+    def __init__(self, dom):
+        self.dom = dom
+        self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0]
+
+    def __call__(self):
+
+        print '{'
+        print '  GEnumClass *klass;'
+        print '  GEnumValue *value_by_name;'
+        print '  GEnumValue *value_by_nick;'
+        print ''
+        print '  g_type_init ();'
+        print '  klass = g_type_class_ref (TP_TYPE_ERROR);'
+
+        for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'):
+            ns = error.parentNode.getAttribute('namespace')
+            nick = error.getAttribute('name').replace(' ', '')
+            enum = ('TP_ERROR_' +
+                    error.getAttribute('name').replace(' ', '_').replace('.', '_').upper())
+            s = ('TP_ERROR_STR_' +
+                 error.getAttribute('name').replace(' ', '_').replace('.', '_').upper())
+
+            print ''
+            print '  /* %s.%s */' % (ns, nick)
+            print ('  value_by_name = g_enum_get_value_by_name (klass, "%s");'
+                    % enum)
+            print ('  value_by_nick = g_enum_get_value_by_nick (klass, "%s");'
+                    % nick)
+            print ('  g_assert (value_by_name != NULL);')
+            print ('  g_assert (value_by_nick != NULL);')
+            print ('  g_assert_cmpint (value_by_name->value, ==, %s);'
+                    % enum)
+            print ('  g_assert_cmpint (value_by_nick->value, ==, %s);'
+                    % enum)
+            print ('  g_assert_cmpstr (value_by_name->value_name, ==, "%s");'
+                    % enum)
+            print ('  g_assert_cmpstr (value_by_nick->value_name, ==, "%s");'
+                    % enum)
+            print ('  g_assert_cmpstr (value_by_name->value_nick, ==, "%s");'
+                    % nick)
+            print ('  g_assert_cmpstr (value_by_nick->value_nick, ==, "%s");'
+                    % nick)
+            print ('  g_assert_cmpstr (%s, ==, TP_ERROR_PREFIX ".%s");'
+                    % (s, nick))
+
+        print '}'
+
+if __name__ == '__main__':
+    argv = sys.argv[1:]
+    Generator(xml.dom.minidom.parse(argv[0]))()
diff --git a/tools/glib-errors-str-gen.py b/tools/glib-errors-str-gen.py
new file mode 100644
index 0000000..a948a7c
--- /dev/null
+++ b/tools/glib-errors-str-gen.py
@@ -0,0 +1,82 @@
+#!/usr/bin/python
+
+import sys
+import xml.dom.minidom
+
+from libglibcodegen import NS_TP, get_docstring, xml_escape
+
+class Generator(object):
+    def __init__(self, dom, basename):
+        self.dom = dom
+        self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0]
+        self.basename = basename
+
+        self.__header = []
+        self.__body = []
+        self.__docs = []
+
+    def h(self, s):
+        if isinstance(s, unicode):
+            s = s.encode('utf-8')
+        self.__header.append(s)
+
+    def b(self, s):
+        if isinstance(s, unicode):
+            s = s.encode('utf-8')
+        self.__body.append(s)
+
+    def d(self, s):
+        if isinstance(s, unicode):
+            s = s.encode('utf-8')
+        self.__docs.append(s)
+
+    def __call__(self):
+        errors = self.errors.getElementsByTagNameNS(NS_TP, 'error')
+
+        self.b('#include <telepathy-glib/errors.h>')
+        self.b('')
+        self.b('const gchar *')
+        self.b('tp_error_get_dbus_name (TpError error)')
+        self.b('{')
+        self.b('  switch (error)')
+        self.b('    {')
+
+        for error in errors:
+            ns = error.parentNode.getAttribute('namespace')
+            nick = error.getAttribute('name').replace(' ', '')
+            uc_nick = error.getAttribute('name').replace(' ', '_').replace('.', '_').upper()
+            name = 'TP_ERROR_STR_' + uc_nick
+            error_name = '%s.%s' % (ns, nick)
+
+            self.d('/**')
+            self.d(' * %s:' % name)
+            self.d(' *')
+            self.d(' * The D-Bus error name %s' % error_name)
+            self.d(' *')
+            self.d(' * %s' % xml_escape(get_docstring(error)))
+            self.d(' */')
+            self.d('')
+
+            self.h('#define %s "%s"' % (name, error_name))
+
+            self.b('      case TP_ERROR_%s:' % uc_nick)
+            self.b('        return %s;' % name)
+
+        self.b('      default:')
+        self.b('        g_return_val_if_reached (NULL);')
+        self.b('    }')
+        self.b('}')
+
+        # make both files end with a newline
+        self.h('')
+        self.b('')
+
+        open(self.basename + '.h', 'w').write('\n'.join(self.__header))
+        open(self.basename + '.c', 'w').write('\n'.join(self.__body))
+        open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs))
+
+if __name__ == '__main__':
+    argv = sys.argv[1:]
+    basename = argv[0]
+
+    Generator(xml.dom.minidom.parse(argv[1]), basename)()
diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py
index 9eb7af5..9dfdcc7 100644
--- a/tools/glib-ginterface-gen.py
+++ b/tools/glib-ginterface-gen.py
@@ -27,7 +27,7 @@ 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, \
+        NS_TP, dbus_gutils_wincaps_to_uscore, \
         signal_to_marshal_name, method_to_glue_marshal_name
 
 
@@ -41,6 +41,7 @@ class Generator(object):
         self.dom = dom
         self.__header = []
         self.__body = []
+        self.__docs = []
 
         assert prefix.endswith('_')
         assert not signal_marshal_prefix.endswith('_')
@@ -66,6 +67,7 @@ class Generator(object):
         self.prefix_ = prefix.lower()
         self.PREFIX_ = prefix.upper()
 
+        self.basename = basename
         self.signal_marshal_prefix = signal_marshal_prefix
         self.headers = headers
         self.end_headers = end_headers
@@ -73,11 +75,20 @@ class Generator(object):
         self.allow_havoc = allow_havoc
 
     def h(self, s):
+        if isinstance(s, unicode):
+            s = s.encode('utf-8')
         self.__header.append(s)
 
     def b(self, s):
+        if isinstance(s, unicode):
+            s = s.encode('utf-8')
         self.__body.append(s)
 
+    def d(self, s):
+        if isinstance(s, unicode):
+            s = s.encode('utf-8')
+        self.__docs.append(s)
+
     def do_node(self, node):
         node_name = node.getAttribute('name').replace('/', '')
         node_name_mixed = self.node_name_mixed = node_name.replace('_', '')
@@ -157,20 +168,55 @@ class Generator(object):
         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 '
+        self.d('/**')
+        self.d(' * %s%s:' % (self.Prefix, node_name_mixed))
+        self.d(' *')
+        self.d(' * Dummy typedef representing any implementation of this '
                'interface.')
-        self.h(' */')
+        self.d(' */')
+
         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.d('/**')
+        self.d(' * %s%sClass:' % (self.Prefix, node_name_mixed))
+        self.d(' *')
+        self.d(' * The class of %s%s.' % (self.Prefix, node_name_mixed))
+
+        if methods:
+            self.d(' *')
+            self.d(' * In a full implementation of this interface (i.e. all')
+            self.d(' * methods implemented), the interface initialization')
+            self.d(' * function used in G_IMPLEMENT_INTERFACE() would')
+            self.d(' * typically look like this:')
+            self.d(' *')
+            self.d(' * <programlisting>')
+            self.d(' * static void')
+            self.d(' * implement_%s (gpointer klass,' % self.node_name_lc)
+            self.d(' *     gpointer unused G_GNUC_UNUSED)')
+            self.d(' * {')
+            self.d(' * #define IMPLEMENT(x) %s%s_implement_&num;&num;x (\\'
+                   % (self.prefix_, self.node_name_lc))
+            self.d(' *   klass, my_object_&num;&num;x)')
+
+            for method in methods:
+                class_member_name = method.getAttribute('tp:name-for-bindings')
+                class_member_name = class_member_name.lower()
+                self.d(' *   IMPLEMENT (%s);' % class_member_name)
+
+            self.d(' * #undef IMPLEMENT')
+            self.d(' * }')
+            self.d(' * </programlisting>')
+        else:
+            self.d(' * This interface has no D-Bus methods, so an')
+            self.d(' * implementation can typically pass %NULL to')
+            self.d(' * G_IMPLEMENT_INTERFACE() as the interface')
+            self.d(' * initialization function.')
+
+        self.d(' */')
+        self.d('')
+
         self.h('typedef struct _%s%sClass %s%sClass;'
                % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed))
         self.h('')
@@ -207,48 +253,56 @@ class Generator(object):
         self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)'
                % (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 properties:
+            self.b('  static TpDBusPropertiesMixinPropInfo properties[%d] = {'
+                   % (len(properties) + 1))
 
-            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')
+            for m in properties:
+                access = m.getAttribute('access')
+                assert access in ('read', 'write', 'readwrite')
 
-            self.b('      { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
-                   % (flags, m.getAttribute('type'), m.getAttribute('name')))
+                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, 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)
+                self.b('      { 0, %s, "%s", 0, NULL, NULL }, /* %s */'
+                       % (flags, m.getAttribute('type'), m.getAttribute('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('      { 0, 0, NULL, 0, NULL, NULL }')
+            self.b('  };')
+            self.b('  static TpDBusPropertiesMixinIfaceInfo interface =')
+            self.b('      { 0, properties, NULL, NULL };')
+            self.b('')
 
-        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('')
+
+        if properties:
+            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('}')
 
         self.b('static void')
@@ -276,6 +330,10 @@ class Generator(object):
         for method, offset in zip(methods, offsets):
             self.do_method_glue(method, offset)
 
+        if len(methods) == 0:
+            # empty arrays are a gcc extension, so put in a dummy member
+            self.b("  { NULL, NULL, 0 }")
+
         self.b('};')
         self.b('')
 
@@ -335,7 +393,11 @@ class Generator(object):
         return ''.join(info) + '\0', offsets
 
     def do_method_glue(self, method, offset):
-        lc_name = camelcase_to_lower(method.getAttribute('name'))
+        lc_name = method.getAttribute('tp:name-for-bindings')
+        if method.getAttribute('name') != lc_name.replace('_', ''):
+            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+                    'not match' % (method.getAttribute('name'), lc_name))
+        lc_name = lc_name.lower()
 
         marshaller = method_to_glue_marshal_name(method,
                 self.signal_marshal_prefix)
@@ -357,10 +419,16 @@ class Generator(object):
 
     def get_method_impl_names(self, method):
         dbus_method_name = method.getAttribute('name')
-        class_member_name = camelcase_to_lower(dbus_method_name)
+
+        class_member_name = method.getAttribute('tp:name-for-bindings')
+        if dbus_method_name != class_member_name.replace('_', ''):
+            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+                    'not match' % (dbus_method_name, class_member_name))
+        class_member_name = class_member_name.lower()
+
         stub_name = (self.prefix_ + self.node_name_lc + '_' +
                      class_member_name)
-        return (stub_name + '_impl', class_member_name)
+        return (stub_name + '_impl', class_member_name + '_cb')
 
     def do_method(self, method):
         assert self.node_name_mixed is not None
@@ -372,7 +440,12 @@ class Generator(object):
         # DoStuff
         dbus_method_name = method.getAttribute('name')
         # do_stuff
-        class_member_name = camelcase_to_lower(dbus_method_name)
+        class_member_name = method.getAttribute('tp:name-for-bindings')
+        if dbus_method_name != class_member_name.replace('_', ''):
+            raise AssertionError('Method %s tp:name-for-bindings (%s) does '
+                    'not match' % (dbus_method_name, class_member_name))
+        class_member_name = class_member_name.lower()
+
         # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint,
         #   DBusGMethodInvocation *);
         stub_name = (self.prefix_ + self.node_name_lc + '_' +
@@ -414,18 +487,19 @@ class Generator(object):
             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')
+        # Implementation type declaration (in header, docs separated)
+        self.d('/**')
+        self.d(' * %s:' % impl_name)
+        self.d(' * @self: The object implementing this interface')
         for (ctype, name) in in_args:
-            self.b(' * @%s: %s (FIXME, generate documentation)'
+            self.d(' * @%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.d(' * @context: Used to return values or throw an error')
+        self.d(' *')
+        self.d(' * The signature of an implementation of the D-Bus method')
+        self.d(' * %s on interface %s.' % (dbus_method_name, self.iface_name))
+        self.d(' */')
+
         self.h('typedef void (*%s) (%s%s *self,'
           % (impl_name, self.Prefix, self.node_name_mixed))
         for (ctype, name) in in_args:
@@ -443,7 +517,7 @@ class Generator(object):
             self.b('    %s%s,' % (ctype, name))
         self.b('    DBusGMethodInvocation *context)')
         self.b('{')
-        self.b('  %s impl = (%s%s_GET_CLASS (self)->%s);'
+        self.b('  %s impl = (%s%s_GET_CLASS (self)->%s_cb);'
           % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name))
         self.b('')
         self.b('  if (impl != NULL)')
@@ -470,38 +544,41 @@ class Generator(object):
                % (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.d('/**')
+        self.d(' * %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'
+        self.d(' * @klass: A class whose instances implement this interface')
+        self.d(' * @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'
+        self.d(' *')
+        self.d(' * 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.d(' * of an implementation of this interface. To be called from')
+        self.d(' * the interface init function.')
+        self.d(' */')
+
         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('  klass->%s_cb = 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')
+        self.d('/**')
+        self.d(' * %s:' % ret_name)
+        self.d(' * @context: The D-Bus method invocation context')
         for (ctype, name) in out_args:
-            self.h(' * @%s: %s (FIXME, generate documentation)'
+            self.d(' * @%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(' */')
+        self.d(' *')
+        self.d(' * Return successfully by calling dbus_g_method_return().')
+        self.d(' * This inline function exists only to provide type-safety.')
+        self.d(' */')
+        self.d('')
+
         tmp = (['DBusGMethodInvocation *context'] +
                [ctype + name for (ctype, name) in out_args])
         self.h('static inline')
@@ -533,8 +610,15 @@ class Generator(object):
         #    const char *arg0, guint arg1);
 
         dbus_name = signal.getAttribute('name')
+
+        ugly_name = signal.getAttribute('tp:name-for-bindings')
+        if dbus_name != ugly_name.replace('_', ''):
+            raise AssertionError('Signal %s tp:name-for-bindings (%s) does '
+                    'not match' % (dbus_name, ugly_name))
+
         stub_name = (self.prefix_ + self.node_name_lc + '_emit_' +
-                     camelcase_to_lower(dbus_name))
+                     ugly_name.lower())
+
         const_name = self.get_signal_const_entry(signal)
 
         # Gather arguments
@@ -564,17 +648,17 @@ class Generator(object):
 
         # FIXME: emit docs
 
-        self.b('/**')
-        self.b(' * %s:' % stub_name)
-        self.b(' * @instance: The object implementing this interface')
+        self.d('/**')
+        self.d(' * %s:' % stub_name)
+        self.d(' * @instance: The object implementing this interface')
         for (ctype, name, gtype) in args:
-            self.b(' * @%s: %s (FIXME, generate documentation)'
+            self.d(' * @%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.'
+        self.d(' *')
+        self.d(' * Type-safe wrapper around g_signal_emit to emit the')
+        self.d(' * %s signal on interface %s.'
                % (dbus_name, self.iface_name))
-        self.b(' */')
+        self.d(' */')
 
         self.b('void')
         self.b(('%s (' % stub_name) + (',\n    '.join(tmp)) + ')')
@@ -590,16 +674,20 @@ class Generator(object):
 
         signal_name = dbus_gutils_wincaps_to_uscore(dbus_name).replace('_',
                 '-')
-        in_base_init.append('  /**')
-        in_base_init.append('   * %s%s::%s:'
+
+        self.d('/**')
+        self.d(' * %s%s::%s:'
                 % (self.Prefix, self.node_name_mixed, signal_name))
+        self.d(' * @self: an object')
         for (ctype, name, gtype) in args:
-            in_base_init.append('   * @%s: %s (FIXME, generate documentation)'
+            self.d(' * @%s: %s (FIXME, generate documentation)'
                    % (name, ctype))
-        in_base_init.append('   *')
-        in_base_init.append('   * The %s D-Bus signal is emitted whenever '
+        self.d(' *')
+        self.d(' * The %s D-Bus signal is emitted whenever '
                 'this GObject signal is.' % dbus_name)
-        in_base_init.append('   */')
+        self.d(' */')
+        self.d('')
+
         in_base_init.append('  %s_signals[%s] ='
                             % (self.node_name_lc, const_name))
         in_base_init.append('  g_signal_new ("%s",' % signal_name)
@@ -616,23 +704,33 @@ class Generator(object):
 
         return in_base_init
 
+    def have_properties(self, nodes):
+        for node in nodes:
+            interface =  node.getElementsByTagName('interface')[0]
+            if interface.getElementsByTagName('property'):
+                return True
+        return False
+
     def __call__(self):
+        nodes = self.dom.getElementsByTagName('node')
+        nodes.sort(cmp_by_name)
+
         self.h('#include <glib-object.h>')
         self.h('#include <dbus/dbus-glib.h>')
-        self.h('#include <telepathy-glib/dbus-properties-mixin.h>')
+
+        if self.have_properties(nodes):
+            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('#include "%s.h"' % self.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)
 
@@ -645,8 +743,9 @@ class Generator(object):
 
         self.h('')
         self.b('')
-        open(basename + '.h', 'w').write('\n'.join(self.__header))
-        open(basename + '.c', 'w').write('\n'.join(self.__body))
+        open(self.basename + '.h', 'w').write('\n'.join(self.__header))
+        open(self.basename + '.c', 'w').write('\n'.join(self.__body))
+        open(self.basename + '-gtk-doc.h', 'w').write('\n'.join(self.__docs))
 
 
 def cmdline_error():
diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py
index fcb46e8..a49c36e 100644
--- a/tools/glib-gtypes-generator.py
+++ b/tools/glib-gtypes-generator.py
@@ -44,16 +44,35 @@ class GTypesGenerator(object):
 
         self.header = open(output + '.h', 'w')
         self.body = open(output + '-body.h', 'w')
+        self.docs = open(output + '-gtk-doc.h', 'w')
 
-        for f in (self.header, self.body):
+        for f in (self.header, self.body, self.docs):
             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')
 
+        # keys are e.g. 'sv', values are the key escaped
         self.need_mappings = {}
+        # keys are the contents of the struct (e.g. 'sssu'), values are the
+        # key escaped
         self.need_structs = {}
-        self.need_arrays = {}
+        # keys are the contents of the struct (e.g. 'sssu'), values are the
+        # key escaped
+        self.need_struct_arrays = {}
+
+        # keys are the contents of the array (unlike need_struct_arrays!),
+        # values are the key escaped
+        self.need_other_arrays = {}
+
+    def h(self, code):
+        self.header.write(code.encode("utf-8"))
+
+    def c(self, code):
+        self.body.write(code.encode("utf-8"))
+
+    def d(self, code):
+        self.docs.write(code.encode('utf-8'))
 
     def do_mapping_header(self, mapping):
         members = mapping.getElementsByTagNameNS(NS_TP, 'member')
@@ -70,45 +89,60 @@ class GTypesGenerator(object):
 
         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')
+        self.d('/**\n * %s:\n *\n' % name)
+        self.d(' * %s\n' % xml_escape(docstring))
+        self.d(' *\n')
+        self.d(' * This macro expands to a call to a function\n')
+        self.d(' * that returns the #GType of a #GHashTable\n')
+        self.d(' * appropriate for representing a D-Bus\n')
+        self.d(' * dictionary of signature\n')
+        self.d(' * <literal>a{%s}</literal>.\n' % impl_sig)
+        self.d(' *\n')
 
         key, value = members
 
-        self.header.write(' * Keys (D-Bus type <literal>%s</literal>,\n'
+        self.d(' * 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'
+            self.d(' * type <literal>%s</literal>,\n' % tp_type)
+        self.d(' * 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.d(' * %s\n' % xml_escape(docstring))
+        self.d(' *\n')
 
-        self.header.write(' * Values (D-Bus type <literal>%s</literal>,\n'
+        self.d(' * 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'
+            self.d(' * type <literal>%s</literal>,\n' % tp_type)
+        self.d(' * 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.d(' * %s\n' % xml_escape(docstring))
+        self.d(' *\n')
 
-        self.header.write(' */\n')
+        self.d(' */\n')
 
-        self.header.write('#define %s (%s ())\n\n' % (name, impl))
+        self.h('#define %s (%s ())\n\n' % (name, impl))
         self.need_mappings[impl_sig] = esc_impl_sig
 
+        array_name = mapping.getAttribute('array-name')
+        if array_name:
+            gtype_name = self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()
+            contents_sig = 'a{' + impl_sig + '}'
+            esc_contents_sig = escape_as_identifier(contents_sig)
+            impl = self.prefix_ + 'type_dbus_array_of_' + esc_contents_sig
+            self.d('/**\n * %s:\n\n' % gtype_name)
+            self.d(' * Expands to a call to a function\n')
+            self.d(' * that returns the #GType of a #GPtrArray\n')
+            self.d(' * of #%s.\n' % name)
+            self.d(' */\n\n')
+
+            self.h('#define %s (%s ())\n\n' % (gtype_name, impl))
+            self.need_other_arrays[contents_sig] = esc_contents_sig
+
     def do_struct_header(self, struct):
         members = struct.getElementsByTagNameNS(NS_TP, 'member')
         impl_sig = ''.join([elt.getAttribute('type') for elt in members])
@@ -128,43 +162,45 @@ class GTypesGenerator(object):
                 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'
+        self.d('/**\n * %s:\n\n' % name)
+        self.d(' * %s\n' % xml_escape(docstring))
+        self.d(' *\n')
+        self.d(' * This macro expands to a call to a function\n')
+        self.d(' * that returns the #GType of a #GValueArray\n')
+        self.d(' * appropriate for representing a D-Bus struct\n')
+        self.d(' * with signature <literal>(%s)</literal>.\n'
                           % impl_sig)
-        self.header.write(' *\n')
+        self.d(' *\n')
 
         for i, member in enumerate(members):
-            self.header.write(' * Member %d (D-Bus type '
+            self.d(' * 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'
+                self.d(' * type <literal>%s</literal>,\n' % tp_type)
+            self.d(' * 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.d(' * %s\n' % xml_escape(docstring))
+            self.d(' *\n')
 
-        self.header.write(' */\n')
-        self.header.write('#define %s (%s ())\n\n' % (name, impl))
+        self.d(' */\n\n')
+
+        self.h('#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.d('/**\n * %s:\n\n' % array_name)
+            self.d(' * Expands to a call to a function\n')
+            self.d(' * that returns the #GType of a #GPtrArray\n')
+            self.d(' * of #%s.\n' % name)
+            self.d(' */\n\n')
+
+            self.h('#define %s (%s ())\n\n' % (array_name, impl))
+            self.need_struct_arrays[impl_sig] = esc_impl_sig
 
         self.need_structs[impl_sig] = esc_impl_sig
 
@@ -176,51 +212,83 @@ class GTypesGenerator(object):
             self.do_mapping_header(mapping)
 
         for sig in self.need_mappings:
-            self.header.write('GType %stype_dbus_hash_%s (void);\n\n' %
+            self.h('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.c('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')
+            self.c('  static GType t = 0;\n\n')
+            self.c('  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", '
+            self.c('    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')
+            self.c('  return t;\n')
+            self.c('}\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.h('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.c('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')
+            self.c('  static GType t = 0;\n\n')
+            self.c('  if (G_UNLIKELY (t == 0))\n')
+            self.c('    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", '
+                self.c('        %s,\n' % gtype)
+            self.c('        G_TYPE_INVALID);\n')
+            self.c('  return t;\n')
+            self.c('}\n\n')
+
+        for sig in self.need_struct_arrays:
+            self.h('GType %stype_dbus_array_%s (void);\n\n' %
+                              (self.prefix_, self.need_struct_arrays[sig]))
+            self.c('GType\n%stype_dbus_array_%s (void)\n{\n' %
+                              (self.prefix_, self.need_struct_arrays[sig]))
+            self.c('  static GType t = 0;\n\n')
+            self.c('  if (G_UNLIKELY (t == 0))\n')
+            self.c('    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')
+                            (self.prefix_, self.need_struct_arrays[sig]))
+            self.c('  return t;\n')
+            self.c('}\n\n')
+
+        for sig in self.need_other_arrays:
+            self.h('GType %stype_dbus_array_of_%s (void);\n\n' %
+                              (self.prefix_, self.need_other_arrays[sig]))
+            self.c('GType\n%stype_dbus_array_of_%s (void)\n{\n' %
+                              (self.prefix_, self.need_other_arrays[sig]))
+            self.c('  static GType t = 0;\n\n')
+            self.c('  if (G_UNLIKELY (t == 0))\n')
+
+            if sig[:2] == 'a{' and sig[-1:] == '}':
+                # array of mappings
+                self.c('    t = dbus_g_type_get_collection ('
+                            '"GPtrArray", '
+                            '%stype_dbus_hash_%s ());\n' %
+                            (self.prefix_, escape_as_identifier(sig[2:-1])))
+            elif sig[:2] == 'a(' and sig[-1:] == ')':
+                # array of arrays of struct
+                self.c('    t = dbus_g_type_get_collection ('
+                            '"GPtrArray", '
+                            '%stype_dbus_array_%s ());\n' %
+                            (self.prefix_, escape_as_identifier(sig[2:-1])))
+            elif sig[:1] == 'a':
+                # array of arrays of non-struct
+                self.c('    t = dbus_g_type_get_collection ('
+                            '"GPtrArray", '
+                            '%stype_dbus_array_of_%s ());\n' %
+                            (self.prefix_, escape_as_identifier(sig[1:])))
+            else:
+                raise AssertionError("array of '%s' not supported" % sig)
+
+            self.c('  return t;\n')
+            self.c('}\n\n')
 
 if __name__ == '__main__':
     argv = sys.argv[1:]
diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py
index 741626c..69c721b 100644
--- a/tools/glib-interfaces-gen.py
+++ b/tools/glib-interfaces-gen.py
@@ -3,36 +3,50 @@
 from sys import argv, stdout, stderr
 import xml.dom.minidom
 
-from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \
+from libglibcodegen import NS_TP, get_docstring, \
         get_descendant_text, get_by_path
 
 class Generator(object):
     def __init__(self, prefix, implfile, declfile, dom):
         self.prefix = prefix + '_'
+
+        assert declfile.endswith('.h')
+        docfile = declfile[:-2] + '-gtk-doc.h'
+
         self.impls = open(implfile, 'w')
         self.decls = open(declfile, 'w')
+        self.docs = open(docfile, 'w')
         self.spec = get_by_path(dom, "spec")[0]
 
+    def h(self, code):
+        self.decls.write(code.encode('utf-8'))
+
+    def c(self, code):
+        self.impls.write(code.encode('utf-8'))
+
+    def d(self, code):
+        self.docs.write(code.encode('utf-8'))
+
     def __call__(self):
-        for file in self.decls, self.impls:
-            self.do_header(file)
+        for f in self.h, self.c:
+            self.do_header(f)
         self.do_body()
 
     # Header
-    def do_header(self, file):
-        file.write('/* Generated from: ')
-        file.write(get_descendant_text(get_by_path(self.spec, 'title')))
+    def do_header(self, f):
+        f('/* Generated from: ')
+        f(get_descendant_text(get_by_path(self.spec, 'title')))
         version = get_by_path(self.spec, "version")
         if version:
-            file.write(' version ' + get_descendant_text(version))
-        file.write('\n\n')
+            f(' version ' + get_descendant_text(version))
+        f('\n\n')
         for copyright in get_by_path(self.spec, 'copyright'):
-            stdout.write(get_descendant_text(copyright))
-            stdout.write('\n')
-        file.write('\n')
-        file.write(get_descendant_text(get_by_path(self.spec, 'license')))
-        file.write(get_descendant_text(get_by_path(self.spec, 'docstring')))
-        file.write("""
+            f(get_descendant_text(copyright))
+            f('\n')
+        f('\n')
+        f(get_descendant_text(get_by_path(self.spec, 'license')))
+        f(get_descendant_text(get_by_path(self.spec, 'docstring')))
+        f("""
  */
 
 """)
@@ -44,25 +58,37 @@ class Generator(object):
 
     def do_iface(self, iface):
         parent_name = get_by_path(iface, '../@name')
-        self.decls.write("""\
+        self.d("""\
 /**
  * %(IFACE_DEFINE)s:
- * 
+ *
  * The interface name "%(name)s"
  */
+""" % {'IFACE_DEFINE' : (self.prefix + 'IFACE_' + \
+            parent_name).upper().replace('/', ''),
+       'name' : iface.getAttribute('name')})
+
+        self.h("""
 #define %(IFACE_DEFINE)s \\
 "%(name)s"
 """ % {'IFACE_DEFINE' : (self.prefix + 'IFACE_' + \
             parent_name).upper().replace('/', ''),
        'name' : iface.getAttribute('name')})
 
-        self.decls.write("""
+        self.d("""
 /**
  * %(IFACE_QUARK_DEFINE)s:
- * 
+ *
  * Expands to a call to a function that returns a quark for the interface \
 name "%(name)s"
  */
+""" % {'IFACE_QUARK_DEFINE' : (self.prefix + 'IFACE_QUARK_' + \
+            parent_name).upper().replace('/', ''),
+       'iface_quark_func' : (self.prefix + 'iface_quark_' + \
+            parent_name).lower().replace('/', ''),
+       'name' : iface.getAttribute('name')})
+
+        self.h("""
 #define %(IFACE_QUARK_DEFINE)s \\
   (%(iface_quark_func)s ())
 
@@ -74,7 +100,7 @@ GQuark %(iface_quark_func)s (void);
             parent_name).lower().replace('/', ''),
        'name' : iface.getAttribute('name')})
 
-        self.impls.write("""\
+        self.c("""\
 GQuark
 %(iface_quark_func)s (void)
 {
@@ -92,6 +118,80 @@ GQuark
             parent_name).lower().replace('/', ''),
        'name' : iface.getAttribute('name')})
 
+        for prop in iface.getElementsByTagNameNS(None, 'property'):
+            self.d("""
+/**
+ * %(IFACE_PREFIX)s_%(PROP_UC)s:
+ *
+ * The fully-qualified property name "%(name)s.%(prop)s"
+ */
+""" % {'IFACE_PREFIX' : (self.prefix + 'PROP_' + \
+                parent_name).upper().replace('/', ''),
+           'PROP_UC': prop.getAttributeNS(NS_TP, "name-for-bindings").upper(),
+           'name' : iface.getAttribute('name'),
+           'prop' : prop.getAttribute('name'),
+           })
+
+            self.h("""
+#define %(IFACE_PREFIX)s_%(PROP_UC)s \\
+"%(name)s.%(prop)s"
+""" % {'IFACE_PREFIX' : (self.prefix + 'PROP_' + \
+                parent_name).upper().replace('/', ''),
+           'PROP_UC': prop.getAttributeNS(NS_TP, "name-for-bindings").upper(),
+           'name' : iface.getAttribute('name'),
+           'prop' : prop.getAttribute('name'),
+           })
+
+
+        for prop in iface.getElementsByTagNameNS(NS_TP, 'contact-attribute'):
+            self.d("""
+/**
+ * %(TOKEN_PREFIX)s_%(TOKEN_UC)s:
+ *
+ * The fully-qualified contact attribute token name "%(name)s/%(prop)s"
+ */
+""" % {'TOKEN_PREFIX' : (self.prefix + 'TOKEN_' + \
+                parent_name).upper().replace('/', ''),
+           'TOKEN_UC': prop.getAttributeNS(None, "name").upper().replace("-", "_").replace(".", "_"),
+           'name' : iface.getAttribute('name'),
+           'prop' : prop.getAttribute('name'),
+           })
+
+            self.h("""
+#define %(TOKEN_PREFIX)s_%(TOKEN_UC)s \\
+"%(name)s/%(prop)s"
+""" % {'TOKEN_PREFIX' : (self.prefix + 'TOKEN_' + \
+                parent_name).upper().replace('/', ''),
+           'TOKEN_UC': prop.getAttributeNS(None, "name").upper().replace("-", "_").replace(".", "_"),
+           'name' : iface.getAttribute('name'),
+           'prop' : prop.getAttribute('name'),
+           })
+
+        for prop in iface.getElementsByTagNameNS(NS_TP, 'hct'):
+            if (prop.getAttribute('is-family') != "yes"):
+                self.d("""
+/**
+ * %(TOKEN_PREFIX)s_%(TOKEN_UC)s:
+ *
+ * The fully-qualified capability token name "%(name)s/%(prop)s"
+ */
+""" % {'TOKEN_PREFIX' : (self.prefix + 'TOKEN_' + \
+                parent_name).upper().replace('/', ''),
+           'TOKEN_UC': prop.getAttributeNS(None, "name").upper().replace("-", "_").replace(".", "_"),
+           'name' : iface.getAttribute('name'),
+           'prop' : prop.getAttribute('name'),
+           })
+
+                self.h("""
+#define %(TOKEN_PREFIX)s_%(TOKEN_UC)s \\
+"%(name)s/%(prop)s"
+""" % {'TOKEN_PREFIX' : (self.prefix + 'TOKEN_' + \
+                parent_name).upper().replace('/', ''),
+           'TOKEN_UC': prop.getAttributeNS(None, "name").upper().replace("-", "_").replace(".", "_"),
+           'name' : iface.getAttribute('name'),
+           'prop' : prop.getAttribute('name'),
+           })
+
 if __name__ == '__main__':
     argv = argv[1:]
     Generator(argv[0], argv[1], argv[2], xml.dom.minidom.parse(argv[3]))()
diff --git a/tools/gobject-foo.py b/tools/gobject-foo.py
index 5921cab..002a290 100644
--- a/tools/gobject-foo.py
+++ b/tools/gobject-foo.py
@@ -5,7 +5,7 @@
 # The master copy of this program is in the telepathy-glib repository -
 # please make any changes there.
 #
-# Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
+# Copyright (C) 2007-2010 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
@@ -33,8 +33,13 @@ def gobject_header(head, tail, as_interface=False):
     gtype = head.upper() + '_TYPE_' + tail.upper()
 
     o("typedef struct _%s %s;" % (MixedCase, MixedCase))
-    o("typedef struct _%sClass %sClass;" % (MixedCase, MixedCase))
-    o("typedef struct _%sPrivate %sPrivate;" % (MixedCase, MixedCase))
+
+    if as_interface:
+        o("typedef struct _%sInterface %sInterface;" % (MixedCase, MixedCase))
+    else:
+        o("typedef struct _%sClass %sClass;" % (MixedCase, MixedCase))
+        o("typedef struct _%sPrivate %sPrivate;" % (MixedCase, MixedCase))
+
     o("")
     o("GType %s_get_type (void);" % lower_case)
     o("")
@@ -54,13 +59,17 @@ def gobject_header(head, tail, as_interface=False):
     o("#define %s_IS_%s(obj) \\" % (head.upper(), tail.upper()))
     o("  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))" % gtype)
 
-    if not as_interface:
+    if as_interface:
+        o("#define %s_GET_IFACE(obj) \\" % UPPER_CASE)
+        o("  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, \\" % gtype)
+        o("                                  %sInterface))" % MixedCase)
+    else:
         o("#define %s_IS_%s_CLASS(klass) \\" % (head.upper(), tail.upper()))
         o("  (G_TYPE_CHECK_CLASS_TYPE ((klass), %s))" % gtype)
 
-    o("#define %s_GET_CLASS(obj) \\" % UPPER_CASE)
-    o("  (G_TYPE_INSTANCE_GET_CLASS ((obj), %s, \\" % gtype)
-    o("                              %sClass))" % MixedCase)
+        o("#define %s_GET_CLASS(obj) \\" % UPPER_CASE)
+        o("  (G_TYPE_INSTANCE_GET_CLASS ((obj), %s, \\" % gtype)
+        o("                              %sClass))" % MixedCase)
 
     return out
 
diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py
index 129c179..6a9d214 100644
--- a/tools/libglibcodegen.py
+++ b/tools/libglibcodegen.py
@@ -23,14 +23,13 @@ please make any changes there.
 
 from libtpcodegen import NS_TP, \
                          Signature, \
-                         camelcase_to_lower, \
-                         camelcase_to_upper, \
                          cmp_by_name, \
                          escape_as_identifier, \
                          get_by_path, \
                          get_descendant_text, \
                          get_docstring, \
-                         xml_escape
+                         xml_escape, \
+                         get_deprecated
 
 def dbus_gutils_wincaps_to_uscore(s):
     """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore
diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py
index 6391f1a..837ff2f 100644
--- a/tools/libtpcodegen.py
+++ b/tools/libtpcodegen.py
@@ -29,32 +29,6 @@ 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)
@@ -146,6 +120,16 @@ def get_docstring(element):
             docstring = ''
     return docstring
 
+def get_deprecated(element):
+    text = []
+    for x in element.childNodes:
+        if hasattr(x, 'data'):
+            text.append(x.data.replace('\n', ' ').strip())
+        else:
+            # This caters for tp:dbus-ref elements, but little else.
+            if x.childNodes and hasattr(x.childNodes[0], 'data'):
+                text.append(x.childNodes[0].data.replace('\n', ' ').strip())
+    return ' '.join(text)
 
 def get_descendant_text(element_or_elements):
     if not element_or_elements:
diff --git a/tools/make-release-mail.py b/tools/make-release-mail.py
new file mode 100644
index 0000000..2bd7c2b
--- /dev/null
+++ b/tools/make-release-mail.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# vim: set fileencoding=utf-8 :
+#
+# Hello. This is make-release-mail.py from the Telepathy project. It's
+# designed to turn an item from a NEWS file into a mail suitable for sending
+# to <telepathy lists freedesktop org>. I hope that you enjoy your stay.
+
+import sys
+
+def extract_description(package, version, news_path):
+    release_name = []
+    details = []
+
+    with open(news_path) as f:
+        lines = (line for line in f.readlines())
+        for line in lines:
+            # Find the 'telepathy-foo 0.1.2' header
+            if line.startswith("%s %s" % (package, version)):
+                break
+
+        # Skip the ====== line, and the first blank line
+        lines.next()
+        lines.next()
+
+        got_release_name = False
+
+        for line in lines:
+            line = line.rstrip()
+            # If we hit the next version header, we're done
+            if line.startswith(package):
+                break
+            # Else, if we hit a blank line and we're still reading the release
+            # name, we're done with the release name.
+            elif not got_release_name and line == '':
+                got_release_name = True
+            # Otherwise, append this to the relevant list
+            elif not got_release_name:
+                release_name.append(line)
+            else:
+                details.append(line)
+
+        assert got_release_name, (release_name, details)
+
+    # We rstrip details because it picks up a trailing blank line
+    return ('\n'.join(release_name), '\n'.join(details).rstrip())
+
+BASE_URL = 'http://telepathy.freedesktop.org/releases'
+
+def main(package, version, news_path):
+    release_name, details = extract_description(package, version, news_path)
+
+    print """
+%(release_name)s
+
+tarball: %(base_url)s/%(package)s/%(package)s-%(version)s.tar.gz
+signature: %(base_url)s/%(package)s/%(package)s-%(version)s.tar.gz.asc
+
+%(details)s""".strip().rstrip() % {
+        'base_url': BASE_URL,
+        'package': package,
+        'version': version,
+        'release_name': release_name,
+        'details': details,
+    }
+
+if __name__ == '__main__':
+    try:
+        package, version, news_path = sys.argv[1:]
+
+        main(package, version, news_path)
+    except ValueError, e:
+        sys.stderr.write(
+            'Usage: %s package-name package.version.number path/to/NEWS\n' %
+            sys.argv[0])
+        sys.stderr.flush()
+        sys.exit(1)
diff --git a/tools/manager-file.py b/tools/manager-file.py
new file mode 100644
index 0000000..45f6404
--- /dev/null
+++ b/tools/manager-file.py
@@ -0,0 +1,175 @@
+#!/usr/bin/python
+
+# manager-file.py: generate .manager files and TpCMParamSpec arrays from the
+# same data (should be suitable for all connection managers that don't have
+# plugins)
+#
+# The master copy of this program is in the telepathy-glib repository -
+# please make any changes there.
+#
+# Copyright (c) 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 re
+import sys
+
+_NOT_C_STR = re.compile(r'[^A-Za-z0-9_-]')
+
+def c_string(x):
+    # whitelist-based brute force and ignorance - escape nearly all punctuation
+    return '"' + _NOT_C_STR.sub(lambda c: r'\x%02x' % ord(c), x) + '"'
+
+def desktop_string(x):
+    return x.replace(' ', r'\s').replace('\n', r'\n').replace('\r', r'\r').replace('\t', r'\t')
+
+supported = list('sbuiqn')
+
+fdefaultencoders = {
+        's': desktop_string,
+        'b': (lambda b: b and '1' or '0'),
+        'u': (lambda n: '%u' % n),
+        'i': (lambda n: '%d' % n),
+        'q': (lambda n: '%u' % n),
+        'n': (lambda n: '%d' % n),
+        }
+for x in supported: assert x in fdefaultencoders
+
+gtypes = {
+        's': 'G_TYPE_STRING',
+        'b': 'G_TYPE_BOOLEAN',
+        'u': 'G_TYPE_UINT',
+        'i': 'G_TYPE_INT',
+        'q': 'G_TYPE_UINT',
+        'n': 'G_TYPE_INT',
+}
+for x in supported: assert x in gtypes
+
+gdefaultencoders = {
+        's': c_string,
+        'b': (lambda b: b and 'GINT_TO_POINTER (TRUE)' or 'GINT_TO_POINTER (FALSE)'),
+        'u': (lambda n: 'GUINT_TO_POINTER (%u)' % n),
+        'i': (lambda n: 'GINT_TO_POINTER (%d)' % n),
+        'q': (lambda n: 'GUINT_TO_POINTER (%u)' % n),
+        'n': (lambda n: 'GINT_TO_POINTER (%d)' % n),
+        }
+for x in supported: assert x in gdefaultencoders
+
+gdefaultdefaults = {
+        's': 'NULL',
+        'b': 'GINT_TO_POINTER (FALSE)',
+        'u': 'GUINT_TO_POINTER (0)',
+        'i': 'GINT_TO_POINTER (0)',
+        'q': 'GUINT_TO_POINTER (0)',
+        'n': 'GINT_TO_POINTER (0)',
+        }
+for x in supported: assert x in gdefaultdefaults
+
+gflags = {
+        'has-default': 'TP_CONN_MGR_PARAM_FLAG_HAS_DEFAULT',
+        'register': 'TP_CONN_MGR_PARAM_FLAG_REGISTER',
+        'required': 'TP_CONN_MGR_PARAM_FLAG_REQUIRED',
+        'secret': 'TP_CONN_MGR_PARAM_FLAG_SECRET',
+        'dbus-property': 'TP_CONN_MGR_PARAM_FLAG_DBUS_PROPERTY',
+}
+
+def write_manager(f, manager, protos):
+    # pointless backwards compat section
+    print >> f, '[ConnectionManager]'
+    print >> f, 'BusName=org.freedesktop.Telepathy.ConnectionManager.' + manager
+    print >> f, 'ObjectPath=/org/freedesktop/Telepathy/ConnectionManager/' + manager
+
+    # protocols
+    for proto, params in protos.iteritems():
+        print >> f
+        print >> f, '[Protocol %s]' % proto
+
+        defaults = {}
+
+        for param, info in params.iteritems():
+            dtype = info['dtype']
+            flags = info.get('flags', '').split()
+            struct_field = info.get('struct_field', param.replace('-', '_'))
+            filter = info.get('filter', 'NULL')
+            filter_data = info.get('filter_data', 'NULL')
+            setter_data = 'NULL'
+
+            if 'default' in info:
+                default = fdefaultencoders[dtype](info['default'])
+                defaults[param] = default
+
+            if flags:
+                flags = ' ' + ' '.join(flags)
+            else:
+                flags = ''
+
+            print >> f, 'param-%s=%s%s' % (param, desktop_string(dtype), flags)
+
+        for param, default in defaults.iteritems():
+            print >> f, 'default-%s=%s' % (param, default)
+
+def write_c_params(f, manager, proto, struct, params):
+    print >> f, "static const TpCMParamSpec %s_%s_params[] = {" % (manager, proto)
+
+    for param, info in params.iteritems():
+        dtype = info['dtype']
+        flags = info.get('flags', '').split()
+        struct_field = info.get('struct_field', param.replace('-', '_'))
+        filter = info.get('filter', 'NULL')
+        filter_data = info.get('filter_data', 'NULL')
+        setter_data = 'NULL'
+
+        if 'default' in info:
+            default = gdefaultencoders[dtype](info['default'])
+        else:
+            default = gdefaultdefaults[dtype]
+
+        if flags:
+            flags = ' | '.join([gflags[flag] for flag in flags])
+        else:
+            flags = '0'
+
+        if struct is None or struct_field is None:
+            struct_offset = '0'
+        else:
+            struct_offset = 'G_STRUCT_OFFSET (%s, %s)' % (struct, struct_field)
+
+        print >> f, ('''  { %s, %s, %s,
+    %s,
+    %s, /* default */
+    %s, /* struct offset */
+    %s, /* filter */
+    %s, /* filter data */
+    %s /* setter data */ },''' %
+                (c_string(param), c_string(dtype), gtypes[dtype], flags,
+                    default, struct_offset, filter, filter_data, setter_data))
+
+    print >> f, "  { NULL }"
+    print >> f, "};"
+
+if __name__ == '__main__':
+    environment = {}
+    execfile(sys.argv[1], environment)
+
+    f = open('%s/%s.manager' % (sys.argv[2], environment['MANAGER']), 'w')
+    write_manager(f, environment['MANAGER'], environment['PARAMS'])
+    f.close()
+
+    f = open('%s/param-spec-struct.h' % sys.argv[2], 'w')
+    for protocol in environment['PARAMS']:
+        write_c_params(f, environment['MANAGER'], protocol,
+                environment['STRUCTS'][protocol],
+                environment['PARAMS'][protocol])
+    f.close()
diff --git a/tools/shave.mk b/tools/shave.mk
new file mode 100644
index 0000000..53cb3bf
--- /dev/null
+++ b/tools/shave.mk
@@ -0,0 +1 @@
+QUIET_GEN = $(Q:@= echo '  GEN   '$@;)
diff --git a/tools/telepathy-glib.supp b/tools/telepathy-glib.supp
new file mode 100644
index 0000000..28bd5a0
--- /dev/null
+++ b/tools/telepathy-glib.supp
@@ -0,0 +1,390 @@
+# Valgrind error suppression file
+
+# ============================= libc ==================================
+
+{
+   ld.so initialization + selinux
+   Memcheck:Leak
+   ...
+   fun:_dl_init
+   obj:/lib/ld-*.so
+}
+
+{
+   dlopen initialization, triggered by handle-leak-debug code
+   Memcheck:Leak
+   ...
+   fun:__libc_dlopen_mode
+   fun:init
+   fun:backtrace
+   fun:handle_leak_debug_bt
+   fun:dynamic_ensure_handle
+   fun:tp_handle_ensure
+}
+
+# default.supp has these for 2.10, but they're too specific
+{
+   Debian libc6 (2.10.x, 2.11.x) stripped dynamic linker
+   Memcheck:Cond
+   fun:index
+   fun:expand_dynamic_string_token
+   fun:_dl_map_object
+   fun:map_doit
+   fun:_dl_catch_error
+   fun:do_preload
+   fun:dl_main
+   fun:_dl_sysdep_start
+   fun:_dl_start
+   obj:/lib/ld-*.so
+}
+{
+   Debian libc6 (2.9.x - 2.11.x) stripped dynamic linker
+   Memcheck:Cond
+   fun:_dl_relocate_object
+   fun:dl_main
+   fun:_dl_sysdep_start
+   fun:_dl_start
+   obj:/lib/ld-*.so
+}
+
+{
+   ld.so initialization on glibc 2.9
+   Memcheck:Cond
+   fun:strlen
+   fun:_dl_init_paths
+   fun:dl_main
+   fun:_dl_sysdep_start
+   fun:_dl_start
+   obj:/lib/ld-2.9.so
+}
+
+# ======================= libselinux on Debian amd64 =====================
+
+{
+   I have no idea what SELinux is doing but it's not my problem
+   Memcheck:Cond
+   ...
+   obj:/lib/libselinux.so.1
+   obj:/lib/libselinux.so.1
+   obj:/lib/libselinux.so.1
+}
+
+{
+   I have no idea what SELinux is doing but it's not my problem
+   Memcheck:Value8
+   ...
+   obj:/lib/libselinux.so.1
+   obj:/lib/libselinux.so.1
+   obj:/lib/libselinux.so.1
+}
+
+{
+   I have no idea what SELinux is doing but it's not my problem
+   Memcheck:Leak
+   ...
+   obj:/lib/libselinux.so.1
+   obj:/lib/libselinux.so.1
+   obj:/lib/libselinux.so.1
+}
+
+# ============================= GLib ==================================
+
+{
+   g_set_prgname copies its argument
+   Memcheck:Leak
+   ...
+   fun:g_set_prgname
+}
+
+{
+   one g_get_charset per child^Wprocess
+   Memcheck:Leak
+   ...
+   fun:g_get_charset
+}
+
+{
+   one g_get_home_dir per process
+   Memcheck:Leak
+   ...
+   fun:g_get_home_dir
+}
+
+{
+   GQuarks can't be freed
+   Memcheck:Leak
+   ...
+   fun:g_quark_from_static_string
+}
+
+{
+   GQuarks can't be freed
+   Memcheck:Leak
+   ...
+   fun:g_quark_from_string
+}
+
+{
+   interned strings can't be freed
+   Memcheck:Leak
+   ...
+   fun:g_intern_string
+}
+
+{
+   interned strings can't be freed
+   Memcheck:Leak
+   ...
+   fun:g_intern_static_string
+}
+
+{
+   shared global default g_main_context
+   Memcheck:Leak
+   ...
+   fun:g_main_context_new
+   fun:g_main_context_default
+}
+
+{
+   GTest initialization
+   Memcheck:Leak
+   ...
+   fun:g_test_init
+   fun:main
+}
+
+{
+   GTest admin
+   Memcheck:Leak
+   ...
+   fun:g_test_add_vtable
+}
+
+{
+   GTest pseudorandomness
+   Memcheck:Leak
+   ...
+   fun:g_rand_new_with_seed_array
+   fun:test_run_seed
+   ...
+   fun:g_test_run
+}
+
+{
+   GSLice initialization
+   Memcheck:Leak
+   ...
+   fun:g_malloc0
+   fun:g_slice_init_nomessage
+   fun:g_slice_alloc
+}
+
+# ============================= GObject ===============================
+
+{
+   g_type_init
+   Memcheck:Leak
+   ...
+   fun:g_type_init
+}
+
+{
+   g_type_init_with_debug_flags
+   Memcheck:Leak
+   ...
+   fun:g_type_init_with_debug_flags
+}
+
+{
+   g_type_register_static
+   Memcheck:Leak
+   ...
+   fun:g_type_register_static
+}
+
+{
+   g_type_add_interface_static
+   Memcheck:Leak
+   ...
+   fun:g_type_add_interface_static
+}
+
+{
+   initialization of interfaces
+   Memcheck:Leak
+   ...
+   fun:type_iface_vtable_base_init_Wm
+   fun:g_type_class_ref
+}
+
+# ============================= GIO ===================================
+
+{
+   GIO init
+   Memcheck:Leak
+   ...
+   fun:g_inet_address_class_intern_init
+}
+
+{
+   g_simple_async_result class
+   Memcheck:Leak
+   ...
+   fun:g_type_class_ref
+   ...
+   fun:g_simple_async_result_new
+}
+
+# ============================= dbus-glib =============================
+
+{
+   registering marshallers is permanent
+   Memcheck:Leak
+   ...
+   fun:dbus_g_object_register_marshaller_array
+   fun:dbus_g_object_register_marshaller
+}
+
+{
+   dbus-glib specialized GTypes are permanent
+   Memcheck:Leak
+   ...
+   fun:dbus_g_type_specialized_init
+}
+
+{
+   libdbus shared connection
+   Memcheck:Leak
+   ...
+   fun:dbus_g_bus_get
+}
+
+{
+   dbus-gobject registrations aren't freed unless we fall off the bus
+   Memcheck:Leak
+   ...
+   fun:g_slist_append
+   fun:dbus_g_connection_register_g_object
+}
+
+{
+   DBusGProxy slots aren't freed unless we fall off the bus
+   Memcheck:Leak
+   ...
+   fun:dbus_connection_allocate_data_slot
+   ...
+   fun:dbus_g_proxy_constructor
+}
+
+{
+   error registrations are for life, not just for Christmas
+   Memcheck:Leak
+   ...
+   fun:dbus_g_error_domain_register
+}
+
+{
+   DBusGProxy class init
+   Memcheck:Leak
+   ...
+   fun:dbus_g_proxy_class_init
+}
+
+# ============================= telepathy-glib ========================
+
+{
+   tp_dbus_daemon_constructor @daemons once per DBusConnection
+   Memcheck:Leak
+   ...
+   fun:g_slice_alloc
+   fun:tp_dbus_daemon_constructor
+}
+
+{
+   tp_proxy_subclass_add_error_mapping refs the enum
+   Memcheck:Leak
+   ...
+   fun:g_type_class_ref
+   fun:tp_proxy_subclass_add_error_mapping
+}
+
+{
+   tp_proxy_or_subclass_hook_on_interface_add never frees its list
+   Memcheck:Leak
+   ...
+   fun:tp_proxy_or_subclass_hook_on_interface_add
+}
+
+{
+   tp_dbus_daemon_constructor filter not freed til we fall off the bus
+   Memcheck:Leak
+   ...
+   fun:dbus_connection_add_filter
+   fun:tp_dbus_daemon_constructor
+}
+
+{
+   tp_g_socket_address_from_variant reffing GNIO types
+   Memcheck:Leak
+   ...
+   fun:g_type_class_ref
+   ...
+   fun:tp_g_socket_address_from_variant
+}
+
+{
+   creating classes for DBusGProxy
+   Memcheck:Leak
+   ...
+   fun:g_type_class_ref
+   ...
+   fun:g_object_new
+   ...
+   fun:tp_proxy_borrow_interface_by_id
+}
+
+{
+   creating classes for tp_dbus_daemon_new
+   Memcheck:Leak
+   ...
+   fun:g_type_class_ref
+   ...
+   fun:g_object_new
+   ...
+   fun:tp_dbus_daemon_new
+}
+
+{
+   creating classes for TpCHannel
+   Memcheck:Leak
+   ...
+   fun:g_type_class_ref
+   ...
+   fun:g_object_new
+   ...
+   fun:tp_channel_new
+}
+
+{
+   creating a boxed type to use in TpCapabilities
+   Memcheck:Leak
+   ...
+   fun:g_type_class_ref
+   ...
+   fun:g_param_spec_boxed
+   fun:tp_capabilities_class_intern_init
+}
+
+# ============================= questionable ==========================
+
+{
+   creating classes for instances (this is a pretty big hammer)
+   Memcheck:Leak
+   ...
+   fun:g_type_class_ref
+   ...
+   fun:g_type_create_instance
+   ...
+   fun:g_param_spec_string
+}
diff --git a/tools/test-wrapper.sh b/tools/test-wrapper.sh
new file mode 100755
index 0000000..9490067
--- /dev/null
+++ b/tools/test-wrapper.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Make tests shut up. On success, if stdout is a tty, we only output messages
+# about skipped tests; on failure, or if stdout is a file or pipe, we output
+# the lot.
+#
+# Usage: test-wrapper.sh PROGRAM [ARGS...]
+
+set -e
+
+if test -t 1 && test "z$CHECK_VERBOSE" = z; then
+  :   # continue with the output-suppressed code path, below
+else
+  "$@" || e=$?
+  exit $e
+fi
+
+e=0
+"$@" > capture-$$.log 2>&1 || e=$?
+if test z$e = z0; then
+  grep -i skipped capture-$$.log || true
+  rm -f capture-$$.log
+else
+  cat capture-$$.log
+  exit $e
+fi
+
+# Copyright © 2010 Collabora Ltd. <http://www.collabora.co.uk/>
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. There is no warranty.
diff --git a/tools/valgrind.mk b/tools/valgrind.mk
new file mode 100644
index 0000000..25a3488
--- /dev/null
+++ b/tools/valgrind.mk
@@ -0,0 +1,13 @@
+VALGRIND = valgrind --tool=memcheck \
+    --verbose \
+    --leak-check=full \
+    --leak-resolution=high \
+    --suppressions=$(top_srcdir)/tools/telepathy-glib.supp \
+    --child-silent-after-fork=yes \
+    --num-callers=20 \
+    --gen-suppressions=all
+
+# other potentially interesting options:
+# --show-reachable=yes   reachable objects (many!)
+# --read-var-info=yes    better diagnostics from DWARF3 info
+# --track-origins=yes    better diagnostics for uninit values (slow)
diff --git a/tools/with-session-bus.sh b/tools/with-session-bus.sh
index 063bd7e..cfedb5b 100644
--- a/tools/with-session-bus.sh
+++ b/tools/with-session-bus.sh
@@ -59,7 +59,9 @@ cleanup ()
 {
   pid=`head -n1 $me-$$.pid`
   if test -n "$pid" ; then
-    echo "Killing temporary bus daemon: $pid" >&2
+    if [ -n "$VERBOSE_TESTS" ]; then
+      echo "Killing temporary bus daemon: $pid" >&2
+    fi
     kill -INT "$pid"
   fi
   rm -f $me-$$.address
@@ -69,8 +71,10 @@ cleanup ()
 trap cleanup INT HUP TERM
 dbus-daemon $dbus_daemon_args
 
-{ echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2
-{ echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2
+if [ -n "$VERBOSE_TESTS" ]; then
+  { echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2
+  { echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2
+fi
 
 e=0
 DBUS_SESSION_BUS_ADDRESS="`cat $me-$$.address`"
diff --git a/tools/xincludator.py b/tools/xincludator.py
new file mode 100644
index 0000000..63e106a
--- /dev/null
+++ b/tools/xincludator.py
@@ -0,0 +1,39 @@
+#!/usr/bin/python
+
+from sys import argv, stdout, stderr
+import codecs, locale
+import os
+import xml.dom.minidom
+
+stdout = codecs.getwriter('utf-8')(stdout)
+
+NS_XI = 'http://www.w3.org/2001/XInclude'
+
+def xincludate(dom, base, dropns = []):
+    remove_attrs = []
+    for i in xrange(dom.documentElement.attributes.length):
+        attr = dom.documentElement.attributes.item(i)
+        if attr.prefix == 'xmlns':
+            if attr.localName in dropns:
+                remove_attrs.append(attr)
+            else:
+                dropns.append(attr.localName)
+    for attr in remove_attrs:
+        dom.documentElement.removeAttributeNode(attr)
+    for include in dom.getElementsByTagNameNS(NS_XI, 'include'):
+        href = include.getAttribute('href')
+        # FIXME: assumes Unixy paths
+        filename = os.path.join(os.path.dirname(base), href)
+        subdom = xml.dom.minidom.parse(filename)
+        xincludate(subdom, filename, dropns)
+        if './' in href:
+            subdom.documentElement.setAttribute('xml:base', href)
+        include.parentNode.replaceChild(subdom.documentElement, include)
+
+if __name__ == '__main__':
+    argv = argv[1:]
+    dom = xml.dom.minidom.parse(argv[0])
+    xincludate(dom, argv[0])
+    xml = dom.toxml()
+    stdout.write(xml)
+    stdout.write('\n')



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]